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/processfactory.hxx>
37 #include <comphelper/random.hxx>
38 #include <sfx2/viewfrm.hxx>
39 #include <sfx2/XmlIdRegistry.hxx>
40 #include <sal/log.hxx>
41 #include <osl/diagnose.h>
43 #include <sfx2/linkmgr.hxx>
44 #include <editeng/ulspitem.hxx>
45 #include <editeng/lrspitem.hxx>
46 #include <svl/numformat.hxx>
47 #include <unotools/lingucfg.hxx>
48 #include <svx/svdpage.hxx>
49 #include <fmtcntnt.hxx>
50 #include <fmtanchr.hxx>
51 #include <fmtfsize.hxx>
52 #include <fmtfordr.hxx>
53 #include <fmtpdsc.hxx>
54 #include <pvprtdat.hxx>
55 #include <rootfrm.hxx>
56 #include <pagedesc.hxx>
58 #include <ftninfo.hxx>
60 #include <charfmt.hxx>
62 #include <poolfmt.hxx>
65 #include <acorrect.hxx>
66 #include <visiturl.hxx>
68 #include <lineinfo.hxx>
69 #include <drawdoc.hxx>
70 #include <extinput.hxx>
73 #include <shellres.hxx>
74 #include <laycache.hxx>
76 #include <istyleaccess.hxx>
77 #include "swstylemanager.hxx"
78 #include <GrammarContact.hxx>
79 #include <OnlineAccessibilityCheck.hxx>
80 #include <tblafmt.hxx>
81 #include <MarkManager.hxx>
82 #include <UndoManager.hxx>
83 #include <DocumentDeviceManager.hxx>
84 #include <DocumentSettingManager.hxx>
85 #include <DocumentDrawModelManager.hxx>
86 #include <DocumentChartDataProviderManager.hxx>
87 #include <DocumentTimerManager.hxx>
88 #include <DocumentLinksAdministrationManager.hxx>
89 #include <DocumentListItemsManager.hxx>
90 #include <DocumentListsManager.hxx>
91 #include <DocumentOutlineNodesManager.hxx>
92 #include <DocumentContentOperationsManager.hxx>
93 #include <DocumentRedlineManager.hxx>
94 #include <DocumentFieldsManager.hxx>
95 #include <DocumentStatisticsManager.hxx>
96 #include <DocumentStateManager.hxx>
97 #include <DocumentLayoutManager.hxx>
98 #include <DocumentStylePoolManager.hxx>
99 #include <DocumentExternalDataManager.hxx>
101 #include <unocrsr.hxx>
102 #include <fmthdft.hxx>
103 #include <frameformats.hxx>
105 #include <numrule.hxx>
107 #include <sfx2/Metadatable.hxx>
108 #include <fmtmeta.hxx>
109 #include <textcontentcontrol.hxx>
111 #include <svx/xfillit0.hxx>
112 #include <unotools/configmgr.hxx>
113 #include <i18nlangtag/mslangid.hxx>
115 using namespace ::com::sun::star
;
116 using namespace ::com::sun::star::document
;
118 constexpr OUStringLiteral DEFAULT_CHAR_FORMAT_NAME
= u
"Character style";
121 * global functions...
123 uno::Reference
< linguistic2::XProofreadingIterator
> const & SwDoc::GetGCIterator() const
125 if (!m_xGCIterator
.is() && SvtLinguConfig().HasGrammarChecker())
127 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
130 m_xGCIterator
= sw::proofreadingiterator::get( xContext
);
132 catch (const uno::Exception
&)
134 OSL_FAIL( "No GCIterator" );
138 return m_xGCIterator
;
141 bool SwDoc::StartGrammarChecking( bool bSkipStart
)
143 // check for a visible view
144 bool bVisible
= false;
145 bool bStarted
= false;
146 const SwDocShell
*pDocShell
= GetDocShell();
147 SfxViewFrame
*pFrame
= SfxViewFrame::GetFirst( pDocShell
, false );
148 while (pFrame
&& !bVisible
)
150 if (pFrame
->IsVisible())
152 pFrame
= SfxViewFrame::GetNext( *pFrame
, pDocShell
, false );
155 //!! only documents with visible views need to be checked
156 //!! (E.g. don't check temporary documents created for printing, see printing of notes and selections.
157 //!! Those get created on the fly and get hard deleted a bit later as well, and no one should have
158 //!! a UNO reference to them)
161 uno::Reference
< linguistic2::XProofreadingIterator
> xGCIterator( GetGCIterator() );
162 if ( xGCIterator
.is() )
164 uno::Reference
< lang::XComponent
> xDoc
= GetDocShell()->GetBaseModel();
165 uno::Reference
< text::XFlatParagraphIteratorProvider
> xFPIP( xDoc
, uno::UNO_QUERY
);
167 // start automatic background checking if not active already
168 if ( xFPIP
.is() && !xGCIterator
->isProofreading( xDoc
) )
173 for (auto pLayout
: GetAllLayouts())
174 { // we're starting it now, don't start grammar checker
175 // again until the user modifies the document
176 pLayout
->SetNeedGrammarCheck(false);
178 xGCIterator
->startProofreading( xDoc
, xFPIP
);
190 static void lcl_DelFormatIndices( SwFormat
const * pFormat
)
192 SwFormatContent
&rFormatContent
= const_cast<SwFormatContent
&>(pFormat
->GetContent());
193 if ( rFormatContent
.GetContentIdx() )
194 rFormatContent
.SetNewContentIdx( nullptr );
195 SwFormatAnchor
&rFormatAnchor
= const_cast<SwFormatAnchor
&>(pFormat
->GetAnchor());
196 if ( rFormatAnchor
.GetAnchorNode() )
197 rFormatAnchor
.SetAnchor( nullptr );
204 : m_pNodes(new SwNodes(*this)),
205 mpAttrPool(new SwAttrPool(this)),
206 maOLEModifiedIdle( "sw::SwDoc maOLEModifiedIdle" ),
207 mpMarkManager(new ::sw::mark::MarkManager(*this)),
208 m_pMetaFieldManager(new ::sw::MetaFieldManager()),
209 m_pContentControlManager(new ::SwContentControlManager()),
210 m_pDocumentDrawModelManager( new ::sw::DocumentDrawModelManager( *this ) ),
211 m_pDocumentRedlineManager( new ::sw::DocumentRedlineManager( *this ) ),
212 m_pDocumentStateManager( new ::sw::DocumentStateManager( *this ) ),
213 m_pUndoManager(new ::sw::UndoManager(
214 std::shared_ptr
<SwNodes
>(new SwNodes(*this)), *m_pDocumentDrawModelManager
, *m_pDocumentRedlineManager
, *m_pDocumentStateManager
)),
215 m_pDocumentSettingManager(new ::sw::DocumentSettingManager(*this)),
216 m_pDocumentChartDataProviderManager( new sw::DocumentChartDataProviderManager( *this ) ),
217 m_pDeviceAccess( new ::sw::DocumentDeviceManager( *this ) ),
218 m_pDocumentTimerManager( new ::sw::DocumentTimerManager( *this ) ),
219 m_pDocumentLinksAdministrationManager( new ::sw::DocumentLinksAdministrationManager( *this ) ),
220 m_pDocumentListItemsManager( new ::sw::DocumentListItemsManager() ),
221 m_pDocumentListsManager( new ::sw::DocumentListsManager( *this ) ),
222 m_pDocumentOutlineNodesManager( new ::sw::DocumentOutlineNodesManager( *this ) ),
223 m_pDocumentContentOperationsManager( new ::sw::DocumentContentOperationsManager( *this ) ),
224 m_pDocumentFieldsManager( new ::sw::DocumentFieldsManager( *this ) ),
225 m_pDocumentStatisticsManager( new ::sw::DocumentStatisticsManager( *this ) ),
226 m_pDocumentLayoutManager( new ::sw::DocumentLayoutManager( *this ) ),
227 m_pDocumentStylePoolManager( new ::sw::DocumentStylePoolManager( *this ) ),
228 m_pDocumentExternalDataManager( new ::sw::DocumentExternalDataManager
),
229 mpDfltFrameFormat( new SwFrameFormat( GetAttrPool(), "Frameformat", nullptr ) ),
230 mpEmptyPageFormat( new SwFrameFormat( GetAttrPool(), "Empty Page", mpDfltFrameFormat
.get() ) ),
231 mpColumnContFormat( new SwFrameFormat( GetAttrPool(), "Columncontainer", mpDfltFrameFormat
.get() ) ),
232 mpDfltCharFormat( new SwCharFormat( GetAttrPool(), DEFAULT_CHAR_FORMAT_NAME
, nullptr ) ),
233 mpDfltTextFormatColl( new SwTextFormatColl( GetAttrPool(), "Paragraph style" ) ),
234 mpDfltGrfFormatColl( new SwGrfFormatColl( GetAttrPool(), "Graphikformatvorlage" ) ),
235 mpFrameFormatTable( new sw::FrameFormats
<SwFrameFormat
*>() ),
236 mpCharFormatTable( new SwCharFormats
),
237 mpSpzFrameFormatTable( new sw::FrameFormats
<sw::SpzFrameFormat
*>() ),
238 mpSectionFormatTable( new SwSectionFormats
),
239 mpTableFrameFormatTable( new sw::TableFrameFormats() ),
240 mpTextFormatCollTable( new SwTextFormatColls() ),
241 mpGrfFormatCollTable( new SwGrfFormatColls() ),
242 mpTOXTypes( new SwTOXTypes
),
243 mpDefTOXBases( new SwDefTOXBase_Impl() ),
244 mpOutlineRule( nullptr ),
245 mpFootnoteInfo( new SwFootnoteInfo
),
246 mpEndNoteInfo( new SwEndNoteInfo
),
247 mpLineNumberInfo( new SwLineNumberInfo
),
248 mpFootnoteIdxs( new SwFootnoteIdxs
),
249 mpDocShell( nullptr ),
250 mpNumberFormatter( nullptr ),
251 mpNumRuleTable( new SwNumRuleTable
),
252 mpExtInputRing( nullptr ),
253 mpGrammarContact(new sw::GrammarContact
),
254 mpOnlineAccessibilityCheck(new sw::OnlineAccessibilityCheck(*this)),
255 mpCellStyles(new SwCellStyleTable
),
261 mbInMailMerge(false),
262 mbInXMLImport(false),
263 mbInWriterfilterImport(false),
265 mbInLoadAsynchron(false),
266 mbIsAutoFormatRedline(false),
267 mbOLEPrtNotifyPending(false),
268 mbAllOLENotify(false),
269 mbInsOnlyTextGlssry(false),
270 mbContains_MSVBasic(false),
271 mbClipBoard( false ),
272 mbColumnSelection( false ),
273 mbIsPrepareSelAll(false),
274 meDictionaryMissing( MissingDictionary::Undefined
),
275 mbContainsAtPageObjWithContentAnchor(false), //#i119292#, fdo#37024
276 meDocType(DOCTYPE_NATIVE
)
278 // The DrawingLayer ItemPool which is used as 2nd pool for Writer documents' pool
279 // has a default for the XFillStyleItem of XFILL_SOLID and the color for it is the default
280 // fill color (blue7 or similar). This is a problem, in Writer we want the default fill
281 // style to be drawing::FillStyle_NONE. This cannot simply be done by changing it in the 2nd pool at the
282 // pool defaults when the DrawingLayer ItemPool is used for Writer, that would lead to
283 // countless problems like DrawObjects initial fill and others.
284 // It is also hard to find all places where the initial ItemSets for Writer (including
285 // style hierarchies) are created and to always set (but only at the root) the FillStyle
286 // to NONE fixed; that will add that attribute to the file format. It will be hard to reset
287 // attribute sets (which is done at import and using UI). Also not a good solution.
288 // Luckily Writer uses pDfltTextFormatColl as default parent for all paragraphs and similar, thus
289 // it is possible to set this attribute here. It will be not reset when importing.
290 mpDfltTextFormatColl
->SetFormatAttr(XFillStyleItem(drawing::FillStyle_NONE
));
291 mpDfltFrameFormat
->SetFormatAttr(XFillStyleItem(drawing::FillStyle_NONE
));
292 // prevent paragraph default margins being applied to everything
293 mpDfltFrameFormat
->SetFormatAttr(SvxULSpaceItem(RES_UL_SPACE
));
294 mpDfltFrameFormat
->SetFormatAttr(SvxLRSpaceItem(RES_LR_SPACE
));
297 * DefaultFormats and DefaultFormatCollections (FormatColl)
298 * are inserted at position 0 at the respective array.
299 * The formats in the FormatColls are derived from the
300 * DefaultFormats and are also in the list.
303 mpFrameFormatTable
->push_back(mpDfltFrameFormat
.get());
304 mpCharFormatTable
->insert(mpDfltCharFormat
.get());
308 mpTextFormatCollTable
->push_back(mpDfltTextFormatColl
.get());
310 mpGrfFormatCollTable
->push_back(mpDfltGrfFormatColl
.get());
312 // Create PageDesc, EmptyPageFormat and ColumnFormat
313 if (m_PageDescs
.empty())
314 getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD
);
316 // Set to "Empty Page"
317 mpEmptyPageFormat
->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Fixed
) );
318 // Set BodyFormat for columns
319 mpColumnContFormat
->SetFormatAttr( SwFormatFillOrder( ATT_LEFT_TO_RIGHT
) );
321 GetDocumentFieldsManager().InitFieldTypes();
323 // Create a default OutlineNumRule (for Filters)
324 mpOutlineRule
= new SwNumRule( SwNumRule::GetOutlineRuleName(),
326 numfunc::GetDefaultPositionAndSpaceMode(),
328 AddNumRule(mpOutlineRule
);
329 // Counting of phantoms depends on <IsOldNumbering()>
330 mpOutlineRule
->SetCountPhantoms( !GetDocumentSettingManager().get(DocumentSettingId::OLD_NUMBERING
) );
333 GetUndoManager().GetUndoNodes().GetEndOfContent(),
334 mpDfltTextFormatColl
.get() );
335 new SwTextNode( GetNodes().GetEndOfContent(),
336 getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD
));
338 maOLEModifiedIdle
.SetPriority( TaskPriority::LOWEST
);
339 maOLEModifiedIdle
.SetInvokeHandler( LINK( this, SwDoc
, DoUpdateModifiedOLE
));
341 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
343 m_pOwnDBManager
.reset(new SwDBManager(this));
344 m_pDBManager
= m_pOwnDBManager
.get();
346 m_pDBManager
= nullptr;
352 // pass empty item set containing the paragraph's list attributes
353 // as ignorable items to the stype manager.
355 SfxItemSetFixed
<RES_PARATR_LIST_BEGIN
, RES_PARATR_LIST_END
-1> aIgnorableParagraphItems( GetAttrPool() );
356 mpStyleAccess
= createStyleManager( &aIgnorableParagraphItems
);
359 static bool bHack
= (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
367 // Initialize the session id of the current document to a random number
368 // smaller than 2^21.
369 mnRsid
= comphelper::rng::uniform_uint_distribution(1, (1 << 21) - 1);
373 if (!utl::ConfigManager::IsFuzzing())
375 // Make sure that in case the document language is not set, then we don't return
376 // LANGUAGE_DONTKNOW, but the UI locale.
377 const SvtLinguConfig aLinguConfig
;
378 SvtLinguOptions aOptions
;
379 aLinguConfig
.GetOptions(aOptions
);
380 LanguageType eLang
= MsLangId::resolveSystemLanguageByScriptType(aOptions
.nDefaultLanguage
,
381 i18n::ScriptType::LATIN
);
382 SetLanguage(eLang
, RES_CHRATR_LANGUAGE
);
383 eLang
= MsLangId::resolveSystemLanguageByScriptType(aOptions
.nDefaultLanguage_CJK
,
384 i18n::ScriptType::ASIAN
);
385 SetLanguage(eLang
, RES_CHRATR_CJK_LANGUAGE
);
386 eLang
= MsLangId::resolveSystemLanguageByScriptType(aOptions
.nDefaultLanguage_CTL
,
387 i18n::ScriptType::COMPLEX
);
388 SetLanguage(eLang
, RES_CHRATR_CTL_LANGUAGE
);
391 getIDocumentState().ResetModified();
397 * Speciality: a member of the class SwDoc is located at
398 * position 0 in the array of the Format and GDI objects.
399 * This MUST not be destroyed using 'delete' in any case!
407 // nothing here should create Undo actions!
408 GetIDocumentUndoRedo().DoUndo(false);
412 mpDocShell
->SetUndoManager(nullptr);
415 mpGrammarContact
.reset();
416 mpOnlineAccessibilityCheck
.reset();
418 getIDocumentTimerAccess().StopIdling(); // stop idle timer
420 mpURLStateChgd
.reset();
422 // Deactivate Undo notification from Draw
423 if( GetDocumentDrawModelManager().GetDrawModel() )
425 GetDocumentDrawModelManager().DrawNotifyUndoHdl();
429 m_pPgPViewPrtData
.reset();
433 //Clear the redline table before the nodes array is destroyed
434 getIDocumentRedlineAccess().GetRedlineTable().DeleteAndDestroyAll();
435 getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteAndDestroyAll();
437 const sw::UnoCursorHint aHint
;
438 cleanupUnoCursorTable();
439 for(const auto& pWeakCursor
: mvUnoCursorTable
)
441 auto pCursor(pWeakCursor
.lock());
443 pCursor
->m_aNotifier
.Broadcast(aHint
);
447 // Release the BaseLinks
449 ::sfx2::SvLinkSources
aTemp(getIDocumentLinksAdministration().GetLinkManager().GetServers());
450 for( const auto& rpLinkSrc
: aTemp
)
453 if( !getIDocumentLinksAdministration().GetLinkManager().GetLinks().empty() )
454 getIDocumentLinksAdministration().GetLinkManager().Remove( 0, getIDocumentLinksAdministration().GetLinkManager().GetLinks().size() );
457 // The ChapterNumbers/Numbers need to be deleted before the styles
458 // or we update all the time!
459 m_pNodes
->m_aOutlineNodes
.clear();
460 SwNodes
& rUndoNodes( GetUndoManager().GetUndoNodes() );
461 rUndoNodes
.m_aOutlineNodes
.clear();
463 mpFootnoteIdxs
->clear();
465 // indices could be registered in attributes
466 m_pUndoManager
->DelAllUndoObj();
468 // The BookMarks contain indices to the Content. These must be deleted
469 // before deleting the Nodes.
470 mpMarkManager
->clearAllMarks();
474 SwPaM
* pTmp
= mpExtInputRing
;
475 mpExtInputRing
= nullptr;
476 while( pTmp
->GetNext() != pTmp
)
478 // coverity[deref_arg] - the SwPaM delete moves a new entry into GetNext()
479 delete pTmp
->GetNext();
484 // Any of the FrameFormats can still have indices registered.
485 // These need to be destroyed now at the latest.
486 for( SwFrameFormat
* pFormat
: *mpFrameFormatTable
)
487 lcl_DelFormatIndices( pFormat
);
488 for( SwFrameFormat
* pFormat
: *mpSpzFrameFormatTable
)
489 lcl_DelFormatIndices( pFormat
);
490 for( SwSectionFormat
* pFormat
: *mpSectionFormatTable
)
491 lcl_DelFormatIndices( pFormat
);
493 // The formats/styles that follow depend on the default formats.
494 // Destroy these only after destroying the FormatIndices, because the content
495 // of headers/footers has to be deleted as well. If in the headers/footers
496 // there are still Flys registered at that point, we have a problem.
497 for( SwPageDesc
*pPageDesc
: m_PageDescs
)
501 // Delete content selections.
502 // Don't wait for the SwNodes dtor to destroy them; so that Formats
503 // do not have any dependencies anymore.
504 m_pNodes
->DelNodes( SwNodeIndex(*m_pNodes
), m_pNodes
->Count() );
505 rUndoNodes
.DelNodes( SwNodeIndex( rUndoNodes
), rUndoNodes
.Count() );
507 // clear TOX after nodes - TOXMarks are gone now so SwTOXType has no clients
508 for (const auto& pType
: *mpTOXTypes
)
510 pType
->CallSwClientNotify(sw::DocumentDyingHint());
513 mpDefTOXBases
.reset();
515 // Delete Formats, make it permanent some time in the future
517 // Delete for Collections
518 // So that we get rid of the dependencies
519 mpFootnoteInfo
->EndListeningAll();
520 mpEndNoteInfo
->EndListeningAll();
522 assert(mpDfltTextFormatColl
.get() == (*mpTextFormatCollTable
)[0]
523 && "Default-Text-Collection must always be at the start");
525 // Optimization: Based on the fact that Standard is always 2nd in the
526 // array, we should delete it as the last. With this we avoid
527 // reparenting the Formats all the time!
528 if( 2 < mpTextFormatCollTable
->size() )
529 mpTextFormatCollTable
->DeleteAndDestroy(2, mpTextFormatCollTable
->size());
530 mpTextFormatCollTable
->DeleteAndDestroy(1, mpTextFormatCollTable
->size());
531 mpTextFormatCollTable
.reset();
533 assert(mpDfltGrfFormatColl
.get() == (*mpGrfFormatCollTable
)[0]
534 && "DefaultGrfCollection must always be at the start");
536 mpGrfFormatCollTable
->DeleteAndDestroy(1, mpGrfFormatCollTable
->size());
537 mpGrfFormatCollTable
.reset();
539 // Without explicitly freeing the DocumentDeviceManager
540 // and relying on the implicit freeing there would be a crash
541 // due to it happening after SwAttrPool is freed.
542 m_pDeviceAccess
.reset();
545 * DefaultFormats and DefaultFormatCollections (FormatColl)
546 * are at position 0 of their respective arrays.
547 * In order to not be deleted by the array's dtor, we remove them
550 mpFrameFormatTable
->erase( mpFrameFormatTable
->begin() );
552 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
553 // On load, SwDBManager::setEmbeddedName() may register a data source.
554 // If we have an embedded one, then sDataSource points to the registered name, so revoke it here.
555 if (!m_pOwnDBManager
->getEmbeddedName().isEmpty() && !maDBData
.sDataSource
.isEmpty())
557 // Remove the revoke listener here first, so that we don't remove the data source from the document.
558 m_pOwnDBManager
->releaseRevokeListener();
559 SwDBManager::RevokeDataSource(maDBData
.sDataSource
);
560 SwDBManager::RevokeDataSource(m_pOwnDBManager
->getEmbeddedName());
562 else if (!m_pOwnDBManager
->getEmbeddedName().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 // Remove connections which was committed but not used.
567 m_pOwnDBManager
->RevokeNotUsedConnections();
570 m_pOwnDBManager
.reset();
573 // All Flys need to be destroyed before the Drawing Model,
574 // because Flys can still contain DrawContacts, when no
575 // Layout could be constructed due to a read error.
576 mpSpzFrameFormatTable
->DeleteAndDestroyAll();
578 // Only now destroy the Model, the drawing objects - which are also
579 // contained in the Undo - need to remove their attributes from the
580 // Model. Also, DrawContacts could exist before this.
581 GetDocumentDrawModelManager().ReleaseDrawModel();
582 // Destroy DrawModel before the LinkManager, because it's always set
584 //The LinkManager gets destroyed automatically with m_pLinksAdministrationManager
586 // Clear the Tables before deleting the defaults, or we crash due to
587 // dependencies on defaults.
588 mpFrameFormatTable
.reset();
589 mpSpzFrameFormatTable
.reset();
591 mpStyleAccess
.reset();
593 mpCharFormatTable
.reset();
594 mpSectionFormatTable
.reset();
595 mpTableFrameFormatTable
.reset();
596 mpDfltTextFormatColl
.reset();
597 mpDfltGrfFormatColl
.reset();
598 mpNumRuleTable
.reset();
600 disposeXForms(); // #i113606#, dispose the XForms objects
603 std::scoped_lock
lock(mNumberFormatterMutex
);
604 delete mpNumberFormatter
; mpNumberFormatter
= nullptr;
606 mpFootnoteInfo
.reset();
607 mpEndNoteInfo
.reset();
608 mpLineNumberInfo
.reset();
609 mpFootnoteIdxs
.reset();
611 mpEmptyPageFormat
.reset();
612 mpColumnContFormat
.reset();
613 mpDfltCharFormat
.reset();
614 mpDfltFrameFormat
.reset();
615 mpLayoutCache
.reset();
619 void SwDoc::SetDocShell( SwDocShell
* pDSh
)
621 if( mpDocShell
== pDSh
)
626 mpDocShell
->SetUndoManager(nullptr);
631 mpDocShell
->SetUndoManager(& GetUndoManager());
632 GetUndoManager().SetDocShell(mpDocShell
);
635 getIDocumentLinksAdministration().GetLinkManager().SetPersist( mpDocShell
);
637 // set DocShell pointer also on DrawModel
638 InitDrawModelAndDocShell(mpDocShell
, GetDocumentDrawModelManager().GetDrawModel());
639 assert(!GetDocumentDrawModelManager().GetDrawModel() ||
640 GetDocumentDrawModelManager().GetDrawModel()->GetPersist() == GetPersist());
643 // Convenience method; to avoid excessive includes from docsh.hxx
644 uno::Reference
< embed::XStorage
> SwDoc::GetDocStorage()
647 return mpDocShell
->GetStorage();
648 if( getIDocumentLinksAdministration().GetLinkManager().GetPersist() )
649 return getIDocumentLinksAdministration().GetLinkManager().GetPersist()->GetStorage();
653 SfxObjectShell
* SwDoc::GetPersist() const
655 return mpDocShell
? mpDocShell
: getIDocumentLinksAdministration().GetLinkManager().GetPersist();
658 void SwDoc::ClearDoc()
660 GetIDocumentUndoRedo().DelAllUndoObj();
661 ::sw::UndoGuard
const undoGuard(GetIDocumentUndoRedo());
663 // Deactivate Undo notification from Draw
664 if( GetDocumentDrawModelManager().GetDrawModel() )
666 GetDocumentDrawModelManager().DrawNotifyUndoHdl();
670 // if there are still FlyFrames dangling around, delete them too
671 while ( !mpSpzFrameFormatTable
->empty() )
672 getIDocumentLayoutAccess().DelLayoutFormat((*mpSpzFrameFormatTable
)[mpSpzFrameFormatTable
->size()-1]);
673 assert(!GetDocumentDrawModelManager().GetDrawModel()
674 || !GetDocumentDrawModelManager().GetDrawModel()->GetPage(0)->GetObjCount());
676 getIDocumentRedlineAccess().GetRedlineTable().DeleteAndDestroyAll();
677 getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteAndDestroyAll();
681 // The BookMarks contain indices to the Content. These must be deleted
682 // before deleting the Nodes.
683 mpMarkManager
->clearAllMarks();
686 // create a dummy pagedesc for the layout
687 SwPageDesc
* pDummyPgDsc
= MakePageDesc("?DUMMY?");
689 SwNodeIndex
aSttIdx( *GetNodes().GetEndOfContent().StartOfSectionNode(), 1 );
690 // create the first one over and over again (without attributes/style etc.
691 SwTextNode
* pFirstNd
= GetNodes().MakeTextNode( aSttIdx
.GetNode(), mpDfltTextFormatColl
.get() );
693 if( getIDocumentLayoutAccess().GetCurrentViewShell() )
695 // set the layout to the dummy pagedesc
696 pFirstNd
->SetAttr( SwFormatPageDesc( pDummyPgDsc
));
698 SwPosition
aPos( *pFirstNd
);
699 SwPaM
const tmpPaM(aSttIdx
.GetNode(), GetNodes().GetEndOfContent());
700 ::PaMCorrAbs(tmpPaM
, aPos
);
703 GetNodes().Delete( aSttIdx
,
704 GetNodes().GetEndOfContent().GetIndex() - aSttIdx
.GetIndex() );
707 // destruction of numbering rules and creation of new outline rule
708 // *after* the document nodes are deleted.
709 mpOutlineRule
= nullptr;
710 for( SwNumRule
* pNumRule
: *mpNumRuleTable
)
712 getIDocumentListsAccess().deleteListForListStyle(pNumRule
->GetName());
715 mpNumRuleTable
->clear();
716 maNumRuleMap
.clear();
718 // creation of new outline numbering rule
719 mpOutlineRule
= new SwNumRule( SwNumRule::GetOutlineRuleName(),
721 numfunc::GetDefaultPositionAndSpaceMode(),
723 AddNumRule(mpOutlineRule
);
724 // Counting of phantoms depends on <IsOldNumbering()>
725 mpOutlineRule
->SetCountPhantoms( !GetDocumentSettingManager().get(DocumentSettingId::OLD_NUMBERING
) );
727 // remove the dummy pagedesc from the array and delete all the old ones
728 size_t nDummyPgDsc
= 0;
729 if (FindPageDesc(pDummyPgDsc
->GetName(), &nDummyPgDsc
))
730 m_PageDescs
.erase( nDummyPgDsc
);
731 for( SwPageDesc
*pPageDesc
: m_PageDescs
)
735 // Delete for Collections
736 // So that we get rid of the dependencies
737 mpFootnoteInfo
->EndListeningAll();
738 mpEndNoteInfo
->EndListeningAll();
740 // Optimization: Based on the fact that Standard is always 2nd in the
741 // array, we should delete it as the last. With this we avoid
742 // reparenting the Formats all the time!
743 if( 2 < mpTextFormatCollTable
->size() )
744 mpTextFormatCollTable
->DeleteAndDestroy(2, mpTextFormatCollTable
->size());
745 mpTextFormatCollTable
->DeleteAndDestroy(1, mpTextFormatCollTable
->size());
746 mpGrfFormatCollTable
->DeleteAndDestroy(1, mpGrfFormatCollTable
->size());
747 mpCharFormatTable
->DeleteAndDestroyAll(/*keepDefault*/true);
749 if( getIDocumentLayoutAccess().GetCurrentViewShell() )
751 // search the FrameFormat of the root frm. This is not allowed to delete
752 mpFrameFormatTable
->erase( getIDocumentLayoutAccess().GetCurrentViewShell()->GetLayout()->GetFormat() );
753 mpFrameFormatTable
->DeleteAndDestroyAll( true );
754 mpFrameFormatTable
->push_back( getIDocumentLayoutAccess().GetCurrentViewShell()->GetLayout()->GetFormat() );
757 mpFrameFormatTable
->DeleteAndDestroyAll( true );
759 GetDocumentFieldsManager().ClearFieldTypes();
762 std::scoped_lock
lock(mNumberFormatterMutex
);
763 delete mpNumberFormatter
; mpNumberFormatter
= nullptr;
766 getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD
);
767 pFirstNd
->ChgFormatColl( getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD
));
768 nDummyPgDsc
= m_PageDescs
.size();
769 m_PageDescs
.push_back( pDummyPgDsc
);
770 // set the layout back to the new standard pagedesc
771 pFirstNd
->ResetAllAttr();
772 // delete now the dummy pagedesc
773 DelPageDesc( nDummyPgDsc
);
776 void SwDoc::SetPreviewPrtData( const SwPagePreviewPrtData
* pNew
)
780 if (m_pPgPViewPrtData
)
782 *m_pPgPViewPrtData
= *pNew
;
786 m_pPgPViewPrtData
.reset(new SwPagePreviewPrtData(*pNew
));
789 else if (m_pPgPViewPrtData
)
791 m_pPgPViewPrtData
.reset();
793 getIDocumentState().SetModified();
796 void SwDoc::SetOLEObjModified()
798 if( getIDocumentLayoutAccess().GetCurrentViewShell() ) maOLEModifiedIdle
.Start();
801 /** SwDoc: Reading and writing of the layout cache. */
802 void SwDoc::ReadLayoutCache( SvStream
& rStream
)
805 mpLayoutCache
.reset( new SwLayoutCache() );
806 if( !mpLayoutCache
->IsLocked() )
808 mpLayoutCache
->GetLockCount() |= 0x8000;
809 mpLayoutCache
->Read( rStream
);
810 mpLayoutCache
->GetLockCount() &= 0x7fff;
814 void SwDoc::WriteLayoutCache( SvStream
& rStream
)
816 SwLayoutCache::Write( rStream
, *this );
819 ::sfx2::IXmlIdRegistry
&
820 SwDoc::GetXmlIdRegistry()
822 // UGLY: this relies on SetClipBoard being called before GetXmlIdRegistry!
823 if (!m_pXmlIdRegistry
)
825 m_pXmlIdRegistry
.reset( ::sfx2::createXmlIdRegistry( IsClipBoard() ) );
827 return *m_pXmlIdRegistry
;
830 void SwDoc::InitTOXTypes()
832 ShellResource
* pShellRes
= SwViewShell::GetShellRes();
833 SwTOXType
* pNew
= new SwTOXType(*this, TOX_CONTENT
, pShellRes
->aTOXContentName
);
834 mpTOXTypes
->emplace_back( pNew
);
835 pNew
= new SwTOXType(*this, TOX_INDEX
, pShellRes
->aTOXIndexName
);
836 mpTOXTypes
->emplace_back( pNew
);
837 pNew
= new SwTOXType(*this, TOX_USER
, pShellRes
->aTOXUserName
);
838 mpTOXTypes
->emplace_back( pNew
);
839 pNew
= new SwTOXType(*this, TOX_ILLUSTRATIONS
, pShellRes
->aTOXIllustrationsName
);
840 mpTOXTypes
->emplace_back( pNew
);
841 pNew
= new SwTOXType(*this, TOX_OBJECTS
, pShellRes
->aTOXObjectsName
);
842 mpTOXTypes
->emplace_back( pNew
);
843 pNew
= new SwTOXType(*this, TOX_TABLES
, pShellRes
->aTOXTablesName
);
844 mpTOXTypes
->emplace_back( pNew
);
845 pNew
= new SwTOXType(*this, TOX_AUTHORITIES
, pShellRes
->aTOXAuthoritiesName
);
846 mpTOXTypes
->emplace_back( pNew
);
847 pNew
= new SwTOXType(*this, TOX_CITATION
, pShellRes
->aTOXCitationName
);
848 mpTOXTypes
->emplace_back( pNew
);
851 void SwDoc::ReplaceDefaults(const SwDoc
& rSource
)
853 // copy property defaults
854 static const WhichRangesContainer
aRangeOfDefaults(svl::Items
<
855 RES_CHRATR_BEGIN
, RES_CHRATR_END
-1,
856 RES_PARATR_BEGIN
, RES_PARATR_END
-1,
857 RES_PARATR_LIST_BEGIN
, RES_PARATR_LIST_END
-1,
858 RES_FRMATR_BEGIN
, RES_FRMATR_END
-1,
859 RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
-1,
860 XATTR_START
, XATTR_END
-1
863 SfxItemSet
aNewDefaults(GetAttrPool(), aRangeOfDefaults
);
865 for (const WhichPair
& rPair
: aRangeOfDefaults
)
867 for (sal_uInt16 nWhich
= rPair
.first
;
868 nWhich
<= rPair
.second
; ++nWhich
)
870 const SfxPoolItem
& rSourceAttr
=
871 rSource
.mpAttrPool
->GetDefaultItem(nWhich
);
872 if (rSourceAttr
!= mpAttrPool
->GetDefaultItem(nWhich
))
873 aNewDefaults
.Put(rSourceAttr
);
877 if (aNewDefaults
.Count())
878 SetDefault(aNewDefaults
);
881 void SwDoc::ReplaceCompatibilityOptions(const SwDoc
& rSource
)
883 m_pDocumentSettingManager
->ReplaceCompatibilityOptions(rSource
.GetDocumentSettingManager());
887 #define CNTNT_DOC( doc ) \
888 ((doc)->GetNodes().GetEndOfContent().GetIndex() - (doc)->GetNodes().GetEndOfExtras().GetIndex() - SwNodeOffset(2))
889 #define CNTNT_IDX( idx ) \
890 ((idx).GetNode().GetIndex() - GetNodes().GetEndOfExtras().GetIndex() - 1)
893 SfxObjectShell
* SwDoc::CreateCopy( bool bCallInitNew
, bool bEmpty
) const
895 SAL_INFO( "sw.pageframe", "(SwDoc::CreateCopy in" );
896 rtl::Reference
<SwDoc
> xRet( new SwDoc
);
898 // we have to use pointer here, since the callee has to decide whether
899 // SfxObjectShellLock or SfxObjectShellRef should be used sometimes the
900 // object will be returned with refcount set to 0 ( if no DoInitNew is done )
901 SfxObjectShell
* pRetShell
= new SwDocShell( *xRet
, SfxObjectCreateMode::STANDARD
);
904 // it could happen that DoInitNew creates model,
905 // that increases the refcount of the object
906 pRetShell
->DoInitNew();
909 xRet
->ReplaceDefaults(*this);
911 xRet
->ReplaceCompatibilityOptions(*this);
913 xRet
->ReplaceStyles(*this);
915 uno::Reference
<beans::XPropertySet
> const xThisSet(
916 GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW
);
917 uno::Reference
<beans::XPropertySet
> const xRetSet(
918 pRetShell
->GetBaseModel(), uno::UNO_QUERY_THROW
);
919 uno::Sequence
<beans::PropertyValue
> aInteropGrabBag
;
920 xThisSet
->getPropertyValue("InteropGrabBag") >>= aInteropGrabBag
;
921 xRetSet
->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag
));
926 SAL_INFO( "sw.createcopy", "CC-Nd-Src: " << CNTNT_DOC( this ) );
927 SAL_INFO( "sw.createcopy", "CC-Nd: " << CNTNT_DOC( xRet
) );
929 xRet
->AppendDoc(*this, 0, bCallInitNew
, 0, 0);
931 SAL_INFO( "sw.createcopy", "CC-Nd: " << CNTNT_DOC( xRet
) );
935 // remove the temporary shell if it is there as it was done before
936 xRet
->SetTmpDocShell( nullptr );
938 SAL_INFO( "sw.pageframe", "SwDoc::CreateCopy out)" );
942 // save bulk letters as single documents
943 static OUString
lcl_FindUniqueName(SwWrtShell
* pTargetShell
, std::u16string_view rStartingPageDesc
, sal_uLong nDocNo
)
947 OUString sTest
= rStartingPageDesc
+ OUString::number( nDocNo
);
948 if( !pTargetShell
->FindPageDescByName( sTest
) )
955 /** Returns whether the passed SwPageDesc& or any of its (transitive) follows
956 contains a header or footer. */
957 static bool lcl_PageDescOrFollowContainsHeaderFooter(const SwPageDesc
& rPageDesc
)
959 // remember already checked page descs to avoid cycle
960 o3tl::sorted_vector
<const SwPageDesc
*> aCheckedPageDescs
;
961 const SwPageDesc
* pCurPageDesc
= &rPageDesc
;
962 while (aCheckedPageDescs
.count(pCurPageDesc
) == 0)
964 const SwFrameFormat
& rMaster
= pCurPageDesc
->GetMaster();
965 if (rMaster
.GetHeader().IsActive() || rMaster
.GetFooter().IsActive())
968 aCheckedPageDescs
.insert(pCurPageDesc
);
969 pCurPageDesc
= pCurPageDesc
->GetFollow();
974 static void lcl_CopyFollowPageDesc(
975 SwWrtShell
& rTargetShell
,
976 const SwPageDesc
& rSourcePageDesc
,
977 const SwPageDesc
& rTargetPageDesc
,
978 const sal_uLong nDocNo
)
980 //now copy the follow page desc, too
981 // note: these may at any point form a cycle, so a loop is needed and it
982 // must be detected that the last iteration closes the cycle and doesn't
983 // copy the first page desc of the cycle again.
984 std::map
<OUString
, OUString
> followMap
{ { rSourcePageDesc
.GetName(), rTargetPageDesc
.GetName() } };
985 SwPageDesc
const* pCurSourcePageDesc(&rSourcePageDesc
);
986 SwPageDesc
const* pCurTargetPageDesc(&rTargetPageDesc
);
989 const SwPageDesc
* pFollowPageDesc
= pCurSourcePageDesc
->GetFollow();
990 OUString sFollowPageDesc
= pFollowPageDesc
->GetName();
991 if (sFollowPageDesc
== pCurSourcePageDesc
->GetName())
995 SwDoc
* pTargetDoc
= rTargetShell
.GetDoc();
996 SwPageDesc
* pTargetFollowPageDesc(nullptr);
997 auto const itMapped(followMap
.find(sFollowPageDesc
));
998 if (itMapped
== followMap
.end())
1000 OUString sNewFollowPageDesc
= lcl_FindUniqueName(&rTargetShell
, sFollowPageDesc
, nDocNo
);
1001 pTargetFollowPageDesc
= pTargetDoc
->MakePageDesc(sNewFollowPageDesc
);
1002 pTargetDoc
->CopyPageDesc(*pFollowPageDesc
, *pTargetFollowPageDesc
, false);
1006 pTargetFollowPageDesc
= pTargetDoc
->FindPageDesc(itMapped
->second
);
1008 SwPageDesc
aDesc(*pCurTargetPageDesc
);
1009 aDesc
.SetFollow(pTargetFollowPageDesc
);
1010 pTargetDoc
->ChgPageDesc(pCurTargetPageDesc
->GetName(), aDesc
);
1011 if (itMapped
!= followMap
.end())
1013 break; // was already copied
1015 pCurSourcePageDesc
= pCurSourcePageDesc
->GetFollow();
1016 pCurTargetPageDesc
= pTargetFollowPageDesc
;
1017 followMap
[pCurSourcePageDesc
->GetName()] = pCurTargetPageDesc
->GetName();
1022 // appends all pages of source SwDoc - based on SwFEShell::Paste( SwDoc* )
1023 SwNodeIndex
SwDoc::AppendDoc(const SwDoc
& rSource
, sal_uInt16
const nStartPageNumber
,
1024 bool const bDeletePrevious
, int pageOffset
, const sal_uLong nDocNo
)
1026 SAL_INFO( "sw.pageframe", "(SwDoc::AppendDoc in " << bDeletePrevious
);
1028 // GetEndOfExtras + 1 = StartOfContent == no content node!
1029 // This ensures it won't be merged in the SwTextNode at the position.
1030 SwNodeIndex
aSourceIdx( rSource
.GetNodes().GetEndOfExtras(), 1 );
1031 // CopyRange works on the range a [mark, point[ and considers an
1032 // index < point outside the selection.
1033 // @see IDocumentContentOperations::CopyRange
1034 SwNodeIndex
aSourceEndIdx( rSource
.GetNodes().GetEndOfContent(), 0 );
1035 SwPaM
aCpyPam( aSourceIdx
, aSourceEndIdx
);
1038 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceIdx
.GetNode().GetNodeType())
1039 << std::dec
<< " " << aSourceIdx
.GetNode().GetIndex() );
1041 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceIdx
.GetNode().GetNodeType())
1042 << std::dec
<< " " << aSourceIdx
.GetNode().GetIndex() );
1043 if ( aSourceIdx
.GetNode().GetNodeType() != SwNodeType::End
) {
1045 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceIdx
.GetNode().GetNodeType()) << std::dec
);
1049 SAL_INFO( "sw.docappend", ".." );
1050 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceEndIdx
.GetNode().GetNodeType())
1051 << std::dec
<< " " << aSourceEndIdx
.GetNode().GetIndex() );
1052 SAL_INFO( "sw.docappend", "NodeType 0x" << std::hex
<< static_cast<int>(aSourceEndIdx
.GetNode().GetNodeType())
1053 << std::dec
<< " " << aSourceEndIdx
.GetNode().GetIndex() );
1054 SAL_INFO( "sw.docappend", "Src-Nd: " << CNTNT_DOC( &rSource
) );
1055 SAL_INFO( "sw.docappend", "Nd: " << CNTNT_DOC( this ) );
1058 SwWrtShell
* pTargetShell
= GetDocShell()->GetWrtShell();
1059 SwPageDesc
* pTargetPageDesc
= nullptr;
1061 if ( pTargetShell
) {
1063 SAL_INFO( "sw.docappend", "Has target write shell" );
1065 pTargetShell
->StartAllAction();
1069 // #i72517# put the styles to the target document
1070 // if the source uses headers or footers the target document
1071 // needs individual page styles
1072 const SwWrtShell
*pSourceShell
= rSource
.GetDocShell()->GetWrtShell();
1073 const SwPageDesc
& rSourcePageDesc
= pSourceShell
->GetPageDesc(
1074 pSourceShell
->GetCurPageDesc());
1075 const OUString sStartingPageDesc
= rSourcePageDesc
.GetName();
1076 const bool bPageStylesWithHeaderFooter
= lcl_PageDescOrFollowContainsHeaderFooter(rSourcePageDesc
);
1077 if( bPageStylesWithHeaderFooter
)
1079 // create a new pagestyle
1080 // copy the pagedesc from the current document to the new
1081 // document and change the name of the to-be-applied style
1082 OUString sNewPageDescName
= lcl_FindUniqueName(pTargetShell
, sStartingPageDesc
, nDocNo
);
1083 pTargetPageDesc
= MakePageDesc( sNewPageDescName
);
1084 if( pTargetPageDesc
)
1086 CopyPageDesc( rSourcePageDesc
, *pTargetPageDesc
, false );
1087 lcl_CopyFollowPageDesc( *pTargetShell
, rSourcePageDesc
, *pTargetPageDesc
, nDocNo
);
1091 pTargetPageDesc
= pTargetShell
->FindPageDescByName( sStartingPageDesc
);
1094 // Otherwise we have to handle SwPlaceholderNodes as first node
1095 if ( pTargetPageDesc
)
1097 SwNodeIndex
aBreakIdx( GetNodes().GetEndOfContent(), -1 );
1098 SwPosition
aBreakPos( aBreakIdx
);
1099 // insert new node - will be removed at the end...
1100 // (don't SplitNode() as it may move flys to the wrong node)
1101 getIDocumentContentOperations().AppendTextNode(aBreakPos
);
1102 SwFormatPageDesc
pageDesc(pTargetPageDesc
);
1103 pageDesc
.SetNumOffset(nStartPageNumber
);
1104 // set break on the last paragraph
1105 getIDocumentContentOperations().InsertPoolItem(SwPaM(aBreakPos
),
1106 pageDesc
, SetAttrMode::DEFAULT
, pTargetShell
->GetLayout());
1107 // tdf#148309 move to the last node - so that the "flush page break"
1108 // code below will format the frame of the node with the page break,
1109 // which is required for new page frames to be created! Else layout
1110 // performance will be terrible.
1111 pTargetShell
->SttEndDoc(false);
1113 // There is now a new empty text node on the new page. If it has
1114 // any marks, those are from the previous page: move them back
1115 // there, otherwise later we can't delete that empty text node.
1116 SwNodeIndex
aNodeIndex(GetNodes().GetEndOfContent(), -1);
1117 if (SwTextNode
* pTextNode
= aNodeIndex
.GetNode().GetTextNode())
1119 // Position of the last paragraph on the previous page.
1121 SwPaM
aPaM(aNodeIndex
);
1122 // Collect the marks starting or ending at this text node.
1123 o3tl::sorted_vector
<sw::mark::IMark
*> aSeenMarks
;
1124 IDocumentMarkAccess
* pMarkAccess
= getIDocumentMarkAccess();
1125 for (const SwContentIndex
* pIndex
= pTextNode
->GetFirstIndex(); pIndex
; pIndex
= pIndex
->GetNext())
1127 sw::mark::IMark
* pMark
= const_cast<sw::mark::IMark
*>(pIndex
->GetMark());
1130 if (!aSeenMarks
.insert(pMark
).second
)
1133 // And move them back.
1134 for (sw::mark::IMark
* pMark
: aSeenMarks
)
1135 pMarkAccess
->repositionMark(pMark
, aPaM
);
1138 // Flush the page break, if we want to keep it
1139 if ( !bDeletePrevious
)
1141 SAL_INFO( "sw.pageframe", "(Flush pagebreak AKA EndAllAction" );
1142 assert(pTargetShell
->GetCursor()->GetPoint()->GetNode().GetTextNode()->GetSwAttrSet().HasItem(RES_PAGEDESC
));
1143 pTargetShell
->EndAllAction();
1144 SAL_INFO( "sw.pageframe", "Flush changes AKA EndAllAction)" );
1145 pTargetShell
->StartAllAction();
1150 SAL_INFO( "sw.docappend", "Nd: " << CNTNT_DOC( this ) );
1153 // -1, otherwise aFixupIdx would move to new EOC
1154 SwNodeIndex
aFixupIdx( GetNodes().GetEndOfContent(), -1 );
1156 // append at the end of document / content
1157 SwPaM
aInsertPam( GetNodes().GetEndOfContent() );
1160 SAL_INFO( "sw.docappend", "Pam-Nd: " << aCpyPam
.GetPointNode().GetIndex() - aCpyPam
.GetMarkNode().GetIndex() + 1
1161 << " (0x" << std::hex
<< static_cast<int>(aCpyPam
.GetMarkNode().GetNodeType()) << std::dec
1162 << " " << aCpyPam
.GetMarkNode().GetIndex()
1163 << " - 0x" << std::hex
<< static_cast<int>(aCpyPam
.GetPointNode().GetNodeType()) << std::dec
1164 << " " << aCpyPam
.GetPointNode().GetIndex() << ")" );
1167 GetIDocumentUndoRedo().StartUndo( SwUndoId::INSGLOSSARY
, nullptr );
1168 getIDocumentFieldsAccess().LockExpFields();
1170 // Position where the appended doc starts. Will be filled in later.
1171 // Initially uses GetEndOfContent() because SwNodeIndex has no default ctor.
1172 SwNodeIndex
aStartAppendIndex( GetNodes().GetEndOfContent() );
1176 // ** refer to SwFEShell::Paste, if you change the following code **
1179 SwPosition
& rInsPos
= *aInsertPam
.GetPoint();
1182 SwNodeIndex
aIndexBefore(rInsPos
.GetNode());
1186 SAL_INFO( "sw.docappend", "CopyRange In: " << CNTNT_DOC( this ) );
1188 rSource
.getIDocumentContentOperations().CopyRange(aCpyPam
, rInsPos
, SwCopyFlags::CopyAll
|SwCopyFlags::CheckPosInFly
);
1189 // Note: aCpyPam is invalid now
1191 SAL_INFO( "sw.docappend", "CopyRange Out: " << CNTNT_DOC( this ) );
1195 SwPaM
aPaM(aIndexBefore
.GetNode(), rInsPos
.GetNode());
1197 aPaM
.GetDoc().MakeUniqueNumRules(aPaM
);
1199 // Update the rsid of each pasted text node
1200 SwNodes
&rDestNodes
= GetNodes();
1201 SwNodeOffset
const nEndIdx
= aPaM
.End()->GetNodeIndex();
1203 for (SwNodeOffset nIdx
= aPaM
.Start()->GetNodeIndex();
1204 nIdx
<= nEndIdx
; ++nIdx
)
1206 SwTextNode
*const pTextNode
= rDestNodes
[nIdx
]->GetTextNode();
1208 UpdateParRsid( pTextNode
);
1213 SwNodeOffset
iDelNodes(0);
1214 SwNodeIndex
aDelIdx( aFixupIdx
);
1216 // we just need to set the new page description and reset numbering
1217 // this keeps all other settings as in the pasted document
1218 if ( nStartPageNumber
|| pTargetPageDesc
) {
1219 std::unique_ptr
<SfxPoolItem
> pNewItem
;
1220 SwTextNode
*aTextNd
= nullptr;
1221 SwFormat
*pFormat
= nullptr;
1223 // find the first node allowed to contain a RES_PAGEDESC
1227 SwNode
&node
= aFixupIdx
.GetNode();
1228 if ( node
.IsTextNode() ) {
1229 // every document contains at least one text node!
1230 aTextNd
= node
.GetTextNode();
1231 pNewItem
.reset(aTextNd
->GetAttr( RES_PAGEDESC
).Clone());
1234 else if ( node
.IsTableNode() ) {
1235 pFormat
= node
.GetTableNode()->GetTable().GetFrameFormat();
1236 pNewItem
.reset(pFormat
->GetFormatAttr( RES_PAGEDESC
).Clone());
1242 SAL_INFO( "sw.docappend", "Idx Del " << CNTNT_IDX( aDelIdx
) );
1243 SAL_INFO( "sw.docappend", "Idx Fix " << CNTNT_IDX( aFixupIdx
) );
1245 // just update the original instead of overwriting
1246 SwFormatPageDesc
*aDesc
= static_cast< SwFormatPageDesc
* >( pNewItem
.get() );
1248 if ( aDesc
->GetPageDesc() )
1249 SAL_INFO( "sw.docappend", "PD Update " << aDesc
->GetPageDesc()->GetName() );
1251 SAL_INFO( "sw.docappend", "PD New" );
1253 if ( nStartPageNumber
)
1254 aDesc
->SetNumOffset( nStartPageNumber
);
1255 if ( pTargetPageDesc
)
1256 aDesc
->RegisterToPageDesc( *pTargetPageDesc
);
1258 aTextNd
->SetAttr( *aDesc
);
1260 pFormat
->SetFormatAttr( *aDesc
);
1263 SAL_INFO( "sw.docappend", "Idx " << CNTNT_IDX( aDelIdx
) );
1268 if ( bDeletePrevious
)
1272 // delete leading empty page(s), e.g. from InsertPageBreak or
1273 // new SwDoc. this has to be done before copying the page bound
1274 // frames, otherwise the drawing layer gets confused.
1276 pTargetShell
->SttEndDoc( false );
1277 aDelIdx
-= iDelNodes
- 1;
1279 SAL_INFO( "sw.docappend", "iDelNodes: " << iDelNodes
1280 << " Idx: " << aDelIdx
.GetNode().GetIndex()
1281 << " EOE: " << GetNodes().GetEndOfExtras().GetIndex() );
1283 GetNodes().Delete( aDelIdx
, iDelNodes
);
1284 aStartAppendIndex
= aFixupIdx
;
1288 aStartAppendIndex
= aFixupIdx
;
1289 ++aStartAppendIndex
;
1293 // finally copy page bound frames
1294 for(sw::SpzFrameFormat
* pCpyFormat
: *rSource
.GetSpzFrameFormats())
1296 const SwFrameFormat
& rCpyFormat
= *pCpyFormat
;
1297 SwFormatAnchor
aAnchor( rCpyFormat
.GetAnchor() );
1298 if (RndStdIds::FLY_AT_PAGE
!= aAnchor
.GetAnchorId())
1300 SAL_INFO( "sw.docappend", "PaAn: " << aAnchor
.GetPageNum()
1301 << " => " << aAnchor
.GetPageNum() + pageOffset
);
1302 if ( pageOffset
!= 0 )
1303 aAnchor
.SetPageNum( aAnchor
.GetPageNum() + pageOffset
);
1304 getIDocumentLayoutAccess().CopyLayoutFormat( rCpyFormat
, aAnchor
, true, true );
1308 GetIDocumentUndoRedo().EndUndo( SwUndoId::INSGLOSSARY
, nullptr );
1310 getIDocumentFieldsAccess().UnlockExpFields();
1311 getIDocumentFieldsAccess().UpdateFields(false);
1314 pTargetShell
->EndAllAction();
1316 SAL_INFO( "sw.pageframe", "SwDoc::AppendDoc out)" );
1317 return aStartAppendIndex
;
1320 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */