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

New commits:
commit f468d61755fad1e38e481f8f439bbce9161a3aa7
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri May 16 09:41:01 2025 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Fri May 16 12:28:14 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/+/185384
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx
index e6288d2e20de..3aaad36d2b7d 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 7dc0f5a13507..5318a6a67ff0 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -998,7 +998,9 @@ namespace
         return bRet;
     }
 
-    bool lcl_AcceptInnerInsertRedline(SwRedlineTable& rArr, 
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(SwRedlineTable& rArr, 
SwRedlineTable::size_type& rPos,
                                       int nDepth)
     {
         SwRangeRedline* pRedl = rArr[rPos];
@@ -3313,7 +3315,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.
         }
@@ -3343,7 +3345,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.
         }
@@ -3483,7 +3485,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 )
@@ -3583,9 +3585,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 an other 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 an other type 
of redline too
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
                 std::unique_ptr<SwUndoAcceptRedline> pUndoRdl
@@ -3598,13 +3598,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