diff options
Diffstat (limited to 'sw/source/core/doc/docfmt.cxx')
-rw-r--r-- | sw/source/core/doc/docfmt.cxx | 2097 |
1 files changed, 2097 insertions, 0 deletions
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx new file mode 100644 index 0000000000..57c42c529e --- /dev/null +++ b/sw/source/core/doc/docfmt.cxx @@ -0,0 +1,2097 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <libxml/xmlwriter.h> +#include <hintids.hxx> +#include <svl/itemiter.hxx> +#include <svl/numformat.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/formatbreakitem.hxx> +#include <editeng/rsiditem.hxx> +#include <editeng/colritem.hxx> +#include <officecfg/Office/Common.hxx> +#include <osl/diagnose.h> +#include <svl/zforlist.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/configmgr.hxx> +#include <sal/log.hxx> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <fmtpdsc.hxx> +#include <fmthdft.hxx> +#include <fmtcntnt.hxx> +#include <doc.hxx> +#include <docfunc.hxx> +#include <drawdoc.hxx> +#include <MarkManager.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <IDocumentUndoRedo.hxx> +#include <DocumentContentOperationsManager.hxx> +#include <DocumentSettingManager.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <IDocumentState.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <rootfrm.hxx> +#include <txtfrm.hxx> +#include <hints.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <UndoCore.hxx> +#include <UndoAttribute.hxx> +#include <UndoInsert.hxx> +#include <pagedesc.hxx> +#include <rolbck.hxx> +#include <mvsave.hxx> +#include <txatbase.hxx> +#include <swtblfmt.hxx> +#include <charfmt.hxx> +#include <docary.hxx> +#include <paratr.hxx> +#include <redline.hxx> +#include <reffld.hxx> +#include <fmtinfmt.hxx> +#include <breakit.hxx> +#include <SwUndoFmt.hxx> +#include <UndoManager.hxx> +#include <swmodule.hxx> +#include <modcfg.hxx> +#include <frameformats.hxx> +#include <textboxhelper.hxx> +#include <textcontentcontrol.hxx> +#include <memory> +#include <algorithm> +#include <functional> + +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +/* + * Internal functions + */ + +static void SetTextFormatCollNext( SwTextFormatColl* pTextColl, const SwTextFormatColl* pDel ) +{ + if ( &pTextColl->GetNextTextFormatColl() == pDel ) + { + pTextColl->SetNextTextFormatColl( *pTextColl ); + } +} + +static bool lcl_RstAttr( SwNode* pNd, void* pArgs ) +{ + const sw::DocumentContentOperationsManager::ParaRstFormat* pPara = static_cast<sw::DocumentContentOperationsManager::ParaRstFormat*>(pArgs); + SwContentNode* pNode = pNd->GetContentNode(); + if (pPara && pPara->pLayout && pPara->pLayout->HasMergedParas() + && pNode && pNode->GetRedlineMergeFlag() == SwNode::Merge::Hidden) + { + return true; + } + if( pNode && pNode->HasSwAttrSet() ) + { + const bool bLocked = pNode->IsModifyLocked(); + pNode->LockModify(); + + SwDoc& rDoc = pNode->GetDoc(); + + // remove unused attribute RES_LR_SPACE + // add list attributes, except RES_PARATR_LIST_AUTOFMT + SfxItemSetFixed< + RES_PARATR_NUMRULE, RES_PARATR_NUMRULE, + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_AUTOFMT - 1, + RES_PAGEDESC, RES_BREAK, + RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME> aSavedAttrsSet(rDoc.GetAttrPool()); + const SfxItemSet* pAttrSetOfNode = pNode->GetpSwAttrSet(); + + std::vector<sal_uInt16> aClearWhichIds; + // restoring all paragraph list attributes + { + SfxItemSetFixed<RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_AUTOFMT - 1> aListAttrSet( rDoc.GetAttrPool() ); + aListAttrSet.Set(*pAttrSetOfNode); + if ( aListAttrSet.Count() ) + { + aSavedAttrsSet.Put(aListAttrSet); + SfxItemIter aIter( aListAttrSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + while( pItem ) + { + aClearWhichIds.push_back( pItem->Which() ); + pItem = aIter.NextItem(); + } + } + } + + if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_PARATR_NUMRULE, false); + pItem && !pItem->GetValue().isEmpty()) + { + aSavedAttrsSet.Put(*pItem); + aClearWhichIds.push_back(RES_PARATR_NUMRULE); + } + if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_PAGEDESC, false); + pItem && pItem->GetPageDesc()) + { + aSavedAttrsSet.Put(*pItem); + aClearWhichIds.push_back(RES_PAGEDESC); + } + if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_BREAK, false); + pItem && pItem->GetBreak() != SvxBreak::NONE) + { + aSavedAttrsSet.Put(*pItem); + aClearWhichIds.push_back(RES_BREAK); + } + if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_FRMATR_STYLE_NAME, false); + pItem && !pItem->GetValue().isEmpty()) + { + aSavedAttrsSet.Put(*pItem); + aClearWhichIds.push_back(RES_FRMATR_STYLE_NAME); + } + if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_FRMATR_CONDITIONAL_STYLE_NAME, false); + pItem && !pItem->GetValue().isEmpty()) + { + aSavedAttrsSet.Put(*pItem); + aClearWhichIds.push_back(RES_FRMATR_CONDITIONAL_STYLE_NAME); + } + + // do not clear items directly from item set and only clear to be kept + // attributes, if no deletion item set is found. + const bool bKeepAttributes = + !pPara || !pPara->pDelSet || pPara->pDelSet->Count() == 0; + if ( bKeepAttributes ) + { + pNode->ResetAttr( aClearWhichIds ); + } + + if( !bLocked ) + pNode->UnlockModify(); + + if( pPara ) + { + SwRegHistory aRegH( pNode, *pNode, pPara->pHistory ); + + if( pPara->pDelSet && pPara->pDelSet->Count() ) + { + OSL_ENSURE( !bKeepAttributes, + "<lcl_RstAttr(..)> - certain attributes are kept, but not needed." ); + SfxItemIter aIter( *pPara->pDelSet ); + for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + { + if ( ( pItem->Which() != RES_PAGEDESC && + pItem->Which() != RES_BREAK && + pItem->Which() != RES_FRMATR_STYLE_NAME && + pItem->Which() != RES_FRMATR_CONDITIONAL_STYLE_NAME && + pItem->Which() != RES_PARATR_NUMRULE ) || + ( aSavedAttrsSet.GetItemState( pItem->Which(), false ) != SfxItemState::SET ) ) + { + pNode->ResetAttr( pItem->Which() ); + } + } + } + else if( pPara->bResetAll ) + pNode->ResetAllAttr(); + else + pNode->ResetAttr( RES_PARATR_BEGIN, POOLATTR_END - 1 ); + } + else + pNode->ResetAllAttr(); + + // only restore saved attributes, if needed + if (bKeepAttributes && aSavedAttrsSet.Count()) + { + pNode->LockModify(); + + pNode->SetAttr(aSavedAttrsSet); + + if( !bLocked ) + pNode->UnlockModify(); + } + } + return true; +} + +void SwDoc::RstTextAttrs(const SwPaM &rRg, bool bInclRefToxMark, + bool bExactRange, SwRootFrame const*const pLayout) +{ + SwHistory* pHst = nullptr; + SwDataChanged aTmp( rRg ); + if (GetIDocumentUndoRedo().DoesUndo()) + { + std::unique_ptr<SwUndoResetAttr> pUndo(new SwUndoResetAttr( rRg, RES_CHRFMT )); + pHst = &pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); + } + auto [pStt, pEnd] = rRg.StartEnd(); // SwPosition* + sw::DocumentContentOperationsManager::ParaRstFormat aPara( + pStt, pEnd, pHst, nullptr, pLayout ); + aPara.bInclRefToxMark = bInclRefToxMark; + aPara.bExactRange = bExactRange; + GetNodes().ForEach( pStt->GetNodeIndex(), pEnd->GetNodeIndex()+1, + sw::DocumentContentOperationsManager::lcl_RstTextAttr, &aPara ); + getIDocumentState().SetModified(); +} + +void SwDoc::ResetAttrs( const SwPaM &rRg, + bool bTextAttr, + const o3tl::sorted_vector<sal_uInt16> &rAttrs, + const bool bSendDataChangedEvents, + SwRootFrame const*const pLayout) +{ + SwPaM* pPam = const_cast<SwPaM*>(&rRg); + std::optional<SwPaM> oExtraPaM; + if( !bTextAttr && !rAttrs.empty() && RES_TXTATR_END > *(rAttrs.begin()) ) + bTextAttr = true; + + if( !rRg.HasMark() ) + { + SwTextNode* pTextNd = rRg.GetPoint()->GetNode().GetTextNode(); + if( !pTextNd ) + return ; + + oExtraPaM.emplace( *rRg.GetPoint() ); + pPam = &*oExtraPaM; + + SwPosition& rSt = *pPam->GetPoint(); + sal_Int32 nMkPos, nPtPos = rSt.GetContentIndex(); + + // Special case: if the Cursor is located within a URL attribute, we take over it's area + SwTextAttr const*const pURLAttr( + pTextNd->GetTextAttrAt(rSt.GetContentIndex(), RES_TXTATR_INETFMT)); + if (pURLAttr && !pURLAttr->GetINetFormat().GetValue().isEmpty()) + { + nMkPos = pURLAttr->GetStart(); + nPtPos = *pURLAttr->End(); + } + else + { + assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is()); + Boundary aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary( + pTextNd->GetText(), nPtPos, + g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ), + WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/, + true); + + if( aBndry.startPos < nPtPos && nPtPos < aBndry.endPos ) + { + nMkPos = aBndry.startPos; + nPtPos = aBndry.endPos; + } + else + { + nPtPos = nMkPos = rSt.GetContentIndex(); + if( bTextAttr ) + pTextNd->DontExpandFormat( nPtPos ); + } + } + + rSt.SetContent(nMkPos); + pPam->SetMark(); + pPam->GetPoint()->SetContent(nPtPos); + } + + // #i96644# + std::optional< SwDataChanged > oDataChanged; + if ( bSendDataChangedEvents ) + { + oDataChanged.emplace( *pPam ); + } + SwHistory* pHst = nullptr; + if (GetIDocumentUndoRedo().DoesUndo()) + { + std::unique_ptr<SwUndoResetAttr> pUndo(new SwUndoResetAttr( rRg, + bTextAttr ? sal_uInt16(RES_CONDTXTFMTCOLL) : sal_uInt16(RES_TXTFMTCOLL) )); + if( !rAttrs.empty() ) + { + pUndo->SetAttrs( o3tl::sorted_vector(rAttrs) ); + } + pHst = &pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); + } + + auto [pStt, pEnd] = pPam->StartEnd(); // SwPosition* + sw::DocumentContentOperationsManager::ParaRstFormat aPara( + pStt, pEnd, pHst, nullptr, pLayout); + + // mst: not including META here; it seems attrs with CH_TXTATR are omitted + SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END - 1, + RES_TXTATR_INETFMT, RES_TXTATR_UNKNOWN_CONTAINER, + RES_PARATR_BEGIN, RES_FRMATR_END - 1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1> + aDelSet(GetAttrPool()); + for( auto it = rAttrs.rbegin(); it != rAttrs.rend(); ++it ) + { + if( POOLATTR_END > *it ) + aDelSet.Put( *GetDfltAttr( *it )); + } + if( aDelSet.Count() ) + aPara.pDelSet = &aDelSet; + + bool bAdd = true; + SwNodeIndex aTmpStt( pStt->GetNode() ); + SwNodeIndex aTmpEnd( pEnd->GetNode() ); + if( pStt->GetContentIndex() ) // just one part + { + // set up a later, and all CharFormatAttr -> TextFormatAttr + SwTextNode* pTNd = aTmpStt.GetNode().GetTextNode(); + if( pTNd && pTNd->HasSwAttrSet() && pTNd->GetpSwAttrSet()->Count() ) + { + if (pHst) + { + SwRegHistory history(pTNd, *pTNd, pHst); + pTNd->FormatToTextAttr(pTNd); + } + else + { + pTNd->FormatToTextAttr(pTNd); + } + } + + ++aTmpStt; + } + if( pEnd->GetContentIndex() == pEnd->GetNode().GetContentNode()->Len() ) + { + // set up a later, and all CharFormatAttr -> TextFormatAttr + ++aTmpEnd; + bAdd = false; + } + else if( pStt->GetNode() != pEnd->GetNode() || !pStt->GetContentIndex() ) + { + SwTextNode* pTNd = aTmpEnd.GetNode().GetTextNode(); + if( pTNd && pTNd->HasSwAttrSet() && pTNd->GetpSwAttrSet()->Count() ) + { + if (pHst) + { + SwRegHistory history(pTNd, *pTNd, pHst); + pTNd->FormatToTextAttr(pTNd); + } + else + { + pTNd->FormatToTextAttr(pTNd); + } + } + } + + if( aTmpStt < aTmpEnd ) + GetNodes().ForEach( pStt->GetNode(), aTmpEnd.GetNode(), lcl_RstAttr, &aPara ); + else if( !rRg.HasMark() ) + { + aPara.bResetAll = false ; + ::lcl_RstAttr( &pStt->GetNode(), &aPara ); + aPara.bResetAll = true ; + } + + if( bTextAttr ) + { + if( bAdd ) + ++aTmpEnd; + GetNodes().ForEach( pStt->GetNode(), aTmpEnd.GetNode(), sw::DocumentContentOperationsManager::lcl_RstTextAttr, &aPara ); + } + + getIDocumentState().SetModified(); + + oDataChanged.reset(); //before delete pPam +} + +/// Set the rsid of the next nLen symbols of rRg to the current session number +void SwDoc::UpdateRsid( const SwPaM &rRg, const sal_Int32 nLen ) +{ + if (!SW_MOD()->GetModuleConfig()->IsStoreRsid()) + return; + + SwTextNode *pTextNode = rRg.GetPoint()->GetNode().GetTextNode(); + if (!pTextNode) + { + return; + } + const sal_Int32 nStart(rRg.GetPoint()->GetContentIndex() - nLen); + SvxRsidItem aRsid( mnRsid, RES_CHRATR_RSID ); + + SfxItemSetFixed<RES_CHRATR_RSID, RES_CHRATR_RSID> aSet(GetAttrPool()); + aSet.Put(aRsid); + bool const bRet(pTextNode->SetAttr(aSet, nStart, + rRg.GetPoint()->GetContentIndex())); + + if (bRet && GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pLastUndo = GetUndoManager().GetLastUndo(); + SwUndoInsert *const pUndoInsert(dynamic_cast<SwUndoInsert*>(pLastUndo)); + // this function is called after Insert so expects to find SwUndoInsert + assert(pUndoInsert); + if (pUndoInsert) + { + pUndoInsert->SetWithRsid(); + } + } +} + +bool SwDoc::UpdateParRsid( SwTextNode *pTextNode, sal_uInt32 nVal ) +{ + if (!SW_MOD()->GetModuleConfig()->IsStoreRsid()) + return false; + + if (!pTextNode) + { + return false; + } + + SvxRsidItem aRsid( nVal ? nVal : mnRsid, RES_PARATR_RSID ); + return pTextNode->SetAttr( aRsid ); +} + +/// Set the attribute according to the stated format. +/// If Undo is enabled, the old values is added to the Undo history. +void SwDoc::SetAttr( const SfxPoolItem& rAttr, SwFormat& rFormat ) +{ + SfxItemSet aSet( GetAttrPool(), rAttr.Which(), rAttr.Which() ); + aSet.Put( rAttr ); + SetAttr( aSet, rFormat ); +} + +/// Set the attribute according to the stated format. +/// If Undo is enabled, the old values is added to the Undo history. +void SwDoc::SetAttr( const SfxItemSet& rSet, SwFormat& rFormat ) +{ + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoFormatAttrHelper aTmp( rFormat ); + rFormat.SetFormatAttr( rSet ); + if ( aTmp.GetUndo() ) + { + GetIDocumentUndoRedo().AppendUndo( aTmp.ReleaseUndo() ); + } + else + { + GetIDocumentUndoRedo().ClearRedo(); + } + } + else + { + rFormat.SetFormatAttr( rSet ); + } + + // If the format is a shape, and it has a textbox, sync. + auto pShapeFormat = dynamic_cast<SwFrameFormat*>(&rFormat); + if (pShapeFormat && SwTextBoxHelper::isTextBox(pShapeFormat, RES_DRAWFRMFMT)) + { + if (auto pObj = pShapeFormat->FindRealSdrObject()) + { + SwTextBoxHelper::syncFlyFrameAttr(*pShapeFormat, rSet, pObj); + SwTextBoxHelper::changeAnchor(pShapeFormat, pObj); + } + } + + getIDocumentState().SetModified(); +} + +void SwDoc::ResetAttrAtFormat( const std::vector<sal_uInt16>& rIds, + SwFormat& rChangedFormat ) +{ + std::unique_ptr<SwUndo> pUndo; + if (GetIDocumentUndoRedo().DoesUndo()) + pUndo.reset(new SwUndoFormatResetAttr( rChangedFormat, rIds )); + + bool bAttrReset = false; + for (const auto& nWhichId : rIds) + bAttrReset = rChangedFormat.ResetFormatAttr(nWhichId) || bAttrReset; + + if ( bAttrReset ) + { + if ( pUndo ) + { + GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) ); + } + + getIDocumentState().SetModified(); + } +} + +static bool lcl_SetNewDefTabStops( SwTwips nOldWidth, SwTwips nNewWidth, + SvxTabStopItem& rChgTabStop ) +{ + // Set the default values of all TabStops to the new value. + // Attention: we always work with the PoolAttribute here, so that + // we don't calculate the same value on the same TabStop (pooled!) for all sets. + // We send a FormatChg to modify. + + sal_uInt16 nOldCnt = rChgTabStop.Count(); + if( !nOldCnt || nOldWidth == nNewWidth ) + return false; + + // Find the default's beginning + sal_uInt16 n; + for( n = nOldCnt; n ; --n ) + if( SvxTabAdjust::Default != rChgTabStop[n - 1].GetAdjustment() ) + break; + ++n; + if( n < nOldCnt ) // delete the DefTabStops + rChgTabStop.Remove( n, nOldCnt - n ); + return true; +} + +/// Set the attribute as new default attribute in this document. +/// If Undo is enabled, the old value is added to the Undo history. +void SwDoc::SetDefault( const SfxPoolItem& rAttr ) +{ + SfxItemSet aSet( GetAttrPool(), rAttr.Which(), rAttr.Which() ); + aSet.Put( rAttr ); + SetDefault( aSet ); +} + +void SwDoc::SetDefault( const SfxItemSet& rSet ) +{ + if( !rSet.Count() ) + return; + + sw::BroadcastingModify aCallMod; + SwAttrSet aOld( GetAttrPool(), rSet.GetRanges() ), + aNew( GetAttrPool(), rSet.GetRanges() ); + SfxItemIter aIter( rSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + SfxItemPool* pSdrPool = GetAttrPool().GetSecondaryPool(); + do + { + bool bCheckSdrDflt = false; + const sal_uInt16 nWhich = pItem->Which(); + aOld.Put( GetAttrPool().GetDefaultItem( nWhich ) ); + GetAttrPool().SetPoolDefaultItem( *pItem ); + aNew.Put( GetAttrPool().GetDefaultItem( nWhich ) ); + + if (isCHRATR(nWhich) || isTXTATR(nWhich)) + { + aCallMod.Add( mpDfltTextFormatColl.get() ); + aCallMod.Add( mpDfltCharFormat.get() ); + bCheckSdrDflt = nullptr != pSdrPool; + } + else if ( isPARATR(nWhich) || + isPARATR_LIST(nWhich) ) + { + aCallMod.Add( mpDfltTextFormatColl.get() ); + bCheckSdrDflt = nullptr != pSdrPool; + } + else if (isGRFATR(nWhich)) + { + aCallMod.Add( mpDfltGrfFormatColl.get() ); + } + else if (isFRMATR(nWhich) || isDrawingLayerAttribute(nWhich) ) + { + aCallMod.Add( mpDfltGrfFormatColl.get() ); + aCallMod.Add( mpDfltTextFormatColl.get() ); + aCallMod.Add( mpDfltFrameFormat.get() ); + } + else if (isBOXATR(nWhich)) + { + aCallMod.Add( mpDfltFrameFormat.get() ); + } + + // also copy the defaults + if( bCheckSdrDflt ) + { + sal_uInt16 nSlotId = GetAttrPool().GetSlotId( nWhich ); + if( 0 != nSlotId && nSlotId != nWhich ) + { + sal_uInt16 nEdtWhich = pSdrPool->GetWhich( nSlotId ); + if( 0 != nEdtWhich && nSlotId != nEdtWhich ) + { + std::unique_ptr<SfxPoolItem> pCpy(pItem->Clone()); + pCpy->SetWhich( nEdtWhich ); + pSdrPool->SetPoolDefaultItem( *pCpy ); + } + } + } + + pItem = aIter.NextItem(); + } while (pItem); + + if( aNew.Count() && aCallMod.HasWriterListeners() ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDefaultAttr>( aOld, *this ) ); + } + + const SvxTabStopItem* pTmpItem = aNew.GetItemIfSet( RES_PARATR_TABSTOP, false ); + if( pTmpItem && pTmpItem->Count() ) + { + // Set the default values of all TabStops to the new value. + // Attention: we always work with the PoolAttribute here, so that + // we don't calculate the same value on the same TabStop (pooled!) for all sets. + // We send a FormatChg to modify. + SwTwips nNewWidth = (*pTmpItem)[ 0 ].GetTabPos(), + nOldWidth = aOld.Get(RES_PARATR_TABSTOP)[ 0 ].GetTabPos(); + + bool bChg = false; + for (const SfxPoolItem* pItem2 : GetAttrPool().GetItemSurrogates(RES_PARATR_TABSTOP)) + { + if(auto pTabStopItem = pItem2->DynamicWhichCast(RES_PARATR_TABSTOP)) + bChg |= lcl_SetNewDefTabStops( nOldWidth, nNewWidth, + *const_cast<SvxTabStopItem*>(pTabStopItem) ); + } + + aNew.ClearItem( RES_PARATR_TABSTOP ); + aOld.ClearItem( RES_PARATR_TABSTOP ); + if( bChg ) + { + SwFormatChg aChgFormat( mpDfltCharFormat.get() ); + // notify the frames + aCallMod.CallSwClientNotify(sw::LegacyModifyHint( &aChgFormat, &aChgFormat )); + } + } + } + + if( aNew.Count() && aCallMod.HasWriterListeners() ) + { + SwAttrSetChg aChgOld( aOld, aOld ); + SwAttrSetChg aChgNew( aNew, aNew ); + aCallMod.CallSwClientNotify(sw::LegacyModifyHint( &aChgOld, &aChgNew )); // all changed are sent + } + + // remove the default formats from the object again + SwIterator<SwClient, sw::BroadcastingModify> aClientIter(aCallMod); + for(SwClient* pClient = aClientIter.First(); pClient; pClient = aClientIter.Next()) + aCallMod.Remove( pClient ); + + getIDocumentState().SetModified(); +} + +/// Get the default attribute in this document +const SfxPoolItem& SwDoc::GetDefault( sal_uInt16 nFormatHint ) const +{ + return GetAttrPool().GetDefaultItem( nFormatHint ); +} + +/// Delete the formats +void SwDoc::DelCharFormat(size_t nFormat, bool bBroadcast) +{ + SwCharFormat * pDel = (*mpCharFormatTable)[nFormat]; + + if (bBroadcast) + BroadcastStyleOperation(pDel->GetName(), SfxStyleFamily::Char, + SfxHintId::StyleSheetErased); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + std::make_unique<SwUndoCharFormatDelete>(pDel, *this)); + } + + delete (*mpCharFormatTable)[nFormat]; + mpCharFormatTable->erase(mpCharFormatTable->begin() + nFormat); + + getIDocumentState().SetModified(); +} + +void SwDoc::DelCharFormat( SwCharFormat const *pFormat, bool bBroadcast ) +{ + size_t nFormat = mpCharFormatTable->GetPos( pFormat ); + OSL_ENSURE( SIZE_MAX != nFormat, "Format not found," ); + DelCharFormat( nFormat, bBroadcast ); +} + +void SwDoc::DelFrameFormat( SwFrameFormat *pFormat, bool bBroadcast ) +{ + if( dynamic_cast<const SwTableBoxFormat*>( pFormat) != nullptr || dynamic_cast<const SwTableLineFormat*>( pFormat) != nullptr ) + { + OSL_ENSURE( false, "Format is not in the DocArray any more, " + "so it can be deleted with delete" ); + delete pFormat; + } + else + { + // The format has to be in the one or the other, we'll see in which one. + if (mpFrameFormatTable->ContainsFormat(pFormat)) + { + if (bBroadcast) + BroadcastStyleOperation(pFormat->GetName(), + SfxStyleFamily::Frame, + SfxHintId::StyleSheetErased); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + std::make_unique<SwUndoFrameFormatDelete>(pFormat, *this)); + } + + mpFrameFormatTable->erase( pFormat ); + delete pFormat; + } + else + { + auto pSpz = static_cast<sw::SpzFrameFormat*>(pFormat); + if(GetSpzFrameFormats()->ContainsFormat(pSpz)) + { + GetSpzFrameFormats()->erase(pSpz); + delete pSpz; + } + else + SAL_WARN("sw", "FrameFormat not found."); + } + } +} + +void SwDoc::DelTableFrameFormat( SwTableFormat *pFormat ) +{ + auto it = mpTableFrameFormatTable->find( pFormat ); + OSL_ENSURE( it != mpTableFrameFormatTable->end(), "Format not found," ); + mpTableFrameFormatTable->erase( it ); + delete pFormat; +} + +SwFrameFormat* SwDoc::FindFrameFormatByName( const OUString& rName ) const +{ + return static_cast<SwFrameFormat*>(mpFrameFormatTable->FindFormatByName(rName)); +} + +/// Create the formats +SwFlyFrameFormat *SwDoc::MakeFlyFrameFormat( const OUString &rFormatName, + SwFrameFormat *pDerivedFrom ) +{ + SwFlyFrameFormat *pFormat = new SwFlyFrameFormat( GetAttrPool(), rFormatName, pDerivedFrom ); + GetSpzFrameFormats()->push_back(pFormat); + getIDocumentState().SetModified(); + return pFormat; +} + +SwDrawFrameFormat *SwDoc::MakeDrawFrameFormat( const OUString &rFormatName, + SwFrameFormat *pDerivedFrom ) +{ + SwDrawFrameFormat *pFormat = new SwDrawFrameFormat( GetAttrPool(), rFormatName, pDerivedFrom); + GetSpzFrameFormats()->push_back(pFormat); + getIDocumentState().SetModified(); + return pFormat; +} + +size_t SwDoc::GetTableFrameFormatCount(bool bUsed) const +{ + if (!bUsed) + return mpTableFrameFormatTable->size(); + return std::count_if(mpTableFrameFormatTable->begin(), mpTableFrameFormatTable->end(), + std::mem_fn(&SwFormat::IsUsed)); +} + +SwTableFormat& SwDoc::GetTableFrameFormat(size_t nFormat, bool bUsed) const +{ + if (!bUsed) + return *const_cast<SwTableFormat*>((*mpTableFrameFormatTable)[nFormat]); + for(SwTableFormat* pFormat: *mpTableFrameFormatTable) + { + if(!pFormat->IsUsed()) + continue; + if(nFormat) + --nFormat; + else + return *pFormat; + } + throw std::out_of_range("Format index out of range."); +} + +SwTableFormat* SwDoc::MakeTableFrameFormat( const OUString &rFormatName, + SwFrameFormat *pDerivedFrom ) +{ + SwTableFormat* pFormat = new SwTableFormat( GetAttrPool(), rFormatName, pDerivedFrom ); + mpTableFrameFormatTable->push_back( pFormat ); + getIDocumentState().SetModified(); + + return pFormat; +} + +SwFrameFormat *SwDoc::MakeFrameFormat(const OUString &rFormatName, + SwFrameFormat *pDerivedFrom, + bool bBroadcast, bool bAuto) +{ + SwFrameFormat *pFormat = new SwFrameFormat( GetAttrPool(), rFormatName, pDerivedFrom ); + + pFormat->SetAuto(bAuto); + mpFrameFormatTable->push_back( pFormat ); + getIDocumentState().SetModified(); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + std::make_unique<SwUndoFrameFormatCreate>(pFormat, pDerivedFrom, *this)); + } + + if (bBroadcast) + { + BroadcastStyleOperation(rFormatName, SfxStyleFamily::Frame, + SfxHintId::StyleSheetCreated); + } + + return pFormat; +} + +SwFormat *SwDoc::MakeFrameFormat_(const OUString &rFormatName, + SwFormat *pDerivedFrom, + bool bBroadcast, bool bAuto) +{ + SwFrameFormat *pFrameFormat = dynamic_cast<SwFrameFormat*>(pDerivedFrom); + pFrameFormat = MakeFrameFormat( rFormatName, pFrameFormat, bBroadcast, bAuto ); + return pFrameFormat; +} + +SwCharFormat *SwDoc::MakeCharFormat( const OUString &rFormatName, + SwCharFormat *pDerivedFrom, + bool bBroadcast ) +{ + SwCharFormat *pFormat = new SwCharFormat( GetAttrPool(), rFormatName, pDerivedFrom ); + mpCharFormatTable->insert( pFormat ); + pFormat->SetAuto(false); + getIDocumentState().SetModified(); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + std::make_unique<SwUndoCharFormatCreate>(pFormat, pDerivedFrom, *this)); + } + + if (bBroadcast) + { + BroadcastStyleOperation(rFormatName, SfxStyleFamily::Char, + SfxHintId::StyleSheetCreated); + } + + return pFormat; +} + +SwFormat *SwDoc::MakeCharFormat_(const OUString &rFormatName, + SwFormat *pDerivedFrom, + bool bBroadcast, bool /*bAuto*/) +{ + SwCharFormat *pCharFormat = dynamic_cast<SwCharFormat*>(pDerivedFrom); + pCharFormat = MakeCharFormat( rFormatName, pCharFormat, bBroadcast ); + return pCharFormat; +} + +/// Create the FormatCollections +SwTextFormatColl* SwDoc::MakeTextFormatColl( const OUString &rFormatName, + SwTextFormatColl *pDerivedFrom, + bool bBroadcast) +{ + SwTextFormatColl *pFormatColl = new SwTextFormatColl( GetAttrPool(), rFormatName, + pDerivedFrom ); + mpTextFormatCollTable->push_back(pFormatColl); + pFormatColl->SetAuto(false); + getIDocumentState().SetModified(); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + std::make_unique<SwUndoTextFormatCollCreate>(pFormatColl, pDerivedFrom, + *this)); + } + + if (bBroadcast) + BroadcastStyleOperation(rFormatName, SfxStyleFamily::Para, + SfxHintId::StyleSheetCreated); + + return pFormatColl; +} + +SwFormat *SwDoc::MakeTextFormatColl_(const OUString &rFormatName, + SwFormat *pDerivedFrom, + bool bBroadcast, bool /*bAuto*/) +{ + SwTextFormatColl *pTextFormatColl = dynamic_cast<SwTextFormatColl*>(pDerivedFrom); + pTextFormatColl = MakeTextFormatColl( rFormatName, pTextFormatColl, bBroadcast ); + return pTextFormatColl; +} + +SwConditionTextFormatColl* SwDoc::MakeCondTextFormatColl( const OUString &rFormatName, + SwTextFormatColl *pDerivedFrom, + bool bBroadcast) +{ + SwConditionTextFormatColl*pFormatColl = new SwConditionTextFormatColl( GetAttrPool(), + rFormatName, pDerivedFrom ); + mpTextFormatCollTable->push_back(pFormatColl); + pFormatColl->SetAuto(false); + getIDocumentState().SetModified(); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + std::make_unique<SwUndoCondTextFormatCollCreate>(pFormatColl, pDerivedFrom, + *this)); + } + + if (bBroadcast) + BroadcastStyleOperation(rFormatName, SfxStyleFamily::Para, + SfxHintId::StyleSheetCreated); + + return pFormatColl; +} + +// GRF +SwGrfFormatColl* SwDoc::MakeGrfFormatColl( const OUString &rFormatName, + SwGrfFormatColl *pDerivedFrom ) +{ + SwGrfFormatColl *pFormatColl = new SwGrfFormatColl( GetAttrPool(), rFormatName, + pDerivedFrom ); + mpGrfFormatCollTable->push_back( pFormatColl ); + pFormatColl->SetAuto(false); + getIDocumentState().SetModified(); + return pFormatColl; +} + +void SwDoc::DelTextFormatColl(size_t nFormatColl, bool bBroadcast) +{ + OSL_ENSURE( nFormatColl, "Remove of Coll 0." ); + + // Who has the to-be-deleted as their Next? + SwTextFormatColl *pDel = (*mpTextFormatCollTable)[nFormatColl]; + if( mpDfltTextFormatColl.get() == pDel ) + return; // never delete default! + + if (bBroadcast) + BroadcastStyleOperation(pDel->GetName(), SfxStyleFamily::Para, + SfxHintId::StyleSheetErased); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + std::unique_ptr<SwUndoTextFormatCollDelete> pUndo; + if (RES_CONDTXTFMTCOLL == pDel->Which()) + { + pUndo.reset(new SwUndoCondTextFormatCollDelete(pDel, *this)); + } + else + { + pUndo.reset(new SwUndoTextFormatCollDelete(pDel, *this)); + } + + GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); + } + + // Remove the FormatColl + mpTextFormatCollTable->erase(mpTextFormatCollTable->begin() + nFormatColl); + // Correct next + for( SwTextFormatColls::const_iterator it = mpTextFormatCollTable->begin() + 1; it != mpTextFormatCollTable->end(); ++it ) + SetTextFormatCollNext( *it, pDel ); + delete pDel; + getIDocumentState().SetModified(); +} + +void SwDoc::DelTextFormatColl( SwTextFormatColl const *pColl, bool bBroadcast ) +{ + size_t nFormat = mpTextFormatCollTable->GetPos( pColl ); + OSL_ENSURE( SIZE_MAX != nFormat, "Collection not found," ); + DelTextFormatColl( nFormat, bBroadcast ); +} + +static bool lcl_SetTextFormatColl( SwNode* pNode, void* pArgs ) +{ + SwContentNode* pCNd = pNode->GetTextNode(); + + if( pCNd == nullptr) + return true; + + sw::DocumentContentOperationsManager::ParaRstFormat* pPara = static_cast<sw::DocumentContentOperationsManager::ParaRstFormat*>(pArgs); + + if (pPara->pLayout && pPara->pLayout->HasMergedParas()) + { + if (pCNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden) + { + return true; + } + if (pCNd->IsTextNode()) + { + pCNd = sw::GetParaPropsNode(*pPara->pLayout, *pCNd); + } + } + + SwTextFormatColl* pFormat = pPara->pFormatColl; + if ( pPara->bReset ) + { + lcl_RstAttr(pCNd, pPara); + + // #i62675# check, if paragraph style has changed + if ( pPara->bResetListAttrs && + pFormat != pCNd->GetFormatColl() && + pFormat->GetItemState( RES_PARATR_NUMRULE ) == SfxItemState::SET ) + { + // Check, if the list style of the paragraph will change. + bool bChangeOfListStyleAtParagraph( true ); + SwTextNode& rTNd(*pCNd->GetTextNode()); + { + SwNumRule* pNumRuleAtParagraph(rTNd.GetNumRule()); + if ( pNumRuleAtParagraph ) + { + const SwNumRuleItem& rNumRuleItemAtParagraphStyle = + pFormat->GetNumRule(); + if ( rNumRuleItemAtParagraphStyle.GetValue() == + pNumRuleAtParagraph->GetName() ) + { + bChangeOfListStyleAtParagraph = false; + } + } + } + + if ( bChangeOfListStyleAtParagraph ) + { + std::unique_ptr< SwRegHistory > pRegH; + if ( pPara->pHistory ) + { + pRegH.reset(new SwRegHistory(&rTNd, rTNd, pPara->pHistory)); + } + + pCNd->ResetAttr( RES_PARATR_NUMRULE ); + + // reset all list attributes + pCNd->ResetAttr( RES_PARATR_LIST_LEVEL ); + pCNd->ResetAttr( RES_PARATR_LIST_ISRESTART ); + pCNd->ResetAttr( RES_PARATR_LIST_RESTARTVALUE ); + pCNd->ResetAttr( RES_PARATR_LIST_ISCOUNTED ); + pCNd->ResetAttr( RES_PARATR_LIST_ID ); + } + else + { + // The List Level must be applied as direct formatting. The spec says: + // 19.495 The style:list-level attribute specifies the list level value + // of a list style that may be applied to any paragraph style. + // It does not directly specify the paragraph's list level value, + // but consumers can change the paragraph's list level value to the specified value + // when the paragraph style is applied. + pCNd->SetAttr(pFormat->GetFormatAttr(RES_PARATR_LIST_LEVEL)); + } + } + } + + // add to History so that old data is saved, if necessary + if( pPara->pHistory ) + pPara->pHistory->AddColl(pCNd->GetFormatColl(), pCNd->GetIndex(), + SwNodeType::Text ); + + pCNd->ChgFormatColl( pFormat ); + + pPara->nWhich++; + + return true; +} + +bool SwDoc::SetTextFormatColl(const SwPaM &rRg, + SwTextFormatColl *pFormat, + const bool bReset, + const bool bResetListAttrs, + SwRootFrame const*const pLayout) +{ + SwDataChanged aTmp( rRg ); + auto [pStt, pEnd] = rRg.StartEnd(); // SwPosition* + SwHistory* pHst = nullptr; + bool bRet = true; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + std::unique_ptr<SwUndoFormatColl> pUndo(new SwUndoFormatColl( rRg, pFormat, + bReset, + bResetListAttrs )); + pHst = pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); + } + + sw::DocumentContentOperationsManager::ParaRstFormat aPara( + pStt, pEnd, pHst, nullptr, pLayout); + aPara.pFormatColl = pFormat; + aPara.bReset = bReset; + // #i62675# + aPara.bResetListAttrs = bResetListAttrs; + + GetNodes().ForEach( pStt->GetNodeIndex(), pEnd->GetNodeIndex()+1, + lcl_SetTextFormatColl, &aPara ); + if( !aPara.nWhich ) + bRet = false; // didn't find a valid Node + + if (bRet) + { + getIDocumentState().SetModified(); + } + + return bRet; +} + +/// Copy the formats to itself +SwFormat* SwDoc::CopyFormat( const SwFormat& rFormat, + const SwFormatsBase& rFormatArr, + FNCopyFormat fnCopyFormat, const SwFormat& rDfltFormat ) +{ + // It's no autoformat, default format or collection format, + // then search for it. + if( !rFormat.IsAuto() || !rFormat.GetRegisteredIn() ) + for( size_t n = 0; n < rFormatArr.GetFormatCount(); ++n ) + { + // Does the Doc already contain the template? + if( rFormatArr.GetFormat(n)->GetName()==rFormat.GetName() ) + return rFormatArr.GetFormat(n); + } + + // Search for the "parent" first + SwFormat* pParent = const_cast<SwFormat*>(&rDfltFormat); + if( rFormat.DerivedFrom() && pParent != rFormat.DerivedFrom() ) + pParent = CopyFormat( *rFormat.DerivedFrom(), rFormatArr, + fnCopyFormat, rDfltFormat ); + + // Create the format and copy the attributes + // #i40550# + SwFormat* pNewFormat = (this->*fnCopyFormat)( rFormat.GetName(), pParent, false, true ); + pNewFormat->SetAuto( rFormat.IsAuto() ); + pNewFormat->CopyAttrs( rFormat ); // copy the attributes + + pNewFormat->SetPoolFormatId( rFormat.GetPoolFormatId() ); + pNewFormat->SetPoolHelpId( rFormat.GetPoolHelpId() ); + + // Always set the HelpFile Id to default! + pNewFormat->SetPoolHlpFileId( UCHAR_MAX ); + + return pNewFormat; +} + +/// copy the frame format +SwFrameFormat* SwDoc::CopyFrameFormat( const SwFrameFormat& rFormat ) +{ + return static_cast<SwFrameFormat*>(CopyFormat( rFormat, *GetFrameFormats(), &SwDoc::MakeFrameFormat_, + *GetDfltFrameFormat() )); +} + +/// copy the char format +SwCharFormat* SwDoc::CopyCharFormat( const SwCharFormat& rFormat ) +{ + return static_cast<SwCharFormat*>(CopyFormat( rFormat, *GetCharFormats(), + &SwDoc::MakeCharFormat_, + *GetDfltCharFormat() )); +} + +/// copy TextNodes +SwTextFormatColl* SwDoc::CopyTextColl( const SwTextFormatColl& rColl ) +{ + SwTextFormatColl* pNewColl = FindTextFormatCollByName( rColl.GetName() ); + if( pNewColl ) + return pNewColl; + + // search for the "parent" first + SwTextFormatColl* pParent = mpDfltTextFormatColl.get(); + if( pParent != rColl.DerivedFrom() ) + pParent = CopyTextColl( *static_cast<SwTextFormatColl*>(rColl.DerivedFrom()) ); + + if( RES_CONDTXTFMTCOLL == rColl.Which() ) + { + pNewColl = new SwConditionTextFormatColl( GetAttrPool(), rColl.GetName(), + pParent); + mpTextFormatCollTable->push_back( pNewColl ); + pNewColl->SetAuto(false); + getIDocumentState().SetModified(); + + // copy the conditions + static_cast<SwConditionTextFormatColl*>(pNewColl)->SetConditions( + static_cast<const SwConditionTextFormatColl&>(rColl).GetCondColls() ); + } + else + pNewColl = MakeTextFormatColl( rColl.GetName(), pParent ); + + // copy the auto formats or the attributes + pNewColl->CopyAttrs( rColl ); + + if(rColl.IsAssignedToListLevelOfOutlineStyle()) + pNewColl->AssignToListLevelOfOutlineStyle(rColl.GetAssignedOutlineStyleLevel()); + pNewColl->SetPoolFormatId( rColl.GetPoolFormatId() ); + pNewColl->SetPoolHelpId( rColl.GetPoolHelpId() ); + + // Always set the HelpFile Id to default! + pNewColl->SetPoolHlpFileId( UCHAR_MAX ); + + if( &rColl.GetNextTextFormatColl() != &rColl ) + pNewColl->SetNextTextFormatColl( *CopyTextColl( rColl.GetNextTextFormatColl() )); + + // create the NumRule if necessary + if( this != rColl.GetDoc() ) + { + const SwNumRuleItem* pItem = pNewColl->GetItemIfSet( RES_PARATR_NUMRULE, + false ); + if( pItem ) + { + const OUString& rName = pItem->GetValue(); + if( !rName.isEmpty() ) + { + const SwNumRule* pRule = rColl.GetDoc()->FindNumRulePtr( rName ); + if( pRule && !pRule->IsAutoRule() ) + { + SwNumRule* pDestRule = FindNumRulePtr( rName ); + if( pDestRule ) + pDestRule->SetInvalidRule( true ); + else + MakeNumRule( rName, pRule ); + } + } + } + } + return pNewColl; +} + +/// copy the graphic nodes +SwGrfFormatColl* SwDoc::CopyGrfColl( const SwGrfFormatColl& rColl ) +{ + SwGrfFormatColl* pNewColl = mpGrfFormatCollTable->FindFormatByName( rColl.GetName() ); + if( pNewColl ) + return pNewColl; + + // Search for the "parent" first + SwGrfFormatColl* pParent = mpDfltGrfFormatColl.get(); + if( pParent != rColl.DerivedFrom() ) + pParent = CopyGrfColl( *static_cast<SwGrfFormatColl*>(rColl.DerivedFrom()) ); + + // if not, copy them + pNewColl = MakeGrfFormatColl( rColl.GetName(), pParent ); + + // copy the attributes + pNewColl->CopyAttrs( rColl ); + + pNewColl->SetPoolFormatId( rColl.GetPoolFormatId() ); + pNewColl->SetPoolHelpId( rColl.GetPoolHelpId() ); + + // Always set the HelpFile Id to default! + pNewColl->SetPoolHlpFileId( UCHAR_MAX ); + + return pNewColl; +} + +void SwDoc::CopyFormatArr( const SwFormatsBase& rSourceArr, + SwFormatsBase const & rDestArr, + FNCopyFormat fnCopyFormat, + SwFormat& rDfltFormat ) +{ + SwFormat* pSrc, *pDest; + + // 1st step: Create all formats (skip the 0th - it's the default one) + for( size_t nSrc = rSourceArr.GetFormatCount(); nSrc > 1; ) + { + pSrc = rSourceArr.GetFormat( --nSrc ); + if( pSrc->IsDefault() || pSrc->IsAuto() ) + continue; + + if( nullptr == rDestArr.FindFormatByName( pSrc->GetName() ) ) + { + if( RES_CONDTXTFMTCOLL == pSrc->Which() ) + MakeCondTextFormatColl( pSrc->GetName(), static_cast<SwTextFormatColl*>(&rDfltFormat) ); + else + // #i40550# + (this->*fnCopyFormat)( pSrc->GetName(), &rDfltFormat, false, true ); + } + } + + // 2nd step: Copy all attributes, set the right parents + for( size_t nSrc = rSourceArr.GetFormatCount(); nSrc > 1; ) + { + pSrc = rSourceArr.GetFormat( --nSrc ); + if( pSrc->IsDefault() || pSrc->IsAuto() ) + continue; + + pDest = rDestArr.FindFormatByName( pSrc->GetName() ); + pDest->SetAuto(false); + pDest->DelDiffs( *pSrc ); + + // #i94285#: existing <SwFormatPageDesc> instance, before copying attributes + const SwFormatPageDesc* pItem; + if( &GetAttrPool() != pSrc->GetAttrSet().GetPool() + && (pItem = pSrc->GetAttrSet().GetItemIfSet( RES_PAGEDESC, false )) + && pItem->GetPageDesc() ) + { + SwFormatPageDesc aPageDesc( *pItem ); + const OUString& rNm = aPageDesc.GetPageDesc()->GetName(); + SwPageDesc* pPageDesc = FindPageDesc( rNm ); + if( !pPageDesc ) + { + pPageDesc = MakePageDesc(rNm); + } + aPageDesc.RegisterToPageDesc( *pPageDesc ); + SwAttrSet aTmpAttrSet( pSrc->GetAttrSet() ); + aTmpAttrSet.Put( aPageDesc ); + pDest->SetFormatAttr( aTmpAttrSet ); + } + else + { + pDest->SetFormatAttr( pSrc->GetAttrSet() ); + } + + pDest->SetPoolFormatId( pSrc->GetPoolFormatId() ); + pDest->SetPoolHelpId( pSrc->GetPoolHelpId() ); + + // Always set the HelpFile Id to default! + pDest->SetPoolHlpFileId( UCHAR_MAX ); + + if( pSrc->DerivedFrom() ) + pDest->SetDerivedFrom( rDestArr.FindFormatByName( + pSrc->DerivedFrom()->GetName() ) ); + if( RES_TXTFMTCOLL == pSrc->Which() || + RES_CONDTXTFMTCOLL == pSrc->Which() ) + { + SwTextFormatColl* pSrcColl = static_cast<SwTextFormatColl*>(pSrc), + * pDstColl = static_cast<SwTextFormatColl*>(pDest); + if( &pSrcColl->GetNextTextFormatColl() != pSrcColl ) + pDstColl->SetNextTextFormatColl( + *static_cast<SwTextFormatColl*>(rDestArr.FindFormatByName( pSrcColl->GetNextTextFormatColl().GetName() )) ); + + if(pSrcColl->IsAssignedToListLevelOfOutlineStyle()) + pDstColl->AssignToListLevelOfOutlineStyle(pSrcColl->GetAssignedOutlineStyleLevel()); + + if( RES_CONDTXTFMTCOLL == pSrc->Which() ) + { + if (pDstColl->Which() != RES_CONDTXTFMTCOLL) + { + // Target already had a style with a matching name, but it's not a conditional + // style, then don't copy the conditions. + continue; + } + + // Copy the conditions, but delete the old ones first! + static_cast<SwConditionTextFormatColl*>(pDstColl)->SetConditions( + static_cast<SwConditionTextFormatColl*>(pSrc)->GetCondColls() ); + } + } + } +} + +void SwDoc::CopyPageDescHeaderFooterImpl( bool bCpyHeader, + const SwFrameFormat& rSrcFormat, SwFrameFormat& rDestFormat ) +{ + // Treat the header and footer attributes in the right way: + // Copy content nodes across documents! + sal_uInt16 nAttr = bCpyHeader ? sal_uInt16(RES_HEADER) : sal_uInt16(RES_FOOTER); + const SfxPoolItem* pItem; + if( SfxItemState::SET != rSrcFormat.GetAttrSet().GetItemState( nAttr, false, &pItem )) + return ; + + // The header only contains the reference to the format from the other document! + std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone()); + + SwFrameFormat* pOldFormat; + if( bCpyHeader ) + pOldFormat = pNewItem->StaticWhichCast(RES_HEADER).GetHeaderFormat(); + else + pOldFormat = pNewItem->StaticWhichCast(RES_FOOTER).GetFooterFormat(); + + if( !pOldFormat ) + return; + + SwFrameFormat* pNewFormat = new SwFrameFormat( GetAttrPool(), "CpyDesc", + GetDfltFrameFormat() ); + pNewFormat->CopyAttrs( *pOldFormat ); + + if( const SwFormatContent* pContent = pNewFormat->GetAttrSet().GetItemIfSet( + RES_CNTNT, false ) ) + { + if( pContent->GetContentIdx() ) + { + const SwNodes& rSrcNds = rSrcFormat.GetDoc()->GetNodes(); + SwStartNode* pSttNd = SwNodes::MakeEmptySection( GetNodes().GetEndOfAutotext(), + bCpyHeader + ? SwHeaderStartNode + : SwFooterStartNode ); + const SwNode& rCSttNd = pContent->GetContentIdx()->GetNode(); + SwNodeRange aRg( rCSttNd, SwNodeOffset(0), *rCSttNd.EndOfSectionNode() ); + rSrcNds.Copy_( aRg, *pSttNd->EndOfSectionNode() ); + rSrcFormat.GetDoc()->GetDocumentContentOperationsManager().CopyFlyInFlyImpl(aRg, nullptr, *pSttNd); + // TODO: investigate calling CopyWithFlyInFly? + SwPaM const source(aRg.aStart, aRg.aEnd); + SwPosition dest(*pSttNd); + sw::CopyBookmarks(source, dest); + pNewFormat->SetFormatAttr( SwFormatContent( pSttNd )); + } + else + pNewFormat->ResetFormatAttr( RES_CNTNT ); + } + if( bCpyHeader ) + pNewItem->StaticWhichCast(RES_HEADER).RegisterToFormat(*pNewFormat); + else + pNewItem->StaticWhichCast(RES_FOOTER).RegisterToFormat(*pNewFormat); + rDestFormat.SetFormatAttr( *pNewItem ); +} + +void SwDoc::CopyPageDesc( const SwPageDesc& rSrcDesc, SwPageDesc& rDstDesc, + bool bCopyPoolIds ) +{ + bool bNotifyLayout = false; + SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout(); + + rDstDesc.SetLandscape( rSrcDesc.GetLandscape() ); + rDstDesc.SetNumType( rSrcDesc.GetNumType() ); + if( rDstDesc.ReadUseOn() != rSrcDesc.ReadUseOn() ) + { + rDstDesc.WriteUseOn( rSrcDesc.ReadUseOn() ); + bNotifyLayout = true; + } + + if( bCopyPoolIds ) + { + rDstDesc.SetPoolFormatId( rSrcDesc.GetPoolFormatId() ); + rDstDesc.SetPoolHelpId( rSrcDesc.GetPoolHelpId() ); + // Always set the HelpFile Id to default! + rDstDesc.SetPoolHlpFileId( UCHAR_MAX ); + } + + if( rSrcDesc.GetFollow() != &rSrcDesc ) + { + const SwPageDesc* pSrcFollow = rSrcDesc.GetFollow(); + SwPageDesc* pFollow = FindPageDesc( pSrcFollow->GetName() ); + if( !pFollow ) + { + // copy + pFollow = MakePageDesc( pSrcFollow->GetName() ); + CopyPageDesc( *pSrcFollow, *pFollow ); + } + rDstDesc.SetFollow( pFollow ); + bNotifyLayout = true; + } + + // the header and footer attributes are copied separately + // the content sections have to be copied in their entirety + { + SfxItemSet aAttrSet( rSrcDesc.GetMaster().GetAttrSet() ); + aAttrSet.ClearItem( RES_HEADER ); + aAttrSet.ClearItem( RES_FOOTER ); + + rDstDesc.GetMaster().DelDiffs( aAttrSet ); + rDstDesc.GetMaster().SetFormatAttr( aAttrSet ); + + aAttrSet.ClearItem(); + aAttrSet.Put( rSrcDesc.GetLeft().GetAttrSet() ); + aAttrSet.ClearItem( RES_HEADER ); + aAttrSet.ClearItem( RES_FOOTER ); + + rDstDesc.GetLeft().DelDiffs( aAttrSet ); + rDstDesc.GetLeft().SetFormatAttr( aAttrSet ); + + aAttrSet.ClearItem(); + aAttrSet.Put( rSrcDesc.GetFirstMaster().GetAttrSet() ); + aAttrSet.ClearItem( RES_HEADER ); + aAttrSet.ClearItem( RES_FOOTER ); + + rDstDesc.GetFirstMaster().DelDiffs( aAttrSet ); + rDstDesc.GetFirstMaster().SetFormatAttr( aAttrSet ); + + aAttrSet.ClearItem(); + aAttrSet.Put( rSrcDesc.GetFirstLeft().GetAttrSet() ); + aAttrSet.ClearItem( RES_HEADER ); + aAttrSet.ClearItem( RES_FOOTER ); + + rDstDesc.GetFirstLeft().DelDiffs( aAttrSet ); + rDstDesc.GetFirstLeft().SetFormatAttr( aAttrSet ); + } + + CopyHeader( rSrcDesc.GetMaster(), rDstDesc.GetMaster() ); + CopyFooter( rSrcDesc.GetMaster(), rDstDesc.GetMaster() ); + if( !rDstDesc.IsHeaderShared() ) + CopyHeader( rSrcDesc.GetLeft(), rDstDesc.GetLeft() ); + else + rDstDesc.GetLeft().SetFormatAttr( rDstDesc.GetMaster().GetHeader() ); + if( !rDstDesc.IsFirstShared() ) + { + CopyHeader( rSrcDesc.GetFirstMaster(), rDstDesc.GetFirstMaster() ); + rDstDesc.GetFirstLeft().SetFormatAttr(rDstDesc.GetFirstMaster().GetHeader()); + } + else + { + rDstDesc.GetFirstMaster().SetFormatAttr( rDstDesc.GetMaster().GetHeader() ); + rDstDesc.GetFirstLeft().SetFormatAttr(rDstDesc.GetLeft().GetHeader()); + } + + if( !rDstDesc.IsFooterShared() ) + CopyFooter( rSrcDesc.GetLeft(), rDstDesc.GetLeft() ); + else + rDstDesc.GetLeft().SetFormatAttr( rDstDesc.GetMaster().GetFooter() ); + if( !rDstDesc.IsFirstShared() ) + { + CopyFooter( rSrcDesc.GetFirstMaster(), rDstDesc.GetFirstMaster() ); + rDstDesc.GetFirstLeft().SetFormatAttr(rDstDesc.GetFirstMaster().GetFooter()); + } + else + { + rDstDesc.GetFirstMaster().SetFormatAttr( rDstDesc.GetMaster().GetFooter() ); + rDstDesc.GetFirstLeft().SetFormatAttr(rDstDesc.GetLeft().GetFooter()); + } + + if( bNotifyLayout && pTmpRoot ) + { + for( auto aLayout : GetAllLayouts() ) + aLayout->AllCheckPageDescs(); + } + + // If foot notes change the pages have to be triggered + if( !(rDstDesc.GetFootnoteInfo() == rSrcDesc.GetFootnoteInfo()) ) + { + sw::PageFootnoteHint aHint; + rDstDesc.SetFootnoteInfo( rSrcDesc.GetFootnoteInfo() ); + rDstDesc.GetMaster().CallSwClientNotify(aHint); + rDstDesc.GetLeft().CallSwClientNotify(aHint); + rDstDesc.GetFirstMaster().CallSwClientNotify(aHint); + rDstDesc.GetFirstLeft().CallSwClientNotify(aHint); + } + + // Copy the stashed formats as well between the page descriptors... + for (bool bFirst : { true, false }) + { + for (bool bLeft : { true, false }) + { + for (bool bHeader : { true, false }) + { + if (!bLeft && !bFirst) + continue; + + // Copy format only if it exists + if (auto pStashedFormatSrc = rSrcDesc.GetStashedFrameFormat(bHeader, bLeft, bFirst)) + { + if (pStashedFormatSrc->GetDoc() != this) + { + SwFrameFormat* pNewFormat = new SwFrameFormat(GetAttrPool(), "CopyDesc", GetDfltFrameFormat()); + + SfxItemSet aAttrSet(pStashedFormatSrc->GetAttrSet()); + aAttrSet.ClearItem(RES_HEADER); + aAttrSet.ClearItem(RES_FOOTER); + + pNewFormat->DelDiffs( aAttrSet ); + pNewFormat->SetFormatAttr( aAttrSet ); + + if (bHeader) + CopyHeader(*pStashedFormatSrc, *pNewFormat); + else + CopyFooter(*pStashedFormatSrc, *pNewFormat); + + rDstDesc.StashFrameFormat(*pNewFormat, bHeader, bLeft, bFirst); + } + else + { + rDstDesc.StashFrameFormat(*pStashedFormatSrc, bHeader, bLeft, bFirst); + } + } + } + } + } +} + +void SwDoc::ReplaceStyles( const SwDoc& rSource, bool bIncludePageStyles ) +{ + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + CopyFormatArr( *rSource.mpCharFormatTable, *mpCharFormatTable, + &SwDoc::MakeCharFormat_, *mpDfltCharFormat ); + CopyFormatArr( *rSource.mpFrameFormatTable, *mpFrameFormatTable, + &SwDoc::MakeFrameFormat_, *mpDfltFrameFormat ); + CopyFormatArr( *rSource.mpTextFormatCollTable, *mpTextFormatCollTable, + &SwDoc::MakeTextFormatColl_, *mpDfltTextFormatColl ); + + //To-Do: + // a) in sd rtf import (View::InsertData) don't use + // a super-fragile test for mere presence of \trowd to + // indicate import of rtf into a table + // b) then drop use of bIncludePageStyles + if (bIncludePageStyles) + { + // and now the page templates + SwPageDescs::size_type nCnt = rSource.m_PageDescs.size(); + if( nCnt ) + { + // a different Doc -> Number formatter needs to be merged + SwTableNumFormatMerge aTNFM( rSource, *this ); + + // 1st step: Create all formats (skip the 0th - it's the default!) + while( nCnt ) + { + const SwPageDesc &rSrc = *rSource.m_PageDescs[ --nCnt ]; + if( nullptr == FindPageDesc( rSrc.GetName() ) ) + MakePageDesc( rSrc.GetName() ); + } + + // 2nd step: Copy all attributes, set the right parents + for (SwPageDescs::size_type i = rSource.m_PageDescs.size(); i; ) + { + const SwPageDesc &rSrc = *rSource.m_PageDescs[ --i ]; + SwPageDesc* pDesc = FindPageDesc( rSrc.GetName() ); + CopyPageDesc( rSrc, *pDesc); + } + } + } + + // then there are the numbering templates + const SwNumRuleTable::size_type nCnt = rSource.GetNumRuleTable().size(); + if( nCnt ) + { + const SwNumRuleTable& rArr = rSource.GetNumRuleTable(); + for( SwNumRuleTable::size_type n = 0; n < nCnt; ++n ) + { + const SwNumRule& rR = *rArr[ n ]; + SwNumRule* pNew = FindNumRulePtr( rR.GetName()); + if( pNew ) + pNew->CopyNumRule(*this, rR); + else + { + if( !rR.IsAutoRule() ) + MakeNumRule( rR.GetName(), &rR ); + else + { + // as we reset all styles, there shouldn't be any unknown + // automatic SwNumRules, because all should have been + // created by the style copying! + // So just warn and ignore. + SAL_WARN( "sw.core", "Found unknown auto SwNumRule during reset!" ); + } + } + } + } + + if (undoGuard.UndoWasEnabled()) + { + // nodes array was modified! + GetIDocumentUndoRedo().DelAllUndoObj(); + } + + getIDocumentState().SetModified(); +} + +void SwDoc::MoveLeftMargin(const SwPaM& rPam, bool bRight, bool bModulus, + SwRootFrame const*const pLayout) +{ + SwHistory* pHistory = nullptr; + if (GetIDocumentUndoRedo().DoesUndo()) + { + std::unique_ptr<SwUndoMoveLeftMargin> pUndo(new SwUndoMoveLeftMargin( rPam, bRight, + bModulus )); + pHistory = &pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) ); + } + + const SvxTabStopItem& rTabItem = GetDefault( RES_PARATR_TABSTOP ); + const sal_Int32 nDefDist = rTabItem.Count() ? rTabItem[0].GetTabPos() : 1134; + const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End(); + SwNodeIndex aIdx( rStt.GetNode() ); + while( aIdx <= rEnd.GetNode() ) + { + SwTextNode* pTNd = aIdx.GetNode().GetTextNode(); + if( pTNd ) + { + pTNd = sw::GetParaPropsNode(*pLayout, aIdx.GetNode()); + SvxFirstLineIndentItem firstLine(pTNd->SwContentNode::GetAttr(RES_MARGIN_FIRSTLINE)); + SvxTextLeftMarginItem leftMargin(pTNd->SwContentNode::GetAttr(RES_MARGIN_TEXTLEFT)); + + // #i93873# See also lcl_MergeListLevelIndentAsLRSpaceItem in thints.cxx + ::sw::ListLevelIndents const indents(pTNd->AreListLevelIndentsApplicable()); + if (indents != ::sw::ListLevelIndents::No) + { + const SwNumRule* pRule = pTNd->GetNumRule(); + if ( pRule ) + { + const int nListLevel = pTNd->GetActualListLevel(); + if ( nListLevel >= 0 ) + { + const SwNumFormat& rFormat = pRule->Get(o3tl::narrowing<sal_uInt16>(nListLevel)); + if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) + { + if (indents & ::sw::ListLevelIndents::LeftMargin) + { + leftMargin.SetTextLeft(rFormat.GetIndentAt()); + } + if (indents & ::sw::ListLevelIndents::FirstLine) + { + firstLine.SetTextFirstLineOffset(static_cast<short>(rFormat.GetFirstLineIndent())); + } + } + } + } + } + + tools::Long nNext = leftMargin.GetTextLeft(); + if( bModulus ) + nNext = ( nNext / nDefDist ) * nDefDist; + + if( bRight ) + nNext += nDefDist; + else + if(nNext >0) // fdo#75936 set limit for decreasing indent + nNext -= nDefDist; + + leftMargin.SetTextLeft( nNext ); + + SwRegHistory aRegH( pTNd, *pTNd, pHistory ); + pTNd->SetAttr(firstLine); + pTNd->SetAttr(leftMargin); + aIdx = *sw::GetFirstAndLastNode(*pLayout, aIdx.GetNode()).second; + } + ++aIdx; + } + getIDocumentState().SetModified(); +} + +bool SwDoc::DontExpandFormat( const SwPosition& rPos, bool bFlag ) +{ + bool bRet = false; + SwTextNode* pTextNd = rPos.GetNode().GetTextNode(); + if( pTextNd ) + { + bRet = pTextNd->DontExpandFormat( rPos.GetContentIndex(), bFlag ); + if( bRet && GetIDocumentUndoRedo().DoesUndo() ) + { + GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDontExpandFormat>(rPos) ); + } + } + return bRet; +} + +SwTableBoxFormat* SwDoc::MakeTableBoxFormat() +{ + SwTableBoxFormat* pFormat = new SwTableBoxFormat( GetAttrPool(), mpDfltFrameFormat.get() ); + pFormat->SetFormatName("TableBox" + OUString::number(reinterpret_cast<sal_IntPtr>(pFormat))); + getIDocumentState().SetModified(); + return pFormat; +} + +SwTableLineFormat* SwDoc::MakeTableLineFormat() +{ + SwTableLineFormat* pFormat = new SwTableLineFormat( GetAttrPool(), mpDfltFrameFormat.get() ); + pFormat->SetFormatName("TableLine" + OUString::number(reinterpret_cast<sal_IntPtr>(pFormat))); + getIDocumentState().SetModified(); + return pFormat; +} + +void SwDoc::EnsureNumberFormatter() +{ + if (mpNumberFormatter == nullptr) + { + LanguageType eLang = LANGUAGE_SYSTEM; + mpNumberFormatter = new SvNumberFormatter(comphelper::getProcessComponentContext(), eLang); + mpNumberFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT_INTL ); + if (!utl::ConfigManager::IsFuzzing()) + mpNumberFormatter->SetYear2000( + officecfg::Office::Common::DateFormat::TwoDigitYear::get()); + }; +} + +SwTableNumFormatMerge::SwTableNumFormatMerge( const SwDoc& rSrc, SwDoc& rDest ) + : pNFormat( nullptr ) +{ + // a different Doc -> Number formatter needs to be merged + if( &rSrc != &rDest ) + { + SvNumberFormatter* pN = const_cast<SwDoc&>(rSrc).GetNumberFormatter( false ); + if( pN ) + { + pNFormat = rDest.GetNumberFormatter(); + pNFormat->MergeFormatter( *pN ); + } + } + + if( &rSrc != &rDest ) + static_cast<SwGetRefFieldType*>(rSrc.getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::GetRef ))-> + MergeWithOtherDoc( rDest ); +} + +SwTableNumFormatMerge::~SwTableNumFormatMerge() +{ + if( pNFormat ) + pNFormat->ClearMergeTable(); +} + +void SwDoc::SetTextFormatCollByAutoFormat( const SwPosition& rPos, sal_uInt16 nPoolId, + const SfxItemSet* pSet ) +{ + SwPaM aPam( rPos ); + SwTextNode* pTNd = rPos.GetNode().GetTextNode(); + assert(pTNd); + + if (mbIsAutoFormatRedline) + { + // create the redline object + const SwTextFormatColl& rColl = *pTNd->GetTextColl(); + SwRangeRedline* pRedl = new SwRangeRedline( RedlineType::FmtColl, aPam ); + pRedl->SetMark(); + + // Only those items that are not set by the Set again in the Node + // are of interest. Thus, we take the difference. + SwRedlineExtraData_FormatColl aExtraData( rColl.GetName(), + rColl.GetPoolFormatId() ); + if( pSet && pTNd->HasSwAttrSet() ) + { + SfxItemSet aTmp( *pTNd->GetpSwAttrSet() ); + aTmp.Differentiate( *pSet ); + // we handle the adjust item separately + const SfxPoolItem* pItem; + if( SfxItemState::SET == pTNd->GetpSwAttrSet()->GetItemState( + RES_PARATR_ADJUST, false, &pItem )) + aTmp.Put( *pItem ); + aExtraData.SetItemSet( aTmp ); + } + pRedl->SetExtraData( &aExtraData ); + + //TODO: Undo is still missing! + getIDocumentRedlineAccess().AppendRedline( pRedl, true ); + } + + SetTextFormatColl( aPam, getIDocumentStylePoolAccess().GetTextCollFromPool( nPoolId ) ); + + if (pSet && pSet->Count()) + { + aPam.SetMark(); + aPam.GetMark()->SetContent(pTNd->GetText().getLength()); + // sw_redlinehide: don't need layout currently because the only caller + // passes in the properties node + assert(static_cast<SwTextFrame const*>(pTNd->getLayoutFrame(nullptr))->GetTextNodeForParaProps() == pTNd); + getIDocumentContentOperations().InsertItemSet( aPam, *pSet ); + } +} + +void SwDoc::SetFormatItemByAutoFormat( const SwPaM& rPam, const SfxItemSet& rSet ) +{ + SwTextNode* pTNd = rPam.GetPoint()->GetNode().GetTextNode(); + assert(pTNd); + + RedlineFlags eOld = getIDocumentRedlineAccess().GetRedlineFlags(); + + if (mbIsAutoFormatRedline) + { + // create the redline object + SwRangeRedline* pRedl = new SwRangeRedline( RedlineType::Format, rPam ); + if( !pRedl->HasMark() ) + pRedl->SetMark(); + + // Only those items that are not set by the Set again in the Node + // are of interest. Thus, we take the difference. + SwRedlineExtraData_Format aExtraData( rSet ); + + pRedl->SetExtraData( &aExtraData ); + + //TODO: Undo is still missing! + getIDocumentRedlineAccess().AppendRedline( pRedl, true ); + + getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld | RedlineFlags::Ignore ); + } + + const sal_Int32 nEnd(rPam.End()->GetContentIndex()); + std::vector<WhichPair> whichIds; + SfxItemIter iter(rSet); + for (SfxPoolItem const* pItem = iter.GetCurItem(); pItem; pItem = iter.NextItem()) + { + whichIds.push_back({pItem->Which(), pItem->Which()}); + } + SfxItemSet currentSet(GetAttrPool(), WhichRangesContainer(whichIds.data(), whichIds.size())); + pTNd->GetParaAttr(currentSet, nEnd, nEnd); + for (const WhichPair& rPair : whichIds) + { // yuk - want to explicitly set the pool defaults too :-/ + currentSet.Put(currentSet.Get(rPair.first)); + } + + getIDocumentContentOperations().InsertItemSet( rPam, rSet, SetAttrMode::DONTEXPAND ); + + // fdo#62536: DONTEXPAND does not work when there is already an AUTOFMT + // here, so insert the old attributes as an empty hint to stop expand + SwPaM endPam(*pTNd, nEnd); + endPam.SetMark(); + getIDocumentContentOperations().InsertItemSet(endPam, currentSet); + + getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); +} + +void SwDoc::ChgFormat(SwFormat & rFormat, const SfxItemSet & rSet) +{ + if (GetIDocumentUndoRedo().DoesUndo()) + { + // copying <rSet> to <aSet> + SfxItemSet aSet(rSet); + // remove from <aSet> all items, which are already set at the format + aSet.Differentiate(rFormat.GetAttrSet()); + // <aSet> contains now all *new* items for the format + + // copying current format item set to <aOldSet> + SfxItemSet aOldSet(rFormat.GetAttrSet()); + // insert new items into <aOldSet> + aOldSet.Put(aSet); + // invalidate all new items in <aOldSet> in order to clear these items, + // if the undo action is triggered. + { + SfxItemIter aIter(aSet); + + for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + { + aOldSet.InvalidateItem(pItem->Which()); + } + } + + GetIDocumentUndoRedo().AppendUndo( + std::make_unique<SwUndoFormatAttr>(std::move(aOldSet), rFormat, /*bSaveDrawPt*/true)); + } + + rFormat.SetFormatAttr(rSet); +} + +void SwDoc::RenameFormat(SwFormat & rFormat, const OUString & sNewName, + bool bBroadcast) +{ + SfxStyleFamily eFamily = SfxStyleFamily::All; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + std::unique_ptr<SwUndo> pUndo; + + switch (rFormat.Which()) + { + case RES_CHRFMT: + pUndo.reset(new SwUndoRenameCharFormat(rFormat.GetName(), sNewName, *this)); + eFamily = SfxStyleFamily::Char; + break; + case RES_TXTFMTCOLL: + pUndo.reset(new SwUndoRenameFormatColl(rFormat.GetName(), sNewName, *this)); + eFamily = SfxStyleFamily::Para; + break; + case RES_FRMFMT: + pUndo.reset(new SwUndoRenameFrameFormat(rFormat.GetName(), sNewName, *this)); + eFamily = SfxStyleFamily::Frame; + break; + + default: + break; + } + + if (pUndo) + { + GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); + } + } + + // name change means the o3tl::sorted_array is not property sorted + if (rFormat.Which() == RES_CHRFMT) + mpCharFormatTable->SetFormatNameAndReindex(static_cast<SwCharFormat*>(&rFormat), sNewName); + else + rFormat.SetFormatName(sNewName); + + if (bBroadcast) + BroadcastStyleOperation(sNewName, eFamily, SfxHintId::StyleSheetModified); +} + +void SwDoc::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + bool bOwns = false; + if (!pWriter) + { + pWriter = xmlNewTextWriterFilename("nodes.xml", 0); + xmlTextWriterSetIndent(pWriter,1); + (void)xmlTextWriterSetIndentString(pWriter, BAD_CAST(" ")); + (void)xmlTextWriterStartDocument(pWriter, nullptr, nullptr, nullptr); + bOwns = true; + } + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwDoc")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + + m_pNodes->dumpAsXml(pWriter); + m_PageDescs.dumpAsXml(pWriter); + maDBData.dumpAsXml(pWriter); + mpMarkManager->dumpAsXml(pWriter); + m_pContentControlManager->dumpAsXml(pWriter); + m_pUndoManager->dumpAsXml(pWriter); + m_pDocumentSettingManager->dumpAsXml(pWriter); + getIDocumentFieldsAccess().GetFieldTypes()->dumpAsXml(pWriter); + mpTextFormatCollTable->dumpAsXml(pWriter); + mpCharFormatTable->dumpAsXml(pWriter); + mpFrameFormatTable->dumpAsXml(pWriter, "frmFormatTable"); + mpSpzFrameFormatTable->dumpAsXml(pWriter, "spzFrameFormatTable"); + mpSectionFormatTable->dumpAsXml(pWriter); + mpTableFrameFormatTable->dumpAsXml(pWriter, "tableFrameFormatTable"); + mpNumRuleTable->dumpAsXml(pWriter); + getIDocumentRedlineAccess().GetRedlineTable().dumpAsXml(pWriter); + getIDocumentRedlineAccess().GetExtraRedlineTable().dumpAsXml(pWriter); + if (const SdrModel* pModel = getIDocumentDrawModelAccess().GetDrawModel()) + pModel->dumpAsXml(pWriter); + + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("mbModified")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(getIDocumentState().IsModified()).getStr())); + (void)xmlTextWriterEndElement(pWriter); + + (void)xmlTextWriterEndElement(pWriter); + if (bOwns) + { + (void)xmlTextWriterEndDocument(pWriter); + xmlFreeTextWriter(pWriter); + } +} + +void SwDBData::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwDBData")); + + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("sDataSource"), BAD_CAST(sDataSource.toUtf8().getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("sCommand"), BAD_CAST(sCommand.toUtf8().getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nCommandType"), BAD_CAST(OString::number(nCommandType).getStr())); + + (void)xmlTextWriterEndElement(pWriter); +} + +std::set<Color> SwDoc::GetDocColors() +{ + std::set<Color> aDocColors; + SwAttrPool& rPool = GetAttrPool(); + const sal_uInt16 pAttribs[] = {RES_CHRATR_COLOR, RES_CHRATR_HIGHLIGHT, RES_BACKGROUND}; + for (sal_uInt16 nAttrib : pAttribs) + { + for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(nAttrib)) + { + auto pColorItem = static_cast<const SvxColorItem*>(pItem); + Color aColor( pColorItem->GetValue() ); + if (COL_AUTO != aColor) + aDocColors.insert(aColor); + } + } + return aDocColors; +} + +// #i69627# +namespace docfunc +{ + bool HasOutlineStyleToBeWrittenAsNormalListStyle( SwDoc& rDoc ) + { + // If a parent paragraph style of one of the paragraph styles, which + // are assigned to the list levels of the outline style, has a list style + // set or inherits a list style from its parent style, the outline style + // has to be written as a normal list style to the OpenDocument file + // format or the OpenOffice.org file format. + bool bRet( false ); + + const SwTextFormatColls* pTextFormatColls( rDoc.GetTextFormatColls() ); + if ( pTextFormatColls ) + { + for ( auto pTextFormatColl : *pTextFormatColls ) + { + if ( pTextFormatColl->IsDefault() || + ! pTextFormatColl->IsAssignedToListLevelOfOutlineStyle() ) + { + continue; + } + + const SwTextFormatColl* pParentTextFormatColl = + dynamic_cast<const SwTextFormatColl*>( pTextFormatColl->DerivedFrom()); + if ( !pParentTextFormatColl ) + continue; + + if ( SfxItemState::SET == pParentTextFormatColl->GetItemState( RES_PARATR_NUMRULE ) ) + { + // #i106218# consider that the outline style is set + const SwNumRuleItem& rDirectItem = pParentTextFormatColl->GetNumRule(); + if ( rDirectItem.GetValue() != rDoc.GetOutlineNumRule()->GetName() ) + { + bRet = true; + break; + } + } + } + + } + return bRet; + } +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |