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 36073dea918401e5f9cd2dd643727165bf827ca1
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue May 13 08:41:24 2025 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Tue May 13 09:25:01 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/+/185244
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@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 8870f80fbba3..e6288d2e20de 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 3ec093c5b06f..7dc0f5a13507 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -1138,6 +1138,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;
@@ -3287,8 +3295,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 an other 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 an other type 
of redline too
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
                 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
@@ -3296,7 +3303,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