sw/source/core/doc/DocumentRedlineManager.cxx |  148 +++++++++++++++++---------
 1 file changed, 97 insertions(+), 51 deletions(-)

New commits:
commit 84a97498abdf5590e36f2845f7ddd13a4335431e
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Fri Jul 24 19:41:29 2020 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Jul 30 11:30:11 2020 +0200

    tdf#133967 sw_redlinehide: fix redline deletion of table containing redlines
    
    A delete redline is created from node 371 to node 1625; there are
    existing redlines in the range, so AppendRedline() splits the new
    redline into pieces between and on the existing redlines.
    
    Even worse, because some of the existing redlines are in a table,
    InsertWithValidRanges() then splits the pieces that overlap the table
    into even smaller pieces, such that there are now the table structural
    nodes that were in the initial new delete redline's range but are now
    covered by none of the pieces.
    
    This means that multiple merged text frames are created, with non-merged
    frames between them, and thus the functions
    UpdateFramesForAddDeleteRedline() and
    UpdateFramesForRemoveDeleteRedline() [for Undo] have to deal with this
    unexpected complication.
    
    (regression from sw_redlinehide)
    
    Change-Id: Ibf71c1deb2bc3fa2af16035954d5ef71b6827be5
    (cherry picked from commit 658baf191ccc03899aef68d03196cee5959a3d07)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99472
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index 22c5d6b81b21..5ce6584e44d2 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -161,31 +161,55 @@ void UpdateFramesForAddDeleteRedline(SwDoc & rDoc, SwPaM 
const& rPam)
     }
     else
     {
-        std::vector<SwTextFrame*> frames;
-        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pStartNode);
-        for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
+        SwTextNode * pNode(pStartNode);
+        do
         {
-            if (pFrame->getRootFrame()->IsHideRedlines())
+            std::vector<SwTextFrame*> frames;
+            SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pNode);
+            for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
             {
-                frames.push_back(pFrame);
+                if (pFrame->getRootFrame()->IsHideRedlines())
+                {
+                    frames.push_back(pFrame);
+                }
             }
+            if (frames.empty())
+            {
+                auto const& layouts(rDoc.GetAllLayouts());
+                assert(std::none_of(layouts.begin(), layouts.end(),
+                    [](SwRootFrame const*const pLayout) { return 
pLayout->IsHideRedlines(); }));
+                (void) layouts;
+                break;
+            }
+            auto eMode(sw::FrameMode::Existing);
+            SwTextNode * pLast(pNode);
+            for (SwTextFrame * pFrame : frames)
+            {
+                SwTextNode & rFirstNode(pFrame->GetMergedPara()
+                    ? *pFrame->GetMergedPara()->pFirstNode
+                    : *pNode);
+                assert(pNode == pStartNode
+                        ? rFirstNode.GetIndex() <= pNode->GetIndex()
+                        : &rFirstNode == pNode);
+                // clear old one first to avoid DelFrames confusing updates & 
asserts...
+                pFrame->SetMergedPara(nullptr);
+                pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
+                    *pFrame, rFirstNode, eMode));
+                eMode = sw::FrameMode::New; // Existing is not idempotent!
+                // the first node of the new redline is not necessarily the 
first
+                // node of the merged frame, there could be another redline 
nearby
+                sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, 
*pNode, nullptr);
+                // if redline is split across table and table cell is empty, 
there's no redline in the cell and so no merged para
+                if (pFrame->GetMergedPara())
+                {
+                    pLast = 
const_cast<SwTextNode*>(pFrame->GetMergedPara()->pLastNode);
+                }
+            }
+            SwNodeIndex tmp(*pLast);
+            // skip over hidden sections!
+            pNode = 
static_cast<SwTextNode*>(pLast->GetNodes().GoNextSection(&tmp, 
/*bSkipHidden=*/true, /*bSkipProtect=*/false));
         }
-        auto eMode(sw::FrameMode::Existing);
-        for (SwTextFrame * pFrame : frames)
-        {
-            SwTextNode & rFirstNode(pFrame->GetMergedPara()
-                ? *pFrame->GetMergedPara()->pFirstNode
-                : *pStartNode);
-            assert(rFirstNode.GetIndex() <= pStartNode->GetIndex());
-            // clear old one first to avoid DelFrames confusing updates & 
asserts...
-            pFrame->SetMergedPara(nullptr);
-            pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
-                *pFrame, rFirstNode, eMode));
-            eMode = sw::FrameMode::New; // Existing is not idempotent!
-            // the first node of the new redline is not necessarily the first
-            // node of the merged frame, there could be another redline nearby
-            sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, 
*pStartNode, nullptr);
-        }
+        while (pNode && pNode->GetIndex() <= rPam.End()->nNode.GetIndex());
     }
     // fields last - SwGetRefField::UpdateField requires up-to-date frames
     UpdateFieldsForRedline(rDoc.getIDocumentFieldsAccess()); // after footnotes
@@ -197,6 +221,7 @@ void UpdateFramesForAddDeleteRedline(SwDoc & rDoc, SwPaM 
const& rPam)
 
 void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
 {
+    bool isAppendObjsCalled(false);
     rDoc.GetFootnoteIdxs().UpdateFootnote(rPam.Start()->nNode);
     SwTextNode *const pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
     if (!pStartNode)
@@ -212,35 +237,44 @@ void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, 
SwPaM const& rPam)
             // note: this will also create frames for all currently hidden flys
             // because it calls AppendAllObjs
             ::MakeFrames(&rDoc, rPam.Start()->nNode, rPam.End()->nNode);
+            isAppendObjsCalled = true;
         }
     }
     else
     {
-        std::vector<SwTextFrame*> frames;
-        std::set<SwRootFrame*> layouts;
-        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pStartNode);
-        for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
+        SwTextNode * pNode(pStartNode);
+        do
         {
-            if (pFrame->getRootFrame()->IsHideRedlines())
+            std::vector<SwTextFrame*> frames;
+            SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pNode);
+            for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
             {
-                frames.push_back(pFrame);
-                layouts.insert(pFrame->getRootFrame());
+                if (pFrame->getRootFrame()->IsHideRedlines())
+                {
+                    frames.push_back(pFrame);
+                }
             }
-        }
-        if (frames.empty())
-        {
-            return;
-        }
-        if (rPam.GetPoint()->nNode != rPam.GetMark()->nNode)
-        {
+            if (frames.empty())
+            {
+                auto const& layouts(rDoc.GetAllLayouts());
+                assert(std::none_of(layouts.begin(), layouts.end(),
+                    [](SwRootFrame const*const pLayout) { return 
pLayout->IsHideRedlines(); }));
+                (void) layouts;
+                break;
+            }
+
             // first, call CheckParaRedlineMerge on the first paragraph,
             // to init flag on new merge range (if any) + 1st node post the 
merge
             auto eMode(sw::FrameMode::Existing);
+            SwTextNode * pLast(pNode);
             for (SwTextFrame * pFrame : frames)
             {
                 if (auto const pMergedPara = pFrame->GetMergedPara())
                 {
-                    assert(pMergedPara->pFirstNode->GetIndex() <= 
pStartNode->GetIndex());
+                    pLast = const_cast<SwTextNode*>(pMergedPara->pLastNode);
+                    assert(pNode == pStartNode
+                        ? pMergedPara->pFirstNode->GetIndex() <= 
pNode->GetIndex()
+                        : pMergedPara->pFirstNode == pNode);
                     // clear old one first to avoid DelFrames confusing 
updates & asserts...
                     SwTextNode & rFirstNode(*pMergedPara->pFirstNode);
                     pFrame->SetMergedPara(nullptr);
@@ -249,24 +283,36 @@ void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, 
SwPaM const& rPam)
                     eMode = sw::FrameMode::New; // Existing is not idempotent!
                 }
             }
-            // now start node until end of merge + 1 has proper flags; 
MakeFrames
-            // should pick up from the next node in need of frames by checking 
flags
-            SwNodeIndex const start(*pStartNode, +1);
-            SwNodeIndex const end(rPam.End()->nNode, +1); // end is exclusive
-            // note: this will also create frames for all currently hidden flys
-            // both on first and non-first nodes because it calls AppendAllObjs
-            ::MakeFrames(&rDoc, start, end);
-            // re-use this to move flys that are now on the wrong frame, with 
end
-            // of redline as "second" node; the nodes between start and end 
should
-            // be complete with MakeFrames already
-            sw::MoveMergedFlysAndFootnotes(frames, *pStartNode,
-                    *rPam.End()->nNode.GetNode().GetTextNode(), false);
+            if (pLast != pNode)
+            {
+                // now start node until end of merge + 1 has proper flags; 
MakeFrames
+                // should pick up from the next node in need of frames by 
checking flags
+                SwNodeIndex const start(*pNode, +1);
+                SwNodeIndex const end(*pLast, +1); // end is exclusive
+                // note: this will also create frames for all currently hidden 
flys
+                // both on first and non-first nodes because it calls 
AppendAllObjs
+                ::MakeFrames(&rDoc, start, end);
+                isAppendObjsCalled = true;
+                // re-use this to move flys that are now on the wrong frame, 
with end
+                // of redline as "second" node; the nodes between start and 
end should
+                // be complete with MakeFrames already
+                sw::MoveMergedFlysAndFootnotes(frames, *pNode, *pLast, false);
+            }
+            SwNodeIndex tmp(*pLast);
+            // skip over hidden sections!
+            pNode = 
static_cast<SwTextNode*>(pLast->GetNodes().GoNextSection(&tmp, 
/*bSkipHidden=*/true, /*bSkipProtect=*/false));
         }
-        else
-        {   // recreate flys in the one node the hard way...
-            for (auto const& pLayout : layouts)
+        while (pNode && pNode->GetIndex() <= rPam.End()->nNode.GetIndex());
+    }
+
+    if (!isAppendObjsCalled)
+    {   // recreate flys in the one node the hard way...
+        for (auto const& pLayout : rDoc.GetAllLayouts())
+        {
+            if (pLayout->IsHideRedlines())
             {
                 AppendAllObjs(rDoc.GetSpzFrameFormats(), pLayout);
+                break;
             }
         }
     }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to