From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- sw/source/core/undo/rolbck.cxx | 1485 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1485 insertions(+) create mode 100644 sw/source/core/undo/rolbck.cxx (limited to 'sw/source/core/undo/rolbck.cxx') diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx new file mode 100644 index 000000000..206ad9343 --- /dev/null +++ b/sw/source/core/undo/rolbck.cxx @@ -0,0 +1,1485 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +OUString SwHistoryHint::GetDescription() const +{ + return OUString(); +} + +SwHistorySetFormat::SwHistorySetFormat( const SfxPoolItem* pFormatHt, sal_uLong nNd ) + : SwHistoryHint( HSTRY_SETFMTHNT ) + , m_pAttr( pFormatHt->Clone() ) + , m_nNodeIndex( nNd ) +{ + switch ( m_pAttr->Which() ) + { + case RES_PAGEDESC: + static_cast(*m_pAttr).ChgDefinedIn( nullptr ); + break; + case RES_PARATR_DROP: + static_cast(*m_pAttr).ChgDefinedIn( nullptr ); + break; + case RES_BOXATR_FORMULA: + { + // save formulas always in plain text + SwTableBoxFormula& rNew = static_cast(*m_pAttr); + if ( rNew.IsIntrnlName() ) + { + const SwTableBoxFormula& rOld = + *static_cast(pFormatHt); + const SwNode* pNd = rOld.GetNodeOfFormula(); + if ( pNd ) + { + const SwTableNode* pTableNode = pNd->FindTableNode(); + if (pTableNode) + { + SwTableFormulaUpdate aMsgHint( &pTableNode->GetTable() ); + aMsgHint.m_eFlags = TBL_BOXNAME; + rNew.ChgDefinedIn( rOld.GetDefinedIn() ); + rNew.ChangeState( &aMsgHint ); + } + } + } + rNew.ChgDefinedIn( nullptr ); + } + break; + } +} + +OUString SwHistorySetFormat::GetDescription() const +{ + OUString aResult; + + switch (m_pAttr->Which()) + { + case RES_BREAK: + switch (static_cast(*m_pAttr).GetBreak()) + { + case SvxBreak::PageBefore: + case SvxBreak::PageAfter: + case SvxBreak::PageBoth: + aResult = SwResId(STR_UNDO_PAGEBREAKS); + + break; + case SvxBreak::ColumnBefore: + case SvxBreak::ColumnAfter: + case SvxBreak::ColumnBoth: + aResult = SwResId(STR_UNDO_COLBRKS); + + break; + default: + break; + } + break; + default: + break; + } + + return aResult; +} + +void SwHistorySetFormat::SetInDoc( SwDoc* pDoc, bool bTmpSet ) +{ + SwNode * pNode = pDoc->GetNodes()[ m_nNodeIndex ]; + if ( pNode->IsContentNode() ) + { + static_cast(pNode)->SetAttr( *m_pAttr ); + } + else if ( pNode->IsTableNode() ) + { + static_cast(pNode)->GetTable().GetFrameFormat()->SetFormatAttr( + *m_pAttr ); + } + else if ( pNode->IsStartNode() && (SwTableBoxStartNode == + static_cast(pNode)->GetStartNodeType()) ) + { + SwTableNode* pTNd = pNode->FindTableNode(); + if ( pTNd ) + { + SwTableBox* pBox = pTNd->GetTable().GetTableBox( m_nNodeIndex ); + if (pBox) + { + pBox->ClaimFrameFormat()->SetFormatAttr( *m_pAttr ); + } + } + } + + if ( !bTmpSet ) + { + m_pAttr.reset(); + } +} + +SwHistorySetFormat::~SwHistorySetFormat() +{ +} + +SwHistoryResetFormat::SwHistoryResetFormat(const SfxPoolItem* pFormatHt, sal_uLong nNodeIdx) + : SwHistoryHint( HSTRY_RESETFMTHNT ) + , m_nNodeIndex( nNodeIdx ) + , m_nWhich( pFormatHt->Which() ) +{ +} + +void SwHistoryResetFormat::SetInDoc( SwDoc* pDoc, bool ) +{ + SwNode * pNode = pDoc->GetNodes()[ m_nNodeIndex ]; + if ( pNode->IsContentNode() ) + { + static_cast(pNode)->ResetAttr( m_nWhich ); + } + else if ( pNode->IsTableNode() ) + { + static_cast(pNode)->GetTable().GetFrameFormat()-> + ResetFormatAttr( m_nWhich ); + } +} + +SwHistorySetText::SwHistorySetText( SwTextAttr* pTextHt, sal_uLong nNodePos ) + : SwHistoryHint( HSTRY_SETTXTHNT ) + , m_nNodeIndex( nNodePos ) + , m_nStart( pTextHt->GetStart() ) + , m_nEnd( pTextHt->GetAnyEnd() ) + , m_bFormatIgnoreStart(pTextHt->IsFormatIgnoreStart()) + , m_bFormatIgnoreEnd (pTextHt->IsFormatIgnoreEnd ()) +{ + // Caution: the following attributes generate no format attributes: + // - NoLineBreak, NoHyphen, Inserted, Deleted + // These cases must be handled separately !!! + + // a little bit complicated but works: first assign a copy of the + // default value and afterwards the values from text attribute + if ( RES_TXTATR_CHARFMT == pTextHt->Which() ) + { + m_pAttr.reset( new SwFormatCharFormat( pTextHt->GetCharFormat().GetCharFormat() ) ); + } + else + { + m_pAttr.reset( pTextHt->GetAttr().Clone() ); + } +} + +SwHistorySetText::~SwHistorySetText() +{ +} + +void SwHistorySetText::SetInDoc( SwDoc* pDoc, bool ) +{ + if (!m_pAttr) + return; + + if ( RES_TXTATR_CHARFMT == m_pAttr->Which() ) + { + // ask the Doc if the CharFormat still exists + if (!pDoc->GetCharFormats()->IsAlive(static_cast(*m_pAttr).GetCharFormat())) + return; // do not set, format does not exist + } + + SwTextNode * pTextNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTextNode(); + OSL_ENSURE( pTextNd, "SwHistorySetText::SetInDoc: not a TextNode" ); + + if ( pTextNd ) + { + SwTextAttr *const pAttr = pTextNd->InsertItem(*m_pAttr, m_nStart, m_nEnd, + SetAttrMode::NOTXTATRCHR | + SetAttrMode::NOHINTADJUST ); + // shouldn't be possible to hit any error/merging path from here + assert(pAttr); + if (m_bFormatIgnoreStart) + { + pAttr->SetFormatIgnoreStart(true); + } + if (m_bFormatIgnoreEnd) + { + pAttr->SetFormatIgnoreEnd(true); + } + } +} + +SwHistorySetTextField::SwHistorySetTextField( const SwTextField* pTextField, sal_uLong nNodePos ) + : SwHistoryHint( HSTRY_SETTXTFLDHNT ) + , m_pField( new SwFormatField( *pTextField->GetFormatField().GetField() ) ) +{ + // only copy if not Sys-FieldType + SwDoc* pDoc = pTextField->GetTextNode().GetDoc(); + + m_nFieldWhich = m_pField->GetField()->GetTyp()->Which(); + if (m_nFieldWhich == SwFieldIds::Database || + m_nFieldWhich == SwFieldIds::User || + m_nFieldWhich == SwFieldIds::SetExp || + m_nFieldWhich == SwFieldIds::Dde || + !pDoc->getIDocumentFieldsAccess().GetSysFieldType( m_nFieldWhich )) + { + m_pFieldType = m_pField->GetField()->GetTyp()->Copy(); + m_pField->GetField()->ChgTyp( m_pFieldType.get() ); // change field type + } + m_nNodeIndex = nNodePos; + m_nPos = pTextField->GetStart(); +} + +OUString SwHistorySetTextField::GetDescription() const +{ + return m_pField->GetField()->GetDescription(); +} + +SwHistorySetTextField::~SwHistorySetTextField() +{ +} + +void SwHistorySetTextField::SetInDoc( SwDoc* pDoc, bool ) +{ + if (!m_pField) + return; + + SwFieldType* pNewFieldType = m_pFieldType.get(); + if ( !pNewFieldType ) + { + pNewFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType( m_nFieldWhich ); + } + else + { + // register type with the document + pNewFieldType = pDoc->getIDocumentFieldsAccess().InsertFieldType( *m_pFieldType ); + } + + m_pField->GetField()->ChgTyp( pNewFieldType ); // change field type + + SwTextNode * pTextNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTextNode(); + OSL_ENSURE( pTextNd, "SwHistorySetTextField: no TextNode" ); + + if ( pTextNd ) + { + pTextNd->InsertItem( *m_pField, m_nPos, m_nPos, + SetAttrMode::NOTXTATRCHR ); + } +} + +SwHistorySetRefMark::SwHistorySetRefMark( const SwTextRefMark* pTextHt, sal_uLong nNodePos ) + : SwHistoryHint( HSTRY_SETREFMARKHNT ) + , m_RefName( pTextHt->GetRefMark().GetRefName() ) + , m_nNodeIndex( nNodePos ) + , m_nStart( pTextHt->GetStart() ) + , m_nEnd( pTextHt->GetAnyEnd() ) +{ +} + +void SwHistorySetRefMark::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTextNode * pTextNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTextNode(); + OSL_ENSURE( pTextNd, "SwHistorySetRefMark: no TextNode" ); + if ( !pTextNd ) + return; + + SwFormatRefMark aRefMark( m_RefName ); + + // if a reference mark without an end already exists here: must not insert! + if ( m_nStart != m_nEnd || + !pTextNd->GetTextAttrForCharAt( m_nStart, RES_TXTATR_REFMARK ) ) + { + pTextNd->InsertItem( aRefMark, m_nStart, m_nEnd, + SetAttrMode::NOTXTATRCHR ); + } +} + +SwHistorySetTOXMark::SwHistorySetTOXMark( const SwTextTOXMark* pTextHt, sal_uLong nNodePos ) + : SwHistoryHint( HSTRY_SETTOXMARKHNT ) + , m_TOXMark( pTextHt->GetTOXMark() ) + , m_TOXName( m_TOXMark.GetTOXType()->GetTypeName() ) + , m_eTOXTypes( m_TOXMark.GetTOXType()->GetType() ) + , m_nNodeIndex( nNodePos ) + , m_nStart( pTextHt->GetStart() ) + , m_nEnd( pTextHt->GetAnyEnd() ) +{ + m_TOXMark.EndListeningAll(); +} + +SwTOXType* SwHistorySetTOXMark::GetSwTOXType(SwDoc& rDoc, TOXTypes eTOXTypes, const OUString& rTOXName) +{ + // search for respective TOX type + const sal_uInt16 nCnt = rDoc.GetTOXTypeCount(eTOXTypes); + SwTOXType* pToxType = nullptr; + for ( sal_uInt16 n = 0; n < nCnt; ++n ) + { + pToxType = const_cast(rDoc.GetTOXType(eTOXTypes, n)); + if (pToxType->GetTypeName() == rTOXName) + break; + pToxType = nullptr; + } + + if ( !pToxType ) // TOX type not found, create new + { + pToxType = const_cast( + rDoc.InsertTOXType(SwTOXType(rDoc, eTOXTypes, rTOXName))); + } + + return pToxType; +} + +void SwHistorySetTOXMark::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTextNode * pTextNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTextNode(); + OSL_ENSURE( pTextNd, "SwHistorySetTOXMark: no TextNode" ); + if ( !pTextNd ) + return; + + SwTOXType* pToxType = GetSwTOXType(*pDoc, m_eTOXTypes, m_TOXName); + + SwTOXMark aNew( m_TOXMark ); + aNew.RegisterToTOXType( *pToxType ); + + pTextNd->InsertItem( aNew, m_nStart, m_nEnd, + SetAttrMode::NOTXTATRCHR ); +} + +bool SwHistorySetTOXMark::IsEqual( const SwTOXMark& rCmp ) const +{ + return m_TOXName == rCmp.GetTOXType()->GetTypeName() && + m_eTOXTypes == rCmp.GetTOXType()->GetType() && + m_TOXMark.GetAlternativeText() == rCmp.GetAlternativeText() && + ( (TOX_INDEX == m_eTOXTypes) + ? ( m_TOXMark.GetPrimaryKey() == rCmp.GetPrimaryKey() && + m_TOXMark.GetSecondaryKey() == rCmp.GetSecondaryKey() ) + : m_TOXMark.GetLevel() == rCmp.GetLevel() + ); +} + +SwHistoryResetText::SwHistoryResetText( sal_uInt16 nWhich, + sal_Int32 nAttrStart, sal_Int32 nAttrEnd, sal_uLong nNodePos ) + : SwHistoryHint( HSTRY_RESETTXTHNT ) + , m_nNodeIndex( nNodePos ), m_nStart( nAttrStart ), m_nEnd( nAttrEnd ) + , m_nAttr( nWhich ) +{ +} + +void SwHistoryResetText::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTextNode * pTextNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTextNode(); + OSL_ENSURE( pTextNd, "SwHistoryResetText: no TextNode" ); + if ( pTextNd ) + { + pTextNd->DeleteAttributes( m_nAttr, m_nStart, m_nEnd ); + } +} + +SwHistorySetFootnote::SwHistorySetFootnote( SwTextFootnote* pTextFootnote, sal_uLong nNodePos ) + : SwHistoryHint( HSTRY_SETFTNHNT ) + , m_pUndo( new SwUndoSaveSection ) + , m_FootnoteNumber( pTextFootnote->GetFootnote().GetNumStr() ) + , m_nNodeIndex( nNodePos ) + , m_nStart( pTextFootnote->GetStart() ) + , m_bEndNote( pTextFootnote->GetFootnote().IsEndNote() ) +{ + OSL_ENSURE( pTextFootnote->GetStartNode(), + "SwHistorySetFootnote: Footnote without Section" ); + + // keep the old NodePos (because who knows what later will be saved/deleted + // in SaveSection) + SwDoc* pDoc = const_cast(pTextFootnote->GetTextNode().GetDoc()); + SwNode* pSaveNd = pDoc->GetNodes()[ m_nNodeIndex ]; + + // keep pointer to StartNode of FootnoteSection and reset its attribute for now + // (as a result, its/all Frames will be deleted automatically) + SwNodeIndex aSttIdx( *pTextFootnote->GetStartNode() ); + pTextFootnote->SetStartNode( nullptr, false ); + + m_pUndo->SaveSection( aSttIdx ); + m_nNodeIndex = pSaveNd->GetIndex(); +} + +SwHistorySetFootnote::SwHistorySetFootnote( const SwTextFootnote &rTextFootnote ) + : SwHistoryHint( HSTRY_SETFTNHNT ) + , m_FootnoteNumber( rTextFootnote.GetFootnote().GetNumStr() ) + , m_nNodeIndex( SwTextFootnote_GetIndex( (&rTextFootnote) ) ) + , m_nStart( rTextFootnote.GetStart() ) + , m_bEndNote( rTextFootnote.GetFootnote().IsEndNote() ) +{ + OSL_ENSURE( rTextFootnote.GetStartNode(), + "SwHistorySetFootnote: Footnote without Section" ); +} + +OUString SwHistorySetFootnote::GetDescription() const +{ + return SwResId(STR_FOOTNOTE); +} + +SwHistorySetFootnote::~SwHistorySetFootnote() +{ +} + +void SwHistorySetFootnote::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTextNode * pTextNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTextNode(); + OSL_ENSURE( pTextNd, "SwHistorySetFootnote: no TextNode" ); + if ( !pTextNd ) + return; + + if (m_pUndo) + { + // set the footnote in the TextNode + SwFormatFootnote aTemp( m_bEndNote ); + SwFormatFootnote& rNew = const_cast( + pDoc->GetAttrPool().Put(aTemp) ); + if ( !m_FootnoteNumber.isEmpty() ) + { + rNew.SetNumStr( m_FootnoteNumber ); + } + SwTextFootnote* pTextFootnote = new SwTextFootnote( rNew, m_nStart ); + + // create the section of the Footnote + SwNodeIndex aIdx( *pTextNd ); + m_pUndo->RestoreSection( pDoc, &aIdx, SwFootnoteStartNode ); + pTextFootnote->SetStartNode( &aIdx ); + if ( m_pUndo->GetHistory() ) + { + // create frames only now + m_pUndo->GetHistory()->Rollback( pDoc ); + } + + pTextNd->InsertHint( pTextFootnote ); + } + else + { + SwTextFootnote * const pFootnote = + static_cast( + pTextNd->GetTextAttrForCharAt( m_nStart )); + assert(pFootnote); + SwFormatFootnote &rFootnote = const_cast(pFootnote->GetFootnote()); + rFootnote.SetNumStr( m_FootnoteNumber ); + if ( rFootnote.IsEndNote() != m_bEndNote ) + { + rFootnote.SetEndNote( m_bEndNote ); + pFootnote->CheckCondColl(); + } + } +} + +SwHistoryChangeFormatColl::SwHistoryChangeFormatColl( SwFormatColl* pFormatColl, sal_uLong nNd, + SwNodeType nNodeWhich ) + : SwHistoryHint( HSTRY_CHGFMTCOLL ) + , m_pColl( pFormatColl ) + , m_nNodeIndex( nNd ) + , m_nNodeType( nNodeWhich ) +{ +} + +void SwHistoryChangeFormatColl::SetInDoc( SwDoc* pDoc, bool ) +{ + SwContentNode * pContentNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetContentNode(); + OSL_ENSURE( pContentNd, "SwHistoryChangeFormatColl: no ContentNode" ); + + // before setting the format, check if it is still available in the + // document. if it has been deleted, there is no undo! + if ( pContentNd && m_nNodeType == pContentNd->GetNodeType() ) + { + if ( SwNodeType::Text == m_nNodeType ) + { + if (pDoc->GetTextFormatColls()->IsAlive(static_cast(m_pColl))) + { + pContentNd->ChgFormatColl( m_pColl ); + } + } + else if (pDoc->GetGrfFormatColls()->IsAlive(static_cast(m_pColl))) + { + pContentNd->ChgFormatColl( m_pColl ); + } + } +} + +SwHistoryTextFlyCnt::SwHistoryTextFlyCnt( SwFrameFormat* const pFlyFormat ) + : SwHistoryHint( HSTRY_FLYCNT ) + , m_pUndo( new SwUndoDelLayFormat( pFlyFormat ) ) +{ + OSL_ENSURE( pFlyFormat, "SwHistoryTextFlyCnt: no Format" ); + m_pUndo->ChgShowSel( false ); +} + +SwHistoryTextFlyCnt::~SwHistoryTextFlyCnt() +{ +} + +void SwHistoryTextFlyCnt::SetInDoc( SwDoc* pDoc, bool ) +{ + ::sw::IShellCursorSupplier *const pISCS(pDoc->GetIShellCursorSupplier()); + assert(pISCS); + ::sw::UndoRedoContext context(*pDoc, *pISCS); + m_pUndo->UndoImpl(context); +} + +SwHistoryBookmark::SwHistoryBookmark( + const ::sw::mark::IMark& rBkmk, + bool bSavePos, + bool bSaveOtherPos) + : SwHistoryHint(HSTRY_BOOKMARK) + , m_aName(rBkmk.GetName()) + , m_aShortName() + , m_aKeycode() + , m_nNode(bSavePos ? + rBkmk.GetMarkPos().nNode.GetIndex() : 0) + , m_nOtherNode(bSaveOtherPos ? + rBkmk.GetOtherMarkPos().nNode.GetIndex() : 0) + , m_nContent(bSavePos ? + rBkmk.GetMarkPos().nContent.GetIndex() : 0) + , m_nOtherContent(bSaveOtherPos ? + rBkmk.GetOtherMarkPos().nContent.GetIndex() :0) + , m_bSavePos(bSavePos) + , m_bSaveOtherPos(bSaveOtherPos) + , m_bHadOtherPos(rBkmk.IsExpanded()) + , m_eBkmkType(IDocumentMarkAccess::GetType(rBkmk)) +{ + const ::sw::mark::IBookmark* const pBookmark = dynamic_cast< const ::sw::mark::IBookmark* >(&rBkmk); + if(pBookmark) + { + m_aKeycode = pBookmark->GetKeyCode(); + m_aShortName = pBookmark->GetShortName(); + + ::sfx2::Metadatable const*const pMetadatable( + dynamic_cast< ::sfx2::Metadatable const* >(pBookmark)); + if (pMetadatable) + { + m_pMetadataUndo = pMetadatable->CreateUndo(); + } + } +} + +void SwHistoryBookmark::SetInDoc( SwDoc* pDoc, bool ) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + std::unique_ptr pPam; + ::sw::mark::IMark* pMark = nullptr; + + if(m_bSavePos) + { + SwContentNode* const pContentNd = rNds[m_nNode]->GetContentNode(); + OSL_ENSURE(pContentNd, + "" + " - wrong node for a mark"); + + // #111660# don't crash when nNode1 doesn't point to content node. + if(pContentNd) + pPam.reset(new SwPaM(*pContentNd, m_nContent)); + } + else + { + pMark = *pMarkAccess->findMark(m_aName); + pPam.reset(new SwPaM(pMark->GetMarkPos())); + } + + if(m_bSaveOtherPos) + { + SwContentNode* const pContentNd = rNds[m_nOtherNode]->GetContentNode(); + OSL_ENSURE(pContentNd, + "" + " - wrong node for a mark"); + + if (pPam != nullptr && pContentNd) + { + pPam->SetMark(); + pPam->GetMark()->nNode = m_nOtherNode; + pPam->GetMark()->nContent.Assign(pContentNd, m_nOtherContent); + } + } + else if(m_bHadOtherPos) + { + if(!pMark) + pMark = *pMarkAccess->findMark(m_aName); + OSL_ENSURE(pMark->IsExpanded(), + "" + " - missing pos on old mark"); + pPam->SetMark(); + *pPam->GetMark() = pMark->GetOtherMarkPos(); + } + + if (pPam) + { + if ( pMark != nullptr ) + { + pMarkAccess->deleteMark( pMark ); + } + ::sw::mark::IBookmark* const pBookmark = + dynamic_cast<::sw::mark::IBookmark*>( + pMarkAccess->makeMark(*pPam, m_aName, m_eBkmkType, sw::mark::InsertMode::New)); + if ( pBookmark != nullptr ) + { + pBookmark->SetKeyCode(m_aKeycode); + pBookmark->SetShortName(m_aShortName); + if (m_pMetadataUndo) + { + ::sfx2::Metadatable * const pMeta( + dynamic_cast< ::sfx2::Metadatable* >(pBookmark)); + OSL_ENSURE(pMeta, "metadata undo, but not metadatable?"); + if (pMeta) + { + pMeta->RestoreMetadata(m_pMetadataUndo); + } + } + } + } +} + +bool SwHistoryBookmark::IsEqualBookmark(const ::sw::mark::IMark& rBkmk) +{ + return m_nNode == rBkmk.GetMarkPos().nNode.GetIndex() + && m_nContent == rBkmk.GetMarkPos().nContent.GetIndex() + && m_aName == rBkmk.GetName(); +} + +SwHistoryNoTextFieldmark::SwHistoryNoTextFieldmark(const ::sw::mark::IFieldmark& rFieldMark) + : SwHistoryHint(HSTRY_NOTEXTFIELDMARK) + , m_sType(rFieldMark.GetFieldname()) + , m_nNode(rFieldMark.GetMarkPos().nNode.GetIndex()) + , m_nContent(rFieldMark.GetMarkPos().nContent.GetIndex()) +{ +} + +void SwHistoryNoTextFieldmark::SetInDoc(SwDoc* pDoc, bool) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + std::unique_ptr pPam; + + const SwContentNode* pContentNd = rNds[m_nNode]->GetContentNode(); + if(pContentNd) + pPam.reset(new SwPaM(*pContentNd, m_nContent)); + + if (pPam) + { + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + pMarkAccess->makeNoTextFieldBookmark(*pPam, OUString(), m_sType); + } +} + +void SwHistoryNoTextFieldmark::ResetInDoc(SwDoc* pDoc) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + std::unique_ptr pPam; + + const SwContentNode* pContentNd = rNds[m_nNode]->GetContentNode(); + if(pContentNd) + pPam.reset(new SwPaM(*pContentNd, m_nContent-1)); + + if (pPam) + { + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + pMarkAccess->deleteFieldmarkAt(*pPam->GetPoint()); + } +} + +SwHistoryTextFieldmark::SwHistoryTextFieldmark(const ::sw::mark::IFieldmark& rFieldMark) + : SwHistoryHint(HSTRY_TEXTFIELDMARK) + , m_sName(rFieldMark.GetName()) + , m_sType(rFieldMark.GetFieldname()) + , m_nStartNode(rFieldMark.GetMarkStart().nNode.GetIndex()) + , m_nStartContent(rFieldMark.GetMarkStart().nContent.GetIndex()) + , m_nEndNode(rFieldMark.GetMarkEnd().nNode.GetIndex()) + , m_nEndContent(rFieldMark.GetMarkEnd().nContent.GetIndex()) +{ + SwPosition const sepPos(sw::mark::FindFieldSep(rFieldMark)); + m_nSepNode = sepPos.nNode.GetIndex(); + m_nSepContent = sepPos.nContent.GetIndex(); +} + +void SwHistoryTextFieldmark::SetInDoc(SwDoc* pDoc, bool) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + + assert(rNds[m_nStartNode]->IsContentNode()); + assert(rNds[m_nEndNode]->IsContentNode()); + assert(rNds[m_nSepNode]->IsContentNode()); + + SwPaM const pam(*rNds[m_nStartNode]->GetContentNode(), m_nStartContent, + *rNds[m_nEndNode]->GetContentNode(), + // subtract 1 for the CH_TXT_ATR_FIELDEND itself, + // plus more if same node as other CH_TXT_ATR + m_nStartNode == m_nEndNode + ? (m_nEndContent - 3) + : m_nSepNode == m_nEndNode + ? (m_nEndContent - 2) + : (m_nEndContent - 1)); + SwPosition const sepPos(*rNds[m_nSepNode]->GetContentNode(), + m_nStartNode == m_nSepNode ? (m_nSepContent - 1) : m_nSepContent); + + IDocumentMarkAccess & rMarksAccess(*pDoc->getIDocumentMarkAccess()); + rMarksAccess.makeFieldBookmark(pam, m_sName, m_sType, &sepPos); +} + +void SwHistoryTextFieldmark::ResetInDoc(SwDoc* pDoc) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + + assert(rNds[m_nStartNode]->IsContentNode()); + assert(rNds[m_nEndNode]->IsContentNode()); + assert(rNds[m_nSepNode]->IsContentNode()); + + SwPosition const pos(*rNds[m_nStartNode]->GetContentNode(), m_nStartContent); + + IDocumentMarkAccess & rMarksAccess(*pDoc->getIDocumentMarkAccess()); + rMarksAccess.deleteFieldmarkAt(pos); +} + +SwHistorySetAttrSet::SwHistorySetAttrSet( const SfxItemSet& rSet, + sal_uLong nNodePos, const std::set &rSetArr ) + : SwHistoryHint( HSTRY_SETATTRSET ) + , m_OldSet( rSet ) + , m_ResetArray( 0, 4 ) + , m_nNodeIndex( nNodePos ) +{ + SfxItemIter aIter( m_OldSet ), aOrigIter( rSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(), + * pOrigItem = aOrigIter.GetCurItem(); + while (pItem && pOrigItem) + { + if( !rSetArr.count( pOrigItem->Which() )) + { + m_ResetArray.push_back( pOrigItem->Which() ); + m_OldSet.ClearItem( pOrigItem->Which() ); + } + else + { + switch ( pItem->Which() ) + { + case RES_PAGEDESC: + static_cast( + const_cast(pItem))->ChgDefinedIn( nullptr ); + break; + + case RES_PARATR_DROP: + static_cast( + const_cast(pItem))->ChgDefinedIn( nullptr ); + break; + + case RES_BOXATR_FORMULA: + { + // When a formula is set, never save the value. It + // possibly must be recalculated! + // Save formulas always in plain text + m_OldSet.ClearItem( RES_BOXATR_VALUE ); + + SwTableBoxFormula& rNew = + *static_cast( + const_cast(pItem)); + if ( rNew.IsIntrnlName() ) + { + const SwTableBoxFormula& rOld = + rSet.Get( RES_BOXATR_FORMULA ); + const SwNode* pNd = rOld.GetNodeOfFormula(); + if ( pNd ) + { + const SwTableNode* pTableNode + = pNd->FindTableNode(); + if (pTableNode) + { + SwTableFormulaUpdate aMsgHint( + &pTableNode->GetTable() ); + aMsgHint.m_eFlags = TBL_BOXNAME; + rNew.ChgDefinedIn( rOld.GetDefinedIn() ); + rNew.ChangeState( &aMsgHint ); + } + } + } + rNew.ChgDefinedIn( nullptr ); + } + break; + } + } + + pItem = aIter.NextItem(); + pOrigItem = aOrigIter.NextItem(); + } +} + +void SwHistorySetAttrSet::SetInDoc( SwDoc* pDoc, bool ) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNode * pNode = pDoc->GetNodes()[ m_nNodeIndex ]; + if ( pNode->IsContentNode() ) + { + static_cast(pNode)->SetAttr( m_OldSet ); + if ( !m_ResetArray.empty() ) + { + static_cast(pNode)->ResetAttr( m_ResetArray ); + } + } + else if ( pNode->IsTableNode() ) + { + SwFormat& rFormat = + *static_cast(pNode)->GetTable().GetFrameFormat(); + rFormat.SetFormatAttr( m_OldSet ); + if ( !m_ResetArray.empty() ) + { + rFormat.ResetFormatAttr( m_ResetArray.front() ); + } + } +} + +SwHistoryChangeFlyAnchor::SwHistoryChangeFlyAnchor( SwFrameFormat& rFormat ) + : SwHistoryHint( HSTRY_CHGFLYANCHOR ) + , m_rFormat( rFormat ) + , m_nOldNodeIndex( rFormat.GetAnchor().GetContentAnchor()->nNode.GetIndex() ) + , m_nOldContentIndex( (RndStdIds::FLY_AT_CHAR == rFormat.GetAnchor().GetAnchorId()) + ? rFormat.GetAnchor().GetContentAnchor()->nContent.GetIndex() + : COMPLETE_STRING ) +{ +} + +void SwHistoryChangeFlyAnchor::SetInDoc( SwDoc* pDoc, bool ) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + if (pDoc->GetSpzFrameFormats()->IsAlive(&m_rFormat)) // Format does still exist + { + SwFormatAnchor aTmp( m_rFormat.GetAnchor() ); + + SwNode* pNd = pDoc->GetNodes()[ m_nOldNodeIndex ]; + SwContentNode* pCNd = pNd->GetContentNode(); + SwPosition aPos( *pNd ); + if ( COMPLETE_STRING != m_nOldContentIndex ) + { + OSL_ENSURE(pCNd, "SwHistoryChangeFlyAnchor: no ContentNode"); + if (pCNd) + { + aPos.nContent.Assign( pCNd, m_nOldContentIndex ); + } + } + aTmp.SetAnchor( &aPos ); + + // so the Layout does not get confused + if (!pCNd || !pCNd->getLayoutFrame(pDoc->getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr)) + { + m_rFormat.DelFrames(); + } + + m_rFormat.SetFormatAttr( aTmp ); + } +} + +SwHistoryChangeFlyChain::SwHistoryChangeFlyChain( SwFlyFrameFormat& rFormat, + const SwFormatChain& rAttr ) + : SwHistoryHint( HSTRY_CHGFLYCHAIN ) + , m_pPrevFormat( rAttr.GetPrev() ) + , m_pNextFormat( rAttr.GetNext() ) + , m_pFlyFormat( &rFormat ) +{ +} + +void SwHistoryChangeFlyChain::SetInDoc( SwDoc* pDoc, bool ) +{ + if (pDoc->GetSpzFrameFormats()->IsAlive(m_pFlyFormat)) + { + SwFormatChain aChain; + + if (m_pPrevFormat && + pDoc->GetSpzFrameFormats()->IsAlive(m_pPrevFormat)) + { + aChain.SetPrev( m_pPrevFormat ); + SwFormatChain aTmp( m_pPrevFormat->GetChain() ); + aTmp.SetNext( m_pFlyFormat ); + m_pPrevFormat->SetFormatAttr( aTmp ); + } + + if (m_pNextFormat && + pDoc->GetSpzFrameFormats()->IsAlive(m_pNextFormat)) + { + aChain.SetNext( m_pNextFormat ); + SwFormatChain aTmp( m_pNextFormat->GetChain() ); + aTmp.SetPrev( m_pFlyFormat ); + m_pNextFormat->SetFormatAttr( aTmp ); + } + + if ( aChain.GetNext() || aChain.GetPrev() ) + { + m_pFlyFormat->SetFormatAttr( aChain ); + } + } +} + +// -> #i27615# +SwHistoryChangeCharFormat::SwHistoryChangeCharFormat(const SfxItemSet & rSet, + const OUString & sFormat) + : SwHistoryHint(HSTRY_CHGCHARFMT) + , m_OldSet(rSet), m_Format(sFormat) +{ +} + +void SwHistoryChangeCharFormat::SetInDoc(SwDoc * pDoc, bool ) +{ + SwCharFormat * pCharFormat = pDoc->FindCharFormatByName(m_Format); + + if (pCharFormat) + { + pCharFormat->SetFormatAttr(m_OldSet); + } +} +// <- #i27615# + +SwHistory::SwHistory() + : m_SwpHstry() + , m_nEndDiff( 0 ) +{ +} + +SwHistory::~SwHistory() +{ +} + +void SwHistory::Add( + const SfxPoolItem* pOldValue, + const SfxPoolItem* pNewValue, + sal_uLong nNodeIdx) +{ + OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" ); + const sal_uInt16 nWhich(pNewValue->Which()); + + // excluded values + if(nWhich == RES_TXTATR_FIELD || nWhich == RES_TXTATR_ANNOTATION) + { + return; + } + + // no default Attribute? + std::unique_ptr pHt; + + // To be able to include the DrawingLayer FillItems something more + // general has to be done to check if an Item is default than to check + // if its pointer equals that in Writer's global PoolDefaults (held in + // aAttrTab and used to fill the pool defaults in Writer - looks as if + // Writer is *older* than the SfxItemPool ?). I checked the possibility to + // get the SfxItemPool here (works), but decided to use the SfxPoolItem's + // global tooling aka IsDefaultItem(const SfxPoolItem*) for now + if(pOldValue && !IsDefaultItem(pOldValue)) + { + pHt.reset( new SwHistorySetFormat( pOldValue, nNodeIdx ) ); + } + else + { + pHt.reset( new SwHistoryResetFormat( pNewValue, nNodeIdx ) ); + } + + m_SwpHstry.push_back( std::move(pHt) ); +} + +// FIXME: refactor the following "Add" methods (DRY)? +void SwHistory::Add( SwTextAttr* pHint, sal_uLong nNodeIdx, bool bNewAttr ) +{ + OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" ); + + std::unique_ptr pHt; + if( !bNewAttr ) + { + switch ( pHint->Which() ) + { + case RES_TXTATR_FTN: + pHt.reset( new SwHistorySetFootnote( + static_cast(pHint), nNodeIdx ) ); + break; + case RES_TXTATR_FLYCNT: + pHt.reset( new SwHistoryTextFlyCnt( static_cast(pHint) + ->GetFlyCnt().GetFrameFormat() ) ); + break; + case RES_TXTATR_FIELD: + case RES_TXTATR_ANNOTATION: + pHt.reset( new SwHistorySetTextField( + static_txtattr_cast(pHint), nNodeIdx) ); + break; + case RES_TXTATR_TOXMARK: + pHt.reset( new SwHistorySetTOXMark( + static_txtattr_cast(pHint), nNodeIdx) ); + break; + case RES_TXTATR_REFMARK: + pHt.reset( new SwHistorySetRefMark( + static_txtattr_cast(pHint), nNodeIdx) ); + break; + default: + pHt.reset( new SwHistorySetText( pHint, nNodeIdx ) ); + } + } + else + { + pHt.reset( new SwHistoryResetText( pHint->Which(), pHint->GetStart(), + pHint->GetAnyEnd(), nNodeIdx ) ); + } + m_SwpHstry.push_back( std::move(pHt) ); +} + +void SwHistory::Add( SwFormatColl* pColl, sal_uLong nNodeIdx, SwNodeType nWhichNd ) +{ + OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" ); + + std::unique_ptr pHt( + new SwHistoryChangeFormatColl( pColl, nNodeIdx, nWhichNd )); + m_SwpHstry.push_back( std::move(pHt) ); +} + +void SwHistory::Add(const ::sw::mark::IMark& rBkmk, bool bSavePos, bool bSaveOtherPos) +{ + OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" ); + + std::unique_ptr pHt; + + switch (IDocumentMarkAccess::GetType(rBkmk)) + { + case IDocumentMarkAccess::MarkType::TEXT_FIELDMARK: + case IDocumentMarkAccess::MarkType::DATE_FIELDMARK: + assert(bSavePos && bSaveOtherPos); // must be deleted completely! + pHt.reset(new SwHistoryTextFieldmark(dynamic_cast(rBkmk))); + break; + case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK: + case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK: + assert(bSavePos && bSaveOtherPos); // must be deleted completely! + pHt.reset(new SwHistoryNoTextFieldmark(dynamic_cast(rBkmk))); + break; + default: + pHt.reset(new SwHistoryBookmark(rBkmk, bSavePos, bSaveOtherPos)); + break; + } + + assert(pHt); + m_SwpHstry.push_back( std::move(pHt) ); +} + +void SwHistory::AddChangeFlyAnchor(SwFrameFormat& rFormat) +{ + std::unique_ptr pHt(new SwHistoryChangeFlyAnchor( rFormat )); + m_SwpHstry.push_back( std::move(pHt) ); +} + +void SwHistory::AddDeleteFly(SwFrameFormat& rFormat, sal_uInt16& rSetPos) +{ + OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" ); + + const sal_uInt16 nWh = rFormat.Which(); + (void) nWh; + // only Flys! + assert((RES_FLYFRMFMT == nWh && dynamic_cast(&rFormat)) + || (RES_DRAWFRMFMT == nWh && dynamic_cast(&rFormat))); + { + std::unique_ptr pHint(new SwHistoryTextFlyCnt( &rFormat )); + m_SwpHstry.push_back( std::move(pHint) ); + + const SwFormatChain* pChainItem; + if( SfxItemState::SET == rFormat.GetItemState( RES_CHAIN, false, + reinterpret_cast(&pChainItem) )) + { + assert(RES_FLYFRMFMT == nWh); // not supported on SdrObjects + if( pChainItem->GetNext() || pChainItem->GetPrev() ) + { + std::unique_ptr pHt( + new SwHistoryChangeFlyChain(static_cast(rFormat), *pChainItem)); + m_SwpHstry.insert( m_SwpHstry.begin() + rSetPos++, std::move(pHt) ); + if ( pChainItem->GetNext() ) + { + SwFormatChain aTmp( pChainItem->GetNext()->GetChain() ); + aTmp.SetPrev( nullptr ); + pChainItem->GetNext()->SetFormatAttr( aTmp ); + } + if ( pChainItem->GetPrev() ) + { + SwFormatChain aTmp( pChainItem->GetPrev()->GetChain() ); + aTmp.SetNext( nullptr ); + pChainItem->GetPrev()->SetFormatAttr( aTmp ); + } + } + rFormat.ResetFormatAttr( RES_CHAIN ); + } + } +} + +void SwHistory::Add( const SwTextFootnote& rFootnote ) +{ + std::unique_ptr pHt(new SwHistorySetFootnote( rFootnote )); + m_SwpHstry.push_back( std::move(pHt) ); +} + +// #i27615# +void SwHistory::Add(const SfxItemSet & rSet, const SwCharFormat & rFormat) +{ + std::unique_ptr pHt(new SwHistoryChangeCharFormat(rSet, rFormat.GetName())); + m_SwpHstry.push_back( std::move(pHt) ); +} + +bool SwHistory::Rollback( SwDoc* pDoc, sal_uInt16 nStart ) +{ + if ( !Count() ) + return false; + + for ( sal_uInt16 i = Count(); i > nStart ; ) + { + SwHistoryHint * pHHt = m_SwpHstry[ --i ].get(); + pHHt->SetInDoc( pDoc, false ); + } + m_SwpHstry.erase( m_SwpHstry.begin() + nStart, m_SwpHstry.end() ); + m_nEndDiff = 0; + return true; +} + +bool SwHistory::TmpRollback( SwDoc* pDoc, sal_uInt16 nStart, bool bToFirst ) +{ + sal_uInt16 nEnd = Count() - m_nEndDiff; + if ( !Count() || !nEnd || nStart >= nEnd ) + return false; + + if ( bToFirst ) + { + for ( ; nEnd > nStart; ++m_nEndDiff ) + { + SwHistoryHint* pHHt = m_SwpHstry[ --nEnd ].get(); + pHHt->SetInDoc( pDoc, true ); + } + } + else + { + for ( ; nStart < nEnd; ++m_nEndDiff, ++nStart ) + { + SwHistoryHint* pHHt = m_SwpHstry[ nStart ].get(); + pHHt->SetInDoc( pDoc, true ); + } + } + return true; +} + +sal_uInt16 SwHistory::SetTmpEnd( sal_uInt16 nNewTmpEnd ) +{ + OSL_ENSURE( nNewTmpEnd <= Count(), "SwHistory::SetTmpEnd: out of bounds" ); + + const sal_uInt16 nOld = Count() - m_nEndDiff; + m_nEndDiff = Count() - nNewTmpEnd; + + // for every SwHistoryFlyCnt, call the Redo of its UndoObject. + // this saves the formats of the flys! + for ( sal_uInt16 n = nOld; n < nNewTmpEnd; n++ ) + { + if ( HSTRY_FLYCNT == (*this)[ n ]->Which() ) + { + static_cast((*this)[ n ]) + ->GetUDelLFormat()->RedoForRollback(); + } + } + + return nOld; +} + +void SwHistory::CopyFormatAttr( + const SfxItemSet& rSet, + sal_uLong nNodeIdx) +{ + if(rSet.Count()) + { + SfxItemIter aIter(rSet); + const SfxPoolItem* pItem = aIter.GetCurItem(); + do + { + if(!IsInvalidItem(pItem)) + { + Add(pItem, pItem, nNodeIdx); + } + + pItem = aIter.NextItem(); + + } while(pItem); + } +} + +void SwHistory::CopyAttr( + SwpHints const * pHts, + const sal_uLong nNodeIdx, + const sal_Int32 nStart, + const sal_Int32 nEnd, + const bool bCopyFields ) +{ + if( !pHts ) + return; + + // copy all attributes of the TextNode in the area from nStart to nEnd + SwTextAttr* pHt; + for( size_t n = 0; n < pHts->Count(); ++n ) + { + // nAttrStt must even be set when !pEndIdx + pHt = pHts->Get(n); + const sal_Int32 nAttrStt = pHt->GetStart(); + const sal_Int32 * pEndIdx = pHt->GetEnd(); + if( nullptr != pEndIdx && nAttrStt > nEnd ) + break; + + // never copy Flys and Footnote !! + bool bNextAttr = false; + switch( pHt->Which() ) + { + case RES_TXTATR_FIELD: + case RES_TXTATR_ANNOTATION: + case RES_TXTATR_INPUTFIELD: + if( !bCopyFields ) + bNextAttr = true; + break; + case RES_TXTATR_FLYCNT: + case RES_TXTATR_FTN: + bNextAttr = true; + break; + } + + if( bNextAttr ) + continue; + + // save all attributes that are somehow in this area + if ( nStart <= nAttrStt ) + { + if ( nEnd > nAttrStt ) + { + Add( pHt, nNodeIdx, false ); + } + } + else if ( pEndIdx && nStart < *pEndIdx ) + { + Add( pHt, nNodeIdx, false ); + } + } +} + +// Class to register the history at a Node, Format, HintsArray, ... +SwRegHistory::SwRegHistory( SwHistory* pHst ) + : SwClient( nullptr ) + , m_pHistory( pHst ) + , m_nNodeIndex( ULONG_MAX ) +{ + MakeSetWhichIds(); +} + +SwRegHistory::SwRegHistory( SwModify* pRegIn, const SwNode& rNd, + SwHistory* pHst ) + : SwClient( pRegIn ) + , m_pHistory( pHst ) + , m_nNodeIndex( rNd.GetIndex() ) +{ + MakeSetWhichIds(); +} + +SwRegHistory::SwRegHistory( const SwNode& rNd, SwHistory* pHst ) + : SwClient( nullptr ) + , m_pHistory( pHst ) + , m_nNodeIndex( rNd.GetIndex() ) +{ + MakeSetWhichIds(); +} + +void SwRegHistory::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + if ( m_pHistory && pNew && pOld != pNew ) + { + if ( pNew->Which() < POOLATTR_END ) + { + if(RES_UPDATE_ATTR == pNew->Which()) + { + // const SfxItemPool& rPool = static_cast< const SwUpdateAttr* >(pNew)->GetSfxItemPool(); + + m_pHistory->Add( + // rPool, + pOld, + pNew, + m_nNodeIndex); + } + else + { + OSL_ENSURE(false, "Unexpected update attribute (!)"); + } + } + else if (pOld && RES_ATTRSET_CHG == pNew->Which()) + { + std::unique_ptr pNewHstr; + const SfxItemSet& rSet = *static_cast< const SwAttrSetChg* >(pOld)->GetChgSet(); + + if ( 1 < rSet.Count() ) + { + pNewHstr.reset( new SwHistorySetAttrSet( rSet, m_nNodeIndex, m_WhichIdSet ) ); + } + else if (const SfxPoolItem* pItem = SfxItemIter(rSet).GetCurItem()) + { + if ( m_WhichIdSet.count( pItem->Which() ) ) + { + pNewHstr.reset( new SwHistorySetFormat( pItem, m_nNodeIndex ) ); + } + else + { + pNewHstr.reset( new SwHistoryResetFormat( pItem, m_nNodeIndex ) ); + } + } + + if (pNewHstr) + m_pHistory->m_SwpHstry.push_back( std::move(pNewHstr) ); + } + } +} + +void SwRegHistory::AddHint( SwTextAttr* pHt, const bool bNew ) +{ + m_pHistory->Add( pHt, m_nNodeIndex, bNew ); +} + +bool SwRegHistory::InsertItems( const SfxItemSet& rSet, + sal_Int32 const nStart, sal_Int32 const nEnd, SetAttrMode const nFlags, + SwTextAttr **ppNewTextAttr ) +{ + if( !rSet.Count() ) + return false; + + SwTextNode * const pTextNode = + dynamic_cast(GetRegisteredIn()); + + OSL_ENSURE(pTextNode, "SwRegHistory not registered at text node?"); + if (!pTextNode) + return false; + + if (m_pHistory) + { + pTextNode->GetOrCreateSwpHints().Register(this); + } + + const bool bInserted = pTextNode->SetAttr( rSet, nStart, nEnd, nFlags, ppNewTextAttr ); + + // Caution: The array can be deleted when inserting an attribute! + // This can happen when the value that should be added first deletes + // an existing attribute but does not need to be added itself because + // the paragraph attributes are identical + // ( -> bForgetAttr in SwpHints::Insert ) + if ( pTextNode->GetpSwpHints() && m_pHistory ) + { + pTextNode->GetpSwpHints()->DeRegister(); + } + +#ifndef NDEBUG + if ( m_pHistory && bInserted ) + { + SfxItemIter aIter(rSet); + for (SfxPoolItem const* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + { // check that the history recorded a hint to reset every item + sal_uInt16 const nWhich(pItem->Which()); + sal_uInt16 const nExpected( + (isCHRATR(nWhich) || RES_TXTATR_UNKNOWN_CONTAINER == nWhich) + ? RES_TXTATR_AUTOFMT + : nWhich); + if (RES_TXTATR_AUTOFMT == nExpected) + continue; // special case, may get set on text node itself + // tdf#105077 even worse, node's set could cause + // nothing at all to be inserted + assert(std::any_of( + m_pHistory->m_SwpHstry.begin(), m_pHistory->m_SwpHstry.end(), + [nExpected](std::unique_ptr const& pHint) -> bool { + SwHistoryResetText const*const pReset( + dynamic_cast(pHint.get())); + return pReset && (pReset->GetWhich() == nExpected); + })); + } + } +#endif + + return bInserted; +} + +void SwRegHistory::RegisterInModify( SwModify* pRegIn, const SwNode& rNd ) +{ + if ( m_pHistory && pRegIn ) + { + pRegIn->Add( this ); + m_nNodeIndex = rNd.GetIndex(); + MakeSetWhichIds(); + } + else + { + m_WhichIdSet.clear(); + } +} + +void SwRegHistory::MakeSetWhichIds() +{ + if (!m_pHistory) return; + + m_WhichIdSet.clear(); + + if( GetRegisteredIn() ) + { + const SfxItemSet* pSet = nullptr; + if( dynamic_cast< const SwContentNode *>( GetRegisteredIn() ) != nullptr ) + { + pSet = static_cast( + GetRegisteredIn())->GetpSwAttrSet(); + } + else if ( dynamic_cast< const SwFormat *>( GetRegisteredIn() ) != nullptr ) + { + pSet = &static_cast( + GetRegisteredIn())->GetAttrSet(); + } + if( pSet && pSet->Count() ) + { + SfxItemIter aIter( *pSet ); + for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + { + sal_uInt16 nW = pItem->Which(); + m_WhichIdSet.insert( nW ); + } + } + } +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3