sw/qa/core/doc/DocumentRedlineManager.cxx | 45 ++++++++++++++++++++++++++ sw/qa/core/doc/data/fmt.docx |binary sw/source/core/doc/DocumentRedlineManager.cxx | 6 +++ 3 files changed, 51 insertions(+)
New commits: commit d0573fff47767656494d26d523cca65429319c26 Author: Miklos Vajna <[email protected]> AuthorDate: Tue Jan 6 08:32:50 2026 +0100 Commit: Caolán McNamara <[email protected]> CommitDate: Fri Jan 9 09:53:02 2026 +0100 Related: tdf#168751 sw interdependent redlines, format on del: fix del-on-fmt Open the bugdoc which has a <format>BBBCCCDDD</format> redline. Select CCC, press delete: now CCC is only covered by a delete redline instead of a format-on-delete redline. The trouble is in sw::DocumentRedlineManager::PreAppendDeleteRedline(), where rCtx.pRedl (format redline) initially covers BBBCCCDDD, but then it gets reduced to cover only BBB. We also create a pNew redline to cover only DDD. This gives Writer a way to set rCtx.pNewRedl's range to CCC without an overlap. The downside is that now reject-all doesn't modify the format of CCC anymore, so some unexpected boldness remains in the document. Fix this similar to how sw::DocumentRedlineManager::PreAppendForeignRedline()'s rCtx.eCmpPos == SwComparePosition::Inside case works: except there PushData() is used to push the redline data "over" (before creating pNew), and here we use PushData() to push the redline data "under". This way UI creates a model where format is always on top of delete (and not the other way around), which is useful, since DOCX only has markup for that order and ODT explicitly says this order should be used in files. Change-Id: Ida640ad7bb99ed89faef306dac2b840ae3be53f3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196592 Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> diff --git a/sw/qa/core/doc/DocumentRedlineManager.cxx b/sw/qa/core/doc/DocumentRedlineManager.cxx index 6bc0e2fef3bd..fdbc9ca90808 100644 --- a/sw/qa/core/doc/DocumentRedlineManager.cxx +++ b/sw/qa/core/doc/DocumentRedlineManager.cxx @@ -392,6 +392,51 @@ CPPUNIT_TEST_FIXTURE(Test, testDelThenFormatOwn) CPPUNIT_ASSERT(!rRedlineData.Next()); } } + +CPPUNIT_TEST_FIXTURE(Test, testFormatThenDel) +{ + // Given an "AAA <format>BBB CCC DDD</format> EEE" document: + createSwDoc("fmt.docx"); + SwDocShell* pDocShell = getSwDocShell(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + pWrtShell->SttEndDoc(/*bStt=*/true); + // Skip "AAA BBB ". + pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 8, /*bBasicCall=*/false); + // Select "CCC". + pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 3, /*bBasicCall=*/false); + + // When deleting CCC: + pWrtShell->DelLeft(); + + // Then make sure the resulting new "delete" redline still tracks formatting: + SwDoc* pDoc = pDocShell->GetDoc(); + IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess(); + SwRedlineTable& rRedlines = rIDRA.GetRedlineTable(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rRedlines.size()); + { + const SwRedlineData& rRedlineData = rRedlines[0]->GetRedlineData(0); + CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlineData.GetType()); + CPPUNIT_ASSERT(!rRedlineData.Next()); + } + { + const SwRedlineData& rRedlineData = rRedlines[1]->GetRedlineData(0); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2 (Format) + // - Actual : 1 (Delete) + // i.e. the middle redline was just "delete", not "format-on-delete", so formatting remained + // in the document after reject-all. + CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlineData.GetType()); + CPPUNIT_ASSERT(rRedlineData.Next()); + const SwRedlineData& rRedlineData2 = rRedlines[1]->GetRedlineData(1); + CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData2.GetType()); + CPPUNIT_ASSERT(!rRedlineData2.Next()); + } + { + const SwRedlineData& rRedlineData = rRedlines[2]->GetRedlineData(0); + CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlineData.GetType()); + CPPUNIT_ASSERT(!rRedlineData.Next()); + } +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/core/doc/data/fmt.docx b/sw/qa/core/doc/data/fmt.docx new file mode 100644 index 000000000000..29fa091007e2 Binary files /dev/null and b/sw/qa/core/doc/data/fmt.docx differ diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index 5b64c1ed8fc6..e357407143cc 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -2227,6 +2227,12 @@ void DocumentRedlineManager::PreAppendDeleteRedline(AppendRedlineContext& rCtx) { if( *rCtx.pEnd != *rCtx.pRStt ) { + // At this point, rCtx.pRedl is the old format redline and rCtx.pNewRedl is the + // new delete redline. Make sure that when this pNewRedl gets appended, it still + // has the formatting redline data from rCtx.pRedl / pNew, and format is on top + // of delete. + rCtx.pNewRedl->PushData(*rCtx.pRedl); + SwRangeRedline* pNew = new SwRangeRedline( *rCtx.pRedl ); pNew->SetStart( *rCtx.pEnd ); rCtx.pRedl->SetEnd( *rCtx.pStart, rCtx.pREnd );
