/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Create content and connect to the format. // Create ContentNode and put it into the autotext selection.
SwNodeRange aRange( GetNodes().GetEndOfAutotext(), SwNodeOffset(-1),
GetNodes().GetEndOfAutotext() );
GetNodes().SectionDown( &aRange, SwFlyStartNode );
OSL_ENSURE(pTextNode!= nullptr, "There should be a SwTextNode!");
if (pTextNode != nullptr)
{
SwFormatFlyCnt aFormat( pFormat ); // may fail if there's no space left or header/ftr if (!pTextNode->InsertItem(aFormat, nStt, nStt))
{ // pFormat is dead now return nullptr;
}
}
}
/* If there is no adjust item in the paragraph style for the content node of the new fly section
propagate an existing adjust item at the anchor to the new content node. */
SwContentNode * pNewTextNd = GetNodes().MakeTextNode
( GetNodes().GetEndOfAutotext(),
getIDocumentStylePoolAccess().GetTextCollFromPool( nCollId ));
SwContentNode * pAnchorNode = pAnchorPos->GetNode().GetContentNode(); // pAnchorNode from cursor must be valid, unless a whole table is selected (in which // case the node is not a content node, and pAnchorNode is nullptr). In the latter case, // bCalledFromShell is false.
assert(!bCalledFromShell || pAnchorNode);
// Attention: Do not create an index on the stack, or we // cannot delete ContentNode in the end!
std::optional<SwPosition> oPos( std::in_place, aIndex );
if( pSelBoxes && !pSelBoxes->empty() )
{ // Table selection // Copy parts of a table: create a table with the same width as the // original one and move (copy and delete) the selected boxes. // The size is corrected on a percentage basis.
// Did we select the whole table? if( pSelBoxes->size() == rTable.GetTabSortBoxes().size() )
{ // move the whole table
SwNodeRange aRg( *pTableNd, SwNodeOffset(0), *pTableNd->EndOfSectionNode(), SwNodeOffset(1) );
// If we move the whole table and it is located within a // FlyFrame, the we create a TextNode after it. // So that this FlyFrame is preserved. if( aRg.aEnd.GetNode().IsEndNode() )
GetNodes().MakeTextNode( aRg.aStart.GetNode(),
GetDfltTextFormatColl() );
// Create undo actions if undo is enabled.
getIDocumentContentOperations().MoveNodeRange( aRg, oPos->GetNode(), SwMoveFlags::CREATEUNDOOBJ );
} else
{
rTable.MakeCopy(*this, *oPos, *pSelBoxes); // Don't delete a part of a table with row span!! // You could delete the content instead -> ToDo //rTable.DeleteSel( this, *pSelBoxes, 0, 0, true, true );
}
// If the table is within the frame, then copy without the following TextNode
aIndex = rContent.GetContentIdx()->GetNode().EndOfSectionIndex() - 1;
OSL_ENSURE( aIndex.GetNode().GetTextNode(), "a TextNode should be here" );
oPos.reset(); // Deregister index! // Delete the empty paragraph after the table, in a way that undo is aware of this.
SwPaM aPaM(aIndex);
getIDocumentContentOperations().DelFullPara(aPaM);
} else
{ // copy all Pams and then delete all bool bOldFlag = mbCopyIsMove; boolconst bOldUndo = GetIDocumentUndoRedo().DoesUndo(); boolconst bOldRedlineMove(getIDocumentRedlineAccess().IsRedlineMove());
mbCopyIsMove = true;
GetIDocumentUndoRedo().DoUndo(false);
getIDocumentRedlineAccess().SetRedlineMove(true); for(const SwPaM& rTmp : rPam.GetRingContainer())
{ if( rTmp.HasMark() &&
*rTmp.GetPoint() != *rTmp.GetMark() )
{ // aPos is the newly created fly section, so definitely outside rPam, it's pointless to check that again.
getIDocumentContentOperations().CopyRange(*const_cast<SwPaM*>(&rTmp), *oPos, SwCopyFlags::IsMoveToFly);
}
}
getIDocumentRedlineAccess().SetRedlineMove(bOldRedlineMove);
mbCopyIsMove = bOldFlag;
GetIDocumentUndoRedo().DoUndo(bOldUndo);
// If we don't have a layout we can't get page anchored FlyFrames. // Also, page anchored FlyFrames are only returned if no range is specified. if( !getIDocumentLayoutAccess().GetCurrentViewShell() || pCmpRange )
{ return aRetval;
}
SwFrameFormat* pFly = pAnchoredObj->GetFrameFormat(); const SwFormatAnchor& rAnchor = pFly->GetAnchor(); if ((RndStdIds::FLY_AT_PARA != rAnchor.GetAnchorId()) &&
(RndStdIds::FLY_AT_FLY != rAnchor.GetAnchorId()) &&
(RndStdIds::FLY_AT_CHAR != rAnchor.GetAnchorId()))
{ const SwContentFrame * pContentFrame = pPage->FindFirstBodyContent(); if ( !pContentFrame )
{ // Oops! An empty page. // In order not to lose the whole frame (RTF) we // look for the last Content before the page. const SwPageFrame *pPrv = static_cast<const SwPageFrame*>(pPage->GetPrev()); while ( !pContentFrame && pPrv )
{
pContentFrame = pPrv->FindFirstBodyContent();
pPrv = static_cast<const SwPageFrame*>(pPrv->GetPrev());
}
} if ( pContentFrame )
{ const SwNode* pNd( pContentFrame->IsTextFrame()
? static_cast<SwTextFrame const*>(pContentFrame)->GetTextNodeFirst()
: static_cast<SwNoTextFrame const*>(pContentFrame)->GetNode() );
aRetval.insert(SwPosFlyFrame(*pNd, pFly, aRetval.size()));
}
}
}
}
pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
}
return aRetval;
}
/* #i6447# changed behaviour if lcl_CpyAttr:
If the old item set contains the item to set (no inheritance) copy the item into the new set.
If the old item set contains the item by inheritance and the new set contains the item, too: If the two items differ copy the item from the old set to the new set.
Otherwise the new set will not be changed.
*/ staticvoid lcl_CpyAttr( SfxItemSet &rNewSet, const SfxItemSet &rOldSet, sal_uInt16 nWhich )
{ const SfxPoolItem *pOldItem = nullptr;
rOldSet.GetItemState( nWhich, false, &pOldItem); if (pOldItem != nullptr)
rNewSet.Put( *pOldItem ); else
{
pOldItem = rOldSet.GetItem( nWhich ); if (pOldItem != nullptr)
{ const SfxPoolItem *pNewItem = rNewSet.GetItem( nWhich ); if (pNewItem != nullptr)
{ if (*pOldItem != *pNewItem)
rNewSet.Put( *pOldItem );
} else {
OSL_FAIL("What am I doing here?");
}
} else {
OSL_FAIL("What am I doing here?");
}
}
// Get the field first, because we retrieve the TextColl via the field's name
OSL_ENSURE( nId == USHRT_MAX || nId < rDoc.getIDocumentFieldsAccess().GetFieldTypes()->size(), "FieldType index out of bounds." );
SwFieldType *pType = (nId != USHRT_MAX) ? (*rDoc.getIDocumentFieldsAccess().GetFieldTypes())[nId].get() : nullptr;
OSL_ENSURE(!pType || pType->Which() == SwFieldIds::SetExp, "wrong Id for Label");
SwTextFormatColl * pColl = nullptr; if( pType )
{ for( auto i = pTextFormatCollTable->size(); i; )
{ if( (*pTextFormatCollTable)[ --i ]->GetName()==pType->GetName() )
{
pColl = (*pTextFormatCollTable)[i]; break;
}
}
OSL_ENSURE( pColl, "no text collection found" );
}
case SwLabelType::Object:
{ // Destroy Frame, // insert new Frame, // insert the corresponding Node with Field into the new Frame, // insert the old Frame with the Object (Picture/OLE) paragraph-bound into the new Frame, // create Frames.
// Get the FlyFrame's Format and decouple the Layout.
SwFrameFormat *pOldFormat = rDoc.GetNodes()[nNdIdx]->GetFlyFormat();
OSL_ENSURE( pOldFormat, "Couldn't find the Fly's Format." ); // #i115719# // <title> and <description> attributes are lost when calling <DelFrames()>. // Thus, keep them and restore them after the calling <MakeFrames()> auto pOldFlyFrameFormat = dynamic_cast<SwFlyFrameFormat*>(pOldFormat); const OUString sTitle( pOldFlyFrameFormat
? pOldFlyFrameFormat->GetObjTitle()
: OUString() ); const OUString sDescription( pOldFlyFrameFormat
? pOldFlyFrameFormat->GetObjDescription()
: OUString() );
pOldFormat->DelFrames();
/* #i6447#: Only the selected items are copied from the old
format. */
SwAttrSet aNewSet = pNewFormat->GetAttrSet().CloneAsValue();
// Copy only the set attributes. // The others should apply from the Templates.
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_PRINT );
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_OPAQUE );
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_PROTECT );
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_SURROUND );
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_VERT_ORIENT );
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_HORI_ORIENT );
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_LR_SPACE );
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_UL_SPACE );
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_BACKGROUND ); if( bCpyBrd )
{ // If there's no BoxItem at graphic, but the new Format has one, then set the // default item in the new Set. Because the graphic's size has never changed! const SfxPoolItem *pItem; if( SfxItemState::SET == pOldFormat->GetAttrSet().
GetItemState( RES_BOX, true, &pItem ))
aNewSet.Put( *pItem ); elseif( SfxItemState::SET == pNewFormat->GetAttrSet().
GetItemState( RES_BOX ))
aNewSet.Put( *GetDfltAttr( RES_BOX ) );
if( SfxItemState::SET == pOldFormat->GetAttrSet().
GetItemState( RES_SHADOW, true, &pItem ))
aNewSet.Put( *pItem ); elseif( SfxItemState::SET == pNewFormat->GetAttrSet().
GetItemState( RES_SHADOW ))
aNewSet.Put( *GetDfltAttr( RES_SHADOW ) );
} else
{ // Hard-set the attributes, because they could come from the Template // and then size calculations could not be correct anymore.
aNewSet.Put( SvxBoxItem(RES_BOX) );
aNewSet.Put( SvxShadowItem(RES_SHADOW) );
}
// Always transfer the anchor, which is a hard attribute anyways.
aNewSet.Put( pOldFormat->GetAnchor() );
// The new one should be changeable in its height.
std::unique_ptr<SwFormatFrameSize> aFrameSize(pOldFormat->GetFrameSize().Clone());
aFrameSize->SetHeightSizeType( SwFrameSize::Minimum );
aNewSet.Put( std::move(aFrameSize) );
// InContents need to be treated in a special way: // The TextAttribute needs to be destroyed. // Unfortunately, this also destroys the Format next to the Frames. // To avoid this, we disconnect the attribute from the Format.
// The old one should not have a flow and it should be adjusted to above and // middle. // Also, the width should be 100% and it should also adjust the height, if changed.
aNewSet.ClearItem();
// Hard-set the attributes, because they could come from the Template // and then size calculations could not be correct anymore. if( bCpyBrd )
{
aNewSet.Put( SvxBoxItem(RES_BOX) );
aNewSet.Put( SvxShadowItem(RES_SHADOW) );
}
aNewSet.Put( SvxLRSpaceItem(RES_LR_SPACE) );
aNewSet.Put( SvxULSpaceItem(RES_UL_SPACE) );
// The old one is paragraph-bound to the paragraph in the new one.
SwFormatAnchor aAnch( RndStdIds::FLY_AT_PARA );
SwNodeIndex aAnchIdx( *pNewFormat->GetContent().GetContentIdx(), 1 );
pNew = aAnchIdx.GetNode().GetTextNode();
SwPosition aPos( aAnchIdx );
aAnch.SetAnchor( &aPos );
aNewSet.Put( aAnch );
// Have only the FlyFrames created. // We leave this to established methods (especially for InCntFlys).
pNewFormat->MakeFrames(); // #i115719# if ( pOldFlyFrameFormat )
{
pOldFlyFrameFormat->SetObjTitle( sTitle );
pOldFlyFrameFormat->SetObjDescription( sDescription );
}
} break;
// Because we get by the TextColl's name, we need to create the field first.
OSL_ENSURE( nId == USHRT_MAX || nId < rDoc.getIDocumentFieldsAccess().GetFieldTypes()->size(), "FieldType index out of bounds" );
SwFieldType *pType = nId != USHRT_MAX ? (*rDoc.getIDocumentFieldsAccess().GetFieldTypes())[nId].get() : nullptr;
OSL_ENSURE( !pType || pType->Which() == SwFieldIds::SetExp, "Wrong label id" );
SwTextFormatColl *pColl = nullptr; if( pType )
{ for( auto i = pTextFormatCollTable->size(); i; )
{ if( (*pTextFormatCollTable)[ --i ]->GetName()==pType->GetName() )
{
pColl = (*pTextFormatCollTable)[i]; break;
}
}
OSL_ENSURE( pColl, "no text collection found" );
}
// Destroy Frame, // insert new Frame, // insert the corresponding Node with Field into the new Frame, // insert the old Frame with the Object (Picture/OLE) paragraph-bound into the new Frame, // create Frames.
// Keep layer ID of drawing object before removing // its frames. // Note: The layer ID is passed to the undo and have to be the correct value. // Removing the frames of the drawing object changes its layer. const SdrLayerID nLayerId = rSdrObj.GetLayer();
pOldFormat->DelFrames();
// InContents need to be treated in a special way: // The TextAttribute needs to be destroyed. // Unfortunately, this also destroys the Format next to the Frames. // To avoid this, we disconnect the attribute from the Format.
SwAttrSet aNewSet = pOldFormat->GetAttrSet().CloneAsValue( false );
// Protect the Frame's size and position if ( rSdrObj.IsMoveProtect() || rSdrObj.IsResizeProtect() )
{
SvxProtectItem aProtect(RES_PROTECT);
aProtect.SetContentProtect( false );
aProtect.SetPosProtect( rSdrObj.IsMoveProtect() );
aProtect.SetSizeProtect( rSdrObj.IsResizeProtect() );
aNewSet.Put( aProtect );
}
// Take over the text wrap
lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_SURROUND );
// Send the frame to the back, if needed. // Consider the 'invisible' hell layer. if ( rDoc.getIDocumentDrawModelAccess().GetHellId() != nLayerId &&
rDoc.getIDocumentDrawModelAccess().GetInvisibleHellId() != nLayerId )
{
SvxOpaqueItem aOpaque( RES_OPAQUE );
aOpaque.SetValue( true );
aNewSet.Put( aOpaque );
}
// Take over position // #i26791# - use directly drawing object's positioning attributes
aNewSet.Put( pOldFormat->GetHoriOrient() );
aNewSet.Put( pOldFormat->GetVertOrient() );
aNewSet.Put( pOldFormat->GetAnchor() );
// The new one should be variable in its height!
Size aSz( rSdrObj.GetCurrentBoundRect().GetSize() );
SwFormatFrameSize aFrameSize( SwFrameSize::Minimum, aSz.Width(), aSz.Height() );
aNewSet.Put( aFrameSize );
// Apply the margin to the new Frame. // Don't set a border, use the one from the Template.
aNewSet.Put( pOldFormat->GetLRSpace() );
aNewSet.Put( pOldFormat->GetULSpace() );
// Set border and shadow to default if the template contains any. if( SfxItemState::SET == pNewFormat->GetAttrSet().GetItemState( RES_BOX ))
aNewSet.Put( *GetDfltAttr( RES_BOX ) );
// #i26791# - set position of the drawing object, which is labeled.
aNewSet.Put( SwFormatVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ) );
aNewSet.Put( SwFormatHoriOrient( 0, text::HoriOrientation::CENTER, text::RelOrientation::FRAME ) );
// The old one is paragraph-bound to the new one's paragraph.
SwFormatAnchor aAnch( RndStdIds::FLY_AT_PARA );
SwNodeIndex aAnchIdx( *pNewFormat->GetContent().GetContentIdx(), 1 );
pNew = aAnchIdx.GetNode().GetTextNode();
SwPosition aPos( aAnchIdx );
aAnch.SetAnchor( &aPos );
aNewSet.Put( aAnch );
staticvoid lcl_collectUsedNums(std::vector<unsignedint>& rSetFlags, sal_Int32 nNmLen, std::u16string_view rName, std::u16string_view rCmpName)
{ if (o3tl::starts_with(rName, rCmpName))
{ // Only get and set the Flag const sal_Int32 nNum = o3tl::toInt32(rName.substr(nNmLen)) - 1; if (nNum >= 0)
rSetFlags.push_back(nNum);
}
}
staticvoid lcl_collectUsedNums(std::vector<unsignedint>& rSetFlags, sal_Int32 nNmLen, const SdrObject& rObj, const UIName& rCmpName)
{ const OUString& sName = rObj.GetName();
lcl_collectUsedNums(rSetFlags, nNmLen, sName, rCmpName.toString()); // tdf#122487 take groups into account, iterate and recurse through their // contents for name collision check if (!rObj.IsGroupObject()) return;
const SdrObjList* pSub(rObj.GetSubList());
assert(pSub && "IsGroupObject is implemented as GetSubList != nullptr"); for (const rtl::Reference<SdrObject>& pObj : *pSub)
{
lcl_collectUsedNums(rSetFlags, nNmLen, *pObj, rCmpName);
}
}
namespace
{ int first_available_number(std::vector<unsignedint>& numbers)
{
std::sort(numbers.begin(), numbers.end()); auto last = std::unique(numbers.begin(), numbers.end());
numbers.erase(last, numbers.end());
for (size_t i = 0; i < numbers.size(); ++i)
{ if (numbers[i] != i) return i;
}
if (!rPrefix.empty())
{ // Generate a name that makes it possible to know this is a copy of which original name, // e.g. 'Picture 1 Copy 1'.
assert(nNdTyp != SwNodeType::NONE);
sal_Int32 nCnt = 1;
OUString aPrefix = SwResId(STR_MARK_COPY).replaceFirst("%1", rPrefix);
OUString aTmp; while(nCnt < SAL_MAX_INT32)
{
aTmp = aPrefix + OUString::number(nCnt);
++nCnt; if (!rDoc.FindFlyByName(UIName(aTmp), nNdTyp))
{ break;
}
} return UIName(aTmp);
}
// All numbers are flagged accordingly, so determine the right one auto nNum = first_available_number(aUsedNums) + 1; return UIName(aName.toString() + OUString::number(nNum));
}
SwTextFootnote::SetUniqueSeqRefNo( *this ); // #i52775# Chapter footnotes did not get updated correctly. // Calling UpdateAllFootnote() instead of UpdateFootnote() solves this problem, // but I do not dare to call UpdateAllFootnote() in all cases: Safety first. if ( FTNNUM_CHAPTER == GetFootnoteInfo().m_eNum )
{
GetFootnoteIdxs().UpdateAllFootnote();
} else
{
SwNodeIndex aTmp( GetNodes() );
GetFootnoteIdxs().UpdateFootnote( aTmp.GetNode() );
}
}
bool SwDoc::IsInHeaderFooter( const SwNode& rIdx ) const
{ // That can also be a Fly in a Fly in the Header. // Is also used by sw3io, to determine if a Redline object is // in the Header or Footer. // Because Redlines are also attached to Start and EndNode, // the Index must not necessarily be from a ContentNode. const SwNode* pNd = &rIdx; const SwNode* pFlyNd = pNd->FindFlyStartNode(); while( pFlyNd )
{ // get up by using the Anchor #if OSL_DEBUG_LEVEL > 0
std::vector<const SwFrameFormat*> checkFormats; for(sw::SpzFrameFormat* pFormat: *GetSpzFrameFormats())
{ const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); if( pIdx && pFlyNd == &pIdx->GetNode() )
checkFormats.push_back( pFormat );
} #endif
std::vector<SwFrameFormat*> const & rFlys(pFlyNd->GetAnchoredFlys()); bool bFound(false); for (size_t i = 0; i < rFlys.size(); ++i)
{ const SwFrameFormat *const pFormat = rFlys[i]; const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); if( pIdx && pFlyNd == &pIdx->GetNode() )
{ #if OSL_DEBUG_LEVEL > 0 auto checkPos = std::find(
checkFormats.begin(), checkFormats.end(), pFormat );
assert( checkPos != checkFormats.end());
checkFormats.erase( checkPos ); #endif const SwFormatAnchor& rAnchor = pFormat->GetAnchor(); if ((RndStdIds::FLY_AT_PAGE == rAnchor.GetAnchorId()) ||
!rAnchor.GetAnchorNode() )
{ returnfalse;
}
pNd = rAnchor.GetAnchorNode();
pFlyNd = pNd->FindFlyStartNode();
bFound = true; break;
}
} if (!bFound)
{
OSL_ENSURE(mbInReading, "Found a FlySection but not a Format!"); returnfalse;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.