1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <DocumentLayoutManager.hxx>
21 #include <IDocumentState.hxx>
22 #include <IDocumentUndoRedo.hxx>
23 #include <DocumentContentOperationsManager.hxx>
24 #include <IDocumentStylePoolAccess.hxx>
27 #include <layouter.hxx>
28 #include <poolfmt.hxx>
30 #include <fmtcntnt.hxx>
31 #include <fmtcnct.hxx>
33 #include <fmtanchr.hxx>
34 #include <txtflcnt.hxx>
35 #include <fmtflcnt.hxx>
37 #include <unoframe.hxx>
38 #include <textboxhelper.hxx>
39 #include <ndindex.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
;
52 DocumentLayoutManager::DocumentLayoutManager( SwDoc
& i_rSwdoc
) :
54 mpCurrentView( nullptr )
58 const SwViewShell
*DocumentLayoutManager::GetCurrentViewShell() const
63 SwViewShell
*DocumentLayoutManager::GetCurrentViewShell()
68 void DocumentLayoutManager::SetCurrentViewShell( SwViewShell
* 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();
81 SwRootFrame
*DocumentLayoutManager::GetCurrentLayout()
83 if(GetCurrentViewShell())
84 return GetCurrentViewShell()->GetLayout();
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;
121 case RndStdIds::HEADER
:
122 case RndStdIds::HEADERL
:
123 case RndStdIds::HEADERR
:
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
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
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!
155 m_rDoc
.getIDocumentState().ResetModified();
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));
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!" );
185 "LayoutFormat was requested with an invalid Request." );
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
& )
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
));
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();
251 sw::SpzFrameFormats
* pSpzs
= pFormat
->GetDoc()->GetSpzFrameFormats();
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();
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
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
318 The Anchor attribute's position is always set to 0! */
319 SwFrameFormat
*DocumentLayoutManager::CopyLayoutFormat(
320 const SwFrameFormat
& rSource
,
321 const SwFormatAnchor
& rNewAnchor
,
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
);
340 bool bCheckControlLayer
= false;
341 rSource
.CallSwClientNotify(sw::CheckDrawFrameFormatLayerHint(&bCheckControlLayer
));
343 bCheckControlLayer
&&
344 ((RndStdIds::FLY_AT_PARA
== rNewAnchor
.GetAnchorId()) || (RndStdIds::FLY_AT_FLY
== rNewAnchor
.GetAnchorId()) || (RndStdIds::FLY_AT_CHAR
== rNewAnchor
.GetAnchorId())) &&
348 // just return if we can't copy this
352 SwFrameFormat
* pDest
= m_rDoc
.GetDfltFrameFormat();
353 if( rSource
.GetRegisteredIn() != pSrcDoc
->GetDfltFrameFormat() )
354 pDest
= m_rDoc
.CopyFrameFormat( *static_cast<const SwFrameFormat
*>(rSource
.GetRegisteredIn()) );
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
);
366 SwXFrame::GetOrCreateSdrObject(*pFormat
);
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
);
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() );
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
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);
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.
440 pDest
->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::MAKE_FRAMES
));
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 );
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();
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
);
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
483 void DocumentLayoutManager::ClearSwLayouterEntries()
485 SwLayouter::ClearMovedFwdFrames( m_rDoc
);
486 SwLayouter::ClearObjsTmpConsiderWrapInfluence( m_rDoc
);
488 SwLayouter::ClearMoveBwdLayoutInfo( m_rDoc
);
491 DocumentLayoutManager::~DocumentLayoutManager()
496 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */