android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / doc / DocumentLayoutManager.cxx
blob6481f104c737deaca73e107f6009b08fcc44d488
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>
47 using namespace ::com::sun::star;
49 namespace sw
52 DocumentLayoutManager::DocumentLayoutManager( SwDoc& i_rSwdoc ) :
53 m_rDoc( i_rSwdoc ),
54 mpCurrentView( nullptr )
58 const SwViewShell *DocumentLayoutManager::GetCurrentViewShell() const
60 return mpCurrentView;
63 SwViewShell *DocumentLayoutManager::GetCurrentViewShell()
65 return mpCurrentView;
68 void DocumentLayoutManager::SetCurrentViewShell( SwViewShell* pNew )
70 mpCurrentView = pNew;
73 // It must be able to communicate to a SwViewShell. This is going to be removed later.
74 const SwRootFrame *DocumentLayoutManager::GetCurrentLayout() const
76 if(GetCurrentViewShell())
77 return GetCurrentViewShell()->GetLayout();
78 return nullptr;
81 SwRootFrame *DocumentLayoutManager::GetCurrentLayout()
83 if(GetCurrentViewShell())
84 return GetCurrentViewShell()->GetLayout();
85 return nullptr;
88 bool DocumentLayoutManager::HasLayout() const
90 // if there is a view, there is always a layout
91 return (mpCurrentView != nullptr);
94 SwLayouter* DocumentLayoutManager::GetLayouter()
96 return mpLayouter.get();
99 const SwLayouter* DocumentLayoutManager::GetLayouter() const
101 return mpLayouter.get();
104 void DocumentLayoutManager::SetLayouter( SwLayouter* pNew )
106 mpLayouter.reset( pNew );
109 /** Create a new format whose settings fit to the Request by default.
111 The format is put into the respective format array.
112 If there already is a fitting format, it is returned instead. */
113 SwFrameFormat *DocumentLayoutManager::MakeLayoutFormat( RndStdIds eRequest, const SfxItemSet* pSet )
115 SwFrameFormat *pFormat = nullptr;
116 const bool bMod = m_rDoc.getIDocumentState().IsModified();
117 bool bHeader = false;
119 switch ( eRequest )
121 case RndStdIds::HEADER:
122 case RndStdIds::HEADERL:
123 case RndStdIds::HEADERR:
125 bHeader = true;
126 [[fallthrough]];
128 case RndStdIds::FOOTER:
130 pFormat = new SwFrameFormat( m_rDoc.GetAttrPool(),
131 (bHeader ? "Right header" : "Right footer"),
132 m_rDoc.GetDfltFrameFormat() );
134 const SwNode& rEndOfAutotext( m_rDoc.GetNodes().GetEndOfAutotext() );
135 SwStartNode* pSttNd =
136 m_rDoc.GetNodes().MakeTextSection
137 ( rEndOfAutotext,
138 bHeader ? SwHeaderStartNode : SwFooterStartNode,
139 m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(o3tl::narrowing<sal_uInt16>( bHeader
140 ? ( eRequest == RndStdIds::HEADERL
141 ? RES_POOLCOLL_HEADERL
142 : eRequest == RndStdIds::HEADERR
143 ? RES_POOLCOLL_HEADERR
144 : RES_POOLCOLL_HEADER )
145 : RES_POOLCOLL_FOOTER
146 ) ) );
147 pFormat->SetFormatAttr( SwFormatContent( pSttNd ));
149 if( pSet ) // Set a few more attributes
150 pFormat->SetFormatAttr( *pSet );
152 // Why set it back? Doc has changed, or not?
153 // In any case, wrong for the FlyFrames!
154 if ( !bMod )
155 m_rDoc.getIDocumentState().ResetModified();
157 break;
159 case RndStdIds::DRAW_OBJECT:
161 pFormat = m_rDoc.MakeDrawFrameFormat( OUString(), m_rDoc.GetDfltFrameFormat() );
162 if( pSet ) // Set a few more attributes
163 pFormat->SetFormatAttr( *pSet );
165 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
167 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
168 std::make_unique<SwUndoInsLayFormat>(pFormat, SwNodeOffset(0), 0));
171 break;
173 #if OSL_DEBUG_LEVEL > 0
174 case RndStdIds::FLY_AT_PAGE:
175 case RndStdIds::FLY_AT_CHAR:
176 case RndStdIds::FLY_AT_FLY:
177 case RndStdIds::FLY_AT_PARA:
178 case RndStdIds::FLY_AS_CHAR:
179 OSL_FAIL( "use new interface instead: SwDoc::MakeFlySection!" );
180 break;
181 #endif
183 default:
184 OSL_ENSURE( false,
185 "LayoutFormat was requested with an invalid Request." );
188 return pFormat;
191 /// Deletes the denoted format and its content.
192 void DocumentLayoutManager::DelLayoutFormat( SwFrameFormat *pFormat )
194 // A chain of frames needs to be merged, if necessary,
195 // so that the Frame's contents are adjusted accordingly before we destroy the Frames.
196 const SwFormatChain &rChain = pFormat->GetChain();
197 if ( rChain.GetPrev() )
199 SwFormatChain aChain( rChain.GetPrev()->GetChain() );
200 aChain.SetNext( rChain.GetNext() );
201 m_rDoc.SetAttr( aChain, *rChain.GetPrev() );
203 if ( rChain.GetNext() )
205 SwFormatChain aChain( rChain.GetNext()->GetChain() );
206 aChain.SetPrev( rChain.GetPrev() );
207 m_rDoc.SetAttr( aChain, *rChain.GetNext() );
210 const SwNodeIndex* pCntIdx = nullptr;
211 // The draw format doesn't own its content, it just has a pointer to it.
212 if (pFormat->Which() != RES_DRAWFRMFMT)
213 pCntIdx = pFormat->GetContent().GetContentIdx();
214 if (pCntIdx && !m_rDoc.GetIDocumentUndoRedo().DoesUndo())
216 // Disconnect if it's an OLE object
217 SwOLENode* pOLENd = m_rDoc.GetNodes()[ pCntIdx->GetIndex()+1 ]->GetOLENode();
218 if( pOLENd && pOLENd->GetOLEObj().IsOleRef() )
222 pOLENd->GetOLEObj().GetOleRef()->changeState( embed::EmbedStates::LOADED );
224 catch ( uno::Exception& )
230 // Destroy Frames
231 pFormat->DelFrames();
233 // Only FlyFrames are undoable at first
234 const sal_uInt16 nWh = pFormat->Which();
235 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo() &&
236 (RES_FLYFRMFMT == nWh || RES_DRAWFRMFMT == nWh))
238 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDelLayFormat>( pFormat ));
240 else
242 // #i32089# - delete at-frame anchored objects
243 if ( nWh == RES_FLYFRMFMT )
245 // determine frame formats of at-frame anchored objects
246 const SwNodeIndex* pContentIdx = nullptr;
247 if (pFormat->Which() != RES_DRAWFRMFMT)
248 pContentIdx = pFormat->GetContent().GetContentIdx();
249 if (pContentIdx)
251 sw::SpzFrameFormats* pSpzs = pFormat->GetDoc()->GetSpzFrameFormats();
252 if ( pSpzs )
254 std::vector<SwFrameFormat*> aToDeleteFrameFormats;
255 const SwNodeOffset nNodeIdxOfFlyFormat( pContentIdx->GetIndex() );
257 for(sw::SpzFrameFormat* pSpz: *pSpzs)
259 const SwFormatAnchor &rAnch = pSpz->GetAnchor();
260 if ( rAnch.GetAnchorId() == RndStdIds::FLY_AT_FLY &&
261 rAnch.GetAnchorNode()->GetIndex() == nNodeIdxOfFlyFormat )
263 aToDeleteFrameFormats.push_back(pSpz);
267 // delete found frame formats
268 while ( !aToDeleteFrameFormats.empty() )
270 SwFrameFormat* pTmpFormat = aToDeleteFrameFormats.back();
271 pFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pTmpFormat );
273 aToDeleteFrameFormats.pop_back();
279 // Delete content
280 if( pCntIdx )
282 SwNode *pNode = &pCntIdx->GetNode();
283 const_cast<SwFormatContent&>(pFormat->GetFormatAttr( RES_CNTNT )).SetNewContentIdx( nullptr );
284 m_rDoc.getIDocumentContentOperations().DeleteSection( pNode );
287 // Delete the character for FlyFrames anchored as char (if necessary)
288 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
289 if ((RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) && rAnchor.GetAnchorNode())
291 SwTextNode *pTextNd = rAnchor.GetAnchorNode()->GetTextNode();
293 // attribute is still in text node, delete it
294 if ( pTextNd )
296 SwTextFlyCnt* const pAttr = static_cast<SwTextFlyCnt*>(
297 pTextNd->GetTextAttrForCharAt( rAnchor.GetAnchorContentOffset(),
298 RES_TXTATR_FLYCNT ));
299 if ( pAttr && (pAttr->GetFlyCnt().GetFrameFormat() == pFormat) )
301 // don't delete, set pointer to 0
302 const_cast<SwFormatFlyCnt&>(pAttr->GetFlyCnt()).SetFlyFormat();
303 pTextNd->EraseText( *rAnchor.GetContentAnchor(), 1 );
308 m_rDoc.DelFrameFormat( pFormat );
310 m_rDoc.getIDocumentState().SetModified();
313 /** Copies the stated format (pSrc) to pDest and returns pDest.
315 If there's no pDest, it is created.
316 If the source format is located in another document, also copy correctly
317 in this case.
318 The Anchor attribute's position is always set to 0! */
319 SwFrameFormat *DocumentLayoutManager::CopyLayoutFormat(
320 const SwFrameFormat& rSource,
321 const SwFormatAnchor& rNewAnchor,
322 bool bSetTextFlyAtt,
323 bool bMakeFrames )
325 const bool bFly = RES_FLYFRMFMT == rSource.Which();
326 const bool bDraw = RES_DRAWFRMFMT == rSource.Which();
327 OSL_ENSURE( bFly || bDraw, "this method only works for fly or draw" );
329 SwDoc* pSrcDoc = const_cast<SwDoc*>(rSource.GetDoc());
331 // May we copy this object?
332 // We may, unless it's 1) it's a control (and therefore a draw)
333 // 2) anchored in a header/footer
334 // 3) anchored (to paragraph?)
335 bool bMayNotCopy = false;
336 const SwNode* pCAnchor = rNewAnchor.GetAnchorNode();
337 bool bInHeaderFooter = pCAnchor && m_rDoc.IsInHeaderFooter(*pCAnchor);
338 if(bDraw)
340 bool bCheckControlLayer = false;
341 rSource.CallSwClientNotify(sw::CheckDrawFrameFormatLayerHint(&bCheckControlLayer));
342 bMayNotCopy =
343 bCheckControlLayer &&
344 ((RndStdIds::FLY_AT_PARA == rNewAnchor.GetAnchorId()) || (RndStdIds::FLY_AT_FLY == rNewAnchor.GetAnchorId()) || (RndStdIds::FLY_AT_CHAR == rNewAnchor.GetAnchorId())) &&
345 bInHeaderFooter;
348 // just return if we can't copy this
349 if( bMayNotCopy )
350 return nullptr;
352 SwFrameFormat* pDest = m_rDoc.GetDfltFrameFormat();
353 if( rSource.GetRegisteredIn() != pSrcDoc->GetDfltFrameFormat() )
354 pDest = m_rDoc.CopyFrameFormat( *static_cast<const SwFrameFormat*>(rSource.GetRegisteredIn()) );
355 if( bFly )
357 // #i11176#
358 // To do a correct cloning concerning the ZOrder for all objects
359 // it is necessary to actually create a draw object for fly frames, too.
360 // These are then added to the DrawingLayer (which needs to exist).
361 // Together with correct sorting of all drawinglayer based objects
362 // before cloning ZOrder transfer works correctly then.
363 SwFlyFrameFormat *pFormat = m_rDoc.MakeFlyFrameFormat( rSource.GetName(), pDest );
364 pDest = pFormat;
366 SwXFrame::GetOrCreateSdrObject(*pFormat);
368 else
369 pDest = m_rDoc.MakeDrawFrameFormat( OUString(), pDest );
371 // Copy all other or new attributes
372 pDest->CopyAttrs( rSource );
374 // Do not copy chains
375 pDest->ResetFormatAttr( RES_CHAIN );
377 if( bFly )
379 // Duplicate the content.
380 const SwNode& rCSttNd = rSource.GetContent().GetContentIdx()->GetNode();
381 SwNodeRange aRg( rCSttNd, SwNodeOffset(1), *rCSttNd.EndOfSectionNode() );
383 SwStartNode* pSttNd = SwNodes::MakeEmptySection( m_rDoc.GetNodes().GetEndOfAutotext(), SwFlyStartNode );
385 // Set the Anchor/ContentIndex first.
386 // Within the copying part, we can access the values (DrawFormat in Headers and Footers)
387 SwNodeIndex aIdx( *pSttNd );
388 SwFormatContent aAttr( rSource.GetContent() );
389 aAttr.SetNewContentIdx( &aIdx );
390 pDest->SetFormatAttr( aAttr );
391 pDest->SetFormatAttr( rNewAnchor );
393 if( !m_rDoc.IsCopyIsMove() || &m_rDoc != pSrcDoc )
395 if( (m_rDoc.IsInReading() && !bInHeaderFooter) || m_rDoc.IsInMailMerge() )
396 pDest->SetFormatName( OUString() );
397 else
399 // Test first if the name is already taken, if so generate a new one.
400 SwNodeType nNdTyp = aRg.aStart.GetNode().GetNodeType();
402 OUString sOld( pDest->GetName() );
403 pDest->SetFormatName( OUString() );
404 if( m_rDoc.FindFlyByName( sOld, nNdTyp ) ) // found one
405 switch( nNdTyp )
407 case SwNodeType::Grf: sOld = m_rDoc.GetUniqueGrfName(sOld); break;
408 case SwNodeType::Ole: sOld = m_rDoc.GetUniqueOLEName(); break;
409 default: sOld = m_rDoc.GetUniqueFrameName(); break;
412 pDest->SetFormatName( sOld );
416 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
418 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsLayFormat>(pDest,SwNodeOffset(0),0));
421 // Make sure that FlyFrames in FlyFrames are copied
422 aIdx = *pSttNd->EndOfSectionNode();
424 //fdo#36631 disable (scoped) any undo operations associated with the
425 //contact object itself. They should be managed by SwUndoInsLayFormat.
426 const ::sw::DrawUndoGuard drawUndoGuard(m_rDoc.GetIDocumentUndoRedo());
428 pSrcDoc->GetDocumentContentOperationsManager().CopyWithFlyInFly(aRg, aIdx.GetNode(), nullptr, false, true, true);
430 else
432 OSL_ENSURE( RES_DRAWFRMFMT == rSource.Which(), "Neither Fly nor Draw." );
433 // #i52780# - Note: moving object to visible layer not needed.
434 rSource.CallSwClientNotify(sw::DrawFormatLayoutCopyHint(static_cast<SwDrawFrameFormat&>(*pDest), m_rDoc));
436 if(pDest->GetAnchor() == rNewAnchor)
438 // Do *not* connect to layout, if a <MakeFrames> will not be called.
439 if(bMakeFrames)
440 pDest->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::MAKE_FRAMES));
443 else
444 pDest->SetFormatAttr( rNewAnchor );
446 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
448 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsLayFormat>(pDest,SwNodeOffset(0),0));
452 if (bSetTextFlyAtt && (RndStdIds::FLY_AS_CHAR == rNewAnchor.GetAnchorId()))
454 SwNode* pAnchorNode = rNewAnchor.GetAnchorNode();
455 SwFormatFlyCnt aFormat( pDest );
456 assert(pAnchorNode->GetTextNode() && "sw.core: text node expected");
457 if (SwTextNode *pTextNd = pAnchorNode->GetTextNode())
458 pTextNd->InsertItem( aFormat, rNewAnchor.GetAnchorContentOffset(), 0 );
461 if( bMakeFrames )
462 pDest->MakeFrames();
464 if (pDest->GetName().isEmpty())
466 // Format name should have unique name. Let's use object name as a fallback
467 SdrObject *pObj = pDest->FindSdrObject();
468 if (pObj)
469 pDest->SetFormatName(pObj->GetName());
472 // If the draw format has a TextBox, then copy its fly format as well.
473 if (const auto& pTextBoxes = rSource.GetOtherTextBoxFormats())
474 pTextBoxes->Clone(&m_rDoc, rNewAnchor, pDest, bSetTextFlyAtt, bMakeFrames);
476 return pDest;
479 //Load document from fdo#42534 under valgrind, drag the scrollbar down so full
480 //document layout is triggered. Close document before layout has completed, and
481 //SwAnchoredObject objects deleted by the deletion of layout remain referenced
482 //by the SwLayouter
483 void DocumentLayoutManager::ClearSwLayouterEntries()
485 SwLayouter::ClearMovedFwdFrames( m_rDoc );
486 SwLayouter::ClearObjsTmpConsiderWrapInfluence( m_rDoc );
487 // #i65250#
488 SwLayouter::ClearMoveBwdLayoutInfo( m_rDoc );
491 DocumentLayoutManager::~DocumentLayoutManager()
496 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */