sw/qa/core/doc/doc.cxx | 37 ++++++++++++++++++++++++++ sw/source/core/doc/DocumentRedlineManager.cxx | 11 ++++++- sw/source/core/undo/unredln.cxx | 4 ++ 3 files changed, 50 insertions(+), 2 deletions(-)
New commits: commit 0a33618f791995a6a67aad14cd7b65976ffd8eda Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Jul 7 10:52:26 2025 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Mon Jul 7 14:25:08 2025 +0200 tdf#166319 sw interdependent redlines: fix redo of accept of ins-then-fmt's fmt The bugdoc has <ins>AA<format>BB</format>CC</ins>, go to middle of BB, accept, undo, redo: there is no format redline in the document, but there should be one. What happens is that the "accept" action creates an SwUndoAcceptRedline with the default depth = 0, but then it carefully calls lcl_DeleteInnerRedline() in sw::DocumentRedlineManager::AcceptRedlineRange() instead of a plain accept. The undo action already knows how to only accept the underlying redline, so fix the problem in sw::DocumentRedlineManager::AcceptRedlineRange() by correctly recording the UI action with depth = 1, which gives us both working undo & redo. The exec of the undo action's redo calls sw::DocumentRedlineManager::AcceptRedline(), which now calls the same lcl_DeleteInnerRedline() as the original UI action, so this looks consistent now. Change-Id: Ibb21c0745f3dd0aacec7cf7448c7c85245dbee69 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187467 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 ba2520d4054e..96869044ce82 100644 --- a/sw/qa/core/doc/doc.cxx +++ b/sw/qa/core/doc/doc.cxx @@ -908,6 +908,43 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testInsThenFormat) // 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 given a state where you're just after the undo for the accept of insert-then-format's + // format: + pWrtShell->Undo(); + // 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; + rRedlines.FindAtPosition(*pCursor->Start(), nRedline); + // A redline is found. + CPPUNIT_ASSERT_LESS(rRedlines.size(), nRedline); + pWrtShell->AcceptRedline(nRedline); + pWrtShell->Undo(); + + // When redoing that accept: + pWrtShell->Redo(); + + // Then make sure we have a single format redline as a result: + pCursor = pWrtShell->GetCursor(); + pCursor->DeleteMark(); + pWrtShell->SttEndDoc(/*bStt=*/true); + // Move inside "BBB". + pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 4, /*bBasicCall=*/false); + nRedline = 0; + pRedline = rRedlines.FindAtPosition(*pCursor->Start(), nRedline); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. everything was accepted, even the format redline was gone from the document, instead of + // just accepting the underlying insert. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size()); + CPPUNIT_ASSERT(pRedline); + CPPUNIT_ASSERT_EQUAL(RedlineType::Format, pRedline->GetType()); + CPPUNIT_ASSERT(!pRedline->GetRedlineData().Next()); } CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testDelThenFormat) diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index a02f5b947a57..8d8358d0fe80 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -3358,15 +3358,22 @@ bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr } else if (pTmp->GetRedlineData(0).CanCombineForAcceptReject(aOrigData)) { + bool bHierarchicalFormat = pTmp->GetType() == RedlineType::Format && pTmp->GetStackCount() > 1; if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) { + sal_Int8 nDepth = 0; + if (bHierarchicalFormat && pTmp->GetType(1) == RedlineType::Insert) + { + // Only work with the underlying insert, so the undo action matches the UI + // action below. + nDepth = 1; + } m_rDoc.GetIDocumentUndoRedo().AppendUndo( - std::make_unique<SwUndoAcceptRedline>(*pTmp)); + std::make_unique<SwUndoAcceptRedline>(*pTmp, nDepth)); } nPamEndNI = pTmp->Start()->GetNodeIndex(); nPamEndCI = pTmp->Start()->GetContentIndex(); - bool bHierarchicalFormat = pTmp->GetType() == RedlineType::Format && pTmp->GetStackCount() > 1; if (bHierarchicalFormat && pTmp->GetType(1) == RedlineType::Insert) { // This combination of 2 redline types prefers accepting the inner one first. diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx index 7786b1a5cf42..77c15f282b7d 100644 --- a/sw/source/core/undo/unredln.cxx +++ b/sw/source/core/undo/unredln.cxx @@ -125,6 +125,10 @@ void SwUndoRedline::dumpAsXml(xmlTextWriterPtr pWriter) const (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(mbHierarchical).getStr())); (void)xmlTextWriterEndElement(pWriter); + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("depth")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), + BAD_CAST(OString::number(mnDepth).getStr())); + (void)xmlTextWriterEndElement(pWriter); (void)xmlTextWriterEndElement(pWriter); }