xref: /core/sw/source/core/doc/doclay.cxx (revision 589bce37)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
33 #include <istype.hxx>
34 #include <swmodule.hxx>
35 #include <modcfg.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>
41 #include <frmatr.hxx>
42 #include <txatbase.hxx>
43 #include <fmtfld.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>
50 #include <frmfmt.hxx>
51 #include <pam.hxx>
52 #include <ndtxt.hxx>
53 #include <ndnotxt.hxx>
54 #include <ndole.hxx>
55 #include <doc.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>
66 #include <cntfrm.hxx>
67 #include <txtfrm.hxx>
68 #include <notxtfrm.hxx>
69 #include <dflyobj.hxx>
70 #include <dcontact.hxx>
71 #include <swundo.hxx>
72 #include <flypos.hxx>
73 #include <UndoInsert.hxx>
74 #include <expfld.hxx>
75 #include <poolfmt.hxx>
76 #include <docary.hxx>
77 #include <swtable.hxx>
78 #include <tblsel.hxx>
79 #include <txtftn.hxx>
80 #include <ftnidx.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>
88 
89 #include <sortedobjs.hxx>
90 
91 #include <string_view>
92 #include <vector>
93 
94 using namespace ::com::sun::star;
95 
96 #define DEF_FLY_WIDTH    2268   // Default width for FlyFrames (2268 == 4cm)
97 
lcl_IsItemSet(const SwContentNode & rNode,sal_uInt16 which)98 static bool lcl_IsItemSet(const SwContentNode & rNode, sal_uInt16 which)
99 {
100     bool bResult = false;
101 
102     if (SfxItemState::SET == rNode.GetSwAttrSet().GetItemState(which))
103         bResult = true;
104 
105     return bResult;
106 }
107 
CloneSdrObj(const SdrObject & rObj,bool bMoveWithinDoc,bool bInsInPage)108 rtl::Reference<SdrObject> SwDoc::CloneSdrObj( const SdrObject& rObj, bool bMoveWithinDoc,
109                                 bool bInsInPage )
110 {
111     // #i52858# - method name changed
112     SdrPage *pPg = getIDocumentDrawModelAccess().GetOrCreateDrawModel()->GetPage( 0 );
113     if( !pPg )
114     {
115         auto pNewPage = getIDocumentDrawModelAccess().GetDrawModel()->AllocPage( false );
116         getIDocumentDrawModelAccess().GetDrawModel()->InsertPage( pNewPage.get() );
117         pPg = pNewPage.get();
118     }
119 
120     // TTTT Clone directly to target SdrModel
121     rtl::Reference<SdrObject> pObj(rObj.CloneSdrObject(*getIDocumentDrawModelAccess().GetDrawModel()));
122 
123     if( bMoveWithinDoc && SdrInventor::FmForm == pObj->GetObjInventor() )
124     {
125         // We need to preserve the Name for Controls
126         uno::Reference< awt::XControlModel >  xModel = static_cast<SdrUnoObj*>(pObj.get())->GetUnoControlModel();
127         uno::Any aVal;
128         uno::Reference< beans::XPropertySet >  xSet(xModel, uno::UNO_QUERY);
129         static constexpr OUString sName(u"Name"_ustr);
130         if( xSet.is() )
131             aVal = xSet->getPropertyValue( sName );
132         if( bInsInPage )
133             pPg->InsertObjectThenMakeNameUnique( pObj.get() );
134         if( xSet.is() )
135             xSet->setPropertyValue( sName, aVal );
136     }
137     else if( bInsInPage )
138         pPg->InsertObjectThenMakeNameUnique( pObj.get() );
139 
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 )
145     {
146         if ( getIDocumentDrawModelAccess().IsVisibleLayerId( nLayerIdForClone ) )
147         {
148             nLayerIdForClone = getIDocumentDrawModelAccess().GetInvisibleLayerIdByVisibleOne( nLayerIdForClone );
149         }
150     }
151     pObj->SetLayer( nLayerIdForClone );
152 
153     return pObj;
154 }
155 
MakeFlySection_(const SwPosition & rAnchPos,const SwContentNode & rNode,RndStdIds eRequestId,const SfxItemSet * pFlySet,SwFrameFormat * pFrameFormat)156 SwFlyFrameFormat* SwDoc::MakeFlySection_( const SwPosition& rAnchPos,
157                                     const SwContentNode& rNode,
158                                     RndStdIds eRequestId,
159                                     const SfxItemSet* pFlySet,
160                                     SwFrameFormat* pFrameFormat )
161 {
162     if( !pFrameFormat )
163         pFrameFormat = getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME );
164 
165     OUString sName;
166     switch( rNode.GetNodeType() )
167     {
168         case SwNodeType::Grf:        sName = GetUniqueGrfName();     break;
169         case SwNodeType::Ole:        sName = GetUniqueOLEName();     break;
170         default:                sName = GetUniqueFrameName();   break;
171     }
172     SwFlyFrameFormat* pFormat = MakeFlyFrameFormat( sName, pFrameFormat );
173 
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 );
179 
180     pFormat->SetFormatAttr( SwFormatContent( rNode.StartOfSectionNode() ));
181 
182     const SwFormatAnchor* pAnchor = nullptr;
183     if( pFlySet )
184     {
185         pAnchor = pFlySet->GetItemIfSet( RES_ANCHOR, false );
186         if( SfxItemState::SET == pFlySet->GetItemState( RES_CNTNT, false ))
187         {
188             SfxItemSet aTmpSet( *pFlySet );
189             aTmpSet.ClearItem( RES_CNTNT );
190             pFormat->SetFormatAttr( aTmpSet );
191         }
192         else
193             pFormat->SetFormatAttr( *pFlySet );
194     }
195 
196     // Anchor not yet set?
197     RndStdIds eAnchorId;
198     // #i107811# Assure that at-page anchored fly frames have a page num or a
199     // content anchor set.
200     if ( !pAnchor ||
201          ( RndStdIds::FLY_AT_PAGE != pAnchor->GetAnchorId() &&
202            !pAnchor->GetAnchorNode() ) ||
203          ( RndStdIds::FLY_AT_PAGE == pAnchor->GetAnchorId() &&
204            !pAnchor->GetAnchorNode() &&
205            pAnchor->GetPageNum() == 0 ) )
206     {
207         // set it again, needed for Undo
208         SwFormatAnchor aAnch( pFormat->GetAnchor() );
209         if (pAnchor && (RndStdIds::FLY_AT_FLY == pAnchor->GetAnchorId()))
210         {
211             const SwNode* pFlyStartNode = rAnchPos.GetNode().FindFlyStartNode();
212             assert(pFlyStartNode);
213             SwPosition aPos(*pFlyStartNode);
214             aAnch.SetAnchor(&aPos);
215             eAnchorId = RndStdIds::FLY_AT_FLY;
216         }
217         else
218         {
219             if( eRequestId != aAnch.GetAnchorId() &&
220                 SfxItemState::SET != pFormat->GetItemState( RES_ANCHOR ) )
221             {
222                 aAnch.SetType( eRequestId );
223             }
224 
225             eAnchorId = aAnch.GetAnchorId();
226             if ( RndStdIds::FLY_AT_PAGE != eAnchorId || !pAnchor || aAnch.GetPageNum() == 0)
227             {
228                 aAnch.SetAnchor( &rAnchPos );
229             }
230         }
231         pFormat->SetFormatAttr( aAnch );
232     }
233     else
234         eAnchorId = pFormat->GetAnchor().GetAnchorId();
235 
236     if ( RndStdIds::FLY_AS_CHAR == eAnchorId )
237     {
238         const sal_Int32 nStt = rAnchPos.GetContentIndex();
239         SwTextNode * pTextNode = rAnchPos.GetNode().GetTextNode();
240 
241         OSL_ENSURE(pTextNode!= nullptr, "There should be a SwTextNode!");
242 
243         if (pTextNode != nullptr)
244         {
245             SwFormatFlyCnt aFormat( pFormat );
246             // may fail if there's no space left or header/ftr
247             if (!pTextNode->InsertItem(aFormat, nStt, nStt))
248             {   // pFormat is dead now
249                 return nullptr;
250             }
251         }
252     }
253 
254     if( SfxItemState::SET != pFormat->GetAttrSet().GetItemState( RES_FRM_SIZE ))
255     {
256         SwFormatFrameSize aFormatSize( SwFrameSize::Variable, 0, DEF_FLY_WIDTH );
257         const SwNoTextNode* pNoTextNode = rNode.GetNoTextNode();
258         if( pNoTextNode )
259         {
260             // Set size
261             Size aSize( pNoTextNode->GetTwipSize() );
262             if( MINFLY > aSize.Width() )
263                 aSize.setWidth( DEF_FLY_WIDTH );
264             aFormatSize.SetWidth( aSize.Width() );
265             if( aSize.Height() )
266             {
267                 aFormatSize.SetHeight( aSize.Height() );
268                 aFormatSize.SetHeightSizeType( SwFrameSize::Fixed );
269             }
270         }
271         pFormat->SetFormatAttr( aFormatSize );
272     }
273 
274     // Set up frames
275     if( getIDocumentLayoutAccess().GetCurrentViewShell() )
276         pFormat->MakeFrames();           // ???
277 
278     if (GetIDocumentUndoRedo().DoesUndo())
279     {
280         SwNodeOffset nNodeIdx = rAnchPos.GetNodeIndex();
281         const sal_Int32 nCntIdx = rAnchPos.GetContentIndex();
282         GetIDocumentUndoRedo().AppendUndo(
283             std::make_unique<SwUndoInsLayFormat>( pFormat, nNodeIdx, nCntIdx ));
284     }
285 
286     getIDocumentState().SetModified();
287     return pFormat;
288 }
289 
MakeFlySection(RndStdIds eAnchorType,const SwPosition * pAnchorPos,const SfxItemSet * pFlySet,SwFrameFormat * pFrameFormat,bool bCalledFromShell)290 SwFlyFrameFormat* SwDoc::MakeFlySection( RndStdIds eAnchorType,
291                                     const SwPosition* pAnchorPos,
292                                     const SfxItemSet* pFlySet,
293                                     SwFrameFormat* pFrameFormat, bool bCalledFromShell )
294 {
295     SwFlyFrameFormat* pFormat = nullptr;
296     if ( !pAnchorPos && (RndStdIds::FLY_AT_PAGE != eAnchorType) )
297     {
298         const SwFormatAnchor* pAnch;
299         if( (pFlySet && (pAnch = pFlySet->GetItemIfSet( RES_ANCHOR, false ))) ||
300             ( pFrameFormat && (pAnch = pFrameFormat->GetItemIfSet(RES_ANCHOR)) ) )
301         {
302             if ( RndStdIds::FLY_AT_PAGE != pAnch->GetAnchorId() )
303             {
304                 pAnchorPos = pAnch->GetContentAnchor();
305             }
306         }
307     }
308 
309     if (pAnchorPos)
310     {
311         if( !pFrameFormat )
312             pFrameFormat = getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME );
313 
314         sal_uInt16 nCollId = o3tl::narrowing<sal_uInt16>(
315             GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE) ? RES_POOLCOLL_TEXT : RES_POOLCOLL_FRAME );
316 
317         /* If there is no adjust item in the paragraph style for the content node of the new fly section
318            propagate an existing adjust item at the anchor to the new content node. */
319         SwContentNode * pNewTextNd = GetNodes().MakeTextNode
320             ( GetNodes().GetEndOfAutotext(),
321              getIDocumentStylePoolAccess().GetTextCollFromPool( nCollId ));
322         SwContentNode * pAnchorNode = pAnchorPos->GetNode().GetContentNode();
323         // pAnchorNode from cursor must be valid, unless a whole table is selected (in which
324         // case the node is not a content node, and pAnchorNode is nullptr). In the latter case,
325         // bCalledFromShell is false.
326         assert(!bCalledFromShell || pAnchorNode);
327 
328         const SfxPoolItem * pItem = nullptr;
329 
330         if (bCalledFromShell && !lcl_IsItemSet(*pNewTextNd, RES_PARATR_ADJUST) &&
331             SfxItemState::SET == pAnchorNode->GetSwAttrSet().GetItemState(RES_PARATR_ADJUST, true, &pItem))
332         {
333             pNewTextNd->SetAttr(*pItem);
334         }
335 
336         pFormat = MakeFlySection_( *pAnchorPos, *pNewTextNd,
337                                 eAnchorType, pFlySet, pFrameFormat );
338     }
339     return pFormat;
340 }
341 
MakeFlyAndMove(const SwPaM & rPam,const SfxItemSet & rSet,const SwSelBoxes * pSelBoxes,SwFrameFormat * pParent)342 SwFlyFrameFormat* SwDoc::MakeFlyAndMove( const SwPaM& rPam, const SfxItemSet& rSet,
343                                     const SwSelBoxes* pSelBoxes,
344                                     SwFrameFormat *pParent )
345 {
346     const SwFormatAnchor& rAnch = rSet.Get( RES_ANCHOR );
347 
348     GetIDocumentUndoRedo().StartUndo( SwUndoId::INSLAYFMT, nullptr );
349 
350     SwFlyFrameFormat* pFormat = MakeFlySection( rAnch.GetAnchorId(), rPam.GetPoint(),
351                                         &rSet, pParent );
352 
353     // If content is selected, it becomes the new frame's content.
354     // Namely, it is moved into the NodeArray's appropriate section.
355 
356     if( pFormat )
357     {
358         do {        // middle check loop
359             const SwFormatContent &rContent = pFormat->GetContent();
360             OSL_ENSURE( rContent.GetContentIdx(), "No content prepared." );
361             SwNodeIndex aIndex( *(rContent.GetContentIdx()), 1 );
362 
363             // Attention: Do not create an index on the stack, or we
364             // cannot delete ContentNode in the end!
365             std::optional<SwPosition> oPos( std::in_place, aIndex );
366 
367             if( pSelBoxes && !pSelBoxes->empty() )
368             {
369                 // Table selection
370                 // Copy parts of a table: create a table with the same width as the
371                 // original one and move (copy and delete) the selected boxes.
372                 // The size is corrected on a percentage basis.
373 
374                 SwTableNode* pTableNd = const_cast<SwTableNode*>((*pSelBoxes)[0]->
375                                                 GetSttNd()->FindTableNode());
376                 if( !pTableNd )
377                     break;
378 
379                 SwTable& rTable = pTableNd->GetTable();
380 
381                 // Did we select the whole table?
382                 if( pSelBoxes->size() == rTable.GetTabSortBoxes().size() )
383                 {
384                     // move the whole table
385                     SwNodeRange aRg( *pTableNd, SwNodeOffset(0), *pTableNd->EndOfSectionNode(), SwNodeOffset(1) );
386 
387                     // If we move the whole table and it is located within a
388                     // FlyFrame, the we create a TextNode after it.
389                     // So that this FlyFrame is preserved.
390                     if( aRg.aEnd.GetNode().IsEndNode() )
391                         GetNodes().MakeTextNode( aRg.aStart.GetNode(),
392                                     GetDfltTextFormatColl() );
393 
394                     // Create undo actions if undo is enabled.
395                     getIDocumentContentOperations().MoveNodeRange( aRg, oPos->GetNode(), SwMoveFlags::CREATEUNDOOBJ );
396                 }
397                 else
398                 {
399                     rTable.MakeCopy(*this, *oPos, *pSelBoxes);
400                     // Don't delete a part of a table with row span!!
401                     // You could delete the content instead -> ToDo
402                     //rTable.DeleteSel( this, *pSelBoxes, 0, 0, true, true );
403                 }
404 
405                 // If the table is within the frame, then copy without the following TextNode
406                 aIndex = rContent.GetContentIdx()->GetNode().EndOfSectionIndex() - 1;
407                 OSL_ENSURE( aIndex.GetNode().GetTextNode(),
408                         "a TextNode should be here" );
409                 oPos.reset();       // Deregister index!
410                 // Delete the empty paragraph after the table, in a way that undo is aware of this.
411                 SwPaM aPaM(aIndex);
412                 getIDocumentContentOperations().DelFullPara(aPaM);
413             }
414             else
415             {
416                 // copy all Pams and then delete all
417                 bool bOldFlag = mbCopyIsMove;
418                 bool const bOldUndo = GetIDocumentUndoRedo().DoesUndo();
419                 bool const bOldRedlineMove(getIDocumentRedlineAccess().IsRedlineMove());
420                 mbCopyIsMove = true;
421                 GetIDocumentUndoRedo().DoUndo(false);
422                 getIDocumentRedlineAccess().SetRedlineMove(true);
423                 for(const SwPaM& rTmp : rPam.GetRingContainer())
424                 {
425                     if( rTmp.HasMark() &&
426                         *rTmp.GetPoint() != *rTmp.GetMark() )
427                     {
428                         // aPos is the newly created fly section, so definitely outside rPam, it's pointless to check that again.
429                         getIDocumentContentOperations().CopyRange(*const_cast<SwPaM*>(&rTmp), *oPos, SwCopyFlags::IsMoveToFly);
430                     }
431                 }
432                 getIDocumentRedlineAccess().SetRedlineMove(bOldRedlineMove);
433                 mbCopyIsMove = bOldFlag;
434                 GetIDocumentUndoRedo().DoUndo(bOldUndo);
435 
436                 for(const SwPaM& rTmp : rPam.GetRingContainer())
437                 {
438                     if( rTmp.HasMark() &&
439                         *rTmp.GetPoint() != *rTmp.GetMark() )
440                     {
441                         getIDocumentContentOperations().DeleteAndJoin( *const_cast<SwPaM*>(&rTmp) );
442                     }
443                 }
444             }
445         } while( false );
446     }
447 
448     getIDocumentState().SetModified();
449 
450     GetIDocumentUndoRedo().EndUndo( SwUndoId::INSLAYFMT, nullptr );
451 
452     return pFormat;
453 }
454 
455 
456 /*
457  * paragraph frames - o.k. if the PaM includes the paragraph from the beginning
458  *                    to the beginning of the next paragraph at least
459  * frames at character - o.k. if the PaM starts at least at the same position
460  *                      as the frame
461  */
lcl_TstFlyRange(const SwPaM * pPam,const SwFormatAnchor & rFlyFormatAnchor)462 static bool lcl_TstFlyRange( const SwPaM* pPam, const SwFormatAnchor& rFlyFormatAnchor )
463 {
464     bool bOk = false;
465     const SwPaM* pTmp = pPam;
466     do {
467         const SwNodeOffset nFlyIndex = rFlyFormatAnchor.GetAnchorNode()->GetIndex();
468         auto [pPaMStart, pPaMEnd] = pTmp->StartEnd(); // SwPosition*
469         const SwNodeOffset nPamStartIndex = pPaMStart->GetNodeIndex();
470         const SwNodeOffset nPamEndIndex = pPaMEnd->GetNodeIndex();
471         if (RndStdIds::FLY_AT_PARA == rFlyFormatAnchor.GetAnchorId())
472             bOk = (nPamStartIndex < nFlyIndex && nPamEndIndex > nFlyIndex) ||
473                (((nPamStartIndex == nFlyIndex) && (pPaMStart->GetContentIndex() == 0)) &&
474                (nPamEndIndex > nFlyIndex));
475         else
476         {
477             const sal_Int32 nFlyContentIndex = rFlyFormatAnchor.GetAnchorContentOffset();
478             const sal_Int32 nPamEndContentIndex = pPaMEnd->GetContentIndex();
479             bOk = (nPamStartIndex < nFlyIndex &&
480                 (( nPamEndIndex > nFlyIndex )||
481                  ((nPamEndIndex == nFlyIndex) &&
482                   (nPamEndContentIndex > nFlyContentIndex))) )
483                 ||
484                        (((nPamStartIndex == nFlyIndex) &&
485                       (pPaMStart->GetContentIndex() <= nFlyContentIndex)) &&
486                      ((nPamEndIndex > nFlyIndex) ||
487                      (nPamEndContentIndex > nFlyContentIndex )));
488         }
489 
490         if( bOk )
491             break;
492         pTmp = pTmp->GetNext();
493     } while( pPam != pTmp );
494     return bOk;
495 }
496 
GetAllFlyFormats(const SwPaM * pCmpRange,bool bDrawAlso,bool bAsCharAlso) const497 SwPosFlyFrames SwDoc::GetAllFlyFormats( const SwPaM* pCmpRange, bool bDrawAlso,
498                            bool bAsCharAlso ) const
499 {
500     SwPosFlyFrames aRetval;
501     const SwStartNode* pDirectFly = nullptr;
502     if (pCmpRange && *pCmpRange->GetPoint() == *pCmpRange->GetMark()
503         && (pCmpRange->GetPoint()->GetNode().IsOLENode()
504             || pCmpRange->GetPoint()->GetNode().IsGrfNode()))
505     {
506         pDirectFly = pCmpRange->GetPoint()->GetNode().FindFlyStartNode();
507     }
508 
509     // collect all anchored somehow to paragraphs
510     for(sw::SpzFrameFormat* pFly: *GetSpzFrameFormats())
511     {
512         bool bDrawFormat = bDrawAlso && RES_DRAWFRMFMT == pFly->Which();
513         bool bFlyFormat = RES_FLYFRMFMT == pFly->Which();
514         if( bFlyFormat || bDrawFormat )
515         {
516             const SwFormatAnchor& rAnchor = pFly->GetAnchor();
517             SwNode const*const pAnchorNode = rAnchor.GetAnchorNode();
518             if (!pAnchorNode)
519                 continue;
520             if (pDirectFly)
521             {
522                 const SwFormatContent& rContent = pFly->GetContent();
523                 const SwNodeIndex* pContentNodeIndex = rContent.GetContentIdx();
524                 if (pContentNodeIndex && pContentNodeIndex->GetIndex() == pDirectFly->GetIndex())
525                 {
526                     aRetval.insert(SwPosFlyFrame(*pAnchorNode, pFly, aRetval.size()));
527                     break;
528                 }
529                 continue;
530             }
531             if ( (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
532                  (RndStdIds::FLY_AT_FLY  == rAnchor.GetAnchorId()) ||
533                  (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
534                  ((RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) && bAsCharAlso) )
535             {
536                 if( pCmpRange && !lcl_TstFlyRange( pCmpRange, rAnchor ))
537                         continue;       // not a valid FlyFrame
538                 aRetval.insert(SwPosFlyFrame(*pAnchorNode, pFly, aRetval.size()));
539             }
540         }
541     }
542 
543     // If we don't have a layout we can't get page anchored FlyFrames.
544     // Also, page anchored FlyFrames are only returned if no range is specified.
545     if( !getIDocumentLayoutAccess().GetCurrentViewShell() || pCmpRange )
546     {
547         return aRetval;
548     }
549 
550     const SwPageFrame *pPage = static_cast<const SwPageFrame*>(getIDocumentLayoutAccess().GetCurrentLayout()->GetLower());
551     while( pPage )
552     {
553         if( pPage->GetSortedObjs() )
554         {
555             const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
556             for(SwAnchoredObject* pAnchoredObj : rObjs)
557             {
558                 if (!bDrawAlso && !pAnchoredObj->DynCastFlyFrame())
559                     continue;
560 
561                 SwFrameFormat* pFly = pAnchoredObj->GetFrameFormat();
562                 const SwFormatAnchor& rAnchor = pFly->GetAnchor();
563                 if ((RndStdIds::FLY_AT_PARA != rAnchor.GetAnchorId()) &&
564                     (RndStdIds::FLY_AT_FLY  != rAnchor.GetAnchorId()) &&
565                     (RndStdIds::FLY_AT_CHAR != rAnchor.GetAnchorId()))
566                 {
567                     const SwContentFrame * pContentFrame = pPage->FindFirstBodyContent();
568                     if ( !pContentFrame )
569                     {
570                         // Oops! An empty page.
571                         // In order not to lose the whole frame (RTF) we
572                         // look for the last Content before the page.
573                         const SwPageFrame *pPrv = static_cast<const SwPageFrame*>(pPage->GetPrev());
574                         while ( !pContentFrame && pPrv )
575                         {
576                             pContentFrame = pPrv->FindFirstBodyContent();
577                             pPrv = static_cast<const SwPageFrame*>(pPrv->GetPrev());
578                         }
579                     }
580                     if ( pContentFrame )
581                     {
582                         const SwNode* pNd( pContentFrame->IsTextFrame()
583                             ? static_cast<SwTextFrame const*>(pContentFrame)->GetTextNodeFirst()
584                             : static_cast<SwNoTextFrame const*>(pContentFrame)->GetNode() );
585                         aRetval.insert(SwPosFlyFrame(*pNd, pFly, aRetval.size()));
586                     }
587                 }
588             }
589         }
590         pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
591     }
592 
593     return aRetval;
594 }
595 
596 /* #i6447# changed behaviour if lcl_CpyAttr:
597 
598    If the old item set contains the item to set (no inheritance) copy the item
599    into the new set.
600 
601    If the old item set contains the item by inheritance and the new set
602    contains the item, too:
603    If the two items differ copy the item from the old set to the new set.
604 
605    Otherwise the new set will not be changed.
606 */
lcl_CpyAttr(SfxItemSet & rNewSet,const SfxItemSet & rOldSet,sal_uInt16 nWhich)607 static void lcl_CpyAttr( SfxItemSet &rNewSet, const SfxItemSet &rOldSet, sal_uInt16 nWhich )
608 {
609     const SfxPoolItem *pOldItem = nullptr;
610 
611     rOldSet.GetItemState( nWhich, false, &pOldItem);
612     if (pOldItem != nullptr)
613         rNewSet.Put( *pOldItem );
614     else
615     {
616         pOldItem = rOldSet.GetItem( nWhich );
617         if (pOldItem != nullptr)
618         {
619             const SfxPoolItem *pNewItem = rNewSet.GetItem( nWhich );
620             if (pNewItem != nullptr)
621             {
622                 if (*pOldItem != *pNewItem)
623                     rNewSet.Put( *pOldItem );
624             }
625             else {
626                 OSL_FAIL("What am I doing here?");
627             }
628         }
629         else {
630             OSL_FAIL("What am I doing here?");
631         }
632     }
633 
634 }
635 
636 static SwFlyFrameFormat *
lcl_InsertLabel(SwDoc & rDoc,SwTextFormatColls * const pTextFormatCollTable,SwUndoInsertLabel * const pUndo,SwLabelType const eType,std::u16string_view rText,std::u16string_view rSeparator,const OUString & rNumberingSeparator,const bool bBefore,const sal_uInt16 nId,const SwNodeOffset nNdIdx,const OUString & rCharacterStyle,const bool bCpyBrd)637 lcl_InsertLabel(SwDoc & rDoc, SwTextFormatColls *const pTextFormatCollTable,
638         SwUndoInsertLabel *const pUndo,
639         SwLabelType const eType, std::u16string_view rText, std::u16string_view rSeparator,
640             const OUString& rNumberingSeparator,
641             const bool bBefore, const sal_uInt16 nId, const SwNodeOffset nNdIdx,
642             const OUString& rCharacterStyle,
643             const bool bCpyBrd )
644 {
645     ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
646 
647     bool bTable = false;    // To save some code.
648 
649     // Get the field first, because we retrieve the TextColl via the field's name
650     OSL_ENSURE( nId == USHRT_MAX  || nId < rDoc.getIDocumentFieldsAccess().GetFieldTypes()->size(),
651             "FieldType index out of bounds." );
652     SwFieldType *pType = (nId != USHRT_MAX) ? (*rDoc.getIDocumentFieldsAccess().GetFieldTypes())[nId].get() : nullptr;
653     OSL_ENSURE(!pType || pType->Which() == SwFieldIds::SetExp, "wrong Id for Label");
654 
655     SwTextFormatColl * pColl = nullptr;
656     if( pType )
657     {
658         for( auto i = pTextFormatCollTable->size(); i; )
659         {
660             if( (*pTextFormatCollTable)[ --i ]->GetName()==pType->GetName() )
661             {
662                 pColl = (*pTextFormatCollTable)[i];
663                 break;
664             }
665         }
666         OSL_ENSURE( pColl, "no text collection found" );
667     }
668 
669     if( !pColl )
670     {
671         pColl = rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_LABEL );
672     }
673 
674     SwTextNode *pNew = nullptr;
675     SwFlyFrameFormat* pNewFormat = nullptr;
676 
677     switch ( eType )
678     {
679         case SwLabelType::Table:
680             bTable = true;
681             [[fallthrough]];
682         case SwLabelType::Fly:
683             // At the FlySection's Beginning/End insert the corresponding Node with its Field.
684             // The Frame is created automatically.
685             {
686                 SwStartNode *pSttNd = rDoc.GetNodes()[nNdIdx]->GetStartNode();
687                 assert(pSttNd && "No StartNode in InsertLabel.");
688                 SwNodeOffset nNode;
689                 if( bBefore )
690                 {
691                     nNode = pSttNd->GetIndex();
692                     if( !bTable )
693                         ++nNode;
694                 }
695                 else
696                 {
697                     nNode = pSttNd->EndOfSectionIndex();
698                     if( bTable )
699                         ++nNode;
700                 }
701 
702                 if( pUndo )
703                     pUndo->SetNodePos( nNode );
704 
705                 // Create Node for labeling paragraph.
706                 SwNodeIndex aIdx( rDoc.GetNodes(), nNode );
707                 pNew = rDoc.GetNodes().MakeTextNode( aIdx.GetNode(), pColl );
708             }
709             break;
710 
711         case SwLabelType::Object:
712             {
713                 // Destroy Frame,
714                 // insert new Frame,
715                 // insert the corresponding Node with Field into the new Frame,
716                 // insert the old Frame with the Object (Picture/OLE) paragraph-bound into the new Frame,
717                 // create Frames.
718 
719                 // Get the FlyFrame's Format and decouple the Layout.
720                 SwFrameFormat *pOldFormat = rDoc.GetNodes()[nNdIdx]->GetFlyFormat();
721                 OSL_ENSURE( pOldFormat, "Couldn't find the Fly's Format." );
722                 // #i115719#
723                 // <title> and <description> attributes are lost when calling <DelFrames()>.
724                 // Thus, keep them and restore them after the calling <MakeFrames()>
725                 auto pOldFlyFrameFormat = dynamic_cast<SwFlyFrameFormat*>(pOldFormat);
726                 const OUString sTitle( pOldFlyFrameFormat
727                                      ? pOldFlyFrameFormat->GetObjTitle()
728                                      : OUString() );
729                 const OUString sDescription( pOldFlyFrameFormat
730                                            ? pOldFlyFrameFormat->GetObjDescription()
731                                            : OUString() );
732                 pOldFormat->DelFrames();
733 
734                 pNewFormat = rDoc.MakeFlyFrameFormat( rDoc.GetUniqueFrameName(),
735                                 rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool(RES_POOLFRM_FRAME) );
736 
737                 /* #i6447#: Only the selected items are copied from the old
738                    format. */
739                 SwAttrSet aNewSet = pNewFormat->GetAttrSet().CloneAsValue();
740 
741                 // Copy only the set attributes.
742                 // The others should apply from the Templates.
743                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_PRINT );
744                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_OPAQUE );
745                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_PROTECT );
746                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_SURROUND );
747                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_VERT_ORIENT );
748                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_HORI_ORIENT );
749                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_LR_SPACE );
750                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_UL_SPACE );
751                 lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_BACKGROUND );
752                 if( bCpyBrd )
753                 {
754                     // If there's no BoxItem at graphic, but the new Format has one, then set the
755                     // default item in the new Set. Because the graphic's size has never changed!
756                     const SfxPoolItem *pItem;
757                     if( SfxItemState::SET == pOldFormat->GetAttrSet().
758                             GetItemState( RES_BOX, true, &pItem ))
759                         aNewSet.Put( *pItem );
760                     else if( SfxItemState::SET == pNewFormat->GetAttrSet().
761                             GetItemState( RES_BOX ))
762                         aNewSet.Put( *GetDfltAttr( RES_BOX ) );
763 
764                     if( SfxItemState::SET == pOldFormat->GetAttrSet().
765                             GetItemState( RES_SHADOW, true, &pItem ))
766                         aNewSet.Put( *pItem );
767                     else if( SfxItemState::SET == pNewFormat->GetAttrSet().
768                             GetItemState( RES_SHADOW ))
769                         aNewSet.Put( *GetDfltAttr( RES_SHADOW ) );
770                 }
771                 else
772                 {
773                     // Hard-set the attributes, because they could come from the Template
774                     // and then size calculations could not be correct anymore.
775                     aNewSet.Put( SvxBoxItem(RES_BOX) );
776                     aNewSet.Put( SvxShadowItem(RES_SHADOW) );
777                 }
778 
779                 // Always transfer the anchor, which is a hard attribute anyways.
780                 aNewSet.Put( pOldFormat->GetAnchor() );
781 
782                 // The new one should be changeable in its height.
783                 std::unique_ptr<SwFormatFrameSize> aFrameSize(pOldFormat->GetFrameSize().Clone());
784                 aFrameSize->SetHeightSizeType( SwFrameSize::Minimum );
785                 aNewSet.Put( std::move(aFrameSize) );
786 
787                 SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection(
788                             rDoc.GetNodes().GetEndOfAutotext(),
789                             SwFlyStartNode, pColl );
790                 aNewSet.Put( SwFormatContent( pSttNd ));
791 
792                 pNewFormat->SetFormatAttr( aNewSet );
793 
794                 // InContents need to be treated in a special way:
795                 // The TextAttribute needs to be destroyed.
796                 // Unfortunately, this also destroys the Format next to the Frames.
797                 // To avoid this, we disconnect the attribute from the Format.
798 
799                 const SwFormatAnchor& rAnchor = pNewFormat->GetAnchor();
800                 if ( RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId() )
801                 {
802                     SwTextNode *pTextNode = rAnchor.GetAnchorNode()->GetTextNode();
803                     OSL_ENSURE( pTextNode->HasHints(), "Missing FlyInCnt-Hint." );
804                     const sal_Int32 nIdx = rAnchor.GetAnchorContentOffset();
805                     SwTextAttr * const pHint =
806                         pTextNode->GetTextAttrForCharAt(nIdx, RES_TXTATR_FLYCNT);
807 
808                     assert(pHint && "Missing Hint.");
809 
810                     OSL_ENSURE( pHint->Which() == RES_TXTATR_FLYCNT,
811                                 "Missing FlyInCnt-Hint." );
812                     OSL_ENSURE( pHint->GetFlyCnt().GetFrameFormat() == pOldFormat,
813                                 "Wrong TextFlyCnt-Hint." );
814 
815                     const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()).SetFlyFormat(
816                             pNewFormat );
817                 }
818 
819                 // The old one should not have a flow and it should be adjusted to above and
820                 // middle.
821                 // Also, the width should be 100% and it should also adjust the height, if changed.
822                 aNewSet.ClearItem();
823 
824                 aNewSet.Put( SwFormatSurround( css::text::WrapTextMode_NONE ) );
825                 aNewSet.Put( SvxOpaqueItem( RES_OPAQUE, true ) );
826 
827                 sal_Int16 eVert = bBefore ? text::VertOrientation::BOTTOM : text::VertOrientation::TOP;
828                 aNewSet.Put( SwFormatVertOrient( 0, eVert ) );
829                 aNewSet.Put( SwFormatHoriOrient( 0, text::HoriOrientation::CENTER ) );
830 
831                 aFrameSize.reset(pOldFormat->GetFrameSize().Clone());
832 
833                 SwOLENode* pOleNode = rDoc.GetNodes()[nNdIdx + 1]->GetOLENode();
834                 bool isMath = false;
835                 if(pOleNode)
836                 {
837                     svt::EmbeddedObjectRef& xRef = pOleNode->GetOLEObj().GetObject();
838                     if(xRef.is())
839                     {
840                         SvGlobalName aCLSID( xRef->getClassID() );
841                         isMath = ( SotExchange::IsMath( aCLSID ) != 0 );
842                     }
843                 }
844                 aFrameSize->SetWidthPercent(isMath ? 0 : 100);
845                 aFrameSize->SetHeightPercent(SwFormatFrameSize::SYNCED);
846                 aNewSet.Put( std::move(aFrameSize) );
847 
848                 // Hard-set the attributes, because they could come from the Template
849                 // and then size calculations could not be correct anymore.
850                 if( bCpyBrd )
851                 {
852                     aNewSet.Put( SvxBoxItem(RES_BOX) );
853                     aNewSet.Put( SvxShadowItem(RES_SHADOW) );
854                 }
855                 aNewSet.Put( SvxLRSpaceItem(RES_LR_SPACE) );
856                 aNewSet.Put( SvxULSpaceItem(RES_UL_SPACE) );
857 
858                 // The old one is paragraph-bound to the paragraph in the new one.
859                 SwFormatAnchor aAnch( RndStdIds::FLY_AT_PARA );
860                 SwNodeIndex aAnchIdx( *pNewFormat->GetContent().GetContentIdx(), 1 );
861                 pNew = aAnchIdx.GetNode().GetTextNode();
862                 SwPosition aPos( aAnchIdx );
863                 aAnch.SetAnchor( &aPos );
864                 aNewSet.Put( aAnch );
865 
866                 if( pUndo )
867                     pUndo->SetFlys( *pOldFormat, aNewSet, *pNewFormat );
868                 else
869                     pOldFormat->SetFormatAttr( aNewSet );
870 
871                 // Have only the FlyFrames created.
872                 // We leave this to established methods (especially for InCntFlys).
873                 pNewFormat->MakeFrames();
874                 // #i115719#
875                 if ( pOldFlyFrameFormat )
876                 {
877                     pOldFlyFrameFormat->SetObjTitle( sTitle );
878                     pOldFlyFrameFormat->SetObjDescription( sDescription );
879                 }
880             }
881             break;
882 
883         default:
884             OSL_ENSURE(false, "unknown LabelType?");
885     }
886     OSL_ENSURE( pNew, "No Label inserted" );
887     if( pNew )
888     {
889         // #i61007# order of captions
890         bool bOrderNumberingFirst = SW_MOD()->GetModuleConfig()->IsCaptionOrderNumberingFirst();
891         // Work up OUString
892         OUString aText;
893         if( bOrderNumberingFirst )
894         {
895             aText = rNumberingSeparator;
896         }
897         if( pType)
898         {
899             aText += pType->GetName();
900             if( !bOrderNumberingFirst )
901                 aText += " ";
902         }
903         sal_Int32 nIdx = aText.getLength();
904         if( !rText.empty() )
905         {
906             aText += rSeparator;
907         }
908         const sal_Int32 nSepIdx = aText.getLength();
909         aText += rText;
910 
911         // Insert string
912         SwContentIndex aIdx( pNew, 0 );
913         pNew->InsertText( aText, aIdx );
914 
915         // Insert field
916         if(pType)
917         {
918             SwSetExpField aField( static_cast<SwSetExpFieldType*>(pType), OUString(), SVX_NUM_ARABIC);
919             if( bOrderNumberingFirst )
920                 nIdx = 0;
921             SwFormatField aFormat( aField );
922             pNew->InsertItem( aFormat, nIdx, nIdx );
923             if(!rCharacterStyle.isEmpty())
924             {
925                 SwCharFormat* pCharFormat = rDoc.FindCharFormatByName(rCharacterStyle);
926                 if( !pCharFormat )
927                 {
928                     const sal_uInt16 nMyId = SwStyleNameMapper::GetPoolIdFromUIName(rCharacterStyle, SwGetPoolIdFromName::ChrFmt);
929                     pCharFormat = rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( nMyId );
930                 }
931                 if (pCharFormat)
932                 {
933                     SwFormatCharFormat aCharFormat( pCharFormat );
934                     pNew->InsertItem( aCharFormat, 0,
935                         nSepIdx + 1, SetAttrMode::DONTEXPAND );
936                 }
937             }
938         }
939 
940         if ( bTable )
941         {
942             if ( bBefore )
943             {
944                 if ( !pNew->GetSwAttrSet().GetKeep().GetValue()  )
945                     pNew->SetAttr( SvxFormatKeepItem( true, RES_KEEP ) );
946             }
947             else
948             {
949                 SwTableNode *const pNd =
950                     rDoc.GetNodes()[nNdIdx]->GetStartNode()->GetTableNode();
951                 SwTable &rTable = pNd->GetTable();
952                 if ( !rTable.GetFrameFormat()->GetKeep().GetValue() )
953                     rTable.GetFrameFormat()->SetFormatAttr( SvxFormatKeepItem( true, RES_KEEP ) );
954                 if ( pUndo )
955                     pUndo->SetUndoKeep();
956             }
957         }
958         rDoc.getIDocumentState().SetModified();
959     }
960 
961     return pNewFormat;
962 }
963 
964 SwFlyFrameFormat *
InsertLabel(SwLabelType const eType,OUString const & rText,OUString const & rSeparator,OUString const & rNumberingSeparator,bool const bBefore,sal_uInt16 const nId,SwNodeOffset const nNdIdx,OUString const & rCharacterStyle,bool const bCpyBrd)965 SwDoc::InsertLabel(
966         SwLabelType const eType, OUString const& rText, OUString const& rSeparator,
967         OUString const& rNumberingSeparator,
968         bool const bBefore, sal_uInt16 const nId, SwNodeOffset const nNdIdx,
969         OUString const& rCharacterStyle,
970         bool const bCpyBrd )
971 {
972     std::unique_ptr<SwUndoInsertLabel> pUndo;
973     if (GetIDocumentUndoRedo().DoesUndo())
974     {
975         pUndo.reset(new SwUndoInsertLabel(
976                         eType, rText, rSeparator, rNumberingSeparator,
977                         bBefore, nId, rCharacterStyle, bCpyBrd, this ));
978     }
979 
980     SwFlyFrameFormat *const pNewFormat = lcl_InsertLabel(*this, mpTextFormatCollTable.get(), pUndo.get(),
981             eType, rText, rSeparator, rNumberingSeparator, bBefore,
982             nId, nNdIdx, rCharacterStyle, bCpyBrd);
983 
984     if (pUndo)
985     {
986         GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
987     }
988     else
989     {
990         GetIDocumentUndoRedo().DelAllUndoObj();
991     }
992 
993     return pNewFormat;
994 }
995 
996 static SwFlyFrameFormat *
lcl_InsertDrawLabel(SwDoc & rDoc,SwTextFormatColls * const pTextFormatCollTable,SwUndoInsertLabel * const pUndo,SwDrawFrameFormat * const pOldFormat,OUString const & rText,const OUString & rSeparator,const OUString & rNumberSeparator,const sal_uInt16 nId,const OUString & rCharacterStyle,SdrObject & rSdrObj)997 lcl_InsertDrawLabel( SwDoc & rDoc, SwTextFormatColls *const pTextFormatCollTable,
998         SwUndoInsertLabel *const pUndo, SwDrawFrameFormat *const pOldFormat,
999         OUString const& rText,
1000                                      const OUString& rSeparator,
1001                                      const OUString& rNumberSeparator,
1002                                      const sal_uInt16 nId,
1003                                      const OUString& rCharacterStyle,
1004                                      SdrObject& rSdrObj )
1005 {
1006     ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
1007     ::sw::DrawUndoGuard const drawUndoGuard(rDoc.GetIDocumentUndoRedo());
1008 
1009     // Because we get by the TextColl's name, we need to create the field first.
1010     OSL_ENSURE( nId == USHRT_MAX  || nId < rDoc.getIDocumentFieldsAccess().GetFieldTypes()->size(),
1011             "FieldType index out of bounds" );
1012     SwFieldType *pType = nId != USHRT_MAX ? (*rDoc.getIDocumentFieldsAccess().GetFieldTypes())[nId].get() : nullptr;
1013     OSL_ENSURE( !pType || pType->Which() == SwFieldIds::SetExp, "Wrong label id" );
1014 
1015     SwTextFormatColl *pColl = nullptr;
1016     if( pType )
1017     {
1018         for( auto i = pTextFormatCollTable->size(); i; )
1019         {
1020             if( (*pTextFormatCollTable)[ --i ]->GetName()==pType->GetName() )
1021             {
1022                 pColl = (*pTextFormatCollTable)[i];
1023                 break;
1024             }
1025         }
1026         OSL_ENSURE( pColl, "no text collection found" );
1027     }
1028 
1029     if( !pColl )
1030     {
1031         pColl = rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_LABEL );
1032     }
1033 
1034     SwTextNode* pNew = nullptr;
1035     SwFlyFrameFormat* pNewFormat = nullptr;
1036 
1037     // Destroy Frame,
1038     // insert new Frame,
1039     // insert the corresponding Node with Field into the new Frame,
1040     // insert the old Frame with the Object (Picture/OLE) paragraph-bound into the new Frame,
1041     // create Frames.
1042 
1043     // Keep layer ID of drawing object before removing
1044     // its frames.
1045     // Note: The layer ID is passed to the undo and have to be the correct value.
1046     //       Removing the frames of the drawing object changes its layer.
1047     const SdrLayerID nLayerId = rSdrObj.GetLayer();
1048 
1049     pOldFormat->DelFrames();
1050 
1051     // InContents need to be treated in a special way:
1052     // The TextAttribute needs to be destroyed.
1053     // Unfortunately, this also destroys the Format next to the Frames.
1054     // To avoid this, we disconnect the attribute from the Format.
1055     SwAttrSet aNewSet = pOldFormat->GetAttrSet().CloneAsValue( false );
1056 
1057     // Protect the Frame's size and position
1058     if ( rSdrObj.IsMoveProtect() || rSdrObj.IsResizeProtect() )
1059     {
1060         SvxProtectItem aProtect(RES_PROTECT);
1061         aProtect.SetContentProtect( false );
1062         aProtect.SetPosProtect( rSdrObj.IsMoveProtect() );
1063         aProtect.SetSizeProtect( rSdrObj.IsResizeProtect() );
1064         aNewSet.Put( aProtect );
1065     }
1066 
1067     // Take over the text wrap
1068     lcl_CpyAttr( aNewSet, pOldFormat->GetAttrSet(), RES_SURROUND );
1069 
1070     // Send the frame to the back, if needed.
1071     // Consider the 'invisible' hell layer.
1072     if ( rDoc.getIDocumentDrawModelAccess().GetHellId() != nLayerId &&
1073          rDoc.getIDocumentDrawModelAccess().GetInvisibleHellId() != nLayerId )
1074     {
1075         SvxOpaqueItem aOpaque( RES_OPAQUE );
1076         aOpaque.SetValue( true );
1077         aNewSet.Put( aOpaque );
1078     }
1079 
1080     // Take over position
1081     // #i26791# - use directly drawing object's positioning attributes
1082     aNewSet.Put( pOldFormat->GetHoriOrient() );
1083     aNewSet.Put( pOldFormat->GetVertOrient() );
1084 
1085     aNewSet.Put( pOldFormat->GetAnchor() );
1086 
1087     // The new one should be variable in its height!
1088     Size aSz( rSdrObj.GetCurrentBoundRect().GetSize() );
1089     SwFormatFrameSize aFrameSize( SwFrameSize::Minimum, aSz.Width(), aSz.Height() );
1090     aNewSet.Put( aFrameSize );
1091 
1092     // Apply the margin to the new Frame.
1093     // Don't set a border, use the one from the Template.
1094     aNewSet.Put( pOldFormat->GetLRSpace() );
1095     aNewSet.Put( pOldFormat->GetULSpace() );
1096 
1097     SwStartNode* pSttNd =
1098         rDoc.GetNodes().MakeTextSection(
1099             rDoc.GetNodes().GetEndOfAutotext(),
1100             SwFlyStartNode, pColl );
1101 
1102     pNewFormat = rDoc.MakeFlyFrameFormat( rDoc.GetUniqueFrameName(),
1103                  rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME ) );
1104 
1105     // Set border and shadow to default if the template contains any.
1106     if( SfxItemState::SET == pNewFormat->GetAttrSet().GetItemState( RES_BOX ))
1107         aNewSet.Put( *GetDfltAttr( RES_BOX ) );
1108 
1109     if( SfxItemState::SET == pNewFormat->GetAttrSet().GetItemState(RES_SHADOW))
1110         aNewSet.Put( *GetDfltAttr( RES_SHADOW ) );
1111 
1112     pNewFormat->SetFormatAttr( SwFormatContent( pSttNd ));
1113     pNewFormat->SetFormatAttr( aNewSet );
1114 
1115     const SwFormatAnchor& rAnchor = pNewFormat->GetAnchor();
1116     if ( RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId() )
1117     {
1118         SwTextNode *pTextNode = rAnchor.GetAnchorNode()->GetTextNode();
1119         OSL_ENSURE( pTextNode->HasHints(), "Missing FlyInCnt-Hint." );
1120         const sal_Int32 nIdx = rAnchor.GetAnchorContentOffset();
1121         SwTextAttr * const pHint =
1122             pTextNode->GetTextAttrForCharAt( nIdx, RES_TXTATR_FLYCNT );
1123 
1124         assert(pHint && "Missing Hint.");
1125 
1126 #if OSL_DEBUG_LEVEL > 0
1127         OSL_ENSURE( pHint->Which() == RES_TXTATR_FLYCNT,
1128                     "Missing FlyInCnt-Hint." );
1129         OSL_ENSURE( pHint->GetFlyCnt().
1130                     GetFrameFormat() == static_cast<SwFrameFormat*>(pOldFormat),
1131                     "Wrong TextFlyCnt-Hint." );
1132 #endif
1133         const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()).SetFlyFormat( pNewFormat );
1134     }
1135 
1136     // The old one should not have a flow
1137     // and it should be adjusted to above and middle.
1138     aNewSet.ClearItem();
1139 
1140     aNewSet.Put( SwFormatSurround( css::text::WrapTextMode_NONE ) );
1141     if (nLayerId == rDoc.getIDocumentDrawModelAccess().GetHellId())
1142     {
1143     // Consider drawing objects in the 'invisible' hell layer
1144         rSdrObj.SetLayer( rDoc.getIDocumentDrawModelAccess().GetHeavenId() );
1145     }
1146     else if (nLayerId == rDoc.getIDocumentDrawModelAccess().GetInvisibleHellId())
1147     {
1148         rSdrObj.SetLayer( rDoc.getIDocumentDrawModelAccess().GetInvisibleHeavenId() );
1149     }
1150     aNewSet.Put( SvxLRSpaceItem( RES_LR_SPACE ) );
1151     aNewSet.Put( SvxULSpaceItem( RES_UL_SPACE ) );
1152 
1153     // #i26791# - set position of the drawing object, which is labeled.
1154     aNewSet.Put( SwFormatVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ) );
1155     aNewSet.Put( SwFormatHoriOrient( 0, text::HoriOrientation::CENTER, text::RelOrientation::FRAME ) );
1156 
1157     // The old one is paragraph-bound to the new one's paragraph.
1158     SwFormatAnchor aAnch( RndStdIds::FLY_AT_PARA );
1159     SwNodeIndex aAnchIdx( *pNewFormat->GetContent().GetContentIdx(), 1 );
1160     pNew = aAnchIdx.GetNode().GetTextNode();
1161     SwPosition aPos( aAnchIdx );
1162     aAnch.SetAnchor( &aPos );
1163     aNewSet.Put( aAnch );
1164 
1165     if( pUndo )
1166     {
1167         pUndo->SetFlys( *pOldFormat, aNewSet, *pNewFormat );
1168         // #i26791# - position no longer needed
1169         pUndo->SetDrawObj( nLayerId );
1170     }
1171     else
1172         pOldFormat->SetFormatAttr( aNewSet );
1173 
1174     // Have only the FlyFrames created.
1175     // We leave this to established methods (especially for InCntFlys).
1176     pNewFormat->MakeFrames();
1177 
1178     OSL_ENSURE( pNew, "No Label inserted" );
1179 
1180     if( pNew )
1181     {
1182         //#i61007# order of captions
1183         bool bOrderNumberingFirst = SW_MOD()->GetModuleConfig()->IsCaptionOrderNumberingFirst();
1184 
1185         // prepare string
1186         OUString aText;
1187         if( bOrderNumberingFirst )
1188         {
1189             aText = rNumberSeparator;
1190         }
1191         if ( pType )
1192         {
1193             aText += pType->GetName();
1194             if( !bOrderNumberingFirst )
1195                 aText += " ";
1196         }
1197         sal_Int32 nIdx = aText.getLength();
1198         aText += rSeparator;
1199         const sal_Int32 nSepIdx = aText.getLength();
1200         aText += rText;
1201 
1202         // insert text
1203         SwContentIndex aIdx( pNew, 0 );
1204         pNew->InsertText( aText, aIdx );
1205 
1206         // insert field
1207         if ( pType )
1208         {
1209             SwSetExpField aField( static_cast<SwSetExpFieldType*>(pType), OUString(), SVX_NUM_ARABIC );
1210             if( bOrderNumberingFirst )
1211                 nIdx = 0;
1212             SwFormatField aFormat( aField );
1213             pNew->InsertItem( aFormat, nIdx, nIdx );
1214             if ( !rCharacterStyle.isEmpty() )
1215             {
1216                 SwCharFormat * pCharFormat = rDoc.FindCharFormatByName(rCharacterStyle);
1217                 if ( !pCharFormat )
1218                 {
1219                     const sal_uInt16 nMyId = SwStyleNameMapper::GetPoolIdFromUIName( rCharacterStyle, SwGetPoolIdFromName::ChrFmt );
1220                     pCharFormat = rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( nMyId );
1221                 }
1222                 if ( pCharFormat )
1223                 {
1224                     SwFormatCharFormat aCharFormat( pCharFormat );
1225                     pNew->InsertItem( aCharFormat, 0, nSepIdx + 1,
1226                             SetAttrMode::DONTEXPAND );
1227                 }
1228             }
1229         }
1230     }
1231 
1232     return pNewFormat;
1233 }
1234 
InsertDrawLabel(OUString const & rText,OUString const & rSeparator,OUString const & rNumberSeparator,sal_uInt16 const nId,OUString const & rCharacterStyle,SdrObject & rSdrObj)1235 SwFlyFrameFormat* SwDoc::InsertDrawLabel(
1236         OUString const& rText,
1237         OUString const& rSeparator,
1238         OUString const& rNumberSeparator,
1239         sal_uInt16 const nId,
1240         OUString const& rCharacterStyle,
1241         SdrObject& rSdrObj )
1242 {
1243     SwDrawContact *const pContact =
1244         static_cast<SwDrawContact*>(GetUserCall( &rSdrObj ));
1245     if (!pContact)
1246         return nullptr;
1247     OSL_ENSURE( RES_DRAWFRMFMT == pContact->GetFormat()->Which(),
1248             "InsertDrawLabel(): not a DrawFrameFormat" );
1249 
1250     SwDrawFrameFormat* pOldFormat = static_cast<SwDrawFrameFormat *>(pContact->GetFormat());
1251     if (!pOldFormat)
1252         return nullptr;
1253 
1254     std::unique_ptr<SwUndoInsertLabel> pUndo;
1255     if (GetIDocumentUndoRedo().DoesUndo())
1256     {
1257         GetIDocumentUndoRedo().ClearRedo();
1258         pUndo.reset(new SwUndoInsertLabel(
1259             SwLabelType::Draw, rText, rSeparator, rNumberSeparator, false,
1260             nId, rCharacterStyle, false, this ));
1261     }
1262 
1263     SwFlyFrameFormat *const pNewFormat = lcl_InsertDrawLabel(
1264         *this, mpTextFormatCollTable.get(), pUndo.get(), pOldFormat,
1265         rText, rSeparator, rNumberSeparator, nId, rCharacterStyle, rSdrObj);
1266 
1267     if (pUndo)
1268     {
1269         GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
1270     }
1271     else
1272     {
1273         GetIDocumentUndoRedo().DelAllUndoObj();
1274     }
1275 
1276     return pNewFormat;
1277 }
1278 
lcl_collectUsedNums(std::vector<unsigned int> & rSetFlags,sal_Int32 nNmLen,std::u16string_view rName,std::u16string_view rCmpName)1279 static void lcl_collectUsedNums(std::vector<unsigned int>& rSetFlags, sal_Int32 nNmLen, std::u16string_view rName, std::u16string_view rCmpName)
1280 {
1281     if (o3tl::starts_with(rName, rCmpName))
1282     {
1283         // Only get and set the Flag
1284         const sal_Int32 nNum = o3tl::toInt32(rName.substr(nNmLen)) - 1;
1285         if (nNum >= 0)
1286             rSetFlags.push_back(nNum);
1287     }
1288 }
1289 
lcl_collectUsedNums(std::vector<unsigned int> & rSetFlags,sal_Int32 nNmLen,const SdrObject & rObj,const OUString & rCmpName)1290 static void lcl_collectUsedNums(std::vector<unsigned int>& rSetFlags, sal_Int32 nNmLen, const SdrObject& rObj, const OUString& rCmpName)
1291 {
1292     OUString sName = rObj.GetName();
1293     lcl_collectUsedNums(rSetFlags, nNmLen, sName, rCmpName);
1294     // tdf#122487 take groups into account, iterate and recurse through their
1295     // contents for name collision check
1296     if (!rObj.IsGroupObject())
1297         return;
1298 
1299     const SdrObjList* pSub(rObj.GetSubList());
1300     assert(pSub && "IsGroupObject is implemented as GetSubList != nullptr");
1301     for (const rtl::Reference<SdrObject>& pObj : *pSub)
1302     {
1303         lcl_collectUsedNums(rSetFlags, nNmLen, *pObj, rCmpName);
1304     }
1305 }
1306 
1307 namespace
1308 {
first_available_number(std::vector<unsigned int> & numbers)1309     int first_available_number(std::vector<unsigned int>& numbers)
1310     {
1311         std::sort(numbers.begin(), numbers.end());
1312         auto last = std::unique(numbers.begin(), numbers.end());
1313         numbers.erase(last, numbers.end());
1314 
1315         for (size_t i = 0; i < numbers.size(); ++i)
1316         {
1317             if (numbers[i] != i)
1318                 return i;
1319         }
1320 
1321         return numbers.size();
1322     }
1323 }
1324 
lcl_GetUniqueFlyName(const SwDoc & rDoc,TranslateId pDefStrId,sal_uInt16 eType,std::u16string_view rPrefix=std::u16string_view (),SwNodeType nNdTyp=SwNodeType::NONE)1325 static OUString lcl_GetUniqueFlyName(const SwDoc& rDoc, TranslateId pDefStrId, sal_uInt16 eType, std::u16string_view rPrefix = std::u16string_view(), SwNodeType nNdTyp = SwNodeType::NONE)
1326 {
1327     assert(eType >= RES_FMT_BEGIN && eType < RES_FMT_END);
1328     if (rDoc.IsInMailMerge())
1329     {
1330         OUString newName = "MailMergeFly"
1331             + DateTimeToOUString( DateTime( DateTime::SYSTEM ) )
1332             + OUString::number( rDoc.GetSpzFrameFormats()->size() + 1 );
1333         return newName;
1334     }
1335 
1336     if (!rPrefix.empty())
1337     {
1338         // Generate a name that makes it possible to know this is a copy of which original name,
1339         // e.g. 'Picture 1 Copy 1'.
1340         assert(nNdTyp != SwNodeType::NONE);
1341         sal_Int32 nCnt = 1;
1342         OUString aPrefix = SwResId(STR_MARK_COPY).replaceFirst("%1", rPrefix);
1343         OUString aTmp;
1344         while(nCnt < SAL_MAX_INT32)
1345         {
1346             aTmp = aPrefix + OUString::number(nCnt);
1347             ++nCnt;
1348             if (!rDoc.FindFlyByName(aTmp, nNdTyp))
1349             {
1350                 break;
1351             }
1352         }
1353         return aTmp;
1354     }
1355 
1356     OUString aName(SwResId(pDefStrId));
1357     sal_Int32 nNmLen = aName.getLength();
1358 
1359     std::vector<unsigned int> aUsedNums;
1360     aUsedNums.reserve(rDoc.GetSpzFrameFormats()->size());
1361 
1362     for(sw::SpzFrameFormat* pFlyFormat: *rDoc.GetSpzFrameFormats())
1363     {
1364         if (eType != pFlyFormat->Which())
1365             continue;
1366         if (eType == RES_DRAWFRMFMT)
1367         {
1368             const SdrObject *pObj = pFlyFormat->FindSdrObject();
1369             if (pObj)
1370                 lcl_collectUsedNums(aUsedNums, nNmLen, *pObj, aName);
1371         }
1372 
1373         lcl_collectUsedNums(aUsedNums, nNmLen, pFlyFormat->GetName(), aName);
1374     }
1375 
1376     // All numbers are flagged accordingly, so determine the right one
1377     auto nNum = first_available_number(aUsedNums) + 1;
1378     return aName + OUString::number(nNum);
1379 }
1380 
GetUniqueGrfName(std::u16string_view rPrefix) const1381 OUString SwDoc::GetUniqueGrfName(std::u16string_view rPrefix) const
1382 {
1383     return lcl_GetUniqueFlyName(*this, STR_GRAPHIC_DEFNAME, RES_FLYFRMFMT, rPrefix, SwNodeType::Grf);
1384 }
1385 
GetUniqueOLEName() const1386 OUString SwDoc::GetUniqueOLEName() const
1387 {
1388     return lcl_GetUniqueFlyName(*this, STR_OBJECT_DEFNAME, RES_FLYFRMFMT);
1389 }
1390 
GetUniqueFrameName() const1391 OUString SwDoc::GetUniqueFrameName() const
1392 {
1393     return lcl_GetUniqueFlyName(*this, STR_FRAME_DEFNAME, RES_FLYFRMFMT);
1394 }
1395 
GetUniqueShapeName() const1396 OUString SwDoc::GetUniqueShapeName() const
1397 {
1398     return lcl_GetUniqueFlyName(*this, STR_SHAPE_DEFNAME, RES_DRAWFRMFMT);
1399 }
1400 
GetUniqueDrawObjectName() const1401 OUString SwDoc::GetUniqueDrawObjectName() const
1402 {
1403     return lcl_GetUniqueFlyName(*this, TranslateId(nullptr, "DrawObject"), RES_DRAWFRMFMT);
1404 }
1405 
FindFlyByName(const OUString & rName,SwNodeType nNdTyp) const1406 const SwFlyFrameFormat* SwDoc::FindFlyByName( const OUString& rName, SwNodeType nNdTyp ) const
1407 {
1408     auto it = GetSpzFrameFormats()->findByTypeAndName( RES_FLYFRMFMT, rName );
1409     if( it == GetSpzFrameFormats()->typeAndNameEnd() )
1410         return nullptr;
1411 
1412     const SwFrameFormat* pFlyFormat = *it;
1413     assert( RES_FLYFRMFMT == pFlyFormat->Which() && pFlyFormat->GetName() == rName );
1414     const SwNodeIndex* pIdx = pFlyFormat->GetContent().GetContentIdx();
1415     if( pIdx && pIdx->GetNode().GetNodes().IsDocNodes() )
1416     {
1417         if( nNdTyp != SwNodeType::NONE )
1418         {
1419             // query for the right NodeType
1420             const SwNode* pNd = GetNodes()[ pIdx->GetIndex()+1 ];
1421             if( nNdTyp == SwNodeType::Text
1422                     ? !pNd->IsNoTextNode()
1423                     : nNdTyp == pNd->GetNodeType() )
1424                 return static_cast<const SwFlyFrameFormat*>(pFlyFormat);
1425         }
1426         else
1427             return static_cast<const SwFlyFrameFormat*>(pFlyFormat);
1428     }
1429     return nullptr;
1430 }
1431 
SetFlyName(SwFlyFrameFormat & rFormat,const OUString & rName)1432 void SwDoc::SetFlyName( SwFlyFrameFormat& rFormat, const OUString& rName )
1433 {
1434     if (rFormat.GetName() == rName)
1435     {
1436         return;
1437     }
1438     OUString sName( rName );
1439     if( sName.isEmpty() || FindFlyByName( sName ) )
1440     {
1441         TranslateId pTyp = STR_FRAME_DEFNAME;
1442         const SwNodeIndex* pIdx = rFormat.GetContent().GetContentIdx();
1443         if( pIdx && pIdx->GetNode().GetNodes().IsDocNodes() )
1444         {
1445             switch( GetNodes()[ pIdx->GetIndex() + 1 ]->GetNodeType() )
1446             {
1447                 case SwNodeType::Grf:
1448                     pTyp = STR_GRAPHIC_DEFNAME;
1449                     break;
1450                 case SwNodeType::Ole:
1451                     pTyp = STR_OBJECT_DEFNAME;
1452                     break;
1453                 default: break;
1454             }
1455         }
1456         sName = lcl_GetUniqueFlyName(*this, pTyp, RES_FLYFRMFMT);
1457     }
1458     rFormat.SetFormatName( sName, true );
1459     getIDocumentState().SetModified();
1460 }
1461 
SetAllUniqueFlyNames()1462 void SwDoc::SetAllUniqueFlyNames()
1463 {
1464     sal_Int32 n, nFlyNum = 0, nGrfNum = 0, nOLENum = 0;
1465 
1466     const OUString sFlyNm(SwResId(STR_FRAME_DEFNAME));
1467     const OUString sGrfNm(SwResId(STR_GRAPHIC_DEFNAME));
1468     const OUString sOLENm(SwResId(STR_OBJECT_DEFNAME));
1469 
1470     n = GetSpzFrameFormats()->size();
1471     if( 255 < n )
1472         n = 255;
1473     SwFrameFormatsV aArr;
1474     aArr.reserve( n );
1475     SwFrameFormat* pFlyFormat;
1476     bool bContainsAtPageObjWithContentAnchor = false;
1477 
1478     for( n = GetSpzFrameFormats()->size(); n; )
1479     {
1480         pFlyFormat = (*GetSpzFrameFormats())[ --n ];
1481         if( RES_FLYFRMFMT == pFlyFormat->Which() )
1482         {
1483             const OUString& aNm = pFlyFormat->GetName();
1484             if ( !aNm.isEmpty() )
1485             {
1486                 sal_Int32 *pNum = nullptr;
1487                 sal_Int32 nLen = 0;
1488                 if ( aNm.startsWith(sGrfNm) )
1489                 {
1490                     nLen = sGrfNm.getLength();
1491                     pNum = &nGrfNum;
1492                 }
1493                 else if( aNm.startsWith(sFlyNm) )
1494                 {
1495                     nLen = sFlyNm.getLength();
1496                     pNum = &nFlyNum;
1497                 }
1498                 else if( aNm.startsWith(sOLENm) )
1499                 {
1500                     nLen = sOLENm.getLength();
1501                     pNum = &nOLENum;
1502                 }
1503 
1504                 if ( pNum )
1505                 {
1506                     const sal_Int32 nNewLen = o3tl::toInt32(aNm.subView( nLen ));
1507                     if (*pNum < nNewLen)
1508                         *pNum = nNewLen;
1509                 }
1510             }
1511             else
1512                 // we want to set that afterwards
1513                 aArr.push_back( pFlyFormat );
1514 
1515         }
1516         if ( !bContainsAtPageObjWithContentAnchor )
1517         {
1518             const SwFormatAnchor& rAnchor = pFlyFormat->GetAnchor();
1519             if ( (RndStdIds::FLY_AT_PAGE == rAnchor.GetAnchorId()) &&
1520                  rAnchor.GetAnchorNode() )
1521             {
1522                 bContainsAtPageObjWithContentAnchor = true;
1523             }
1524         }
1525     }
1526     SetContainsAtPageObjWithContentAnchor( bContainsAtPageObjWithContentAnchor );
1527 
1528     for( n = aArr.size(); n; )
1529     {
1530         pFlyFormat = aArr[ --n ];
1531         const SwNodeIndex* pIdx = pFlyFormat->GetContent().GetContentIdx();
1532         if( pIdx && pIdx->GetNode().GetNodes().IsDocNodes() )
1533         {
1534             switch( GetNodes()[ pIdx->GetIndex() + 1 ]->GetNodeType() )
1535             {
1536             case SwNodeType::Grf:
1537                 pFlyFormat->SetFormatName( sGrfNm + OUString::number( ++nGrfNum ));
1538                 break;
1539             case SwNodeType::Ole:
1540                 pFlyFormat->SetFormatName( sOLENm + OUString::number( ++nOLENum ));
1541                 break;
1542             default:
1543                 pFlyFormat->SetFormatName( sFlyNm + OUString::number( ++nFlyNum ));
1544                 break;
1545             }
1546         }
1547     }
1548     aArr.clear();
1549 
1550     if( GetFootnoteIdxs().empty() )
1551         return;
1552 
1553     SwTextFootnote::SetUniqueSeqRefNo( *this );
1554     // #i52775# Chapter footnotes did not get updated correctly.
1555     // Calling UpdateAllFootnote() instead of UpdateFootnote() solves this problem,
1556     // but I do not dare to call UpdateAllFootnote() in all cases: Safety first.
1557     if ( FTNNUM_CHAPTER == GetFootnoteInfo().m_eNum )
1558     {
1559         GetFootnoteIdxs().UpdateAllFootnote();
1560     }
1561     else
1562     {
1563         SwNodeIndex aTmp( GetNodes() );
1564         GetFootnoteIdxs().UpdateFootnote( aTmp.GetNode() );
1565     }
1566 }
1567 
IsInHeaderFooter(const SwNode & rIdx) const1568 bool SwDoc::IsInHeaderFooter( const SwNode& rIdx ) const
1569 {
1570     // That can also be a Fly in a Fly in the Header.
1571     // Is also used by sw3io, to determine if a Redline object is
1572     // in the Header or Footer.
1573     // Because Redlines are also attached to Start and EndNode,
1574     // the Index must not necessarily be from a ContentNode.
1575     const SwNode* pNd = &rIdx;
1576     const SwNode* pFlyNd = pNd->FindFlyStartNode();
1577     while( pFlyNd )
1578     {
1579         // get up by using the Anchor
1580 #if OSL_DEBUG_LEVEL > 0
1581         std::vector<const SwFrameFormat*> checkFormats;
1582         for(sw::SpzFrameFormat* pFormat: *GetSpzFrameFormats())
1583         {
1584             const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx();
1585             if( pIdx && pFlyNd == &pIdx->GetNode() )
1586                 checkFormats.push_back( pFormat );
1587         }
1588 #endif
1589         std::vector<SwFrameFormat*> const & rFlys(pFlyNd->GetAnchoredFlys());
1590         bool bFound(false);
1591         for (size_t i = 0; i < rFlys.size(); ++i)
1592         {
1593             const SwFrameFormat *const pFormat = rFlys[i];
1594             const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx();
1595             if( pIdx && pFlyNd == &pIdx->GetNode() )
1596             {
1597 #if OSL_DEBUG_LEVEL > 0
1598                 auto checkPos = std::find(
1599                         checkFormats.begin(), checkFormats.end(), pFormat );
1600                 assert( checkPos != checkFormats.end());
1601                 checkFormats.erase( checkPos );
1602 #endif
1603                 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1604                 if ((RndStdIds::FLY_AT_PAGE == rAnchor.GetAnchorId()) ||
1605                     !rAnchor.GetAnchorNode() )
1606                 {
1607                     return false;
1608                 }
1609 
1610                 pNd = rAnchor.GetAnchorNode();
1611                 pFlyNd = pNd->FindFlyStartNode();
1612                 bFound = true;
1613                 break;
1614             }
1615         }
1616         if (!bFound)
1617         {
1618             OSL_ENSURE(mbInReading, "Found a FlySection but not a Format!");
1619             return false;
1620         }
1621     }
1622 
1623     return nullptr != pNd->FindHeaderStartNode() ||
1624             nullptr != pNd->FindFooterStartNode();
1625 }
1626 
GetTextDirection(const SwPosition & rPos,const Point * pPt) const1627 SvxFrameDirection SwDoc::GetTextDirection( const SwPosition& rPos,
1628                                const Point* pPt ) const
1629 {
1630     SvxFrameDirection nRet = SvxFrameDirection::Unknown;
1631 
1632     SwContentNode *pNd = rPos.GetNode().GetContentNode();
1633 
1634     // #i42921# - use new method <SwContentNode::GetTextDirection(..)>
1635     if ( pNd )
1636     {
1637         nRet = pNd->GetTextDirection( rPos, pPt );
1638     }
1639     if ( nRet == SvxFrameDirection::Unknown )
1640     {
1641         const SvxFrameDirectionItem* pItem = nullptr;
1642         if( pNd )
1643         {
1644             // Are we in a FlyFrame? Then look at that for the correct attribute
1645             const SwFrameFormat* pFlyFormat = pNd->GetFlyFormat();
1646             while( pFlyFormat )
1647             {
1648                 pItem = &pFlyFormat->GetFrameDir();
1649                 if( SvxFrameDirection::Environment == pItem->GetValue() )
1650                 {
1651                     pItem = nullptr;
1652                     const SwFormatAnchor* pAnchor = &pFlyFormat->GetAnchor();
1653                     if ((RndStdIds::FLY_AT_PAGE != pAnchor->GetAnchorId()) &&
1654                         pAnchor->GetAnchorNode())
1655                     {
1656                         pFlyFormat = pAnchor->GetAnchorNode()->GetFlyFormat();
1657                     }
1658                     else
1659                         pFlyFormat = nullptr;
1660                 }
1661                 else
1662                     pFlyFormat = nullptr;
1663             }
1664 
1665             if( !pItem )
1666             {
1667                 const SwPageDesc* pPgDsc = pNd->FindPageDesc();
1668                 if( pPgDsc )
1669                     pItem = &pPgDsc->GetMaster().GetFrameDir();
1670             }
1671         }
1672         if( !pItem )
1673             pItem = &GetAttrPool().GetUserOrPoolDefaultItem( RES_FRAMEDIR );
1674         nRet = pItem->GetValue();
1675     }
1676     return nRet;
1677 }
1678 
IsInVerticalText(const SwPosition & rPos) const1679 bool SwDoc::IsInVerticalText( const SwPosition& rPos ) const
1680 {
1681     const SvxFrameDirection nDir = GetTextDirection( rPos );
1682     return SvxFrameDirection::Vertical_RL_TB == nDir || SvxFrameDirection::Vertical_LR_TB == nDir;
1683 }
1684 
GetAllLayouts()1685 o3tl::sorted_vector<SwRootFrame*> SwDoc::GetAllLayouts()
1686 {
1687     o3tl::sorted_vector<SwRootFrame*> aAllLayouts;
1688     SwViewShell *pStart = getIDocumentLayoutAccess().GetCurrentViewShell();
1689     if(pStart)
1690     {
1691         for(const SwViewShell& rShell : pStart->GetRingContainer())
1692         {
1693             if(rShell.GetLayout())
1694                 aAllLayouts.insert(rShell.GetLayout());
1695         }
1696     }
1697     return aAllLayouts;
1698 }
1699 
1700 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1701