Rebased ref, commits from common ancestor:
commit 953021f6ad5f13f8f40544a5ddc8605ff4a7a046
Author:     Michael Stahl <mst...@redhat.com>
AuthorDate: Wed May 20 13:18:42 2015 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    gbuild: allow recording of CppunitTests and PythonTests too
    
    Since these don't use soffice they need to be tweaked to use RR varaiable.
    
    Unfortunately rr crashes in some CppunitTest so don't enable that now.
    Unfortunately rr crashes in PythonTest.
    
    Change-Id: I2143618fa2181e36b6aaeded43637cb3481f5e47

diff --git a/solenv/gbuild/CppunitTest.mk b/solenv/gbuild/CppunitTest.mk
index 1ac3b210e149..8e130d481802 100644
--- a/solenv/gbuild/CppunitTest.mk
+++ b/solenv/gbuild/CppunitTest.mk
@@ -63,6 +63,10 @@ gb_CppunitTest_VALGRINDTOOL += --vgdb=yes --vgdb-error=0
 endif
 endif
 
+ifneq ($(strip $(RR)),)
+gb_CppunitTest_RR := rr record
+endif
+
 # defined by platform
 #  gb_CppunitTest_get_filename
 gb_CppunitTest_RUNTIMEDEPS := $(call 
gb_Executable_get_runtime_dependencies,cppunittester)
@@ -134,7 +138,8 @@ else
                $(gb_CppunitTest_malloc_check) \
                $(if $(strip $(PYTHON_URE)),\
                        PYTHONDONTWRITEBYTECODE=1) \
-               $(ICECREAM_RUN) $(gb_CppunitTest_GDBTRACE) 
$(gb_CppunitTest_VALGRINDTOOL) $(gb_CppunitTest_CPPTESTCOMMAND) \
+               $(ICECREAM_RUN) $(gb_CppunitTest_GDBTRACE) 
$(gb_CppunitTest_VALGRINDTOOL) $(gb_CppunitTest_RR) \
+                       $(gb_CppunitTest_CPPTESTCOMMAND) \
                $(call gb_LinkTarget_get_target,$(call 
gb_CppunitTest_get_linktarget,$*)) \
                $(call gb_CppunitTest__make_args) "-env:CPPUNITTESTTARGET=$@" \
                $(if $(gb_CppunitTest_POSTGDBTRACE), \
diff --git a/solenv/gbuild/PythonTest.mk b/solenv/gbuild/PythonTest.mk
index c579a34ea6d5..a2bac3819e02 100644
--- a/solenv/gbuild/PythonTest.mk
+++ b/solenv/gbuild/PythonTest.mk
@@ -55,7 +55,7 @@ else
                $(if $(filter-out MACOSX WNT,$(OS_FOR_BUILD)),$(if 
$(DISABLE_GUI),, \
                        SAL_USE_VCLPLUGIN=svp \
                )) \
-               $(gb_CppunitTest_GDBTRACE) $(gb_CppunitTest_VALGRINDTOOL) \
+               $(gb_CppunitTest_GDBTRACE) $(gb_CppunitTest_VALGRINDTOOL) 
$(gb_CppunitTest_RR) \
                        $(gb_PythonTest_COMMAND) \
                        $(if 
$(PYTHON_TEST_NAME),$(PYTHON_TEST_NAME),$(MODULES)) \
                $(if $(gb_CppunitTest__interactive),, \
commit b3e360ba7aa4091e5cafa7be32828d70245c0d6c
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Thu Sep 6 12:58:18 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: update flys and footnotes on redline ops
    
    Re-use some code that is already used elsewhere; for the
    UpdateFramesForAddDeleteRedline(), the same code as for switching
    the layout to Hide mode should work, for
    UpdateFramesForRemoveDeleteRedline() use the code that is used for
    SwTextNode::SplitContentNode().
    
    Change-Id: I97601bfb63478cc999cf7017da0225b2dc62ad37

diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index caec50025ef1..d27a579d3e43 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -140,25 +140,34 @@ void UpdateFramesForAddDeleteRedline(SwPaM const& rPam)
         pFrame->SetMergedPara(nullptr);
         pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
             *pFrame, rFirstNode, sw::FrameMode::Existing));
+        // 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);
     }
 }
 
 void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
 {
+    SwTextNode *const pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
+    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())
+    {
+        if (pFrame->getRootFrame()->IsHideRedlines())
+        {
+            frames.push_back(pFrame);
+            layouts.insert(pFrame->getRootFrame());
+        }
+    }
+    if (frames.empty())
+    {
+        return;
+    }
     if (rPam.GetPoint()->nNode != rPam.GetMark()->nNode)
     {
         // first, call CheckParaRedlineMerge on the first paragraph,
         // to init flag on new merge range (if any) + 1st node post the merge
-        SwTextNode *const 
pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
-        std::vector<SwTextFrame*> frames;
-        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pStartNode);
-        for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
-        {
-            if (pFrame->getRootFrame()->IsHideRedlines())
-            {
-                frames.push_back(pFrame);
-            }
-        }
         for (SwTextFrame * pFrame : frames)
         {
             if (auto const pMergedPara = pFrame->GetMergedPara())
@@ -173,11 +182,22 @@ void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, 
SwPaM const& rPam)
         }
         // 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
-        if (!frames.empty())
+        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);
+    }
+    else
+    {   // recreate flys in the one node the hard way...
+        for (auto const& pLayout : layouts)
         {
-            SwNodeIndex const start(*pStartNode, +1);
-            SwNodeIndex const end(rPam.End()->nNode, +1); // end is exclusive
-            ::MakeFrames(&rDoc, start, end);
+            AppendAllObjs(rDoc.GetSpzFrameFormats(), pLayout);
         }
     }
 }
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index a52bf0f14fa0..0b19178734d2 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -105,12 +105,19 @@ TextFrameIndex UpdateMergedParaForDelete(MergedPara & 
rMerged,
         bool isRealDelete,
         SwTextNode const& rNode, sal_Int32 nIndex, sal_Int32 nLen);
 
+void MoveMergedFlysAndFootnotes(std::vector<SwTextFrame*> const& rFrames,
+        SwTextNode const& rFirstNode, SwTextNode & rSecondNode, bool);
+
 void MoveDeletedPrevFrames(SwTextNode & rDeletedPrev, SwTextNode & rNode);
 void CheckResetRedlineMergeFlag(SwTextNode & rNode, bool bRecreateMerged);
 
 void UpdateFramesForAddDeleteRedline(SwPaM const& rPam);
 void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam);
 
+void AddRemoveFlysAnchoredToFrameStartingAtNode(
+        SwTextFrame & rFrame, SwTextNode & rTextNode,
+        std::set<sal_uLong> *pSkipped);
+
 } // namespace sw
 
 /// Represents the visualization of a paragraph. Typical upper is an
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 3e6ff2d4f565..e6fbd7c553dc 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4167,6 +4167,74 @@ void SwRootFrame::InvalidateAllObjPos()
     }
 }
 
+namespace sw {
+
+/// rTextNode is the first one of the "new" merge - if rTextNode isn't the same
+/// as MergedPara::pFirstNode, then nodes before rTextNode have their flys
+/// already properly attached, so only the other nodes need handling here.
+void AddRemoveFlysAnchoredToFrameStartingAtNode(
+        SwTextFrame & rFrame, SwTextNode & rTextNode,
+        std::set<sal_uLong> *const pSkipped)
+{
+    auto const pMerged(rFrame.GetMergedPara());
+    if (pMerged
+        // do this only *once*, for the *last* frame
+        // otherwise AppendObj would create multiple frames for fly-frames!
+        && !rFrame.GetFollow())
+    {
+        assert(pMerged->pFirstNode->GetIndex() <= rTextNode.GetIndex()
+            && rTextNode.GetIndex() <= pMerged->pLastNode->GetIndex());
+        // add visible flys in non-first node to merged frame
+        // (hidden flys remain and are deleted via DelFrames())
+        SwFrameFormats& rTable(*rTextNode.GetDoc()->GetSpzFrameFormats());
+        SwPageFrame *const pPage(rFrame.FindPageFrame());
+        std::vector<sw::Extent>::const_iterator 
iterFirst(pMerged->extents.begin());
+        std::vector<sw::Extent>::const_iterator iter(iterFirst);
+        SwTextNode const* pNode(pMerged->pFirstNode);
+        for ( ; ; ++iter)
+        {
+            if (iter == pMerged->extents.end()
+                || iter->pNode != pNode)
+            {
+                if (pNode == &rTextNode)
+                {   // remove existing hidden at-char anchored flys
+                    RemoveHiddenObjsOfNode(
+                        rTextNode, &iterFirst, &iter);
+                }
+                else if (rTextNode.GetIndex() < pNode->GetIndex())
+                {
+                    // pNode's frame has been deleted by 
CheckParaRedlineMerge()
+                    AppendObjsOfNode(&rTable,
+                        pNode->GetIndex(), &rFrame, pPage, rTextNode.GetDoc(),
+                        &iterFirst, &iter);
+                    if (pSkipped)
+                    {
+                        // if a fly has been added by AppendObjsOfNode, it 
must be skipped; if not, then it doesn't matter if it's skipped or not because 
it has no frames and because of that it would be skipped anyway
+                        if (auto const pFlys = pNode->GetAnchoredFlys())
+                        {
+                            for (auto const pFly : *pFlys)
+                            {
+                                if (pFly->Which() != RES_DRAWFRMFMT)
+                                {
+                                    
pSkipped->insert(pFly->GetContent().GetContentIdx()->GetIndex());
+                                }
+                            }
+                        }
+                    }
+                }
+                if (iter == pMerged->extents.end())
+                {
+                    break;
+                }
+                pNode = iter->pNode;
+                iterFirst = iter;
+            }
+        }
+    }
+}
+
+} // namespace sw
+
 static void UnHideRedlines(SwRootFrame & rLayout,
         SwNodes & rNodes, SwNode const& rEndOfSectionNode,
         std::set<sal_uLong> *const pSkipped)
@@ -4226,59 +4294,7 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                                 }
                             }
                         }
-                        if (pMerged
-                            // do this only *once*, for the *last* frame
-                            // otherwise AppendObj would create multiple 
frames for fly-frames!
-                            && !pFrame->GetFollow())
-                        {
-                            // add visible flys in non-first node to merged 
frame
-                            // (hidden flys remain and are deleted via 
DelFrames())
-                            SwFrameFormats& 
rTable(*rTextNode.GetDoc()->GetSpzFrameFormats());
-                            SwPageFrame *const pPage(pFrame->FindPageFrame());
-                            std::vector<sw::Extent>::const_iterator 
iterFirst(pMerged->extents.begin());
-                            std::vector<sw::Extent>::const_iterator 
iter(iterFirst);
-                            SwTextNode const* pNode(&rTextNode);
-                            for ( ; ; ++iter)
-                            {
-                                if (iter == pMerged->extents.end()
-                                    || iter->pNode != pNode)
-                                {
-                                    if (pNode == &rTextNode)
-                                    {   // remove existing hidden at-char 
anchored flys
-                                        RemoveHiddenObjsOfNode(
-                                            rTextNode, &iterFirst, &iter);
-                                    }
-                                    else
-                                    {
-                                        // pNode's frame has been deleted by 
CheckParaRedlineMerge()
-                                        AppendObjsOfNode(&rTable,
-                                            pNode->GetIndex(), pFrame, pPage,
-                                            rTextNode.GetDoc(),
-                                            &iterFirst, &iter);
-                                        if (pSkipped)
-                                        {
-                                            // if a fly has been added by 
AppendObjsOfNode, it must be skipped; if not, then it doesn't matter if it's 
skipped or not because it has no frames and because of that it would be skipped 
anyway
-                                            if (auto const pFlys = 
pNode->GetAnchoredFlys())
-                                            {
-                                                for (auto const pFly : *pFlys)
-                                                {
-                                                    if (pFly->Which() != 
RES_DRAWFRMFMT)
-                                                    {
-                                                        
pSkipped->insert(pFly->GetContent().GetContentIdx()->GetIndex());
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                    if (iter == pMerged->extents.end())
-                                    {
-                                        break;
-                                    }
-                                    pNode = iter->pNode;
-                                    iterFirst = iter;
-                                }
-                            }
-                        }
+                        
sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, rTextNode, pSkipped);
                     }
                 }
                 else
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index a8d672dda16e..9c16f081eb69 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -365,13 +365,18 @@ static void lcl_ChangeFootnoteRef( SwTextNode &rNode )
     }
 }
 
-namespace {
+namespace sw {
 
 // check if there are flys on the existing frames (now on "pNode")
 // that need to be moved to the new frames of "this"
 void MoveMergedFlysAndFootnotes(std::vector<SwTextFrame*> const& rFrames,
-        SwTextNode const& rFirstNode, SwTextNode const& rSecondNode)
+        SwTextNode const& rFirstNode, SwTextNode & rSecondNode,
+        bool isSplitNode)
 {
+    if (!isSplitNode)
+    {
+        lcl_ChangeFootnoteRef(rSecondNode);
+    }
     int nLevel(0);
     for (sal_uLong nIndex = rSecondNode.GetIndex() + 1; ; ++nIndex)
     {
@@ -608,7 +613,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & 
rPos,
         }
         if (eOldMergeFlag != SwNode::Merge::None)
         {
-            MoveMergedFlysAndFootnotes(frames, *pNode, *this);
+            MoveMergedFlysAndFootnotes(frames, *pNode, *this, true);
         }
     }
     else
@@ -739,7 +744,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & 
rPos,
 
         if (bRecreateThis)
         {
-            MoveMergedFlysAndFootnotes(frames, *pNode, *this);
+            MoveMergedFlysAndFootnotes(frames, *pNode, *this, true);
         }
     }
 
commit 0c07bb358b1dc365e034687bcda1c973ce887b1c
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Wed Sep 5 13:03:02 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw: remove window invalidation from SwRedlineTable::DeleteAndDestroyAll()
    
    This is called in 2 situations, from ClearDoc() and from SwDoc dtor.
    
    In the latter case, there is no window any more, and in the former case,
    surely something else must have invalidated it already.
    
    Change-Id: Ideecdeb145171a4dafbec50a04d4ec5aa2acab82

diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 56dfd57a82f9..6fe4e815dc69 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -605,9 +605,6 @@ void SwRedlineTable::Remove( size_type nP )
 
 void SwRedlineTable::DeleteAndDestroyAll()
 {
-    if (maVector.empty())
-        return;
-    SwDoc *const pDoc = maVector.front()->GetDoc();
     while (!maVector.empty())
     {
         auto const pRedline = maVector.back();
@@ -615,14 +612,6 @@ void SwRedlineTable::DeleteAndDestroyAll()
         LOKRedlineNotification(RedlineNotification::Remove, pRedline);
         delete pRedline;
     }
-    if (pDoc && !pDoc->IsInDtor())
-    {
-        SwViewShell* 
pSh(pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() );
-        if (pSh)
-        {
-            pSh->InvalidateWindows(SwRect(0, 0, SAL_MAX_INT32, SAL_MAX_INT32));
-        }
-    }
 }
 
 void SwRedlineTable::DeleteAndDestroy(size_type const nP)
commit bec70c9eb1fee59aa0632b34cd91727e32398d9b
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Tue Sep 4 18:59:01 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw: SwDocTest: adjust this so it actually tests something interesting
    
    * test more than 1 paragraph, by calling SplitNode()
    * enable Undo, because that's the more usual situation
    * remove one mode that is identical to the previous one
    * use SwUnoCursor because plain SwCursor isn't corrected when nodes
      are deleted
    * create a selection before calling Delete functions
    
    Change-Id: If406bd8c37b005e431fbaebe82f297b051da1ed3

diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx
index 1a6d18d35c3a..cc95e3ce1da2 100644
--- a/sw/qa/core/uwriter.cxx
+++ b/sw/qa/core/uwriter.cxx
@@ -35,6 +35,7 @@
 
 #include <breakit.hxx>
 #include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <IDocumentFieldsAccess.hxx>
 #include <IDocumentStatistics.hxx>
@@ -1067,7 +1068,6 @@ void SwDocTest::randomTest()
         RedlineFlags::NONE,
         RedlineFlags::On | RedlineFlags::ShowMask,
         RedlineFlags::On | RedlineFlags::Ignore,
-        RedlineFlags::On | RedlineFlags::Ignore | RedlineFlags::ShowMask,
         RedlineFlags::On | RedlineFlags::ShowInsert,
         RedlineFlags::On | RedlineFlags::ShowDelete
     };
@@ -1077,6 +1077,7 @@ void SwDocTest::randomTest()
 
     for( size_t rlm = 0; rlm < SAL_N_ELEMENTS(modes); rlm++ )
     {
+        m_pDoc->GetIDocumentUndoRedo().DoUndo(true);
         m_pDoc->ClearDoc();
 
         // setup redlining
@@ -1085,15 +1086,31 @@ void SwDocTest::randomTest()
 
         for( int i = 0; i < 2000; i++ )
         {
-            SwCursor aCrs(getRandomPosition(m_pDoc, i/20), nullptr);
-            aCrs.SetMark();
+            std::shared_ptr<SwUnoCursor> pCrs(
+                m_pDoc->CreateUnoCursor(getRandomPosition(m_pDoc, i/20)));
 
             switch (getRand (i < 50 ? 3 : 6)) {
             // insert ops first
             case 0: {
-                if 
(!m_pDoc->getIDocumentContentOperations().InsertString(aCrs, getRandString())) {
-//                    fprintf (stderr, "failed to insert string !\n");
+                OUString const tmp(getRandString());
+                sal_Int32 current(0);
+                sal_Int32 nextBreak(tmp.indexOf('\n'));
+                do
+                {
+                    sal_Int32 const len((nextBreak == -1 ? tmp.getLength() : 
nextBreak - current));
+                    if (0 < len)
+                    {
+                        m_pDoc->getIDocumentContentOperations().InsertString(
+                            *pCrs, tmp.copy(current, len));
+                    }
+                    if (nextBreak != -1)
+                    {
+                        
m_pDoc->getIDocumentContentOperations().SplitNode(*pCrs->GetPoint(), false);
+                        current = nextBreak + 1;
+                        nextBreak = tmp.indexOf('\n', current);
+                    }
                 }
+                while (nextBreak != -1);
                 break;
             }
             case 1:
@@ -1106,19 +1123,27 @@ void SwDocTest::randomTest()
 
             // movement / deletion ops later
             case 3: // deletion
+                pCrs->SetMark();
                 switch (getRand(6)) {
                 case 0:
-                    m_pDoc->getIDocumentContentOperations().DelFullPara(aCrs);
+                    *pCrs->GetMark() = getRandomPosition(m_pDoc, 42);
+                    m_pDoc->getIDocumentContentOperations().DelFullPara(*pCrs);
                     break;
                 case 1:
-                    m_pDoc->getIDocumentContentOperations().DeleteRange(aCrs);
+                    *pCrs->GetMark() = getRandomPosition(m_pDoc, 42);
+                    m_pDoc->getIDocumentContentOperations().DeleteRange(*pCrs);
                     break;
                 case 2:
-                    
m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aCrs, !!getRand(1));
+                    *pCrs->GetMark() = getRandomPosition(m_pDoc, 42);
+                    
m_pDoc->getIDocumentContentOperations().DeleteAndJoin(*pCrs, !!getRand(1));
                     break;
                 case 3:
                 default:
-                    m_pDoc->getIDocumentContentOperations().Overwrite(aCrs, 
getRandString());
+                    OUString const tmp(getRandString());
+                    if (tmp.getLength())
+                    {
+                        
m_pDoc->getIDocumentContentOperations().Overwrite(*pCrs, tmp);
+                    }
                     break;
                 }
                 break;
@@ -1131,7 +1156,7 @@ void SwDocTest::randomTest()
                            SwMoveFlags::REDLINES |
                            SwMoveFlags::NO_DELFRMS;
                 SwPosition aTo(getRandomPosition(m_pDoc, i/10));
-                m_pDoc->getIDocumentContentOperations().MoveRange(aCrs, aTo, 
nFlags);
+                m_pDoc->getIDocumentContentOperations().MoveRange(*pCrs, aTo, 
nFlags);
                 break;
             }
 
commit c25acede28b623051f6ebe4e99362057aa8e7257
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Tue Sep 4 18:55:13 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw: SwRedlineTable::DeleteAndDestroy() is surprisingly dangerous
    
    At least with the randomised test, it can happen that deleting one
    redline will recursively delete other redlines that are located in
    the hidden content section of the redline, or at least try to and
    crash because those have already been deleted before.
    
    The callers will either delete 1 redline, or delete all of them
    via DeleteAndDestroyAll(), so put a safer loop into
    DeleteAndDestroyAll() and have DeleteAndDestroy() only delete 1.
    
    Change-Id: I9c4225544a43a4a03f4eb7b6f56e7fe848c8ca54

diff --git a/sw/inc/docary.hxx b/sw/inc/docary.hxx
index 20871385fa97..940789ad262e 100644
--- a/sw/inc/docary.hxx
+++ b/sw/inc/docary.hxx
@@ -345,7 +345,7 @@ public:
 
     void Remove( size_type nPos );
     void Remove( const SwRangeRedline* p );
-    void DeleteAndDestroy( size_type nPos, size_type nLen = 1 );
+    void DeleteAndDestroy(size_type nPos);
     void DeleteAndDestroyAll();
 
     void dumpAsXml(struct _xmlTextWriter* pWriter) const;
@@ -389,7 +389,7 @@ public:
 
     void Insert( SwExtraRedline* p );
 
-    void DeleteAndDestroy( sal_uInt16 nPos, sal_uInt16 nLen = 1 );
+    void DeleteAndDestroy( sal_uInt16 nPos);
     void DeleteAndDestroyAll();
 
     void dumpAsXml(struct _xmlTextWriter* pWriter) const;
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 950526187efc..56dfd57a82f9 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -605,26 +605,32 @@ void SwRedlineTable::Remove( size_type nP )
 
 void SwRedlineTable::DeleteAndDestroyAll()
 {
-    DeleteAndDestroy(0, size());
-}
-
-void SwRedlineTable::DeleteAndDestroy( size_type nP, size_type nL )
-{
-    SwDoc* pDoc = nullptr;
-    if( !nP && nL && nL == size() )
-        pDoc = maVector.front()->GetDoc();
-
-    for( vector_type::const_iterator it = maVector.begin() + nP; it != 
maVector.begin() + nP + nL; ++it )
+    if (maVector.empty())
+        return;
+    SwDoc *const pDoc = maVector.front()->GetDoc();
+    while (!maVector.empty())
+    {
+        auto const pRedline = maVector.back();
+        maVector.erase(maVector.back());
+        LOKRedlineNotification(RedlineNotification::Remove, pRedline);
+        delete pRedline;
+    }
+    if (pDoc && !pDoc->IsInDtor())
     {
-        LOKRedlineNotification(RedlineNotification::Remove, *it);
-        delete *it;
+        SwViewShell* 
pSh(pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() );
+        if (pSh)
+        {
+            pSh->InvalidateWindows(SwRect(0, 0, SAL_MAX_INT32, SAL_MAX_INT32));
+        }
     }
-    maVector.erase( maVector.begin() + nP, maVector.begin() + nP + nL );
+}
 
-    SwViewShell* pSh;
-    if( pDoc && !pDoc->IsInDtor() &&
-        nullptr != ( pSh = 
pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() ) )
-        pSh->InvalidateWindows( SwRect( 0, 0, SAL_MAX_INT32, SAL_MAX_INT32 ) );
+void SwRedlineTable::DeleteAndDestroy(size_type const nP)
+{
+    auto const pRedline = maVector[nP];
+    maVector.erase(maVector.begin() + nP);
+    LOKRedlineNotification(RedlineNotification::Remove, pRedline);
+    delete pRedline;
 }
 
 SwRedlineTable::size_type SwRedlineTable::FindNextOfSeqNo( size_type nSttPos ) 
const
@@ -1883,7 +1889,7 @@ void SwExtraRedlineTable::Insert( SwExtraRedline* p )
     //p->CallDisplayFunc();
 }
 
-void SwExtraRedlineTable::DeleteAndDestroy( sal_uInt16 nPos, sal_uInt16 nLen )
+void SwExtraRedlineTable::DeleteAndDestroy(sal_uInt16 const nPos)
 {
     /*
     SwDoc* pDoc = 0;
@@ -1891,10 +1897,8 @@ void SwExtraRedlineTable::DeleteAndDestroy( sal_uInt16 
nPos, sal_uInt16 nLen )
         pDoc = front()->GetDoc();
     */
 
-    for( std::vector<SwExtraRedline*>::iterator it = m_aExtraRedlines.begin() 
+ nPos; it != m_aExtraRedlines.begin() + nPos + nLen; ++it )
-        delete *it;
-
-    m_aExtraRedlines.erase( m_aExtraRedlines.begin() + nPos, 
m_aExtraRedlines.begin() + nPos + nLen );
+    delete m_aExtraRedlines[nPos];
+    m_aExtraRedlines.erase(m_aExtraRedlines.begin() + nPos);
 
     /*
     SwViewShell* pSh;
@@ -1906,7 +1910,12 @@ void SwExtraRedlineTable::DeleteAndDestroy( sal_uInt16 
nPos, sal_uInt16 nLen )
 
 void SwExtraRedlineTable::DeleteAndDestroyAll()
 {
-    DeleteAndDestroy(0, m_aExtraRedlines.size());
+    while (!m_aExtraRedlines.empty())
+    {
+        auto const pRedline = m_aExtraRedlines.back();
+        m_aExtraRedlines.pop_back();
+        delete pRedline;
+    }
 }
 
 SwExtraRedline::~SwExtraRedline()
commit ed81bd445dab56b1eaeea43254174fedb9e2c6e4
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Tue Sep 4 18:52:56 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw: SwUndoOverwrite ctor shouldn't DeleteRedline if ...
    
    ... it's at the end of the node already, similar to CanGrouping().
    
    Change-Id: Ic7c6f5caa6e69e9414112cb245db97fd5d79e87d

diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx
index bee06b365dd4..d5652ce85e6e 100644
--- a/sw/source/core/undo/unovwr.cxx
+++ b/sw/source/core/undo/unovwr.cxx
@@ -43,6 +43,13 @@ SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& 
rPos,
     : SwUndo(SwUndoId::OVERWRITE, pDoc),
       pRedlSaveData( nullptr ), bGroup( false )
 {
+    SwTextNode *const pTextNd = rPos.nNode.GetNode().GetTextNode();
+    assert(pTextNd);
+    sal_Int32 const nTextNdLen = pTextNd->GetText().getLength();
+
+    nSttNode = rPos.nNode.GetIndex();
+    nSttContent = rPos.nContent.GetIndex();
+
     if( !pDoc->getIDocumentRedlineAccess().IsIgnoreRedline() && 
!pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty() )
     {
         SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
@@ -52,16 +59,13 @@ SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& 
rPos,
         {
             pRedlSaveData.reset();
         }
+        if (nSttContent < nTextNdLen)
+        {
+            pDoc->getIDocumentRedlineAccess().DeleteRedline(aPam, false, 
USHRT_MAX);
+        }
     }
 
-    nSttNode = rPos.nNode.GetIndex();
-    nSttContent = rPos.nContent.GetIndex();
-
-    SwTextNode* pTextNd = rPos.nNode.GetNode().GetTextNode();
-    OSL_ENSURE( pTextNd, "Overwrite not in a TextNode?" );
-
     bInsChar = true;
-    sal_Int32 nTextNdLen = pTextNd->GetText().getLength();
     if( nSttContent < nTextNdLen )     // no pure insert?
     {
         aDelStr += OUStringLiteral1( pTextNd->GetText()[nSttContent] );
commit 873b1ed61ac8992b77f820cf604fa2def4c5f722
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Tue Sep 4 16:21:56 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw: SwUndoOverwrite::CanGrouping() should ignore redlines for inserted
    
    ... characters; if the character is inserted at the end of the node,
    the aPam end position will have an invalid index Len()+1 and
    the DeleteRedline() will correct existing redlines onto that index,
    which will assert later.
    
    Change-Id: Ia31cd1937385fb10fd284e7add61c39f96b917ab

diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx
index e2fb76a19f63..bee06b365dd4 100644
--- a/sw/source/core/undo/unovwr.cxx
+++ b/sw/source/core/undo/unovwr.cxx
@@ -120,6 +120,7 @@ bool SwUndoOverwrite::CanGrouping( SwDoc* pDoc, SwPosition& 
rPos,
         rCC.isLetterNumeric( aInsStr, aInsStr.getLength()-1 ) )
         return false;
 
+    if (!bInsChar && rPos.nContent.GetIndex() < 
pDelTextNd->GetText().getLength())
     {
         SwRedlineSaveDatas aTmpSav;
         SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
commit 6065be5754dab67455acaa35b2751212861820a8
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Tue Sep 4 14:34:03 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw: avoid updating redlines to be empty in Overwrite()
    
    The problem is that SwIndexReg::Update will correct a 1-character
    redline in the middle of the newly-inserted part of the overwrite string
    into a 0-length redline, which then a later SwTextNode::Update() will
    correct in such a way that the whole thing becomes unsorted.
    
    Just delete redlines in the entire overwrite range, which should help;
    the aPam actually deletes them in the *last* character only which
    seems rather unintentional anyway.
    
    Change-Id: I61b6b312998e0779651d30f636312ef13556428c

diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 1bb52e00e186..dc45775cbf25 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -2357,8 +2357,12 @@ bool DocumentContentOperationsManager::MoveAndJoin( 
SwPaM& rPaM, SwPosition& rPo
     return bRet;
 }
 
+// Overwrite only uses the point of the PaM, the mark is ignored; characters
+// are replaced from point until the end of the node; at the end of the node,
+// characters are inserted.
 bool DocumentContentOperationsManager::Overwrite( const SwPaM &rRg, const 
OUString &rStr )
 {
+    assert(rStr.getLength());
     SwPosition& rPt = *const_cast<SwPosition*>(rRg.GetPoint());
     if( m_rDoc.GetAutoCorrExceptWord() )                  // Add to AutoCorrect
     {
@@ -2382,6 +2386,7 @@ bool DocumentContentOperationsManager::Overwrite( const 
SwPaM &rRg, const OUStri
                                 ? pNode->GetpSwpHints()->Count() : 0;
     SwDataChanged aTmp( rRg );
     SwIndex& rIdx = rPt.nContent;
+    sal_Int32 const nActualStart(rIdx.GetIndex());
     sal_Int32 nStart = 0;
 
     bool bOldExpFlg = pNode->IsIgnoreDontExpand();
@@ -2443,14 +2448,14 @@ bool DocumentContentOperationsManager::Overwrite( const 
SwPaM &rRg, const OUStri
     if (!m_rDoc.GetIDocumentUndoRedo().DoesUndo() &&
         !m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && 
!m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
     {
-        SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
+        SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, 
rPt.nContent.GetIndex());
         m_rDoc.getIDocumentRedlineAccess().DeleteRedline( aPam, true, 
USHRT_MAX );
     }
     else if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
     {
         // FIXME: this redline is WRONG: there is no DELETE, and the skipped
         // characters are also included in aPam
-        SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
+        SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, 
rPt.nContent.GetIndex());
         m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( 
nsRedlineType_t::REDLINE_INSERT, aPam ), true);
     }
 
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index dc196aadc9ed..caec50025ef1 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -82,6 +82,8 @@ using namespace com::sun::star;
             for(SwRangeRedline* j : rTable)
             {
                 // check for empty redlines
+                // note: these can destroy sorting in SwTextNode::Update()
+                // if there's another one wihout mark on the same pos.
                 OSL_ENSURE( ( *(j->GetPoint()) != *(j->GetMark()) ) ||
                             ( j->GetContentIdx() != nullptr ),
                             ERROR_PREFIX "empty redline" );
commit 393ead12c00824fb0145fab7dd0d4f48c954ae60
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Tue Sep 4 11:51:02 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: SwDocTest: avoid deleting selections that ...
    
    ... start or end outside of the body in randomTest().
    
    Also, it would be more interesting to delete parts of the one
    paragraph, not always the whole thing.
    
    Change-Id: I782bcde24e0ed542c32ae50b50997555fd32813f

diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx
index f0055671a58a..1a6d18d35c3a 100644
--- a/sw/qa/core/uwriter.cxx
+++ b/sw/qa/core/uwriter.cxx
@@ -1041,12 +1041,20 @@ getRandomPosition(SwDoc *pDoc, int /* nOffset */)
 {
     const SwPosition aPos(pDoc->GetNodes().GetEndOfContent());
     size_t nNodes = aPos.nNode.GetNode().GetIndex() - 
aPos.nNode.GetNode().StartOfSectionIndex();
-    size_t n = comphelper::rng::uniform_size_distribution(0, nNodes);
+    // exclude body start/end node
+    size_t n = comphelper::rng::uniform_size_distribution(1, nNodes - 1);
     SwPaM pam(aPos);
     for (sal_uLong i = 0; i < n; ++i)
     {
         pam.Move(fnMoveBackward, GoInNode);
     }
+    SwTextNode *const pTextNode(pam.GetPoint()->nNode.GetNode().GetTextNode());
+    assert(pTextNode);
+    int n2 = comphelper::rng::uniform_int_distribution(0, pTextNode->Len());
+    for (sal_Int32 i = 0; i < n2; ++i)
+    {
+        pam.Move(fnMoveBackward, GoInContent);
+    }
     return *pam.GetPoint();
 }
 
commit 816461162da2c23915ef2f2e29209454e17e981d
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Mon Sep 3 18:07:29 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: update frames on redline ops
    
    When Delete redline is created, removed, accepted, rejected & undo/redo
    of all of these, update all the text frames so they're merged or not,
    as required.
    
    Change-Id: I08aa6aea270a50d19f4bda0caf016870a42a8dd3

diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 11af40aaa469..1bb52e00e186 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -44,6 +44,7 @@
 #include <fmtcnct.hxx>
 #include <SwStyleNameMapper.hxx>
 #include <redline.hxx>
+#include <txtfrm.hxx>
 #include <unocrsr.hxx>
 #include <mvsave.hxx>
 #include <ndtxt.hxx>
@@ -3619,6 +3620,11 @@ bool 
DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & rPa
         m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( 
nsRedlineType_t::REDLINE_DELETE, rPam ), true );
     m_rDoc.getIDocumentState().SetModified();
 
+    // sw_redlinehide: 2 reasons why this is needed:
+    // 1. it's the first redline in node => RedlineDelText was sent but ignored
+    // 2. redline spans multiple nodes => must merge text frames
+    sw::UpdateFramesForAddDeleteRedline(rPam);
+
     if (pUndo)
     {
         m_rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::EMPTY, nullptr );
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index ad9c292810a1..dc196aadc9ed 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -19,6 +19,7 @@
 #include <DocumentRedlineManager.hxx>
 #include <frmfmt.hxx>
 #include <rootfrm.hxx>
+#include <txtfrm.hxx>
 #include <doc.hxx>
 #include <IDocumentUndoRedo.hxx>
 #include <IDocumentState.hxx>
@@ -113,6 +114,74 @@ using namespace com::sun::star;
 
 #endif
 
+namespace sw {
+
+void UpdateFramesForAddDeleteRedline(SwPaM const& rPam)
+{
+    SwTextNode *const pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
+    std::vector<SwTextFrame*> frames;
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pStartNode);
+    for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+    {
+        if (pFrame->getRootFrame()->IsHideRedlines())
+        {
+            frames.push_back(pFrame);
+        }
+    }
+    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, sw::FrameMode::Existing));
+    }
+}
+
+void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
+{
+    if (rPam.GetPoint()->nNode != rPam.GetMark()->nNode)
+    {
+        // first, call CheckParaRedlineMerge on the first paragraph,
+        // to init flag on new merge range (if any) + 1st node post the merge
+        SwTextNode *const 
pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
+        std::vector<SwTextFrame*> frames;
+        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pStartNode);
+        for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
+        {
+            if (pFrame->getRootFrame()->IsHideRedlines())
+            {
+                frames.push_back(pFrame);
+            }
+        }
+        for (SwTextFrame * pFrame : frames)
+        {
+            if (auto const pMergedPara = pFrame->GetMergedPara())
+            {
+                assert(pMergedPara->pFirstNode->GetIndex() <= 
pStartNode->GetIndex());
+                // clear old one first to avoid DelFrames confusing updates & 
asserts...
+                SwTextNode & rFirstNode(*pMergedPara->pFirstNode);
+                pFrame->SetMergedPara(nullptr);
+                pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
+                    *pFrame, rFirstNode, sw::FrameMode::Existing));
+            }
+        }
+        // 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
+        if (!frames.empty())
+        {
+            SwNodeIndex const start(*pStartNode, +1);
+            SwNodeIndex const end(rPam.End()->nNode, +1); // end is exclusive
+            ::MakeFrames(&rDoc, start, end);
+        }
+    }
+}
+
+} // namespace sw
+
 namespace
 {
     inline bool IsPrevPos( const SwPosition & rPos1, const SwPosition & rPos2 )
@@ -294,6 +363,7 @@ namespace
     {
         bool bRet = true;
         SwRangeRedline* pRedl = rArr[ rPos ];
+        SwDoc& rDoc = *pRedl->GetDoc();
         SwPosition *pRStt = nullptr, *pREnd = nullptr;
         SwComparePosition eCmp = SwComparePosition::Outside;
         if( pSttRng && pEndRng )
@@ -309,7 +379,6 @@ namespace
         {
         case nsRedlineType_t::REDLINE_INSERT:
             {
-                SwDoc& rDoc = *pRedl->GetDoc();
                 const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
                 bool bDelRedl = false;
                 switch( eCmp )
@@ -390,6 +459,8 @@ namespace
             {
                 SwRangeRedline* pNew = nullptr;
                 bool bCheck = false, bReplace = false;
+                SwPaM const updatePaM(pSttRng ? *pSttRng : *pRedl->Start(),
+                                      pEndRng ? *pEndRng : *pRedl->End());
 
                 switch( eCmp )
                 {
@@ -473,6 +544,8 @@ namespace
                     rArr.Remove( pRedl );
                     rArr.Insert( pRedl );
                 }
+
+                sw::UpdateFramesForRemoveDeleteRedline(rDoc, updatePaM);
             }
             break;
 
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 10bde328c903..a52bf0f14fa0 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -108,6 +108,9 @@ TextFrameIndex UpdateMergedParaForDelete(MergedPara & 
rMerged,
 void MoveDeletedPrevFrames(SwTextNode & rDeletedPrev, SwTextNode & rNode);
 void CheckResetRedlineMergeFlag(SwTextNode & rNode, bool bRecreateMerged);
 
+void UpdateFramesForAddDeleteRedline(SwPaM const& rPam);
+void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam);
+
 } // namespace sw
 
 /// Represents the visualization of a paragraph. Typical upper is an
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index 58d2de808363..fb1d30f9f953 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -25,6 +25,7 @@
 #include <swundo.hxx>
 #include <pam.hxx>
 #include <ndtxt.hxx>
+#include <txtfrm.hxx>
 #include <UndoCore.hxx>
 #include <UndoDelete.hxx>
 #include <strings.hrc>
@@ -106,6 +107,17 @@ void SwUndoRedline::UndoImpl(::sw::UndoRedoContext & 
rContext)
         }
         SetPaM(rPam, true);
     }
+
+    // update frames after calling SetSaveData
+    if (dynamic_cast<SwUndoRedlineDelete*>(this))
+    {
+        sw::UpdateFramesForRemoveDeleteRedline(rDoc, rPam);
+    }
+    else if (dynamic_cast<SwUndoAcceptRedline*>(this)
+          || dynamic_cast<SwUndoRejectRedline*>(this))
+    {   // (can't check here if there's a delete redline being accepted)
+        sw::UpdateFramesForAddDeleteRedline(rPam);
+    }
 }
 
 void SwUndoRedline::RedoImpl(::sw::UndoRedoContext & rContext)
@@ -191,6 +203,7 @@ void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, 
SwPaM & rPam)
     {
         rDoc.getIDocumentRedlineAccess().AppendRedline( new 
SwRangeRedline(*mpRedlData, rPam), false );
     }
+    sw::UpdateFramesForAddDeleteRedline(rPam);
 }
 
 bool SwUndoRedlineDelete::CanGrouping( const SwUndoRedlineDelete& rNext )
commit 458e35da41e84e38febb758b0ce163faebb00bd2
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Mon Sep 3 15:12:29 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: remove a pointless level of indentation
    
    Change-Id: I82893951b6e227ab1ed6423e08a0370561482cd8

diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index d9b9250d617a..11af40aaa469 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -3563,92 +3563,89 @@ 
DocumentContentOperationsManager::~DocumentContentOperationsManager()
 
 bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & 
rPam, const bool )
 {
-    OSL_ENSURE( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn(), 
"DeleteAndJoinWithRedline: redline off" );
+    assert(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn());
 
-    {
-        SwUndoRedlineDelete* pUndo = nullptr;
-        RedlineFlags eOld = 
m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
-        m_rDoc.GetDocumentRedlineManager().checkRedlining( eOld );
+    SwUndoRedlineDelete* pUndo = nullptr;
+    RedlineFlags eOld = m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
+    m_rDoc.GetDocumentRedlineManager().checkRedlining( eOld );
 
-        auto & rDMA(*m_rDoc.getIDocumentMarkAccess());
-        std::vector<std::unique_ptr<SwUndo>> MarkUndos;
-        for (auto iter = rDMA.getAnnotationMarksBegin();
-                  iter != rDMA.getAnnotationMarksEnd(); )
+    auto & rDMA(*m_rDoc.getIDocumentMarkAccess());
+    std::vector<std::unique_ptr<SwUndo>> MarkUndos;
+    for (auto iter = rDMA.getAnnotationMarksBegin();
+              iter != rDMA.getAnnotationMarksEnd(); )
+    {
+        // tdf#111524 remove annotation marks that have their field
+        // characters deleted
+        SwPosition const& rEndPos((**iter).GetMarkEnd());
+        if (*rPam.Start() < rEndPos && rEndPos <= *rPam.End())
         {
-            // tdf#111524 remove annotation marks that have their field
-            // characters deleted
-            SwPosition const& rEndPos((**iter).GetMarkEnd());
-            if (*rPam.Start() < rEndPos && rEndPos <= *rPam.End())
+            if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
-                if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
-                {
-                    
MarkUndos.emplace_back(o3tl::make_unique<SwUndoDeleteBookmark>(**iter));
-                }
-                // iter is into annotation mark vector so must be dereferenced!
-                rDMA.deleteMark(&**iter);
-                // this invalidates iter, have to start over...
-                iter = rDMA.getAnnotationMarksBegin();
+                
MarkUndos.emplace_back(o3tl::make_unique<SwUndoDeleteBookmark>(**iter));
             }
-            else
-            {   // marks are sorted by start
-                if (*rPam.End() < (**iter).GetMarkStart())
-                {
-                    break;
-                }
-                ++iter;
+            // iter is into annotation mark vector so must be dereferenced!
+            rDMA.deleteMark(&**iter);
+            // this invalidates iter, have to start over...
+            iter = rDMA.getAnnotationMarksBegin();
+        }
+        else
+        {   // marks are sorted by start
+            if (*rPam.End() < (**iter).GetMarkStart())
+            {
+                break;
             }
+            ++iter;
         }
+    }
 
-        if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
+    if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
+    {
+        /* please don't translate -- for cultural reasons this comment is 
protected
+           until the redline implementation is finally fixed some day */
+        //JP 06.01.98: MUSS noch optimiert werden!!!
+        m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags(
+            RedlineFlags::On | RedlineFlags::ShowInsert | 
RedlineFlags::ShowDelete);
+        pUndo = new SwUndoRedlineDelete( rPam, SwUndoId::DELETE );
+        const SwRewriter aRewriter = pUndo->GetRewriter();
+        m_rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::DELETE, &aRewriter 
);
+        for (auto& it : MarkUndos)
         {
-
-            /* please don't translate -- for cultural reasons this comment is 
protected
-               until the redline implementation is finally fixed some day */
-            //JP 06.01.98: MUSS noch optimiert werden!!!
-            m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags(
-                RedlineFlags::On | RedlineFlags::ShowInsert | 
RedlineFlags::ShowDelete );
-            pUndo = new SwUndoRedlineDelete( rPam, SwUndoId::DELETE );
-            const SwRewriter aRewriter = pUndo->GetRewriter();
-            m_rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::DELETE, 
&aRewriter );
-            for (auto& it : MarkUndos)
-            {
-                m_rDoc.GetIDocumentUndoRedo().AppendUndo(it.release());
-            }
-            m_rDoc.GetIDocumentUndoRedo().AppendUndo( pUndo );
+            m_rDoc.GetIDocumentUndoRedo().AppendUndo(it.release());
         }
+        m_rDoc.GetIDocumentUndoRedo().AppendUndo( pUndo );
+    }
 
-        if ( *rPam.GetPoint() != *rPam.GetMark() )
-            m_rDoc.getIDocumentRedlineAccess().AppendRedline( new 
SwRangeRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true );
-        m_rDoc.getIDocumentState().SetModified();
+    if (*rPam.GetPoint() != *rPam.GetMark())
+        m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( 
nsRedlineType_t::REDLINE_DELETE, rPam ), true );
+    m_rDoc.getIDocumentState().SetModified();
 
-        if ( pUndo )
+    if (pUndo)
+    {
+        m_rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::EMPTY, nullptr );
+        // ??? why the hell is the AppendUndo not below the
+        // CanGrouping, so this hideous cleanup wouldn't be necessary?
+        // bah, this is redlining, probably changing this would break it...
+        if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo())
         {
-            m_rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::EMPTY, nullptr );
-            // ??? why the hell is the AppendUndo not below the
-            // CanGrouping, so this hideous cleanup wouldn't be necessary?
-            // bah, this is redlining, probably changing this would break it...
-            if ( m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo() )
+            SwUndo * const pLastUndo( m_rDoc.GetUndoManager().GetLastUndo() );
+            SwUndoRedlineDelete *const pUndoRedlineDel( 
dynamic_cast<SwUndoRedlineDelete*>(pLastUndo) );
+            if (pUndoRedlineDel)
             {
-                SwUndo * const pLastUndo( 
m_rDoc.GetUndoManager().GetLastUndo() );
-                SwUndoRedlineDelete * const pUndoRedlineDel( dynamic_cast< 
SwUndoRedlineDelete* >( pLastUndo ) );
-                if ( pUndoRedlineDel )
+                bool const bMerged = pUndoRedlineDel->CanGrouping( *pUndo );
+                if (bMerged)
                 {
-                    bool const bMerged = pUndoRedlineDel->CanGrouping( *pUndo 
);
-                    if ( bMerged )
-                    {
-                        ::sw::UndoGuard const undoGuard( 
m_rDoc.GetIDocumentUndoRedo() );
-                        SwUndo const* const pDeleted = 
m_rDoc.GetUndoManager().RemoveLastUndo();
-                        OSL_ENSURE( pDeleted == pUndo, 
"DeleteAndJoinWithRedlineImpl: "
-                            "undo removed is not undo inserted?" );
-                        delete pDeleted;
-                    }
+                    ::sw::UndoGuard const undoGuard( 
m_rDoc.GetIDocumentUndoRedo() );
+                    SwUndo const*const pDeleted = 
m_rDoc.GetUndoManager().RemoveLastUndo();
+                    OSL_ENSURE( pDeleted == pUndo, 
"DeleteAndJoinWithRedlineImpl: "
+                        "undo removed is not undo inserted?" );
+                    delete pDeleted;
                 }
             }
-            //JP 06.01.98: MUSS noch optimiert werden!!!
-            m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld );
         }
-        return true;
+        //JP 06.01.98: MUSS noch optimiert werden!!!
+        m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld );
     }
+    return true;
 }
 
 bool DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam,
commit a17c75e87b5d0a35f824eda6a5ca65a667be8b9b
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Mon Sep 3 12:18:25 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: handle delete-without-redline inside of redline
    
    The problem is that the SwInsText/SwDelText do not transfer the
    "deleted-ness" of the text from one node to the other in the
    SwTextFrame, so add a new hint that is sent after SwInsText & before
    SwDelText to move the info that is in the extents vector.
    
    Change-Id: I32d8dbe52a18556d8dc2c50a47246a6600fdb355

diff --git a/sw/inc/hints.hxx b/sw/inc/hints.hxx
index bee0ebb1c21a..bdf2eceaa8a6 100644
--- a/sw/inc/hints.hxx
+++ b/sw/inc/hints.hxx
@@ -31,6 +31,7 @@ class SwNodes;
 class SwPageFrame;
 class SwFrame;
 class SwHistory;
+class SwTextNode;
 
 // Base class for all Message-Hints:
 // "Overhead" of SfxPoolItem is handled here
@@ -95,6 +96,18 @@ public:
 
 namespace sw {
 
+/// text is moved into pDestNode
+class MoveText : public SfxHint
+{
+public:
+    SwTextNode * pDestNode;
+    sal_Int32 nDestStart;
+    sal_Int32 nSourceStart;
+    sal_Int32 nLen;
+
+    MoveText(SwTextNode *pD, sal_Int32 nD, sal_Int32 nS, sal_Int32 nL);
+};
+
 /// new delete redline is created
 class RedlineDelText : public SfxHint
 {
diff --git a/sw/source/core/attr/hints.cxx b/sw/source/core/attr/hints.cxx
index 7c1ff2a40aec..7746058a7e1e 100644
--- a/sw/source/core/attr/hints.cxx
+++ b/sw/source/core/attr/hints.cxx
@@ -48,6 +48,11 @@ SwDelText::SwDelText( sal_Int32 nS, sal_Int32 nL )
 
 namespace sw {
 
+MoveText::MoveText(SwTextNode *const pD, sal_Int32 const nD, sal_Int32 const 
nS, sal_Int32 const nL)
+    : pDestNode(pD), nDestStart(nD), nSourceStart(nS), nLen(nL)
+{
+}
+
 RedlineDelText::RedlineDelText(sal_Int32 const nS, sal_Int32 const nL)
     : nStart(nS), nLen(nL)
 {
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index dcb4a632ef58..ef792d95d9ea 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -1656,6 +1656,72 @@ static void lcl_ModifyOfst(SwTextFrame* pFrame, 
TextFrameIndex const nPos, TextF
     }
 }
 
+namespace {
+
+void UpdateMergedParaForMove(sw::MergedPara & rMerged,
+        SwTextFrame & rTextFrame,
+        bool & o_rbRecalcFootnoteFlag,
+        SwTextNode const& rDestNode,
+        SwTextNode const& rNode,
+        sal_Int32 const nDestStart,
+        sal_Int32 const nSourceStart,
+        sal_Int32 const nLen)
+{
+    std::vector<std::pair<sal_Int32, sal_Int32>> deleted;
+    sal_Int32 const nSourceEnd(nSourceStart + nLen);
+    sal_Int32 nLastEnd(0);
+    for (auto it = rMerged.extents.begin(); it != rMerged.extents.end(); ++it)
+    {
+        if (it->pNode == &rNode)
+        {
+            sal_Int32 const nStart(std::max(nLastEnd, nSourceStart));
+            sal_Int32 const nEnd(std::min(it->nStart, nSourceEnd));
+            if (nStart < nEnd)
+            {
+                deleted.emplace_back(nStart, nEnd);
+            }
+            nLastEnd = it->nEnd;
+            if (nSourceEnd <= it->nEnd)
+            {
+                break;
+            }
+        }
+        else if (rNode.GetIndex() < it->pNode->GetIndex())
+        {
+            break;
+        }
+    }
+    if (nLastEnd != rNode.Len() + nLen) // add nLen, string was removed already
+    {
+        assert(rNode.Len() == 0 || nLastEnd < nSourceEnd);
+        if (nLastEnd < nSourceEnd)
+        {
+            deleted.emplace_back(std::max(nLastEnd, nSourceStart), nSourceEnd);
+        }
+    }
+    if (!deleted.empty())
+    {
+        o_rbRecalcFootnoteFlag = true;
+        for (auto it : deleted)
+        {
+            sal_Int32 const nStart(it.first - nSourceStart + nDestStart);
+            TextFrameIndex const nDeleted = UpdateMergedParaForDelete(rMerged, 
false,
+                rDestNode, nStart, it.second - it.first);
+            assert(nDeleted == it.second - it.first);
+            assert(nDeleted);
+            // InvalidateRange/lcl_SetScriptInval was called sufficiently for 
SwInsText
+            lcl_SetWrong(rTextFrame, rDestNode, nStart, -nDeleted, false);
+            if (rTextFrame.HasFollow())
+            {
+                TextFrameIndex const nIndex(sw::MapModelToView(rMerged, 
&rDestNode, nStart));
+                lcl_ModifyOfst(&rTextFrame, nIndex, nDeleted); // FIXME why 
positive?
+            }
+        }
+    }
+}
+
+} // namespace
+
 /**
  * Related: fdo#56031 filter out attribute changes that don't matter for
  * humans/a11y to stop flooding the destination mortal with useless noise
@@ -1675,6 +1741,7 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, 
SfxHint const& rHint)
 {
     SfxPoolItem const* pOld(nullptr);
     SfxPoolItem const* pNew(nullptr);
+    sw::MoveText const* pMoveText(nullptr);
     sw::RedlineDelText const* pRedlineDelText(nullptr);
     sw::RedlineUnDelText const* pRedlineUnDelText(nullptr);
 
@@ -1683,6 +1750,10 @@ void SwTextFrame::SwClientNotify(SwModify const& 
rModify, SfxHint const& rHint)
         pOld = pHint->m_pOld;
         pNew = pHint->m_pNew;
     }
+    else if (auto const pHt = dynamic_cast<sw::MoveText const*>(&rHint))
+    {
+        pMoveText = pHt;
+    }
     else if (auto const pHynt = dynamic_cast<sw::RedlineDelText 
const*>(&rHint))
     {
         pRedlineDelText = pHynt;
@@ -1805,6 +1876,27 @@ void SwTextFrame::SwClientNotify(SwModify const& 
rModify, SfxHint const& rHint)
                 lcl_ModifyOfst( this, nPos, nLen );
         }
     }
+    else if (pMoveText)
+    {
+        if (m_pMergedPara
+            && m_pMergedPara->pFirstNode->GetIndex() <= 
pMoveText->pDestNode->GetIndex()
+            && pMoveText->pDestNode->GetIndex() <= 
m_pMergedPara->pLastNode->GetIndex())
+        {   // if it's not 2 nodes in merged frame, assume the target node 
doesn't have frames at all
+            assert(std::abs(static_cast<long>(rNode.GetIndex()) - 
static_cast<long>(pMoveText->pDestNode->GetIndex())) == 1);
+            UpdateMergedParaForMove(*m_pMergedPara,
+                    *this,
+                    bRecalcFootnoteFlag,
+                    *pMoveText->pDestNode, rNode,
+                    pMoveText->nDestStart,
+                    pMoveText->nSourceStart,
+                    pMoveText->nLen);
+        }
+        else
+        {
+            // there is a situation where this is okay: from JoinNext, which 
will then call CheckResetRedlineMergeFlag, which will then create merged from 
scratch for this frame
+            // assert(!m_pMergedPara || !getRootFrame()->IsHideRedlines() || 
!pMoveText->pDestNode->getLayoutFrame(getRootFrame()));
+        }
+    }
     else switch (nWhich)
     {
         case RES_LINENUMBER:
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 5f5869905b89..a8d672dda16e 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -2503,6 +2503,8 @@ void SwTextNode::CutImpl( SwTextNode * const pDest, const 
SwIndex & rDestStart,
     // want to find their anchor text frame in the follow chain
     SwInsText aInsHint( nDestStart, nLen );
     pDest->ModifyNotification( nullptr, &aInsHint );
+    sw::MoveText const moveHint(pDest, nDestStart, nTextStartIdx, nLen);
+    CallSwClientNotify(moveHint);
     SwDelText aDelHint( nTextStartIdx, nLen );
     ModifyNotification( nullptr, &aDelHint );
 
commit c680b7f425d007663cd3cbad35fdbce0d88bd694
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Fri Aug 31 19:14:58 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: call CompressRedlines later in DeleteRange*
    
    DocumentContentOperationsManager::DeleteRange* functions should call
    CompressRedlines after sw_JoinText, because otherwise if there's a join,
    the FillSaveData in SwUndoDelete ctor will split redlines that contain
    the selection into 2, and they won't be recombined although CanCombine
    is true for them.
    
    If you do 2 operations, then on Undo of the second, SetSaveData
    will restore the previous redlines and join them into 1, but then it will
    assert because it expects 2 redlines, pointlessly split.
    
    Change-Id: I1df3f2205b4f16904f66b5af1f3b9f0ccbaf24a0

diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index f6a2562983cd..d9b9250d617a 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1763,6 +1763,12 @@ void DocumentContentOperationsManager::DeleteSection( 
SwNode *pNode )
 void DocumentContentOperationsManager::DeleteRange( SwPaM & rPam )
 {
     lcl_DoWithBreaks( *this, rPam, 
&DocumentContentOperationsManager::DeleteRangeImpl );
+
+    if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
+        && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
+    {
+        m_rDoc.getIDocumentRedlineAccess().CompressRedlines();
+    }
 }
 
 bool DocumentContentOperationsManager::DelFullPara( SwPaM& rPam )
@@ -3667,6 +3673,12 @@ bool 
DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam,
         ::sw_JoinText( rPam, bJoinPrev );
     }
 
+    if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
+        && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
+    {
+        m_rDoc.getIDocumentRedlineAccess().CompressRedlines();
+    }
+
     return true;
 }
 
@@ -3859,8 +3871,6 @@ bool 
DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam)
 
     } while( false );
 
-    if( !m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && 
!m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )
-        m_rDoc.getIDocumentRedlineAccess().CompressRedlines();
     m_rDoc.getIDocumentState().SetModified();
 
     return true;
commit 4f016edcbdbdb417f623450cc461aff5f1c04fd4
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Wed Aug 22 17:09:02 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: SwUndoDelete
    
    This is problematic because of the calls to SplitNode.
    Ideally we'd want the SplitNode to create merged frames already, but
    that doesn't seem to be easy to achieve; several problems with this are:
    
    1. the redlines are only restored at the end of UndoImpl
    2. even if we store another set of SwRedlineSaveDatas right before the
       Join (while preventing the first SwRedlineSaveDatas from deleting
       them), and restore them by passing a closure to SplitNode, there
       are complaints about empty redlines, and also this case isn't
       handled properly:
    
         f<delete start>o<redline start>o
         b<redline end>a<redline start>r
         b<redline end>a<delete end>z
    
    So instead, let SplitNode create whatever frames it does, and fix it up
    at the end manually on the start node's frames.
    
    This necessitates delaying the creation of the frames on the moved nodes
    until the end too.
    
    Change-Id: I8ba2967659cc2ddbe6f7c40e0447d79601498ed6

diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index 7e942b427ecb..f4f6c5559d85 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -41,6 +41,9 @@
 #include <sfx2/app.hxx>
 #include <fldbas.hxx>
 #include <fmtfld.hxx>
+#include <frmtool.hxx>
+#include <txtfrm.hxx>
+#include <rootfrm.hxx>
 #include <strings.hrc>
 #include <vector>
 
@@ -763,6 +766,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
 
     SwNodeIndex aIdx(rDoc.GetNodes(), nCalcStt);
     SwNode* pInsNd = &aIdx.GetNode();
+    SwNode* pMovedNode = nullptr;
 
     {   // code block so that SwPosition is detached when deleting a Node
         SwPosition aPos( aIdx );
@@ -838,7 +842,6 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
                     ++aPos.nNode;
             }
         }
-        SwNode* pMovedNode = nullptr;
         if( m_nSectDiff )
         {
             sal_uLong nMoveIndex = aPos.nNode.GetIndex();
@@ -866,7 +869,11 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
         {
             SwNodeRange aRange( *m_pMvStt, 0, *m_pMvStt, m_nNode );
             SwNodeIndex aCopyIndex( aPos.nNode, -1 );
-            rDoc.GetUndoManager().GetUndoNodes().Copy_( aRange, aPos.nNode );
+            rDoc.GetUndoManager().GetUndoNodes().Copy_(aRange, aPos.nNode,
+                    // sw_redlinehide: delay creating frames: the flags on the
+                    // nodes aren't necessarily up-to-date, and the redlines
+                    // from m_pRedlSaveData aren't applied yet...
+                    false);
 
             if( m_nReplaceDummy )
             {
@@ -889,9 +896,6 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
             }
         }
 
-        if( pMovedNode )
-            lcl_MakeAutoFrames(*rDoc.GetSpzFrameFormats(), 
pMovedNode->GetIndex());
-
         if( m_aSttStr )
         {
             aPos.nNode = nSttNode - m_nNdDiff + ( m_bJoinNext ? 0 : 
m_nReplaceDummy );
@@ -958,6 +962,52 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
     if( m_pRedlSaveData )
         SetSaveData(rDoc, *m_pRedlSaveData);
 
+    if (m_aSttStr && (!m_bFromTableCopy || 0 != m_nNode))
+    {
+        // only now do we have redlines in the document again; fix up the split
+        // frames
+        SwTextNode *const pStartNode(aIdx.GetNodes()[nSttNode]->GetTextNode());
+        assert(pStartNode);
+        std::vector<SwTextFrame*> frames;
+        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pStartNode);
+        for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
+        {
+            if (pFrame->getRootFrame()->IsHideRedlines())
+            {
+                frames.push_back(pFrame);
+            }
+        }
+        for (SwTextFrame * pFrame : frames)
+        {
+            // SplitNode could have moved the original frame to the start node
+            // & created a new one on end, or could have created new frame on
+            // start node... grab start node's frame and recreate MergedPara.
+            SwTextNode & rFirstNode(pFrame->GetMergedPara()
+                ? *pFrame->GetMergedPara()->pFirstNode
+                : *pStartNode);
+            assert(rFirstNode.GetIndex() <= pStartNode->GetIndex());
+            pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
+                        *pFrame, rFirstNode, sw::FrameMode::Existing));
+            // note: this may or may not delete frames on the end node
+        }
+    }
+
+    // create frames after SetSaveData has recreated redlines
+    if (0 != m_nNode)
+    {
+        // don't include end node in the range: it may have been merged already
+        // by the start node, or it may be merged by one of the moved nodes,
+        // but if it isn't merged, its current frame(s) should be good...
+        SwNodeIndex const start(rDoc.GetNodes(), nSttNode + (m_bDelFullPara ? 
0 : 1));
+        SwNodeIndex const end(rDoc.GetNodes(), nEndNode);
+        ::MakeFrames(&rDoc, start, end);
+    }
+
+    if (pMovedNode)
+    {   // probably better do this after creating all frames
+        lcl_MakeAutoFrames(*rDoc.GetSpzFrameFormats(), pMovedNode->GetIndex());
+    }
+
     AddUndoRedoPaM(rContext, true);
 }
 
commit a94756ddcb29e993c426f98e195c54879c99e0bf
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Wed Aug 22 15:09:59 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: something about Join
    
    Change-Id: I047b6008c5f0bb6e79c63421a4dba09ba8cf3320
    Todo: remember what i was thinking when i wrote this

diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx
index 89454ea879ae..54c6a1c56e74 100644
--- a/sw/source/core/doc/docedt.cxx
+++ b/sw/source/core/doc/docedt.cxx
@@ -412,7 +412,13 @@ bool sw_JoinText( SwPaM& rPam, bool bJoinPrev )
                     rPam.GetBound( false ) = aAlphaPos;
             }
             // delete the Node, at last!
+            SwNode::Merge const 
eOldMergeFlag(pOldTextNd->GetRedlineMergeFlag());
+            if (eOldMergeFlag == SwNode::Merge::First)
+            {
+                sw::MoveDeletedPrevFrames(*pOldTextNd, *pTextNd);
+            }
             pDoc->GetNodes().Delete( aOldIdx );
+            sw::CheckResetRedlineMergeFlag(*pTextNd, eOldMergeFlag == 
SwNode::Merge::NonFirst);
         }
         else
         {
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 028c3605aa50..10bde328c903 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -105,6 +105,9 @@ TextFrameIndex UpdateMergedParaForDelete(MergedPara & 
rMerged,
         bool isRealDelete,
         SwTextNode const& rNode, sal_Int32 nIndex, sal_Int32 nLen);
 
+void MoveDeletedPrevFrames(SwTextNode & rDeletedPrev, SwTextNode & rNode);
+void CheckResetRedlineMergeFlag(SwTextNode & rNode, bool bRecreateMerged);
+
 } // namespace sw
 
 /// Represents the visualization of a paragraph. Typical upper is an
@@ -726,7 +729,7 @@ public:
 
     static void repaintTextFrames( const SwTextNode& rNode );
 
-    void RegisterToNode( SwTextNode& );
+    void RegisterToNode(SwTextNode &, bool isForceNodeAsFirst = false);
 
     virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const override;
 };
diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx
index 3a37ae92bc7f..8b8e7bd22610 100644
--- a/sw/source/core/layout/ssfrm.cxx
+++ b/sw/source/core/layout/ssfrm.cxx
@@ -440,14 +440,19 @@ SwContentFrame::~SwContentFrame()
 {
 }
 
-void SwTextFrame::RegisterToNode(SwTextNode & rNode)
+void SwTextFrame::RegisterToNode(SwTextNode & rNode, bool const 
isForceNodeAsFirst)
 {
+    if (isForceNodeAsFirst && m_pMergedPara)
+    {   // nothing registered here, in particular no redlines
+        assert(m_pMergedPara->pFirstNode->GetIndex() + 1 == rNode.GetIndex());
+        assert(!m_pMergedPara->pFirstNode->HasAnyIndex());
+    }
     assert(&rNode != GetDep());
     assert(!m_pMergedPara
         || (m_pMergedPara->pFirstNode->GetIndex() < rNode.GetIndex())
         || (rNode.GetIndex() + 1 == m_pMergedPara->pFirstNode->GetIndex()));
     SwTextNode & rFirstNode(
-        (m_pMergedPara && m_pMergedPara->pFirstNode->GetIndex() < 
rNode.GetIndex())
+        (!isForceNodeAsFirst && m_pMergedPara && 
m_pMergedPara->pFirstNode->GetIndex() < rNode.GetIndex())
             ? *m_pMergedPara->pFirstNode
             : rNode);
     // sw_redlinehide: use New here, because the only caller also calls 
lcl_ChangeFootnoteRef
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index a826aabcf625..5f5869905b89 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -830,8 +830,51 @@ void SwTextNode::MoveTextAttr_To_AttrSet()
 
 }
 
-namespace {
+namespace sw {
+
+    // None,Node->None
+    // None,First->First
+    // First,NonFirst->First
+    // NonFirst,First->NonFirst
+    // NonFirst,None->NonFirst
+
 
+void MoveDeletedPrevFrames(SwTextNode & rDeletedPrev, SwTextNode & rNode)
+{
+    std::vector<SwTextFrame*> frames;
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(rDeletedPrev);
+    for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+    {
+        frames.push_back(pFrame);
+    }
+    {
+        auto frames2(frames);
+        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIt(rNode);
+        for (SwTextFrame* pFrame = aIt.First(); pFrame; pFrame = aIt.Next())
+        {
+            auto const it(std::find(frames2.begin(), frames2.end(), pFrame));
+            assert(it != frames2.end());
+            frames2.erase(it);
+        }
+        assert(frames2.empty());
+    }
+    for (SwTextFrame * pFrame : frames)
+    {
+        pFrame->RegisterToNode(rNode, true);
+#if 0
+        if (pFrame->m_pMergedPara && pFrame->m_pMergedPara->pFirstNode == 
&rDeletedPrev && GetIndex() <= pFrame->m_pMergedPara->pLastNode->GetIndex())
+        {
+            pFrame->listeners.StopListening(&rDeletedPrev);
+            pFrame->m_pMergedPara->pFirstNode = &rNode;
+            &rNode.SetRedlineMergeFlag(SwNodes::Merge::First);
+        }
+#endif
+    }
+}
+
+    /// not only fix the flag; if prev is First the frame is actually 
deleted!!!
+    // if prev is First : must not delete frame but move it
+    // if prev is NonFirst : must delete frame (if this is First/None) & merge 
into prev
 void CheckResetRedlineMergeFlag(SwTextNode & rNode, bool const bRecreateMerged)
 {
     if (bRecreateMerged)
@@ -850,6 +893,9 @@ void CheckResetRedlineMergeFlag(SwTextNode & rNode, bool 
const bRecreateMerged)
             assert(rFirstNode.GetIndex() <= rNode.GetIndex());
             pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
                         *pFrame, rFirstNode, sw::FrameMode::Existing));
+            assert(pFrame->GetMergedPara());
+            assert(pFrame->GetMergedPara()->listener.IsListeningTo(&rNode));
+            assert(rNode.GetIndex() <= 
pFrame->GetMergedPara()->pLastNode->GetIndex());
         }
     }
     else if (rNode.GetRedlineMergeFlag() != SwNode::Merge::None)
@@ -1055,6 +1101,10 @@ void SwTextNode::JoinPrev()
             pDoc->CorrAbs( aIdx, SwPosition( *this ), nLen, true );
         }
         SwNode::Merge const eOldMergeFlag(pTextNode->GetRedlineMergeFlag());
+        if (eOldMergeFlag == SwNode::Merge::First)
+        {
+            sw::MoveDeletedPrevFrames(*pTextNode, *this);
+        }
         rNds.Delete(aIdx);
         SetWrong( pList, false );
         SetGrammarCheck( pList3, false );
commit 7822345a4dae69e8aa019bacf0c73e89a9ff09d7
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Wed Aug 22 15:04:18 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    sw_redlinehide_2: DelFrames is called for hidden nodes too now
    
    Change-Id: I9933d8b8ee29bb4da74819d7d2350a5b2b04aa09

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 8d8a4072bcdd..3e6ff2d4f565 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4348,8 +4348,9 @@ static void UnHideRedlines(SwRootFrame & rLayout,
             {
                 if (rNode.IsContentNode())
                 {
-                    // note: no-op for NonFirst nodes, only Hidden will delete
-                    static_cast<SwContentNode&>(rNode).DelFrames(&rLayout);
+                    // note: nothing to do here, already done
+                    auto const 
pFrame(static_cast<SwContentNode&>(rNode).getLayoutFrame(&rLayout));
+                    assert(!pFrame || 
static_cast<SwTextFrame*>(pFrame)->GetMergedPara()->pFirstNode != &rNode);
                 }
                 else if (rNode.IsTableNode())
                 {
commit efea694ce62de1b2d4c7449ea21a8cb6d2f12d2c
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Wed Aug 22 13:26:18 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    Revert "this looks like a wrong path..."
    
    This reverts commit 391b6325117483c73f6fd0fb2286b37aaeeb46e4.

diff --git a/sw/inc/IDocumentContentOperations.hxx 
b/sw/inc/IDocumentContentOperations.hxx
index b3204109a8a0..fb4006334a15 100644
--- a/sw/inc/IDocumentContentOperations.hxx
+++ b/sw/inc/IDocumentContentOperations.hxx
@@ -22,7 +22,6 @@
 
 #include <sal/types.h>
 #include <rtl/ustring.hxx>
-#include <functional>
 #include "swtypes.hxx"
 
 class SwPaM;
@@ -38,9 +37,6 @@ class SwFrameFormat;
 class SwDrawFrameFormat;
 class SwFlyFrameFormat;
 class SwNodeIndex;
-class SwTextNode;
-
-namespace sw { namespace mark { enum class RestoreMode; } }
 
 namespace utl { class TransliterationWrapper; }
 namespace svt { class EmbeddedObjectRef; }
@@ -190,8 +186,7 @@ public:
 
     /** Split a node at rPos (implemented only for TextNode).
     */
-    virtual bool SplitNode(const SwPosition &rPos, bool bChkTableStart,
-        std::function<void ()> const* pRedlineRestore = nullptr) = 0;
+    virtual bool SplitNode(const SwPosition &rPos, bool bChkTableStart) = 0;
 
     virtual bool AppendTextNode(SwPosition& rPos) = 0;
 
diff --git a/sw/inc/IDocumentRedlineAccess.hxx 
b/sw/inc/IDocumentRedlineAccess.hxx
index d6c44b24e680..a68af07fb707 100644
--- a/sw/inc/IDocumentRedlineAccess.hxx
+++ b/sw/inc/IDocumentRedlineAccess.hxx
@@ -180,7 +180,7 @@ public:
     virtual bool DeleteRedline(
         /*[in]*/const SwPaM& rPam,
         /*[in]*/bool bSaveInUndo,
-        /*[in]*/sal_uInt16 nDelType, bool bIgnoreJoining = false) = 0;
+        /*[in]*/sal_uInt16 nDelType) = 0;
 
     virtual bool DeleteRedline(
         /*[in]*/const SwStartNode& rSection,
diff --git a/sw/inc/undobj.hxx b/sw/inc/undobj.hxx
index afb4ecee7184..2e84ff9c1d6e 100644
--- a/sw/inc/undobj.hxx
+++ b/sw/inc/undobj.hxx
@@ -119,11 +119,9 @@ public:
 
     bool IsDelBox() const;
 
-    enum class DelRange { Ignore, Delete, DeleteNonJoining };
     // Save and set Redline data.
     static bool FillSaveData( const SwPaM& rRange, SwRedlineSaveDatas& rSData,
-                              DelRange eDelRange = DelRange::Delete,
-                              bool bCopyNext = true );
+                              bool bDelRange = true, bool bCopyNext = true );
     static bool FillSaveDataForFormat( const SwPaM& , SwRedlineSaveDatas& );
     static void SetSaveData( SwDoc& rDoc, SwRedlineSaveDatas& rSData );
     static bool HasHiddenRedlines( const SwRedlineSaveDatas& rSData );
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 688318420c85..f6a2562983cd 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -2831,8 +2831,7 @@ SwDrawFrameFormat* 
DocumentContentOperationsManager::InsertDrawObj(
     return pFormat;
 }
 
-bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool 
bChkTableStart,
-        std::function<void ()> const*const pRedlineRestore)
+bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool 
bChkTableStart )
 {
     SwContentNode *pNode = rPos.nNode.GetNode().GetContentNode();
     if(nullptr == pNode)
@@ -2966,10 +2965,6 @@ bool DocumentContentOperationsManager::SplitNode( const 
SwPosition &rPos, bool b
                         m_rDoc.getIDocumentRedlineAccess().SplitRedline(aPam);
                     }
                 }
-                if (pRedlineRestore)
-                {
-                    (*pRedlineRestore)();
-                }
             }
         });
     pNode->GetTextNode()->SplitContentNode(rPos, &restoreFunc);
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index beb8728b0c9a..ad9c292810a1 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -1923,7 +1923,7 @@ bool DocumentRedlineManager::SplitRedline( const SwPaM& 
rRange )
 }
 
 bool DocumentRedlineManager::DeleteRedline( const SwPaM& rRange, bool 
bSaveInUndo,
-        sal_uInt16 const nDelType, bool const bIgnoreJoining)
+                            sal_uInt16 nDelType )
 {
     if( RedlineFlags::IgnoreDeleteRedlines & meRedlineFlags ||
         !rRange.HasMark() || *rRange.GetMark() == *rRange.GetPoint() )
@@ -1956,13 +1956,6 @@ bool DocumentRedlineManager::DeleteRedline( const SwPaM& 
rRange, bool bSaveInUnd
         SwPosition* pRStt = pRedl->Start(),
                   * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
                                                        : pRedl->GetPoint();
-        if (bIgnoreJoining && pRStt->nNode != pREnd->nNode
-            && pRStt->nNode.GetIndex() <= pStt->nNode.GetIndex()
-            && pEnd->nNode.GetIndex() <= pREnd->nNode.GetIndex())
-        {
-            continue; // ignore node-joining redline
-        }
-
         switch( ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ) )
         {
         case SwComparePosition::Equal:
diff --git a/sw/source/core/inc/DocumentContentOperationsManager.hxx 
b/sw/source/core/inc/DocumentContentOperationsManager.hxx
index 55f15ad3b79e..c60676617b78 100644
--- a/sw/source/core/inc/DocumentContentOperationsManager.hxx
+++ b/sw/source/core/inc/DocumentContentOperationsManager.hxx
@@ -78,8 +78,7 @@ public:
     SwFlyFrameFormat* InsertOLE(const SwPaM &rRg, const OUString& rObjName, 
sal_Int64 nAspect, const SfxItemSet* pFlyAttrSet,
                            const SfxItemSet* pGrfAttrSet) override;
 
-    bool SplitNode(const SwPosition &rPos, bool bChkTableStart,
-        std::function<void ()> const* pRedlineRestore = nullptr) override;
+    bool SplitNode(const SwPosition &rPos, bool bChkTableStart) override;
 
     bool AppendTextNode(SwPosition& rPos) override;
 
diff --git a/sw/source/core/inc/DocumentRedlineManager.hxx 
b/sw/source/core/inc/DocumentRedlineManager.hxx
index d9cdf7ca3e59..f534cccea3fd 100644
--- a/sw/source/core/inc/DocumentRedlineManager.hxx
+++ b/sw/source/core/inc/DocumentRedlineManager.hxx
@@ -61,7 +61,7 @@ public:
     virtual bool DeleteRedline(
         /*[in]*/const SwPaM& rPam,
         /*[in]*/bool bSaveInUndo,
-        /*[in]*/sal_uInt16 nDelType, bool bIgnoreJoining = false) override;
+        /*[in]*/sal_uInt16 nDelType) override;
 
     virtual bool DeleteRedline(
         /*[in]*/const SwStartNode& rSection,
diff --git a/sw/source/core/inc/UndoDelete.hxx 
b/sw/source/core/inc/UndoDelete.hxx
index 699bc09c21b1..f22832b18d54 100644
--- a/sw/source/core/inc/UndoDelete.hxx
+++ b/sw/source/core/inc/UndoDelete.hxx
@@ -40,7 +40,6 @@ class SwUndoDelete
     std::unique_ptr<SwNodeIndex> m_pMvStt;            // Position of Nodes in 
UndoNodes-Array
     boost::optional<OUString> m_aSttStr, m_aEndStr;
     std::unique_ptr<SwRedlineSaveDatas> m_pRedlSaveData;
-    std::unique_ptr<SwRedlineSaveDatas> m_pRedlSaveDataAtEnd;
     std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart;
     std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd;
 
diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index 0b7e93979016..7e942b427ecb 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -32,8 +32,6 @@
 #include <swundo.hxx>
 #include <pam.hxx>
 #include <ndtxt.hxx>
-#include <txtfrm.hxx>
-#include <rootfrm.hxx>
 #include <UndoCore.hxx>
 #include <rolbck.hxx>
 #include <poolfmt.hxx>
@@ -121,15 +119,11 @@ SwUndoDelete::SwUndoDelete(
     bCacheComment = false;
 
     SwDoc * pDoc = rPam.GetDoc();
-    bool bMustDelete(false);
 
     if( !pDoc->getIDocumentRedlineAccess().IsIgnoreRedline() && 
!pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty() )
     {
         m_pRedlSaveData.reset(new SwRedlineSaveDatas);
-//        if (!FillSaveData(rPam, *m_pRedlSaveData, false /*true in 2nd 
call*/))
-        bMustDelete = rPam.GetPoint()->nNode != rPam.GetMark()->nNode;
-//        if (!FillSaveData(rPam, *m_pRedlSaveData, rPam.GetPoint()->nNode == 
rPam.GetMark()->nNode))
-        if (!FillSaveData(rPam, *m_pRedlSaveData, 
SwUndo::DelRange::DeleteNonJoining))
+        if( !FillSaveData( rPam, *m_pRedlSaveData ))
         {
             m_pRedlSaveData.reset();
         }
@@ -216,7 +210,7 @@ SwUndoDelete::SwUndoDelete(
 
     if( !pSttTextNd && !pEndTextNd )
         --rPam.GetPoint()->nNode;
-//    rPam.DeleteMark();          // the SPoint is in the selection
+    rPam.DeleteMark();          // the SPoint is in the selection
 
     if( !pEndTextNd )
         nEndContent = 0;
@@ -360,22 +354,6 @@ SwUndoDelete::SwUndoDelete(
     // is a history necessary here at all?
     if( pHistory && !pHistory->Count() )
         pHistory.reset();
-
-    assert(pDoc->getIDocumentRedlineAccess().IsIgnoreRedline()
-        || pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty()
-        || (pStt->nNode != pEnd->nNode) == bMustDelete);
-    if (pStt->nNode != pEnd->nNode
-        && !pDoc->getIDocumentRedlineAccess().IsIgnoreRedline()
-        && !pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty())
-    {   // horrible duplication that SplitNode can undo
-        m_pRedlSaveDataAtEnd.reset(new SwRedlineSaveDatas);
-        if (!FillSaveData(rPam, *m_pRedlSaveDataAtEnd))
-        {
-            m_pRedlSaveDataAtEnd.reset();
-        }
-    }
-
-    rPam.DeleteMark(); // now it is no longer a range...
 }
 
 bool SwUndoDelete::SaveContent( const SwPosition* pStt, const SwPosition* pEnd,
@@ -506,7 +484,7 @@ bool SwUndoDelete::CanGrouping( SwDoc* pDoc, const SwPaM& 
rDelPam )
 
     {
         SwRedlineSaveDatas aTmpSav;
-        const bool bSaved = FillSaveData(rDelPam, aTmpSav, 
SwUndo::DelRange::Ignore);
+        const bool bSaved = FillSaveData( rDelPam, aTmpSav, false );
 
         bool bOk = ( !m_pRedlSaveData && !bSaved ) ||
                    ( m_pRedlSaveData && bSaved &&
@@ -810,7 +788,6 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
             pInsNd = nullptr;         // do not delete Node!
 
         bool bNodeMove = 0 != m_nNode;
-        bool bRedlAtEndRestored(false);
 
         if( m_aEndStr )
         {
@@ -826,17 +803,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
             if( m_aSttStr && !m_bFromTableCopy )
             {
                 sal_uLong nOldIdx = aPos.nNode.GetIndex();
-                // call this before messing with frames in SplitNode
-                std::function<void ()> restoreFunc(
-                    [&]()
-                    {
-                        if (m_pRedlSaveDataAtEnd)
-                        {
-                            SetSaveData(rDoc, *m_pRedlSaveDataAtEnd);
-                        }
-                    });
-                rDoc.getIDocumentContentOperations().SplitNode(aPos, false, 
&restoreFunc);
-                bRedlAtEndRestored = true;
+                rDoc.getIDocumentContentOperations().SplitNode( aPos, false );
                 // After the split all objects are anchored at the first
                 // paragraph, but the pHistory of the fly frame formats relies
                 // on anchoring at the start of the selection
@@ -845,11 +812,6 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
                     lcl_ReAnchorAtContentFlyFrames(*rDoc.GetSpzFrameFormats(), 
aPos, nOldIdx);
                 pTextNd = aPos.nNode.GetNode().GetTextNode();
             }
-            else if (m_pRedlSaveDataAtEnd)
-            {
-                SetSaveData(rDoc, *m_pRedlSaveDataAtEnd);
-                bRedlAtEndRestored = true;
-            }
             if( pTextNd )
             {
                 OUString const ins( pTextNd->InsertText(*m_aEndStr, 
aPos.nContent,
@@ -868,30 +830,14 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
                 if (nSttContent < pNd->GetText().getLength())
                 {
                     sal_uLong nOldIdx = aPos.nNode.GetIndex();
-                    // call this before messing with frames in SplitNode
-                    std::function<void ()> restoreFunc(
-                        [&]()
-                        {
-                            if (m_pRedlSaveDataAtEnd)
-                            {
-                                SetSaveData(rDoc, *m_pRedlSaveDataAtEnd);
-                            }
-                        });
-                    rDoc.getIDocumentContentOperations().SplitNode(aPos, 
false, &restoreFunc);
-                    bRedlAtEndRestored = true;
+                    rDoc.getIDocumentContentOperations().SplitNode( aPos, 
false );
                     if( m_bBackSp )
                         
lcl_ReAnchorAtContentFlyFrames(*rDoc.GetSpzFrameFormats(), aPos, nOldIdx);
                 }
                 else
-                {
                     ++aPos.nNode;
-                }
             }
         }
-        if (!bRedlAtEndRestored && m_pRedlSaveDataAtEnd)
-        {
-            SetSaveData(rDoc, *m_pRedlSaveDataAtEnd);
-        }
         SwNode* pMovedNode = nullptr;
         if( m_nSectDiff )
         {
@@ -920,23 +866,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
         {
             SwNodeRange aRange( *m_pMvStt, 0, *m_pMvStt, m_nNode );
             SwNodeIndex aCopyIndex( aPos.nNode, -1 );
-            rDoc.GetUndoManager().GetUndoNodes().Copy_(aRange, aPos.nNode,
-                    // SplitNode would have inited this flag; at this point,
-                    // either all these nodes are Hidden or all are None
-                    // (it might be that in the None case, the 2nd SetSaveData
-                    //  below will introduce new redlines...)
-                    false);
-#if 0
-                    aPos.nNode.GetRedlineMergeFlag() == SwNode::Merge::None);
-#endif
-            if (aPos.nNode.GetNode().GetRedlineMergeFlag() != 
SwNode::Merge::None)
-            {
-                for (sal_uLong i = aCopyIndex.GetIndex() + m_nNode; 
aCopyIndex.GetIndex() < i; --i)
-                {
-                    
rDoc.GetNodes()[i]->SetRedlineMergeFlag(SwNode::Merge::Hidden);
-                }
-            }
-            // TODO after the SetSaveData we need to check again ???
+            rDoc.GetUndoManager().GetUndoNodes().Copy_( aRange, aPos.nNode );
 
             if( m_nReplaceDummy )
             {
@@ -1026,62 +956,8 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & 
rContext)
     if( pInsNd )
         rDoc.GetNodes().Delete( aIdx );
     if( m_pRedlSaveData )
-    {
         SetSaveData(rDoc, *m_pRedlSaveData);
 
-#if 0
-        if (m_aSttStr && (!m_bFromTableCopy || 0 != m_nNode))
-        {
-            // only now do we have redlines in the document again; fix up the 
frame
-            SwTextNode *const 
pStartNode(aIdx.GetNodes()[nSttNode]->GetTextNode());
-            SwTextNode *const 
pEndNode(aIdx.GetNodes()[nEndNode]->GetTextNode());
-            // FIXME we need to fetch frame of end node????
-            // the MakeCopy already creates frames of intermediate nodes 
depending on their flag... problem: deletion was with redlines shown, restore 
with hidden
-            assert(pNode);
-            std::vector<SwTextFrame*> frames;
-            SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> 
aIter(*pEndNode);
-            for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = 
aIter.Next())
-            {
-                if (pFrame->getRootFrame()->IsHideRedlines())
-                {
-                    frames.push_back(pFrame);
-                }
-            }
-            for (SwTextFrame * pFrame : frames)
-            {
-// this is not going to work if there are intermediate nodes with frames       
         pFrame->RegisterToNode(*pStartNode);
-#if 0
-                SwTextNode & rFirstNode(pFrame->GetMergedPara()
-                    ? *pFrame->GetMergedPara()->pFirstNode
-                    : *pStartNode);
-                assert(rFirstNode.GetIndex() <= pNode->GetIndex());
-                pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
-                            *pFrame, rFirstNode, sw::FrameMode::Existing));
-#endif
-            }
-        }
-#endif
-    }
-
-    // create frames after SetSaveData has recreated redlines
-    if (0 != m_nNode)
-    {
-        SwNodeIndex const start(rDoc.GetNodes(), nSttNode + 1);
-        SwNodeIndex const end(rDoc.GetNodes(), nEndNode);
-        ::MakeFrames(&rDoc, start, end);
-    }
-
-    // ... plan: let SplitNode do whatever;
-    // don't create frames on moved nodes;
-    // after SetSaveData, call CheckRedline... on start node,
-    // then MakeFrames
-    // ... what about end node ? will be either properly merged or properly 
un-merged after handling start node, so just include it in MakeFrames range.
-    //
-    // The interesting case is
-    //  f<delete start>o<redline start>o
-    //  b<redline end>a<redline start>r
-    //  b<redline end>a<delete end>z
-
     AddUndoRedoPaM(rContext, true);
 }
 
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index 94299badd501..5afbde167ad2 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -1378,7 +1378,7 @@ void SwRedlineSaveData::RedlineToDoc( SwPaM const & rPam )
 bool SwUndo::FillSaveData(
     const SwPaM& rRange,
     SwRedlineSaveDatas& rSData,
-    DelRange const eDelRange,
+    bool bDelRange,
     bool bCopyNext )
 {
     rSData.clear();
@@ -1403,10 +1403,9 @@ bool SwUndo::FillSaveData(
             rSData.push_back(std::unique_ptr<SwRedlineSaveData, 
o3tl::default_delete<SwRedlineSaveData>>(new SwRedlineSaveData(eCmpPos, *pStt, 
*pEnd, *pRedl, bCopyNext)));
         }
     }
-    if (!rSData.empty() && eDelRange != DelRange::Ignore)
+    if( !rSData.empty() && bDelRange )
     {
-        rRange.GetDoc()->getIDocumentRedlineAccess().DeleteRedline(
-            rRange, false, USHRT_MAX, eDelRange == DelRange::DeleteNonJoining);
+        rRange.GetDoc()->getIDocumentRedlineAccess().DeleteRedline( rRange, 
false, USHRT_MAX );
     }
     return !rSData.empty();
 }
diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx
index 6e6a64fbd52a..e2fb76a19f63 100644
--- a/sw/source/core/undo/unovwr.cxx
+++ b/sw/source/core/undo/unovwr.cxx
@@ -48,7 +48,7 @@ SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& 
rPos,
         SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
                     rPos.nNode, rPos.nContent.GetIndex()+1 );
         pRedlSaveData.reset( new SwRedlineSaveDatas );
-        if (!FillSaveData( aPam, *pRedlSaveData, SwUndo::DelRange::Ignore))
+        if( !FillSaveData( aPam, *pRedlSaveData, false ))
         {
             pRedlSaveData.reset();
         }
@@ -125,7 +125,7 @@ bool SwUndoOverwrite::CanGrouping( SwDoc* pDoc, SwPosition& 
rPos,
         SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
                     rPos.nNode, rPos.nContent.GetIndex()+1 );
 
-        const bool bSaved = FillSaveData(aPam, aTmpSav, 
SwUndo::DelRange::Ignore);
+        const bool bSaved = FillSaveData( aPam, aTmpSav, false );
 
         bool bOk = ( !pRedlSaveData && !bSaved ) ||
                    ( pRedlSaveData && bSaved &&
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index 9bdad5c20299..58d2de808363 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -58,8 +58,7 @@ SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& 
rRange )
     sal_uLong nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex();
 
     mpRedlSaveData.reset( new SwRedlineSaveDatas );
-    if (!FillSaveData(rRange, *mpRedlSaveData, SwUndo::DelRange::Ignore,
-                      SwUndoId::REJECT_REDLINE != mnUserId))
+    if( !FillSaveData( rRange, *mpRedlSaveData, false, 
SwUndoId::REJECT_REDLINE != mnUserId ))
     {
         mpRedlSaveData.reset();
     }
@@ -119,8 +118,7 @@ void SwUndoRedline::RedoImpl(::sw::UndoRedoContext & 
rContext)
     if( mpRedlSaveData && mbHiddenRedlines )
     {
         sal_uLong nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex();
-        FillSaveData(rPam, *mpRedlSaveData, SwUndo::DelRange::Ignore,
-                SwUndoId::REJECT_REDLINE != mnUserId);
+        FillSaveData(rPam, *mpRedlSaveData, false, SwUndoId::REJECT_REDLINE != 
mnUserId );
 
         nEndExtra -= rDoc.GetNodes().GetEndOfExtras().GetIndex();
         nSttNode -= nEndExtra;
@@ -399,7 +397,7 @@ SwUndoCompDoc::SwUndoCompDoc( const SwRangeRedline& rRedl )
     }
 
     pRedlSaveData.reset( new SwRedlineSaveDatas );
-    if (!FillSaveData( rRedl, *pRedlSaveData, SwUndo::DelRange::Ignore))
+    if( !FillSaveData( rRedl, *pRedlSaveData, false ))
     {
         pRedlSaveData.reset();
     }
diff --git a/sw/source/core/undo/unsect.cxx b/sw/source/core/undo/unsect.cxx
index b225ae42235e..f17cae630316 100644
--- a/sw/source/core/undo/unsect.cxx
+++ b/sw/source/core/undo/unsect.cxx
@@ -88,7 +88,7 @@ SwUndoInsSection::SwUndoInsSection(
         SetRedlineFlags( rDoc.getIDocumentRedlineAccess().GetRedlineFlags() );
     }
         m_pRedlineSaveData.reset( new SwRedlineSaveDatas );
-        if (!FillSaveData( rPam, *m_pRedlineSaveData, 
SwUndo::DelRange::Ignore))
+        if( !FillSaveData( rPam, *m_pRedlineSaveData, false ))
             m_pRedlineSaveData.reset( nullptr );
 
     if( !rPam.HasMark() )
commit ecb94c409fb24003c79128fc063306e4b045872c
Author:     Michael Stahl <michael.st...@cib.de>
AuthorDate: Wed Aug 22 13:22:29 2018 +0200
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Thu Sep 6 13:13:24 2018 +0200

    this looks like a wrong path...
    
    Change-Id: I81181ecb8fa3bae47e9dc0d2a5b49b92608629e6

diff --git a/sw/inc/IDocumentContentOperations.hxx 
b/sw/inc/IDocumentContentOperations.hxx
index fb4006334a15..b3204109a8a0 100644
--- a/sw/inc/IDocumentContentOperations.hxx
+++ b/sw/inc/IDocumentContentOperations.hxx
@@ -22,6 +22,7 @@
 
 #include <sal/types.h>
 #include <rtl/ustring.hxx>
+#include <functional>
 #include "swtypes.hxx"
 
 class SwPaM;
@@ -37,6 +38,9 @@ class SwFrameFormat;
 class SwDrawFrameFormat;
 class SwFlyFrameFormat;
 class SwNodeIndex;
+class SwTextNode;
+
+namespace sw { namespace mark { enum class RestoreMode; } }
 
 namespace utl { class TransliterationWrapper; }
 namespace svt { class EmbeddedObjectRef; }
@@ -186,7 +190,8 @@ public:
 
     /** Split a node at rPos (implemented only for TextNode).
     */
-    virtual bool SplitNode(const SwPosition &rPos, bool bChkTableStart) = 0;
+    virtual bool SplitNode(const SwPosition &rPos, bool bChkTableStart,
+        std::function<void ()> const* pRedlineRestore = nullptr) = 0;
 
     virtual bool AppendTextNode(SwPosition& rPos) = 0;
 
diff --git a/sw/inc/IDocumentRedlineAccess.hxx 
b/sw/inc/IDocumentRedlineAccess.hxx
index a68af07fb707..d6c44b24e680 100644
--- a/sw/inc/IDocumentRedlineAccess.hxx
+++ b/sw/inc/IDocumentRedlineAccess.hxx
@@ -180,7 +180,7 @@ public:
     virtual bool DeleteRedline(
         /*[in]*/const SwPaM& rPam,
         /*[in]*/bool bSaveInUndo,
-        /*[in]*/sal_uInt16 nDelType) = 0;
+        /*[in]*/sal_uInt16 nDelType, bool bIgnoreJoining = false) = 0;
 
     virtual bool DeleteRedline(
         /*[in]*/const SwStartNode& rSection,
diff --git a/sw/inc/undobj.hxx b/sw/inc/undobj.hxx
index 2e84ff9c1d6e..afb4ecee7184 100644
--- a/sw/inc/undobj.hxx
+++ b/sw/inc/undobj.hxx
@@ -119,9 +119,11 @@ public:
 
     bool IsDelBox() const;
 
+    enum class DelRange { Ignore, Delete, DeleteNonJoining };
     // Save and set Redline data.
     static bool FillSaveData( const SwPaM& rRange, SwRedlineSaveDatas& rSData,

... etc. - the rest is truncated
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to