sw/qa/core/doc/doc.cxx | 25 +++++++++++++++++++++++++ sw/source/core/doc/DocumentRedlineManager.cxx | 24 ++++++++++++------------ 2 files changed, 37 insertions(+), 12 deletions(-)
New commits: commit 569eb476bbdf83aab0f377da5cb7d2e8c77192b8 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 12:14:44 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/+/186127 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx index 439ee619dacb..d4396bc24e32 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 1a365a927d43..386f49c9022c 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -3345,21 +3345,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); } @@ -3652,16 +3648,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 @@ -3676,7 +3671,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()); @@ -3684,6 +3679,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);