sw/qa/core/doc/data/del-then-format.docx      |binary
 sw/qa/core/doc/doc.cxx                        |   25 +++++++++++++++++++++++++
 sw/source/core/doc/DocumentRedlineManager.cxx |   24 +++++++++++++++++++++---
 3 files changed, 46 insertions(+), 3 deletions(-)

New commits:
commit 96faaaf83a1c8b897ce675d175b4d8756d0ea0df
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue May 13 08:41:24 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue May 13 15:28:34 2025 +0200

    tdf#166319 sw interdependent redlines: handle accept of delete under format
    
    The bugdoc has <del>AA<format>BB</format>CC</del> in it, clicking accept
    in the middle of AA results in a leftover BB in the document.
    
    This is because the outer redline type of BB is format, so the other
    type is not accepted together with the delete accept. But this is not
    correct: if the delete is to be accepted, then it's just a small detail
    that there was a format on top of it: all this delete is meant to be
    accepted, like Word does.
    
    Fix the problem similar to how commit
    90077e9b4372e1e3445cc6fb2158a0f2bbb8b1b8 (tdf#166319 sw interdependent
    redlines: handle reject of insert under format, 2025-05-09) handled the
    reject of inserts: if there is a format, then see if it has an
    underlying delete, and if so, still combine the to-be-accepted changes.
    
    Note that rejecting the format + deleting the range means we get
    correctly working undo/redo for this use-case.
    
    Change-Id: I8f05d8f94574d5e89432bf9c2df3a737fa8d6d13
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185251
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/core/doc/data/del-then-format.docx 
b/sw/qa/core/doc/data/del-then-format.docx
new file mode 100644
index 000000000000..f458578f5568
Binary files /dev/null and b/sw/qa/core/doc/data/del-then-format.docx differ
diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx
index dce183e12355..e7af522adeeb 100644
--- a/sw/qa/core/doc/doc.cxx
+++ b/sw/qa/core/doc/doc.cxx
@@ -792,6 +792,31 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testInsThenFormat)
     CPPUNIT_ASSERT(pTextNode->GetText().isEmpty());
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testDelThenFormat)
+{
+    // Given a document with <del>A<format>B</format>C</del> style redlines:
+    // When importing that document:
+    createSwDoc("del-then-format.docx");
+
+    // When accepting the delete:
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->AcceptRedline(0);
+
+    // Then make sure no redlines and no content remain:
+    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: 0
+    // - Actual  : 1
+    // i.e. the delete-then-format redline remained in the document.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rRedlines.size());
+    SwTextNode* pTextNode = 
pWrtShell->GetCursor()->GetPointNode().GetTextNode();
+    // Also make sure the text of the format-on-delete redline is removed.
+    CPPUNIT_ASSERT(pTextNode->GetText().isEmpty());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index b4b016e06983..cd25b95ab5c5 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -1137,6 +1137,14 @@ namespace
 /// delete-on-insert can be combined if accepting an insert.
 bool CanCombineTypesForAcceptReject(SwRedlineData& rInnerData, SwRangeRedline& 
rOuterRedline)
 {
+    if (rInnerData.GetType() == RedlineType::Delete)
+    {
+        // Delete is OK to have 'format' on it, but 'insert' will be next to 
the 'delete'.
+        return rOuterRedline.GetType() == RedlineType::Format
+            && rOuterRedline.GetStackCount() > 1
+            && rOuterRedline.GetType(1) == RedlineType::Delete;
+    }
+
     if (rInnerData.GetType() != RedlineType::Insert)
     {
         return false;
@@ -3286,8 +3294,7 @@ bool 
DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr
         else if (CanCombineTypesForAcceptReject(aOrigData, *pTmp)
                  && 
pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData))
         {
-            // The Insert redline we want to accept has another type of 
redline too
-            // we should leave the other type of redline, and only accept the 
inner insert.
+            // The Insert/Delete redline we want to accept has another type of 
redline too
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
                 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
@@ -3295,7 +3302,18 @@ bool 
DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr
             }
             nPamEndtNI = pTmp->Start()->GetNodeIndex();
             nPamEndCI = pTmp->Start()->GetContentIndex();
-            bRet |= lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 1);
+            if (aOrigData.GetType() == RedlineType::Delete)
+            {
+                // We should delete the other type of redline when accepting 
the inner delete.
+                SwPaM aPam(*pTmp->Start(), *pTmp->End());
+                bRet |= lcl_RejectRedline(maRedlineTable, nRdlIdx, 
bCallDelete);
+                m_rDoc.getIDocumentContentOperations().DeleteRange(aPam);
+            }
+            else
+            {
+                // we should leave the other type of redline, and only accept 
the inner insert.
+                bRet |= lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 
1);
+            }
             nRdlIdx++; //we will decrease it in the loop anyway.
         }
     } while (nRdlIdx > 0);

Reply via email to