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

New commits:
commit f5b92d0d027c8f69b0c571e306e31578f858d4bf
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Wed Jun 18 09:35:21 2025 +0200
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Thu Jun 19 06:23:55 2025 +0200

    tdf#166319 sw interdependent redlines: fix redo of reject of del-then-fmt's 
del
    
    The bugdoc has <del>AA<format>BB</format>CC</del>, rejecting AA just
    leaves the BB format redline, undo works, but redo results in no
    redlines, while we again want a single format redline.
    
    The first problem was that the del-then-fmt redline's undo action was an
    SwUndoAcceptRedline, while the UI action was a reject. This was not a
    problem on undo, since both accept and reject has the undo code to
    restore a previous state, but redo will have to perform different
    actions (re-accept or re-reject).
    
    The second problem was that sw::DocumentRedlineManager::RejectRedline()
    assumed that rejecting an underlying redline (depth = 1, instead of the
    usual depth = 0) could be always implemented by accepting the redline,
    since that works for the insert/delete combination. Improve this, so in
    case we get a format-on-delete, then we again properly reject just the
    underlying redline, as the original UI action did.
    
    Change-Id: I846abcfa34a7d55709bc9af6e566a3e83d79d833
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186646
    Reviewed-by: Mike Kaganski <mike.kagan...@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 a3826cde2791..fc0772e08d1d 100644
--- a/sw/qa/core/doc/doc.cxx
+++ b/sw/qa/core/doc/doc.cxx
@@ -970,6 +970,25 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testDelThenFormat)
     // - Actual  : 3
     // i.e. the surrounding delete redlines were not combined on reject.
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
+
+    // Reset to the state after file load:
+    pWrtShell->Undo();
+    // And when we do a reject for the first "delete" part, undo, redo:
+    pWrtShell->RejectRedline(0);
+    pWrtShell->Undo();
+    pWrtShell->Redo();
+
+    // Then make sure get a single format redline, matching the state right 
after reject:
+    {
+        // Without the accompanying fix in place, this test would have failed 
with:
+        // - Expected: 1
+        // - Actual  : 0
+        // i.e. the format redline was lost on redo.
+        CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
+        const SwRedlineData& rRedlineData1 = rRedlines[0]->GetRedlineData(0);
+        CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlineData1.GetType());
+        CPPUNIT_ASSERT(!rRedlineData1.Next());
+    }
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index b86e0691d8bf..3ae851126f8b 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -3706,11 +3706,21 @@ bool 
DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr
         else if (CanCombineTypesForAcceptReject(aOrigData, *pTmp)
                  && 
pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData))
         {
-            // The Insert/Delete redline we want to reject has an other type 
of redline too
+            RedlineType eInnerType = aOrigData.GetType();
+            RedlineType eOuterType = pTmp->GetType();
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
-                std::unique_ptr<SwUndoAcceptRedline> pUndoRdl
-                    = std::make_unique<SwUndoAcceptRedline>(*pTmp);
+                std::unique_ptr<SwUndoRedline> pUndoRdl;
+                if (eInnerType == RedlineType::Delete && eOuterType == 
RedlineType::Format)
+                {
+                    // Format on insert: record rejection of the underlying 
insert.
+                    pUndoRdl = std::make_unique<SwUndoRejectRedline>(*pTmp, 
/*nDepth=*/1, /*bHierarchical=*/true);
+                }
+                else
+                {
+                    // The Insert/Delete redline we want to reject has an 
other type of redline too
+                    pUndoRdl = std::make_unique<SwUndoAcceptRedline>(*pTmp);
+                }
 #if OSL_DEBUG_LEVEL > 0
                 pUndoRdl->SetRedlineCountDontCheck(true);
 #endif
@@ -3719,8 +3729,6 @@ bool 
DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr
             nPamEndNI = pTmp->Start()->GetNodeIndex();
             nPamEndCI = pTmp->Start()->GetContentIndex();
             std::optional<SwPaM> oPam;
-            RedlineType eInnerType = aOrigData.GetType();
-            RedlineType eOuterType = pTmp->GetType();
             if (eInnerType == RedlineType::Insert && eOuterType == 
RedlineType::Format)
             {
                 // The accept won't implicitly delete the range, so track its 
boundaries.
@@ -3922,11 +3930,23 @@ bool DocumentRedlineManager::RejectRedline( const 
SwPaM& rPam, bool bCallDelete,
     }
     else
     {
-        // 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_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete))
-            nRet = 1;
+        const SwRangeRedline* pRedline = 
maRedlineTable.FindAtPosition(*rPam.Start(), nRdlIdx);
+        if (nDepth == 1 && pRedline && pRedline->GetType(0) == 
RedlineType::Format
+            && pRedline->GetType(1) == RedlineType::Delete)
+        {
+            // Reject a format-on-delete by getting rid of the underlying 
delete.
+            if (lcl_DeleteInnerRedline(maRedlineTable, nRdlIdx, nDepth))
+            {
+                nRet = 1;
+            }
+        }
+        else
+        {
+            // For now it is called only if it is an Insert redline in a 
delete redline.
+            if (lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete))
+                nRet = 1;
+        }
     }
 
     if( nRet > 0 )

Reply via email to