sw/inc/IDocumentRedlineAccess.hxx                                  |   16 
 sw/inc/redline.hxx                                                 |    2 
 sw/qa/extras/uiwriter/data/tdf157662_redlineNestedInsertDelete.odt |binary
 sw/qa/extras/uiwriter/uiwriter5.cxx                                |   62 ++
 sw/source/core/doc/DocumentRedlineManager.cxx                      |  274 
+++++++++-
 sw/source/core/doc/docredln.cxx                                    |   35 +
 sw/source/core/edit/edredln.cxx                                    |    4 
 sw/source/core/inc/DocumentRedlineManager.hxx                      |   19 
 sw/source/core/inc/UndoCore.hxx                                    |    4 
 sw/source/core/inc/UndoRedline.hxx                                 |   10 
 sw/source/core/undo/undobj.cxx                                     |    4 
 sw/source/core/undo/unredln.cxx                                    |   25 
 12 files changed, 419 insertions(+), 36 deletions(-)

New commits:
commit 52fa7aed48632166e064e6a227e034f0981c4205
Author:     Attila Szűcs <attila.sz...@collabora.com>
AuthorDate: Mon Aug 28 07:40:20 2023 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Sat Oct 14 11:55:27 2023 +0200

    tdf#157662 SW: redline: accept/reject done for all parts
    
    Tracked changes divided into smaller parts when they are
    overlapping. But if the Author, and Change time, and some more
    is equal, then they can be combined into 1 change later..
    
    Modified AcceptRedline / RejectRedline, to seek for all these parts
    that are neightbour to each other, and can be combined, and
    reject/accept them all at once. Even those that are deepen in the tree.
    i.e.: insert that have a delete redline too.
    
    when rejecting an insert redline, that have a delete redline too,
    the delete redline is accepted instead. (have the same result.)
    
    when accepting an insert redline, that have a delete redline too,
    The delete redline remains, while the insert is deleted. (=accepted)
    
    made some limitations to lessen the probability of regression:
    No anonym, No table, No seqNo, and dont use it in RejectAll/AcceptAll
    
    Added unittest to check that accept/reject handle more redlines
    at once, but not too many..
    
    Change-Id: Ibd0a39f7847b22b279a797babb30ba162e70a513
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157950
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/sw/inc/IDocumentRedlineAccess.hxx 
b/sw/inc/IDocumentRedlineAccess.hxx
index 73f87fa8c799..c2b71aa1005a 100644
--- a/sw/inc/IDocumentRedlineAccess.hxx
+++ b/sw/inc/IDocumentRedlineAccess.hxx
@@ -183,15 +183,23 @@ public:
 
     virtual void SetRedlineMove(/*[in]*/bool bFlag) = 0;
 
-    virtual bool AcceptRedline(/*[in]*/SwRedlineTable::size_type nPos, 
/*[in]*/bool bCallDelete) = 0;
+    virtual bool AcceptRedline(/*[in]*/ SwRedlineTable::size_type nPos, 
/*[in]*/ bool bCallDelete,
+                               /*[in]*/ bool bRange = false)
+        = 0;
 
-    virtual bool AcceptRedline(/*[in]*/const SwPaM& rPam, /*[in]*/bool 
bCallDelete) = 0;
+    virtual bool AcceptRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool 
bCallDelete,
+                               /*[in]*/ sal_Int8 nDepth = 0)
+        = 0;
 
     virtual void AcceptRedlineParagraphFormatting(/*[in]*/const SwPaM& rPam ) 
= 0;
 
-    virtual bool RejectRedline(/*[in]*/SwRedlineTable::size_type nPos, 
/*[in]*/bool bCallDelete) = 0;
+    virtual bool RejectRedline(/*[in]*/ SwRedlineTable::size_type nPos,
+                               /*[in]*/ bool bCallDelete, /*[in]*/ bool bRange 
= false)
+        = 0;
 
-    virtual bool RejectRedline(/*[in]*/const SwPaM& rPam, /*[in]*/bool 
bCallDelete) = 0;
+    virtual bool RejectRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool 
bCallDelete,
+                               /*[in]*/ sal_Int8 nDepth = 0)
+        = 0;
 
     virtual const SwRangeRedline* SelNextRedline(/*[in]*/SwPaM& rPam) const = 
0;
 
diff --git a/sw/inc/redline.hxx b/sw/inc/redline.hxx
index 7ef6b9cad20f..d8eba6480618 100644
--- a/sw/inc/redline.hxx
+++ b/sw/inc/redline.hxx
@@ -144,6 +144,7 @@ public:
     void SetMoved() { m_bMoved = true; }
     bool IsMoved() const { return m_bMoved; }
     bool CanCombine( const SwRedlineData& rCmp ) const;
+    bool CanCombineForAcceptReject( const SwRedlineData& rCmp ) const;
 
     // ExtraData gets copied, the pointer is therefore not taken over by
     // the RedlineObject
@@ -261,6 +262,7 @@ public:
 
     void PushData( const SwRangeRedline& rRedl, bool bOwnAsNext = true );
     bool PopData();
+    bool PopAllDataAfter(int depth);
 
     /**
        Returns textual description of a redline data element of
diff --git a/sw/qa/extras/uiwriter/data/tdf157662_redlineNestedInsertDelete.odt 
b/sw/qa/extras/uiwriter/data/tdf157662_redlineNestedInsertDelete.odt
new file mode 100644
index 000000000000..d97521559a84
Binary files /dev/null and 
b/sw/qa/extras/uiwriter/data/tdf157662_redlineNestedInsertDelete.odt differ
diff --git a/sw/qa/extras/uiwriter/uiwriter5.cxx 
b/sw/qa/extras/uiwriter/uiwriter5.cxx
index 285a3adb7c61..d97e0a8911f0 100644
--- a/sw/qa/extras/uiwriter/uiwriter5.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter5.cxx
@@ -2231,6 +2231,68 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, 
testRedlineDOCXTableMoveToFrame)
     CPPUNIT_ASSERT(!xTableNames->hasByName("Table2"));
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, 
testTdf157662_AcceptInsertRedlineCutWithDeletion)
+{
+    createSwDoc("tdf157662_redlineNestedInsertDelete.odt");
+    SwDoc* pDoc = getSwDoc();
+
+    // turn on red-lining and show changes
+    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | 
RedlineFlags::ShowDelete
+                                                      | 
RedlineFlags::ShowInsert);
+    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
+                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+    CPPUNIT_ASSERT_MESSAGE(
+        "redlines should be visible",
+        
IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
+
+    SwEditShell* const pEditShell(pDoc->GetEditShell());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(9), 
pEditShell->GetRedlineCount());
+
+    // Accept the insert that splitted into 3 parts .. accept all 3 of them
+    pEditShell->AcceptRedline(6);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(7), 
pEditShell->GetRedlineCount());
+    // The middle had a delete too, rejecting the delete will remove that 
redline too.
+    pEditShell->RejectRedline(6);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(6), 
pEditShell->GetRedlineCount());
+
+    // Accept insert that splitted into 4 parts, but separeted to 2-2 parts, 
with another insert.
+    // It will accept only 2 parts, that is not separated. It leave the 
deletion.
+    pEditShell->AcceptRedline(0);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(5), 
pEditShell->GetRedlineCount());
+    // Accepting the delete will remove that redline.
+    // (only that one, as its other half is separated from it with an insert)
+    pEditShell->AcceptRedline(0);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(4), 
pEditShell->GetRedlineCount());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, 
testTdf157662_RejectInsertRedlineCutWithDeletion)
+{
+    createSwDoc("tdf157662_redlineNestedInsertDelete.odt");
+    SwDoc* pDoc = getSwDoc();
+
+    // turn on red-lining and show changes
+    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | 
RedlineFlags::ShowDelete
+                                                      | 
RedlineFlags::ShowInsert);
+    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
+                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+    CPPUNIT_ASSERT_MESSAGE(
+        "redlines should be visible",
+        
IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
+
+    SwEditShell* const pEditShell(pDoc->GetEditShell());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(9), 
pEditShell->GetRedlineCount());
+
+    // Reject the insert that splitted into 3 parts .. reject all 3 of them
+    // it even remove the deletion, that was on the 2. insert...
+    pEditShell->RejectRedline(6);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(6), 
pEditShell->GetRedlineCount());
+
+    // Reject insert that splitted into 4 parts, but separeted to 2-2 parts, 
with another insert.
+    // It will reject only 2 parts, that is not separated. It remove the 
deletion.
+    pEditShell->RejectRedline(0);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(4), 
pEditShell->GetRedlineCount());
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf143215)
 {
     // load a table with tracked insertion of an empty row
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index 75c5ba1ccc10..f5ab5a9fdba3 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -992,6 +992,18 @@ namespace
         return bRet;
     }
 
+    bool lcl_AcceptInnerInsertRedline(SwRedlineTable& rArr, 
SwRedlineTable::size_type& rPos,
+                                      int nDepth)
+    {
+        SwRangeRedline* pRedl = rArr[rPos];
+        SwDoc& rDoc = pRedl->GetDoc();
+        SwPaM const updatePaM(*pRedl->Start(), *pRedl->End());
+
+        pRedl->PopAllDataAfter(nDepth);
+        sw::UpdateFramesForRemoveDeleteRedline(rDoc, updatePaM);
+        return true;
+    }
+
     typedef bool (*Fn_AcceptReject)( SwRedlineTable& rArr, 
SwRedlineTable::size_type& rPos,
                             bool bCallDelete,
                             const SwPosition* pSttRng,
@@ -2863,7 +2875,118 @@ const SwRangeRedline* 
DocumentRedlineManager::GetRedline( const SwPosition& rPos
     // #TODO - add 'SwExtraRedlineTable' also ?
 }
 
-bool DocumentRedlineManager::AcceptRedline( SwRedlineTable::size_type nPos, 
bool bCallDelete )
+namespace
+{
+bool lcl_CanCombineWithRange(SwRangeRedline* pTmp, SwRangeRedline* pOther, 
SwPosition* pPamAct,
+                             SwPosition* pPamOther, SwPosition* pPamAct2, 
SwPosition* pPamOther2)
+{
+    if (!pOther->IsVisible())
+        return false;
+
+    if (*pPamAct != *pPamOther)
+        return false;
+
+    if 
(!pTmp->GetRedlineData(0).CanCombineForAcceptReject(pOther->GetRedlineData(0)))
+    {
+        if (pOther->GetStackCount() <= 1
+            || 
!pTmp->GetRedlineData(0).CanCombineForAcceptReject(pOther->GetRedlineData(1)))
+            return false;
+    }
+    if (pPamAct2->GetNode().StartOfSectionNode() != 
pPamOther2->GetNode().StartOfSectionNode())
+        return false;
+
+    return true;
+}
+}
+
+void DocumentRedlineManager::FindRangeToAcceptReject(SwRedlineTable::size_type 
nPos,
+                                                     SwPosition** pPamStart, 
SwPosition** pPamEnd,
+                                                     
SwRedlineTable::size_type& nPosEnd) const
+{
+    SwRangeRedline* pTmp = maRedlineTable[nPos];
+    nPosEnd = nPos;
+    SwRedlineTable::size_type nPosStart = nPos;
+    SwRangeRedline* pOther;
+
+    while (nPosStart > 0 && (pOther = maRedlineTable[nPosStart - 1])
+           && lcl_CanCombineWithRange(pTmp, pOther, *pPamStart, pOther->End(), 
pOther->Start(),
+                                      *pPamEnd))
+    {
+        nPosStart--;
+        *pPamStart = pOther->Start();
+    }
+    while (nPosEnd + 1 < maRedlineTable.size() && (pOther = 
maRedlineTable[nPosEnd + 1])
+           && lcl_CanCombineWithRange(pTmp, pOther, *pPamEnd, pOther->Start(), 
pOther->End(),
+                                      *pPamStart))
+    {
+        nPosEnd++;
+        *pPamEnd = pOther->End();
+    }
+}
+
+bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type 
nPos, bool bCallDelete,
+                                                SwPosition* pPamStart, 
SwPosition* pPamEnd,
+                                                SwRedlineTable::size_type& 
nPosEnd)
+{
+    bool bRet = false;
+
+    SwRangeRedline* pTmp = maRedlineTable[nPos];
+    SwRedlineTable::size_type nRdlIdx = nPosEnd + 1;
+    SwRedlineData aOrigData = pTmp->GetRedlineData(0);
+
+    SwNodeOffset nPamStartNI = pPamStart->GetNodeIndex();
+    sal_Int32 nPamStartCI = pPamStart->GetContentIndex();
+    SwNodeOffset nPamEndtNI = pPamEnd->GetNodeIndex();
+    sal_Int32 nPamEndCI = pPamEnd->GetContentIndex();
+    do
+    {
+        nRdlIdx--;
+        pTmp = maRedlineTable[nRdlIdx];
+        if (pTmp->Start()->GetNodeIndex() < nPamStartNI
+            || (pTmp->Start()->GetNodeIndex() == nPamStartNI
+                && pTmp->Start()->GetContentIndex() < nPamStartCI))
+            break;
+
+        if (pTmp->End()->GetNodeIndex() > nPamEndtNI
+            || (pTmp->End()->GetNodeIndex() == nPamEndtNI
+                && pTmp->End()->GetContentIndex() > nPamEndCI))
+        {
+        }
+        else if (pTmp->GetRedlineData(0).CanCombineForAcceptReject(aOrigData))
+        {
+            if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
+            {
+                m_rDoc.GetIDocumentUndoRedo().AppendUndo(
+                    std::make_unique<SwUndoAcceptRedline>(*pTmp));
+            }
+            nPamEndtNI = pTmp->Start()->GetNodeIndex();
+            nPamEndCI = pTmp->Start()->GetContentIndex();
+            bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete);
+            nRdlIdx++; //we will decrease it in the loop anyway.
+        }
+        else if (aOrigData.GetType() == RedlineType::Insert
+                 && pTmp->GetType() == RedlineType::Delete && 
pTmp->GetStackCount() > 1
+                 && pTmp->GetType(1) == RedlineType::Insert
+                 && 
pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData))
+        {
+            // The Insert redline we want to accept has a deletion redline too
+            // we should leave the deletion redline, and only accept the inner 
insert.
+            if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
+            {
+                m_rDoc.GetIDocumentUndoRedo().AppendUndo(
+                    std::make_unique<SwUndoAcceptRedline>(*pTmp, 1));
+            }
+            nPamEndtNI = pTmp->Start()->GetNodeIndex();
+            nPamEndCI = pTmp->Start()->GetContentIndex();
+            bRet |= lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 1);
+            nRdlIdx++; //we will decrease it in the loop anyway.
+        }
+    } while (nRdlIdx > 0);
+    return bRet;
+}
+
+bool DocumentRedlineManager::AcceptRedline(SwRedlineTable::size_type nPos, 
bool bCallDelete,
+                                           bool bRange)
 {
     bool bRet = false;
 
@@ -2873,6 +2996,8 @@ bool DocumentRedlineManager::AcceptRedline( 
SwRedlineTable::size_type nPos, bool
       SetRedlineFlags( RedlineFlags::ShowInsert | RedlineFlags::ShowDelete | 
meRedlineFlags );
 
     SwRangeRedline* pTmp = maRedlineTable[ nPos ];
+    bool bAnonym = pTmp->GetRedlineData(0).IsAnonymized();
+
     pTmp->Show(0, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
     pTmp->Show(1, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
     if( pTmp->HasMark() && pTmp->IsVisible() )
@@ -2888,7 +3013,18 @@ bool DocumentRedlineManager::AcceptRedline( 
SwRedlineTable::size_type nPos, bool
         int nLoopCnt = 2;
         sal_uInt16 nSeqNo = pTmp->GetSeqNo();
 
-        do {
+        if (bRange && !nSeqNo && !bAnonym
+            && !pTmp->Start()->GetNode().StartOfSectionNode()->IsTableNode())
+        {
+            auto [pPamStart, pPamEnd] = pTmp->StartEnd();
+            SwRedlineTable::size_type nPosEnd;
+            FindRangeToAcceptReject(nPos, &pPamStart, &pPamEnd, nPosEnd);
+
+            // Accept redlines between pPamStart-pPamEnd.
+            // but only those that can be combined with the selected.
+            bRet |= AcceptRedlineRange(nPos, bCallDelete, pPamStart, pPamEnd, 
nPosEnd);
+        }
+        else do {
 
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
@@ -2918,7 +3054,7 @@ bool DocumentRedlineManager::AcceptRedline( 
SwRedlineTable::size_type nPos, bool
             else
                 nLoopCnt = 0;
 
-        } while( nLoopCnt );
+        } while (nLoopCnt);
 
         if( bRet )
         {
@@ -2936,7 +3072,7 @@ bool DocumentRedlineManager::AcceptRedline( 
SwRedlineTable::size_type nPos, bool
     // #TODO - add 'SwExtraRedlineTable' also ?
 }
 
-bool DocumentRedlineManager::AcceptRedline( const SwPaM& rPam, bool 
bCallDelete )
+bool DocumentRedlineManager::AcceptRedline( const SwPaM& rPam, bool 
bCallDelete, sal_Int8 nDepth )
 {
     // Switch to visible in any case
     if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
@@ -2957,11 +3093,23 @@ bool DocumentRedlineManager::AcceptRedline( const 
SwPaM& rPam, bool bCallDelete
     if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
     {
         m_rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::ACCEPT_REDLINE, 
nullptr );
-        
m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAcceptRedline>(*pPam));
+        m_rDoc.GetIDocumentUndoRedo().AppendUndo(
+            std::make_unique<SwUndoAcceptRedline>(*pPam, nDepth));
     }
 
-    int nRet = lcl_AcceptRejectRedl( lcl_AcceptRedline, maRedlineTable,
-                                     bCallDelete, *pPam );
+    int nRet = 0;
+    if (nDepth == 0)
+    {
+        nRet = lcl_AcceptRejectRedl(lcl_AcceptRedline, maRedlineTable, 
bCallDelete, *pPam);
+    }
+    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_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 1))
+            nRet = 1;
+    }
     if( nRet > 0 )
     {
         CompressRedlines();
@@ -3011,7 +3159,79 @@ void 
DocumentRedlineManager::AcceptRedlineParagraphFormatting( const SwPaM &rPam
     }
 }
 
-bool DocumentRedlineManager::RejectRedline( SwRedlineTable::size_type nPos, 
bool bCallDelete )
+bool DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type 
nPos, bool bCallDelete,
+                                                SwPosition* pPamStart, 
SwPosition* pPamEnd,
+                                                SwRedlineTable::size_type& 
nPosEnd)
+{
+    bool bRet = false;
+
+    SwRangeRedline* pTmp = maRedlineTable[nPos];
+    SwRedlineTable::size_type nRdlIdx = nPosEnd + 1;
+    SwRedlineData aOrigData = pTmp->GetRedlineData(0);
+
+    SwNodeOffset nPamStartNI = pPamStart->GetNodeIndex();
+    sal_Int32 nPamStartCI = pPamStart->GetContentIndex();
+    SwNodeOffset nPamEndtNI = pPamEnd->GetNodeIndex();
+    sal_Int32 nPamEndCI = pPamEnd->GetContentIndex();
+    do
+    {
+        nRdlIdx--;
+        pTmp = maRedlineTable[nRdlIdx];
+        if (pTmp->Start()->GetNodeIndex() < nPamStartNI
+            || (pTmp->Start()->GetNodeIndex() == nPamStartNI
+                && pTmp->Start()->GetContentIndex() < nPamStartCI))
+            break;
+
+        if (pTmp->End()->GetNodeIndex() > nPamEndtNI
+            || (pTmp->End()->GetNodeIndex() == nPamEndtNI
+                && pTmp->End()->GetContentIndex() > nPamEndCI))
+        {
+        }
+        else if (pTmp->GetRedlineData(0).CanCombineForAcceptReject(aOrigData))
+        {
+            if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
+            {
+                std::unique_ptr<SwUndoRejectRedline> pUndoRdl
+                    = std::make_unique<SwUndoRejectRedline>(*pTmp);
+#if OSL_DEBUG_LEVEL > 0
+                pUndoRdl->SetRedlineCountDontCheck(true);
+#endif
+                m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndoRdl));
+            }
+            nPamEndtNI = pTmp->Start()->GetNodeIndex();
+            nPamEndCI = pTmp->Start()->GetContentIndex();
+            bRet |= lcl_RejectRedline(maRedlineTable, nRdlIdx, bCallDelete);
+            nRdlIdx++; //we will decrease it in the loop anyway.
+        }
+        else if (aOrigData.GetType() == RedlineType::Insert
+                 && pTmp->GetType() == RedlineType::Delete && 
pTmp->GetStackCount() > 1
+                 && pTmp->GetType(1) == RedlineType::Insert
+                 && 
pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData))
+        {
+            // The Insert redline we want to reject has a deletion redline too
+            // without the insert, the delete is meaningless
+            // so we rather just accept the deletion redline
+            if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
+            {
+                std::unique_ptr<SwUndoRejectRedline> pUndoRdl
+                    = std::make_unique<SwUndoRejectRedline>(*pTmp, 1);
+#if OSL_DEBUG_LEVEL > 0
+                pUndoRdl->SetRedlineCountDontCheck(true);
+#endif
+                m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndoRdl));
+            }
+            nPamEndtNI = pTmp->Start()->GetNodeIndex();
+            nPamEndCI = pTmp->Start()->GetContentIndex();
+            bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete);
+            nRdlIdx++; //we will decrease it in the loop anyway.
+        }
+
+    } while (nRdlIdx > 0);
+    return bRet;
+}
+
+bool DocumentRedlineManager::RejectRedline(SwRedlineTable::size_type nPos,
+                                           bool bCallDelete, bool bRange)
 {
     bool bRet = false;
 
@@ -3021,6 +3241,8 @@ bool DocumentRedlineManager::RejectRedline( 
SwRedlineTable::size_type nPos, bool
       SetRedlineFlags( RedlineFlags::ShowInsert | RedlineFlags::ShowDelete | 
meRedlineFlags );
 
     SwRangeRedline* pTmp = maRedlineTable[ nPos ];
+    bool bAnonym = pTmp->GetRedlineData(0).IsAnonymized();
+
     pTmp->Show(0, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
     pTmp->Show(1, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
     if( pTmp->HasMark() && pTmp->IsVisible() )
@@ -3036,7 +3258,19 @@ bool DocumentRedlineManager::RejectRedline( 
SwRedlineTable::size_type nPos, bool
         int nLoopCnt = 2;
         sal_uInt16 nSeqNo = pTmp->GetSeqNo();
 
-        do {
+        if (bRange && !nSeqNo && !bAnonym
+            && !pTmp->Start()->GetNode().StartOfSectionNode()->IsTableNode())
+        {
+            auto [pPamStart, pPamEnd] = pTmp->StartEnd();
+            SwRedlineTable::size_type nPosEnd;
+            FindRangeToAcceptReject(nPos, &pPamStart, &pPamEnd, nPosEnd);
+
+            // Reject items between pPamStart-pPamEnd
+            // but only those that can be combined with the selected.
+
+            bRet |= RejectRedlineRange(nPos, bCallDelete, pPamStart, pPamEnd, 
nPosEnd);
+        }
+        else do {
 
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
@@ -3066,7 +3300,7 @@ bool DocumentRedlineManager::RejectRedline( 
SwRedlineTable::size_type nPos, bool
             else
                 nLoopCnt = 0;
 
-        } while( nLoopCnt );
+        } while (nLoopCnt);
 
         if( bRet )
         {
@@ -3084,7 +3318,7 @@ bool DocumentRedlineManager::RejectRedline( 
SwRedlineTable::size_type nPos, bool
     // #TODO - add 'SwExtraRedlineTable' also ?
 }
 
-bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool 
bCallDelete )
+bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool 
bCallDelete, sal_Int8 nDepth )
 {
     // Switch to visible in any case
     if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
@@ -3100,11 +3334,23 @@ bool DocumentRedlineManager::RejectRedline( const 
SwPaM& rPam, bool bCallDelete
     if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
     {
         m_rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::REJECT_REDLINE, 
nullptr );
-        m_rDoc.GetIDocumentUndoRedo().AppendUndo( 
std::make_unique<SwUndoRejectRedline>(aPam) );
+        m_rDoc.GetIDocumentUndoRedo().AppendUndo( 
std::make_unique<SwUndoRejectRedline>(aPam, nDepth) );
+    }
+
+    int nRet = 0;
+    if (nDepth == 0)
+    {
+        nRet = lcl_AcceptRejectRedl(lcl_RejectRedline, maRedlineTable, 
bCallDelete, aPam);
+    }
+    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;
     }
 
-    int nRet = lcl_AcceptRejectRedl( lcl_RejectRedline, maRedlineTable,
-                                        bCallDelete, aPam );
     if( nRet > 0 )
     {
         CompressRedlines();
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 205e532712eb..50c259faee6b 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -1109,6 +1109,20 @@ bool SwRedlineData::CanCombine(const SwRedlineData& 
rCmp) const
                     *m_pExtraData == *rCmp.m_pExtraData ));
 }
 
+// Check if we could/should accept/reject the 2 redlineData at the same time.
+// No need to check its childs equality
+bool SwRedlineData::CanCombineForAcceptReject(const SwRedlineData& rCmp) const
+{
+    return m_nAuthor == rCmp.m_nAuthor &&
+            m_eType == rCmp.m_eType &&
+            m_sComment == rCmp.m_sComment &&
+            deltaOneMinute(GetTimeStamp(), rCmp.GetTimeStamp()) &&
+            m_bMoved == rCmp.m_bMoved &&
+            (( !m_pExtraData && !rCmp.m_pExtraData ) ||
+                ( m_pExtraData && rCmp.m_pExtraData &&
+                    *m_pExtraData == *rCmp.m_pExtraData ));
+}
+
 /// ExtraData is copied. The Pointer's ownership is thus NOT transferred
 /// to the Redline Object!
 void SwRedlineData::SetExtraData( const SwRedlineExtraData* pData )
@@ -1981,6 +1995,27 @@ bool SwRangeRedline::PopData()
     return true;
 }
 
+bool SwRangeRedline::PopAllDataAfter(int depth)
+{
+    assert(depth > 0);
+    SwRedlineData* pCur = m_pRedlineData;
+    while (depth > 1)
+    {
+        pCur = pCur->m_pNext;
+        if (!pCur)
+            return false;
+        depth--;
+    }
+
+    while (pCur->m_pNext)
+    {
+        SwRedlineData* pToDelete = pCur->m_pNext;
+        pCur->m_pNext = pToDelete->m_pNext;
+        delete pToDelete;
+    }
+    return true;
+}
+
 sal_uInt16 SwRangeRedline::GetStackCount() const
 {
     sal_uInt16 nRet = 1;
diff --git a/sw/source/core/edit/edredln.cxx b/sw/source/core/edit/edredln.cxx
index 835a1c37389c..1778745f57e4 100644
--- a/sw/source/core/edit/edredln.cxx
+++ b/sw/source/core/edit/edredln.cxx
@@ -68,7 +68,7 @@ bool SwEditShell::AcceptRedline( SwRedlineTable::size_type 
nPos )
 {
     CurrShell aCurr( this );
     StartAllAction();
-    bool bRet = GetDoc()->getIDocumentRedlineAccess().AcceptRedline( nPos, 
true );
+    bool bRet = GetDoc()->getIDocumentRedlineAccess().AcceptRedline( nPos, 
true, true );
     if( !nPos && !::IsExtraData( GetDoc() ) )
         lcl_InvalidateAll( this );
     EndAllAction();
@@ -79,7 +79,7 @@ bool SwEditShell::RejectRedline( SwRedlineTable::size_type 
nPos )
 {
     CurrShell aCurr( this );
     StartAllAction();
-    bool bRet = GetDoc()->getIDocumentRedlineAccess().RejectRedline( nPos, 
true );
+    bool bRet = GetDoc()->getIDocumentRedlineAccess().RejectRedline( nPos, 
true, true );
     if( !nPos && !::IsExtraData( GetDoc() ) )
         lcl_InvalidateAll( this );
     EndAllAction();
diff --git a/sw/source/core/inc/DocumentRedlineManager.hxx 
b/sw/source/core/inc/DocumentRedlineManager.hxx
index a3644f4aea9e..2f9c133605fa 100644
--- a/sw/source/core/inc/DocumentRedlineManager.hxx
+++ b/sw/source/core/inc/DocumentRedlineManager.hxx
@@ -89,15 +89,19 @@ public:
 
     virtual void SetRedlineMove(/*[in]*/bool bFlag) override;
 
-    virtual bool AcceptRedline(/*[in]*/SwRedlineTable::size_type nPos, 
/*[in]*/bool bCallDelete) override;
+    virtual bool AcceptRedline(/*[in]*/ SwRedlineTable::size_type nPos, 
/*[in]*/ bool bCallDelete,
+                               /*[in]*/ bool bRange = false) override;
 
-    virtual bool AcceptRedline(/*[in]*/const SwPaM& rPam, /*[in]*/bool 
bCallDelete) override;
+    virtual bool AcceptRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool 
bCallDelete,
+                               /*[in]*/ sal_Int8 nDepth = 0) override;
 
     virtual void AcceptRedlineParagraphFormatting(/*[in]*/const SwPaM& rPam) 
override;
 
-    virtual bool RejectRedline(/*[in]*/SwRedlineTable::size_type nPos, 
/*[in]*/bool bCallDelete) override;
+    virtual bool RejectRedline(/*[in]*/ SwRedlineTable::size_type nPos, 
/*[in]*/ bool bCallDelete,
+                               /*[in]*/ bool bRange = false) override;
 
-    virtual bool RejectRedline(/*[in]*/const SwPaM& rPam, /*[in]*/bool 
bCallDelete) override;
+    virtual bool RejectRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool 
bCallDelete,
+                               /*[in]*/ sal_Int8 nDepth = 0) override;
 
     virtual void AcceptAllRedline(/*[in]*/bool bAcceptReject) override;
 
@@ -137,6 +141,13 @@ public:
 
 private:
 
+    void FindRangeToAcceptReject(SwRedlineTable::size_type nPos, SwPosition** 
pPamStart,
+                                 SwPosition** pPamEnd, 
SwRedlineTable::size_type& nPosEnd) const;
+    bool RejectRedlineRange(SwRedlineTable::size_type nPos, bool bCallDelete, 
SwPosition* pPamStart,
+                            SwPosition* pPamEnd, SwRedlineTable::size_type& 
nPosEnd);
+    bool AcceptRedlineRange(SwRedlineTable::size_type nPos, bool bCallDelete, 
SwPosition* pPamStart,
+                            SwPosition* pPamEnd, SwRedlineTable::size_type& 
nPosEnd);
+
     DocumentRedlineManager(DocumentRedlineManager const&) = delete;
     DocumentRedlineManager& operator=(DocumentRedlineManager const&) = delete;
 
diff --git a/sw/source/core/inc/UndoCore.hxx b/sw/source/core/inc/UndoCore.hxx
index 5c4b709ffb70..94891df09e49 100644
--- a/sw/source/core/inc/UndoCore.hxx
+++ b/sw/source/core/inc/UndoCore.hxx
@@ -61,6 +61,7 @@ public:
 
 #if OSL_DEBUG_LEVEL > 0
     sal_uInt16 m_nRedlineCount;
+    bool m_bRedlineCountDontCheck;
     bool m_bRedlineMoved;
 #endif
 };
@@ -78,6 +79,9 @@ public:
     void push_back(std::unique_ptr<SwRedlineSaveData> pNew) { 
m_Data.push_back(std::move(pNew)); }
     const SwRedlineSaveData& operator[](size_t const nIdx) const { return 
*m_Data[ nIdx ]; }
     SwRedlineSaveData& operator[](size_t const nIdx) { return *m_Data[ nIdx ]; 
}
+#if OSL_DEBUG_LEVEL > 0
+    void SetRedlineCountDontCheck(bool bCheck) { 
m_Data[0]->m_bRedlineCountDontCheck=bCheck; }
+#endif
 };
 
 namespace sw {
diff --git a/sw/source/core/inc/UndoRedline.hxx 
b/sw/source/core/inc/UndoRedline.hxx
index f1cf45800fdb..127aeae0aa29 100644
--- a/sw/source/core/inc/UndoRedline.hxx
+++ b/sw/source/core/inc/UndoRedline.hxx
@@ -36,12 +36,13 @@ protected:
     std::unique_ptr<SwRedlineSaveDatas> mpRedlSaveData;
     SwUndoId mnUserId;
     bool mbHiddenRedlines;
+    sal_Int8 mnDepth;       // index of the SwRedlineData in SwRangeRedline
 
     virtual void UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam);
     virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam);
 
 public:
-    SwUndoRedline( SwUndoId nUserId, const SwPaM& rRange );
+    SwUndoRedline( SwUndoId nUserId, const SwPaM& rRange, sal_Int8 nDepth = 0 
);
 
     virtual ~SwUndoRedline() override;
 
@@ -49,6 +50,9 @@ public:
     virtual void RedoImpl( ::sw::UndoRedoContext & ) override;
 
     sal_uInt16 GetRedlSaveCount() const;
+#if OSL_DEBUG_LEVEL > 0
+    void SetRedlineCountDontCheck(bool bCheck);
+#endif
 };
 
 class SwUndoRedlineDelete final : public SwUndoRedline
@@ -106,7 +110,7 @@ private:
     virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
 
 public:
-    SwUndoAcceptRedline( const SwPaM& rRange );
+    SwUndoAcceptRedline( const SwPaM& rRange, sal_Int8 nDepth = 0 );
 
     virtual void RepeatImpl( ::sw::RepeatContext & ) override;
 };
@@ -117,7 +121,7 @@ private:
     virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
 
 public:
-    SwUndoRejectRedline( const SwPaM& rRange );
+    SwUndoRejectRedline( const SwPaM& rRange, sal_Int8 nDepth = 0 );
 
     virtual void RepeatImpl( ::sw::RepeatContext & ) override;
 };
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index dce7f3eb2724..bd258dcd5767 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -1410,6 +1410,7 @@ SwRedlineSaveData::SwRedlineSaveData(
 
 #if OSL_DEBUG_LEVEL > 0
     m_nRedlineCount = 
rSttPos.GetNode().GetDoc().getIDocumentRedlineAccess().GetRedlineTable().size();
+    m_bRedlineCountDontCheck = false;
     m_bRedlineMoved = rRedl.IsMoved();
 #endif
 }
@@ -1525,7 +1526,8 @@ void SwUndo::SetSaveData( SwDoc& rDoc, 
SwRedlineSaveDatas& rSData )
 #if OSL_DEBUG_LEVEL > 0
     // check redline count against count saved in RedlineSaveData object
     // except in the case of moved redlines
-    assert(rSData.empty() || rSData[0].m_bRedlineMoved ||
+    assert(
+        rSData.empty() || rSData[0].m_bRedlineMoved || 
rSData[0].m_bRedlineCountDontCheck ||
            (rSData[0].m_nRedlineCount == 
rDoc.getIDocumentRedlineAccess().GetRedlineTable().size()));
             // "redline count not restored properly"
 #endif
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index a8a572a40d4d..f77ceb3d26d8 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -37,10 +37,11 @@
 #include <sortopt.hxx>
 #include <docedt.hxx>
 
-SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange )
+SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange, sal_Int8 
nDepth )
     : SwUndo( SwUndoId::REDLINE, &rRange.GetDoc() ), SwUndRng( rRange ),
     mnUserId( nUsrId ),
-    mbHiddenRedlines( false )
+    mbHiddenRedlines( false ),
+    mnDepth( nDepth )
 {
     // consider Redline
     SwDoc& rDoc = rRange.GetDoc();
@@ -88,6 +89,14 @@ sal_uInt16 SwUndoRedline::GetRedlSaveCount() const
     return mpRedlSaveData ? mpRedlSaveData->size() : 0;
 }
 
+#if OSL_DEBUG_LEVEL > 0
+void SwUndoRedline::SetRedlineCountDontCheck(bool bCheck)
+{
+    if (mpRedlSaveData)
+        mpRedlSaveData->SetRedlineCountDontCheck(bCheck);
+}
+#endif
+
 void SwUndoRedline::UndoImpl(::sw::UndoRedoContext & rContext)
 {
     SwDoc& rDoc = rContext.GetDoc();
@@ -417,14 +426,14 @@ void SwUndoRedlineSort::SetSaveRange( const SwPaM& rRange 
)
     m_nSaveEndContent = rPos.GetContentIndex();
 }
 
-SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange )
-    : SwUndoRedline( SwUndoId::ACCEPT_REDLINE, rRange )
+SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange, sal_Int8 nDepth 
/* = 0 */ )
+    : SwUndoRedline( SwUndoId::ACCEPT_REDLINE, rRange, nDepth )
 {
 }
 
 void SwUndoAcceptRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
 {
-    rDoc.getIDocumentRedlineAccess().AcceptRedline(rPam, false);
+    rDoc.getIDocumentRedlineAccess().AcceptRedline(rPam, false, mnDepth);
 }
 
 void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext & rContext)
@@ -432,14 +441,14 @@ void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext 
& rContext)
     
rContext.GetDoc().getIDocumentRedlineAccess().AcceptRedline(rContext.GetRepeatPaM(),
 true);
 }
 
-SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange )
-    : SwUndoRedline( SwUndoId::REJECT_REDLINE, rRange )
+SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange, sal_Int8 nDepth 
/* = 0 */ )
+    : SwUndoRedline( SwUndoId::REJECT_REDLINE, rRange, nDepth )
 {
 }
 
 void SwUndoRejectRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
 {
-    rDoc.getIDocumentRedlineAccess().RejectRedline(rPam, false);
+    rDoc.getIDocumentRedlineAccess().RejectRedline(rPam, false, mnDepth);
 }
 
 void SwUndoRejectRedline::RepeatImpl(::sw::RepeatContext & rContext)

Reply via email to