sw/inc/IDocumentRedlineAccess.hxx             |    3 +-
 sw/qa/core/doc/DocumentRedlineManager.cxx     |   27 ++++++++++++++++++++++++++
 sw/source/core/doc/DocumentRedlineManager.cxx |   25 ++++++++++++++++++------
 sw/source/core/inc/DocumentRedlineManager.hxx |    3 +-
 sw/source/core/inc/UndoRedline.hxx            |    2 -
 sw/source/core/undo/unredln.cxx               |    6 ++---
 6 files changed, 54 insertions(+), 12 deletions(-)

New commits:
commit d4b80d48e4bba78b100a80d642573d84c6221694
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Oct 7 08:27:32 2025 +0200
Commit:     Caolán McNamara <[email protected]>
CommitDate: Tue Oct 7 09:51:45 2025 +0200

    tdf#166319 sw interdependent redlines: fix redo of direct reject for format
    
    Open the bugdoc, select the format part of the insert-then-format
    redline in the manage changes dialog, reject, undo, redo: the result is
    <ins>AAA</ins>BBB<ins>CCC</ins> instead of one big insert redline.
    Similarly, open the other bugdoc with a delete and a format redline in
    it, select the format part of the delete-then-format redline in the
    manage changes dialog, reject, undo, redo: the result is
    <del>AAA</del><format>BBB</format><del>CCC</del> instead of one big
    delete redline.
    
    What happens is that the UI action uses
    sw::DocumentRedlineManager::RejectRedlineRange(), while the redo uses
    sw::DocumentRedlineManager::RejectRedline(), and while the first
    supported direct accepts, the later did not.
    
    Fix the problem by:
    1) In sw::DocumentRedlineManager::RejectRedlineRange(), create the undo
       action with the correct depth & directness for direct rejects
    2) In DocumentRedlineManager::RejectRedline(), use use
       lcl_RejectOuterFormat() to directly reject a format redline instead
       of the usual lcl_AcceptRejectRedl(), which gives us matching behavior
       for the UI action & the redo.
    
    Writer's interdependent redlines are now in a reasonable state with
    this: actions for the redline under cursor work with ins/del when
    possible (looking "through" format); while the manage changes dialog
    still allows working on the format redline directly if that's wanted.
    
    Change-Id: Idb90dfbd86ac26ff51da8a34731ea75a48748bdf
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192000
    Tested-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sw/inc/IDocumentRedlineAccess.hxx 
b/sw/inc/IDocumentRedlineAccess.hxx
index dd37a92c9fc7..da6906b06bec 100644
--- a/sw/inc/IDocumentRedlineAccess.hxx
+++ b/sw/inc/IDocumentRedlineAccess.hxx
@@ -217,7 +217,8 @@ public:
         = 0;
 
     virtual bool RejectRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool 
bCallDelete,
-                               /*[in]*/ sal_Int8 nDepth = 0)
+                               /*[in]*/ sal_Int8 nDepth = 0,
+                               bool bDirect = false)
         = 0;
 
     virtual const SwRangeRedline* SelNextRedline(/*[in]*/SwPaM& rPam) const = 
0;
diff --git a/sw/qa/core/doc/DocumentRedlineManager.cxx 
b/sw/qa/core/doc/DocumentRedlineManager.cxx
index 260287e72fa9..cba1b81727f1 100644
--- a/sw/qa/core/doc/DocumentRedlineManager.cxx
+++ b/sw/qa/core/doc/DocumentRedlineManager.cxx
@@ -248,6 +248,20 @@ CPPUNIT_TEST_FIXTURE(Test, testDelThenFormatDirect)
         const SvxWeightItem& rWeightItem = aSet.Get(RES_CHRATR_WEIGHT);
         CPPUNIT_ASSERT_EQUAL(WEIGHT_NORMAL, rWeightItem.GetValue());
     }
+
+    // And given an undo:
+    pWrtShell->Undo();
+
+    // When redoing:
+    pWrtShell->Redo();
+
+    // Then make sure that we only get a single big delete redline:
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 3
+    // i.e. we got <del>AAA</del><format>BBB</format><del>CCC</del> instead of 
one big delete
+    // redline.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testInsThenFormatDirect)
@@ -325,6 +339,19 @@ CPPUNIT_TEST_FIXTURE(Test, testInsThenFormatDirect)
         const SvxWeightItem& rWeightItem = aSet.Get(RES_CHRATR_WEIGHT);
         CPPUNIT_ASSERT_EQUAL(WEIGHT_NORMAL, rWeightItem.GetValue());
     }
+
+    // And given an undo:
+    pWrtShell->Undo();
+
+    // When redoing:
+    pWrtShell->Redo();
+
+    // Then make sure that we only get a single big insert redline:
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 2
+    // i.e. we got <ins>AAA</ins>BBB<ins>CCC</ins> instead of one big insert.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
 }
 }
 
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index 64c3a712debc..b33ab235f486 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -3740,13 +3740,13 @@ bool 
DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
                 sal_Int8 nDepth = 0;
-                if (bHierarchicalFormat && pTmp->GetType(1) == 
RedlineType::Delete)
+                if (bHierarchicalFormat && pTmp->GetType(1) == 
RedlineType::Delete && !bDirect)
                 {
                     // Only work with the underlying delete, so the undo 
action matches the UI
                     // action below.
                     nDepth = 1;
                 }
-                auto pUndoRdl = std::make_unique<SwUndoRejectRedline>(*pTmp, 
nDepth, bHierarchical);
+                auto pUndoRdl = std::make_unique<SwUndoRejectRedline>(*pTmp, 
nDepth, bHierarchical, bDirect);
 #if OSL_DEBUG_LEVEL > 0
                 pUndoRdl->SetRedlineCountDontCheck(true);
 #endif
@@ -3983,7 +3983,7 @@ bool 
DocumentRedlineManager::RejectRedline(SwRedlineTable::size_type nPos,
     // #TODO - add 'SwExtraRedlineTable' also ?
 }
 
-bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool 
bCallDelete, sal_Int8 nDepth )
+bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool 
bCallDelete, sal_Int8 nDepth, bool bDirect )
 {
     // Switch to visible in any case
     if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
@@ -4003,14 +4003,27 @@ bool DocumentRedlineManager::RejectRedline( const 
SwPaM& rPam, bool bCallDelete,
     }
 
     int nRet = 0;
+    SwRedlineTable::size_type nRdlIdx = 0;
+    const SwRangeRedline* pRedline = 
maRedlineTable.FindAtPosition(*rPam.Start(), nRdlIdx);
     if (nDepth == 0)
     {
-        nRet = lcl_AcceptRejectRedl(lcl_RejectRedline, maRedlineTable, 
bCallDelete, aPam);
+        bool bHierarchicalFormat = pRedline && pRedline->GetType() == 
RedlineType::Format && pRedline->GetStackCount() > 1;
+        if (bHierarchicalFormat && bDirect && (pRedline->GetType(1) == 
RedlineType::Insert || pRedline->GetType(1) == RedlineType::Delete))
+        {
+            // Direct reject: work with the format redline on top.
+            if (lcl_RejectOuterFormat(maRedlineTable, nRdlIdx))
+            {
+                nRet = 1;
+            }
+        }
+        else
+        {
+            // Non-direct reject: work with all redlines under aPam.
+            nRet = lcl_AcceptRejectRedl(lcl_RejectRedline, maRedlineTable, 
bCallDelete, aPam);
+        }
     }
     else
     {
-        SwRedlineTable::size_type nRdlIdx = 0;
-        const SwRangeRedline* pRedline = 
maRedlineTable.FindAtPosition(*rPam.Start(), nRdlIdx);
         if (nDepth == 1 && pRedline && pRedline->GetType(0) == 
RedlineType::Format
             && pRedline->GetType(1) == RedlineType::Delete)
         {
diff --git a/sw/source/core/inc/DocumentRedlineManager.hxx 
b/sw/source/core/inc/DocumentRedlineManager.hxx
index 47a1d2443a5a..020b38e3e053 100644
--- a/sw/source/core/inc/DocumentRedlineManager.hxx
+++ b/sw/source/core/inc/DocumentRedlineManager.hxx
@@ -118,7 +118,8 @@ public:
                                bool bDirect = false) override;
 
     virtual bool RejectRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool 
bCallDelete,
-                               /*[in]*/ sal_Int8 nDepth = 0) override;
+                               /*[in]*/ sal_Int8 nDepth = 0,
+                               bool bDirect = false) override;
 
     virtual void AcceptAllRedline(/*[in]*/bool bAcceptReject) override;
 
diff --git a/sw/source/core/inc/UndoRedline.hxx 
b/sw/source/core/inc/UndoRedline.hxx
index ead00d21e043..6476b3e0b41d 100644
--- a/sw/source/core/inc/UndoRedline.hxx
+++ b/sw/source/core/inc/UndoRedline.hxx
@@ -129,7 +129,7 @@ private:
     virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
 
 public:
-    SwUndoRejectRedline( const SwPaM& rRange, sal_Int8 nDepth = 0, bool 
bHierarchical = false );
+    SwUndoRejectRedline( const SwPaM& rRange, sal_Int8 nDepth = 0, bool 
bHierarchical = false, bool bDirect = false );
 
     virtual void RepeatImpl( ::sw::RepeatContext & ) override;
 };
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index 6cacd98ee28b..9d3de5e67c1a 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -482,14 +482,14 @@ void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext 
& rContext)
     
rContext.GetDoc().getIDocumentRedlineAccess().AcceptRedline(rContext.GetRepeatPaM(),
 true);
 }
 
-SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange, sal_Int8 nDepth 
/* = 0 */, bool bHierarchical /*= false*/ )
-    : SwUndoRedline( SwUndoId::REJECT_REDLINE, rRange, nDepth, bHierarchical )
+SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange, sal_Int8 nDepth 
/* = 0 */, bool bHierarchical /*= false*/, bool bDirect /*= false*/ )
+    : SwUndoRedline( SwUndoId::REJECT_REDLINE, rRange, nDepth, bHierarchical, 
bDirect )
 {
 }
 
 void SwUndoRejectRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
 {
-    rDoc.getIDocumentRedlineAccess().RejectRedline(rPam, false, mnDepth);
+    rDoc.getIDocumentRedlineAccess().RejectRedline(rPam, false, mnDepth, 
mbDirect);
 }
 
 void SwUndoRejectRedline::RepeatImpl(::sw::RepeatContext & rContext)

Reply via email to