ITEM: Refactor ItemType
[LibreOffice.git] / sw / source / core / doc / DocumentLayoutManager.cxx
blobc1d7cfb2edf7258568196c01bce6616ac7496ab5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <DocumentLayoutManager.hxx>
20 #include <doc.hxx>
21 #include <IDocumentState.hxx>
22 #include <IDocumentUndoRedo.hxx>
23 #include <DocumentContentOperationsManager.hxx>
24 #include <IDocumentStylePoolAccess.hxx>
25 #include <undobj.hxx>
26 #include <viewsh.hxx>
27 #include <layouter.hxx>
28 #include <poolfmt.hxx>
29 #include <frmfmt.hxx>
30 #include <fmtcntnt.hxx>
31 #include <fmtcnct.hxx>
32 #include <ndole.hxx>
33 #include <fmtanchr.hxx>
34 #include <txtflcnt.hxx>
35 #include <fmtflcnt.hxx>
36 #include <ndtxt.hxx>
37 #include <unoframe.hxx>
38 #include <textboxhelper.hxx>
39 #include <ndindex.hxx>
40 #include <pam.hxx>
41 #include <frameformats.hxx>
42 #include <com/sun/star/embed/EmbedStates.hpp>
43 #include <svx/svdobj.hxx>
44 #include <svx/svdpage.hxx>
45 #include <osl/diagnose.h>
46 #include <vcl/scheduler.hxx>
48 using namespace ::com::sun::star;
50 namespace sw
53 DocumentLayoutManager::DocumentLayoutManager( SwDoc& i_rSwdoc ) :
54 m_rDoc( i_rSwdoc ),
55 mpCurrentView( nullptr )
59 const SwViewShell *DocumentLayoutManager::GetCurrentViewShell() const
61 return mpCurrentView;
64 SwViewShell *DocumentLayoutManager::GetCurrentViewShell()
66 return mpCurrentView;
69 void DocumentLayoutManager::SetCurrentViewShell( SwViewShell* pNew )
71 mpCurrentView = pNew;
74 // It must be able to communicate to a SwViewShell. This is going to be removed later.
75 const SwRootFrame *DocumentLayoutManager::GetCurrentLayout() const
77 if(GetCurrentViewShell())
78 return GetCurrentViewShell()->GetLayout();
79 return nullptr;
82 SwRootFrame *DocumentLayoutManager::GetCurrentLayout()
84 if(GetCurrentViewShell())
85 return GetCurrentViewShell()->GetLayout();
86 return nullptr;
89 bool DocumentLayoutManager::HasLayout() const
91 // if there is a view, there is always a layout
92 return (mpCurrentView != nullptr);
95 SwLayouter* DocumentLayoutManager::GetLayouter()
97 return mpLayouter.get();
100 const SwLayouter* DocumentLayoutManager::GetLayouter() const
102 return mpLayouter.get();
105 void DocumentLayoutManager::SetLayouter( SwLayouter* pNew )
107 mpLayouter.reset( pNew );
110 /** Create a new format whose settings fit to the Request by default.
112 The format is put into the respective format array.
113 If there already is a fitting format, it is returned instead. */
114 SwFrameFormat *DocumentLayoutManager::MakeLayoutFormat( RndStdIds eRequest, const SfxItemSet* pSet )
116 SwFrameFormat *pFormat = nullptr;
117 const bool bMod = m_rDoc.getIDocumentState().IsModified();
118 bool bHeader = false;
120 switch ( eRequest )
122 case RndStdIds::HEADER:
123 case RndStdIds::HEADERL:
124 case RndStdIds::HEADERR:
126 bHeader = true;
127 [[fallthrough]];
129 case RndStdIds::FOOTER:
131 pFormat = new SwFrameFormat( m_rDoc.GetAttrPool(),
132 (bHeader ? u"Right header"_ustr : u"Right footer"_ustr),
133 m_rDoc.GetDfltFrameFormat() );
135 const SwNode& rEndOfAutotext( m_rDoc.GetNodes().GetEndOfAutotext() );
136 SwStartNode* pSttNd =
137 m_rDoc.GetNodes().MakeTextSection
138 ( rEndOfAutotext,
139 bHeader ? SwHeaderStartNode : SwFooterStartNode,
140 m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(o3tl::narrowing<sal_uInt16>( bHeader
141 ? ( eRequest == RndStdIds::HEADERL
142 ? RES_POOLCOLL_HEADERL
143 : eRequest == RndStdIds::HEADERR
144 ? RES_POOLCOLL_HEADERR
145 : RES_POOLCOLL_HEADER )
146 : RES_POOLCOLL_FOOTER
147 ) ) );
148 pFormat->SetFormatAttr( SwFormatContent( pSttNd ));
150 if( pSet ) // Set a few more attributes
151 pFormat->SetFormatAttr( *pSet );
153 // Why set it back? Doc has changed, or not?
154 // In any case, wrong for the FlyFrames!
155 if ( !bMod )
156 m_rDoc.getIDocumentState().ResetModified();
158 break;
160 case RndStdIds::DRAW_OBJECT:
162 pFormat = m_rDoc.MakeDrawFrameFormat( OUString(), m_rDoc.GetDfltFrameFormat() );
163 if( pSet ) // Set a few more attributes
164 pFormat->SetFormatAttr( *pSet );
166 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
168 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
169 std::make_unique<SwUndoInsLayFormat>(pFormat, SwNodeOffset(0), 0));
172 break;
174 #if OSL_DEBUG_LEVEL > 0
175 case RndStdIds::FLY_AT_PAGE:
176 case RndStdIds::FLY_AT_CHAR:
177 case RndStdIds::FLY_AT_FLY:
178 case RndStdIds::FLY_AT_PARA:
179 case RndStdIds::FLY_AS_CHAR:
180 OSL_FAIL( "use new interface instead: SwDoc::MakeFlySection!" );
181 break;
182 #endif
184 default:
185 OSL_ENSURE( false,
186 "LayoutFormat was requested with an invalid Request." );
189 return pFormat;
192 /// Deletes the denoted format and its content.
193 void DocumentLayoutManager::DelLayoutFormat( SwFrameFormat *pFormat )
195 // Do not paint, until the destruction is complete. Paint may access the layout and nodes
196 // while it's in inconsistent state, and crash.
197 Scheduler::IdlesLockGuard g;
198 // A chain of frames needs to be merged, if necessary,
199 // so that the Frame's contents are adjusted accordingly before we destroy the Frames.
200 const SwFormatChain &rChain = pFormat->GetChain();
201 if ( rChain.GetPrev() )
203 SwFormatChain aChain( rChain.GetPrev()->GetChain() );
204 aChain.SetNext( rChain.GetNext() );
205 m_rDoc.SetAttr( aChain, *rChain.GetPrev() );
207 if ( rChain.GetNext() )
209 SwFormatChain aChain( rChain.GetNext()->GetChain() );
210 aChain.SetPrev( rChain.GetPrev() );
211 m_rDoc.SetAttr( aChain, *rChain.GetNext() );
214 const SwNodeIndex* pCntIdx = nullptr;
215 // The draw format doesn't own its content, it just has a pointer to it.
216 if (pFormat->Which() != RES_DRAWFRMFMT)
217 pCntIdx = pFormat->GetContent().GetContentIdx();
218 if (pCntIdx && !m_rDoc.GetIDocumentUndoRedo().DoesUndo())
220 // Disconnect if it's an OLE object
221 SwOLENode* pOLENd = m_rDoc.GetNodes()[ pCntIdx->GetIndex()+1 ]->GetOLENode();
222 if( pOLENd && pOLENd->GetOLEObj().IsOleRef() )
226 pOLENd->GetOLEObj().GetOleRef()->changeState( embed::EmbedStates::LOADED );
228 catch ( uno::Exception& )
234 // Destroy Frames
235 pFormat->DelFrames();
237 // Only FlyFrames are undoable at first
238 const sal_uInt16 nWh = pFormat->Which();
239 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo() &&
240 (RES_FLYFRMFMT == nWh || RES_DRAWFRMFMT == nWh))
242 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDelLayFormat>( pFormat ));
244 else
246 // #i32089# - delete at-frame anchored objects
247 if ( nWh == RES_FLYFRMFMT )
249 // determine frame formats of at-frame anchored objects
250 const SwNodeIndex* pContentIdx = nullptr;
251 if (pFormat->Which() != RES_DRAWFRMFMT)
252 pContentIdx = pFormat->GetContent().GetContentIdx();
253 if (pContentIdx)
255 sw::SpzFrameFormats* pSpzs = pFormat->GetDoc()->GetSpzFrameFormats();
256 if ( pSpzs )
258 std::vector<SwFrameFormat*> aToDeleteFrameFormats;
259 const SwNodeOffset nNodeIdxOfFlyFormat( pContentIdx->GetIndex() );
261 for(sw::SpzFrameFormat* pSpz: *pSpzs)
263 const SwFormatAnchor &rAnch = pSpz->GetAnchor();
264 if ( rAnch.GetAnchorId() == RndStdIds::FLY_AT_FLY &&
265 rAnch.GetAnchorNode()->GetIndex() == nNodeIdxOfFlyFormat )
267 aToDeleteFrameFormats.push_back(pSpz);
271 // delete found frame formats
272 while ( !aToDeleteFrameFormats.empty() )
274 SwFrameFormat* pTmpFormat = aToDeleteFrameFormats.back();
275 pFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pTmpFormat );
277 aToDeleteFrameFormats.pop_back();
283 // Delete content
284 if( pCntIdx )
286 SwNode *pNode = &pCntIdx->GetNode();
287 const_cast<SwFormatContent&>(pFormat->GetFormatAttr( RES_CNTNT )).SetNewContentIdx( nullptr );
288 m_rDoc.getIDocumentContentOperations().DeleteSection( pNode );
291 // Delete the character for FlyFrames anchored as char (if necessary)
292 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
293 if ((RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) && rAnchor.GetAnchorNode())
295 SwTextNode *pTextNd = rAnchor.GetAnchorNode()->GetTextNode();
297 // attribute is still in text node, delete it
298 if ( pTextNd )
300 SwTextFlyCnt* const pAttr = static_cast<SwTextFlyCnt*>(
301 pTextNd->GetTextAttrForCharAt( rAnchor.GetAnchorContentOffset(),
302 RES_TXTATR_FLYCNT ));
303 if ( pAttr && (pAttr->GetFlyCnt().GetFrameFormat() == pFormat) )
305 // don't delete, set pointer to 0
306 const_cast<SwFormatFlyCnt&>(pAttr->GetFlyCnt()).SetFlyFormat();
307 pTextNd->EraseText( *rAnchor.GetContentAnchor(), 1 );
312 m_rDoc.DelFrameFormat( pFormat );
314 m_rDoc.getIDocumentState().SetModified();
317 /** Copies the stated format (pSrc) to pDest and returns pDest.
319 If there's no pDest, it is created.
320 If the source format is located in another document, also copy correctly
321 in this case.
322 The Anchor attribute's position is always set to 0! */
323 SwFrameFormat *DocumentLayoutManager::CopyLayoutFormat(
324 const SwFrameFormat& rSource,
325 const SwFormatAnchor& rNewAnchor,
326 bool bSetTextFlyAtt,
327 bool bMakeFrames )
329 const bool bFly = RES_FLYFRMFMT == rSource.Which();
330 const bool bDraw = RES_DRAWFRMFMT == rSource.Which();
331 OSL_ENSURE( bFly || bDraw, "this method only works for fly or draw" );
333 SwDoc* pSrcDoc = const_cast<SwDoc*>(rSource.GetDoc());
335 // May we copy this object?
336 // We may, unless it's 1) it's a control (and therefore a draw)
337 // 2) anchored in a header/footer
338 // 3) anchored (to paragraph?)
339 bool bMayNotCopy = false;
340 const SwNode* pCAnchor = rNewAnchor.GetAnchorNode();
341 bool bInHeaderFooter = pCAnchor && m_rDoc.IsInHeaderFooter(*pCAnchor);
342 if(bDraw)
344 bool bCheckControlLayer = false;
345 rSource.CallSwClientNotify(sw::CheckDrawFrameFormatLayerHint(&bCheckControlLayer));
346 bMayNotCopy =
347 bCheckControlLayer &&
348 ((RndStdIds::FLY_AT_PARA == rNewAnchor.GetAnchorId()) || (RndStdIds::FLY_AT_FLY == rNewAnchor.GetAnchorId()) || (RndStdIds::FLY_AT_CHAR == rNewAnchor.GetAnchorId())) &&
349 bInHeaderFooter;
352 // just return if we can't copy this
353 if( bMayNotCopy )
354 return nullptr;
356 SwFrameFormat* pDest = m_rDoc.GetDfltFrameFormat();
357 if( rSource.GetRegisteredIn() != pSrcDoc->GetDfltFrameFormat() )
358 pDest = m_rDoc.CopyFrameFormat( *static_cast<const SwFrameFormat*>(rSource.GetRegisteredIn()) );
359 if( bFly )
361 // #i11176#
362 // To do a correct cloning concerning the ZOrder for all objects
363 // it is necessary to actually create a draw object for fly frames, too.
364 // These are then added to the DrawingLayer (which needs to exist).
365 // Together with correct sorting of all drawinglayer based objects
366 // before cloning ZOrder transfer works correctly then.
367 SwFlyFrameFormat *pFormat = m_rDoc.MakeFlyFrameFormat( rSource.GetName(), pDest );
368 pDest = pFormat;
370 SwXFrame::GetOrCreateSdrObject(*pFormat);
372 else
373 pDest = m_rDoc.MakeDrawFrameFormat( OUString(), pDest );
375 // Copy all other or new attributes
376 pDest->CopyAttrs( rSource );
378 // Do not copy chains
379 pDest->ResetFormatAttr( RES_CHAIN );
381 if( bFly )
383 // Duplicate the content.
384 const SwNode& rCSttNd = rSource.GetContent().GetContentIdx()->GetNode();
385 SwNodeRange aRg( rCSttNd, SwNodeOffset(1), *rCSttNd.EndOfSectionNode() );
387 SwStartNode* pSttNd = SwNodes::MakeEmptySection( m_rDoc.GetNodes().GetEndOfAutotext(), SwFlyStartNode );
389 // Set the Anchor/ContentIndex first.
390 // Within the copying part, we can access the values (DrawFormat in Headers and Footers)
391 SwNodeIndex aIdx( *pSttNd );
392 SwFormatContent aAttr( rSource.GetContent() );
393 aAttr.SetNewContentIdx( &aIdx );
394 pDest->SetFormatAttr( aAttr );
395 pDest->SetFormatAttr( rNewAnchor );
397 if( !m_rDoc.IsCopyIsMove() || &m_rDoc != pSrcDoc )
399 if( (m_rDoc.IsInReading() && !bInHeaderFooter) || m_rDoc.IsInMailMerge() )
400 pDest->SetFormatName( OUString() );
401 else
403 // Test first if the name is already taken, if so generate a new one.
404 SwNodeType nNdTyp = aRg.aStart.GetNode().GetNodeType();
406 OUString sOld( pDest->GetName() );
407 pDest->SetFormatName( OUString() );
408 if( m_rDoc.FindFlyByName( sOld, nNdTyp ) ) // found one
409 switch( nNdTyp )
411 case SwNodeType::Grf: sOld = m_rDoc.GetUniqueGrfName(sOld); break;
412 case SwNodeType::Ole: sOld = m_rDoc.GetUniqueOLEName(); break;
413 default: sOld = m_rDoc.GetUniqueFrameName(); break;
416 pDest->SetFormatName( sOld );
420 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
422 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsLayFormat>(pDest,SwNodeOffset(0),0));
425 // Make sure that FlyFrames in FlyFrames are copied
426 aIdx = *pSttNd->EndOfSectionNode();
428 //fdo#36631 disable (scoped) any undo operations associated with the
429 //contact object itself. They should be managed by SwUndoInsLayFormat.
430 const ::sw::DrawUndoGuard drawUndoGuard(m_rDoc.GetIDocumentUndoRedo());
432 pSrcDoc->GetDocumentContentOperationsManager().CopyWithFlyInFly(aRg, aIdx.GetNode(), nullptr, false, true, true);
434 else
436 OSL_ENSURE( RES_DRAWFRMFMT == rSource.Which(), "Neither Fly nor Draw." );
437 // #i52780# - Note: moving object to visible layer not needed.
438 rSource.CallSwClientNotify(sw::DrawFormatLayoutCopyHint(static_cast<SwDrawFrameFormat&>(*pDest), m_rDoc));
440 if(pDest->GetAnchor() == rNewAnchor)
442 // Do *not* connect to layout, if a <MakeFrames> will not be called.
443 if(bMakeFrames)
444 pDest->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::MAKE_FRAMES));
447 else
448 pDest->SetFormatAttr( rNewAnchor );
450 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
452 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsLayFormat>(pDest,SwNodeOffset(0),0));
456 if (bSetTextFlyAtt && (RndStdIds::FLY_AS_CHAR == rNewAnchor.GetAnchorId()))
458 SwNode* pAnchorNode = rNewAnchor.GetAnchorNode();
459 SwFormatFlyCnt aFormat( pDest );
460 assert(pAnchorNode->GetTextNode() && "sw.core: text node expected");
461 if (SwTextNode *pTextNd = pAnchorNode->GetTextNode())
462 pTextNd->InsertItem( aFormat, rNewAnchor.GetAnchorContentOffset(), 0 );
465 if( bMakeFrames )
466 pDest->MakeFrames();
468 if (pDest->GetName().isEmpty())
470 // Format name should have unique name. Let's use object name as a fallback
471 SdrObject *pObj = pDest->FindSdrObject();
472 if (pObj)
473 pDest->SetFormatName(pObj->GetName());
476 // If the draw format has a TextBox, then copy its fly format as well.
477 if (const auto& pTextBoxes = rSource.GetOtherTextBoxFormats())
478 pTextBoxes->Clone(&m_rDoc, rNewAnchor, pDest, bSetTextFlyAtt, bMakeFrames);
480 return pDest;
483 //Load document from fdo#42534 under valgrind, drag the scrollbar down so full
484 //document layout is triggered. Close document before layout has completed, and
485 //SwAnchoredObject objects deleted by the deletion of layout remain referenced
486 //by the SwLayouter
487 void DocumentLayoutManager::ClearSwLayouterEntries()
489 SwLayouter::ClearMovedFwdFrames( m_rDoc );
490 SwLayouter::ClearObjsTmpConsiderWrapInfluence( m_rDoc );
491 // #i65250#
492 SwLayouter::ClearMoveBwdLayoutInfo( m_rDoc );
495 DocumentLayoutManager::~DocumentLayoutManager()
500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */