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/+/196918
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Miklos Vajna
2026-01-10 10:34:04 +01:00
parent 4a4253ac07
commit dcccb89dd3
3 changed files with 51 additions and 0 deletions
+45
View File
@@ -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: */
Binary file not shown.
@@ -2226,6 +2226,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 );