diff options
-rw-r--r-- | sw/inc/undobj.hxx | 7 | ||||
-rw-r--r-- | sw/source/core/doc/doctxm.cxx | 118 | ||||
-rw-r--r-- | sw/source/core/inc/UndoSection.hxx | 22 | ||||
-rw-r--r-- | sw/source/core/undo/undobj.cxx | 20 | ||||
-rw-r--r-- | sw/source/core/undo/unsect.cxx | 89 |
5 files changed, 196 insertions, 60 deletions
diff --git a/sw/inc/undobj.hxx b/sw/inc/undobj.hxx index 8610ab3d38a6..38cab61b0b58 100644 --- a/sw/inc/undobj.hxx +++ b/sw/inc/undobj.hxx @@ -163,7 +163,8 @@ protected: sal_uLong* pEndNdIdx = nullptr ); static void MoveFromUndoNds( SwDoc& rDoc, sal_uLong nNodeIdx, SwPosition& rInsPos, - const sal_uLong* pEndNdIdx = nullptr ); + const sal_uLong* pEndNdIdx = nullptr, + bool bForceCreateFrames = false); // These two methods move the SPoint back/forth from PaM. With it // a range can be spanned for Undo/Redo. (In this case the SPoint @@ -199,9 +200,9 @@ public: ~SwUndoSaveSection(); void SaveSection( const SwNodeIndex& rSttIdx ); - void SaveSection( const SwNodeRange& rRange ); + void SaveSection(const SwNodeRange& rRange, bool bExpandNodes = true); void RestoreSection( SwDoc* pDoc, SwNodeIndex* pIdx, sal_uInt16 nSectType ); - void RestoreSection( SwDoc* pDoc, const SwNodeIndex& rInsPos ); + void RestoreSection(SwDoc* pDoc, const SwNodeIndex& rInsPos, bool bForceCreateFrames = false); const SwHistory* GetHistory() const { return pHistory.get(); } SwHistory* GetHistory() { return pHistory.get(); } diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx index d1dd7e59139d..13ca079c2804 100644 --- a/sw/source/core/doc/doctxm.cxx +++ b/sw/source/core/doc/doctxm.cxx @@ -51,6 +51,7 @@ #include <txtfrm.hxx> #include <rootfrm.hxx> #include <UndoAttribute.hxx> +#include <UndoSection.hxx> #include <swundo.hxx> #include <mdiexp.hxx> #include <docary.hxx> @@ -870,8 +871,50 @@ void SwTOXBaseSection::Update(const SfxItemSet* pAttr, SwNode2LayoutSaveUpperFrames aN2L(*pSectNd); const_cast<SwSectionNode*>(pSectNd)->DelFrames(); + // This would be a good time to update the Numbering + pDoc->UpdateNumRule(); + + if( GetCreateType() & SwTOXElement::Mark ) + UpdateMarks( aIntl, pOwnChapterNode, pLayout ); + + if( GetCreateType() & SwTOXElement::OutlineLevel ) + UpdateOutline( pOwnChapterNode, pLayout ); + + if( GetCreateType() & SwTOXElement::Template ) + UpdateTemplate( pOwnChapterNode, pLayout ); + + if( GetCreateType() & SwTOXElement::Ole || + TOX_OBJECTS == SwTOXBase::GetType()) + UpdateContent( SwTOXElement::Ole, pOwnChapterNode, pLayout ); + + if( GetCreateType() & SwTOXElement::Table || + (TOX_TABLES == SwTOXBase::GetType() && IsFromObjectNames()) ) + UpdateTable( pOwnChapterNode, pLayout ); + + if( GetCreateType() & SwTOXElement::Graphic || + (TOX_ILLUSTRATIONS == SwTOXBase::GetType() && IsFromObjectNames())) + UpdateContent( SwTOXElement::Graphic, pOwnChapterNode, pLayout ); + + if( !GetSequenceName().isEmpty() && !IsFromObjectNames() && + (TOX_TABLES == SwTOXBase::GetType() || + TOX_ILLUSTRATIONS == SwTOXBase::GetType() ) ) + UpdateSequence( pOwnChapterNode, pLayout ); + + if( GetCreateType() & SwTOXElement::Frame ) + UpdateContent( SwTOXElement::Frame, pOwnChapterNode, pLayout ); + + if(TOX_AUTHORITIES == SwTOXBase::GetType()) + UpdateAuthorities( aIntl, pLayout ); + + // Insert AlphaDelimitters if needed (just for keywords) + if( TOX_INDEX == SwTOXBase::GetType() && + ( GetOptions() & SwTOIOptions::AlphaDelimiter ) ) + InsertAlphaDelimitter( aIntl ); + // remove old content an insert one empty textnode (to hold the layout!) SwTextNode* pFirstEmptyNd; + + SwUndoUpdateIndex * pUndo(nullptr); { pDoc->getIDocumentRedlineAccess().DeleteRedline( *pSectNd, true, USHRT_MAX ); @@ -886,6 +929,8 @@ void SwTOXBaseSection::Update(const SfxItemSet* pAttr, const SwContentNode* pCNd = aNxtIdx.GetNode().GetContentNode(); if( !pCNd ) pCNd = pDoc->GetNodes().GoNext( &aNxtIdx ); + assert(pCNd != pFirstEmptyNd); + assert(pCNd->GetIndex() < pFirstEmptyNd->GetIndex()); if( pCNd->HasSwAttrSet() ) { SfxItemSet aBrkSet( pDoc->GetAttrPool(), aBreakSetRange ); @@ -894,16 +939,28 @@ void SwTOXBaseSection::Update(const SfxItemSet* pAttr, pFirstEmptyNd->SetAttr( aBrkSet ); } } - --aEndIdx; - SwPosition aPos( aEndIdx, SwIndex( pFirstEmptyNd, 0 )); - SwDoc::CorrAbs( aSttIdx, aEndIdx, aPos, true ); - // delete flys in whole range including start node which requires - // giving the node before start node as Mark parameter, hence -1. - // (flys must be deleted because the anchor nodes are removed) - DelFlyInRange( SwNodeIndex(aSttIdx, -1), aEndIdx ); + if (pDoc->GetIDocumentUndoRedo().DoesUndo()) + { + // note: this will first append a SwUndoDelSection from the ctor... + pUndo = new SwUndoUpdateIndex(*this); + // tdf#123313 insert Undo *after* all CrossRefBookmark Undos have + // been inserted by the Update*() functions + pDoc->GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndoUpdateIndex>(pUndo)); + } + else + { + --aEndIdx; + SwPosition aPos( aEndIdx, SwIndex( pFirstEmptyNd, 0 )); + SwDoc::CorrAbs( aSttIdx, aEndIdx, aPos, true ); + + // delete flys in whole range including start node which requires + // giving the node before start node as Mark parameter, hence -1. + // (flys must be deleted because the anchor nodes are removed) + DelFlyInRange( SwNodeIndex(aSttIdx, -1), aEndIdx ); - pDoc->GetNodes().Delete( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() ); + pDoc->GetNodes().Delete( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() ); + } } // insert title of TOX @@ -922,47 +979,12 @@ void SwTOXBaseSection::Update(const SfxItemSet* pAttr, SwSectionFormat* pSectFormat = pDoc->MakeSectionFormat(); pDoc->GetNodes().InsertTextSection( aStt, *pSectFormat, headerData, nullptr, &aIdx, true, false); - } - - // This would be a good time to update the Numbering - pDoc->UpdateNumRule(); - - if( GetCreateType() & SwTOXElement::Mark ) - UpdateMarks( aIntl, pOwnChapterNode, pLayout ); - - if( GetCreateType() & SwTOXElement::OutlineLevel ) - UpdateOutline( pOwnChapterNode, pLayout ); - - if( GetCreateType() & SwTOXElement::Template ) - UpdateTemplate( pOwnChapterNode, pLayout ); - - if( GetCreateType() & SwTOXElement::Ole || - TOX_OBJECTS == SwTOXBase::GetType()) - UpdateContent( SwTOXElement::Ole, pOwnChapterNode, pLayout ); - - if( GetCreateType() & SwTOXElement::Table || - (TOX_TABLES == SwTOXBase::GetType() && IsFromObjectNames()) ) - UpdateTable( pOwnChapterNode, pLayout ); - if( GetCreateType() & SwTOXElement::Graphic || - (TOX_ILLUSTRATIONS == SwTOXBase::GetType() && IsFromObjectNames())) - UpdateContent( SwTOXElement::Graphic, pOwnChapterNode, pLayout ); - - if( !GetSequenceName().isEmpty() && !IsFromObjectNames() && - (TOX_TABLES == SwTOXBase::GetType() || - TOX_ILLUSTRATIONS == SwTOXBase::GetType() ) ) - UpdateSequence( pOwnChapterNode, pLayout ); - - if( GetCreateType() & SwTOXElement::Frame ) - UpdateContent( SwTOXElement::Frame, pOwnChapterNode, pLayout ); - - if(TOX_AUTHORITIES == SwTOXBase::GetType()) - UpdateAuthorities( aIntl, pLayout ); - - // Insert AlphaDelimitters if needed (just for keywords) - if( TOX_INDEX == SwTOXBase::GetType() && - ( GetOptions() & SwTOIOptions::AlphaDelimiter ) ) - InsertAlphaDelimitter( aIntl ); + if (pUndo) + { + pUndo->TitleSectionInserted(*pSectFormat); + } + } // Sort the List of all TOC Marks and TOC Sections std::vector<SwTextFormatColl*> aCollArr( GetTOXForm().GetFormMax(), nullptr ); diff --git a/sw/source/core/inc/UndoSection.hxx b/sw/source/core/inc/UndoSection.hxx index ef8847dae1e0..985259728b64 100644 --- a/sw/source/core/inc/UndoSection.hxx +++ b/sw/source/core/inc/UndoSection.hxx @@ -70,6 +70,28 @@ std::unique_ptr<SwUndo> MakeUndoDelSection(SwSectionFormat const&); std::unique_ptr<SwUndo> MakeUndoUpdateSection(SwSectionFormat const&, bool const); + +class SwTOXBaseSection; +class SwUndoDelSection; + +class SwUndoUpdateIndex : public SwUndo +{ +private: + std::unique_ptr<SwUndoDelSection> m_pTitleSectionUpdated; + std::unique_ptr<SwUndoSaveSection> const m_pSaveSectionOriginal; + std::unique_ptr<SwUndoSaveSection> const m_pSaveSectionUpdated; + sal_uLong const m_nStartIndex; + +public: + SwUndoUpdateIndex(SwTOXBaseSection &); + virtual ~SwUndoUpdateIndex() override; + + void TitleSectionInserted(SwSectionFormat & rSectionFormat); + + virtual void UndoImpl(::sw::UndoRedoContext &) override; + virtual void RedoImpl(::sw::UndoRedoContext &) override; +}; + #endif // INCLUDED_SW_SOURCE_CORE_INC_UNDOSECTION_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx index 0d17568e3b09..a294c7e7e1c5 100644 --- a/sw/source/core/undo/undobj.cxx +++ b/sw/source/core/undo/undobj.cxx @@ -726,7 +726,7 @@ void SwUndoSaveContent::MoveToUndoNds( SwPaM& rPaM, SwNodeIndex* pNodeIdx, if( pCpyNd || pEndNdIdx ) { SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 ); - rDoc.GetNodes().MoveNodes( aRg, rNds, aPos.nNode, false ); + rDoc.GetNodes().MoveNodes( aRg, rNds, aPos.nNode, true ); aPos.nContent = 0; --aPos.nNode; } @@ -745,7 +745,7 @@ void SwUndoSaveContent::MoveToUndoNds( SwPaM& rPaM, SwNodeIndex* pNodeIdx, void SwUndoSaveContent::MoveFromUndoNds( SwDoc& rDoc, sal_uLong nNodeIdx, SwPosition& rInsPos, - const sal_uLong* pEndNdIdx ) + const sal_uLong* pEndNdIdx, bool const bForceCreateFrames) { // here comes the recovery SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes(); @@ -793,7 +793,7 @@ void SwUndoSaveContent::MoveFromUndoNds( SwDoc& rDoc, sal_uLong nNodeIdx, SwNodeRange aRg( rNds, nNodeIdx, rNds, (pEndNdIdx ? ((*pEndNdIdx) + 1) : rNds.GetEndOfExtras().GetIndex() ) ); - rNds.MoveNodes( aRg, rDoc.GetNodes(), rInsPos.nNode, nullptr == pEndNdIdx ); + rNds.MoveNodes(aRg, rDoc.GetNodes(), rInsPos.nNode, nullptr == pEndNdIdx || bForceCreateFrames); } else { @@ -1205,7 +1205,7 @@ void SwUndoSaveSection::SaveSection( const SwNodeIndex& rSttIdx ) } void SwUndoSaveSection::SaveSection( - const SwNodeRange& rRange ) + const SwNodeRange& rRange, bool const bExpandNodes) { SwPaM aPam( rRange.aStart, rRange.aEnd ); @@ -1231,8 +1231,11 @@ void SwUndoSaveSection::SaveSection( nStartPos = rRange.aStart.GetIndex(); - --aPam.GetPoint()->nNode; - ++aPam.GetMark()->nNode; + if (bExpandNodes) + { + --aPam.GetPoint()->nNode; + ++aPam.GetMark()->nNode; + } SwContentNode* pCNd = aPam.GetContentNode( false ); if( pCNd ) @@ -1266,13 +1269,14 @@ void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, SwNodeIndex* pIdx, } } -void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, const SwNodeIndex& rInsPos ) +void SwUndoSaveSection::RestoreSection( + SwDoc *const pDoc, const SwNodeIndex& rInsPos, bool bForceCreateFrames) { if( ULONG_MAX != nStartPos ) // was there any content? { SwPosition aInsPos( rInsPos ); sal_uLong nEnd = m_pMovedStart->GetIndex() + nMvLen - 1; - MoveFromUndoNds(*pDoc, m_pMovedStart->GetIndex(), aInsPos, &nEnd); + MoveFromUndoNds(*pDoc, m_pMovedStart->GetIndex(), aInsPos, &nEnd, bForceCreateFrames); // destroy indices again, content was deleted from UndoNodes array m_pMovedStart.reset(); diff --git a/sw/source/core/undo/unsect.cxx b/sw/source/core/undo/unsect.cxx index f449639a7937..ef84c67a138f 100644 --- a/sw/source/core/undo/unsect.cxx +++ b/sw/source/core/undo/unsect.cxx @@ -29,6 +29,8 @@ #include <IDocumentRedlineAccess.hxx> #include <IDocumentFieldsAccess.hxx> #include <IDocumentLayoutAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <poolfmt.hxx> #include <docary.hxx> #include <swundo.hxx> #include <pam.hxx> @@ -204,7 +206,8 @@ void SwUndoInsSection::RedoImpl(::sw::UndoRedoContext & rContext) pLayout = pLayoutToReset; } pUpdateTOX = rDoc.InsertTableOf( *rPam.GetPoint(), - *m_pTOXBase->first, m_pAttrSet.get(), true, pLayout); + // don't expand: will be done by SwUndoUpdateIndex::RedoImpl() + *m_pTOXBase->first, m_pAttrSet.get(), false, pLayout); } else { @@ -507,4 +510,88 @@ void SwUndoUpdateSection::RedoImpl(::sw::UndoRedoContext & rContext) UndoImpl(rContext); } + +SwUndoUpdateIndex::SwUndoUpdateIndex(SwTOXBaseSection & rTOX) + : SwUndo(SwUndoId::INSSECTION, rTOX.GetFormat()->GetDoc()) + , m_pSaveSectionOriginal(new SwUndoSaveSection) + , m_pSaveSectionUpdated(new SwUndoSaveSection) + , m_nStartIndex(rTOX.GetFormat()->GetSectionNode()->GetIndex() + 1) +{ + SwDoc & rDoc(*rTOX.GetFormat()->GetDoc()); + assert(rDoc.GetNodes()[m_nStartIndex-1]->IsSectionNode()); + assert(rDoc.GetNodes()[rDoc.GetNodes()[m_nStartIndex]->EndOfSectionIndex()-1]->IsTextNode()); // -1 for extra empty node + // note: title is optional + assert(rDoc.GetNodes()[m_nStartIndex]->IsTextNode() + || rDoc.GetNodes()[m_nStartIndex]->IsSectionNode()); + SwNodeIndex const first(rDoc.GetNodes(), m_nStartIndex); + if (first.GetNode().IsSectionNode()) + { + SwSectionFormat & rSectionFormat(*first.GetNode().GetSectionNode()->GetSection().GetFormat()); + // note: DelSectionFormat will create & append SwUndoDelSection! + rDoc.DelSectionFormat(& rSectionFormat); // remove inner section nodes + } + assert(first.GetNode().IsTextNode()); // invariant: ToX section is *never* empty + SwNodeIndex const last(rDoc.GetNodes(), rDoc.GetNodes()[m_nStartIndex]->EndOfSectionIndex() - 2); // skip empty node + assert(last.GetNode().IsTextNode()); + m_pSaveSectionOriginal->SaveSection(SwNodeRange(first, last), false); +} + +SwUndoUpdateIndex::~SwUndoUpdateIndex() = default; + +void SwUndoUpdateIndex::TitleSectionInserted(SwSectionFormat & rFormat) +{ + SwNodeIndex const tmp(rFormat.GetDoc()->GetNodes(), m_nStartIndex); // title inserted before empty node + assert(tmp.GetNode().IsSectionNode()); + assert(tmp.GetNode().GetSectionNode()->GetSection().GetFormat() == &rFormat); + m_pTitleSectionUpdated.reset(static_cast<SwUndoDelSection*>(MakeUndoDelSection(rFormat).release())); +} + +void SwUndoUpdateIndex::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc(rContext.GetDoc()); + if (m_pTitleSectionUpdated) + { + m_pTitleSectionUpdated->RedoImpl(rContext); + } + SwNodeIndex const first(rDoc.GetNodes(), m_nStartIndex); + assert(first.GetNode().IsTextNode()); // invariant: ToX section is *never* empty + SwNodeIndex const last(rDoc.GetNodes(), rDoc.GetNodes()[m_nStartIndex]->EndOfSectionIndex() - 1); + assert(last.GetNode().IsTextNode()); + // dummy node so that SaveSection doesn't remove ToX section... + SwTextNode *const pDeletionPrevention = rDoc.GetNodes().MakeTextNode( + SwNodeIndex(*rDoc.GetNodes()[m_nStartIndex]->EndOfSectionNode()), + rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_TEXT)); + m_pSaveSectionUpdated->SaveSection(SwNodeRange(first, last), false); + m_pSaveSectionOriginal->RestoreSection(&rDoc, first, true); + // delete before restoring nested undo, so its node indexes match + SwNodeIndex const del(*pDeletionPrevention); + SwDoc::CorrAbs(del, del, SwPosition(SwNodeIndex(*rDoc.GetNodes()[m_nStartIndex]->EndOfSectionNode())), true); + rDoc.GetNodes().Delete(del); + // original title section will be restored by next Undo, see ctor! +} + +void SwUndoUpdateIndex::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc(rContext.GetDoc()); + // original title section was deleted by previous Undo, see ctor! + SwNodeIndex const first(rDoc.GetNodes(), m_nStartIndex); + assert(first.GetNode().IsTextNode()); // invariant: ToX section is *never* empty + SwNodeIndex const last(rDoc.GetNodes(), rDoc.GetNodes()[m_nStartIndex]->EndOfSectionIndex() - 1); + assert(last.GetNode().IsTextNode()); + // dummy node so that SaveSection doesn't remove ToX section... + SwTextNode *const pDeletionPrevention = rDoc.GetNodes().MakeTextNode( + SwNodeIndex(*rDoc.GetNodes()[m_nStartIndex]->EndOfSectionNode()), + rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_TEXT)); + m_pSaveSectionOriginal->SaveSection(SwNodeRange(first, last), false); + m_pSaveSectionUpdated->RestoreSection(&rDoc, first, true); + // delete before restoring nested undo, so its node indexes match + SwNodeIndex const del(*pDeletionPrevention); + SwDoc::CorrAbs(del, del, SwPosition(SwNodeIndex(*rDoc.GetNodes()[m_nStartIndex]->EndOfSectionNode())), true); + rDoc.GetNodes().Delete(del); + if (m_pTitleSectionUpdated) + { + m_pTitleSectionUpdated->UndoImpl(rContext); + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |