sw/source/core/doc/DocumentRedlineManager.cxx | 940 +++++++++++++------------- sw/source/core/inc/DocumentRedlineManager.hxx | 1 2 files changed, 476 insertions(+), 465 deletions(-)
New commits: commit 20252bd54ffdcf08a951929bf159437216294330 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed May 7 10:32:13 2025 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed May 7 16:11:10 2025 +0200 sw redline: extract a PreAppendDeleteRedline() from AppendRedline() Similar to commit 7a19e55b09dba8a7c04209f6525418a6af485e7a (sw redline: extract a PreAppendInsertRedline() from AppendRedline(), 2025-05-06), but this is for delete redlines. Change-Id: I5b4422f15c87300b4831ed33d81d353d0e1227e7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185018 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index 035c9dc35a3f..fe9b8dbbf082 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -1419,6 +1419,9 @@ public: bool& bDec; bool& bCompress; const bool bCallDelete; + + const sal_uInt32 nMoveIDToDelete; + std::set<sal_uInt32>& deletedMoveIDs; }; void DocumentRedlineManager::PreAppendInsertRedline(AppendRedlineContext& rCtx) @@ -1685,6 +1688,463 @@ void DocumentRedlineManager::PreAppendInsertRedline(AppendRedlineContext& rCtx) } } +void DocumentRedlineManager::PreAppendDeleteRedline(AppendRedlineContext& rCtx) +{ + switch( rCtx.pRedl->GetType() ) + { + case RedlineType::Delete: + switch( rCtx.eCmpPos ) + { + case SwComparePosition::Outside: + { + // Overlaps the current one completely, + // split the new one + if (*rCtx.pEnd == *rCtx.pREnd) + { + rCtx.pNewRedl->SetEnd(*rCtx.pRStt, rCtx.pEnd); + } + else if (*rCtx.pStart == *rCtx.pRStt) + { + rCtx.pNewRedl->SetStart(*rCtx.pREnd, rCtx.pStart); + } + else + { + SwRangeRedline* pNew = new SwRangeRedline( *rCtx.pNewRedl ); + pNew->SetStart( *rCtx.pREnd ); + rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd ); + AppendRedline( pNew, rCtx.bCallDelete ); + rCtx.n = 0; // re-initialize + rCtx.bDec = true; + } + } + break; + + case SwComparePosition::Inside: + case SwComparePosition::Equal: + delete rCtx.pNewRedl; + rCtx.pNewRedl = nullptr; + rCtx.bCompress = true; + + MaybeNotifyRedlineModification(*rCtx.pRedl, m_rDoc); + break; + + case SwComparePosition::OverlapBefore: + case SwComparePosition::OverlapBehind: + if( rCtx.pRedl->IsOwnRedline( *rCtx.pNewRedl ) && + rCtx.pRedl->CanCombine( *rCtx.pNewRedl )) + { + // If that's the case we can merge it, meaning + // the new one covers this well + if( SwComparePosition::OverlapBehind == rCtx.eCmpPos ) + rCtx.pNewRedl->SetStart( *rCtx.pRStt, rCtx.pStart ); + else + rCtx.pNewRedl->SetEnd( *rCtx.pREnd, rCtx.pEnd ); + maRedlineTable.DeleteAndDestroy( rCtx.n ); + rCtx.bDec = true; + } + else if( SwComparePosition::OverlapBehind == rCtx.eCmpPos ) + rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart ); + else + rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd ); + break; + + case SwComparePosition::CollideEnd: + if (rCtx.pRStt->GetContentIndex() != 0 + && rCtx.pRStt->GetNode() != rCtx.pREnd->GetNode()) + { // tdf#147466 HACK: don't combine in this case to avoid the tdf#119571 code from *undeleting* section nodes + break; + } + [[fallthrough]]; + case SwComparePosition::CollideStart: + if( rCtx.pRedl->IsOwnRedline( *rCtx.pNewRedl ) && + rCtx.pRedl->CanCombine( *rCtx.pNewRedl ) ) + { + if( IsHideChanges( GetRedlineFlags() )) + { + // Before we can merge, we make it visible! + // We insert temporarily so that pNew is + // also dealt with when moving the indices. + maRedlineTable.Insert(rCtx.pNewRedl); + rCtx.pRedl->Show(0, maRedlineTable.GetPos(rCtx.pRedl)); + maRedlineTable.Remove( rCtx.pNewRedl ); + rCtx.pRStt = rCtx.pRedl->Start(); + rCtx.pREnd = rCtx.pRedl->End(); + } + + // If that's the case we can merge it, meaning + // the new one covers this well + if( SwComparePosition::CollideStart == rCtx.eCmpPos ) + rCtx.pNewRedl->SetStart( *rCtx.pRStt, rCtx.pStart ); + else + rCtx.pNewRedl->SetEnd( *rCtx.pREnd, rCtx.pEnd ); + + // delete current (below), and restart process with + // previous + SwRedlineTable::size_type nToBeDeleted = rCtx.n; + rCtx.bDec = true; + + if( *(rCtx.pNewRedl->Start()) <= *rCtx.pREnd ) + { + // Whoooah, we just extended the new 'redline' + // beyond previous redlines, so better start + // again. Of course this is not supposed to + // happen, and in an ideal world it doesn't, + // but unfortunately this code is buggy and + // totally rotten so it does happen and we + // better fix it. + rCtx.n = 0; + } + + maRedlineTable.DeleteAndDestroy( nToBeDeleted ); + } + break; + default: + break; + } + break; + + case RedlineType::Insert: + { + // b62341295: Do not throw away redlines + // even if they are not allowed to be combined + RedlineFlags eOld = GetRedlineFlags(); + if( !( eOld & RedlineFlags::DontCombineRedlines ) && + rCtx.pRedl->IsOwnRedline( *rCtx.pNewRedl ) && + // tdf#116084 tdf#121176 don't combine anonymized deletion + // and anonymized insertion, i.e. with the same dummy timestamp + !rCtx.pRedl->GetRedlineData(0).IsAnonymized() ) + { + // Collect MoveID's of the redlines we delete. + if (rCtx.nMoveIDToDelete > 1 && maRedlineTable[rCtx.n]->GetMoved() > 0 + && (rCtx.eCmpPos == SwComparePosition::Equal + || rCtx.eCmpPos == SwComparePosition::Inside + || rCtx.eCmpPos == SwComparePosition::Outside + || rCtx.eCmpPos == SwComparePosition::OverlapBefore + || rCtx.eCmpPos == SwComparePosition::OverlapBehind)) + { + rCtx.deletedMoveIDs.insert(maRedlineTable[rCtx.n]->GetMoved()); + } + + // Set to NONE, so that the Delete::Redo merges the Redline data correctly! + // The ShowMode needs to be retained! + SetRedlineFlags_intern(eOld & ~RedlineFlags(RedlineFlags::On | RedlineFlags::Ignore)); + switch( rCtx.eCmpPos ) + { + case SwComparePosition::Equal: + rCtx.bCompress = true; + maRedlineTable.DeleteAndDestroy( rCtx.n ); + rCtx.bDec = true; + [[fallthrough]]; + + case SwComparePosition::Inside: + if( rCtx.bCallDelete ) + { + // DeleteAndJoin does not yield the + // desired result if there is no paragraph to + // join with, i.e. at the end of the document. + // For this case, we completely delete the + // paragraphs (if, of course, we also start on + // a paragraph boundary). + if( (rCtx.pStart->GetContentIndex() == 0) && + rCtx.pEnd->GetNode().IsEndNode() ) + { + rCtx.pEnd->Adjust(SwNodeOffset(-1)); + m_rDoc.getIDocumentContentOperations().DelFullPara( *rCtx.pNewRedl ); + } + else + m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *rCtx.pNewRedl ); + + rCtx.bCompress = true; + } + delete rCtx.pNewRedl; + rCtx.pNewRedl = nullptr; + + // No need to call MaybeNotifyRedlineModification, because a notification + // was already sent in DocumentRedlineManager::DeleteRedline + break; + + case SwComparePosition::Outside: + { + maRedlineTable.Remove( rCtx.n ); + rCtx.bDec = true; + if( rCtx.bCallDelete ) + { + TemporaryRedlineUpdater const u(m_rDoc, *rCtx.pNewRedl); + m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *rCtx.pRedl ); + rCtx.n = 0; // re-initialize + } + delete rCtx.pRedl; + } + break; + + case SwComparePosition::OverlapBefore: + { + SwPaM aPam( *rCtx.pRStt, *rCtx.pEnd ); + + if( *rCtx.pEnd == *rCtx.pREnd ) + maRedlineTable.DeleteAndDestroy( rCtx.n ); + else + { + rCtx.pRedl->SetStart( *rCtx.pEnd, rCtx.pRStt ); + // re-insert + maRedlineTable.Remove( rCtx.n ); + maRedlineTable.Insert( rCtx.pRedl, rCtx.n ); + } + + if( rCtx.bCallDelete ) + { + TemporaryRedlineUpdater const u(m_rDoc, *rCtx.pNewRedl); + m_rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); + rCtx.n = 0; // re-initialize + } + rCtx.bDec = true; + } + break; + + case SwComparePosition::OverlapBehind: + { + SwPaM aPam( *rCtx.pStart, *rCtx.pREnd ); + + if( *rCtx.pStart == *rCtx.pRStt ) + { + maRedlineTable.DeleteAndDestroy( rCtx.n ); + rCtx.bDec = true; + } + else + rCtx.pRedl->SetEnd( *rCtx.pStart, rCtx.pREnd ); + + if( rCtx.bCallDelete ) + { + TemporaryRedlineUpdater const u(m_rDoc, *rCtx.pNewRedl); + m_rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); + rCtx.n = 0; // re-initialize + rCtx.bDec = true; + } + } + break; + default: + break; + } + + SetRedlineFlags_intern(eOld); + } + else + { + // it may be necessary to split the existing redline in + // two. In this case, pRedl will be changed to cover + // only part of its former range, and pNew will cover + // the remainder. + SwRangeRedline* pNew = nullptr; + + switch( rCtx.eCmpPos ) + { + case SwComparePosition::Equal: + { + rCtx.pRedl->PushData( *rCtx.pNewRedl ); + delete rCtx.pNewRedl; + rCtx.pNewRedl = nullptr; + if( IsHideChanges( GetRedlineFlags() )) + { + rCtx.pRedl->Hide(0, maRedlineTable.GetPos(rCtx.pRedl)); + } + rCtx.bCompress = true; + + // set IsMoved checking nearby redlines + SwRedlineTable::size_type nRIdx = maRedlineTable.GetPos(rCtx.pRedl); + if (nRIdx < maRedlineTable.size()) // in case above 're-insert' failed + maRedlineTable.isMoved(nRIdx); + + } + break; + + case SwComparePosition::Inside: + { + if( *rCtx.pRStt == *rCtx.pStart ) + { + // #i97421# + // redline w/out extent loops + if (*rCtx.pStart != *rCtx.pEnd) + { + rCtx.pNewRedl->PushData( *rCtx.pRedl, false ); + rCtx.pRedl->SetStart( *rCtx.pEnd, rCtx.pRStt ); + // re-insert + maRedlineTable.Remove( rCtx.n ); + maRedlineTable.Insert( rCtx.pRedl, rCtx.n ); + rCtx.bDec = true; + } + } + else + { + rCtx.pNewRedl->PushData( *rCtx.pRedl, false ); + if( *rCtx.pREnd != *rCtx.pEnd ) + { + pNew = new SwRangeRedline( *rCtx.pRedl ); + pNew->SetStart( *rCtx.pEnd ); + } + rCtx.pRedl->SetEnd( *rCtx.pStart, rCtx.pREnd ); + if( !rCtx.pRedl->HasValidRange() ) + { + // re-insert + maRedlineTable.Remove( rCtx.n ); + maRedlineTable.Insert( rCtx.pRedl, rCtx.n ); + } + } + } + break; + + case SwComparePosition::Outside: + { + rCtx.pRedl->PushData( *rCtx.pNewRedl ); + if( *rCtx.pEnd == *rCtx.pREnd ) + { + rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd ); + } + else if (*rCtx.pStart == *rCtx.pRStt) + { + rCtx.pNewRedl->SetStart(*rCtx.pREnd, rCtx.pStart); + } + else + { + pNew = new SwRangeRedline( *rCtx.pNewRedl ); + pNew->SetEnd( *rCtx.pRStt ); + rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart ); + } + rCtx.bCompress = true; + } + break; + + case SwComparePosition::OverlapBefore: + { + if( *rCtx.pEnd == *rCtx.pREnd ) + { + rCtx.pRedl->PushData( *rCtx.pNewRedl ); + rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd ); + if( IsHideChanges( GetRedlineFlags() )) + { + maRedlineTable.Insert(rCtx.pNewRedl); + rCtx.pRedl->Hide(0, maRedlineTable.GetPos(rCtx.pRedl)); + maRedlineTable.Remove( rCtx.pNewRedl ); + } + } + else + { + pNew = new SwRangeRedline( *rCtx.pRedl ); + pNew->PushData( *rCtx.pNewRedl ); + pNew->SetEnd( *rCtx.pEnd ); + rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd ); + rCtx.pRedl->SetStart( *pNew->End(), rCtx.pRStt ) ; + // re-insert + maRedlineTable.Remove( rCtx.n ); + maRedlineTable.Insert( rCtx.pRedl ); + rCtx.bDec = true; + } + } + break; + + case SwComparePosition::OverlapBehind: + { + if( *rCtx.pStart == *rCtx.pRStt ) + { + rCtx.pRedl->PushData( *rCtx.pNewRedl ); + rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart ); + if( IsHideChanges( GetRedlineFlags() )) + { + maRedlineTable.Insert( rCtx.pNewRedl ); + rCtx.pRedl->Hide(0, maRedlineTable.GetPos(rCtx.pRedl)); + maRedlineTable.Remove( rCtx.pNewRedl ); + } + } + else + { + pNew = new SwRangeRedline( *rCtx.pRedl ); + pNew->PushData( *rCtx.pNewRedl ); + pNew->SetStart( *rCtx.pStart ); + rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart ); + rCtx.pRedl->SetEnd( *pNew->Start(), rCtx.pREnd ); + if( !rCtx.pRedl->HasValidRange() ) + { + // re-insert + maRedlineTable.Remove( rCtx.n ); + maRedlineTable.Insert( rCtx.pRedl ); + } + } + } + break; + default: + break; + } + + // insert the pNew part (if it exists) + if( pNew ) + { + maRedlineTable.Insert( pNew ); + + // pNew must be deleted if Insert() wasn't + // successful. But that can't happen, since pNew is + // part of the original pRedl redline. + // OSL_ENSURE( bRet, "Can't insert existing redline?" ); + + // restart (now with pRedl being split up) + rCtx.n = 0; + rCtx.bDec = true; + } + } + } + break; + + case RedlineType::Format: + switch( rCtx.eCmpPos ) + { + case SwComparePosition::OverlapBefore: + rCtx.pRedl->SetStart( *rCtx.pEnd, rCtx.pRStt ); + // re-insert + maRedlineTable.Remove( rCtx.n ); + maRedlineTable.Insert( rCtx.pRedl, rCtx.n ); + rCtx.bDec = true; + break; + + case SwComparePosition::OverlapBehind: + rCtx.pRedl->SetEnd( *rCtx.pStart, rCtx.pREnd ); + break; + + case SwComparePosition::Equal: + case SwComparePosition::Outside: + // Overlaps the current one completely or has the + // same dimension, delete the old one + maRedlineTable.DeleteAndDestroy( rCtx.n ); + rCtx.bDec = true; + break; + + case SwComparePosition::Inside: + // Overlaps the current one completely, + // split or shorten the new one + if( *rCtx.pEnd != *rCtx.pREnd ) + { + if( *rCtx.pEnd != *rCtx.pRStt ) + { + SwRangeRedline* pNew = new SwRangeRedline( *rCtx.pRedl ); + pNew->SetStart( *rCtx.pEnd ); + rCtx.pRedl->SetEnd( *rCtx.pStart, rCtx.pREnd ); + if( ( *rCtx.pStart == *rCtx.pRStt ) && + ( rCtx.pRedl->GetContentIdx() == nullptr ) ) + maRedlineTable.DeleteAndDestroy( rCtx.n ); + AppendRedline( pNew, rCtx.bCallDelete ); + rCtx.n = 0; // re-initialize + rCtx.bDec = true; + } + } + else + rCtx.pRedl->SetEnd( *rCtx.pStart, rCtx.pREnd ); + break; + default: + break; + } + break; + default: + break; + } +} + /* Text means Text not "polluted" by Redlines. @@ -1821,480 +2281,30 @@ DocumentRedlineManager::AppendRedline(SwRangeRedline* pNewRedl, bool const bCall if ( SwComparePosition::Before == eCmpPos && !IsPrevPos( *pEnd, *pRStt )) break; + AppendRedlineContext aContext{ pNewRedl, + pStart, + pEnd, + pRedl, + pRStt, + pREnd, + eCmpPos, + n, + bMerged, + bDec, + bCompress, + bCallDelete, + nMoveIDToDelete, + deletedMoveIDs }; switch( pNewRedl->GetType() ) { case RedlineType::Insert: { - AppendRedlineContext aContext{ pNewRedl, - pStart, - pEnd, - pRedl, - pRStt, - pREnd, - eCmpPos, - n, - bMerged, - bDec, - bCompress, - bCallDelete }; PreAppendInsertRedline(aContext); break; } case RedlineType::Delete: - switch( pRedl->GetType() ) - { - case RedlineType::Delete: - switch( eCmpPos ) - { - case SwComparePosition::Outside: - { - // Overlaps the current one completely, - // split the new one - if (*pEnd == *pREnd) - { - pNewRedl->SetEnd(*pRStt, pEnd); - } - else if (*pStart == *pRStt) - { - pNewRedl->SetStart(*pREnd, pStart); - } - else - { - SwRangeRedline* pNew = new SwRangeRedline( *pNewRedl ); - pNew->SetStart( *pREnd ); - pNewRedl->SetEnd( *pRStt, pEnd ); - AppendRedline( pNew, bCallDelete ); - n = 0; // re-initialize - bDec = true; - } - } - break; - - case SwComparePosition::Inside: - case SwComparePosition::Equal: - delete pNewRedl; - pNewRedl = nullptr; - bCompress = true; - - MaybeNotifyRedlineModification(*pRedl, m_rDoc); - break; - - case SwComparePosition::OverlapBefore: - case SwComparePosition::OverlapBehind: - if( pRedl->IsOwnRedline( *pNewRedl ) && - pRedl->CanCombine( *pNewRedl )) - { - // If that's the case we can merge it, meaning - // the new one covers this well - if( SwComparePosition::OverlapBehind == eCmpPos ) - pNewRedl->SetStart( *pRStt, pStart ); - else - pNewRedl->SetEnd( *pREnd, pEnd ); - maRedlineTable.DeleteAndDestroy( n ); - bDec = true; - } - else if( SwComparePosition::OverlapBehind == eCmpPos ) - pNewRedl->SetStart( *pREnd, pStart ); - else - pNewRedl->SetEnd( *pRStt, pEnd ); - break; - - case SwComparePosition::CollideEnd: - if (pRStt->GetContentIndex() != 0 - && pRStt->GetNode() != pREnd->GetNode()) - { // tdf#147466 HACK: don't combine in this case to avoid the tdf#119571 code from *undeleting* section nodes - break; - } - [[fallthrough]]; - case SwComparePosition::CollideStart: - if( pRedl->IsOwnRedline( *pNewRedl ) && - pRedl->CanCombine( *pNewRedl ) ) - { - if( IsHideChanges( GetRedlineFlags() )) - { - // Before we can merge, we make it visible! - // We insert temporarily so that pNew is - // also dealt with when moving the indices. - maRedlineTable.Insert(pNewRedl); - pRedl->Show(0, maRedlineTable.GetPos(pRedl)); - maRedlineTable.Remove( pNewRedl ); - pRStt = pRedl->Start(); - pREnd = pRedl->End(); - } - - // If that's the case we can merge it, meaning - // the new one covers this well - if( SwComparePosition::CollideStart == eCmpPos ) - pNewRedl->SetStart( *pRStt, pStart ); - else - pNewRedl->SetEnd( *pREnd, pEnd ); - - // delete current (below), and restart process with - // previous - SwRedlineTable::size_type nToBeDeleted = n; - bDec = true; - - if( *(pNewRedl->Start()) <= *pREnd ) - { - // Whoooah, we just extended the new 'redline' - // beyond previous redlines, so better start - // again. Of course this is not supposed to - // happen, and in an ideal world it doesn't, - // but unfortunately this code is buggy and - // totally rotten so it does happen and we - // better fix it. - n = 0; - } - - maRedlineTable.DeleteAndDestroy( nToBeDeleted ); - } - break; - default: - break; - } - break; - - case RedlineType::Insert: - { - // b62341295: Do not throw away redlines - // even if they are not allowed to be combined - RedlineFlags eOld = GetRedlineFlags(); - if( !( eOld & RedlineFlags::DontCombineRedlines ) && - pRedl->IsOwnRedline( *pNewRedl ) && - // tdf#116084 tdf#121176 don't combine anonymized deletion - // and anonymized insertion, i.e. with the same dummy timestamp - !pRedl->GetRedlineData(0).IsAnonymized() ) - { - // Collect MoveID's of the redlines we delete. - if (nMoveIDToDelete > 1 && maRedlineTable[n]->GetMoved() > 0 - && (eCmpPos == SwComparePosition::Equal - || eCmpPos == SwComparePosition::Inside - || eCmpPos == SwComparePosition::Outside - || eCmpPos == SwComparePosition::OverlapBefore - || eCmpPos == SwComparePosition::OverlapBehind)) - { - deletedMoveIDs.insert(maRedlineTable[n]->GetMoved()); - } - - // Set to NONE, so that the Delete::Redo merges the Redline data correctly! - // The ShowMode needs to be retained! - SetRedlineFlags_intern(eOld & ~RedlineFlags(RedlineFlags::On | RedlineFlags::Ignore)); - switch( eCmpPos ) - { - case SwComparePosition::Equal: - bCompress = true; - maRedlineTable.DeleteAndDestroy( n ); - bDec = true; - [[fallthrough]]; - - case SwComparePosition::Inside: - if( bCallDelete ) - { - // DeleteAndJoin does not yield the - // desired result if there is no paragraph to - // join with, i.e. at the end of the document. - // For this case, we completely delete the - // paragraphs (if, of course, we also start on - // a paragraph boundary). - if( (pStart->GetContentIndex() == 0) && - pEnd->GetNode().IsEndNode() ) - { - pEnd->Adjust(SwNodeOffset(-1)); - m_rDoc.getIDocumentContentOperations().DelFullPara( *pNewRedl ); - } - else - m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pNewRedl ); - - bCompress = true; - } - delete pNewRedl; - pNewRedl = nullptr; - - // No need to call MaybeNotifyRedlineModification, because a notification - // was already sent in DocumentRedlineManager::DeleteRedline - break; - - case SwComparePosition::Outside: - { - maRedlineTable.Remove( n ); - bDec = true; - if( bCallDelete ) - { - TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl); - m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pRedl ); - n = 0; // re-initialize - } - delete pRedl; - } - break; - - case SwComparePosition::OverlapBefore: - { - SwPaM aPam( *pRStt, *pEnd ); - - if( *pEnd == *pREnd ) - maRedlineTable.DeleteAndDestroy( n ); - else - { - pRedl->SetStart( *pEnd, pRStt ); - // re-insert - maRedlineTable.Remove( n ); - maRedlineTable.Insert( pRedl, n ); - } - - if( bCallDelete ) - { - TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl); - m_rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); - n = 0; // re-initialize - } - bDec = true; - } - break; - - case SwComparePosition::OverlapBehind: - { - SwPaM aPam( *pStart, *pREnd ); - - if( *pStart == *pRStt ) - { - maRedlineTable.DeleteAndDestroy( n ); - bDec = true; - } - else - pRedl->SetEnd( *pStart, pREnd ); - - if( bCallDelete ) - { - TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl); - m_rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); - n = 0; // re-initialize - bDec = true; - } - } - break; - default: - break; - } - - SetRedlineFlags_intern(eOld); - } - else - { - // it may be necessary to split the existing redline in - // two. In this case, pRedl will be changed to cover - // only part of its former range, and pNew will cover - // the remainder. - SwRangeRedline* pNew = nullptr; - - switch( eCmpPos ) - { - case SwComparePosition::Equal: - { - pRedl->PushData( *pNewRedl ); - delete pNewRedl; - pNewRedl = nullptr; - if( IsHideChanges( GetRedlineFlags() )) - { - pRedl->Hide(0, maRedlineTable.GetPos(pRedl)); - } - bCompress = true; - - // set IsMoved checking nearby redlines - SwRedlineTable::size_type nRIdx = maRedlineTable.GetPos(pRedl); - if (nRIdx < maRedlineTable.size()) // in case above 're-insert' failed - maRedlineTable.isMoved(nRIdx); - - } - break; - - case SwComparePosition::Inside: - { - if( *pRStt == *pStart ) - { - // #i97421# - // redline w/out extent loops - if (*pStart != *pEnd) - { - pNewRedl->PushData( *pRedl, false ); - pRedl->SetStart( *pEnd, pRStt ); - // re-insert - maRedlineTable.Remove( n ); - maRedlineTable.Insert( pRedl, n ); - bDec = true; - } - } - else - { - pNewRedl->PushData( *pRedl, false ); - if( *pREnd != *pEnd ) - { - pNew = new SwRangeRedline( *pRedl ); - pNew->SetStart( *pEnd ); - } - pRedl->SetEnd( *pStart, pREnd ); - if( !pRedl->HasValidRange() ) - { - // re-insert - maRedlineTable.Remove( n ); - maRedlineTable.Insert( pRedl, n ); - } - } - } - break; - - case SwComparePosition::Outside: - { - pRedl->PushData( *pNewRedl ); - if( *pEnd == *pREnd ) - { - pNewRedl->SetEnd( *pRStt, pEnd ); - } - else if (*pStart == *pRStt) - { - pNewRedl->SetStart(*pREnd, pStart); - } - else - { - pNew = new SwRangeRedline( *pNewRedl ); - pNew->SetEnd( *pRStt ); - pNewRedl->SetStart( *pREnd, pStart ); - } - bCompress = true; - } - break; - - case SwComparePosition::OverlapBefore: - { - if( *pEnd == *pREnd ) - { - pRedl->PushData( *pNewRedl ); - pNewRedl->SetEnd( *pRStt, pEnd ); - if( IsHideChanges( GetRedlineFlags() )) - { - maRedlineTable.Insert(pNewRedl); - pRedl->Hide(0, maRedlineTable.GetPos(pRedl)); - maRedlineTable.Remove( pNewRedl ); - } - } - else - { - pNew = new SwRangeRedline( *pRedl ); - pNew->PushData( *pNewRedl ); - pNew->SetEnd( *pEnd ); - pNewRedl->SetEnd( *pRStt, pEnd ); - pRedl->SetStart( *pNew->End(), pRStt ) ; - // re-insert - maRedlineTable.Remove( n ); - maRedlineTable.Insert( pRedl ); - bDec = true; - } - } - break; - - case SwComparePosition::OverlapBehind: - { - if( *pStart == *pRStt ) - { - pRedl->PushData( *pNewRedl ); - pNewRedl->SetStart( *pREnd, pStart ); - if( IsHideChanges( GetRedlineFlags() )) - { - maRedlineTable.Insert( pNewRedl ); - pRedl->Hide(0, maRedlineTable.GetPos(pRedl)); - maRedlineTable.Remove( pNewRedl ); - } - } - else - { - pNew = new SwRangeRedline( *pRedl ); - pNew->PushData( *pNewRedl ); - pNew->SetStart( *pStart ); - pNewRedl->SetStart( *pREnd, pStart ); - pRedl->SetEnd( *pNew->Start(), pREnd ); - if( !pRedl->HasValidRange() ) - { - // re-insert - maRedlineTable.Remove( n ); - maRedlineTable.Insert( pRedl ); - } - } - } - break; - default: - break; - } - - // insert the pNew part (if it exists) - if( pNew ) - { - maRedlineTable.Insert( pNew ); - - // pNew must be deleted if Insert() wasn't - // successful. But that can't happen, since pNew is - // part of the original pRedl redline. - // OSL_ENSURE( bRet, "Can't insert existing redline?" ); - - // restart (now with pRedl being split up) - n = 0; - bDec = true; - } - } - } - break; - - case RedlineType::Format: - switch( eCmpPos ) - { - case SwComparePosition::OverlapBefore: - pRedl->SetStart( *pEnd, pRStt ); - // re-insert - maRedlineTable.Remove( n ); - maRedlineTable.Insert( pRedl, n ); - bDec = true; - break; - - case SwComparePosition::OverlapBehind: - pRedl->SetEnd( *pStart, pREnd ); - break; - - case SwComparePosition::Equal: - case SwComparePosition::Outside: - // Overlaps the current one completely or has the - // same dimension, delete the old one - maRedlineTable.DeleteAndDestroy( n ); - bDec = true; - break; - - case SwComparePosition::Inside: - // Overlaps the current one completely, - // split or shorten the new one - if( *pEnd != *pREnd ) - { - if( *pEnd != *pRStt ) - { - SwRangeRedline* pNew = new SwRangeRedline( *pRedl ); - pNew->SetStart( *pEnd ); - pRedl->SetEnd( *pStart, pREnd ); - if( ( *pStart == *pRStt ) && - ( pRedl->GetContentIdx() == nullptr ) ) - maRedlineTable.DeleteAndDestroy( n ); - AppendRedline( pNew, bCallDelete ); - n = 0; // re-initialize - bDec = true; - } - } - else - pRedl->SetEnd( *pStart, pREnd ); - break; - default: - break; - } - break; - default: - break; - } + PreAppendDeleteRedline(aContext); break; case RedlineType::Format: diff --git a/sw/source/core/inc/DocumentRedlineManager.hxx b/sw/source/core/inc/DocumentRedlineManager.hxx index 6287ccc1c2e9..7adc4f4cb4c6 100644 --- a/sw/source/core/inc/DocumentRedlineManager.hxx +++ b/sw/source/core/inc/DocumentRedlineManager.hxx @@ -166,6 +166,7 @@ private: bool AcceptMovedRedlines(sal_uInt32 nMovedID, bool bCallDelete); bool RejectMovedRedlines(sal_uInt32 nMovedID, bool bCallDelete); void PreAppendInsertRedline(AppendRedlineContext& rCtx); + void PreAppendDeleteRedline(AppendRedlineContext& rCtx); DocumentRedlineManager(DocumentRedlineManager const&) = delete; DocumentRedlineManager& operator=(DocumentRedlineManager const&) = delete;