ITEM: Refactor ItemType
[LibreOffice.git] / sw / source / core / doc / docnew.cxx
blobf3b9e768557abdf1a675d89d01d487f941f0baca
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 .
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>
29 #include <doc.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>
58 #include <ndtxt.hxx>
59 #include <ftninfo.hxx>
60 #include <ftnidx.hxx>
61 #include <charfmt.hxx>
62 #include <frmfmt.hxx>
63 #include <poolfmt.hxx>
64 #include <dbmgr.hxx>
65 #include <docsh.hxx>
66 #include <acorrect.hxx>
67 #include <visiturl.hxx>
68 #include <docary.hxx>
69 #include <lineinfo.hxx>
70 #include <drawdoc.hxx>
71 #include <extinput.hxx>
72 #include <viewsh.hxx>
73 #include <doctxm.hxx>
74 #include <shellres.hxx>
75 #include <laycache.hxx>
76 #include <mvsave.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>
101 #include <wrtsh.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();
150 if (!pDocShell)
151 return bStarted;
152 SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pDocShell, false );
153 while (pFrame && !bVisible)
155 if (pFrame->IsVisible())
156 bVisible = true;
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)
164 if (bVisible)
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()) ) )
175 bStarted = true;
176 if ( !bSkipStart )
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 );
189 return bStarted;
193 * internal functions
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 );
206 * exported methods
208 SwDoc::SwDoc()
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),
262 mReferenceCount(0),
263 mbDtor(false),
264 mbCopyIsMove(false),
265 mbInReading(false),
266 mbInWriting(false),
267 mbInMailMerge(false),
268 mbInXMLImport(false),
269 mbInWriterfilterImport(false),
270 mbUpdateTOX(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.
308 /* Formats */
309 mpFrameFormatTable->push_back(mpDfltFrameFormat.get());
310 mpCharFormatTable->insert(mpDfltCharFormat.get());
312 /* FormatColls */
313 // TXT
314 mpTextFormatCollTable->push_back(mpDfltTextFormatColl.get());
315 // GRF
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(),
331 // #i89178#
332 numfunc::GetDefaultPositionAndSpaceMode(),
333 OUTLINE_RULE );
334 AddNumRule(mpOutlineRule);
335 // Counting of phantoms depends on <IsOldNumbering()>
336 mpOutlineRule->SetCountPhantoms( !GetDocumentSettingManager().get(DocumentSettingId::OLD_NUMBERING) );
338 new SwTextNode(
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
348 // Create DBManager
349 m_pOwnDBManager.reset(new SwDBManager(this));
350 m_pDBManager = m_pOwnDBManager.get();
351 #else
352 m_pDBManager = nullptr;
353 #endif
355 // create TOXTypes
356 InitTOXTypes();
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);
367 if (bHack)
369 mnRsid = 0;
371 else
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);
377 mnRsidRoot = mnRsid;
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();
399 s_pLast = this;
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!
407 SwDoc::~SwDoc()
409 s_pLast = nullptr;
411 mxVbaFind.clear();
413 // nothing here should create Undo actions!
414 GetIDocumentUndoRedo().DoUndo(false);
416 if (mpDocShell)
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();
432 ClrContourCache();
435 m_pPgPViewPrtData.reset();
437 mbDtor = true;
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());
448 if(pCursor)
449 pCursor->m_aNotifier.Broadcast(aHint);
451 mpACEWord.reset();
453 // Release the BaseLinks
455 ::sfx2::SvLinkSources aTemp(getIDocumentLinksAdministration().GetLinkManager().GetServers());
456 for( const auto& rpLinkSrc : aTemp )
457 rpLinkSrc->Closed();
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();
478 if( mpExtInputRing )
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();
487 delete pTmp;
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 )
504 delete pPageDesc;
505 m_PageDescs.clear();
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());
519 mpTOXTypes->clear();
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
555 * now.
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();
578 #endif
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
590 // in the DrawModel.
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();
621 mpTOXTypes.reset();
622 mpEmptyPageFormat.reset();
623 mpColumnContFormat.reset();
624 mpDfltCharFormat.reset();
625 mpDfltFrameFormat.reset();
626 mpLayoutCache.reset();
627 mpAttrPool.clear();
630 void SwDoc::SetDocShell( SwDocShell* pDSh )
632 if( mpDocShell == pDSh )
633 return;
635 if (mpDocShell)
637 mpDocShell->SetUndoManager(nullptr);
639 mpDocShell = pDSh;
640 if (mpDocShell)
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()
657 if( mpDocShell )
658 return mpDocShell->GetStorage();
659 if( getIDocumentLinksAdministration().GetLinkManager().GetPersist() )
660 return getIDocumentLinksAdministration().GetLinkManager().GetPersist()->GetStorage();
661 return nullptr;
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();
678 ClrContourCache();
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();
690 mpACEWord.reset();
692 // The BookMarks contain indices to the Content. These must be deleted
693 // before deleting the Nodes.
694 mpMarkManager->clearAllMarks();
695 InitTOXTypes();
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() );
717 // #i62440#
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());
724 delete pNumRule;
726 mpNumRuleTable->clear();
727 maNumRuleMap.clear();
729 // creation of new outline numbering rule
730 mpOutlineRule = new SwNumRule( SwNumRule::GetOutlineRuleName(),
731 // #i89178#
732 numfunc::GetDefaultPositionAndSpaceMode(),
733 OUTLINE_RULE );
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 )
743 delete pPageDesc;
744 m_PageDescs.clear();
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() );
768 else
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 )
790 if( pNew )
792 if (m_pPgPViewPrtData)
794 *m_pPgPViewPrtData = *pNew;
796 else
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 )
816 if( !mpLayoutCache )
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);
896 if (!bEqual)
897 aNewDefaults.Put(rSourceAttr);
901 if (aNewDefaults.Count())
902 SetDefault(aNewDefaults);
905 void SwDoc::ReplaceCompatibilityOptions(const SwDoc& rSource)
907 m_pDocumentSettingManager->ReplaceCompatibilityOptions(rSource.GetDocumentSettingManager());
910 #ifdef DBG_UTIL
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)
915 #endif
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);
926 if( bCallInitNew )
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));
946 if( !bEmpty )
948 #ifdef DBG_UTIL
949 SAL_INFO( "sw.createcopy", "CC-Nd-Src: " << CNTNT_DOC( this ) );
950 SAL_INFO( "sw.createcopy", "CC-Nd: " << CNTNT_DOC( xRet ) );
951 #endif
952 xRet->AppendDoc(*this, 0, bCallInitNew, 0, 0);
953 #ifdef DBG_UTIL
954 SAL_INFO( "sw.createcopy", "CC-Nd: " << CNTNT_DOC( xRet ) );
955 #endif
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)" );
962 return pRetShell;
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 ) )
972 return sTest;
973 ++nDocNo;
975 while( true );
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())
989 return true;
991 aCheckedPageDescs.insert(pCurPageDesc);
992 pCurPageDesc = pCurPageDesc->GetFollow();
994 return false;
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())
1016 break;
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);
1027 else
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();
1042 while (true);
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 );
1060 #ifdef DBG_UTIL
1061 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex << static_cast<int>(aSourceIdx.GetNode().GetNodeType())
1062 << std::dec << " " << aSourceIdx.GetNode().GetIndex() );
1063 ++aSourceIdx;
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 ) {
1067 ++aSourceIdx;
1068 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex << static_cast<int>(aSourceIdx.GetNode().GetNodeType()) << std::dec );
1069 --aSourceIdx;
1071 --aSourceIdx;
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 ) );
1079 #endif
1081 SwWrtShell* pTargetShell = GetDocShell()->GetWrtShell();
1082 SwPageDesc* pTargetPageDesc = nullptr;
1084 if ( pTargetShell ) {
1085 #ifdef DBG_UTIL
1086 SAL_INFO( "sw.docappend", "Has target write shell" );
1087 #endif
1088 pTargetShell->StartAllAction();
1090 if( nDocNo > 0 )
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 );
1113 else
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.
1143 --aNodeIndex;
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)
1151 continue;
1152 sw::mark::MarkBase* pMark = static_cast<sw::mark::MarkBase*>(pIndex->GetOwner());
1153 if (!aSeenMarks.insert(pMark).second)
1154 continue;
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();
1172 #ifdef DBG_UTIL
1173 SAL_INFO( "sw.docappend", "Nd: " << CNTNT_DOC( this ) );
1174 #endif
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() );
1182 #ifdef DBG_UTIL
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() << ")" );
1188 #endif
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() );
1198 // **
1199 // ** refer to SwFEShell::Paste, if you change the following code **
1200 // **
1202 SwPosition& rInsPos = *aInsertPam.GetPoint();
1205 SwNodeIndex aIndexBefore(rInsPos.GetNode());
1207 --aIndexBefore;
1208 #ifdef DBG_UTIL
1209 SAL_INFO( "sw.docappend", "CopyRange In: " << CNTNT_DOC( this ) );
1210 #endif
1211 rSource.getIDocumentContentOperations().CopyRange(aCpyPam, rInsPos, SwCopyFlags::CopyAll|SwCopyFlags::CheckPosInFly);
1212 // Note: aCpyPam is invalid now
1213 #ifdef DBG_UTIL
1214 SAL_INFO( "sw.docappend", "CopyRange Out: " << CNTNT_DOC( this ) );
1215 #endif
1217 ++aIndexBefore;
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();
1230 if ( pTextNode )
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
1247 while (true) {
1248 ++aFixupIdx;
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());
1255 break;
1257 else if ( node.IsTableNode() ) {
1258 pFormat = node.GetTableNode()->GetTable().GetFrameFormat();
1259 pNewItem.reset(pFormat->GetFormatAttr( RES_PAGEDESC ).Clone());
1260 break;
1264 #ifdef DBG_UTIL
1265 SAL_INFO( "sw.docappend", "Idx Del " << CNTNT_IDX( aDelIdx ) );
1266 SAL_INFO( "sw.docappend", "Idx Fix " << CNTNT_IDX( aFixupIdx ) );
1267 #endif
1268 // just update the original instead of overwriting
1269 SwFormatPageDesc *aDesc = static_cast< SwFormatPageDesc* >( pNewItem.get() );
1270 #ifdef DBG_UTIL
1271 if ( aDesc->GetPageDesc() )
1272 SAL_INFO( "sw.docappend", "PD Update " << aDesc->GetPageDesc()->GetName() );
1273 else
1274 SAL_INFO( "sw.docappend", "PD New" );
1275 #endif
1276 if ( nStartPageNumber )
1277 aDesc->SetNumOffset( nStartPageNumber );
1278 if ( pTargetPageDesc )
1279 aDesc->RegisterToPageDesc( *pTargetPageDesc );
1280 if ( aTextNd )
1281 aTextNd->SetAttr( *aDesc );
1282 else
1283 pFormat->SetFormatAttr( *aDesc );
1285 #ifdef DBG_UTIL
1286 SAL_INFO( "sw.docappend", "Idx " << CNTNT_IDX( aDelIdx ) );
1287 #endif
1288 iDelNodes++;
1291 if ( bDeletePrevious )
1292 iDelNodes++;
1294 if ( iDelNodes ) {
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.
1298 if ( pTargetShell )
1299 pTargetShell->SttEndDoc( false );
1300 aDelIdx -= iDelNodes - 1;
1301 #ifdef DBG_UTIL
1302 SAL_INFO( "sw.docappend", "iDelNodes: " << iDelNodes
1303 << " Idx: " << aDelIdx.GetNode().GetIndex()
1304 << " EOE: " << GetNodes().GetEndOfExtras().GetIndex() );
1305 #endif
1306 GetNodes().Delete( aDelIdx, iDelNodes );
1307 aStartAppendIndex = aFixupIdx;
1309 else
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())
1322 continue;
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);
1336 if ( pTargetShell )
1337 pTargetShell->EndAllAction();
1339 SAL_INFO( "sw.pageframe", "SwDoc::AppendDoc out)" );
1340 return aStartAppendIndex;
1343 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */