sw/qa/core/doc/doc.cxx                        |   17 ++++++++++++++
 sw/source/core/doc/DocumentRedlineManager.cxx |   30 ++++++++++++++++++--------
 2 files changed, 38 insertions(+), 9 deletions(-)

New commits:
commit d659f4b12a24e275e38ec5aa7406c32c9fa08c48
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri May 16 09:41:01 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri May 16 14:03:33 2025 +0200

    tdf#166319 sw interdependent redlines: handle reject of delete under format
    
    The bugdoc has <del>AA<format>BB</format>CC</del> in it, and once the
    cursor is in the middle of the AA, then pressing Reject should get rid
    of the delete and keep the format, but it resulted in no redlines and a
    "AACC" string.
    
    What happened is that we found the delete under format, but the action
    was still reject, and it's OK to implement reject by deleting the
    content for insert-then-format, but this won't work for
    delete-then-format.
    
    Fix the problem by reusing lcl_AcceptInnerInsertRedline() for this
    purpose: accepting an underlying insert is effectively a NOP (body text
    doesn't change), and rejecting a delete is in the same category.
    
    Rename to lcl_DeleteInnerRedline(), because what this function does is
    to get rid of "underlying" (earlier) redlines of a redline, so this is
    useful for rejecting deletes as well, not just for accepting inserts.
    
    Change-Id: Ie2db419844b77638d12fa6edfcbc0d5c3b59ad20
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185404
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx
index e7af522adeeb..62ddfb9bab26 100644
--- a/sw/qa/core/doc/doc.cxx
+++ b/sw/qa/core/doc/doc.cxx
@@ -815,6 +815,23 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testDelThenFormat)
     SwTextNode* pTextNode = 
pWrtShell->GetCursor()->GetPointNode().GetTextNode();
     // Also make sure the text of the format-on-delete redline is removed.
     CPPUNIT_ASSERT(pTextNode->GetText().isEmpty());
+
+    // And when rejecting the delete:
+    pWrtShell->Undo();
+    CPPUNIT_ASSERT_EQUAL(u"AAABBBCCC"_ustr, pTextNode->GetText());
+    pWrtShell->RejectRedline(0);
+
+    // Then make sure the delete goes away, but the text node string and the 
format redline stays:
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 0
+    // i.e. the format redline on top of the delete was lost.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
+    CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlines[0]->GetType());
+    const SwRedlineData& rRedlineData = rRedlines[0]->GetRedlineData();
+    CPPUNIT_ASSERT(!rRedlineData.Next());
+    // This was AAACCC.
+    CPPUNIT_ASSERT_EQUAL(u"AAABBBCCC"_ustr, pTextNode->GetText());
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index cd25b95ab5c5..b50d07a5b263 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -997,7 +997,9 @@ namespace
         return bRet;
     }
 
-    bool lcl_AcceptInnerInsertRedline(const SwRedlineTable& rArr, const 
SwRedlineTable::size_type& rPos,
+    /// Given a redline that has an other underlying redline, drop that 
underlying redline.
+    /// Used to accept an insert or rejecting a delete, i.e. no changes to the 
text node strings.
+    bool lcl_DeleteInnerRedline(const SwRedlineTable& rArr, const 
SwRedlineTable::size_type& rPos,
                                       int nDepth)
     {
         SwRangeRedline* pRedl = rArr[rPos];
@@ -3312,7 +3314,7 @@ bool 
DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr
             else
             {
                 // we should leave the other type of redline, and only accept 
the inner insert.
-                bRet |= lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 
1);
+                bRet |= lcl_DeleteInnerRedline(maRedlineTable, nRdlIdx, 1);
             }
             nRdlIdx++; //we will decrease it in the loop anyway.
         }
@@ -3342,7 +3344,7 @@ bool 
DocumentRedlineManager::AcceptMovedRedlines(sal_uInt32 nMovedID, bool bCall
             if (pTmp->GetMoved(0) == nMovedID)
                 bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, 
bCallDelete);
             else
-                bRet |= lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 
1);
+                bRet |= lcl_DeleteInnerRedline(maRedlineTable, nRdlIdx, 1);
 
             nRdlIdx++; //we will decrease it in the loop anyway.
         }
@@ -3482,7 +3484,7 @@ bool DocumentRedlineManager::AcceptRedline( const SwPaM& 
rPam, bool bCallDelete,
         // For now it is called only if it is an Insert redline in a delete 
redline.
         SwRedlineTable::size_type nRdlIdx = 0;
         maRedlineTable.FindAtPosition(*rPam.Start(), nRdlIdx);
-        if (lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 1))
+        if (lcl_DeleteInnerRedline(maRedlineTable, nRdlIdx, 1))
             nRet = 1;
     }
     if( nRet > 0 )
@@ -3582,9 +3584,7 @@ bool 
DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr
         else if (CanCombineTypesForAcceptReject(aOrigData, *pTmp)
                  && 
pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData))
         {
-            // The Insert redline we want to reject has another type of 
redline too
-            // without the insert, the other type is meaningless
-            // so we rather just accept the other type of redline
+            // The Insert/Delete redline we want to reject has another type of 
redline too
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
                 std::unique_ptr<SwUndoAcceptRedline> pUndoRdl
@@ -3597,13 +3597,25 @@ bool 
DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr
             nPamEndtNI = pTmp->Start()->GetNodeIndex();
             nPamEndCI = pTmp->Start()->GetContentIndex();
             std::optional<SwPaM> oPam;
+            RedlineType eInnerType = aOrigData.GetType();
             RedlineType eOuterType = pTmp->GetType();
-            if (eOuterType == RedlineType::Format)
+            if (eInnerType == RedlineType::Insert && eOuterType == 
RedlineType::Format)
             {
                 // The accept won't implicitly delete the range, so track its 
boundaries.
                 oPam.emplace(*pTmp->Start(), *pTmp->End());
             }
-            bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete);
+
+            if (eInnerType == RedlineType::Delete && eOuterType == 
RedlineType::Format)
+            {
+                // Keep the outer redline, just get rid of the underlying 
delete.
+                bRet |= lcl_DeleteInnerRedline(maRedlineTable, nRdlIdx, 1);
+            }
+            else
+            {
+                // without the insert, the other type is meaningless
+                // so we rather just accept the other type of redline
+                bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, 
bCallDelete);
+            }
             if (oPam)
             {
                 // Handles undo/redo itself.

Reply via email to