ITEM: Refactor ItemType
[LibreOffice.git] / sw / source / core / doc / docfmt.cxx
blob4945c9f948e8368c7e14883df021095b678aa555
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 <libxml/xmlwriter.h>
21 #include <hintids.hxx>
22 #include <svl/itemiter.hxx>
23 #include <svl/numformat.hxx>
24 #include <editeng/tstpitem.hxx>
25 #include <editeng/lrspitem.hxx>
26 #include <editeng/formatbreakitem.hxx>
27 #include <editeng/rsiditem.hxx>
28 #include <officecfg/Office/Common.hxx>
29 #include <osl/diagnose.h>
30 #include <svl/zforlist.hxx>
31 #include <svx/DocumentColorHelper.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <unotools/configmgr.hxx>
34 #include <sal/log.hxx>
35 #include <com/sun/star/i18n/WordType.hpp>
36 #include <com/sun/star/i18n/XBreakIterator.hpp>
37 #include <fmtpdsc.hxx>
38 #include <fmthdft.hxx>
39 #include <fmtcntnt.hxx>
40 #include <doc.hxx>
41 #include <docfunc.hxx>
42 #include <drawdoc.hxx>
43 #include <MarkManager.hxx>
44 #include <IDocumentDrawModelAccess.hxx>
45 #include <IDocumentUndoRedo.hxx>
46 #include <DocumentContentOperationsManager.hxx>
47 #include <DocumentSettingManager.hxx>
48 #include <IDocumentFieldsAccess.hxx>
49 #include <IDocumentState.hxx>
50 #include <IDocumentLayoutAccess.hxx>
51 #include <IDocumentRedlineAccess.hxx>
52 #include <IDocumentStylePoolAccess.hxx>
53 #include <rootfrm.hxx>
54 #include <txtfrm.hxx>
55 #include <hints.hxx>
56 #include <ndtxt.hxx>
57 #include <pam.hxx>
58 #include <UndoCore.hxx>
59 #include <UndoAttribute.hxx>
60 #include <UndoInsert.hxx>
61 #include <pagedesc.hxx>
62 #include <rolbck.hxx>
63 #include <mvsave.hxx>
64 #include <txatbase.hxx>
65 #include <swtblfmt.hxx>
66 #include <charfmt.hxx>
67 #include <docary.hxx>
68 #include <paratr.hxx>
69 #include <redline.hxx>
70 #include <reffld.hxx>
71 #include <fmtinfmt.hxx>
72 #include <breakit.hxx>
73 #include <SwUndoFmt.hxx>
74 #include <UndoManager.hxx>
75 #include <swmodule.hxx>
76 #include <modcfg.hxx>
77 #include <frameformats.hxx>
78 #include <textboxhelper.hxx>
79 #include <textcontentcontrol.hxx>
80 #include <memory>
81 #include <algorithm>
82 #include <functional>
84 using namespace ::com::sun::star::i18n;
85 using namespace ::com::sun::star::uno;
88 * Internal functions
91 static void SetTextFormatCollNext( SwTextFormatColl* pTextColl, const SwTextFormatColl* pDel )
93 if ( &pTextColl->GetNextTextFormatColl() == pDel )
95 pTextColl->SetNextTextFormatColl( *pTextColl );
99 static bool lcl_RstAttr( SwNode* pNd, void* pArgs )
101 const sw::DocumentContentOperationsManager::ParaRstFormat* pPara = static_cast<sw::DocumentContentOperationsManager::ParaRstFormat*>(pArgs);
102 SwContentNode* pNode = pNd->GetContentNode();
103 if (pPara && pPara->pLayout && pPara->pLayout->HasMergedParas()
104 && pNode && pNode->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
106 return true;
108 if( pNode && pNode->HasSwAttrSet() )
110 const bool bLocked = pNode->IsModifyLocked();
111 pNode->LockModify();
113 SwDoc& rDoc = pNode->GetDoc();
115 // remove unused attribute RES_LR_SPACE
116 // add list attributes, except RES_PARATR_LIST_AUTOFMT
117 SfxItemSetFixed<
118 RES_PARATR_NUMRULE, RES_PARATR_NUMRULE,
119 RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_AUTOFMT - 1,
120 RES_PAGEDESC, RES_BREAK,
121 RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME> aSavedAttrsSet(rDoc.GetAttrPool());
122 const SfxItemSet* pAttrSetOfNode = pNode->GetpSwAttrSet();
124 std::vector<sal_uInt16> aClearWhichIds;
125 // restoring all paragraph list attributes
127 SfxItemSetFixed<RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_AUTOFMT - 1> aListAttrSet( rDoc.GetAttrPool() );
128 aListAttrSet.Set(*pAttrSetOfNode);
129 if ( aListAttrSet.Count() )
131 aSavedAttrsSet.Put(aListAttrSet);
132 SfxItemIter aIter( aListAttrSet );
133 const SfxPoolItem* pItem = aIter.GetCurItem();
134 while( pItem )
136 aClearWhichIds.push_back( pItem->Which() );
137 pItem = aIter.NextItem();
142 if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_PARATR_NUMRULE, false);
143 pItem && !pItem->GetValue().isEmpty())
145 aSavedAttrsSet.Put(*pItem);
146 aClearWhichIds.push_back(RES_PARATR_NUMRULE);
148 if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_PAGEDESC, false);
149 pItem && pItem->GetPageDesc())
151 aSavedAttrsSet.Put(*pItem);
152 aClearWhichIds.push_back(RES_PAGEDESC);
154 if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_BREAK, false);
155 pItem && pItem->GetBreak() != SvxBreak::NONE)
157 aSavedAttrsSet.Put(*pItem);
158 aClearWhichIds.push_back(RES_BREAK);
160 if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_FRMATR_STYLE_NAME, false);
161 pItem && !pItem->GetValue().isEmpty())
163 aSavedAttrsSet.Put(*pItem);
164 aClearWhichIds.push_back(RES_FRMATR_STYLE_NAME);
166 if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_FRMATR_CONDITIONAL_STYLE_NAME, false);
167 pItem && !pItem->GetValue().isEmpty())
169 aSavedAttrsSet.Put(*pItem);
170 aClearWhichIds.push_back(RES_FRMATR_CONDITIONAL_STYLE_NAME);
173 // do not clear items directly from item set and only clear to be kept
174 // attributes, if no deletion item set is found.
175 const bool bKeepAttributes =
176 !pPara || !pPara->pDelSet || pPara->pDelSet->Count() == 0;
177 if ( bKeepAttributes )
179 pNode->ResetAttr( aClearWhichIds );
182 if( !bLocked )
183 pNode->UnlockModify();
185 if( pPara )
187 SwRegHistory aRegH( pNode, *pNode, pPara->pHistory );
189 if( pPara->pDelSet && pPara->pDelSet->Count() )
191 OSL_ENSURE( !bKeepAttributes,
192 "<lcl_RstAttr(..)> - certain attributes are kept, but not needed." );
193 SfxItemIter aIter( *pPara->pDelSet );
194 for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
196 if ( ( pItem->Which() != RES_PAGEDESC &&
197 pItem->Which() != RES_BREAK &&
198 pItem->Which() != RES_FRMATR_STYLE_NAME &&
199 pItem->Which() != RES_FRMATR_CONDITIONAL_STYLE_NAME &&
200 pItem->Which() != RES_PARATR_NUMRULE ) ||
201 ( aSavedAttrsSet.GetItemState( pItem->Which(), false ) != SfxItemState::SET ) )
203 pNode->ResetAttr( pItem->Which() );
207 else if( pPara->bResetAll )
208 pNode->ResetAllAttr();
209 else
210 pNode->ResetAttr( RES_PARATR_BEGIN, POOLATTR_END - 1 );
212 else
213 pNode->ResetAllAttr();
215 // only restore saved attributes, if needed
216 if (bKeepAttributes && aSavedAttrsSet.Count())
218 pNode->LockModify();
220 pNode->SetAttr(aSavedAttrsSet);
222 if( !bLocked )
223 pNode->UnlockModify();
226 return true;
229 void SwDoc::RstTextAttrs(const SwPaM &rRg, bool bInclRefToxMark,
230 bool bExactRange, SwRootFrame const*const pLayout)
232 SwHistory* pHst = nullptr;
233 SwDataChanged aTmp( rRg );
234 if (GetIDocumentUndoRedo().DoesUndo())
236 std::unique_ptr<SwUndoResetAttr> pUndo(new SwUndoResetAttr( rRg, RES_CHRFMT ));
237 pHst = &pUndo->GetHistory();
238 GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
240 auto [pStart, pEnd] = rRg.StartEnd(); // SwPosition*
241 sw::DocumentContentOperationsManager::ParaRstFormat aPara(
242 pStart, pEnd, pHst, nullptr, pLayout );
243 aPara.bInclRefToxMark = bInclRefToxMark;
244 aPara.bExactRange = bExactRange;
245 GetNodes().ForEach( pStart->GetNodeIndex(), pEnd->GetNodeIndex()+1,
246 sw::DocumentContentOperationsManager::lcl_RstTextAttr, &aPara );
247 getIDocumentState().SetModified();
250 void SwDoc::ResetAttrs( const SwPaM &rRg,
251 bool bTextAttr,
252 const o3tl::sorted_vector<sal_uInt16> &rAttrs,
253 const bool bSendDataChangedEvents,
254 SwRootFrame const*const pLayout)
256 SwPaM* pPam = const_cast<SwPaM*>(&rRg);
257 std::optional<SwPaM> oExtraPaM;
258 if( !bTextAttr && !rAttrs.empty() && RES_TXTATR_END > *(rAttrs.begin()) )
259 bTextAttr = true;
261 if( !rRg.HasMark() )
263 SwTextNode* pTextNd = rRg.GetPoint()->GetNode().GetTextNode();
264 if( !pTextNd )
265 return ;
267 oExtraPaM.emplace( *rRg.GetPoint() );
268 pPam = &*oExtraPaM;
270 SwPosition& rSt = *pPam->GetPoint();
271 sal_Int32 nMkPos, nPtPos = rSt.GetContentIndex();
273 // Special case: if the Cursor is located within a URL attribute, we take over it's area
274 SwTextAttr const*const pURLAttr(
275 pTextNd->GetTextAttrAt(rSt.GetContentIndex(), RES_TXTATR_INETFMT));
276 if (pURLAttr && !pURLAttr->GetINetFormat().GetValue().isEmpty())
278 nMkPos = pURLAttr->GetStart();
279 nPtPos = *pURLAttr->End();
281 else
283 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
284 Boundary aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
285 pTextNd->GetText(), nPtPos,
286 g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
287 WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
288 true);
290 if( aBndry.startPos < nPtPos && nPtPos < aBndry.endPos )
292 nMkPos = aBndry.startPos;
293 nPtPos = aBndry.endPos;
295 else
297 nPtPos = nMkPos = rSt.GetContentIndex();
298 if( bTextAttr )
299 pTextNd->DontExpandFormat( nPtPos );
303 rSt.SetContent(nMkPos);
304 pPam->SetMark();
305 pPam->GetPoint()->SetContent(nPtPos);
308 // #i96644#
309 std::optional< SwDataChanged > oDataChanged;
310 if ( bSendDataChangedEvents )
312 oDataChanged.emplace( *pPam );
314 SwHistory* pHst = nullptr;
315 if (GetIDocumentUndoRedo().DoesUndo())
317 std::unique_ptr<SwUndoResetAttr> pUndo(new SwUndoResetAttr( rRg,
318 bTextAttr ? sal_uInt16(RES_CONDTXTFMTCOLL) : sal_uInt16(RES_TXTFMTCOLL) ));
319 if( !rAttrs.empty() )
321 pUndo->SetAttrs( o3tl::sorted_vector(rAttrs) );
323 pHst = &pUndo->GetHistory();
324 GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
327 auto [pStart, pEnd] = pPam->StartEnd(); // SwPosition*
328 sw::DocumentContentOperationsManager::ParaRstFormat aPara(
329 pStart, pEnd, pHst, nullptr, pLayout);
331 // mst: not including META here; it seems attrs with CH_TXTATR are omitted
332 SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
333 RES_TXTATR_INETFMT, RES_TXTATR_UNKNOWN_CONTAINER,
334 RES_PARATR_BEGIN, RES_FRMATR_END - 1,
335 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1>
336 aDelSet(GetAttrPool());
337 for( auto it = rAttrs.rbegin(); it != rAttrs.rend(); ++it )
339 if( POOLATTR_END > *it )
340 aDelSet.Put( *GetDfltAttr( *it ));
342 if( aDelSet.Count() )
343 aPara.pDelSet = &aDelSet;
345 bool bAdd = true;
346 SwNodeIndex aTmpStt( pStart->GetNode() );
347 SwNodeIndex aTmpEnd( pEnd->GetNode() );
348 if( pStart->GetContentIndex() ) // just one part
350 // set up a later, and all CharFormatAttr -> TextFormatAttr
351 SwTextNode* pTNd = aTmpStt.GetNode().GetTextNode();
352 if( pTNd && pTNd->HasSwAttrSet() && pTNd->GetpSwAttrSet()->Count() )
354 if (pHst)
356 SwRegHistory history(pTNd, *pTNd, pHst);
357 pTNd->FormatToTextAttr(pTNd);
359 else
361 pTNd->FormatToTextAttr(pTNd);
365 ++aTmpStt;
367 if (!pEnd->GetNode().IsContentNode()
368 || pEnd->GetContentIndex() == pEnd->GetNode().GetContentNode()->Len())
370 // set up a later, and all CharFormatAttr -> TextFormatAttr
371 ++aTmpEnd;
372 bAdd = false;
374 else if( pStart->GetNode() != pEnd->GetNode() || !pStart->GetContentIndex() )
376 SwTextNode* pTNd = aTmpEnd.GetNode().GetTextNode();
377 if( pTNd && pTNd->HasSwAttrSet() && pTNd->GetpSwAttrSet()->Count() )
379 if (pHst)
381 SwRegHistory history(pTNd, *pTNd, pHst);
382 pTNd->FormatToTextAttr(pTNd);
384 else
386 pTNd->FormatToTextAttr(pTNd);
391 if( aTmpStt < aTmpEnd )
392 GetNodes().ForEach( pStart->GetNode(), aTmpEnd.GetNode(), lcl_RstAttr, &aPara );
393 else if( !rRg.HasMark() )
395 aPara.bResetAll = false ;
396 ::lcl_RstAttr( &pStart->GetNode(), &aPara );
397 aPara.bResetAll = true ;
400 if( bTextAttr )
402 if( bAdd )
403 ++aTmpEnd;
404 GetNodes().ForEach( pStart->GetNode(), aTmpEnd.GetNode(), sw::DocumentContentOperationsManager::lcl_RstTextAttr, &aPara );
407 getIDocumentState().SetModified();
409 oDataChanged.reset(); //before delete pPam
412 /// Set the rsid of the next nLen symbols of rRg to the current session number
413 void SwDoc::UpdateRsid( const SwPaM &rRg, const sal_Int32 nLen )
415 if (!SwModule::get()->GetModuleConfig()->IsStoreRsid())
416 return;
418 SwTextNode *pTextNode = rRg.GetPoint()->GetNode().GetTextNode();
419 if (!pTextNode)
421 return;
423 const sal_Int32 nStart(rRg.GetPoint()->GetContentIndex() - nLen);
424 SvxRsidItem aRsid( mnRsid, RES_CHRATR_RSID );
426 SfxItemSetFixed<RES_CHRATR_RSID, RES_CHRATR_RSID> aSet(GetAttrPool());
427 aSet.Put(aRsid);
428 bool const bRet(pTextNode->SetAttr(aSet, nStart,
429 rRg.GetPoint()->GetContentIndex()));
431 if (bRet && GetIDocumentUndoRedo().DoesUndo())
433 SwUndo *const pLastUndo = GetUndoManager().GetLastUndo();
434 SwUndoInsert *const pUndoInsert(dynamic_cast<SwUndoInsert*>(pLastUndo));
435 // this function is called after Insert so expects to find SwUndoInsert
436 assert(pUndoInsert);
437 if (pUndoInsert)
439 pUndoInsert->SetWithRsid();
444 bool SwDoc::UpdateParRsid( SwTextNode *pTextNode, sal_uInt32 nVal )
446 if (!SwModule::get()->GetModuleConfig()->IsStoreRsid())
447 return false;
449 if (!pTextNode)
451 return false;
454 SvxRsidItem aRsid( nVal ? nVal : mnRsid, RES_PARATR_RSID );
455 return pTextNode->SetAttr( aRsid );
458 /// Set the attribute according to the stated format.
459 /// If Undo is enabled, the old values is added to the Undo history.
460 void SwDoc::SetAttr( const SfxPoolItem& rAttr, SwFormat& rFormat )
462 SfxItemSet aSet( GetAttrPool(), rAttr.Which(), rAttr.Which() );
463 aSet.Put( rAttr );
464 SetAttr( aSet, rFormat );
467 /// Set the attribute according to the stated format.
468 /// If Undo is enabled, the old values is added to the Undo history.
469 void SwDoc::SetAttr( const SfxItemSet& rSet, SwFormat& rFormat )
471 if (GetIDocumentUndoRedo().DoesUndo())
473 SwUndoFormatAttrHelper aTmp( rFormat );
474 rFormat.SetFormatAttr( rSet );
475 if ( aTmp.GetUndo() )
477 GetIDocumentUndoRedo().AppendUndo( aTmp.ReleaseUndo() );
479 else
481 GetIDocumentUndoRedo().ClearRedo();
484 else
486 rFormat.SetFormatAttr( rSet );
489 // If the format is a shape, and it has a textbox, sync.
490 auto pShapeFormat = dynamic_cast<SwFrameFormat*>(&rFormat);
491 if (pShapeFormat && SwTextBoxHelper::isTextBox(pShapeFormat, RES_DRAWFRMFMT))
493 if (auto pObj = pShapeFormat->FindRealSdrObject())
495 SwTextBoxHelper::syncFlyFrameAttr(*pShapeFormat, rSet, pObj);
496 SwTextBoxHelper::changeAnchor(pShapeFormat, pObj);
500 getIDocumentState().SetModified();
503 void SwDoc::ResetAttrAtFormat( const std::vector<sal_uInt16>& rIds,
504 SwFormat& rChangedFormat )
506 std::unique_ptr<SwUndo> pUndo;
507 if (GetIDocumentUndoRedo().DoesUndo())
508 pUndo.reset(new SwUndoFormatResetAttr( rChangedFormat, rIds ));
510 bool bAttrReset = false;
511 for (const auto& nWhichId : rIds)
512 bAttrReset = rChangedFormat.ResetFormatAttr(nWhichId) || bAttrReset;
514 if ( bAttrReset )
516 if ( pUndo )
518 GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
521 getIDocumentState().SetModified();
525 static bool lcl_SetNewDefTabStops( SwTwips nOldWidth, SwTwips nNewWidth,
526 SvxTabStopItem& rChgTabStop )
528 // Set the default values of all TabStops to the new value.
529 // Attention: we always work with the PoolAttribute here, so that
530 // we don't calculate the same value on the same TabStop (pooled!) for all sets.
531 // We send a FormatChg to modify.
533 sal_uInt16 nOldCnt = rChgTabStop.Count();
534 if( !nOldCnt || nOldWidth == nNewWidth )
535 return false;
537 // Find the default's beginning
538 sal_uInt16 n;
539 for( n = nOldCnt; n ; --n )
540 if( SvxTabAdjust::Default != rChgTabStop[n - 1].GetAdjustment() )
541 break;
542 ++n;
543 if( n < nOldCnt ) // delete the DefTabStops
544 rChgTabStop.Remove( n, nOldCnt - n );
545 return true;
548 /// Set the attribute as new default attribute in this document.
549 /// If Undo is enabled, the old value is added to the Undo history.
550 void SwDoc::SetDefault( const SfxPoolItem& rAttr )
552 SfxItemSet aSet( GetAttrPool(), rAttr.Which(), rAttr.Which() );
553 aSet.Put( rAttr );
554 SetDefault( aSet );
557 void SwDoc::SetDefault( const SfxItemSet& rSet )
559 if( !rSet.Count() )
560 return;
562 sw::BroadcastingModify aCallMod;
563 SwAttrSet aOld( GetAttrPool(), rSet.GetRanges() ),
564 aNew( GetAttrPool(), rSet.GetRanges() );
565 SfxItemIter aIter( rSet );
566 const SfxPoolItem* pItem = aIter.GetCurItem();
567 SfxItemPool* pSdrPool = GetAttrPool().GetSecondaryPool();
570 bool bCheckSdrDflt = false;
571 const sal_uInt16 nWhich = pItem->Which();
572 aOld.Put( GetAttrPool().GetUserOrPoolDefaultItem( nWhich ) );
573 GetAttrPool().SetUserDefaultItem( *pItem );
574 aNew.Put( GetAttrPool().GetUserOrPoolDefaultItem( nWhich ) );
576 if (isCHRATR(nWhich) || isTXTATR(nWhich))
578 aCallMod.Add(*mpDfltTextFormatColl);
579 aCallMod.Add(*mpDfltCharFormat);
580 bCheckSdrDflt = nullptr != pSdrPool;
582 else if ( isPARATR(nWhich) ||
583 isPARATR_LIST(nWhich) )
585 aCallMod.Add(*mpDfltTextFormatColl);
586 bCheckSdrDflt = nullptr != pSdrPool;
588 else if (isGRFATR(nWhich))
590 aCallMod.Add(*mpDfltGrfFormatColl);
592 else if (isFRMATR(nWhich) || isDrawingLayerAttribute(nWhich) )
594 aCallMod.Add(*mpDfltGrfFormatColl);
595 aCallMod.Add(*mpDfltTextFormatColl);
596 aCallMod.Add(*mpDfltFrameFormat);
598 else if (isBOXATR(nWhich))
600 aCallMod.Add(*mpDfltFrameFormat);
603 // also copy the defaults
604 if( bCheckSdrDflt )
606 sal_uInt16 nSlotId = GetAttrPool().GetSlotId( nWhich );
607 if( 0 != nSlotId && nSlotId != nWhich )
609 sal_uInt16 nEdtWhich = pSdrPool->GetWhichIDFromSlotID( nSlotId );
610 if( 0 != nEdtWhich && nSlotId != nEdtWhich )
612 std::unique_ptr<SfxPoolItem> pCpy(pItem->Clone());
613 pCpy->SetWhich( nEdtWhich );
614 pSdrPool->SetUserDefaultItem( *pCpy );
619 pItem = aIter.NextItem();
620 } while (pItem);
622 if( aNew.Count() && aCallMod.HasWriterListeners() )
624 if (GetIDocumentUndoRedo().DoesUndo())
626 GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDefaultAttr>( aOld, *this ) );
629 const SvxTabStopItem* pTmpItem = aNew.GetItemIfSet( RES_PARATR_TABSTOP, false );
630 if( pTmpItem && pTmpItem->Count() )
632 // Set the default values of all TabStops to the new value.
633 // Attention: we always work with the PoolAttribute here, so that
634 // we don't calculate the same value on the same TabStop (pooled!) for all sets.
635 // We send a FormatChg to modify.
636 SwTwips nNewWidth = (*pTmpItem)[ 0 ].GetTabPos(),
637 nOldWidth = aOld.Get(RES_PARATR_TABSTOP)[ 0 ].GetTabPos();
639 bool bChg = false;
640 ForEachParaAtrTabStopItem([&bChg, &nOldWidth, &nNewWidth](const SvxTabStopItem& rTabStopItem) -> bool {
641 // pItem2 and thus pTabStopItem is a evtl. shared & RefCounted
642 // Item and *should* not be changed that way. lcl_SetNewDefTabStops
643 // seems to change pTabStopItem (!). This may need to be changed
644 // to use iterateItemSurrogates and a defined write cycle.
645 bChg |= lcl_SetNewDefTabStops( nOldWidth, nNewWidth,
646 const_cast<SvxTabStopItem&>(rTabStopItem) );
647 return true;
650 aNew.ClearItem( RES_PARATR_TABSTOP );
651 aOld.ClearItem( RES_PARATR_TABSTOP );
652 if( bChg )
654 SwFormatChangeHint aChgFormat( mpDfltCharFormat.get(), mpDfltCharFormat.get() );
655 // notify the frames
656 aCallMod.CallSwClientNotify(aChgFormat);
661 if( aNew.Count() && aCallMod.HasWriterListeners() )
663 SwAttrSetChg aChgOld( aOld, aOld );
664 SwAttrSetChg aChgNew( aNew, aNew );
665 aCallMod.CallSwClientNotify(sw::LegacyModifyHint( &aChgOld, &aChgNew )); // all changed are sent
668 // remove the default formats from the object again
669 SwIterator<SwClient, sw::BroadcastingModify> aClientIter(aCallMod);
670 for(SwClient* pClient = aClientIter.First(); pClient; pClient = aClientIter.Next())
671 aCallMod.Remove(*pClient);
673 getIDocumentState().SetModified();
676 /// Get the default attribute in this document
677 const SfxPoolItem& SwDoc::GetDefault( sal_uInt16 nFormatHint ) const
679 return GetAttrPool().GetUserOrPoolDefaultItem( nFormatHint );
682 /// Delete the formats
683 void SwDoc::DelCharFormat(size_t nFormat, bool bBroadcast)
685 SwCharFormat * pDel = (*mpCharFormatTable)[nFormat];
687 if (bBroadcast)
688 BroadcastStyleOperation(pDel->GetName(), SfxStyleFamily::Char,
689 SfxHintId::StyleSheetErased);
691 if (GetIDocumentUndoRedo().DoesUndo())
693 GetIDocumentUndoRedo().AppendUndo(
694 std::make_unique<SwUndoCharFormatDelete>(pDel, *this));
697 // tdf#140061 keep SwCharFormat instances alive while SwDoc is alive
698 mpCharFormatDeletionTable->insert(pDel);
699 mpCharFormatTable->erase(mpCharFormatTable->begin() + nFormat);
701 getIDocumentState().SetModified();
704 void SwDoc::DelCharFormat( SwCharFormat const *pFormat, bool bBroadcast )
706 size_t nFormat = mpCharFormatTable->GetPos( pFormat );
707 OSL_ENSURE( SIZE_MAX != nFormat, "Format not found," );
708 DelCharFormat( nFormat, bBroadcast );
711 void SwDoc::DelFrameFormat( SwFrameFormat *pFormat, bool bBroadcast )
713 assert(pFormat && "ContainsFormat will always deref pFormat");
714 if( dynamic_cast<const SwTableBoxFormat*>( pFormat) != nullptr || dynamic_cast<const SwTableLineFormat*>( pFormat) != nullptr )
716 OSL_ENSURE( false, "Format is not in the DocArray any more, "
717 "so it can be deleted with delete" );
718 delete pFormat;
720 else
722 // The format has to be in the one or the other, we'll see in which one.
723 if (mpFrameFormatTable->ContainsFormat(pFormat))
725 if (bBroadcast)
726 BroadcastStyleOperation(pFormat->GetName(),
727 SfxStyleFamily::Frame,
728 SfxHintId::StyleSheetErased);
730 if (GetIDocumentUndoRedo().DoesUndo())
732 GetIDocumentUndoRedo().AppendUndo(
733 std::make_unique<SwUndoFrameFormatDelete>(pFormat, *this));
736 mpFrameFormatTable->erase( pFormat );
737 delete pFormat;
739 else
741 auto pSpz = static_cast<sw::SpzFrameFormat*>(pFormat);
742 if(GetSpzFrameFormats()->ContainsFormat(pSpz))
744 GetSpzFrameFormats()->erase(pSpz);
745 delete pSpz;
747 else
748 SAL_WARN("sw", "FrameFormat not found.");
753 void SwDoc::DelTableFrameFormat( SwTableFormat *pFormat )
755 auto it = mpTableFrameFormatTable->find( pFormat );
756 OSL_ENSURE( it != mpTableFrameFormatTable->end(), "Format not found," );
757 mpTableFrameFormatTable->erase( it );
758 delete pFormat;
761 SwFrameFormat* SwDoc::FindFrameFormatByName( const OUString& rName ) const
763 return static_cast<SwFrameFormat*>(mpFrameFormatTable->FindFormatByName(rName));
766 /// Create the formats
767 SwFlyFrameFormat *SwDoc::MakeFlyFrameFormat( const OUString &rFormatName,
768 SwFrameFormat *pDerivedFrom )
770 SwFlyFrameFormat *pFormat = new SwFlyFrameFormat( GetAttrPool(), rFormatName, pDerivedFrom );
771 GetSpzFrameFormats()->push_back(pFormat);
772 getIDocumentState().SetModified();
773 return pFormat;
776 SwDrawFrameFormat *SwDoc::MakeDrawFrameFormat( const OUString &rFormatName,
777 SwFrameFormat *pDerivedFrom )
779 SwDrawFrameFormat *pFormat = new SwDrawFrameFormat( GetAttrPool(), rFormatName, pDerivedFrom);
780 GetSpzFrameFormats()->push_back(pFormat);
781 getIDocumentState().SetModified();
782 return pFormat;
785 size_t SwDoc::GetTableFrameFormatCount(bool bUsed) const
787 if (!bUsed)
788 return mpTableFrameFormatTable->size();
789 return std::count_if(mpTableFrameFormatTable->begin(), mpTableFrameFormatTable->end(),
790 std::mem_fn(&SwFormat::IsUsed));
793 SwTableFormat& SwDoc::GetTableFrameFormat(size_t nFormat, bool bUsed) const
795 if (!bUsed)
796 return *const_cast<SwTableFormat*>((*mpTableFrameFormatTable)[nFormat]);
797 for(SwTableFormat* pFormat: *mpTableFrameFormatTable)
799 if(!pFormat->IsUsed())
800 continue;
801 if(nFormat)
802 --nFormat;
803 else
804 return *pFormat;
806 throw std::out_of_range("Format index out of range.");
809 SwTableFormat* SwDoc::MakeTableFrameFormat( const OUString &rFormatName,
810 SwFrameFormat *pDerivedFrom )
812 SwTableFormat* pFormat = new SwTableFormat( GetAttrPool(), rFormatName, pDerivedFrom );
813 mpTableFrameFormatTable->push_back( pFormat );
814 getIDocumentState().SetModified();
816 return pFormat;
819 SwFrameFormat *SwDoc::MakeFrameFormat(const OUString &rFormatName,
820 SwFrameFormat *pDerivedFrom,
821 bool bAuto)
823 SwFrameFormat *pFormat = new SwFrameFormat( GetAttrPool(), rFormatName, pDerivedFrom );
825 pFormat->SetAuto(bAuto);
826 mpFrameFormatTable->push_back( pFormat );
827 getIDocumentState().SetModified();
829 if (GetIDocumentUndoRedo().DoesUndo())
831 GetIDocumentUndoRedo().AppendUndo(
832 std::make_unique<SwUndoFrameFormatCreate>(pFormat, pDerivedFrom, *this));
835 return pFormat;
838 SwFormat *SwDoc::MakeFrameFormat_(const OUString &rFormatName,
839 SwFormat *pDerivedFrom,
840 bool bAuto)
842 SwFrameFormat *pFrameFormat = dynamic_cast<SwFrameFormat*>(pDerivedFrom);
843 pFrameFormat = MakeFrameFormat( rFormatName, pFrameFormat, bAuto );
844 return pFrameFormat;
847 SwCharFormat *SwDoc::MakeCharFormat( const OUString &rFormatName,
848 SwCharFormat *pDerivedFrom )
850 SwCharFormat *pFormat = new SwCharFormat( GetAttrPool(), rFormatName, pDerivedFrom );
851 mpCharFormatTable->insert( pFormat );
852 pFormat->SetAuto(false);
853 getIDocumentState().SetModified();
855 if (GetIDocumentUndoRedo().DoesUndo())
857 GetIDocumentUndoRedo().AppendUndo(
858 std::make_unique<SwUndoCharFormatCreate>(pFormat, pDerivedFrom, *this));
861 return pFormat;
864 SwFormat *SwDoc::MakeCharFormat_(const OUString &rFormatName,
865 SwFormat *pDerivedFrom,
866 bool /*bAuto*/)
868 SwCharFormat *pCharFormat = dynamic_cast<SwCharFormat*>(pDerivedFrom);
869 pCharFormat = MakeCharFormat( rFormatName, pCharFormat );
870 return pCharFormat;
873 /// Create the FormatCollections
874 SwTextFormatColl* SwDoc::MakeTextFormatColl( const OUString &rFormatName,
875 SwTextFormatColl *pDerivedFrom)
877 SwTextFormatColl *pFormatColl = new SwTextFormatColl( GetAttrPool(), rFormatName,
878 pDerivedFrom );
879 mpTextFormatCollTable->push_back(pFormatColl);
880 pFormatColl->SetAuto(false);
881 getIDocumentState().SetModified();
883 if (GetIDocumentUndoRedo().DoesUndo())
885 GetIDocumentUndoRedo().AppendUndo(
886 std::make_unique<SwUndoTextFormatCollCreate>(pFormatColl, pDerivedFrom,
887 *this));
890 return pFormatColl;
893 SwFormat *SwDoc::MakeTextFormatColl_(const OUString &rFormatName,
894 SwFormat *pDerivedFrom,
895 bool /*bAuto*/)
897 SwTextFormatColl *pTextFormatColl = dynamic_cast<SwTextFormatColl*>(pDerivedFrom);
898 pTextFormatColl = MakeTextFormatColl( rFormatName, pTextFormatColl );
899 return pTextFormatColl;
902 SwConditionTextFormatColl* SwDoc::MakeCondTextFormatColl( const OUString &rFormatName,
903 SwTextFormatColl *pDerivedFrom)
905 SwConditionTextFormatColl*pFormatColl = new SwConditionTextFormatColl( GetAttrPool(),
906 rFormatName, pDerivedFrom );
907 mpTextFormatCollTable->push_back(pFormatColl);
908 pFormatColl->SetAuto(false);
909 getIDocumentState().SetModified();
911 if (GetIDocumentUndoRedo().DoesUndo())
913 GetIDocumentUndoRedo().AppendUndo(
914 std::make_unique<SwUndoCondTextFormatCollCreate>(pFormatColl, pDerivedFrom,
915 *this));
918 return pFormatColl;
921 // GRF
922 SwGrfFormatColl* SwDoc::MakeGrfFormatColl( const OUString &rFormatName,
923 SwGrfFormatColl *pDerivedFrom )
925 SwGrfFormatColl *pFormatColl = new SwGrfFormatColl( GetAttrPool(), rFormatName,
926 pDerivedFrom );
927 mpGrfFormatCollTable->push_back( pFormatColl );
928 pFormatColl->SetAuto(false);
929 getIDocumentState().SetModified();
930 return pFormatColl;
933 void SwDoc::DelTextFormatColl(size_t nFormatColl, bool bBroadcast)
935 OSL_ENSURE( nFormatColl, "Remove of Coll 0." );
937 // Who has the to-be-deleted as their Next?
938 SwTextFormatColl *pDel = (*mpTextFormatCollTable)[nFormatColl];
939 if( mpDfltTextFormatColl.get() == pDel )
940 return; // never delete default!
942 if (bBroadcast)
943 BroadcastStyleOperation(pDel->GetName(), SfxStyleFamily::Para,
944 SfxHintId::StyleSheetErased);
946 if (GetIDocumentUndoRedo().DoesUndo())
948 std::unique_ptr<SwUndoTextFormatCollDelete> pUndo;
949 if (RES_CONDTXTFMTCOLL == pDel->Which())
951 pUndo.reset(new SwUndoCondTextFormatCollDelete(pDel, *this));
953 else
955 pUndo.reset(new SwUndoTextFormatCollDelete(pDel, *this));
958 GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
961 // Remove the FormatColl
962 mpTextFormatCollTable->erase(mpTextFormatCollTable->begin() + nFormatColl);
963 // Correct next
964 for( SwTextFormatColls::const_iterator it = mpTextFormatCollTable->begin() + 1; it != mpTextFormatCollTable->end(); ++it )
965 SetTextFormatCollNext( *it, pDel );
966 delete pDel;
967 getIDocumentState().SetModified();
970 void SwDoc::DelTextFormatColl( SwTextFormatColl const *pColl, bool bBroadcast )
972 size_t nFormat = mpTextFormatCollTable->GetPos( pColl );
973 OSL_ENSURE( SIZE_MAX != nFormat, "Collection not found," );
974 DelTextFormatColl( nFormat, bBroadcast );
977 static bool lcl_SetTextFormatColl( SwNode* pNode, void* pArgs )
979 SwContentNode* pCNd = pNode->GetTextNode();
981 if( pCNd == nullptr)
982 return true;
984 sw::DocumentContentOperationsManager::ParaRstFormat* pPara = static_cast<sw::DocumentContentOperationsManager::ParaRstFormat*>(pArgs);
986 if (pPara->pLayout && pPara->pLayout->HasMergedParas())
988 if (pCNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
990 return true;
992 if (pCNd->IsTextNode())
994 pCNd = sw::GetParaPropsNode(*pPara->pLayout, *pCNd);
998 SwTextFormatColl* pFormat = pPara->pFormatColl;
999 if ( pPara->bReset )
1001 if (pCNd->IsTextNode() && pPara->bResetAllCharAttrs && pPara->pDelSet && pPara->pDelSet->Count())
1003 //TODO: copy to select the text node completely
1004 SwPosition aStart(*pCNd, 0);
1005 SwPosition aEnd(*pCNd, pCNd->GetTextNode()->GetText().getLength());
1006 sw::DocumentContentOperationsManager::ParaRstFormat aPara(
1007 &aStart, &aEnd, pPara->pHistory, nullptr, pPara->pLayout);
1008 aPara.pFormatColl = pPara->pFormatColl;
1009 aPara.bReset = pPara->bReset;
1010 // #i62675#
1011 aPara.bResetListAttrs = pPara->bResetListAttrs;
1012 aPara.bResetAllCharAttrs = pPara->bResetAllCharAttrs;
1013 aPara.pDelSet = pPara->pDelSet;
1014 sw::DocumentContentOperationsManager::lcl_RstTextAttr(pCNd, &aPara);
1017 lcl_RstAttr(pCNd, pPara);
1019 // #i62675# check, if paragraph style has changed
1020 if ( pPara->bResetListAttrs &&
1021 (pPara->bResetAllCharAttrs || pFormat != pCNd->GetFormatColl())
1022 && pCNd->GetTextNode()->IsInList() )
1024 // Check, if the list style of the paragraph will change.
1025 bool bChangeOfListStyleAtParagraph( true );
1026 SwTextNode& rTNd(*pCNd->GetTextNode());
1028 SwNumRule* pNumRuleAtParagraph(rTNd.GetNumRule());
1029 if ( pNumRuleAtParagraph )
1031 const SwNumRuleItem& rNumRuleItemAtParagraphStyle =
1032 rTNd.GetTextColl()->GetNumRule();
1033 if ( rNumRuleItemAtParagraphStyle.GetValue() ==
1034 pNumRuleAtParagraph->GetName() )
1036 bChangeOfListStyleAtParagraph = false;
1041 std::optional<SwRegHistory> oRegH;
1042 if (pPara->pHistory)
1043 oRegH.emplace(&rTNd, rTNd, pPara->pHistory);
1045 if ( bChangeOfListStyleAtParagraph )
1047 pCNd->ResetAttr( RES_PARATR_NUMRULE );
1049 // reset all list attributes
1050 pCNd->ResetAttr( RES_PARATR_LIST_LEVEL );
1051 pCNd->ResetAttr( RES_PARATR_LIST_ISRESTART );
1052 pCNd->ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
1053 pCNd->ResetAttr( RES_PARATR_LIST_ISCOUNTED );
1054 pCNd->ResetAttr( RES_PARATR_LIST_ID );
1056 else
1058 // The List Level must be applied as direct formatting. The spec says:
1059 // 19.495 The style:list-level attribute specifies the list level value
1060 // of a list style that may be applied to any paragraph style.
1061 // It does not directly specify the paragraph's list level value,
1062 // but consumers can change the paragraph's list level value to the specified value
1063 // when the paragraph style is applied.
1064 pCNd->SetAttr(pFormat->GetFormatAttr(RES_PARATR_LIST_LEVEL));
1069 // add to History so that old data is saved, if necessary
1070 if( pPara->pHistory )
1071 pPara->pHistory->AddColl(pCNd->GetFormatColl(), pCNd->GetIndex(),
1072 SwNodeType::Text );
1074 pCNd->ChgFormatColl( pFormat );
1076 pPara->nWhich++;
1078 return true;
1081 bool SwDoc::SetTextFormatColl(const SwPaM &rRg,
1082 SwTextFormatColl *pFormat,
1083 const bool bReset,
1084 const bool bResetListAttrs,
1085 const bool bResetAllCharAttrs,
1086 SwRootFrame const*const pLayout)
1088 SwDataChanged aTmp( rRg );
1089 auto [pStart, pEnd] = rRg.StartEnd(); // SwPosition*
1090 SwHistory* pHst = nullptr;
1091 bool bRet = true;
1093 if (GetIDocumentUndoRedo().DoesUndo())
1095 std::unique_ptr<SwUndoFormatColl> pUndo(new SwUndoFormatColl( rRg, pFormat,
1096 bReset,
1097 bResetListAttrs ));
1098 pHst = pUndo->GetHistory();
1099 GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
1102 std::shared_ptr<SfxItemSet> pDelSet;
1103 sw::DocumentContentOperationsManager::ParaRstFormat aPara(
1104 pStart, pEnd, pHst, nullptr, pLayout);
1105 aPara.pFormatColl = pFormat;
1106 aPara.bReset = bReset;
1107 // #i62675#
1108 aPara.bResetListAttrs = bResetListAttrs;
1109 aPara.bResetAllCharAttrs = bResetAllCharAttrs;
1110 if (bResetAllCharAttrs)
1112 o3tl::sorted_vector<sal_uInt16> aAttribs;
1113 pDelSet = sw::DocumentContentOperationsManager::lcl_createDelSet(*this);
1114 aPara.pDelSet = pDelSet.get();
1117 GetNodes().ForEach( pStart->GetNodeIndex(), pEnd->GetNodeIndex()+1,
1118 lcl_SetTextFormatColl, &aPara );
1119 if( !aPara.nWhich )
1120 bRet = false; // didn't find a valid Node
1122 if (bRet)
1124 getIDocumentState().SetModified();
1127 return bRet;
1130 /// Copy the formats to itself
1131 SwFormat* SwDoc::CopyFormat( const SwFormat& rFormat,
1132 const SwFormatsBase& rFormatArr,
1133 FNCopyFormat fnCopyFormat, const SwFormat& rDfltFormat )
1135 // It's no autoformat, default format or collection format,
1136 // then search for it.
1137 if( !rFormat.IsAuto() || !rFormat.GetRegisteredIn() )
1138 for( size_t n = 0; n < rFormatArr.GetFormatCount(); ++n )
1140 // Does the Doc already contain the template?
1141 if( rFormatArr.GetFormat(n)->GetName()==rFormat.GetName() )
1142 return rFormatArr.GetFormat(n);
1145 // Search for the "parent" first
1146 SwFormat* pParent = const_cast<SwFormat*>(&rDfltFormat);
1147 if( rFormat.DerivedFrom() && pParent != rFormat.DerivedFrom() )
1148 pParent = CopyFormat( *rFormat.DerivedFrom(), rFormatArr,
1149 fnCopyFormat, rDfltFormat );
1151 // Create the format and copy the attributes
1152 // #i40550#
1153 SwFormat* pNewFormat = (this->*fnCopyFormat)( rFormat.GetName(), pParent, true );
1154 pNewFormat->SetAuto( rFormat.IsAuto() );
1155 pNewFormat->CopyAttrs( rFormat ); // copy the attributes
1157 pNewFormat->SetPoolFormatId( rFormat.GetPoolFormatId() );
1158 pNewFormat->SetPoolHelpId( rFormat.GetPoolHelpId() );
1160 // Always set the HelpFile Id to default!
1161 pNewFormat->SetPoolHlpFileId( UCHAR_MAX );
1163 return pNewFormat;
1166 /// copy the frame format
1167 SwFrameFormat* SwDoc::CopyFrameFormat( const SwFrameFormat& rFormat )
1169 return static_cast<SwFrameFormat*>(CopyFormat( rFormat, *GetFrameFormats(), &SwDoc::MakeFrameFormat_,
1170 *GetDfltFrameFormat() ));
1173 /// copy the char format
1174 SwCharFormat* SwDoc::CopyCharFormat( const SwCharFormat& rFormat )
1176 return static_cast<SwCharFormat*>(CopyFormat( rFormat, *GetCharFormats(),
1177 &SwDoc::MakeCharFormat_,
1178 *GetDfltCharFormat() ));
1181 /// copy TextNodes
1182 SwTextFormatColl* SwDoc::CopyTextColl( const SwTextFormatColl& rColl )
1184 SwTextFormatColl* pNewColl = FindTextFormatCollByName( rColl.GetName() );
1185 if( pNewColl )
1186 return pNewColl;
1188 // search for the "parent" first
1189 SwTextFormatColl* pParent = mpDfltTextFormatColl.get();
1190 if( pParent != rColl.DerivedFrom() )
1191 pParent = CopyTextColl( *static_cast<SwTextFormatColl*>(rColl.DerivedFrom()) );
1193 if( RES_CONDTXTFMTCOLL == rColl.Which() )
1195 pNewColl = new SwConditionTextFormatColl( GetAttrPool(), rColl.GetName(),
1196 pParent);
1197 mpTextFormatCollTable->push_back( pNewColl );
1198 pNewColl->SetAuto(false);
1199 getIDocumentState().SetModified();
1201 // copy the conditions
1202 static_cast<SwConditionTextFormatColl*>(pNewColl)->SetConditions(
1203 static_cast<const SwConditionTextFormatColl&>(rColl).GetCondColls() );
1205 else
1206 pNewColl = MakeTextFormatColl( rColl.GetName(), pParent );
1208 // copy the auto formats or the attributes
1209 pNewColl->CopyAttrs( rColl );
1211 if(rColl.IsAssignedToListLevelOfOutlineStyle())
1212 pNewColl->AssignToListLevelOfOutlineStyle(rColl.GetAssignedOutlineStyleLevel());
1213 pNewColl->SetPoolFormatId( rColl.GetPoolFormatId() );
1214 pNewColl->SetPoolHelpId( rColl.GetPoolHelpId() );
1216 // Always set the HelpFile Id to default!
1217 pNewColl->SetPoolHlpFileId( UCHAR_MAX );
1219 if( &rColl.GetNextTextFormatColl() != &rColl )
1220 pNewColl->SetNextTextFormatColl( *CopyTextColl( rColl.GetNextTextFormatColl() ));
1222 // create the NumRule if necessary
1223 if( this != rColl.GetDoc() )
1225 const SwNumRuleItem* pItem = pNewColl->GetItemIfSet( RES_PARATR_NUMRULE,
1226 false );
1227 if( pItem )
1229 const OUString& rName = pItem->GetValue();
1230 if( !rName.isEmpty() )
1232 const SwNumRule* pRule = rColl.GetDoc()->FindNumRulePtr( rName );
1233 if( pRule && !pRule->IsAutoRule() )
1235 SwNumRule* pDestRule = FindNumRulePtr( rName );
1236 if( pDestRule )
1237 pDestRule->Invalidate();
1238 else
1239 MakeNumRule( rName, pRule );
1244 return pNewColl;
1247 /// copy the graphic nodes
1248 SwGrfFormatColl* SwDoc::CopyGrfColl( const SwGrfFormatColl& rColl )
1250 SwGrfFormatColl* pNewColl = mpGrfFormatCollTable->FindFormatByName( rColl.GetName() );
1251 if( pNewColl )
1252 return pNewColl;
1254 // Search for the "parent" first
1255 SwGrfFormatColl* pParent = mpDfltGrfFormatColl.get();
1256 if( pParent != rColl.DerivedFrom() )
1257 pParent = CopyGrfColl( *static_cast<SwGrfFormatColl*>(rColl.DerivedFrom()) );
1259 // if not, copy them
1260 pNewColl = MakeGrfFormatColl( rColl.GetName(), pParent );
1262 // copy the attributes
1263 pNewColl->CopyAttrs( rColl );
1265 pNewColl->SetPoolFormatId( rColl.GetPoolFormatId() );
1266 pNewColl->SetPoolHelpId( rColl.GetPoolHelpId() );
1268 // Always set the HelpFile Id to default!
1269 pNewColl->SetPoolHlpFileId( UCHAR_MAX );
1271 return pNewColl;
1274 void SwDoc::CopyFormatArr( const SwFormatsBase& rSourceArr,
1275 SwFormatsBase const & rDestArr,
1276 FNCopyFormat fnCopyFormat,
1277 SwFormat& rDfltFormat )
1279 SwFormat* pSrc, *pDest;
1281 // 1st step: Create all formats (skip the 0th - it's the default one)
1282 for( size_t nSrc = rSourceArr.GetFormatCount(); nSrc > 1; )
1284 pSrc = rSourceArr.GetFormat( --nSrc );
1285 if( pSrc->IsDefault() || pSrc->IsAuto() )
1286 continue;
1288 if( nullptr == rDestArr.FindFormatByName( pSrc->GetName() ) )
1290 if( RES_CONDTXTFMTCOLL == pSrc->Which() )
1291 MakeCondTextFormatColl( pSrc->GetName(), static_cast<SwTextFormatColl*>(&rDfltFormat) );
1292 else
1293 // #i40550#
1294 (this->*fnCopyFormat)( pSrc->GetName(), &rDfltFormat, true );
1298 // 2nd step: Copy all attributes, set the right parents
1299 for( size_t nSrc = rSourceArr.GetFormatCount(); nSrc > 1; )
1301 pSrc = rSourceArr.GetFormat( --nSrc );
1302 if( pSrc->IsDefault() || pSrc->IsAuto() )
1303 continue;
1305 pDest = rDestArr.FindFormatByName( pSrc->GetName() );
1306 pDest->SetAuto(false);
1307 pDest->DelDiffs( *pSrc );
1309 // #i94285#: existing <SwFormatPageDesc> instance, before copying attributes
1310 const SwFormatPageDesc* pItem;
1311 if( &GetAttrPool() != pSrc->GetAttrSet().GetPool()
1312 && (pItem = pSrc->GetAttrSet().GetItemIfSet( RES_PAGEDESC, false ))
1313 && pItem->GetPageDesc() )
1315 SwFormatPageDesc aPageDesc( *pItem );
1316 const OUString& rNm = aPageDesc.GetPageDesc()->GetName();
1317 SwPageDesc* pPageDesc = FindPageDesc( rNm );
1318 if( !pPageDesc )
1320 pPageDesc = MakePageDesc(rNm);
1322 aPageDesc.RegisterToPageDesc( *pPageDesc );
1323 SwAttrSet aTmpAttrSet( pSrc->GetAttrSet() );
1324 aTmpAttrSet.Put( aPageDesc );
1325 pDest->SetFormatAttr( aTmpAttrSet );
1327 else
1329 pDest->SetFormatAttr( pSrc->GetAttrSet() );
1332 pDest->SetPoolFormatId( pSrc->GetPoolFormatId() );
1333 pDest->SetPoolHelpId( pSrc->GetPoolHelpId() );
1335 // Always set the HelpFile Id to default!
1336 pDest->SetPoolHlpFileId( UCHAR_MAX );
1338 if( pSrc->DerivedFrom() )
1339 pDest->SetDerivedFrom( rDestArr.FindFormatByName(
1340 pSrc->DerivedFrom()->GetName() ) );
1341 if( RES_TXTFMTCOLL == pSrc->Which() ||
1342 RES_CONDTXTFMTCOLL == pSrc->Which() )
1344 SwTextFormatColl* pSrcColl = static_cast<SwTextFormatColl*>(pSrc),
1345 * pDstColl = static_cast<SwTextFormatColl*>(pDest);
1346 if( &pSrcColl->GetNextTextFormatColl() != pSrcColl )
1347 pDstColl->SetNextTextFormatColl(
1348 *static_cast<SwTextFormatColl*>(rDestArr.FindFormatByName( pSrcColl->GetNextTextFormatColl().GetName() )) );
1350 if(pSrcColl->IsAssignedToListLevelOfOutlineStyle())
1351 pDstColl->AssignToListLevelOfOutlineStyle(pSrcColl->GetAssignedOutlineStyleLevel());
1353 if( RES_CONDTXTFMTCOLL == pSrc->Which() )
1355 if (pDstColl->Which() != RES_CONDTXTFMTCOLL)
1357 // Target already had a style with a matching name, but it's not a conditional
1358 // style, then don't copy the conditions.
1359 continue;
1362 // Copy the conditions, but delete the old ones first!
1363 static_cast<SwConditionTextFormatColl*>(pDstColl)->SetConditions(
1364 static_cast<SwConditionTextFormatColl*>(pSrc)->GetCondColls() );
1370 void SwDoc::CopyPageDescHeaderFooterImpl( bool bCpyHeader,
1371 const SwFrameFormat& rSrcFormat, SwFrameFormat& rDestFormat )
1373 // Treat the header and footer attributes in the right way:
1374 // Copy content nodes across documents!
1375 sal_uInt16 nAttr = bCpyHeader ? sal_uInt16(RES_HEADER) : sal_uInt16(RES_FOOTER);
1376 const SfxPoolItem* pItem;
1377 if( SfxItemState::SET != rSrcFormat.GetAttrSet().GetItemState( nAttr, false, &pItem ))
1378 return ;
1380 // The header only contains the reference to the format from the other document!
1381 std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone());
1383 SwFrameFormat* pOldFormat;
1384 if( bCpyHeader )
1385 pOldFormat = pNewItem->StaticWhichCast(RES_HEADER).GetHeaderFormat();
1386 else
1387 pOldFormat = pNewItem->StaticWhichCast(RES_FOOTER).GetFooterFormat();
1389 if( !pOldFormat )
1390 return;
1392 SwFrameFormat* pNewFormat = new SwFrameFormat( GetAttrPool(), u"CpyDesc"_ustr,
1393 GetDfltFrameFormat() );
1394 pNewFormat->CopyAttrs( *pOldFormat );
1396 if( const SwFormatContent* pContent = pNewFormat->GetAttrSet().GetItemIfSet(
1397 RES_CNTNT, false ) )
1399 if( pContent->GetContentIdx() )
1401 const SwNodes& rSrcNds = rSrcFormat.GetDoc()->GetNodes();
1402 SwStartNode* pSttNd = SwNodes::MakeEmptySection( GetNodes().GetEndOfAutotext(),
1403 bCpyHeader
1404 ? SwHeaderStartNode
1405 : SwFooterStartNode );
1406 const SwNode& rCSttNd = pContent->GetContentIdx()->GetNode();
1407 SwNodeRange aRg( rCSttNd, SwNodeOffset(0), *rCSttNd.EndOfSectionNode() );
1408 rSrcNds.Copy_( aRg, *pSttNd->EndOfSectionNode() );
1409 rSrcFormat.GetDoc()->GetDocumentContentOperationsManager().CopyFlyInFlyImpl(aRg, nullptr, *pSttNd);
1410 // TODO: investigate calling CopyWithFlyInFly?
1411 SwPaM const source(aRg.aStart, aRg.aEnd);
1412 SwPosition dest(*pSttNd);
1413 sw::CopyBookmarks(source, dest);
1414 pNewFormat->SetFormatAttr( SwFormatContent( pSttNd ));
1416 else
1417 pNewFormat->ResetFormatAttr( RES_CNTNT );
1419 if( bCpyHeader )
1420 pNewItem->StaticWhichCast(RES_HEADER).RegisterToFormat(*pNewFormat);
1421 else
1422 pNewItem->StaticWhichCast(RES_FOOTER).RegisterToFormat(*pNewFormat);
1423 rDestFormat.SetFormatAttr( *pNewItem );
1426 void SwDoc::CopyPageDesc( const SwPageDesc& rSrcDesc, SwPageDesc& rDstDesc,
1427 bool bCopyPoolIds )
1429 bool bNotifyLayout = false;
1430 SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout();
1432 rDstDesc.SetLandscape( rSrcDesc.GetLandscape() );
1433 rDstDesc.SetNumType( rSrcDesc.GetNumType() );
1434 if( rDstDesc.ReadUseOn() != rSrcDesc.ReadUseOn() )
1436 rDstDesc.WriteUseOn( rSrcDesc.ReadUseOn() );
1437 bNotifyLayout = true;
1440 if( bCopyPoolIds )
1442 rDstDesc.SetPoolFormatId( rSrcDesc.GetPoolFormatId() );
1443 rDstDesc.SetPoolHelpId( rSrcDesc.GetPoolHelpId() );
1444 // Always set the HelpFile Id to default!
1445 rDstDesc.SetPoolHlpFileId( UCHAR_MAX );
1448 if( rSrcDesc.GetFollow() != &rSrcDesc )
1450 const SwPageDesc* pSrcFollow = rSrcDesc.GetFollow();
1451 SwPageDesc* pFollow = FindPageDesc( pSrcFollow->GetName() );
1452 if( !pFollow )
1454 // copy
1455 pFollow = MakePageDesc( pSrcFollow->GetName() );
1456 CopyPageDesc( *pSrcFollow, *pFollow );
1458 rDstDesc.SetFollow( pFollow );
1459 bNotifyLayout = true;
1462 // the header and footer attributes are copied separately
1463 // the content sections have to be copied in their entirety
1465 SfxItemSet aAttrSet( rSrcDesc.GetMaster().GetAttrSet() );
1466 aAttrSet.ClearItem( RES_HEADER );
1467 aAttrSet.ClearItem( RES_FOOTER );
1469 rDstDesc.GetMaster().DelDiffs( aAttrSet );
1470 rDstDesc.GetMaster().SetFormatAttr( aAttrSet );
1472 aAttrSet.ClearItem();
1473 aAttrSet.Put( rSrcDesc.GetLeft().GetAttrSet() );
1474 aAttrSet.ClearItem( RES_HEADER );
1475 aAttrSet.ClearItem( RES_FOOTER );
1477 rDstDesc.GetLeft().DelDiffs( aAttrSet );
1478 rDstDesc.GetLeft().SetFormatAttr( aAttrSet );
1480 aAttrSet.ClearItem();
1481 aAttrSet.Put( rSrcDesc.GetFirstMaster().GetAttrSet() );
1482 aAttrSet.ClearItem( RES_HEADER );
1483 aAttrSet.ClearItem( RES_FOOTER );
1485 rDstDesc.GetFirstMaster().DelDiffs( aAttrSet );
1486 rDstDesc.GetFirstMaster().SetFormatAttr( aAttrSet );
1488 aAttrSet.ClearItem();
1489 aAttrSet.Put( rSrcDesc.GetFirstLeft().GetAttrSet() );
1490 aAttrSet.ClearItem( RES_HEADER );
1491 aAttrSet.ClearItem( RES_FOOTER );
1493 rDstDesc.GetFirstLeft().DelDiffs( aAttrSet );
1494 rDstDesc.GetFirstLeft().SetFormatAttr( aAttrSet );
1497 CopyHeader( rSrcDesc.GetMaster(), rDstDesc.GetMaster() );
1498 CopyFooter( rSrcDesc.GetMaster(), rDstDesc.GetMaster() );
1499 if( !rDstDesc.IsHeaderShared() )
1500 CopyHeader( rSrcDesc.GetLeft(), rDstDesc.GetLeft() );
1501 else
1502 rDstDesc.GetLeft().SetFormatAttr( rDstDesc.GetMaster().GetHeader() );
1503 if( !rDstDesc.IsFirstShared() )
1505 CopyHeader( rSrcDesc.GetFirstMaster(), rDstDesc.GetFirstMaster() );
1506 rDstDesc.GetFirstLeft().SetFormatAttr(rDstDesc.GetFirstMaster().GetHeader());
1508 else
1510 rDstDesc.GetFirstMaster().SetFormatAttr( rDstDesc.GetMaster().GetHeader() );
1511 rDstDesc.GetFirstLeft().SetFormatAttr(rDstDesc.GetLeft().GetHeader());
1514 if( !rDstDesc.IsFooterShared() )
1515 CopyFooter( rSrcDesc.GetLeft(), rDstDesc.GetLeft() );
1516 else
1517 rDstDesc.GetLeft().SetFormatAttr( rDstDesc.GetMaster().GetFooter() );
1518 if( !rDstDesc.IsFirstShared() )
1520 CopyFooter( rSrcDesc.GetFirstMaster(), rDstDesc.GetFirstMaster() );
1521 rDstDesc.GetFirstLeft().SetFormatAttr(rDstDesc.GetFirstMaster().GetFooter());
1523 else
1525 rDstDesc.GetFirstMaster().SetFormatAttr( rDstDesc.GetMaster().GetFooter() );
1526 rDstDesc.GetFirstLeft().SetFormatAttr(rDstDesc.GetLeft().GetFooter());
1529 if( bNotifyLayout && pTmpRoot )
1531 for( auto aLayout : GetAllLayouts() )
1532 aLayout->AllCheckPageDescs();
1535 // If foot notes change the pages have to be triggered
1536 if( !(rDstDesc.GetFootnoteInfo() == rSrcDesc.GetFootnoteInfo()) )
1538 sw::PageFootnoteHint aHint;
1539 rDstDesc.SetFootnoteInfo( rSrcDesc.GetFootnoteInfo() );
1540 rDstDesc.GetMaster().CallSwClientNotify(aHint);
1541 rDstDesc.GetLeft().CallSwClientNotify(aHint);
1542 rDstDesc.GetFirstMaster().CallSwClientNotify(aHint);
1543 rDstDesc.GetFirstLeft().CallSwClientNotify(aHint);
1546 // Copy the stashed formats as well between the page descriptors...
1547 for (bool bFirst : { true, false })
1549 for (bool bLeft : { true, false })
1551 for (bool bHeader : { true, false })
1553 if (!bLeft && !bFirst)
1554 continue;
1556 // Copy format only if it exists
1557 if (auto pStashedFormatSrc = rSrcDesc.GetStashedFrameFormat(bHeader, bLeft, bFirst))
1559 if (pStashedFormatSrc->GetDoc() != this)
1561 SwFrameFormat newFormat(GetAttrPool(), u"CopyDesc"_ustr, GetDfltFrameFormat());
1563 SfxItemSet aAttrSet(pStashedFormatSrc->GetAttrSet());
1564 aAttrSet.ClearItem(RES_HEADER);
1565 aAttrSet.ClearItem(RES_FOOTER);
1567 newFormat.DelDiffs(aAttrSet);
1568 newFormat.SetFormatAttr(aAttrSet);
1570 if (bHeader)
1571 CopyHeader(*pStashedFormatSrc, newFormat);
1572 else
1573 CopyFooter(*pStashedFormatSrc, newFormat);
1575 rDstDesc.StashFrameFormat(newFormat, bHeader, bLeft, bFirst);
1577 else
1579 rDstDesc.StashFrameFormat(*pStashedFormatSrc, bHeader, bLeft, bFirst);
1587 void SwDoc::ReplaceStyles( const SwDoc& rSource, bool bIncludePageStyles )
1589 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1591 CopyFormatArr( *rSource.mpCharFormatTable, *mpCharFormatTable,
1592 &SwDoc::MakeCharFormat_, *mpDfltCharFormat );
1593 CopyFormatArr( *rSource.mpFrameFormatTable, *mpFrameFormatTable,
1594 &SwDoc::MakeFrameFormat_, *mpDfltFrameFormat );
1595 CopyFormatArr( *rSource.mpTextFormatCollTable, *mpTextFormatCollTable,
1596 &SwDoc::MakeTextFormatColl_, *mpDfltTextFormatColl );
1598 //To-Do:
1599 // a) in sd rtf import (View::InsertData) don't use
1600 // a super-fragile test for mere presence of \trowd to
1601 // indicate import of rtf into a table
1602 // b) then drop use of bIncludePageStyles
1603 if (bIncludePageStyles)
1605 // and now the page templates
1606 SwPageDescs::size_type nCnt = rSource.m_PageDescs.size();
1607 if( nCnt )
1609 // a different Doc -> Number formatter needs to be merged
1610 SwTableNumFormatMerge aTNFM( rSource, *this );
1612 // 1st step: Create all formats (skip the 0th - it's the default!)
1613 while( nCnt )
1615 const SwPageDesc &rSrc = *rSource.m_PageDescs[ --nCnt ];
1616 if( nullptr == FindPageDesc( rSrc.GetName() ) )
1617 MakePageDesc( rSrc.GetName() );
1620 // 2nd step: Copy all attributes, set the right parents
1621 for (SwPageDescs::size_type i = rSource.m_PageDescs.size(); i; )
1623 const SwPageDesc &rSrc = *rSource.m_PageDescs[ --i ];
1624 SwPageDesc* pDesc = FindPageDesc( rSrc.GetName() );
1625 CopyPageDesc( rSrc, *pDesc);
1630 // then there are the numbering templates
1631 const SwNumRuleTable::size_type nCnt = rSource.GetNumRuleTable().size();
1632 if( nCnt )
1634 const SwNumRuleTable& rArr = rSource.GetNumRuleTable();
1635 for( SwNumRuleTable::size_type n = 0; n < nCnt; ++n )
1637 const SwNumRule& rR = *rArr[ n ];
1638 SwNumRule* pNew = FindNumRulePtr( rR.GetName());
1639 if( pNew )
1640 pNew->CopyNumRule(*this, rR);
1641 else
1643 if( !rR.IsAutoRule() )
1644 MakeNumRule( rR.GetName(), &rR );
1645 else
1647 // as we reset all styles, there shouldn't be any unknown
1648 // automatic SwNumRules, because all should have been
1649 // created by the style copying!
1650 // So just warn and ignore.
1651 SAL_WARN( "sw.core", "Found unknown auto SwNumRule during reset!" );
1657 if (undoGuard.UndoWasEnabled())
1659 // nodes array was modified!
1660 GetIDocumentUndoRedo().DelAllUndoObj();
1663 getIDocumentState().SetModified();
1666 void SwDoc::MoveLeftMargin(const SwPaM& rPam, bool bRight, bool bModulus,
1667 SwRootFrame const*const pLayout)
1669 SwHistory* pHistory = nullptr;
1670 if (GetIDocumentUndoRedo().DoesUndo())
1672 std::unique_ptr<SwUndoMoveLeftMargin> pUndo(new SwUndoMoveLeftMargin( rPam, bRight,
1673 bModulus ));
1674 pHistory = &pUndo->GetHistory();
1675 GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
1678 const SvxTabStopItem& rTabItem = GetDefault( RES_PARATR_TABSTOP );
1679 const sal_Int32 nDefDist = rTabItem.Count() ? rTabItem[0].GetTabPos() : 1134;
1680 const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
1681 SwNodeIndex aIdx( rStt.GetNode() );
1682 while( aIdx <= rEnd.GetNode() )
1684 SwTextNode* pTNd = aIdx.GetNode().GetTextNode();
1685 if( pTNd )
1687 pTNd = sw::GetParaPropsNode(*pLayout, aIdx.GetNode());
1688 SvxFirstLineIndentItem firstLine(pTNd->SwContentNode::GetAttr(RES_MARGIN_FIRSTLINE));
1689 SvxTextLeftMarginItem leftMargin(pTNd->SwContentNode::GetAttr(RES_MARGIN_TEXTLEFT));
1691 // #i93873# See also lcl_MergeListLevelIndentAsLRSpaceItem in thints.cxx
1692 ::sw::ListLevelIndents const indents(pTNd->AreListLevelIndentsApplicable());
1693 if (indents != ::sw::ListLevelIndents::No)
1695 const SwNumRule* pRule = pTNd->GetNumRule();
1696 if ( pRule )
1698 const int nListLevel = pTNd->GetActualListLevel();
1699 if ( nListLevel >= 0 )
1701 const SwNumFormat& rFormat = pRule->Get(o3tl::narrowing<sal_uInt16>(nListLevel));
1702 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1704 if (indents & ::sw::ListLevelIndents::LeftMargin)
1706 leftMargin.SetTextLeft(
1707 SvxIndentValue::twips(rFormat.GetIndentAt()));
1709 if (indents & ::sw::ListLevelIndents::FirstLine)
1711 firstLine.SetTextFirstLineOffset(SvxIndentValue{
1712 static_cast<double>(rFormat.GetFirstLineIndent()),
1713 rFormat.GetFirstLineIndentUnit() });
1720 tools::Long nNext = leftMargin.ResolveTextLeft({});
1721 if( bModulus )
1722 nNext = ( nNext / nDefDist ) * nDefDist;
1724 if( bRight )
1725 nNext += nDefDist;
1726 else
1727 if(nNext >0) // fdo#75936 set limit for decreasing indent
1728 nNext -= nDefDist;
1730 leftMargin.SetTextLeft(SvxIndentValue::twips(nNext));
1732 SwRegHistory aRegH( pTNd, *pTNd, pHistory );
1733 pTNd->SetAttr(firstLine);
1734 pTNd->SetAttr(leftMargin);
1735 aIdx = *sw::GetFirstAndLastNode(*pLayout, aIdx.GetNode()).second;
1737 ++aIdx;
1739 getIDocumentState().SetModified();
1742 bool SwDoc::DontExpandFormat( const SwPosition& rPos, bool bFlag )
1744 bool bRet = false;
1745 SwTextNode* pTextNd = rPos.GetNode().GetTextNode();
1746 if( pTextNd )
1748 bRet = pTextNd->DontExpandFormat( rPos.GetContentIndex(), bFlag );
1749 if( bRet && GetIDocumentUndoRedo().DoesUndo() )
1751 GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDontExpandFormat>(rPos) );
1754 return bRet;
1757 SwTableBoxFormat* SwDoc::MakeTableBoxFormat()
1759 SwTableBoxFormat* pFormat = new SwTableBoxFormat( GetAttrPool(), mpDfltFrameFormat.get() );
1760 pFormat->SetFormatName("TableBox" + OUString::number(reinterpret_cast<sal_IntPtr>(pFormat)));
1761 getIDocumentState().SetModified();
1762 return pFormat;
1765 SwTableLineFormat* SwDoc::MakeTableLineFormat()
1767 SwTableLineFormat* pFormat = new SwTableLineFormat( GetAttrPool(), mpDfltFrameFormat.get() );
1768 pFormat->SetFormatName("TableLine" + OUString::number(reinterpret_cast<sal_IntPtr>(pFormat)));
1769 getIDocumentState().SetModified();
1770 return pFormat;
1773 void SwDoc::EnsureNumberFormatter()
1775 if (mpNumberFormatter == nullptr)
1777 LanguageType eLang = LANGUAGE_SYSTEM;
1778 mpNumberFormatter = new SvNumberFormatter(comphelper::getProcessComponentContext(), eLang);
1779 mpNumberFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT_INTL );
1780 if (!comphelper::IsFuzzing())
1781 mpNumberFormatter->SetYear2000(
1782 officecfg::Office::Common::DateFormat::TwoDigitYear::get());
1786 SwTableNumFormatMerge::SwTableNumFormatMerge( const SwDoc& rSrc, SwDoc& rDest )
1787 : pNFormat( nullptr )
1789 // a different Doc -> Number formatter needs to be merged
1790 if( &rSrc != &rDest )
1792 SvNumberFormatter* pN = const_cast<SwDoc&>(rSrc).GetNumberFormatter( false );
1793 if( pN )
1795 pNFormat = rDest.GetNumberFormatter();
1796 pNFormat->MergeFormatter( *pN );
1800 if( &rSrc != &rDest )
1801 static_cast<SwGetRefFieldType*>(rSrc.getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::GetRef ))->
1802 MergeWithOtherDoc( rDest );
1805 SwTableNumFormatMerge::~SwTableNumFormatMerge()
1807 if( pNFormat )
1808 pNFormat->ClearMergeTable();
1811 void SwDoc::SetTextFormatCollByAutoFormat( const SwPosition& rPos, sal_uInt16 nPoolId,
1812 const SfxItemSet* pSet )
1814 SwPaM aPam( rPos );
1815 SwTextNode* pTNd = rPos.GetNode().GetTextNode();
1816 assert(pTNd);
1818 if (mbIsAutoFormatRedline)
1820 // create the redline object
1821 const SwTextFormatColl& rColl = *pTNd->GetTextColl();
1822 SwRangeRedline* pRedl = new SwRangeRedline( RedlineType::FmtColl, aPam );
1823 pRedl->SetMark();
1825 // Only those items that are not set by the Set again in the Node
1826 // are of interest. Thus, we take the difference.
1827 SwRedlineExtraData_FormatColl aExtraData( rColl.GetName(),
1828 rColl.GetPoolFormatId() );
1829 if( pSet && pTNd->HasSwAttrSet() )
1831 SfxItemSet aTmp( *pTNd->GetpSwAttrSet() );
1832 aTmp.Differentiate( *pSet );
1833 // we handle the adjust item separately
1834 const SfxPoolItem* pItem;
1835 if( SfxItemState::SET == pTNd->GetpSwAttrSet()->GetItemState(
1836 RES_PARATR_ADJUST, false, &pItem ))
1837 aTmp.Put( *pItem );
1838 aExtraData.SetItemSet( aTmp );
1840 pRedl->SetExtraData( &aExtraData );
1842 //TODO: Undo is still missing!
1843 getIDocumentRedlineAccess().AppendRedline( pRedl, true );
1846 SetTextFormatColl( aPam, getIDocumentStylePoolAccess().GetTextCollFromPool( nPoolId ) );
1848 if (pSet && pSet->Count())
1850 aPam.SetMark();
1851 aPam.GetMark()->SetContent(pTNd->GetText().getLength());
1852 // sw_redlinehide: don't need layout currently because the only caller
1853 // passes in the properties node
1854 assert(static_cast<SwTextFrame const*>(pTNd->getLayoutFrame(nullptr))->GetTextNodeForParaProps() == pTNd);
1855 getIDocumentContentOperations().InsertItemSet( aPam, *pSet );
1859 void SwDoc::SetFormatItemByAutoFormat( const SwPaM& rPam, const SfxItemSet& rSet )
1861 SwTextNode* pTNd = rPam.GetPoint()->GetNode().GetTextNode();
1862 assert(pTNd);
1864 RedlineFlags eOld = getIDocumentRedlineAccess().GetRedlineFlags();
1866 if (mbIsAutoFormatRedline)
1868 // create the redline object
1869 SwRangeRedline* pRedl = new SwRangeRedline( RedlineType::Format, rPam );
1870 if( !pRedl->HasMark() )
1871 pRedl->SetMark();
1873 // Only those items that are not set by the Set again in the Node
1874 // are of interest. Thus, we take the difference.
1875 SwRedlineExtraData_Format aExtraData( rSet );
1877 pRedl->SetExtraData( &aExtraData );
1879 //TODO: Undo is still missing!
1880 getIDocumentRedlineAccess().AppendRedline( pRedl, true );
1882 getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld | RedlineFlags::Ignore );
1885 const sal_Int32 nEnd(rPam.End()->GetContentIndex());
1886 std::vector<WhichPair> whichIds;
1887 SfxItemIter iter(rSet);
1888 for (SfxPoolItem const* pItem = iter.GetCurItem(); pItem; pItem = iter.NextItem())
1890 if (RES_CHRATR_BEGIN <= pItem->Which() && pItem->Which() < RES_CHRATR_END)
1891 { // tdf#162911 don't add items with static default like INETFMT
1892 whichIds.push_back({pItem->Which(), pItem->Which()});
1896 ::std::optional<SfxItemSet> oCurrentSet;
1897 if (!whichIds.empty())
1899 // ITEM: Need to sort these due to ItemSet using unordered_set and
1900 // WhichRangesContainer expect these sorted ascending
1901 std::sort(whichIds.begin(), whichIds.end(), [](WhichPair& a, WhichPair& b) {return a.first < b.first;});
1903 oCurrentSet.emplace(GetAttrPool(), WhichRangesContainer(whichIds.data(), whichIds.size()));
1904 pTNd->GetParaAttr(*oCurrentSet, nEnd, nEnd);
1905 for (const WhichPair& rPair : whichIds)
1906 { // yuk - want to explicitly set the pool defaults too :-/
1907 oCurrentSet->Put(oCurrentSet->Get(rPair.first));
1911 getIDocumentContentOperations().InsertItemSet( rPam, rSet, SetAttrMode::DONTEXPAND );
1913 if (!whichIds.empty())
1915 // fdo#62536: DONTEXPAND does not work when there is already an AUTOFMT
1916 // here, so insert the old attributes as an empty hint to stop expand
1917 SwPaM endPam(*pTNd, nEnd);
1918 endPam.SetMark();
1919 getIDocumentContentOperations().InsertItemSet(endPam, *oCurrentSet);
1922 getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
1925 void SwDoc::ChgFormat(SwFormat & rFormat, const SfxItemSet & rSet)
1927 if (GetIDocumentUndoRedo().DoesUndo())
1929 // copying <rSet> to <aSet>
1930 SfxItemSet aSet(rSet);
1931 // remove from <aSet> all items, which are already set at the format
1932 aSet.Differentiate(rFormat.GetAttrSet());
1933 // <aSet> contains now all *new* items for the format
1935 // copying current format item set to <aOldSet>
1936 SfxItemSet aOldSet(rFormat.GetAttrSet());
1937 // insert new items into <aOldSet>
1938 aOldSet.Put(aSet);
1939 // invalidate all new items in <aOldSet> in order to clear these items,
1940 // if the undo action is triggered.
1942 SfxItemIter aIter(aSet);
1944 for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
1946 aOldSet.InvalidateItem(pItem->Which());
1950 GetIDocumentUndoRedo().AppendUndo(
1951 std::make_unique<SwUndoFormatAttr>(std::move(aOldSet), rFormat, /*bSaveDrawPt*/true));
1954 rFormat.SetFormatAttr(rSet);
1957 void SwDoc::RenameFormat(SwFormat & rFormat, const OUString & sNewName,
1958 bool bBroadcast)
1960 SfxStyleFamily eFamily = SfxStyleFamily::All;
1962 if (GetIDocumentUndoRedo().DoesUndo())
1964 std::unique_ptr<SwUndo> pUndo;
1966 switch (rFormat.Which())
1968 case RES_CHRFMT:
1969 pUndo.reset(new SwUndoRenameCharFormat(rFormat.GetName(), sNewName, *this));
1970 eFamily = SfxStyleFamily::Char;
1971 break;
1972 case RES_TXTFMTCOLL:
1973 pUndo.reset(new SwUndoRenameFormatColl(rFormat.GetName(), sNewName, *this));
1974 eFamily = SfxStyleFamily::Para;
1975 break;
1976 case RES_FRMFMT:
1977 pUndo.reset(new SwUndoRenameFrameFormat(rFormat.GetName(), sNewName, *this));
1978 eFamily = SfxStyleFamily::Frame;
1979 break;
1981 default:
1982 break;
1985 if (pUndo)
1987 GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
1991 // name change means the o3tl::sorted_array is not property sorted
1992 if (rFormat.Which() == RES_CHRFMT)
1993 mpCharFormatTable->SetFormatNameAndReindex(static_cast<SwCharFormat*>(&rFormat), sNewName);
1994 else
1995 rFormat.SetFormatName(sNewName);
1997 if (bBroadcast)
1998 BroadcastStyleOperation(sNewName, eFamily, SfxHintId::StyleSheetModified);
2001 void SwDoc::dumpAsXml(xmlTextWriterPtr pWriter) const
2003 bool bOwns = false;
2004 if (!pWriter)
2006 pWriter = xmlNewTextWriterFilename("nodes.xml", 0);
2007 xmlTextWriterSetIndent(pWriter,1);
2008 (void)xmlTextWriterSetIndentString(pWriter, BAD_CAST(" "));
2009 (void)xmlTextWriterStartDocument(pWriter, nullptr, nullptr, nullptr);
2010 bOwns = true;
2012 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwDoc"));
2013 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
2015 m_pNodes->dumpAsXml(pWriter);
2016 m_PageDescs.dumpAsXml(pWriter);
2017 maDBData.dumpAsXml(pWriter);
2018 mpMarkManager->dumpAsXml(pWriter);
2019 m_pContentControlManager->dumpAsXml(pWriter);
2020 m_pUndoManager->dumpAsXml(pWriter);
2021 m_pDocumentSettingManager->dumpAsXml(pWriter);
2022 getIDocumentFieldsAccess().GetFieldTypes()->dumpAsXml(pWriter);
2023 mpTextFormatCollTable->dumpAsXml(pWriter);
2024 mpCharFormatTable->dumpAsXml(pWriter);
2025 mpFrameFormatTable->dumpAsXml(pWriter, "frmFormatTable");
2026 mpSpzFrameFormatTable->dumpAsXml(pWriter, "spzFrameFormatTable");
2027 mpSectionFormatTable->dumpAsXml(pWriter);
2028 mpTableFrameFormatTable->dumpAsXml(pWriter, "tableFrameFormatTable");
2029 mpNumRuleTable->dumpAsXml(pWriter);
2030 getIDocumentRedlineAccess().GetRedlineTable().dumpAsXml(pWriter);
2031 getIDocumentRedlineAccess().GetExtraRedlineTable().dumpAsXml(pWriter);
2032 if (const SdrModel* pModel = getIDocumentDrawModelAccess().GetDrawModel())
2033 pModel->dumpAsXml(pWriter);
2035 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("mbModified"));
2036 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(getIDocumentState().IsModified()).getStr()));
2037 (void)xmlTextWriterEndElement(pWriter);
2039 (void)xmlTextWriterEndElement(pWriter);
2040 if (bOwns)
2042 (void)xmlTextWriterEndDocument(pWriter);
2043 xmlFreeTextWriter(pWriter);
2047 void SwDBData::dumpAsXml(xmlTextWriterPtr pWriter) const
2049 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwDBData"));
2051 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("sDataSource"), BAD_CAST(sDataSource.toUtf8().getStr()));
2052 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("sCommand"), BAD_CAST(sCommand.toUtf8().getStr()));
2053 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nCommandType"), BAD_CAST(OString::number(nCommandType).getStr()));
2055 (void)xmlTextWriterEndElement(pWriter);
2058 std::set<Color> SwDoc::GetDocColors()
2060 std::set<Color> aDocColors;
2061 SwAttrPool& rPool = GetAttrPool();
2063 svx::DocumentColorHelper::queryColors<SvxColorItem>(RES_CHRATR_COLOR, &rPool, aDocColors);
2064 svx::DocumentColorHelper::queryColors<SvxBrushItem>(RES_CHRATR_HIGHLIGHT, &rPool, aDocColors);
2065 svx::DocumentColorHelper::queryColors<SvxBrushItem>(RES_CHRATR_BACKGROUND, &rPool, aDocColors);
2067 return aDocColors;
2070 // #i69627#
2071 namespace docfunc
2073 bool HasOutlineStyleToBeWrittenAsNormalListStyle( SwDoc& rDoc )
2075 // If a parent paragraph style of one of the paragraph styles, which
2076 // are assigned to the list levels of the outline style, has a list style
2077 // set or inherits a list style from its parent style, the outline style
2078 // has to be written as a normal list style to the OpenDocument file
2079 // format or the OpenOffice.org file format.
2080 bool bRet( false );
2082 const SwTextFormatColls* pTextFormatColls( rDoc.GetTextFormatColls() );
2083 if ( pTextFormatColls )
2085 for ( auto pTextFormatColl : *pTextFormatColls )
2087 if ( pTextFormatColl->IsDefault() ||
2088 ! pTextFormatColl->IsAssignedToListLevelOfOutlineStyle() )
2090 continue;
2093 const SwTextFormatColl* pParentTextFormatColl =
2094 dynamic_cast<const SwTextFormatColl*>( pTextFormatColl->DerivedFrom());
2095 if ( !pParentTextFormatColl )
2096 continue;
2098 if ( SfxItemState::SET == pParentTextFormatColl->GetItemState( RES_PARATR_NUMRULE ) )
2100 // #i106218# consider that the outline style is set
2101 const SwNumRuleItem& rDirectItem = pParentTextFormatColl->GetNumRule();
2102 if ( rDirectItem.GetValue() != rDoc.GetOutlineNumRule()->GetName() )
2104 bRet = true;
2105 break;
2111 return bRet;
2114 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */