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