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 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <config_features.h>
25 #include <config_fuzzers.h>
27 #include <o3tl/sorted_vector.hxx>
30 #include <proofreadingiterator.hxx>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/text/XFlatParagraphIteratorProvider.hpp>
33 #include <com/sun/star/linguistic2/XProofreadingIterator.hpp>
34 #include <com/sun/star/i18n/ScriptType.hpp>
36 #include <comphelper/configuration.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <comphelper/random.hxx>
39 #include <sfx2/viewfrm.hxx>
40 #include <sfx2/XmlIdRegistry.hxx>
41 #include <sal/log.hxx>
42 #include <osl/diagnose.h>
44 #include <sfx2/linkmgr.hxx>
45 #include <editeng/ulspitem.hxx>
46 #include <editeng/lrspitem.hxx>
47 #include <svl/numformat.hxx>
48 #include <unotools/lingucfg.hxx>
49 #include <svx/svdpage.hxx>
50 #include <fmtcntnt.hxx>
51 #include <fmtanchr.hxx>
52 #include <fmtfsize.hxx>
53 #include <fmtfordr.hxx>
54 #include <fmtpdsc.hxx>
55 #include <pvprtdat.hxx>
56 #include <rootfrm.hxx>
57 #include <pagedesc.hxx>
59 #include <ftninfo.hxx>
61 #include <charfmt.hxx>
63 #include <poolfmt.hxx>
66 #include <acorrect.hxx>
67 #include <visiturl.hxx>
69 #include <lineinfo.hxx>
70 #include <drawdoc.hxx>
71 #include <extinput.hxx>
74 #include <shellres.hxx>
75 #include <laycache.hxx>
77 #include <istyleaccess.hxx>
78 #include "swstylemanager.hxx"
79 #include <GrammarContact.hxx>
80 #include <OnlineAccessibilityCheck.hxx>
81 #include <tblafmt.hxx>
82 #include <MarkManager.hxx>
83 #include <UndoManager.hxx>
84 #include <DocumentDeviceManager.hxx>
85 #include <DocumentSettingManager.hxx>
86 #include <DocumentDrawModelManager.hxx>
87 #include <DocumentChartDataProviderManager.hxx>
88 #include <DocumentTimerManager.hxx>
89 #include <DocumentLinksAdministrationManager.hxx>
90 #include <DocumentListItemsManager.hxx>
91 #include <DocumentListsManager.hxx>
92 #include <DocumentOutlineNodesManager.hxx>
93 #include <DocumentContentOperationsManager.hxx>
94 #include <DocumentRedlineManager.hxx>
95 #include <DocumentFieldsManager.hxx>
96 #include <DocumentStatisticsManager.hxx>
97 #include <DocumentStateManager.hxx>
98 #include <DocumentLayoutManager.hxx>
99 #include <DocumentStylePoolManager.hxx>
100 #include <DocumentExternalDataManager.hxx>
102 #include <unocrsr.hxx>
103 #include <fmthdft.hxx>
104 #include <frameformats.hxx>
106 #include <numrule.hxx>
108 #include <sfx2/Metadatable.hxx>
109 #include <fmtmeta.hxx>
110 #include <textcontentcontrol.hxx>
112 #include <svx/xfillit0.hxx>
113 #include <unotools/configmgr.hxx>
114 #include <i18nlangtag/mslangid.hxx>
115 #include <svl/setitem.hxx>
116 #include <unotxdoc.hxx>
118 using namespace ::com::sun::star
;
119 using namespace ::com::sun::star::document
;
121 constexpr OUStringLiteral DEFAULT_CHAR_FORMAT_NAME
= u
"Character style";
124 * global functions...
126 uno::Reference
< linguistic2::XProofreadingIterator
> const & SwDoc::GetGCIterator() const
128 if (!m_xGCIterator
.is() && SvtLinguConfig().HasGrammarChecker())
130 const uno::Reference
< uno::XComponentContext
>& xContext( comphelper::getProcessComponentContext() );
133 m_xGCIterator
= sw::proofreadingiterator::get( xContext
);
135 catch (const uno::Exception
&)
137 OSL_FAIL( "No GCIterator" );
141 return m_xGCIterator
;
144 bool SwDoc::StartGrammarChecking( bool bSkipStart
)
146 // check for a visible view
147 bool bVisible
= false;
148 bool bStarted
= false;
149 const SwDocShell
*pDocShell
= GetDocShell();
152 SfxViewFrame
*pFrame
= SfxViewFrame::GetFirst( pDocShell
, false );
153 while (pFrame
&& !bVisible
)
155 if (pFrame
->IsVisible())
157 pFrame
= SfxViewFrame::GetNext( *pFrame
, pDocShell
, false );
160 //!! only documents with visible views need to be checked
161 //!! (E.g. don't check temporary documents created for printing, see printing of notes and selections.
162 //!! Those get created on the fly and get hard deleted a bit later as well, and no one should have
163 //!! a UNO reference to them)
166 uno::Reference
< linguistic2::XProofreadingIterator
> xGCIterator( GetGCIterator() );
167 if ( xGCIterator
.is() )
169 rtl::Reference
< SwXTextDocument
> xDoc
= pDocShell
->GetBaseModel();
170 uno::Reference
< text::XFlatParagraphIteratorProvider
> xFPIP( xDoc
);
172 // start automatic background checking if not active already
173 if ( xFPIP
.is() && !xGCIterator
->isProofreading( cppu::getXWeak(xDoc
.get()) ) )
178 for (auto pLayout
: GetAllLayouts())
179 { // we're starting it now, don't start grammar checker
180 // again until the user modifies the document
181 pLayout
->SetNeedGrammarCheck(false);
183 xGCIterator
->startProofreading( cppu::getXWeak(xDoc
.get()), xFPIP
);
195 static void lcl_DelFormatIndices( SwFormat
const * pFormat
)
197 SwFormatContent
&rFormatContent
= const_cast<SwFormatContent
&>(pFormat
->GetContent());
198 if ( rFormatContent
.GetContentIdx() )
199 rFormatContent
.SetNewContentIdx( nullptr );
200 SwFormatAnchor
&rFormatAnchor
= const_cast<SwFormatAnchor
&>(pFormat
->GetAnchor());
201 if ( rFormatAnchor
.GetAnchorNode() )
202 rFormatAnchor
.SetAnchor( nullptr );
209 : m_pNodes(new SwNodes(*this)),
210 mpAttrPool(new SwAttrPool(this)),
211 maOLEModifiedIdle( "sw::SwDoc maOLEModifiedIdle" ),
212 mpMarkManager(new ::sw::mark::MarkManager(*this)),
213 m_pMetaFieldManager(new ::sw::MetaFieldManager()),
214 m_pContentControlManager(new ::SwContentControlManager()),
215 m_pDocumentDrawModelManager( new ::sw::DocumentDrawModelManager( *this ) ),
216 m_pDocumentRedlineManager( new ::sw::DocumentRedlineManager( *this ) ),
217 m_pDocumentStateManager( new ::sw::DocumentStateManager( *this ) ),
218 m_pUndoManager(new ::sw::UndoManager(
219 std::shared_ptr
<SwNodes
>(new SwNodes(*this)), *m_pDocumentDrawModelManager
, *m_pDocumentRedlineManager
, *m_pDocumentStateManager
)),
220 m_pDocumentSettingManager(new ::sw::DocumentSettingManager(*this)),
221 m_pDocumentChartDataProviderManager( new sw::DocumentChartDataProviderManager( *this ) ),
222 m_pDeviceAccess( new ::sw::DocumentDeviceManager( *this ) ),
223 m_pDocumentTimerManager( new ::sw::DocumentTimerManager( *this ) ),
224 m_pDocumentLinksAdministrationManager( new ::sw::DocumentLinksAdministrationManager( *this ) ),
225 m_pDocumentListItemsManager( new ::sw::DocumentListItemsManager() ),
226 m_pDocumentListsManager( new ::sw::DocumentListsManager( *this ) ),
227 m_pDocumentOutlineNodesManager( new ::sw::DocumentOutlineNodesManager( *this ) ),
228 m_pDocumentContentOperationsManager( new ::sw::DocumentContentOperationsManager( *this ) ),
229 m_pDocumentFieldsManager( new ::sw::DocumentFieldsManager( *this ) ),
230 m_pDocumentStatisticsManager( new ::sw::DocumentStatisticsManager( *this ) ),
231 m_pDocumentLayoutManager( new ::sw::DocumentLayoutManager( *this ) ),
232 m_pDocumentStylePoolManager( new ::sw::DocumentStylePoolManager( *this ) ),
233 m_pDocumentExternalDataManager( new ::sw::DocumentExternalDataManager
),
234 mpDfltFrameFormat( new SwFrameFormat( GetAttrPool(), u
"Frameformat"_ustr
, nullptr ) ),
235 mpEmptyPageFormat( new SwFrameFormat( GetAttrPool(), u
"Empty Page"_ustr
, mpDfltFrameFormat
.get() ) ),
236 mpColumnContFormat( new SwFrameFormat( GetAttrPool(), u
"Columncontainer"_ustr
, mpDfltFrameFormat
.get() ) ),
237 mpDfltCharFormat( new SwCharFormat( GetAttrPool(), DEFAULT_CHAR_FORMAT_NAME
, nullptr ) ),
238 mpDfltTextFormatColl( new SwTextFormatColl( GetAttrPool(), u
"Paragraph style"_ustr
) ),
239 mpDfltGrfFormatColl( new SwGrfFormatColl( GetAttrPool(), u
"Graphikformatvorlage"_ustr
) ),
240 mpFrameFormatTable( new sw::FrameFormats
<SwFrameFormat
*>() ),
241 mpCharFormatTable( new SwCharFormats
),
242 mpCharFormatDeletionTable( new SwCharFormats
),
243 mpSpzFrameFormatTable( new sw::FrameFormats
<sw::SpzFrameFormat
*>() ),
244 mpSectionFormatTable( new SwSectionFormats
),
245 mpTableFrameFormatTable( new sw::TableFrameFormats() ),
246 mpTextFormatCollTable( new SwTextFormatColls() ),
247 mpGrfFormatCollTable( new SwGrfFormatColls() ),
248 mpTOXTypes( new SwTOXTypes
),
249 mpDefTOXBases( new SwDefTOXBase_Impl() ),
250 mpOutlineRule( nullptr ),
251 mpFootnoteInfo( new SwFootnoteInfo
),
252 mpEndNoteInfo( new SwEndNoteInfo
),
253 mpLineNumberInfo( new SwLineNumberInfo
),
254 mpFootnoteIdxs( new SwFootnoteIdxs
),
255 mpDocShell( nullptr ),
256 mpNumberFormatter( nullptr ),
257 mpNumRuleTable( new SwNumRuleTable
),
258 mpExtInputRing( nullptr ),
259 mpGrammarContact(new sw::GrammarContact
),
260 mpOnlineAccessibilityCheck(new sw::OnlineAccessibilityCheck(*this)),
261 mpCellStyles(new SwCellStyleTable
),
267 mbInMailMerge(false),
268 mbInXMLImport(false),
269 mbInWriterfilterImport(false),
271 mbInLoadAsynchron(false),
272 mbIsAutoFormatRedline(false),
273 mbOLEPrtNotifyPending(false),
274 mbAllOLENotify(false),
275 mbInsOnlyTextGlssry(false),
276 mbContains_MSVBasic(false),
277 mbClipBoard( false ),
278 mbColumnSelection( false ),
279 mbIsPrepareSelAll(false),
280 meDictionaryMissing( MissingDictionary::Undefined
),
281 mbContainsAtPageObjWithContentAnchor(false), //#i119292#, fdo#37024
282 meDocType(DOCTYPE_NATIVE
)
284 // The DrawingLayer ItemPool which is used as 2nd pool for Writer documents' pool
285 // has a default for the XFillStyleItem of XFILL_SOLID and the color for it is the default
286 // fill color (blue7 or similar). This is a problem, in Writer we want the default fill
287 // style to be drawing::FillStyle_NONE. This cannot simply be done by changing it in the 2nd pool at the
288 // pool defaults when the DrawingLayer ItemPool is used for Writer, that would lead to
289 // countless problems like DrawObjects initial fill and others.
290 // It is also hard to find all places where the initial ItemSets for Writer (including
291 // style hierarchies) are created and to always set (but only at the root) the FillStyle
292 // to NONE fixed; that will add that attribute to the file format. It will be hard to reset
293 // attribute sets (which is done at import and using UI). Also not a good solution.
294 // Luckily Writer uses pDfltTextFormatColl as default parent for all paragraphs and similar, thus
295 // it is possible to set this attribute here. It will be not reset when importing.
296 mpDfltTextFormatColl
->SetFormatAttr(XFillStyleItem(drawing::FillStyle_NONE
));
297 mpDfltFrameFormat
->SetFormatAttr(XFillStyleItem(drawing::FillStyle_NONE
));
298 // prevent paragraph default margins being applied to everything
299 mpDfltFrameFormat
->SetFormatAttr(SvxULSpaceItem(RES_UL_SPACE
));
300 mpDfltFrameFormat
->SetFormatAttr(SvxLRSpaceItem(RES_LR_SPACE
));
303 * DefaultFormats and DefaultFormatCollections (FormatColl)
304 * are inserted at position 0 at the respective array.
305 * The formats in the FormatColls are derived from the
306 * DefaultFormats and are also in the list.
309 mpFrameFormatTable
->push_back(mpDfltFrameFormat
.get());
310 mpCharFormatTable
->insert(mpDfltCharFormat
.get());
314 mpTextFormatCollTable
->push_back(mpDfltTextFormatColl
.get());
316 mpGrfFormatCollTable
->push_back(mpDfltGrfFormatColl
.get());
318 // Create PageDesc, EmptyPageFormat and ColumnFormat
319 if (m_PageDescs
.empty())
320 getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD
);
322 // Set to "Empty Page"
323 mpEmptyPageFormat
->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Fixed
) );
324 // Set BodyFormat for columns
325 mpColumnContFormat
->SetFormatAttr( SwFormatFillOrder( ATT_LEFT_TO_RIGHT
) );
327 GetDocumentFieldsManager().InitFieldTypes();
329 // Create a default OutlineNumRule (for Filters)
330 mpOutlineRule
= new SwNumRule( SwNumRule::GetOutlineRuleName(),
332 numfunc::GetDefaultPositionAndSpaceMode(),
334 AddNumRule(mpOutlineRule
);
335 // Counting of phantoms depends on <IsOldNumbering()>
336 mpOutlineRule
->SetCountPhantoms( !GetDocumentSettingManager().get(DocumentSettingId::OLD_NUMBERING
) );
339 GetUndoManager().GetUndoNodes().GetEndOfContent(),
340 mpDfltTextFormatColl
.get() );
341 new SwTextNode( GetNodes().GetEndOfContent(),
342 getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD
));
344 maOLEModifiedIdle
.SetPriority( TaskPriority::LOWEST
);
345 maOLEModifiedIdle
.SetInvokeHandler( LINK( this, SwDoc
, DoUpdateModifiedOLE
));
347 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
349 m_pOwnDBManager
.reset(new SwDBManager(this));
350 m_pDBManager
= m_pOwnDBManager
.get();
352 m_pDBManager
= nullptr;
358 // pass empty item set containing the paragraph's list attributes
359 // as ignorable items to the stype manager.
361 SfxItemSetFixed
<RES_PARATR_LIST_BEGIN
, RES_PARATR_LIST_END
-1> aIgnorableParagraphItems( GetAttrPool() );
362 mpStyleAccess
= createStyleManager( &aIgnorableParagraphItems
);
365 static bool bHack
= (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
373 // Initialize the session id of the current document to a random number
374 // smaller than 2^21.
375 mnRsid
= comphelper::rng::uniform_uint_distribution(1, (1 << 21) - 1);
379 if (!comphelper::IsFuzzing())
381 // Make sure that in case the document language is not set, then we don't return
382 // LANGUAGE_DONTKNOW, but the UI locale.
383 const SvtLinguConfig aLinguConfig
;
384 SvtLinguOptions aOptions
;
385 aLinguConfig
.GetOptions(aOptions
);
386 LanguageType eLang
= MsLangId::resolveSystemLanguageByScriptType(aOptions
.nDefaultLanguage
,
387 i18n::ScriptType::LATIN
);
388 SetLanguage(eLang
, RES_CHRATR_LANGUAGE
);
389 eLang
= MsLangId::resolveSystemLanguageByScriptType(aOptions
.nDefaultLanguage_CJK
,
390 i18n::ScriptType::ASIAN
);
391 SetLanguage(eLang
, RES_CHRATR_CJK_LANGUAGE
);
392 eLang
= MsLangId::resolveSystemLanguageByScriptType(aOptions
.nDefaultLanguage_CTL
,
393 i18n::ScriptType::COMPLEX
);
394 SetLanguage(eLang
, RES_CHRATR_CTL_LANGUAGE
);
397 getIDocumentState().ResetModified();
403 * Speciality: a member of the class SwDoc is located at
404 * position 0 in the array of the Format and GDI objects.
405 * This MUST not be destroyed using 'delete' in any case!
413 // nothing here should create Undo actions!
414 GetIDocumentUndoRedo().DoUndo(false);
418 mpDocShell
->SetUndoManager(nullptr);
421 mpGrammarContact
.reset();
422 mpOnlineAccessibilityCheck
.reset();
424 getIDocumentTimerAccess().StopIdling(); // stop idle timer
426 mpURLStateChgd
.reset();
428 // Deactivate Undo notification from Draw
429 if( GetDocumentDrawModelManager().GetDrawModel() )
431 GetDocumentDrawModelManager().DrawNotifyUndoHdl();
435 m_pPgPViewPrtData
.reset();
439 //Clear the redline table before the nodes array is destroyed
440 getIDocumentRedlineAccess().GetRedlineTable().DeleteAndDestroyAll();
441 getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteAndDestroyAll();
443 const sw::UnoCursorHint aHint
;
444 cleanupUnoCursorTable();
445 for(const auto& pWeakCursor
: mvUnoCursorTable
)
447 auto pCursor(pWeakCursor
.lock());
449 pCursor
->m_aNotifier
.Broadcast(aHint
);
453 // Release the BaseLinks
455 ::sfx2::SvLinkSources
aTemp(getIDocumentLinksAdministration().GetLinkManager().GetServers());
456 for( const auto& rpLinkSrc
: aTemp
)
459 if( !getIDocumentLinksAdministration().GetLinkManager().GetLinks().empty() )
460 getIDocumentLinksAdministration().GetLinkManager().Remove( 0, getIDocumentLinksAdministration().GetLinkManager().GetLinks().size() );
463 // The ChapterNumbers/Numbers need to be deleted before the styles
464 // or we update all the time!
465 m_pNodes
->m_aOutlineNodes
.clear();
466 SwNodes
& rUndoNodes( GetUndoManager().GetUndoNodes() );
467 rUndoNodes
.m_aOutlineNodes
.clear();
469 mpFootnoteIdxs
->clear();
471 // indices could be registered in attributes
472 m_pUndoManager
->DelAllUndoObj();
474 // The BookMarks contain indices to the Content. These must be deleted
475 // before deleting the Nodes.
476 mpMarkManager
->clearAllMarks();
480 SwPaM
* pTmp
= mpExtInputRing
;
481 mpExtInputRing
= nullptr;
482 while( pTmp
->GetNext() != pTmp
)
484 // coverity[deref_arg] - the SwPaM delete moves a new entry into GetNext()
485 delete pTmp
->GetNext();
490 // Any of the FrameFormats can still have indices registered.
491 // These need to be destroyed now at the latest.
492 for( SwFrameFormat
* pFormat
: *mpFrameFormatTable
)
493 lcl_DelFormatIndices( pFormat
);
494 for( SwFrameFormat
* pFormat
: *mpSpzFrameFormatTable
)
495 lcl_DelFormatIndices( pFormat
);
496 for( SwSectionFormat
* pFormat
: *mpSectionFormatTable
)
497 lcl_DelFormatIndices( pFormat
);
499 // The formats/styles that follow depend on the default formats.
500 // Destroy these only after destroying the FormatIndices, because the content
501 // of headers/footers has to be deleted as well. If in the headers/footers
502 // there are still Flys registered at that point, we have a problem.
503 for( SwPageDesc
*pPageDesc
: m_PageDescs
)
507 // Delete content selections.
508 // Don't wait for the SwNodes dtor to destroy them; so that Formats
509 // do not have any dependencies anymore.
510 m_pNodes
->DelNodes( SwNodeIndex(*m_pNodes
), m_pNodes
->Count() );
511 rUndoNodes
.DelNodes( SwNodeIndex( rUndoNodes
), rUndoNodes
.Count() );
512 mpEndNoteInfo
->ResetSwSection();
514 // clear TOX after nodes - TOXMarks are gone now so SwTOXType has no clients
515 for (const auto& pType
: *mpTOXTypes
)
517 pType
->CallSwClientNotify(sw::DocumentDyingHint());
520 mpDefTOXBases
.reset();
522 // Delete Formats, make it permanent some time in the future
524 // Delete for Collections
525 // So that we get rid of the dependencies
526 mpFootnoteInfo
->EndListeningAll();
527 mpEndNoteInfo
->EndListeningAll();
529 assert(mpDfltTextFormatColl
.get() == (*mpTextFormatCollTable
)[0]
530 && "Default-Text-Collection must always be at the start");
532 // Optimization: Based on the fact that Standard is always 2nd in the
533 // array, we should delete it as the last. With this we avoid
534 // reparenting the Formats all the time!
535 if( 2 < mpTextFormatCollTable
->size() )
536 mpTextFormatCollTable
->DeleteAndDestroy(2, mpTextFormatCollTable
->size());
537 mpTextFormatCollTable
->DeleteAndDestroy(1, mpTextFormatCollTable
->size());
538 mpTextFormatCollTable
.reset();
540 assert(mpDfltGrfFormatColl
.get() == (*mpGrfFormatCollTable
)[0]
541 && "DefaultGrfCollection must always be at the start");
543 mpGrfFormatCollTable
->DeleteAndDestroy(1, mpGrfFormatCollTable
->size());
544 mpGrfFormatCollTable
.reset();
546 // Without explicitly freeing the DocumentDeviceManager
547 // and relying on the implicit freeing there would be a crash
548 // due to it happening after SwAttrPool is freed.
549 m_pDeviceAccess
.reset();
552 * DefaultFormats and DefaultFormatCollections (FormatColl)
553 * are at position 0 of their respective arrays.
554 * In order to not be deleted by the array's dtor, we remove them
557 mpFrameFormatTable
->erase( mpFrameFormatTable
->begin() );
559 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
560 // On load, SwDBManager::setEmbeddedName() may register a data source.
561 // If we have an embedded one, then sDataSource points to the registered name, so revoke it here.
562 if (!m_pOwnDBManager
->getEmbeddedName().isEmpty() && !maDBData
.sDataSource
.isEmpty())
564 // Remove the revoke listener here first, so that we don't remove the data source from the document.
565 m_pOwnDBManager
->releaseRevokeListener();
566 SwDBManager::RevokeDataSource(maDBData
.sDataSource
);
567 SwDBManager::RevokeDataSource(m_pOwnDBManager
->getEmbeddedName());
569 else if (!m_pOwnDBManager
->getEmbeddedName().isEmpty())
571 // Remove the revoke listener here first, so that we don't remove the data source from the document.
572 m_pOwnDBManager
->releaseRevokeListener();
573 // Remove connections which was committed but not used.
574 m_pOwnDBManager
->RevokeNotUsedConnections();
577 m_pOwnDBManager
.reset();
580 // All Flys need to be destroyed before the Drawing Model,
581 // because Flys can still contain DrawContacts, when no
582 // Layout could be constructed due to a read error.
583 mpSpzFrameFormatTable
->DeleteAndDestroyAll();
585 // Only now destroy the Model, the drawing objects - which are also
586 // contained in the Undo - need to remove their attributes from the
587 // Model. Also, DrawContacts could exist before this.
588 GetDocumentDrawModelManager().ReleaseDrawModel();
589 // Destroy DrawModel before the LinkManager, because it's always set
591 //The LinkManager gets destroyed automatically with m_pLinksAdministrationManager
593 // Clear the Tables before deleting the defaults, or we crash due to
594 // dependencies on defaults.
595 mpFrameFormatTable
.reset();
596 mpSpzFrameFormatTable
.reset();
598 mpStyleAccess
.reset();
600 mpCharFormatTable
.reset();
601 // tdf#140061 keep SwCharFormat instances alive while SwDoc is alive
602 if (mpCharFormatDeletionTable
)
603 mpCharFormatDeletionTable
->DeleteAndDestroyAll(/*keepDefault*/false);
604 mpCharFormatDeletionTable
.reset();
605 mpSectionFormatTable
.reset();
606 mpTableFrameFormatTable
.reset();
607 mpDfltTextFormatColl
.reset();
608 mpDfltGrfFormatColl
.reset();
609 mpNumRuleTable
.reset();
611 disposeXForms(); // #i113606#, dispose the XForms objects
614 std::scoped_lock
lock(mNumberFormatterMutex
);
615 delete mpNumberFormatter
; mpNumberFormatter
= nullptr;
617 mpFootnoteInfo
.reset();
618 mpEndNoteInfo
.reset();
619 mpLineNumberInfo
.reset();
620 mpFootnoteIdxs
.reset();
622 mpEmptyPageFormat
.reset();
623 mpColumnContFormat
.reset();
624 mpDfltCharFormat
.reset();
625 mpDfltFrameFormat
.reset();
626 mpLayoutCache
.reset();
630 void SwDoc::SetDocShell( SwDocShell
* pDSh
)
632 if( mpDocShell
== pDSh
)
637 mpDocShell
->SetUndoManager(nullptr);
642 mpDocShell
->SetUndoManager(& GetUndoManager());
643 GetUndoManager().SetDocShell(mpDocShell
);
646 getIDocumentLinksAdministration().GetLinkManager().SetPersist( mpDocShell
);
648 // set DocShell pointer also on DrawModel
649 InitDrawModelAndDocShell(mpDocShell
, GetDocumentDrawModelManager().GetDrawModel());
650 assert(!GetDocumentDrawModelManager().GetDrawModel() ||
651 GetDocumentDrawModelManager().GetDrawModel()->GetPersist() == GetPersist());
654 // Convenience method; to avoid excessive includes from docsh.hxx
655 uno::Reference
< embed::XStorage
> SwDoc::GetDocStorage()
658 return mpDocShell
->GetStorage();
659 if( getIDocumentLinksAdministration().GetLinkManager().GetPersist() )
660 return getIDocumentLinksAdministration().GetLinkManager().GetPersist()->GetStorage();
664 SfxObjectShell
* SwDoc::GetPersist() const
666 return mpDocShell
? mpDocShell
: getIDocumentLinksAdministration().GetLinkManager().GetPersist();
669 void SwDoc::ClearDoc()
671 GetIDocumentUndoRedo().DelAllUndoObj();
672 ::sw::UndoGuard
const undoGuard(GetIDocumentUndoRedo());
674 // Deactivate Undo notification from Draw
675 if( GetDocumentDrawModelManager().GetDrawModel() )
677 GetDocumentDrawModelManager().DrawNotifyUndoHdl();
681 // if there are still FlyFrames dangling around, delete them too
682 while ( !mpSpzFrameFormatTable
->empty() )
683 getIDocumentLayoutAccess().DelLayoutFormat((*mpSpzFrameFormatTable
)[mpSpzFrameFormatTable
->size()-1]);
684 assert(!GetDocumentDrawModelManager().GetDrawModel()
685 || !GetDocumentDrawModelManager().GetDrawModel()->GetPage(0)->GetObjCount());
687 getIDocumentRedlineAccess().GetRedlineTable().DeleteAndDestroyAll();
688 getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteAndDestroyAll();
692 // The BookMarks contain indices to the Content. These must be deleted
693 // before deleting the Nodes.
694 mpMarkManager
->clearAllMarks();
697 // create a dummy pagedesc for the layout
698 SwPageDesc
* pDummyPgDsc
= MakePageDesc(u
"?DUMMY?"_ustr
);
700 SwNodeIndex
aSttIdx( *GetNodes().GetEndOfContent().StartOfSectionNode(), 1 );
701 // create the first one over and over again (without attributes/style etc.
702 SwTextNode
* pFirstNd
= GetNodes().MakeTextNode( aSttIdx
.GetNode(), mpDfltTextFormatColl
.get() );
704 if( getIDocumentLayoutAccess().GetCurrentViewShell() )
706 // set the layout to the dummy pagedesc
707 pFirstNd
->SetAttr( SwFormatPageDesc( pDummyPgDsc
));
709 SwPosition
aPos( *pFirstNd
);
710 SwPaM
const tmpPaM(aSttIdx
.GetNode(), GetNodes().GetEndOfContent());
711 ::PaMCorrAbs(tmpPaM
, aPos
);
714 GetNodes().Delete( aSttIdx
,
715 GetNodes().GetEndOfContent().GetIndex() - aSttIdx
.GetIndex() );
718 // destruction of numbering rules and creation of new outline rule
719 // *after* the document nodes are deleted.
720 mpOutlineRule
= nullptr;
721 for( SwNumRule
* pNumRule
: *mpNumRuleTable
)
723 getIDocumentListsAccess().deleteListForListStyle(pNumRule
->GetName());
726 mpNumRuleTable
->clear();
727 maNumRuleMap
.clear();
729 // creation of new outline numbering rule
730 mpOutlineRule
= new SwNumRule( SwNumRule::GetOutlineRuleName(),
732 numfunc::GetDefaultPositionAndSpaceMode(),
734 AddNumRule(mpOutlineRule
);
735 // Counting of phantoms depends on <IsOldNumbering()>
736 mpOutlineRule
->SetCountPhantoms( !GetDocumentSettingManager().get(DocumentSettingId::OLD_NUMBERING
) );
738 // remove the dummy pagedesc from the array and delete all the old ones
739 size_t nDummyPgDsc
= 0;
740 if (FindPageDesc(pDummyPgDsc
->GetName(), &nDummyPgDsc
))
741 m_PageDescs
.erase( nDummyPgDsc
);
742 for( SwPageDesc
*pPageDesc
: m_PageDescs
)
746 // Delete for Collections
747 // So that we get rid of the dependencies
748 mpFootnoteInfo
->EndListeningAll();
749 mpEndNoteInfo
->EndListeningAll();
751 // Optimization: Based on the fact that Standard is always 2nd in the
752 // array, we should delete it as the last. With this we avoid
753 // reparenting the Formats all the time!
754 if( 2 < mpTextFormatCollTable
->size() )
755 mpTextFormatCollTable
->DeleteAndDestroy(2, mpTextFormatCollTable
->size());
756 mpTextFormatCollTable
->DeleteAndDestroy(1, mpTextFormatCollTable
->size());
757 mpGrfFormatCollTable
->DeleteAndDestroy(1, mpGrfFormatCollTable
->size());
758 mpCharFormatTable
->DeleteAndDestroyAll(/*keepDefault*/true);
759 mpCharFormatDeletionTable
->DeleteAndDestroyAll(/*keepDefault*/false);
761 if( getIDocumentLayoutAccess().GetCurrentViewShell() )
763 // search the FrameFormat of the root frm. This is not allowed to delete
764 mpFrameFormatTable
->erase( getIDocumentLayoutAccess().GetCurrentViewShell()->GetLayout()->GetFormat() );
765 mpFrameFormatTable
->DeleteAndDestroyAll( true );
766 mpFrameFormatTable
->push_back( getIDocumentLayoutAccess().GetCurrentViewShell()->GetLayout()->GetFormat() );
769 mpFrameFormatTable
->DeleteAndDestroyAll( true );
771 GetDocumentFieldsManager().ClearFieldTypes();
774 std::scoped_lock
lock(mNumberFormatterMutex
);
775 delete mpNumberFormatter
; mpNumberFormatter
= nullptr;
778 getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD
);
779 pFirstNd
->ChgFormatColl( getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD
));
780 nDummyPgDsc
= m_PageDescs
.size();
781 m_PageDescs
.push_back( pDummyPgDsc
);
782 // set the layout back to the new standard pagedesc
783 pFirstNd
->ResetAllAttr();
784 // delete now the dummy pagedesc
785 DelPageDesc( nDummyPgDsc
);
788 void SwDoc::SetPreviewPrtData( const SwPagePreviewPrtData
* pNew
)
792 if (m_pPgPViewPrtData
)
794 *m_pPgPViewPrtData
= *pNew
;
798 m_pPgPViewPrtData
.reset(new SwPagePreviewPrtData(*pNew
));
801 else if (m_pPgPViewPrtData
)
803 m_pPgPViewPrtData
.reset();
805 getIDocumentState().SetModified();
808 void SwDoc::SetOLEObjModified()
810 if( getIDocumentLayoutAccess().GetCurrentViewShell() ) maOLEModifiedIdle
.Start();
813 /** SwDoc: Reading and writing of the layout cache. */
814 void SwDoc::ReadLayoutCache( SvStream
& rStream
)
817 mpLayoutCache
.reset( new SwLayoutCache() );
818 if( !mpLayoutCache
->IsLocked() )
820 mpLayoutCache
->GetLockCount() |= 0x8000;
821 mpLayoutCache
->Read( rStream
);
822 mpLayoutCache
->GetLockCount() &= 0x7fff;
826 void SwDoc::WriteLayoutCache( SvStream
& rStream
)
828 SwLayoutCache::Write( rStream
, *this );
831 ::sfx2::IXmlIdRegistry
&
832 SwDoc::GetXmlIdRegistry()
834 // UGLY: this relies on SetClipBoard being called before GetXmlIdRegistry!
835 if (!m_pXmlIdRegistry
)
837 m_pXmlIdRegistry
.reset( ::sfx2::createXmlIdRegistry( IsClipBoard() ) );
839 return *m_pXmlIdRegistry
;
842 void SwDoc::InitTOXTypes()
844 ShellResource
* pShellRes
= SwViewShell::GetShellRes();
845 SwTOXType
* pNew
= new SwTOXType(*this, TOX_CONTENT
, pShellRes
->aTOXContentName
);
846 mpTOXTypes
->emplace_back( pNew
);
847 pNew
= new SwTOXType(*this, TOX_INDEX
, pShellRes
->aTOXIndexName
);
848 mpTOXTypes
->emplace_back( pNew
);
849 pNew
= new SwTOXType(*this, TOX_USER
, pShellRes
->aTOXUserName
);
850 mpTOXTypes
->emplace_back( pNew
);
851 pNew
= new SwTOXType(*this, TOX_ILLUSTRATIONS
, pShellRes
->aTOXIllustrationsName
);
852 mpTOXTypes
->emplace_back( pNew
);
853 pNew
= new SwTOXType(*this, TOX_OBJECTS
, pShellRes
->aTOXObjectsName
);
854 mpTOXTypes
->emplace_back( pNew
);
855 pNew
= new SwTOXType(*this, TOX_TABLES
, pShellRes
->aTOXTablesName
);
856 mpTOXTypes
->emplace_back( pNew
);
857 pNew
= new SwTOXType(*this, TOX_AUTHORITIES
, pShellRes
->aTOXAuthoritiesName
);
858 mpTOXTypes
->emplace_back( pNew
);
859 pNew
= new SwTOXType(*this, TOX_CITATION
, pShellRes
->aTOXCitationName
);
860 mpTOXTypes
->emplace_back( pNew
);
863 void SwDoc::ReplaceDefaults(const SwDoc
& rSource
)
865 // copy property defaults
866 static const WhichRangesContainer
aRangeOfDefaults(svl::Items
<
867 RES_CHRATR_BEGIN
, RES_CHRATR_END
-1,
868 RES_PARATR_BEGIN
, RES_PARATR_END
-1,
869 RES_PARATR_LIST_BEGIN
, RES_PARATR_LIST_END
-1,
870 RES_FRMATR_BEGIN
, RES_FRMATR_END
-1,
871 RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
-1,
872 XATTR_START
, XATTR_END
-1
875 SfxItemSet
aNewDefaults(GetAttrPool(), aRangeOfDefaults
);
877 for (const WhichPair
& rPair
: aRangeOfDefaults
)
879 for (sal_uInt16 nWhich
= rPair
.first
;
880 nWhich
<= rPair
.second
; ++nWhich
)
882 const SfxPoolItem
& rSourceAttr(rSource
.mpAttrPool
->GetUserOrPoolDefaultItem(nWhich
));
883 const SfxPoolItem
& rDestAttr(mpAttrPool
->GetUserOrPoolDefaultItem(nWhich
));
884 bool bEqual(SfxPoolItem::areSame(rSourceAttr
, rDestAttr
));
886 if (!bEqual
&& rSourceAttr
.isSetItem() && rDestAttr
.isSetItem())
888 // the normal SfxSetItem::operator== returns false when pools are different,
889 // which will always be the case here. Use the compare without pool
890 // comparison - the chances that the defaults in pools of the same type are
891 // equal are high, and cloning them is expensive
892 bEqual
= static_cast<const SfxSetItem
&>(rSourceAttr
).GetItemSet().Equals(
893 static_cast<const SfxSetItem
&>(rDestAttr
).GetItemSet(), false);
897 aNewDefaults
.Put(rSourceAttr
);
901 if (aNewDefaults
.Count())
902 SetDefault(aNewDefaults
);
905 void SwDoc::ReplaceCompatibilityOptions(const SwDoc
& rSource
)
907 m_pDocumentSettingManager
->ReplaceCompatibilityOptions(rSource
.GetDocumentSettingManager());
911 #define CNTNT_DOC( doc ) \
912 ((doc)->GetNodes().GetEndOfContent().GetIndex() - (doc)->GetNodes().GetEndOfExtras().GetIndex() - SwNodeOffset(2))
913 #define CNTNT_IDX( idx ) \
914 ((idx).GetNode().GetIndex() - GetNodes().GetEndOfExtras().GetIndex() - 1)
917 rtl::Reference
<SfxObjectShell
> SwDoc::CreateCopy(bool bCallInitNew
, bool bEmpty
) const
919 SAL_INFO( "sw.pageframe", "(SwDoc::CreateCopy in" );
920 rtl::Reference
<SwDoc
> xRet( new SwDoc
);
922 // we have to use pointer here, since the callee has to decide whether
923 // SfxObjectShellLock or SfxObjectShellRef should be used sometimes the
924 // object will be returned with refcount set to 0 ( if no DoInitNew is done )
925 rtl::Reference
<SfxObjectShell
> pRetShell
= new SwDocShell(*xRet
, SfxObjectCreateMode::STANDARD
);
928 // it could happen that DoInitNew creates model,
929 // that increases the refcount of the object
930 pRetShell
->DoInitNew();
933 xRet
->ReplaceDefaults(*this);
935 xRet
->ReplaceCompatibilityOptions(*this);
937 xRet
->ReplaceStyles(*this);
939 rtl::Reference
<SwXTextDocument
> const xThisSet(GetDocShell()->GetBaseModel());
940 uno::Reference
<beans::XPropertySet
> const xRetSet(
941 pRetShell
->GetBaseModel(), uno::UNO_QUERY_THROW
);
942 uno::Sequence
<beans::PropertyValue
> aInteropGrabBag
;
943 xThisSet
->getPropertyValue(u
"InteropGrabBag"_ustr
) >>= aInteropGrabBag
;
944 xRetSet
->setPropertyValue(u
"InteropGrabBag"_ustr
, uno::Any(aInteropGrabBag
));
949 SAL_INFO( "sw.createcopy", "CC-Nd-Src: " << CNTNT_DOC( this ) );
950 SAL_INFO( "sw.createcopy", "CC-Nd: " << CNTNT_DOC( xRet
) );
952 xRet
->AppendDoc(*this, 0, bCallInitNew
, 0, 0);
954 SAL_INFO( "sw.createcopy", "CC-Nd: " << CNTNT_DOC( xRet
) );
958 // remove the temporary shell if it is there as it was done before
959 xRet
->SetTmpDocShell( nullptr );
961 SAL_INFO( "sw.pageframe", "SwDoc::CreateCopy out)" );
965 // save bulk letters as single documents
966 static OUString
lcl_FindUniqueName(SwWrtShell
* pTargetShell
, std::u16string_view rStartingPageDesc
, sal_uLong nDocNo
)
970 OUString sTest
= rStartingPageDesc
+ OUString::number( nDocNo
);
971 if( !pTargetShell
->FindPageDescByName( sTest
) )
978 /** Returns whether the passed SwPageDesc& or any of its (transitive) follows
979 contains a header or footer. */
980 static bool lcl_PageDescOrFollowContainsHeaderFooter(const SwPageDesc
& rPageDesc
)
982 // remember already checked page descs to avoid cycle
983 o3tl::sorted_vector
<const SwPageDesc
*> aCheckedPageDescs
;
984 const SwPageDesc
* pCurPageDesc
= &rPageDesc
;
985 while (aCheckedPageDescs
.count(pCurPageDesc
) == 0)
987 const SwFrameFormat
& rMaster
= pCurPageDesc
->GetMaster();
988 if (rMaster
.GetHeader().IsActive() || rMaster
.GetFooter().IsActive())
991 aCheckedPageDescs
.insert(pCurPageDesc
);
992 pCurPageDesc
= pCurPageDesc
->GetFollow();
997 static void lcl_CopyFollowPageDesc(
998 SwWrtShell
& rTargetShell
,
999 const SwPageDesc
& rSourcePageDesc
,
1000 const SwPageDesc
& rTargetPageDesc
,
1001 const sal_uLong nDocNo
)
1003 //now copy the follow page desc, too
1004 // note: these may at any point form a cycle, so a loop is needed and it
1005 // must be detected that the last iteration closes the cycle and doesn't
1006 // copy the first page desc of the cycle again.
1007 std::map
<OUString
, OUString
> followMap
{ { rSourcePageDesc
.GetName(), rTargetPageDesc
.GetName() } };
1008 SwPageDesc
const* pCurSourcePageDesc(&rSourcePageDesc
);
1009 SwPageDesc
const* pCurTargetPageDesc(&rTargetPageDesc
);
1012 const SwPageDesc
* pFollowPageDesc
= pCurSourcePageDesc
->GetFollow();
1013 OUString sFollowPageDesc
= pFollowPageDesc
->GetName();
1014 if (sFollowPageDesc
== pCurSourcePageDesc
->GetName())
1018 SwDoc
* pTargetDoc
= rTargetShell
.GetDoc();
1019 SwPageDesc
* pTargetFollowPageDesc(nullptr);
1020 auto const itMapped(followMap
.find(sFollowPageDesc
));
1021 if (itMapped
== followMap
.end())
1023 OUString sNewFollowPageDesc
= lcl_FindUniqueName(&rTargetShell
, sFollowPageDesc
, nDocNo
);
1024 pTargetFollowPageDesc
= pTargetDoc
->MakePageDesc(sNewFollowPageDesc
);
1025 pTargetDoc
->CopyPageDesc(*pFollowPageDesc
, *pTargetFollowPageDesc
, false);
1029 pTargetFollowPageDesc
= pTargetDoc
->FindPageDesc(itMapped
->second
);
1031 SwPageDesc
aDesc(*pCurTargetPageDesc
);
1032 aDesc
.SetFollow(pTargetFollowPageDesc
);
1033 pTargetDoc
->ChgPageDesc(pCurTargetPageDesc
->GetName(), aDesc
);
1034 if (itMapped
!= followMap
.end())
1036 break; // was already copied
1038 pCurSourcePageDesc
= pCurSourcePageDesc
->GetFollow();
1039 pCurTargetPageDesc
= pTargetFollowPageDesc
;
1040 followMap
[pCurSourcePageDesc
->GetName()] = pCurTargetPageDesc
->GetName();
1045 // appends all pages of source SwDoc - based on SwFEShell::Paste( SwDoc* )
1046 SwNodeIndex
SwDoc::AppendDoc(const SwDoc
& rSource
, sal_uInt16
const nStartPageNumber
,
1047 bool const bDeletePrevious
, int pageOffset
, const sal_uLong nDocNo
)
1049 SAL_INFO( "sw.pageframe", "(SwDoc::AppendDoc in " << bDeletePrevious
);
1051 // GetEndOfExtras + 1 = StartOfContent == no content node!
1052 // This ensures it won't be merged in the SwTextNode at the position.
1053 SwNodeIndex
aSourceIdx( rSource
.GetNodes().GetEndOfExtras(), 1 );
1054 // CopyRange works on the range a [mark, point[ and considers an
1055 // index < point outside the selection.
1056 // @see IDocumentContentOperations::CopyRange
1057 SwNodeIndex
aSourceEndIdx( rSource
.GetNodes().GetEndOfContent(), 0 );
1058 SwPaM
aCpyPam( aSourceIdx
, aSourceEndIdx
);
1061 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceIdx
.GetNode().GetNodeType())
1062 << std::dec
<< " " << aSourceIdx
.GetNode().GetIndex() );
1064 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceIdx
.GetNode().GetNodeType())
1065 << std::dec
<< " " << aSourceIdx
.GetNode().GetIndex() );
1066 if ( aSourceIdx
.GetNode().GetNodeType() != SwNodeType::End
) {
1068 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceIdx
.GetNode().GetNodeType()) << std::dec
);
1072 SAL_INFO( "sw.docappend", ".." );
1073 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceEndIdx
.GetNode().GetNodeType())
1074 << std::dec
<< " " << aSourceEndIdx
.GetNode().GetIndex() );
1075 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceEndIdx
.GetNode().GetNodeType())
1076 << std::dec
<< " " << aSourceEndIdx
.GetNode().GetIndex() );
1077 SAL_INFO( "sw.docappend", "Src-Nd: " << CNTNT_DOC( &rSource
) );
1078 SAL_INFO( "sw.docappend", "Nd: " << CNTNT_DOC( this ) );
1081 SwWrtShell
* pTargetShell
= GetDocShell()->GetWrtShell();
1082 SwPageDesc
* pTargetPageDesc
= nullptr;
1084 if ( pTargetShell
) {
1086 SAL_INFO( "sw.docappend", "Has target write shell" );
1088 pTargetShell
->StartAllAction();
1092 // #i72517# put the styles to the target document
1093 // if the source uses headers or footers the target document
1094 // needs individual page styles
1095 const SwWrtShell
*pSourceShell
= rSource
.GetDocShell()->GetWrtShell();
1096 const SwPageDesc
& rSourcePageDesc
= pSourceShell
->GetPageDesc(
1097 pSourceShell
->GetCurPageDesc());
1098 const OUString sStartingPageDesc
= rSourcePageDesc
.GetName();
1099 const bool bPageStylesWithHeaderFooter
= lcl_PageDescOrFollowContainsHeaderFooter(rSourcePageDesc
);
1100 if( bPageStylesWithHeaderFooter
)
1102 // create a new pagestyle
1103 // copy the pagedesc from the current document to the new
1104 // document and change the name of the to-be-applied style
1105 OUString sNewPageDescName
= lcl_FindUniqueName(pTargetShell
, sStartingPageDesc
, nDocNo
);
1106 pTargetPageDesc
= MakePageDesc( sNewPageDescName
);
1107 if( pTargetPageDesc
)
1109 CopyPageDesc( rSourcePageDesc
, *pTargetPageDesc
, false );
1110 lcl_CopyFollowPageDesc( *pTargetShell
, rSourcePageDesc
, *pTargetPageDesc
, nDocNo
);
1114 pTargetPageDesc
= pTargetShell
->FindPageDescByName( sStartingPageDesc
);
1117 // Otherwise we have to handle SwPlaceholderNodes as first node
1118 if ( pTargetPageDesc
)
1120 SwNodeIndex
aBreakIdx( GetNodes().GetEndOfContent(), -1 );
1121 SwPosition
aBreakPos( aBreakIdx
);
1122 // insert new node - will be removed at the end...
1123 // (don't SplitNode() as it may move flys to the wrong node)
1124 getIDocumentContentOperations().AppendTextNode(aBreakPos
);
1125 SwFormatPageDesc
pageDesc(pTargetPageDesc
);
1126 pageDesc
.SetNumOffset(nStartPageNumber
);
1127 // set break on the last paragraph
1128 getIDocumentContentOperations().InsertPoolItem(SwPaM(aBreakPos
),
1129 pageDesc
, SetAttrMode::DEFAULT
, pTargetShell
->GetLayout());
1130 // tdf#148309 move to the last node - so that the "flush page break"
1131 // code below will format the frame of the node with the page break,
1132 // which is required for new page frames to be created! Else layout
1133 // performance will be terrible.
1134 pTargetShell
->SttEndDoc(false);
1136 // There is now a new empty text node on the new page. If it has
1137 // any marks, those are from the previous page: move them back
1138 // there, otherwise later we can't delete that empty text node.
1139 SwNodeIndex
aNodeIndex(GetNodes().GetEndOfContent(), -1);
1140 if (SwTextNode
* pTextNode
= aNodeIndex
.GetNode().GetTextNode())
1142 // Position of the last paragraph on the previous page.
1144 SwPaM
aPaM(aNodeIndex
);
1145 // Collect the marks starting or ending at this text node.
1146 o3tl::sorted_vector
<sw::mark::MarkBase
*> aSeenMarks
;
1147 IDocumentMarkAccess
* pMarkAccess
= getIDocumentMarkAccess();
1148 for (const SwContentIndex
* pIndex
= pTextNode
->GetFirstIndex(); pIndex
; pIndex
= pIndex
->GetNext())
1150 if (!pIndex
->GetOwner() || pIndex
->GetOwner()->GetOwnerType() != SwContentIndexOwnerType::Mark
)
1152 sw::mark::MarkBase
* pMark
= static_cast<sw::mark::MarkBase
*>(pIndex
->GetOwner());
1153 if (!aSeenMarks
.insert(pMark
).second
)
1156 // And move them back.
1157 for (sw::mark::MarkBase
* pMark
: aSeenMarks
)
1158 pMarkAccess
->repositionMark(pMark
, aPaM
);
1161 // Flush the page break, if we want to keep it
1162 if ( !bDeletePrevious
)
1164 SAL_INFO( "sw.pageframe", "(Flush pagebreak AKA EndAllAction" );
1165 assert(pTargetShell
->GetCursor()->GetPoint()->GetNode().GetTextNode()->GetSwAttrSet().HasItem(RES_PAGEDESC
));
1166 pTargetShell
->EndAllAction();
1167 SAL_INFO( "sw.pageframe", "Flush changes AKA EndAllAction)" );
1168 pTargetShell
->StartAllAction();
1173 SAL_INFO( "sw.docappend", "Nd: " << CNTNT_DOC( this ) );
1176 // -1, otherwise aFixupIdx would move to new EOC
1177 SwNodeIndex
aFixupIdx( GetNodes().GetEndOfContent(), -1 );
1179 // append at the end of document / content
1180 SwPaM
aInsertPam( GetNodes().GetEndOfContent() );
1183 SAL_INFO( "sw.docappend", "Pam-Nd: " << aCpyPam
.GetPointNode().GetIndex() - aCpyPam
.GetMarkNode().GetIndex() + 1
1184 << " (0x" << std::hex
<< static_cast<int>(aCpyPam
.GetMarkNode().GetNodeType()) << std::dec
1185 << " " << aCpyPam
.GetMarkNode().GetIndex()
1186 << " - 0x" << std::hex
<< static_cast<int>(aCpyPam
.GetPointNode().GetNodeType()) << std::dec
1187 << " " << aCpyPam
.GetPointNode().GetIndex() << ")" );
1190 GetIDocumentUndoRedo().StartUndo( SwUndoId::INSGLOSSARY
, nullptr );
1191 getIDocumentFieldsAccess().LockExpFields();
1193 // Position where the appended doc starts. Will be filled in later.
1194 // Initially uses GetEndOfContent() because SwNodeIndex has no default ctor.
1195 SwNodeIndex
aStartAppendIndex( GetNodes().GetEndOfContent() );
1199 // ** refer to SwFEShell::Paste, if you change the following code **
1202 SwPosition
& rInsPos
= *aInsertPam
.GetPoint();
1205 SwNodeIndex
aIndexBefore(rInsPos
.GetNode());
1209 SAL_INFO( "sw.docappend", "CopyRange In: " << CNTNT_DOC( this ) );
1211 rSource
.getIDocumentContentOperations().CopyRange(aCpyPam
, rInsPos
, SwCopyFlags::CopyAll
|SwCopyFlags::CheckPosInFly
);
1212 // Note: aCpyPam is invalid now
1214 SAL_INFO( "sw.docappend", "CopyRange Out: " << CNTNT_DOC( this ) );
1218 SwPaM
aPaM(aIndexBefore
.GetNode(), rInsPos
.GetNode());
1220 aPaM
.GetDoc().MakeUniqueNumRules(aPaM
);
1222 // Update the rsid of each pasted text node
1223 SwNodes
&rDestNodes
= GetNodes();
1224 SwNodeOffset
const nEndIdx
= aPaM
.End()->GetNodeIndex();
1226 for (SwNodeOffset nIdx
= aPaM
.Start()->GetNodeIndex();
1227 nIdx
<= nEndIdx
; ++nIdx
)
1229 SwTextNode
*const pTextNode
= rDestNodes
[nIdx
]->GetTextNode();
1231 UpdateParRsid( pTextNode
);
1236 SwNodeOffset
iDelNodes(0);
1237 SwNodeIndex
aDelIdx( aFixupIdx
);
1239 // we just need to set the new page description and reset numbering
1240 // this keeps all other settings as in the pasted document
1241 if ( nStartPageNumber
|| pTargetPageDesc
) {
1242 std::unique_ptr
<SfxPoolItem
> pNewItem
;
1243 SwTextNode
*aTextNd
= nullptr;
1244 SwFormat
*pFormat
= nullptr;
1246 // find the first node allowed to contain a RES_PAGEDESC
1250 SwNode
&node
= aFixupIdx
.GetNode();
1251 if ( node
.IsTextNode() ) {
1252 // every document contains at least one text node!
1253 aTextNd
= node
.GetTextNode();
1254 pNewItem
.reset(aTextNd
->GetAttr( RES_PAGEDESC
).Clone());
1257 else if ( node
.IsTableNode() ) {
1258 pFormat
= node
.GetTableNode()->GetTable().GetFrameFormat();
1259 pNewItem
.reset(pFormat
->GetFormatAttr( RES_PAGEDESC
).Clone());
1265 SAL_INFO( "sw.docappend", "Idx Del " << CNTNT_IDX( aDelIdx
) );
1266 SAL_INFO( "sw.docappend", "Idx Fix " << CNTNT_IDX( aFixupIdx
) );
1268 // just update the original instead of overwriting
1269 SwFormatPageDesc
*aDesc
= static_cast< SwFormatPageDesc
* >( pNewItem
.get() );
1271 if ( aDesc
->GetPageDesc() )
1272 SAL_INFO( "sw.docappend", "PD Update " << aDesc
->GetPageDesc()->GetName() );
1274 SAL_INFO( "sw.docappend", "PD New" );
1276 if ( nStartPageNumber
)
1277 aDesc
->SetNumOffset( nStartPageNumber
);
1278 if ( pTargetPageDesc
)
1279 aDesc
->RegisterToPageDesc( *pTargetPageDesc
);
1281 aTextNd
->SetAttr( *aDesc
);
1283 pFormat
->SetFormatAttr( *aDesc
);
1286 SAL_INFO( "sw.docappend", "Idx " << CNTNT_IDX( aDelIdx
) );
1291 if ( bDeletePrevious
)
1295 // delete leading empty page(s), e.g. from InsertPageBreak or
1296 // new SwDoc. this has to be done before copying the page bound
1297 // frames, otherwise the drawing layer gets confused.
1299 pTargetShell
->SttEndDoc( false );
1300 aDelIdx
-= iDelNodes
- 1;
1302 SAL_INFO( "sw.docappend", "iDelNodes: " << iDelNodes
1303 << " Idx: " << aDelIdx
.GetNode().GetIndex()
1304 << " EOE: " << GetNodes().GetEndOfExtras().GetIndex() );
1306 GetNodes().Delete( aDelIdx
, iDelNodes
);
1307 aStartAppendIndex
= aFixupIdx
;
1311 aStartAppendIndex
= aFixupIdx
;
1312 ++aStartAppendIndex
;
1316 // finally copy page bound frames
1317 for(sw::SpzFrameFormat
* pCpyFormat
: *rSource
.GetSpzFrameFormats())
1319 const SwFrameFormat
& rCpyFormat
= *pCpyFormat
;
1320 SwFormatAnchor
aAnchor( rCpyFormat
.GetAnchor() );
1321 if (RndStdIds::FLY_AT_PAGE
!= aAnchor
.GetAnchorId())
1323 SAL_INFO( "sw.docappend", "PaAn: " << aAnchor
.GetPageNum()
1324 << " => " << aAnchor
.GetPageNum() + pageOffset
);
1325 if ( pageOffset
!= 0 )
1326 aAnchor
.SetPageNum( aAnchor
.GetPageNum() + pageOffset
);
1327 getIDocumentLayoutAccess().CopyLayoutFormat( rCpyFormat
, aAnchor
, true, true );
1331 GetIDocumentUndoRedo().EndUndo( SwUndoId::INSGLOSSARY
, nullptr );
1333 getIDocumentFieldsAccess().UnlockExpFields();
1334 getIDocumentFieldsAccess().UpdateFields(false);
1337 pTargetShell
->EndAllAction();
1339 SAL_INFO( "sw.pageframe", "SwDoc::AppendDoc out)" );
1340 return aStartAppendIndex
;
1343 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */