sw/qa/core/doc/doc.cxx | 11 +--- sw/source/core/doc/DocumentRedlineManager.cxx | 66 ++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 16 deletions(-)
New commits: commit a76771f6e9b4bc845a69adf9d72e34223f7097bc Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri May 30 08:26:07 2025 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Fri May 30 10:36:41 2025 +0200 tdf#166319 sw interdependent redlines: combine on accept of del-then-fmt's fmt The bugdoc has <del>AA<format>BB</format>CC</del> in it, accepting the BB part resulted in <del>AA</del><del>CC</del>. The removal of BB is good, but there was no combine to also remove AA and CC. The problem is that the delete-then-format wasn't combined with the surrounding delete redlines. Fix the problem by introducing a new CanReverseCombineTypesForAccept() for the case when the redline with 2 types is conditionally combined with an other redline and by using that in sw::DocumentRedlineManager::AcceptRedlineRange(). Also extract some duplicated code into a new lcl_AcceptInnerDelete(). Change-Id: Ib5881b6c9aa44ae5dcf79342dbd64bbd61f734c2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186029 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx index 68433eb15939..fc92707807f6 100644 --- a/sw/qa/core/doc/doc.cxx +++ b/sw/qa/core/doc/doc.cxx @@ -899,12 +899,11 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testDelThenFormat) CPPUNIT_ASSERT_LESS(rRedlines.size(), nRedline); pWrtShell->AcceptRedline(nRedline); - // Then make sure BBB gets removed from the document: - // Without the accompanying fix in place, this test would have failed with: - // - Expected: AAACCC - // - Actual : AAABBBCCC - // i.e. BBB's formatting was removed, but not BBB itself. - CPPUNIT_ASSERT_EQUAL(u"AAACCC"_ustr, pTextNode->GetText()); + // Then make sure the format-on-delete is accepted, i.e. neither the format-on-delete BBB, nor + // the surrounding AAA and CCC deletes are in the text anymore: + // Without the accompanying fix in place, this test would have failed, the text was AAABBBCCC, + // just the format of BBB was dropped. + CPPUNIT_ASSERT(pTextNode->GetText().isEmpty()); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index 8d66eff2f9ae..cde8434a6641 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -1012,6 +1012,24 @@ namespace return true; } + /// Given a redline that has two types and the underlying type is + /// delete, reject the redline based on that underlying type. Used + /// to accept a delete-then-format, i.e. this does change the text + /// node string. + bool lcl_AcceptInnerDelete(SwRangeRedline& rRedline, SwRedlineTable& rRedlines, + SwRedlineTable::size_type& rRedlineIndex, bool bCallDelete) + { + bool bRet = false; + + SwPaM aPam(*rRedline.Start(), *rRedline.End()); + bRet |= lcl_RejectRedline(rRedlines, rRedlineIndex, bCallDelete); + // Handles undo/redo itself. + SwDoc& rDoc = rRedline.GetDoc(); + rDoc.getIDocumentContentOperations().DeleteRange(aPam); + + return bRet; + } + typedef bool (*Fn_AcceptReject)( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos, bool bCallDelete, const SwPosition* pSttRng, @@ -1174,6 +1192,41 @@ bool CanCombineTypesForAcceptReject(SwRedlineData& rInnerData, SwRangeRedline& r return true; } + +/// Decides if it's OK to combine this rInnerData having 2 types with an +/// outer rOuterRedline for accept purposes. E.g. format-on-delete and +/// delete can be combined if accepting a delete. +bool CanReverseCombineTypesForAccept(SwRangeRedline& rOuterRedline, SwRedlineData& rInnerData) +{ + switch (rOuterRedline.GetType()) + { + case RedlineType::Insert: + case RedlineType::Delete: + break; + default: + return false; + } + + if (rInnerData.GetType() != RedlineType::Format) + { + return false; + } + + const SwRedlineData* pInnerDataNext = rInnerData.Next(); + if (!pInnerDataNext) + { + return false; + } + + switch (pInnerDataNext->GetType()) + { + case RedlineType::Insert: + case RedlineType::Delete: + return pInnerDataNext->GetType() == rOuterRedline.GetType(); + default: + return false; + } +} } namespace sw @@ -3303,10 +3356,7 @@ bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr else if (bHierarchicalFormat && pTmp->GetType(1) == RedlineType::Delete) { // Get rid of the format itself and then accept the delete by deleting the range. - SwPaM aPam(*pTmp->Start(), *pTmp->End()); - bRet |= lcl_RejectRedline(maRedlineTable, nRdlIdx, bCallDelete); - // Handles undo/redo itself. - m_rDoc.getIDocumentContentOperations().DeleteRange(aPam); + bRet |= lcl_AcceptInnerDelete(*pTmp, maRedlineTable, nRdlIdx, bCallDelete); bHandled = true; } @@ -3331,9 +3381,7 @@ bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr if (aOrigData.GetType() == RedlineType::Delete) { // We should delete the other type of redline when accepting the inner delete. - SwPaM aPam(*pTmp->Start(), *pTmp->End()); - bRet |= lcl_RejectRedline(maRedlineTable, nRdlIdx, bCallDelete); - m_rDoc.getIDocumentContentOperations().DeleteRange(aPam); + bRet |= lcl_AcceptInnerDelete(*pTmp, maRedlineTable, nRdlIdx, bCallDelete); } else { @@ -3342,9 +3390,7 @@ bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr } nRdlIdx++; //we will decrease it in the loop anyway. } - else if (pTmp->GetType() == RedlineType::Insert - && aOrigData.GetType() == RedlineType::Format && aOrigData.Next() - && aOrigData.Next()->GetType() == RedlineType::Insert) + else if (CanReverseCombineTypesForAccept(*pTmp, aOrigData)) { // The aOrigData has 2 types and for these types we want the underlying type to be // combined with the type of the surrounding redlines, so accept pTmp, too.