1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
21 #include <sot/exchange.hxx>
22 #include <svx/svdpage.hxx>
23 #include <editeng/keepitem.hxx>
24 #include <editeng/ulspitem.hxx>
25 #include <editeng/lrspitem.hxx>
26 #include <editeng/boxitem.hxx>
27 #include <editeng/shaditem.hxx>
28 #include <editeng/protitem.hxx>
29 #include <editeng/opaqitem.hxx>
30 #include <osl/diagnose.h>
31 #include <svx/svdouno.hxx>
32 #include <editeng/frmdiritem.hxx>
34 #include <swmodule.hxx>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/embed/XEmbeddedObject.hpp>
38 #include <SwStyleNameMapper.hxx>
39 #include <drawdoc.hxx>
40 #include <fchrfmt.hxx>
42 #include <txatbase.hxx>
44 #include <fmtornt.hxx>
45 #include <fmtcntnt.hxx>
46 #include <fmtanchr.hxx>
47 #include <fmtfsize.hxx>
48 #include <fmtsrnd.hxx>
49 #include <fmtflcnt.hxx>
53 #include <ndnotxt.hxx>
56 #include <IDocumentUndoRedo.hxx>
57 #include <IDocumentRedlineAccess.hxx>
58 #include <DocumentSettingManager.hxx>
59 #include <IDocumentDrawModelAccess.hxx>
60 #include <IDocumentFieldsAccess.hxx>
61 #include <IDocumentState.hxx>
62 #include <IDocumentLayoutAccess.hxx>
63 #include <IDocumentStylePoolAccess.hxx>
64 #include <rootfrm.hxx>
65 #include <pagefrm.hxx>
68 #include <notxtfrm.hxx>
69 #include <dflyobj.hxx>
70 #include <dcontact.hxx>
73 #include <UndoInsert.hxx>
75 #include <poolfmt.hxx>
77 #include <swtable.hxx>
81 #include <ftninfo.hxx>
82 #include <pagedesc.hxx>
83 #include <strings.hrc>
84 #include <frameformats.hxx>
85 #include <tools/datetimeutils.hxx>
86 #include <comphelper/string.hxx>
87 #include <o3tl/string_view.hxx>
89 #include <sortedobjs.hxx>
91 #include <string_view>
94 using namespace ::com::sun::star
;
96 #define DEF_FLY_WIDTH 2268 // Default width for FlyFrames (2268 == 4cm)
98 static bool lcl_IsItemSet(const SwContentNode
& rNode
, sal_uInt16 which
)
100 bool bResult
= false;
102 if (SfxItemState::SET
== rNode
.GetSwAttrSet().GetItemState(which
))
108 rtl::Reference
<SdrObject
> SwDoc::CloneSdrObj( const SdrObject
& rObj
, bool bMoveWithinDoc
,
111 // #i52858# - method name changed
112 SdrPage
*pPg
= getIDocumentDrawModelAccess().GetOrCreateDrawModel()->GetPage( 0 );
115 auto pNewPage
= getIDocumentDrawModelAccess().GetDrawModel()->AllocPage( false );
116 getIDocumentDrawModelAccess().GetDrawModel()->InsertPage( pNewPage
.get() );
117 pPg
= pNewPage
.get();
120 // TTTT Clone directly to target SdrModel
121 rtl::Reference
<SdrObject
> pObj(rObj
.CloneSdrObject(*getIDocumentDrawModelAccess().GetDrawModel()));
123 if( bMoveWithinDoc
&& SdrInventor::FmForm
== pObj
->GetObjInventor() )
125 // We need to preserve the Name for Controls
126 uno::Reference
< awt::XControlModel
> xModel
= static_cast<SdrUnoObj
*>(pObj
.get())->GetUnoControlModel();
128 uno::Reference
< beans::XPropertySet
> xSet(xModel
, uno::UNO_QUERY
);
129 static const OUStringLiteral
sName(u
"Name");
131 aVal
= xSet
->getPropertyValue( sName
);
133 pPg
->InsertObjectThenMakeNameUnique( pObj
.get() );
135 xSet
->setPropertyValue( sName
, aVal
);
137 else if( bInsInPage
)
138 pPg
->InsertObjectThenMakeNameUnique( pObj
.get() );
140 // For drawing objects: set layer of cloned object to invisible layer
141 SdrLayerID nLayerIdForClone
= rObj
.GetLayer();
142 if ( dynamic_cast<const SwFlyDrawObj
*>( pObj
.get() ) == nullptr &&
143 dynamic_cast<const SwVirtFlyDrawObj
*>( pObj
.get() ) == nullptr &&
144 pObj
->GetObjIdentifier() != SdrObjKind::NewFrame
)
146 if ( getIDocumentDrawModelAccess().IsVisibleLayerId( nLayerIdForClone
) )
148 nLayerIdForClone
= getIDocumentDrawModelAccess().GetInvisibleLayerIdByVisibleOne( nLayerIdForClone
);
151 pObj
->SetLayer( nLayerIdForClone
);
156 SwFlyFrameFormat
* SwDoc::MakeFlySection_( const SwPosition
& rAnchPos
,
157 const SwContentNode
& rNode
,
158 RndStdIds eRequestId
,
159 const SfxItemSet
* pFlySet
,
160 SwFrameFormat
* pFrameFormat
)
163 pFrameFormat
= getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME
);
166 switch( rNode
.GetNodeType() )
168 case SwNodeType::Grf
: sName
= GetUniqueGrfName(); break;
169 case SwNodeType::Ole
: sName
= GetUniqueOLEName(); break;
170 default: sName
= GetUniqueFrameName(); break;
172 SwFlyFrameFormat
* pFormat
= MakeFlyFrameFormat( sName
, pFrameFormat
);
174 // Create content and connect to the format.
175 // Create ContentNode and put it into the autotext selection.
176 SwNodeRange
aRange( GetNodes().GetEndOfAutotext(), SwNodeOffset(-1),
177 GetNodes().GetEndOfAutotext() );
178 GetNodes().SectionDown( &aRange
, SwFlyStartNode
);
180 pFormat
->SetFormatAttr( SwFormatContent( rNode
.StartOfSectionNode() ));
182 const SwFormatAnchor
* pAnchor
= nullptr;
185 pAnchor
= pFlySet
->GetItemIfSet( RES_ANCHOR
, false );
186 if( SfxItemState::SET
== pFlySet
->GetItemState( RES_CNTNT
, false ))
188 SfxItemSet
aTmpSet( *pFlySet
);
189 aTmpSet
.ClearItem( RES_CNTNT
);
190 pFormat
->SetFormatAttr( aTmpSet
);
193 pFormat
->SetFormatAttr( *pFlySet
);
196 // Anchor not yet set?
198 // #i107811# Assure that at-page anchored fly frames have a page num or a
199 // content anchor set.
201 ( RndStdIds::FLY_AT_PAGE
!= pAnchor
->GetAnchorId() &&
202 !pAnchor
->GetAnchorNode() ) ||
203 ( RndStdIds::FLY_AT_PAGE
== pAnchor
->GetAnchorId() &&
204 !pAnchor
->GetAnchorNode() &&
205 pAnchor
->GetPageNum() == 0 ) )
207 // set it again, needed for Undo
208 SwFormatAnchor
aAnch( pFormat
->GetAnchor() );
209 if (pAnchor
&& (RndStdIds::FLY_AT_FLY
== pAnchor
->GetAnchorId()))
211 SwPosition
aPos( *rAnchPos
.GetNode().FindFlyStartNode() );
212 aAnch
.SetAnchor( &aPos
);
213 eAnchorId
= RndStdIds::FLY_AT_FLY
;
217 if( eRequestId
!= aAnch
.GetAnchorId() &&
218 SfxItemState::SET
!= pFormat
->GetItemState( RES_ANCHOR
) )
220 aAnch
.SetType( eRequestId
);
223 eAnchorId
= aAnch
.GetAnchorId();
224 if ( RndStdIds::FLY_AT_PAGE
!= eAnchorId
|| !pAnchor
|| aAnch
.GetPageNum() == 0)
226 aAnch
.SetAnchor( &rAnchPos
);
229 pFormat
->SetFormatAttr( aAnch
);
232 eAnchorId
= pFormat
->GetAnchor().GetAnchorId();
234 if ( RndStdIds::FLY_AS_CHAR
== eAnchorId
)
236 const sal_Int32 nStt
= rAnchPos
.GetContentIndex();
237 SwTextNode
* pTextNode
= rAnchPos
.GetNode().GetTextNode();
239 OSL_ENSURE(pTextNode
!= nullptr, "There should be a SwTextNode!");
241 if (pTextNode
!= nullptr)
243 SwFormatFlyCnt
aFormat( pFormat
);
244 // may fail if there's no space left or header/ftr
245 if (!pTextNode
->InsertItem(aFormat
, nStt
, nStt
))
246 { // pFormat is dead now
252 if( SfxItemState::SET
!= pFormat
->GetAttrSet().GetItemState( RES_FRM_SIZE
))
254 SwFormatFrameSize
aFormatSize( SwFrameSize::Variable
, 0, DEF_FLY_WIDTH
);
255 const SwNoTextNode
* pNoTextNode
= rNode
.GetNoTextNode();
259 Size
aSize( pNoTextNode
->GetTwipSize() );
260 if( MINFLY
> aSize
.Width() )
261 aSize
.setWidth( DEF_FLY_WIDTH
);
262 aFormatSize
.SetWidth( aSize
.Width() );
265 aFormatSize
.SetHeight( aSize
.Height() );
266 aFormatSize
.SetHeightSizeType( SwFrameSize::Fixed
);
269 pFormat
->SetFormatAttr( aFormatSize
);
273 if( getIDocumentLayoutAccess().GetCurrentViewShell() )
274 pFormat
->MakeFrames(); // ???
276 if (GetIDocumentUndoRedo().DoesUndo())
278 SwNodeOffset nNodeIdx
= rAnchPos
.GetNodeIndex();
279 const sal_Int32 nCntIdx
= rAnchPos
.GetContentIndex();
280 GetIDocumentUndoRedo().AppendUndo(
281 std::make_unique
<SwUndoInsLayFormat
>( pFormat
, nNodeIdx
, nCntIdx
));
284 getIDocumentState().SetModified();
288 SwFlyFrameFormat
* SwDoc::MakeFlySection( RndStdIds eAnchorType
,
289 const SwPosition
* pAnchorPos
,
290 const SfxItemSet
* pFlySet
,
291 SwFrameFormat
* pFrameFormat
, bool bCalledFromShell
)
293 SwFlyFrameFormat
* pFormat
= nullptr;
294 if ( !pAnchorPos
&& (RndStdIds::FLY_AT_PAGE
!= eAnchorType
) )
296 const SwFormatAnchor
* pAnch
;
297 if( (pFlySet
&& (pAnch
= pFlySet
->GetItemIfSet( RES_ANCHOR
, false ))) ||
298 ( pFrameFormat
&& (pAnch
= pFrameFormat
->GetItemIfSet(RES_ANCHOR
)) ) )
300 if ( RndStdIds::FLY_AT_PAGE
!= pAnch
->GetAnchorId() )
302 pAnchorPos
= pAnch
->GetContentAnchor();
310 pFrameFormat
= getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME
);
312 sal_uInt16 nCollId
= o3tl::narrowing
<sal_uInt16
>(
313 GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE
) ? RES_POOLCOLL_TEXT
: RES_POOLCOLL_FRAME
);
315 /* If there is no adjust item in the paragraph style for the content node of the new fly section
316 propagate an existing adjust item at the anchor to the new content node. */
317 SwContentNode
* pNewTextNd
= GetNodes().MakeTextNode
318 ( GetNodes().GetEndOfAutotext(),
319 getIDocumentStylePoolAccess().GetTextCollFromPool( nCollId
));
320 SwContentNode
* pAnchorNode
= pAnchorPos
->GetNode().GetContentNode();
321 // pAnchorNode from cursor must be valid, unless a whole table is selected (in which
322 // case the node is not a content node, and pAnchorNode is nullptr). In the latter case,
323 // bCalledFromShell is false.
324 assert(!bCalledFromShell
|| pAnchorNode
);
326 const SfxPoolItem
* pItem
= nullptr;
328 if (bCalledFromShell
&& !lcl_IsItemSet(*pNewTextNd
, RES_PARATR_ADJUST
) &&
329 SfxItemState::SET
== pAnchorNode
->GetSwAttrSet().GetItemState(RES_PARATR_ADJUST
, true, &pItem
))
331 pNewTextNd
->SetAttr(*pItem
);
334 pFormat
= MakeFlySection_( *pAnchorPos
, *pNewTextNd
,
335 eAnchorType
, pFlySet
, pFrameFormat
);
340 SwFlyFrameFormat
* SwDoc::MakeFlyAndMove( const SwPaM
& rPam
, const SfxItemSet
& rSet
,
341 const SwSelBoxes
* pSelBoxes
,
342 SwFrameFormat
*pParent
)
344 const SwFormatAnchor
& rAnch
= rSet
.Get( RES_ANCHOR
);
346 GetIDocumentUndoRedo().StartUndo( SwUndoId::INSLAYFMT
, nullptr );
348 SwFlyFrameFormat
* pFormat
= MakeFlySection( rAnch
.GetAnchorId(), rPam
.GetPoint(),
351 // If content is selected, it becomes the new frame's content.
352 // Namely, it is moved into the NodeArray's appropriate section.
356 do { // middle check loop
357 const SwFormatContent
&rContent
= pFormat
->GetContent();
358 OSL_ENSURE( rContent
.GetContentIdx(), "No content prepared." );
359 SwNodeIndex
aIndex( *(rContent
.GetContentIdx()), 1 );
361 // Attention: Do not create an index on the stack, or we
362 // cannot delete ContentNode in the end!
363 std::optional
<SwPosition
> oPos( std::in_place
, aIndex
);
365 if( pSelBoxes
&& !pSelBoxes
->empty() )
368 // Copy parts of a table: create a table with the same width as the
369 // original one and move (copy and delete) the selected boxes.
370 // The size is corrected on a percentage basis.
372 SwTableNode
* pTableNd
= const_cast<SwTableNode
*>((*pSelBoxes
)[0]->
373 GetSttNd()->FindTableNode());
377 SwTable
& rTable
= pTableNd
->GetTable();
379 // Did we select the whole table?
380 if( pSelBoxes
->size() == rTable
.GetTabSortBoxes().size() )
382 // move the whole table
383 SwNodeRange
aRg( *pTableNd
, SwNodeOffset(0), *pTableNd
->EndOfSectionNode(), SwNodeOffset(1) );
385 // If we move the whole table and it is located within a
386 // FlyFrame, the we create a TextNode after it.
387 // So that this FlyFrame is preserved.
388 if( aRg
.aEnd
.GetNode().IsEndNode() )
389 GetNodes().MakeTextNode( aRg
.aStart
.GetNode(),
390 GetDfltTextFormatColl() );
392 getIDocumentContentOperations().MoveNodeRange( aRg
, oPos
->GetNode(), SwMoveFlags::DEFAULT
);
396 rTable
.MakeCopy(*this, *oPos
, *pSelBoxes
);
397 // Don't delete a part of a table with row span!!
398 // You could delete the content instead -> ToDo
399 //rTable.DeleteSel( this, *pSelBoxes, 0, 0, true, true );
402 // If the table is within the frame, then copy without the following TextNode
403 aIndex
= rContent
.GetContentIdx()->GetNode().EndOfSectionIndex() - 1;
404 OSL_ENSURE( aIndex
.GetNode().GetTextNode(),
405 "a TextNode should be here" );
406 oPos
.reset(); // Deregister index!
407 GetNodes().Delete( aIndex
);
409 // This is a hack: whilst FlyFrames/Headers/Footers are not undoable we delete all Undo objects
410 if( GetIDocumentUndoRedo().DoesUndo() )
412 GetIDocumentUndoRedo().DelAllUndoObj();
417 // copy all Pams and then delete all
418 bool bOldFlag
= mbCopyIsMove
;
419 bool const bOldUndo
= GetIDocumentUndoRedo().DoesUndo();
420 bool const bOldRedlineMove(getIDocumentRedlineAccess().IsRedlineMove());
422 GetIDocumentUndoRedo().DoUndo(false);
423 getIDocumentRedlineAccess().SetRedlineMove(true);
424 for(const SwPaM
& rTmp
: rPam
.GetRingContainer())
426 if( rTmp
.HasMark() &&
427 *rTmp
.GetPoint() != *rTmp
.GetMark() )
429 // aPos is the newly created fly section, so definitely outside rPam, it's pointless to check that again.
430 getIDocumentContentOperations().CopyRange(*const_cast<SwPaM
*>(&rTmp
), *oPos
, SwCopyFlags::IsMoveToFly
);
433 getIDocumentRedlineAccess().SetRedlineMove(bOldRedlineMove
);
434 mbCopyIsMove
= bOldFlag
;
435 GetIDocumentUndoRedo().DoUndo(bOldUndo
);
437 for(const SwPaM
& rTmp
: rPam
.GetRingContainer())
439 if( rTmp
.HasMark() &&
440 *rTmp
.GetPoint() != *rTmp
.GetMark() )
442 getIDocumentContentOperations().DeleteAndJoin( *const_cast<SwPaM
*>(&rTmp
) );
449 getIDocumentState().SetModified();
451 GetIDocumentUndoRedo().EndUndo( SwUndoId::INSLAYFMT
, nullptr );
458 * paragraph frames - o.k. if the PaM includes the paragraph from the beginning
459 * to the beginning of the next paragraph at least
460 * frames at character - o.k. if the PaM starts at least at the same position
463 static bool lcl_TstFlyRange( const SwPaM
* pPam
, const SwFormatAnchor
& rFlyFormatAnchor
)
466 const SwPaM
* pTmp
= pPam
;
468 const SwNodeOffset nFlyIndex
= rFlyFormatAnchor
.GetAnchorNode()->GetIndex();
469 auto [pPaMStart
, pPaMEnd
] = pTmp
->StartEnd(); // SwPosition*
470 const SwNodeOffset nPamStartIndex
= pPaMStart
->GetNodeIndex();
471 const SwNodeOffset nPamEndIndex
= pPaMEnd
->GetNodeIndex();
472 if (RndStdIds::FLY_AT_PARA
== rFlyFormatAnchor
.GetAnchorId())
473 bOk
= (nPamStartIndex
< nFlyIndex
&& nPamEndIndex
> nFlyIndex
) ||
474 (((nPamStartIndex
== nFlyIndex
) && (pPaMStart
->GetContentIndex() == 0)) &&
475 (nPamEndIndex
> nFlyIndex
));
478 const sal_Int32 nFlyContentIndex
= rFlyFormatAnchor
.GetAnchorContentOffset();
479 const sal_Int32 nPamEndContentIndex
= pPaMEnd
->GetContentIndex();
480 bOk
= (nPamStartIndex
< nFlyIndex
&&
481 (( nPamEndIndex
> nFlyIndex
)||
482 ((nPamEndIndex
== nFlyIndex
) &&
483 (nPamEndContentIndex
> nFlyContentIndex
))) )
485 (((nPamStartIndex
== nFlyIndex
) &&
486 (pPaMStart
->GetContentIndex() <= nFlyContentIndex
)) &&
487 ((nPamEndIndex
> nFlyIndex
) ||
488 (nPamEndContentIndex
> nFlyContentIndex
)));
493 pTmp
= pTmp
->GetNext();
494 } while( pPam
!= pTmp
);
498 SwPosFlyFrames
SwDoc::GetAllFlyFormats( const SwPaM
* pCmpRange
, bool bDrawAlso
,
499 bool bAsCharAlso
) const
501 SwPosFlyFrames aRetval
;
502 const SwStartNode
* pDirectFly
= nullptr;
503 if (pCmpRange
&& *pCmpRange
->GetPoint() == *pCmpRange
->GetMark()
504 && (pCmpRange
->GetPoint()->GetNode().IsOLENode()
505 || pCmpRange
->GetPoint()->GetNode().IsGrfNode()))
507 pDirectFly
= pCmpRange
->GetPoint()->GetNode().FindFlyStartNode();
510 // collect all anchored somehow to paragraphs
511 for(sw::SpzFrameFormat
* pFly
: *GetSpzFrameFormats())
513 bool bDrawFormat
= bDrawAlso
&& RES_DRAWFRMFMT
== pFly
->Which();
514 bool bFlyFormat
= RES_FLYFRMFMT
== pFly
->Which();
515 if( bFlyFormat
|| bDrawFormat
)
517 const SwFormatAnchor
& rAnchor
= pFly
->GetAnchor();
518 SwNode
const*const pAnchorNode
= rAnchor
.GetAnchorNode();
523 const SwFormatContent
& rContent
= pFly
->GetContent();
524 const SwNodeIndex
* pContentNodeIndex
= rContent
.GetContentIdx();
525 if (pContentNodeIndex
&& pContentNodeIndex
->GetIndex() == pDirectFly
->GetIndex())
527 aRetval
.insert(SwPosFlyFrame(*pAnchorNode
, pFly
, aRetval
.size()));
532 if ( (RndStdIds::FLY_AT_PARA
== rAnchor
.GetAnchorId()) ||
533 (RndStdIds::FLY_AT_FLY
== rAnchor
.GetAnchorId()) ||
534 (RndStdIds::FLY_AT_CHAR
== rAnchor
.GetAnchorId()) ||
535 ((RndStdIds::FLY_AS_CHAR
== rAnchor
.GetAnchorId()) && bAsCharAlso
) )
537 if( pCmpRange
&& !lcl_TstFlyRange( pCmpRange
, rAnchor
))
538 continue; // not a valid FlyFrame
539 aRetval
.insert(SwPosFlyFrame(*pAnchorNode
, pFly
, aRetval
.size()));
544 // If we don't have a layout we can't get page anchored FlyFrames.
545 // Also, page anchored FlyFrames are only returned if no range is specified.
546 if( !getIDocumentLayoutAccess().GetCurrentViewShell() || pCmpRange
)
551 const SwPageFrame
*pPage
= static_cast<const SwPageFrame
*>(getIDocumentLayoutAccess().GetCurrentLayout()->GetLower());
554 if( pPage
->GetSortedObjs() )
556 const SwSortedObjs
&rObjs
= *pPage
->GetSortedObjs();
557 for(SwAnchoredObject
* pAnchoredObj
: rObjs
)
560 if ( pAnchoredObj
->DynCastFlyFrame() != nullptr )
561 pFly
= &(pAnchoredObj
->GetFrameFormat());
562 else if ( bDrawAlso
)
563 pFly
= &(pAnchoredObj
->GetFrameFormat());
567 const SwFormatAnchor
& rAnchor
= pFly
->GetAnchor();
568 if ((RndStdIds::FLY_AT_PARA
!= rAnchor
.GetAnchorId()) &&
569 (RndStdIds::FLY_AT_FLY
!= rAnchor
.GetAnchorId()) &&
570 (RndStdIds::FLY_AT_CHAR
!= rAnchor
.GetAnchorId()))
572 const SwContentFrame
* pContentFrame
= pPage
->FindFirstBodyContent();
573 if ( !pContentFrame
)
575 // Oops! An empty page.
576 // In order not to lose the whole frame (RTF) we
577 // look for the last Content before the page.
578 const SwPageFrame
*pPrv
= static_cast<const SwPageFrame
*>(pPage
->GetPrev());
579 while ( !pContentFrame
&& pPrv
)
581 pContentFrame
= pPrv
->FindFirstBodyContent();
582 pPrv
= static_cast<const SwPageFrame
*>(pPrv
->GetPrev());
587 const SwNode
* pNd( pContentFrame
->IsTextFrame()
588 ? static_cast<SwTextFrame
const*>(pContentFrame
)->GetTextNodeFirst()
589 : static_cast<SwNoTextFrame
const*>(pContentFrame
)->GetNode() );
590 aRetval
.insert(SwPosFlyFrame(*pNd
, pFly
, aRetval
.size()));
595 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
601 /* #i6447# changed behaviour if lcl_CpyAttr:
603 If the old item set contains the item to set (no inheritance) copy the item
606 If the old item set contains the item by inheritance and the new set
607 contains the item, too:
608 If the two items differ copy the item from the old set to the new set.
610 Otherwise the new set will not be changed.
612 static void lcl_CpyAttr( SfxItemSet
&rNewSet
, const SfxItemSet
&rOldSet
, sal_uInt16 nWhich
)
614 const SfxPoolItem
*pOldItem
= nullptr;
616 rOldSet
.GetItemState( nWhich
, false, &pOldItem
);
617 if (pOldItem
!= nullptr)
618 rNewSet
.Put( *pOldItem
);
621 pOldItem
= rOldSet
.GetItem( nWhich
);
622 if (pOldItem
!= nullptr)
624 const SfxPoolItem
*pNewItem
= rNewSet
.GetItem( nWhich
);
625 if (pNewItem
!= nullptr)
627 if (*pOldItem
!= *pNewItem
)
628 rNewSet
.Put( *pOldItem
);
631 OSL_FAIL("What am I doing here?");
635 OSL_FAIL("What am I doing here?");
641 static SwFlyFrameFormat
*
642 lcl_InsertLabel(SwDoc
& rDoc
, SwTextFormatColls
*const pTextFormatCollTable
,
643 SwUndoInsertLabel
*const pUndo
,
644 SwLabelType
const eType
, std::u16string_view rText
, std::u16string_view rSeparator
,
645 const OUString
& rNumberingSeparator
,
646 const bool bBefore
, const sal_uInt16 nId
, const SwNodeOffset nNdIdx
,
647 const OUString
& rCharacterStyle
,
650 ::sw::UndoGuard
const undoGuard(rDoc
.GetIDocumentUndoRedo());
652 bool bTable
= false; // To save some code.
654 // Get the field first, because we retrieve the TextColl via the field's name
655 OSL_ENSURE( nId
== USHRT_MAX
|| nId
< rDoc
.getIDocumentFieldsAccess().GetFieldTypes()->size(),
656 "FieldType index out of bounds." );
657 SwFieldType
*pType
= (nId
!= USHRT_MAX
) ? (*rDoc
.getIDocumentFieldsAccess().GetFieldTypes())[nId
].get() : nullptr;
658 OSL_ENSURE(!pType
|| pType
->Which() == SwFieldIds::SetExp
, "wrong Id for Label");
660 SwTextFormatColl
* pColl
= nullptr;
663 for( auto i
= pTextFormatCollTable
->size(); i
; )
665 if( (*pTextFormatCollTable
)[ --i
]->GetName()==pType
->GetName() )
667 pColl
= (*pTextFormatCollTable
)[i
];
671 OSL_ENSURE( pColl
, "no text collection found" );
676 pColl
= rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_LABEL
);
679 SwTextNode
*pNew
= nullptr;
680 SwFlyFrameFormat
* pNewFormat
= nullptr;
684 case SwLabelType::Table
:
687 case SwLabelType::Fly
:
688 // At the FlySection's Beginning/End insert the corresponding Node with its Field.
689 // The Frame is created automatically.
691 SwStartNode
*pSttNd
= rDoc
.GetNodes()[nNdIdx
]->GetStartNode();
692 OSL_ENSURE( pSttNd
, "No StartNode in InsertLabel." );
696 nNode
= pSttNd
->GetIndex();
702 nNode
= pSttNd
->EndOfSectionIndex();
708 pUndo
->SetNodePos( nNode
);
710 // Create Node for labeling paragraph.
711 SwNodeIndex
aIdx( rDoc
.GetNodes(), nNode
);
712 pNew
= rDoc
.GetNodes().MakeTextNode( aIdx
.GetNode(), pColl
);
716 case SwLabelType::Object
:
720 // insert the corresponding Node with Field into the new Frame,
721 // insert the old Frame with the Object (Picture/OLE) paragraph-bound into the new Frame,
724 // Get the FlyFrame's Format and decouple the Layout.
725 SwFrameFormat
*pOldFormat
= rDoc
.GetNodes()[nNdIdx
]->GetFlyFormat();
726 OSL_ENSURE( pOldFormat
, "Couldn't find the Fly's Format." );
728 // <title> and <description> attributes are lost when calling <DelFrames()>.
729 // Thus, keep them and restore them after the calling <MakeFrames()>
730 auto pOldFlyFrameFormat
= dynamic_cast<SwFlyFrameFormat
*>(pOldFormat
);
731 const OUString
sTitle( pOldFlyFrameFormat
732 ? pOldFlyFrameFormat
->GetObjTitle()
734 const OUString
sDescription( pOldFlyFrameFormat
735 ? pOldFlyFrameFormat
->GetObjDescription()
737 pOldFormat
->DelFrames();
739 pNewFormat
= rDoc
.MakeFlyFrameFormat( rDoc
.GetUniqueFrameName(),
740 rDoc
.getIDocumentStylePoolAccess().GetFrameFormatFromPool(RES_POOLFRM_FRAME
) );
742 /* #i6447#: Only the selected items are copied from the old
744 std::unique_ptr
<SfxItemSet
> pNewSet
= pNewFormat
->GetAttrSet().Clone();
746 // Copy only the set attributes.
747 // The others should apply from the Templates.
748 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_PRINT
);
749 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_OPAQUE
);
750 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_PROTECT
);
751 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_SURROUND
);
752 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_VERT_ORIENT
);
753 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_HORI_ORIENT
);
754 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_LR_SPACE
);
755 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_UL_SPACE
);
756 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_BACKGROUND
);
759 // If there's no BoxItem at graphic, but the new Format has one, then set the
760 // default item in the new Set. Because the graphic's size has never changed!
761 const SfxPoolItem
*pItem
;
762 if( SfxItemState::SET
== pOldFormat
->GetAttrSet().
763 GetItemState( RES_BOX
, true, &pItem
))
764 pNewSet
->Put( *pItem
);
765 else if( SfxItemState::SET
== pNewFormat
->GetAttrSet().
766 GetItemState( RES_BOX
))
767 pNewSet
->Put( *GetDfltAttr( RES_BOX
) );
769 if( SfxItemState::SET
== pOldFormat
->GetAttrSet().
770 GetItemState( RES_SHADOW
, true, &pItem
))
771 pNewSet
->Put( *pItem
);
772 else if( SfxItemState::SET
== pNewFormat
->GetAttrSet().
773 GetItemState( RES_SHADOW
))
774 pNewSet
->Put( *GetDfltAttr( RES_SHADOW
) );
778 // Hard-set the attributes, because they could come from the Template
779 // and then size calculations could not be correct anymore.
780 pNewSet
->Put( SvxBoxItem(RES_BOX
) );
781 pNewSet
->Put( SvxShadowItem(RES_SHADOW
) );
784 // Always transfer the anchor, which is a hard attribute anyways.
785 pNewSet
->Put( pOldFormat
->GetAnchor() );
787 // The new one should be changeable in its height.
788 std::unique_ptr
<SwFormatFrameSize
> aFrameSize(pOldFormat
->GetFrameSize().Clone());
789 aFrameSize
->SetHeightSizeType( SwFrameSize::Minimum
);
790 pNewSet
->Put( std::move(aFrameSize
) );
792 SwStartNode
* pSttNd
= rDoc
.GetNodes().MakeTextSection(
793 rDoc
.GetNodes().GetEndOfAutotext(),
794 SwFlyStartNode
, pColl
);
795 pNewSet
->Put( SwFormatContent( pSttNd
));
797 pNewFormat
->SetFormatAttr( *pNewSet
);
799 // InContents need to be treated in a special way:
800 // The TextAttribute needs to be destroyed.
801 // Unfortunately, this also destroys the Format next to the Frames.
802 // To avoid this, we disconnect the attribute from the Format.
804 const SwFormatAnchor
& rAnchor
= pNewFormat
->GetAnchor();
805 if ( RndStdIds::FLY_AS_CHAR
== rAnchor
.GetAnchorId() )
807 SwTextNode
*pTextNode
= rAnchor
.GetAnchorNode()->GetTextNode();
808 OSL_ENSURE( pTextNode
->HasHints(), "Missing FlyInCnt-Hint." );
809 const sal_Int32 nIdx
= rAnchor
.GetAnchorContentOffset();
810 SwTextAttr
* const pHint
=
811 pTextNode
->GetTextAttrForCharAt(nIdx
, RES_TXTATR_FLYCNT
);
813 assert(pHint
&& "Missing Hint.");
815 OSL_ENSURE( pHint
->Which() == RES_TXTATR_FLYCNT
,
816 "Missing FlyInCnt-Hint." );
817 OSL_ENSURE( pHint
->GetFlyCnt().GetFrameFormat() == pOldFormat
,
818 "Wrong TextFlyCnt-Hint." );
820 const_cast<SwFormatFlyCnt
&>(pHint
->GetFlyCnt()).SetFlyFormat(
824 // The old one should not have a flow and it should be adjusted to above and
826 // Also, the width should be 100% and it should also adjust the height, if changed.
827 pNewSet
->ClearItem();
829 pNewSet
->Put( SwFormatSurround( css::text::WrapTextMode_NONE
) );
830 pNewSet
->Put( SvxOpaqueItem( RES_OPAQUE
, true ) );
832 sal_Int16 eVert
= bBefore
? text::VertOrientation::BOTTOM
: text::VertOrientation::TOP
;
833 pNewSet
->Put( SwFormatVertOrient( 0, eVert
) );
834 pNewSet
->Put( SwFormatHoriOrient( 0, text::HoriOrientation::CENTER
) );
836 aFrameSize
.reset(pOldFormat
->GetFrameSize().Clone());
838 SwOLENode
* pOleNode
= rDoc
.GetNodes()[nNdIdx
+ 1]->GetOLENode();
842 svt::EmbeddedObjectRef
& xRef
= pOleNode
->GetOLEObj().GetObject();
845 SvGlobalName
aCLSID( xRef
->getClassID() );
846 isMath
= ( SotExchange::IsMath( aCLSID
) != 0 );
849 aFrameSize
->SetWidthPercent(isMath
? 0 : 100);
850 aFrameSize
->SetHeightPercent(SwFormatFrameSize::SYNCED
);
851 pNewSet
->Put( std::move(aFrameSize
) );
853 // Hard-set the attributes, because they could come from the Template
854 // and then size calculations could not be correct anymore.
857 pNewSet
->Put( SvxBoxItem(RES_BOX
) );
858 pNewSet
->Put( SvxShadowItem(RES_SHADOW
) );
860 pNewSet
->Put( SvxLRSpaceItem(RES_LR_SPACE
) );
861 pNewSet
->Put( SvxULSpaceItem(RES_UL_SPACE
) );
863 // The old one is paragraph-bound to the paragraph in the new one.
864 SwFormatAnchor
aAnch( RndStdIds::FLY_AT_PARA
);
865 SwNodeIndex
aAnchIdx( *pNewFormat
->GetContent().GetContentIdx(), 1 );
866 pNew
= aAnchIdx
.GetNode().GetTextNode();
867 SwPosition
aPos( aAnchIdx
);
868 aAnch
.SetAnchor( &aPos
);
869 pNewSet
->Put( aAnch
);
872 pUndo
->SetFlys( *pOldFormat
, *pNewSet
, *pNewFormat
);
874 pOldFormat
->SetFormatAttr( *pNewSet
);
878 // Have only the FlyFrames created.
879 // We leave this to established methods (especially for InCntFlys).
880 pNewFormat
->MakeFrames();
882 if ( pOldFlyFrameFormat
)
884 pOldFlyFrameFormat
->SetObjTitle( sTitle
);
885 pOldFlyFrameFormat
->SetObjDescription( sDescription
);
891 OSL_ENSURE(false, "unknown LabelType?");
893 OSL_ENSURE( pNew
, "No Label inserted" );
896 // #i61007# order of captions
897 bool bOrderNumberingFirst
= SW_MOD()->GetModuleConfig()->IsCaptionOrderNumberingFirst();
900 if( bOrderNumberingFirst
)
902 aText
= rNumberingSeparator
;
906 aText
+= pType
->GetName();
907 if( !bOrderNumberingFirst
)
910 sal_Int32 nIdx
= aText
.getLength();
915 const sal_Int32 nSepIdx
= aText
.getLength();
919 SwContentIndex
aIdx( pNew
, 0 );
920 pNew
->InsertText( aText
, aIdx
);
925 SwSetExpField
aField( static_cast<SwSetExpFieldType
*>(pType
), OUString(), SVX_NUM_ARABIC
);
926 if( bOrderNumberingFirst
)
928 SwFormatField
aFormat( aField
);
929 pNew
->InsertItem( aFormat
, nIdx
, nIdx
);
930 if(!rCharacterStyle
.isEmpty())
932 SwCharFormat
* pCharFormat
= rDoc
.FindCharFormatByName(rCharacterStyle
);
935 const sal_uInt16 nMyId
= SwStyleNameMapper::GetPoolIdFromUIName(rCharacterStyle
, SwGetPoolIdFromName::ChrFmt
);
936 pCharFormat
= rDoc
.getIDocumentStylePoolAccess().GetCharFormatFromPool( nMyId
);
940 SwFormatCharFormat
aCharFormat( pCharFormat
);
941 pNew
->InsertItem( aCharFormat
, 0,
942 nSepIdx
+ 1, SetAttrMode::DONTEXPAND
);
951 if ( !pNew
->GetSwAttrSet().GetKeep().GetValue() )
952 pNew
->SetAttr( SvxFormatKeepItem( true, RES_KEEP
) );
956 SwTableNode
*const pNd
=
957 rDoc
.GetNodes()[nNdIdx
]->GetStartNode()->GetTableNode();
958 SwTable
&rTable
= pNd
->GetTable();
959 if ( !rTable
.GetFrameFormat()->GetKeep().GetValue() )
960 rTable
.GetFrameFormat()->SetFormatAttr( SvxFormatKeepItem( true, RES_KEEP
) );
962 pUndo
->SetUndoKeep();
965 rDoc
.getIDocumentState().SetModified();
973 SwLabelType
const eType
, OUString
const& rText
, OUString
const& rSeparator
,
974 OUString
const& rNumberingSeparator
,
975 bool const bBefore
, sal_uInt16
const nId
, SwNodeOffset
const nNdIdx
,
976 OUString
const& rCharacterStyle
,
979 std::unique_ptr
<SwUndoInsertLabel
> pUndo
;
980 if (GetIDocumentUndoRedo().DoesUndo())
982 pUndo
.reset(new SwUndoInsertLabel(
983 eType
, rText
, rSeparator
, rNumberingSeparator
,
984 bBefore
, nId
, rCharacterStyle
, bCpyBrd
, this ));
987 SwFlyFrameFormat
*const pNewFormat
= lcl_InsertLabel(*this, mpTextFormatCollTable
.get(), pUndo
.get(),
988 eType
, rText
, rSeparator
, rNumberingSeparator
, bBefore
,
989 nId
, nNdIdx
, rCharacterStyle
, bCpyBrd
);
993 GetIDocumentUndoRedo().AppendUndo(std::move(pUndo
));
997 GetIDocumentUndoRedo().DelAllUndoObj();
1003 static SwFlyFrameFormat
*
1004 lcl_InsertDrawLabel( SwDoc
& rDoc
, SwTextFormatColls
*const pTextFormatCollTable
,
1005 SwUndoInsertLabel
*const pUndo
, SwDrawFrameFormat
*const pOldFormat
,
1006 OUString
const& rText
,
1007 const OUString
& rSeparator
,
1008 const OUString
& rNumberSeparator
,
1009 const sal_uInt16 nId
,
1010 const OUString
& rCharacterStyle
,
1011 SdrObject
& rSdrObj
)
1013 ::sw::UndoGuard
const undoGuard(rDoc
.GetIDocumentUndoRedo());
1014 ::sw::DrawUndoGuard
const drawUndoGuard(rDoc
.GetIDocumentUndoRedo());
1016 // Because we get by the TextColl's name, we need to create the field first.
1017 OSL_ENSURE( nId
== USHRT_MAX
|| nId
< rDoc
.getIDocumentFieldsAccess().GetFieldTypes()->size(),
1018 "FieldType index out of bounds" );
1019 SwFieldType
*pType
= nId
!= USHRT_MAX
? (*rDoc
.getIDocumentFieldsAccess().GetFieldTypes())[nId
].get() : nullptr;
1020 OSL_ENSURE( !pType
|| pType
->Which() == SwFieldIds::SetExp
, "Wrong label id" );
1022 SwTextFormatColl
*pColl
= nullptr;
1025 for( auto i
= pTextFormatCollTable
->size(); i
; )
1027 if( (*pTextFormatCollTable
)[ --i
]->GetName()==pType
->GetName() )
1029 pColl
= (*pTextFormatCollTable
)[i
];
1033 OSL_ENSURE( pColl
, "no text collection found" );
1038 pColl
= rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_LABEL
);
1041 SwTextNode
* pNew
= nullptr;
1042 SwFlyFrameFormat
* pNewFormat
= nullptr;
1045 // insert new Frame,
1046 // insert the corresponding Node with Field into the new Frame,
1047 // insert the old Frame with the Object (Picture/OLE) paragraph-bound into the new Frame,
1050 // Keep layer ID of drawing object before removing
1052 // Note: The layer ID is passed to the undo and have to be the correct value.
1053 // Removing the frames of the drawing object changes its layer.
1054 const SdrLayerID nLayerId
= rSdrObj
.GetLayer();
1056 pOldFormat
->DelFrames();
1058 // InContents need to be treated in a special way:
1059 // The TextAttribute needs to be destroyed.
1060 // Unfortunately, this also destroys the Format next to the Frames.
1061 // To avoid this, we disconnect the attribute from the Format.
1062 std::unique_ptr
<SfxItemSet
> pNewSet
= pOldFormat
->GetAttrSet().Clone( false );
1064 // Protect the Frame's size and position
1065 if ( rSdrObj
.IsMoveProtect() || rSdrObj
.IsResizeProtect() )
1067 SvxProtectItem
aProtect(RES_PROTECT
);
1068 aProtect
.SetContentProtect( false );
1069 aProtect
.SetPosProtect( rSdrObj
.IsMoveProtect() );
1070 aProtect
.SetSizeProtect( rSdrObj
.IsResizeProtect() );
1071 pNewSet
->Put( aProtect
);
1074 // Take over the text wrap
1075 lcl_CpyAttr( *pNewSet
, pOldFormat
->GetAttrSet(), RES_SURROUND
);
1077 // Send the frame to the back, if needed.
1078 // Consider the 'invisible' hell layer.
1079 if ( rDoc
.getIDocumentDrawModelAccess().GetHellId() != nLayerId
&&
1080 rDoc
.getIDocumentDrawModelAccess().GetInvisibleHellId() != nLayerId
)
1082 SvxOpaqueItem
aOpaque( RES_OPAQUE
);
1083 aOpaque
.SetValue( true );
1084 pNewSet
->Put( aOpaque
);
1087 // Take over position
1088 // #i26791# - use directly drawing object's positioning attributes
1089 pNewSet
->Put( pOldFormat
->GetHoriOrient() );
1090 pNewSet
->Put( pOldFormat
->GetVertOrient() );
1092 pNewSet
->Put( pOldFormat
->GetAnchor() );
1094 // The new one should be variable in its height!
1095 Size
aSz( rSdrObj
.GetCurrentBoundRect().GetSize() );
1096 SwFormatFrameSize
aFrameSize( SwFrameSize::Minimum
, aSz
.Width(), aSz
.Height() );
1097 pNewSet
->Put( aFrameSize
);
1099 // Apply the margin to the new Frame.
1100 // Don't set a border, use the one from the Template.
1101 pNewSet
->Put( pOldFormat
->GetLRSpace() );
1102 pNewSet
->Put( pOldFormat
->GetULSpace() );
1104 SwStartNode
* pSttNd
=
1105 rDoc
.GetNodes().MakeTextSection(
1106 rDoc
.GetNodes().GetEndOfAutotext(),
1107 SwFlyStartNode
, pColl
);
1109 pNewFormat
= rDoc
.MakeFlyFrameFormat( rDoc
.GetUniqueFrameName(),
1110 rDoc
.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME
) );
1112 // Set border and shadow to default if the template contains any.
1113 if( SfxItemState::SET
== pNewFormat
->GetAttrSet().GetItemState( RES_BOX
))
1114 pNewSet
->Put( *GetDfltAttr( RES_BOX
) );
1116 if( SfxItemState::SET
== pNewFormat
->GetAttrSet().GetItemState(RES_SHADOW
))
1117 pNewSet
->Put( *GetDfltAttr( RES_SHADOW
) );
1119 pNewFormat
->SetFormatAttr( SwFormatContent( pSttNd
));
1120 pNewFormat
->SetFormatAttr( *pNewSet
);
1122 const SwFormatAnchor
& rAnchor
= pNewFormat
->GetAnchor();
1123 if ( RndStdIds::FLY_AS_CHAR
== rAnchor
.GetAnchorId() )
1125 SwTextNode
*pTextNode
= rAnchor
.GetAnchorNode()->GetTextNode();
1126 OSL_ENSURE( pTextNode
->HasHints(), "Missing FlyInCnt-Hint." );
1127 const sal_Int32 nIdx
= rAnchor
.GetAnchorContentOffset();
1128 SwTextAttr
* const pHint
=
1129 pTextNode
->GetTextAttrForCharAt( nIdx
, RES_TXTATR_FLYCNT
);
1131 assert(pHint
&& "Missing Hint.");
1133 #if OSL_DEBUG_LEVEL > 0
1134 OSL_ENSURE( pHint
->Which() == RES_TXTATR_FLYCNT
,
1135 "Missing FlyInCnt-Hint." );
1136 OSL_ENSURE( pHint
->GetFlyCnt().
1137 GetFrameFormat() == static_cast<SwFrameFormat
*>(pOldFormat
),
1138 "Wrong TextFlyCnt-Hint." );
1140 const_cast<SwFormatFlyCnt
&>(pHint
->GetFlyCnt()).SetFlyFormat( pNewFormat
);
1143 // The old one should not have a flow
1144 // and it should be adjusted to above and middle.
1145 pNewSet
->ClearItem();
1147 pNewSet
->Put( SwFormatSurround( css::text::WrapTextMode_NONE
) );
1148 if (nLayerId
== rDoc
.getIDocumentDrawModelAccess().GetHellId())
1150 // Consider drawing objects in the 'invisible' hell layer
1151 rSdrObj
.SetLayer( rDoc
.getIDocumentDrawModelAccess().GetHeavenId() );
1153 else if (nLayerId
== rDoc
.getIDocumentDrawModelAccess().GetInvisibleHellId())
1155 rSdrObj
.SetLayer( rDoc
.getIDocumentDrawModelAccess().GetInvisibleHeavenId() );
1157 pNewSet
->Put( SvxLRSpaceItem( RES_LR_SPACE
) );
1158 pNewSet
->Put( SvxULSpaceItem( RES_UL_SPACE
) );
1160 // #i26791# - set position of the drawing object, which is labeled.
1161 pNewSet
->Put( SwFormatVertOrient( 0, text::VertOrientation::TOP
, text::RelOrientation::FRAME
) );
1162 pNewSet
->Put( SwFormatHoriOrient( 0, text::HoriOrientation::CENTER
, text::RelOrientation::FRAME
) );
1164 // The old one is paragraph-bound to the new one's paragraph.
1165 SwFormatAnchor
aAnch( RndStdIds::FLY_AT_PARA
);
1166 SwNodeIndex
aAnchIdx( *pNewFormat
->GetContent().GetContentIdx(), 1 );
1167 pNew
= aAnchIdx
.GetNode().GetTextNode();
1168 SwPosition
aPos( aAnchIdx
);
1169 aAnch
.SetAnchor( &aPos
);
1170 pNewSet
->Put( aAnch
);
1174 pUndo
->SetFlys( *pOldFormat
, *pNewSet
, *pNewFormat
);
1175 // #i26791# - position no longer needed
1176 pUndo
->SetDrawObj( nLayerId
);
1179 pOldFormat
->SetFormatAttr( *pNewSet
);
1183 // Have only the FlyFrames created.
1184 // We leave this to established methods (especially for InCntFlys).
1185 pNewFormat
->MakeFrames();
1187 OSL_ENSURE( pNew
, "No Label inserted" );
1191 //#i61007# order of captions
1192 bool bOrderNumberingFirst
= SW_MOD()->GetModuleConfig()->IsCaptionOrderNumberingFirst();
1196 if( bOrderNumberingFirst
)
1198 aText
= rNumberSeparator
;
1202 aText
+= pType
->GetName();
1203 if( !bOrderNumberingFirst
)
1206 sal_Int32 nIdx
= aText
.getLength();
1207 aText
+= rSeparator
;
1208 const sal_Int32 nSepIdx
= aText
.getLength();
1212 SwContentIndex
aIdx( pNew
, 0 );
1213 pNew
->InsertText( aText
, aIdx
);
1218 SwSetExpField
aField( static_cast<SwSetExpFieldType
*>(pType
), OUString(), SVX_NUM_ARABIC
);
1219 if( bOrderNumberingFirst
)
1221 SwFormatField
aFormat( aField
);
1222 pNew
->InsertItem( aFormat
, nIdx
, nIdx
);
1223 if ( !rCharacterStyle
.isEmpty() )
1225 SwCharFormat
* pCharFormat
= rDoc
.FindCharFormatByName(rCharacterStyle
);
1228 const sal_uInt16 nMyId
= SwStyleNameMapper::GetPoolIdFromUIName( rCharacterStyle
, SwGetPoolIdFromName::ChrFmt
);
1229 pCharFormat
= rDoc
.getIDocumentStylePoolAccess().GetCharFormatFromPool( nMyId
);
1233 SwFormatCharFormat
aCharFormat( pCharFormat
);
1234 pNew
->InsertItem( aCharFormat
, 0, nSepIdx
+ 1,
1235 SetAttrMode::DONTEXPAND
);
1244 SwFlyFrameFormat
* SwDoc::InsertDrawLabel(
1245 OUString
const& rText
,
1246 OUString
const& rSeparator
,
1247 OUString
const& rNumberSeparator
,
1248 sal_uInt16
const nId
,
1249 OUString
const& rCharacterStyle
,
1250 SdrObject
& rSdrObj
)
1252 SwDrawContact
*const pContact
=
1253 static_cast<SwDrawContact
*>(GetUserCall( &rSdrObj
));
1256 OSL_ENSURE( RES_DRAWFRMFMT
== pContact
->GetFormat()->Which(),
1257 "InsertDrawLabel(): not a DrawFrameFormat" );
1259 SwDrawFrameFormat
* pOldFormat
= static_cast<SwDrawFrameFormat
*>(pContact
->GetFormat());
1263 std::unique_ptr
<SwUndoInsertLabel
> pUndo
;
1264 if (GetIDocumentUndoRedo().DoesUndo())
1266 GetIDocumentUndoRedo().ClearRedo();
1267 pUndo
.reset(new SwUndoInsertLabel(
1268 SwLabelType::Draw
, rText
, rSeparator
, rNumberSeparator
, false,
1269 nId
, rCharacterStyle
, false, this ));
1272 SwFlyFrameFormat
*const pNewFormat
= lcl_InsertDrawLabel(
1273 *this, mpTextFormatCollTable
.get(), pUndo
.get(), pOldFormat
,
1274 rText
, rSeparator
, rNumberSeparator
, nId
, rCharacterStyle
, rSdrObj
);
1278 GetIDocumentUndoRedo().AppendUndo( std::move(pUndo
) );
1282 GetIDocumentUndoRedo().DelAllUndoObj();
1288 static void lcl_collectUsedNums(std::vector
<unsigned int>& rSetFlags
, sal_Int32 nNmLen
, std::u16string_view rName
, std::u16string_view rCmpName
)
1290 if (o3tl::starts_with(rName
, rCmpName
))
1292 // Only get and set the Flag
1293 const sal_Int32 nNum
= o3tl::toInt32(rName
.substr(nNmLen
)) - 1;
1295 rSetFlags
.push_back(nNum
);
1299 static void lcl_collectUsedNums(std::vector
<unsigned int>& rSetFlags
, sal_Int32 nNmLen
, const SdrObject
& rObj
, const OUString
& rCmpName
)
1301 OUString sName
= rObj
.GetName();
1302 lcl_collectUsedNums(rSetFlags
, nNmLen
, sName
, rCmpName
);
1303 // tdf#122487 take groups into account, iterate and recurse through their
1304 // contents for name collision check
1305 if (!rObj
.IsGroupObject())
1308 const SdrObjList
* pSub(rObj
.GetSubList());
1309 assert(pSub
&& "IsGroupObject is implemented as GetSubList != nullptr");
1310 const size_t nCount
= pSub
->GetObjCount();
1311 for (size_t i
= 0; i
< nCount
; ++i
)
1313 SdrObject
* pObj
= pSub
->GetObj(i
);
1316 lcl_collectUsedNums(rSetFlags
, nNmLen
, *pObj
, rCmpName
);
1322 int first_available_number(std::vector
<unsigned int>& numbers
)
1324 std::sort(numbers
.begin(), numbers
.end());
1325 auto last
= std::unique(numbers
.begin(), numbers
.end());
1326 numbers
.erase(last
, numbers
.end());
1328 for (size_t i
= 0; i
< numbers
.size(); ++i
)
1330 if (numbers
[i
] != i
)
1334 return numbers
.size();
1338 static OUString
lcl_GetUniqueFlyName(const SwDoc
& rDoc
, TranslateId pDefStrId
, sal_uInt16 eType
, std::u16string_view rPrefix
= std::u16string_view(), SwNodeType nNdTyp
= SwNodeType::NONE
)
1340 assert(eType
>= RES_FMT_BEGIN
&& eType
< RES_FMT_END
);
1341 if (rDoc
.IsInMailMerge())
1343 OUString newName
= "MailMergeFly"
1344 + OStringToOUString( DateTimeToOString( DateTime( DateTime::SYSTEM
)), RTL_TEXTENCODING_ASCII_US
)
1345 + OUString::number( rDoc
.GetSpzFrameFormats()->size() + 1 );
1349 if (!rPrefix
.empty())
1351 // Generate a name that makes it possible to know this is a copy of which original name,
1352 // e.g. 'Picture 1 Copy 1'.
1353 assert(nNdTyp
!= SwNodeType::NONE
);
1355 OUString aPrefix
= SwResId(STR_MARK_COPY
).replaceFirst("%1", rPrefix
);
1357 while(nCnt
< SAL_MAX_INT32
)
1359 aTmp
= aPrefix
+ OUString::number(nCnt
);
1361 if (!rDoc
.FindFlyByName(aTmp
, nNdTyp
))
1369 OUString
aName(SwResId(pDefStrId
));
1370 sal_Int32 nNmLen
= aName
.getLength();
1372 std::vector
<unsigned int> aUsedNums
;
1373 aUsedNums
.reserve(rDoc
.GetSpzFrameFormats()->size());
1375 for(sw::SpzFrameFormat
* pFlyFormat
: *rDoc
.GetSpzFrameFormats())
1377 if (eType
!= pFlyFormat
->Which())
1379 if (eType
== RES_DRAWFRMFMT
)
1381 const SdrObject
*pObj
= pFlyFormat
->FindSdrObject();
1383 lcl_collectUsedNums(aUsedNums
, nNmLen
, *pObj
, aName
);
1386 OUString sName
= pFlyFormat
->GetName();
1387 lcl_collectUsedNums(aUsedNums
, nNmLen
, sName
, aName
);
1390 // All numbers are flagged accordingly, so determine the right one
1391 auto nNum
= first_available_number(aUsedNums
) + 1;
1392 return aName
+ OUString::number(nNum
);
1395 OUString
SwDoc::GetUniqueGrfName(std::u16string_view rPrefix
) const
1397 return lcl_GetUniqueFlyName(*this, STR_GRAPHIC_DEFNAME
, RES_FLYFRMFMT
, rPrefix
, SwNodeType::Grf
);
1400 OUString
SwDoc::GetUniqueOLEName() const
1402 return lcl_GetUniqueFlyName(*this, STR_OBJECT_DEFNAME
, RES_FLYFRMFMT
);
1405 OUString
SwDoc::GetUniqueFrameName() const
1407 return lcl_GetUniqueFlyName(*this, STR_FRAME_DEFNAME
, RES_FLYFRMFMT
);
1410 OUString
SwDoc::GetUniqueShapeName() const
1412 return lcl_GetUniqueFlyName(*this, STR_SHAPE_DEFNAME
, RES_DRAWFRMFMT
);
1415 OUString
SwDoc::GetUniqueDrawObjectName() const
1417 return lcl_GetUniqueFlyName(*this, TranslateId(nullptr, "DrawObject"), RES_DRAWFRMFMT
);
1420 const SwFlyFrameFormat
* SwDoc::FindFlyByName( const OUString
& rName
, SwNodeType nNdTyp
) const
1422 auto it
= GetSpzFrameFormats()->findByTypeAndName( RES_FLYFRMFMT
, rName
);
1423 if( it
== GetSpzFrameFormats()->typeAndNameEnd() )
1426 const SwFrameFormat
* pFlyFormat
= *it
;
1427 assert( RES_FLYFRMFMT
== pFlyFormat
->Which() && pFlyFormat
->GetName() == rName
);
1428 const SwNodeIndex
* pIdx
= pFlyFormat
->GetContent().GetContentIdx();
1429 if( pIdx
&& pIdx
->GetNode().GetNodes().IsDocNodes() )
1431 if( nNdTyp
!= SwNodeType::NONE
)
1433 // query for the right NodeType
1434 const SwNode
* pNd
= GetNodes()[ pIdx
->GetIndex()+1 ];
1435 if( nNdTyp
== SwNodeType::Text
1436 ? !pNd
->IsNoTextNode()
1437 : nNdTyp
== pNd
->GetNodeType() )
1438 return static_cast<const SwFlyFrameFormat
*>(pFlyFormat
);
1441 return static_cast<const SwFlyFrameFormat
*>(pFlyFormat
);
1446 void SwDoc::SetFlyName( SwFlyFrameFormat
& rFormat
, const OUString
& rName
)
1448 if (rFormat
.GetName() == rName
)
1452 OUString
sName( rName
);
1453 if( sName
.isEmpty() || FindFlyByName( sName
) )
1455 TranslateId pTyp
= STR_FRAME_DEFNAME
;
1456 const SwNodeIndex
* pIdx
= rFormat
.GetContent().GetContentIdx();
1457 if( pIdx
&& pIdx
->GetNode().GetNodes().IsDocNodes() )
1459 switch( GetNodes()[ pIdx
->GetIndex() + 1 ]->GetNodeType() )
1461 case SwNodeType::Grf
:
1462 pTyp
= STR_GRAPHIC_DEFNAME
;
1464 case SwNodeType::Ole
:
1465 pTyp
= STR_OBJECT_DEFNAME
;
1470 sName
= lcl_GetUniqueFlyName(*this, pTyp
, RES_FLYFRMFMT
);
1472 rFormat
.SetFormatName( sName
, true );
1473 getIDocumentState().SetModified();
1476 void SwDoc::SetAllUniqueFlyNames()
1478 sal_Int32 n
, nFlyNum
= 0, nGrfNum
= 0, nOLENum
= 0;
1480 const OUString
sFlyNm(SwResId(STR_FRAME_DEFNAME
));
1481 const OUString
sGrfNm(SwResId(STR_GRAPHIC_DEFNAME
));
1482 const OUString
sOLENm(SwResId(STR_OBJECT_DEFNAME
));
1484 n
= GetSpzFrameFormats()->size();
1487 SwFrameFormatsV aArr
;
1489 SwFrameFormat
* pFlyFormat
;
1490 bool bContainsAtPageObjWithContentAnchor
= false;
1492 for( n
= GetSpzFrameFormats()->size(); n
; )
1494 pFlyFormat
= (*GetSpzFrameFormats())[ --n
];
1495 if( RES_FLYFRMFMT
== pFlyFormat
->Which() )
1497 const OUString
& aNm
= pFlyFormat
->GetName();
1498 if ( !aNm
.isEmpty() )
1500 sal_Int32
*pNum
= nullptr;
1502 if ( aNm
.startsWith(sGrfNm
) )
1504 nLen
= sGrfNm
.getLength();
1507 else if( aNm
.startsWith(sFlyNm
) )
1509 nLen
= sFlyNm
.getLength();
1512 else if( aNm
.startsWith(sOLENm
) )
1514 nLen
= sOLENm
.getLength();
1520 const sal_Int32 nNewLen
= o3tl::toInt32(aNm
.subView( nLen
));
1521 if (*pNum
< nNewLen
)
1526 // we want to set that afterwards
1527 aArr
.push_back( pFlyFormat
);
1530 if ( !bContainsAtPageObjWithContentAnchor
)
1532 const SwFormatAnchor
& rAnchor
= pFlyFormat
->GetAnchor();
1533 if ( (RndStdIds::FLY_AT_PAGE
== rAnchor
.GetAnchorId()) &&
1534 rAnchor
.GetAnchorNode() )
1536 bContainsAtPageObjWithContentAnchor
= true;
1540 SetContainsAtPageObjWithContentAnchor( bContainsAtPageObjWithContentAnchor
);
1542 for( n
= aArr
.size(); n
; )
1544 pFlyFormat
= aArr
[ --n
];
1545 const SwNodeIndex
* pIdx
= pFlyFormat
->GetContent().GetContentIdx();
1546 if( pIdx
&& pIdx
->GetNode().GetNodes().IsDocNodes() )
1548 switch( GetNodes()[ pIdx
->GetIndex() + 1 ]->GetNodeType() )
1550 case SwNodeType::Grf
:
1551 pFlyFormat
->SetFormatName( sGrfNm
+ OUString::number( ++nGrfNum
));
1553 case SwNodeType::Ole
:
1554 pFlyFormat
->SetFormatName( sOLENm
+ OUString::number( ++nOLENum
));
1557 pFlyFormat
->SetFormatName( sFlyNm
+ OUString::number( ++nFlyNum
));
1564 if( GetFootnoteIdxs().empty() )
1567 SwTextFootnote::SetUniqueSeqRefNo( *this );
1568 // #i52775# Chapter footnotes did not get updated correctly.
1569 // Calling UpdateAllFootnote() instead of UpdateFootnote() solves this problem,
1570 // but I do not dare to call UpdateAllFootnote() in all cases: Safety first.
1571 if ( FTNNUM_CHAPTER
== GetFootnoteInfo().m_eNum
)
1573 GetFootnoteIdxs().UpdateAllFootnote();
1577 SwNodeIndex
aTmp( GetNodes() );
1578 GetFootnoteIdxs().UpdateFootnote( aTmp
.GetNode() );
1582 bool SwDoc::IsInHeaderFooter( const SwNode
& rIdx
) const
1584 // That can also be a Fly in a Fly in the Header.
1585 // Is also used by sw3io, to determine if a Redline object is
1586 // in the Header or Footer.
1587 // Because Redlines are also attached to Start and EndNode,
1588 // the Index must not necessarily be from a ContentNode.
1589 const SwNode
* pNd
= &rIdx
;
1590 const SwNode
* pFlyNd
= pNd
->FindFlyStartNode();
1593 // get up by using the Anchor
1594 #if OSL_DEBUG_LEVEL > 0
1595 std::vector
<const SwFrameFormat
*> checkFormats
;
1596 for(sw::SpzFrameFormat
* pFormat
: *GetSpzFrameFormats())
1598 const SwNodeIndex
* pIdx
= pFormat
->GetContent().GetContentIdx();
1599 if( pIdx
&& pFlyNd
== &pIdx
->GetNode() )
1600 checkFormats
.push_back( pFormat
);
1603 std::vector
<SwFrameFormat
*> const & rFlys(pFlyNd
->GetAnchoredFlys());
1605 for (size_t i
= 0; i
< rFlys
.size(); ++i
)
1607 const SwFrameFormat
*const pFormat
= rFlys
[i
];
1608 const SwNodeIndex
* pIdx
= pFormat
->GetContent().GetContentIdx();
1609 if( pIdx
&& pFlyNd
== &pIdx
->GetNode() )
1611 #if OSL_DEBUG_LEVEL > 0
1612 auto checkPos
= std::find(
1613 checkFormats
.begin(), checkFormats
.end(), pFormat
);
1614 assert( checkPos
!= checkFormats
.end());
1615 checkFormats
.erase( checkPos
);
1617 const SwFormatAnchor
& rAnchor
= pFormat
->GetAnchor();
1618 if ((RndStdIds::FLY_AT_PAGE
== rAnchor
.GetAnchorId()) ||
1619 !rAnchor
.GetAnchorNode() )
1624 pNd
= rAnchor
.GetAnchorNode();
1625 pFlyNd
= pNd
->FindFlyStartNode();
1632 OSL_ENSURE(mbInReading
, "Found a FlySection but not a Format!");
1637 return nullptr != pNd
->FindHeaderStartNode() ||
1638 nullptr != pNd
->FindFooterStartNode();
1641 SvxFrameDirection
SwDoc::GetTextDirection( const SwPosition
& rPos
,
1642 const Point
* pPt
) const
1644 SvxFrameDirection nRet
= SvxFrameDirection::Unknown
;
1646 SwContentNode
*pNd
= rPos
.GetNode().GetContentNode();
1648 // #i42921# - use new method <SwContentNode::GetTextDirection(..)>
1651 nRet
= pNd
->GetTextDirection( rPos
, pPt
);
1653 if ( nRet
== SvxFrameDirection::Unknown
)
1655 const SvxFrameDirectionItem
* pItem
= nullptr;
1658 // Are we in a FlyFrame? Then look at that for the correct attribute
1659 const SwFrameFormat
* pFlyFormat
= pNd
->GetFlyFormat();
1662 pItem
= &pFlyFormat
->GetFrameDir();
1663 if( SvxFrameDirection::Environment
== pItem
->GetValue() )
1666 const SwFormatAnchor
* pAnchor
= &pFlyFormat
->GetAnchor();
1667 if ((RndStdIds::FLY_AT_PAGE
!= pAnchor
->GetAnchorId()) &&
1668 pAnchor
->GetAnchorNode())
1670 pFlyFormat
= pAnchor
->GetAnchorNode()->GetFlyFormat();
1673 pFlyFormat
= nullptr;
1676 pFlyFormat
= nullptr;
1681 const SwPageDesc
* pPgDsc
= pNd
->FindPageDesc();
1683 pItem
= &pPgDsc
->GetMaster().GetFrameDir();
1687 pItem
= &GetAttrPool().GetDefaultItem( RES_FRAMEDIR
);
1688 nRet
= pItem
->GetValue();
1693 bool SwDoc::IsInVerticalText( const SwPosition
& rPos
) const
1695 const SvxFrameDirection nDir
= GetTextDirection( rPos
);
1696 return SvxFrameDirection::Vertical_RL_TB
== nDir
|| SvxFrameDirection::Vertical_LR_TB
== nDir
;
1699 o3tl::sorted_vector
<SwRootFrame
*> SwDoc::GetAllLayouts()
1701 o3tl::sorted_vector
<SwRootFrame
*> aAllLayouts
;
1702 SwViewShell
*pStart
= getIDocumentLayoutAccess().GetCurrentViewShell();
1705 for(const SwViewShell
& rShell
: pStart
->GetRingContainer())
1707 if(rShell
.GetLayout())
1708 aAllLayouts
.insert(rShell
.GetLayout());
1714 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */