sw/qa/core/doc/DocumentRedlineManager.cxx     |   39 ++++++++++++++++++++++++++
 sw/qa/core/doc/data/del-then-format-own.docx  |binary
 sw/source/core/doc/DocumentRedlineManager.cxx |    9 ++++++
 3 files changed, 48 insertions(+)

New commits:
commit de12d41f140aee260fa751cd75b19ce3dc895dbf
Author:     Miklos Vajna <[email protected]>
AuthorDate: Mon Dec 22 09:35:27 2025 +0100
Commit:     Mike Kaganski <[email protected]>
CommitDate: Mon Dec 22 13:21:24 2025 +0100

    tdf#168751 sw interdependent redlines, format on delete: fix unwanted 
combine
    
    The DOCX bugdoc has a format redline (mark as bold) + a delete redline,
    and these two overlap. Open the document in Writer, reject the delete
    redline, the boldness remains in the document, which is unexpected.
    
    The problem is an in case a format redline is created and that would be
    on top of an insert or delete from the same author, then we currently
    merge this into the insert/delete redline. The reason for this seems to
    be that search&replace inserts text to the document and then copies
    direct format from the insert position to the inserted text range, and
    this format should not show up on the UI, since the UI action was just
    to replace text. Another variant of this is autocorrect "make first
    character of the paragraph uppercase" in action, which is internally
    again a replace.
    
    Fix the problem by disabling combine of redlines in
    sw::DocumentRedlineManager::PreAppendFormatRedline(), in case we would
    do a combine and this is a format on delete. This way the format is
    rejected by the UI reject action and the unwanted format on insert still
    doesn't show up. The behavior was like this already in case the authors
    of the format and the delete redlines were different.
    
    Note that this tweak is not even important for the insert-then-format
    case: accept doesn't modify the body text and reject would remove text
    from the body text, so we get rid of the unwanted format anyway.
    
    Change-Id: Ib08b0c62c012f14801deae47a4b85d77e32fc1a8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196066
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/sw/qa/core/doc/DocumentRedlineManager.cxx 
b/sw/qa/core/doc/DocumentRedlineManager.cxx
index cba1b81727f1..6bc0e2fef3bd 100644
--- a/sw/qa/core/doc/DocumentRedlineManager.cxx
+++ b/sw/qa/core/doc/DocumentRedlineManager.cxx
@@ -353,6 +353,45 @@ CPPUNIT_TEST_FIXTURE(Test, testInsThenFormatDirect)
     // i.e. we got <ins>AAA</ins>BBB<ins>CCC</ins> instead of one big insert.
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testDelThenFormatOwn)
+{
+    // Given a document with an overlapping delete and format redline:
+    // When importing that document:
+    createSwDoc("del-then-format-own.docx");
+
+    // Then make sure that the overlap part is not lost, instead it's 
represented with an
+    // SwRangeRedline with 2 SwRedlineData members:
+    SwDocShell* pDocShell = getSwDocShell();
+    SwDoc* pDoc = pDocShell->GetDoc();
+    IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess();
+    SwRedlineTable& rRedlines = rIDRA.GetRedlineTable();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 3
+    // - Actual  : 2
+    // i.e. the document had a format and a delete redline, but part of the 
format was lost.
+    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());
+    }
+    {
+        // Overlap: both format and delete is tracked, so reject removes all 
boldness from the
+        // document.
+        const SwRedlineData& rRedlineData = rRedlines[1]->GetRedlineData(0);
+        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::Delete, rRedlineData.GetType());
+        CPPUNIT_ASSERT(!rRedlineData.Next());
+    }
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/doc/data/del-then-format-own.docx 
b/sw/qa/core/doc/data/del-then-format-own.docx
new file mode 100644
index 000000000000..6263df4e0f6f
Binary files /dev/null and b/sw/qa/core/doc/data/del-then-format-own.docx differ
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index b33ab235f486..5b64c1ed8fc6 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -2261,6 +2261,15 @@ void 
DocumentRedlineManager::PreAppendFormatRedline(AppendRedlineContext& rCtx)
         bool bCombineRedlines = !(eOld & RedlineFlags::DontCombineRedlines)
                                 && rCtx.pRedl->IsOwnRedline(*rCtx.pNewRedl)
                                 && 
!rCtx.pRedl->GetRedlineData(0).IsAnonymized();
+
+        if (bCombineRedlines && rCtx.pRedl->GetType() == RedlineType::Delete
+            && rCtx.pNewRedl->GetType() == RedlineType::Format)
+        {
+            // Don't fold format on top of delete into the delete, that would 
give an incorrect
+            // result when rejecting this redline, the format would remain in 
the doc model.
+            bCombineRedlines = false;
+        }
+
         if (bCombineRedlines || rCtx.pRedl->IsMoved())
         {
             switch( rCtx.eCmpPos )

Reply via email to