sw/inc/ndarr.hxx                                        |    4 
 sw/source/core/doc/DocumentContentOperationsManager.cxx |   23 +-
 sw/source/core/docnode/nodes.cxx                        |  145 ++++++++++------
 sw/source/core/layout/frmtool.cxx                       |    5 
 4 files changed, 117 insertions(+), 60 deletions(-)

New commits:
commit 40bd193475374addbd8d9e6ade7c617d263df137
Author:     Michael Stahl <[email protected]>
AuthorDate: Thu Dec 23 12:07:40 2021 +0100
Commit:     Michael Stahl <[email protected]>
CommitDate: Thu Dec 23 17:56:18 2021 +0100

    tdf#135061 sw_redlinehide: fix copy into delete redline following table
    
    When pasting, the entire document body is covered by a delete redline.
    
    The insert position is in the last node, whose SwTextFrame has a
    MergedPara, and the problem is that the MergedPara::pLastNode continues
    to point to the last node of the document, even when the delete redline
    is adjusted to end in a newly inserted node by
    SaveRedlEndPosForRestore::Restore().
    
    Thus afer the 2nd paste, SwDoc::SearchNumRule() goes into infinite loop
    from node 141 to 86 and then jump via the bad MergedPara back to 141.
    
    The reason is that in DocumentContentOperationsManager::CopyWithFlyInFly()
    the RecreateStartTextFrames() isn't called.
    
    This is because it only checks if the preceding node is a text node,
    while here it is a table node.
    
    Fix this by checking if the node at the insert position is merged to a
    node preceding the previous node.
    
    Change-Id: I103b60b2bec86af11006ed591cfda2feb5f575a3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127273
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 70ac13eecfa620e94770a64110eeaa05f8c266e6)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127317
    Reviewed-by: Xisco Fauli <[email protected]>
    (cherry picked from commit f7455f031b5338b55b0c58822b3502913603e99c)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127355
    Tested-by: Michael Stahl <[email protected]>

diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 758c990e927e..45346c3f1a04 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -3450,21 +3450,28 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
         aRedlRest.Restore();
         if (bMakeNewFrames) // tdf#130685 only after aRedlRest
         {   // recreate from previous node (could be merged now)
-            if (SwTextNode *const pNode = aSavePos.GetNode().GetTextNode())
+            std::unordered_set<SwTextFrame*> frames;
+            SwTextNode * pNode = aSavePos.GetNode().GetTextNode();
+            SwTextNode *const pEndNode = rInsPos.GetNode().GetTextNode();
+            if (pEndNode)
             {
-                std::unordered_set<SwTextFrame*> frames;
-                SwTextNode *const pEndNode = rInsPos.GetNode().GetTextNode();
-                if (pEndNode)
+                SwIterator<SwTextFrame, SwTextNode, 
sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
+                for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
                 {
-                    SwIterator<SwTextFrame, SwTextNode, 
sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
-                    for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
+                    if (pFrame->getRootFrame()->IsHideRedlines())
                     {
-                        if (pFrame->getRootFrame()->IsHideRedlines())
+                        frames.insert(pFrame);
+                        // tdf#135061 check if end node is merged to a 
preceding node
+                        if (pNode == nullptr && pFrame->GetMergedPara()
+                            && pFrame->GetMergedPara()->pFirstNode->GetIndex() 
< aSavePos.GetIndex())
                         {
-                            frames.insert(pFrame);
+                            pNode = pFrame->GetMergedPara()->pFirstNode;
                         }
                     }
                 }
+            }
+            if (pNode != nullptr)
+            {
                 sw::RecreateStartTextFrames(*pNode);
                 if (!frames.empty())
                 {   // tdf#132187 check if the end node needs new frames
commit 1c7e0ec38101aa9b62ed3abdf0871002e6d1bdba
Author:     Michael Stahl <[email protected]>
AuthorDate: Tue Dec 21 15:19:33 2021 +0100
Commit:     Michael Stahl <[email protected]>
CommitDate: Thu Dec 23 17:56:03 2021 +0100

    tdf#135061 sw_redlinehide: create frames following hidden table
    
    When pasting, the entire document body is covered by a delete redline.
    
    The insert position is in the last node, following a table; table nodes
    do hot have any connection to frames if they are hidden by redlines,
    so MakeFrames() won't create frames for the inserted nodes.
    
    Refactor SwNodes::FindPrvNxtFrameNode() so that it can detect that table
    nodes are hidden in the current layout and continue to search in this
    case.
    
    For multiple layouts, MakeFrames() may need to use different nodes per
    layout, as the "nearest" one in one layout may be hidden in another.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127272
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit af4e20426ad24c6f2c0164b37472f2b7b54ecd30)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127316
    Reviewed-by: Xisco Fauli <[email protected]>
    (cherry picked from commit 1ca3c0d70b31ed173a896bcb37cc731b5324a573)
    
    Change-Id: I3bb2c861c861438ac2695ab49dd91dc2bde87db4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127354
    Tested-by: Michael Stahl <[email protected]>
    Reviewed-by: Michael Stahl <[email protected]>

diff --git a/sw/inc/ndarr.hxx b/sw/inc/ndarr.hxx
index d5cfcc06cd3f..7504a283fdf3 100644
--- a/sw/inc/ndarr.hxx
+++ b/sw/inc/ndarr.hxx
@@ -44,6 +44,7 @@ class SwNodeIndex;
 class SwNodeRange;
 class SwOLENode;
 class SwPaM;
+class SwRootFrame;
 class SwSectionData;
 class SwSectionFormat;
 class SwTOXBase;
@@ -310,7 +311,8 @@ public:
      forward after pEnd.
      If no valid node is found, return 0. rFrameIdx points to the node with 
frames. **/
     SwNode* FindPrvNxtFrameNode( SwNodeIndex& rFrameIdx,
-                                const SwNode* pEnd ) const;
+                                const SwNode* pEnd,
+                                SwRootFrame const* pLayout = nullptr) const;
 
     SwNode * DocumentSectionStartNode(SwNode * pNode) const;
     SwNode * DocumentSectionEndNode(SwNode * pNode) const;
diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx
index 3833ac633c3b..28088536c7ba 100644
--- a/sw/source/core/docnode/nodes.cxx
+++ b/sw/source/core/docnode/nodes.cxx
@@ -43,6 +43,7 @@
 #include <fmtftn.hxx>
 
 #include <docsh.hxx>
+#include <rootfrm.hxx>
 
 typedef std::vector<SwStartNode*> SwStartNodePointers;
 
@@ -2047,7 +2048,8 @@ SwContentNode* SwNodes::GoPrevSection( SwNodeIndex * pIdx,
  * @return result node; 0 if not found
  */
 SwNode* SwNodes::FindPrvNxtFrameNode( SwNodeIndex& rFrameIdx,
-                                    const SwNode* pEnd ) const
+        SwNode const*const pEnd,
+        SwRootFrame const*const pLayout) const
 {
     assert(pEnd != nullptr); // every caller currently
 
@@ -2070,53 +2072,65 @@ SwNode* SwNodes::FindPrvNxtFrameNode( SwNodeIndex& 
rFrameIdx,
                     ? pSttNd->StartOfSectionNode()->FindTableNode()
                     : pSttNd->FindTableNode();
             SwNodeIndex aIdx( rFrameIdx );
+
+            // search backward for a content or table node
+
             --aIdx;
-            SwNode *const pNd = &aIdx.GetNode();
+            pFrameNd = &aIdx.GetNode();
 
-            pFrameNd = pNd;
-            if (pFrameNd->IsContentNode())
+            do
             {
-                rFrameIdx = aIdx;
-                return pFrameNd;
-            }
-            // search forward or backward for a content node
-            pFrameNd = GoPrevSection( &aIdx, true, false );
-            if ( nullptr != pFrameNd &&
-                    ::CheckNodesRange( aIdx, rFrameIdx, true ) &&
-                    // Never out of the table at the start
-                    pFrameNd->FindTableNode() == pTableNd &&
-                    // Bug 37652: Never out of the table at the end
-                    (!pFrameNd->FindTableNode() || 
pFrameNd->FindTableBoxStartNode()
-                        == pSttNd->FindTableBoxStartNode() ) &&
-                     (!pSectNd || pSttNd->IsSectionNode() ||
-                      pSectNd->GetIndex() < pFrameNd->GetIndex())
-                    )
-            {
-                rFrameIdx = aIdx;
-            }
-            else
-            {
-                aIdx = pEnd->GetIndex() + 1;
-
-                pFrameNd = &aIdx.GetNode();
-                if (!pFrameNd->IsContentNode())
+                if (pFrameNd->IsContentNode())
                 {
-                    pFrameNd = GoNextSection( &aIdx, true, false );
-                    // NEVER leave the section when doing this!
-                    if (pFrameNd
-                        && !(::CheckNodesRange(aIdx, rFrameIdx, true)
-                             && (pFrameNd->FindTableNode() == pTableNd &&
-                                // NEVER go out of the table cell at the end
-                                (!pFrameNd->FindTableNode() || 
pFrameNd->FindTableBoxStartNode()
-                                    == pSttNd->FindTableBoxStartNode()))
-                             && (!pSectNd || pSttNd->IsSectionNode() ||
-                               pSectNd->EndOfSectionIndex() > 
pFrameNd->GetIndex()))
-                        )
+                    // TODO why does this not check for nested tables like 
forward direction
+                    rFrameIdx = aIdx;
+                    return pFrameNd;
+                }
+                else if (pFrameNd->IsEndNode() && 
pFrameNd->StartOfSectionNode()->IsTableNode())
+                {
+                    if (pLayout == nullptr
+                        || !pLayout->IsHideRedlines()
+                        || 
pFrameNd->StartOfSectionNode()->GetRedlineMergeFlag() != SwNode::Merge::Hidden)
                     {
-                        pFrameNd = nullptr;
+                        pFrameNd = pFrameNd->StartOfSectionNode();
+                        rFrameIdx = *pFrameNd;
+                        return pFrameNd;
+                    }
+                    else
+                    {
+                        aIdx = *pFrameNd->StartOfSectionNode();
+                        --aIdx;
+                        pFrameNd = &aIdx.GetNode();
                     }
                 }
-                if (pFrameNd && pFrameNd->IsContentNode())
+                else
+                {
+                    pFrameNd = GoPrevSection( &aIdx, true, false );
+                    if ( nullptr != pFrameNd && !(
+                            ::CheckNodesRange( aIdx, rFrameIdx, true ) &&
+                            // Never out of the table at the start
+                            pFrameNd->FindTableNode() == pTableNd &&
+                            // Bug 37652: Never out of the table at the end
+                            (!pFrameNd->FindTableNode() || 
pFrameNd->FindTableBoxStartNode()
+                                == pSttNd->FindTableBoxStartNode() ) &&
+                             (!pSectNd || pSttNd->IsSectionNode() ||
+                              pSectNd->GetIndex() < pFrameNd->GetIndex())
+                            ))
+                    {
+                        pFrameNd = nullptr; // no preceding content node, stop 
search
+                    }
+                }
+            }
+            while (pFrameNd != nullptr);
+
+            // search forward for a content or table node
+
+            aIdx = pEnd->GetIndex() + 1;
+            pFrameNd = &aIdx.GetNode();
+
+            do
+            {
+                if (pFrameNd->IsContentNode())
                 {
                     // Undo when merging a table with one before, if there is 
also one after it.
                     // However, if the node is in a table, it needs to be 
returned if the
@@ -2131,23 +2145,54 @@ SwNode* SwNodes::FindPrvNxtFrameNode( SwNodeIndex& 
rFrameIdx,
                         rFrameIdx = *pFrameNd;
                     }
                     else
+                    {
                         rFrameIdx = aIdx;
+                    }
+                    return pFrameNd;
                 }
-                else if( pNd->IsEndNode() && 
pNd->StartOfSectionNode()->IsTableNode() )
+                else if (pFrameNd->IsTableNode())
                 {
-                    pFrameNd = pNd->StartOfSectionNode();
-                    rFrameIdx = *pFrameNd;
+                    if (pLayout == nullptr
+                        || !pLayout->IsHideRedlines()
+                        || pFrameNd->GetRedlineMergeFlag() != 
SwNode::Merge::Hidden)
+                    {
+                        rFrameIdx = *pFrameNd;
+                        return pFrameNd;
+                    }
+                    else
+                    {
+                        aIdx = *pFrameNd->EndOfSectionNode();
+                        ++aIdx;
+                        pFrameNd = &aIdx.GetNode();
+                    }
                 }
                 else
                 {
+                    pFrameNd = GoNextSection( &aIdx, true, false );
+                    // NEVER leave the section when doing this!
+                    if (pFrameNd
+                        && !(::CheckNodesRange(aIdx, rFrameIdx, true)
+                             && (pFrameNd->FindTableNode() == pTableNd &&
+                                // NEVER go out of the table cell at the end
+                                (!pFrameNd->FindTableNode() || 
pFrameNd->FindTableBoxStartNode()
+                                    == pSttNd->FindTableBoxStartNode()))
+                             && (!pSectNd || pSttNd->IsSectionNode() ||
+                               pSectNd->EndOfSectionIndex() > 
pFrameNd->GetIndex()))
+                        )
+                    {
+                        pFrameNd = nullptr; // no following content node, stop 
search
+                    }
+                }
+            }
+            while (pFrameNd != nullptr);
+
+            // probably this is dead code, because the GoNextSection()
+            // should have ended up in the first text node in the table and
+            // then checked it's in a table?
+            {
                     aIdx = pEnd->GetIndex() + 1;
 
                     pFrameNd = &aIdx.GetNode();
-                    if (pFrameNd->IsTableNode())
-                    {
-                        rFrameIdx = aIdx;
-                    }
-                    else
                     {
                         pFrameNd = nullptr;
 
@@ -2165,9 +2210,9 @@ SwNode* SwNodes::FindPrvNxtFrameNode( SwNodeIndex& 
rFrameIdx,
                         {
                             rFrameIdx = aIdx;
                             pFrameNd = &aIdx.GetNode();
+                            assert(!"this isn't dead code?");
                         }
                     }
-                }
             }
         }
     }
diff --git a/sw/source/core/layout/frmtool.cxx 
b/sw/source/core/layout/frmtool.cxx
index ba56f95b34da..2a604cf8a15c 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -69,6 +69,7 @@
 #include <undobj.hxx>
 #include <DocumentSettingManager.hxx>
 #include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
 #include <IDocumentTimerAccess.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <IDocumentFieldsAccess.hxx>
@@ -1944,8 +1945,10 @@ void MakeFrames( SwDoc *pDoc, const SwNodeIndex &rSttIdx,
 
     SwNodeIndex aTmp( rSttIdx );
     sal_uLong nEndIdx = rEndIdx.GetIndex();
+    // TODO for multiple layouts there should be a loop here
     SwNode* pNd = pDoc->GetNodes().FindPrvNxtFrameNode( aTmp,
-                                            pDoc->GetNodes()[ nEndIdx-1 ]);
+                    pDoc->GetNodes()[ nEndIdx-1 ],
+                    pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
     if ( pNd )
     {
         bool bApres = aTmp < rSttIdx;

Reply via email to