sw/qa/core/doc/doc.cxx | 25 +++++++++++++++++++++++++ sw/source/core/doc/DocumentRedlineManager.cxx | 24 ++++++++++++------------ 2 files changed, 37 insertions(+), 12 deletions(-)
New commits: commit ba2d3e338ff72d426feda5112899fcbe7e8f90ea Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Jun 2 08:45:18 2025 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jun 2 11:10:53 2025 +0200 tdf#166319 sw interdependent redlines: handle reject of del-then-fmt's fmt The bugdoc has <del>AA<format>BB</format>CC</del> in it, rejecting the BB part is meant to get rid of the delete redline and keep the format redline. The problem is that the old code only considered the primary type (format) of the redline, but that's not correct: it's just a small detail that there was a format on top of the delete. Fix the problem by extending sw::DocumentRedlineManager::RejectRedlineRange(), so it ignores format for both insert as delete. Also simplify sw::DocumentRedlineManager::AcceptRedlineRange(), we have 3 non-overlapping cases there, so no need for bHandled there. Change-Id: I2607740dd0c1ddc447bb3f761f06c07fe80486b9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186123 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx index fc92707807f6..30811a5f241a 100644 --- a/sw/qa/core/doc/doc.cxx +++ b/sw/qa/core/doc/doc.cxx @@ -904,6 +904,31 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testDelThenFormat) // 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()); + + // And when rejecting the delete with the cursor inside BBB: + pWrtShell->Undo(); + CPPUNIT_ASSERT_EQUAL(u"AAABBBCCC"_ustr, pTextNode->GetText()); + // Undo() creates a new cursor. + pCursor = pWrtShell->GetCursor(); + pCursor->DeleteMark(); + pWrtShell->SttEndDoc(/*bStt=*/true); + // Move inside "BBB". + pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 4, /*bBasicCall=*/false); + nRedline = 0; + const SwRangeRedline* pRedline = rRedlines.FindAtPosition(*pCursor->Start(), nRedline); + // A redline is found. + CPPUNIT_ASSERT_LESS(rRedlines.size(), nRedline); + pWrtShell->RejectRedline(nRedline); + + // Then make sure the format-on-delete is rejected, i.e. the delete part is gone but the format + // part is kept: + nRedline = 0; + pRedline = rRedlines.FindAtPosition(*pCursor->Start(), nRedline); + // Without the accompanying fix in place, this test would have failed, the redline over BBB was + // gone completely. + CPPUNIT_ASSERT(pRedline); + CPPUNIT_ASSERT_EQUAL(RedlineType::Format, pRedline->GetType()); + CPPUNIT_ASSERT(!pRedline->GetRedlineData().Next()); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index 03e597162618..ef731d5d6856 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -3346,21 +3346,17 @@ bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr nPamEndCI = pTmp->Start()->GetContentIndex(); bool bHierarchicalFormat = pTmp->GetType() == RedlineType::Format && pTmp->GetStackCount() > 1; - bool bHandled = false; if (bHierarchicalFormat && pTmp->GetType(1) == RedlineType::Insert) { // This combination of 2 redline types prefers accepting the inner one first. bRet |= lcl_DeleteInnerRedline(maRedlineTable, nRdlIdx, 1); - bHandled = true; } else if (bHierarchicalFormat && pTmp->GetType(1) == RedlineType::Delete) { // Get rid of the format itself and then accept the delete by deleting the range. bRet |= lcl_AcceptInnerDelete(*pTmp, maRedlineTable, nRdlIdx, bCallDelete); - bHandled = true; } - - if (!bHandled) + else { bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete); } @@ -3653,16 +3649,15 @@ bool DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr } else if (pTmp->GetRedlineData(0).CanCombineForAcceptReject(aOrigData)) { - bool bFormatOnInsert = pTmp->GetType() == RedlineType::Format - && pTmp->GetStackCount() > 1 - && pTmp->GetType(1) == RedlineType::Insert; + bool bHierarchicalFormat + = pTmp->GetType() == RedlineType::Format && pTmp->GetStackCount() > 1; if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) { std::unique_ptr<SwUndoRedline> pUndoRdl; - if (bFormatOnInsert) + if (bHierarchicalFormat) { - // Format on insert: this is rejected by accepting the format + deleting the - // range. + // Format on an other type: just create an accept undo action, we'll deal with + // insert or delete below separately. pUndoRdl = std::make_unique<SwUndoAcceptRedline>(*pTmp); } else @@ -3677,7 +3672,7 @@ bool DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr nPamEndtNI = pTmp->Start()->GetNodeIndex(); nPamEndCI = pTmp->Start()->GetContentIndex(); - if (bFormatOnInsert) + if (bHierarchicalFormat && pTmp->GetType(1) == RedlineType::Insert) { // Accept the format itself and then reject the insert by deleting the range. SwPaM aPam(*pTmp->Start(), *pTmp->End()); @@ -3685,6 +3680,11 @@ bool DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr // Handles undo/redo itself. m_rDoc.getIDocumentContentOperations().DeleteRange(aPam); } + else if (bHierarchicalFormat && pTmp->GetType(1) == RedlineType::Delete) + { + // Keep the format redline on top, just get rid of the delete at the bottom. + bRet |= lcl_DeleteInnerRedline(maRedlineTable, nRdlIdx, 1); + } else { bRet |= lcl_RejectRedline(maRedlineTable, nRdlIdx, bCallDelete);