[Libreoffice-commits] core.git: Branch 'private/mst/sw_redlinehide_2' - 68 commits - svl/source sw/inc sw/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Mon Sep 3 17:05:02 UTC 2018


Rebased ref, commits from common ancestor:
commit 455271c854ae3a6d578a576d05f7692d7a462e23
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Sep 3 18:07:29 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 19:03:00 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..db1dcabb5d80 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,69 @@ 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());
+        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());
+                pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
+                    *pFrame, *pMergedPara->pFirstNode, 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 +358,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 +374,6 @@ namespace
         {
         case nsRedlineType_t::REDLINE_INSERT:
             {
-                SwDoc& rDoc = *pRedl->GetDoc();
                 const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
                 bool bDelRedl = false;
                 switch( eCmp )
@@ -390,6 +454,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 +539,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 efcf3444cd8702a4462ee0f84ade8a7b10af82d4
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Sep 3 15:12:29 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 19:03:00 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 1aa10125d634f2a48b11ea8f6a56b930fa9e6e22
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Sep 3 12:18:25 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 19:03:00 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..464f4609f81d 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,26 @@ 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
+        {
+            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 520bf6f6c2bf..5474b1a479ad 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -2496,6 +2496,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 f0047bdfe9044f704f2b2544fb05fe7b413709ac
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Aug 31 19:14:58 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 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 fdded7af680fc452ba5753075f77b886026bca5e
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 17:09:02 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 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 4665af6e63235d6a46078da72cbb8468de7cfde5
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 15:09:59 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 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 286ae4dafec6..520bf6f6c2bf 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -823,8 +823,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)
@@ -843,6 +886,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)
@@ -1048,6 +1094,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 053a643b99cd26fd880babb47a212a05d7e3f4aa
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 15:04:18 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 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 65a65a62d4c5fd343f17a25f9f29218c8149bc66
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 15:03:42 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 2018 +0200

    sw_redlinehide_2: another assert (merge this?)
    
    Change-Id: Ica141176e0accd07f9b4246a71df5e660119078e

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index bcea7f789905..8d8a4072bcdd 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4172,6 +4172,7 @@ static void UnHideRedlines(SwRootFrame & rLayout,
         std::set<sal_uLong> *const pSkipped)
 {
     assert(rEndOfSectionNode.IsEndNode());
+    assert(rNodes[rEndOfSectionNode.StartOfSectionNode()->GetIndex() + 1]->IsCreateFrameWhenHidingRedlines()); // first node is never hidden
     for (sal_uLong i = rEndOfSectionNode.StartOfSectionNode()->GetIndex() + 1;
          i < rEndOfSectionNode.GetIndex(); ++i)
     {
commit 9b2d1d115d530938a02e47800280be0984371579
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 13:26:18 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 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 e57a7ba9dd0e2af02e83244b5ba32ee8abd1dcca
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 13:22:29 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 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,
-                              bool bDelRange = true, bool bCopyNext = true );
+                              DelRange eDelRange = DelRange::Delete,
+                              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 f6a2562983cd..688318420c85 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -2831,7 +2831,8 @@ SwDrawFrameFormat* DocumentContentOperationsManager::InsertDrawObj(
     return pFormat;
 }
 
-bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool bChkTableStart )
+bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool bChkTableStart,
+        std::function<void ()> const*const pRedlineRestore)
 {
     SwContentNode *pNode = rPos.nNode.GetNode().GetContentNode();
     if(nullptr == pNode)
@@ -2965,6 +2966,10 @@ 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 ad9c292810a1..beb8728b0c9a 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 nDelType )
+        sal_uInt16 const nDelType, bool const bIgnoreJoining)
 {
     if( RedlineFlags::IgnoreDeleteRedlines & meRedlineFlags ||
         !rRange.HasMark() || *rRange.GetMark() == *rRange.GetPoint() )
@@ -1956,6 +1956,13 @@ 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 c60676617b78..55f15ad3b79e 100644
--- a/sw/source/core/inc/DocumentContentOperationsManager.hxx
+++ b/sw/source/core/inc/DocumentContentOperationsManager.hxx
@@ -78,7 +78,8 @@ 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) override;
+    bool SplitNode(const SwPosition &rPos, bool bChkTableStart,
+        std::function<void ()> const* pRedlineRestore = nullptr) override;
 
     bool AppendTextNode(SwPosition& rPos) override;
 
diff --git a/sw/source/core/inc/DocumentRedlineManager.hxx b/sw/source/core/inc/DocumentRedlineManager.hxx
index f534cccea3fd..d9cdf7ca3e59 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) override;
+        /*[in]*/sal_uInt16 nDelType, bool bIgnoreJoining = false) 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 f22832b18d54..699bc09c21b1 100644
--- a/sw/source/core/inc/UndoDelete.hxx
+++ b/sw/source/core/inc/UndoDelete.hxx
@@ -40,6 +40,7 @@ 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 7e942b427ecb..0b7e93979016 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -32,6 +32,8 @@
 #include <swundo.hxx>
 #include <pam.hxx>
 #include <ndtxt.hxx>
+#include <txtfrm.hxx>
+#include <rootfrm.hxx>
 #include <UndoCore.hxx>
 #include <rolbck.hxx>
 #include <poolfmt.hxx>
@@ -119,11 +121,15 @@ 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 ))
+//        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))
         {
             m_pRedlSaveData.reset();
         }
@@ -210,7 +216,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;
@@ -354,6 +360,22 @@ 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,
@@ -484,7 +506,7 @@ bool SwUndoDelete::CanGrouping( SwDoc* pDoc, const SwPaM& rDelPam )
 
     {
         SwRedlineSaveDatas aTmpSav;
-        const bool bSaved = FillSaveData( rDelPam, aTmpSav, false );
+        const bool bSaved = FillSaveData(rDelPam, aTmpSav, SwUndo::DelRange::Ignore);
 
         bool bOk = ( !m_pRedlSaveData && !bSaved ) ||
                    ( m_pRedlSaveData && bSaved &&
@@ -788,6 +810,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
             pInsNd = nullptr;         // do not delete Node!
 
         bool bNodeMove = 0 != m_nNode;
+        bool bRedlAtEndRestored(false);
 
         if( m_aEndStr )
         {
@@ -803,7 +826,17 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
             if( m_aSttStr && !m_bFromTableCopy )
             {
                 sal_uLong nOldIdx = aPos.nNode.GetIndex();
-                rDoc.getIDocumentContentOperations().SplitNode( aPos, false );
+                // 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;
                 // 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
@@ -812,6 +845,11 @@ 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,
@@ -830,14 +868,30 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
                 if (nSttContent < pNd->GetText().getLength())
                 {
                     sal_uLong nOldIdx = aPos.nNode.GetIndex();
-                    rDoc.getIDocumentContentOperations().SplitNode( aPos, false );
+                    // 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;
                     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 )
         {
@@ -866,7 +920,23 @@ 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,
+                    // 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 ???
 
             if( m_nReplaceDummy )
             {
@@ -956,8 +1026,62 @@ 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 5afbde167ad2..94299badd501 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,
-    bool bDelRange,
+    DelRange const eDelRange,
     bool bCopyNext )
 {
     rSData.clear();
@@ -1403,9 +1403,10 @@ bool SwUndo::FillSaveData(
             rSData.push_back(std::unique_ptr<SwRedlineSaveData, o3tl::default_delete<SwRedlineSaveData>>(new SwRedlineSaveData(eCmpPos, *pStt, *pEnd, *pRedl, bCopyNext)));
         }
     }
-    if( !rSData.empty() && bDelRange )
+    if (!rSData.empty() && eDelRange != DelRange::Ignore)
     {
-        rRange.GetDoc()->getIDocumentRedlineAccess().DeleteRedline( rRange, false, USHRT_MAX );
+        rRange.GetDoc()->getIDocumentRedlineAccess().DeleteRedline(
+            rRange, false, USHRT_MAX, eDelRange == DelRange::DeleteNonJoining);
     }
     return !rSData.empty();
 }
diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx
index e2fb76a19f63..6e6a64fbd52a 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, false ))
+        if (!FillSaveData( aPam, *pRedlSaveData, SwUndo::DelRange::Ignore))
         {
             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, false );
+        const bool bSaved = FillSaveData(aPam, aTmpSav, SwUndo::DelRange::Ignore);
 
         bool bOk = ( !pRedlSaveData && !bSaved ) ||
                    ( pRedlSaveData && bSaved &&
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index 58d2de808363..9bdad5c20299 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -58,7 +58,8 @@ SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange )
     sal_uLong nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex();
 
     mpRedlSaveData.reset( new SwRedlineSaveDatas );
-    if( !FillSaveData( rRange, *mpRedlSaveData, false, SwUndoId::REJECT_REDLINE != mnUserId ))
+    if (!FillSaveData(rRange, *mpRedlSaveData, SwUndo::DelRange::Ignore,
+                      SwUndoId::REJECT_REDLINE != mnUserId))
     {
         mpRedlSaveData.reset();
     }
@@ -118,7 +119,8 @@ void SwUndoRedline::RedoImpl(::sw::UndoRedoContext & rContext)
     if( mpRedlSaveData && mbHiddenRedlines )
     {
         sal_uLong nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex();
-        FillSaveData(rPam, *mpRedlSaveData, false, SwUndoId::REJECT_REDLINE != mnUserId );
+        FillSaveData(rPam, *mpRedlSaveData, SwUndo::DelRange::Ignore,
+                SwUndoId::REJECT_REDLINE != mnUserId);
 
         nEndExtra -= rDoc.GetNodes().GetEndOfExtras().GetIndex();
         nSttNode -= nEndExtra;
@@ -397,7 +399,7 @@ SwUndoCompDoc::SwUndoCompDoc( const SwRangeRedline& rRedl )
     }
 
     pRedlSaveData.reset( new SwRedlineSaveDatas );
-    if( !FillSaveData( rRedl, *pRedlSaveData, false ))
+    if (!FillSaveData( rRedl, *pRedlSaveData, SwUndo::DelRange::Ignore))
     {
         pRedlSaveData.reset();
     }
diff --git a/sw/source/core/undo/unsect.cxx b/sw/source/core/undo/unsect.cxx
index f17cae630316..b225ae42235e 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, false ))
+        if (!FillSaveData( rPam, *m_pRedlineSaveData, SwUndo::DelRange::Ignore))
             m_pRedlineSaveData.reset( nullptr );
 
     if( !rPam.HasMark() )
commit 12109afd58a59192469f4372ef152a852f576737
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 12:56:33 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 2018 +0200

    sw_redlinehide_2: SwContentNode::DelFrames()
    
    ... needs to remove extents when it's called when moving nodes to
    Undo-nodes-array.
    
    Change-Id: I32cf38074d9f3d614d5f854979be6b0135d53914

diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx
index 9175a1b076be..1cfdb934672d 100644
--- a/sw/source/core/docnode/node.cxx
+++ b/sw/source/core/docnode/node.cxx
@@ -1320,7 +1320,7 @@ void SwContentNode::MakeFramesForAdjacentContentNode(SwContentNode& rNode)
  * Deletes all Views from the Doc for this Node.
  * The ContentFrames are removed from the corresponding Layout.
  */
-void SwContentNode::DelFrames(SwRootFrame const*const pLayout, bool const fromDtor)
+void SwContentNode::DelFrames(SwRootFrame const*const pLayout, bool const)
 {
     if( !HasWriterListeners() )
         return;
@@ -1339,24 +1339,27 @@ void SwContentNode::DelFrames(SwRootFrame const*const pLayout, bool const fromDt
             {
                 if (this != pMerged->pFirstNode)
                 {
-                    if (fromDtor)
+                    // pointer should have been updated to a different node
+                    assert(this != pMerged->pParaPropsNode);
+                    // SwNodes::RemoveNode iterates *backwards* - so
+                    // ensure there are no more extents pointing to this
+                    // node as SwFrame::InvalidatePage() will access them.
+                    // Note: cannot send via SwClientNotify from dtor
+                    // because that would access deleted wrong-lists
+                    sw::UpdateMergedParaForDelete(*pMerged, true,
+                            *static_cast<SwTextNode*>(this), 0, Len());
+                    if (this == pMerged->pLastNode)
                     {
-                        // pointer should have been updated to a different node
-                        assert(this != pMerged->pParaPropsNode);
-                        // manual update required i'm afraid...
-                        if (this == pMerged->pLastNode)
-                        {
-                            pMerged->pLastNode = GetNodes()[GetIndex()-1]->GetTextNode();
-                            // at first glance nothing guarantees this...
-                            // but the redline must end on a text-node...
-                            // so everything before this node that isn't a text
-                            // node should have been deleted already so that
-                            // there's a text node before.
-                            assert(pMerged->pLastNode->IsTextNode());
-                        }
-                        // avoid re-parenting mess (ModifyChangedHint)
-                        pMerged->listener.EndListening(this);
+                        pMerged->pLastNode = GetNodes()[GetIndex()-1]->GetTextNode();
+                        // at first glance nothing guarantees this...
+                        // but the redline must end on a text-node...
+                        // so everything before this node that isn't a text
+                        // node should have been deleted already so that
+                        // there's a text node before.
+                        assert(pMerged->pLastNode->IsTextNode());
                     }
+                    // avoid re-parenting mess (ModifyChangedHint)
+                    pMerged->listener.EndListening(this);
                     continue; // don't delete
                 }
             }
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index def5fcff7ce9..028c3605aa50 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -101,6 +101,10 @@ std::unique_ptr<sw::MergedPara> CheckParaRedlineMerge(SwTextFrame & rFrame, SwTe
 
 bool FrameContainsNode(SwContentFrame const& rFrame, sal_uLong nNodeIndex);
 
+TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged,
+        bool isRealDelete,
+        SwTextNode const& rNode, sal_Int32 nIndex, sal_Int32 nLen);
+
 } // namespace sw
 
 /// Represents the visualization of a paragraph. Typical upper is an
commit 41884009b0a2eb511449b9b7623f594f8b77bd2e
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 12:52:13 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 2018 +0200

    sw_redlinehide_2: assert calls with wrong start node
    
    Change-Id: I132ea43397b8990c5759db66f62749df8aaa45d5

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 975a412e98de..f63aed9f9e1b 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -78,6 +78,7 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
         SwPosition const*const pEnd(pRed->End());
         assert(*pStart != *pEnd); // empty delete allowed if shown ???
         bHaveRedlines = true;
+        assert(pNode != &rTextNode || &pStart->nNode.GetNode() == &rTextNode); // detect calls with wrong start node
         if (pStart->nContent != nLastEnd) // not 0 so we eliminate adjacent deletes
         {
             extents.emplace_back(pNode, nLastEnd, pStart->nContent.GetIndex());
commit 1d2d7f32c8ec60a1631f9a546321cd13a8cda3ab
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 22 12:39:54 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 2018 +0200

    sw: add a real create-no-frames flag to MakeCopy/MakeTextNode
    
    SwNodes::CopyNodes calling MakeCopy() and then immediately DelFrames()
    considered silly.
    
    Apparently SwOLENode/SwGrfNode don't actually create frames anyway since
    that is done via their SwFrameFormats, so they just ignore the parameter.
    
    Change-Id: I8a8f52da1d25bb5689345e956a33aebd727e8fc7

diff --git a/sw/inc/ndarr.hxx b/sw/inc/ndarr.hxx
index e9a3a7f11788..598397c43cf6 100644
--- a/sw/inc/ndarr.hxx
+++ b/sw/inc/ndarr.hxx
@@ -204,7 +204,8 @@ public:
 
     /// Implementations of "Make...Node" are in the given .cxx-files.
     SwTextNode *MakeTextNode( const SwNodeIndex & rWhere,
-                            SwTextFormatColl *pColl ); ///< in ndtxt.cxx
+                            SwTextFormatColl *pColl,
+                            bool bNewFrames = true); ///< in ndtxt.cxx
     SwStartNode* MakeTextSection( const SwNodeIndex & rWhere,
                             SwStartNodeType eSttNdTyp,
                             SwTextFormatColl *pColl );
diff --git a/sw/inc/ndgrf.hxx b/sw/inc/ndgrf.hxx
index 0a6c67a65481..998c414a879f 100644
--- a/sw/inc/ndgrf.hxx
+++ b/sw/inc/ndgrf.hxx
@@ -109,7 +109,7 @@ public:
     void SetScaleImageMap( bool b )      { bScaleImageMap = b; }
 
     /// in ndcopy.cxx
-    virtual SwContentNode* MakeCopy( SwDoc*, const SwNodeIndex& ) const override;
+    virtual SwContentNode* MakeCopy(SwDoc*, const SwNodeIndex&, bool bNewFrames) const override;
 
     /** Re-read in case graphic was not OK. The current one
        gets replaced by the new one. */
diff --git a/sw/inc/ndole.hxx b/sw/inc/ndole.hxx
index 93139c986526..21896f6f99c0 100644
--- a/sw/inc/ndole.hxx
+++ b/sw/inc/ndole.hxx
@@ -112,7 +112,7 @@ public:
     virtual ~SwOLENode() override;
 
     /// Is in ndcopy.cxx.
-    virtual SwContentNode* MakeCopy( SwDoc*, const SwNodeIndex& ) const override;
+    virtual SwContentNode* MakeCopy(SwDoc*, const SwNodeIndex&, bool bNewFrames) const override;
 
     virtual Size GetTwipSize() const override;
 
diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index bfb9d0b3fe4a..2a5e48145cd8 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -669,7 +669,7 @@ public:
 
     /// in ndcopy.cxx
     bool IsSymbolAt(sal_Int32 nBegin) const; // In itratr.cxx.
-    virtual SwContentNode* MakeCopy( SwDoc*, const SwNodeIndex& ) const override;
+    virtual SwContentNode* MakeCopy(SwDoc*, const SwNodeIndex&, bool bNewFrames) const override;
 
     /// Interactive hyphenation: we find TextFrame and call its CalcHyph.
     bool Hyphenate( SwInterHyphInfo &rHyphInf );
diff --git a/sw/inc/node.hxx b/sw/inc/node.hxx
index 60149f2fc24a..05b69c9acb21 100644
--- a/sw/inc/node.hxx
+++ b/sw/inc/node.hxx
@@ -418,7 +418,7 @@ public:
        There are differences between text node and formula node. */
     virtual sal_Int32 Len() const;
 
-    virtual SwContentNode* MakeCopy( SwDoc*, const SwNodeIndex& ) const = 0;
+    virtual SwContentNode* MakeCopy(SwDoc*, const SwNodeIndex&, bool bNewFrames) const = 0;
 
     /// Get information from Client.
     virtual bool GetInfo( SfxPoolItem& ) const override;
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 58a4fe796c54..f6a2562983cd 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -4307,7 +4307,7 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
                             pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD));
                     else
                     {
-                        pDestTextNd = pSttTextNd->MakeCopy( pDoc, aInsPos )->GetTextNode();
+                        pDestTextNd = pSttTextNd->MakeCopy(pDoc, aInsPos, true)->GetTextNode();
                         bCopyOk = true;
                     }
                     aDestIdx.Assign( pDestTextNd, 0 );
diff --git a/sw/source/core/docnode/ndcopy.cxx b/sw/source/core/docnode/ndcopy.cxx
index 431a91e35055..5ec923298e7e 100644
--- a/sw/source/core/docnode/ndcopy.cxx
+++ b/sw/source/core/docnode/ndcopy.cxx
@@ -52,7 +52,7 @@ struct MapTableFrameFormat
 
 typedef std::vector<MapTableFrameFormat> MapTableFrameFormats;
 
-SwContentNode* SwTextNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
+SwContentNode* SwTextNode::MakeCopy(SwDoc* pDoc, const SwNodeIndex& rIdx, bool const bNewFrames) const
 {
     // the Copy-Textnode is the Node with the Text, the Copy-Attrnode is the
     // node with the collection and hard attributes. Normally is the same
@@ -75,7 +75,7 @@ SwContentNode* SwTextNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) cons
     if( !pColl )
         pColl = pDoc->CopyTextColl( *GetTextColl() );
 
-    SwTextNode* pTextNd = pDoc->GetNodes().MakeTextNode( rIdx, pColl );
+    SwTextNode* pTextNd = pDoc->GetNodes().MakeTextNode(rIdx, pColl, bNewFrames);
 
     // METADATA: register copy
     pTextNd->RegisterAsCopyOf(*pCpyTextNd);
diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx
index 4aa473c4308e..aed8aafbdaeb 100644
--- a/sw/source/core/docnode/nodes.cxx
+++ b/sw/source/core/docnode/nodes.cxx
@@ -1858,11 +1858,8 @@ void SwNodes::CopyNodes( const SwNodeRange& rRange,
         case SwNodeType::Grf:
         case SwNodeType::Ole:
             {
-                SwContentNode* pNew = static_cast<SwContentNode*>(pCurrentNode)->MakeCopy(
-                                            pDoc, aInsPos );
-                // frames are always created as default, so delete if needed
-                if( !bNewFrames )
-                    pNew->DelFrames(nullptr);
+                 static_cast<SwContentNode*>(pCurrentNode)->MakeCopy(
+                                            pDoc, aInsPos, bNewFrames);
             }
             break;
 
diff --git a/sw/source/core/graphic/ndgrf.cxx b/sw/source/core/graphic/ndgrf.cxx
index ccf2a54a34a5..d607928ad112 100644
--- a/sw/source/core/graphic/ndgrf.cxx
+++ b/sw/source/core/graphic/ndgrf.cxx
@@ -700,7 +700,7 @@ void SwGrfNode::ScaleImageMap()
     }
 }
 
-SwContentNode* SwGrfNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
+SwContentNode* SwGrfNode::MakeCopy(SwDoc* pDoc, const SwNodeIndex& rIdx, bool) const
 {
     // copy formats into the other document
     SwGrfFormatColl* pColl = pDoc->CopyGrfColl( *GetGrfColl() );
diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx
index 8d59c502817c..924a4db44904 100644
--- a/sw/source/core/ole/ndole.cxx
+++ b/sw/source/core/ole/ndole.cxx
@@ -407,7 +407,7 @@ Size SwOLENode::GetTwipSize() const
     return const_cast<SwOLENode*>(this)->maOLEObj.GetObject().GetSize( &aMapMode );
 }
 
-SwContentNode* SwOLENode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
+SwContentNode* SwOLENode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx, bool) const
 {
     // If there's already a SvPersist instance, we use it
     SfxObjectShell* pPersistShell = pDoc->GetPersist();
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 3ccba7a31c75..286ae4dafec6 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -112,7 +112,7 @@ typedef std::vector<SwTextAttr*> SwpHts;
 #endif
 
 SwTextNode *SwNodes::MakeTextNode( const SwNodeIndex & rWhere,
-                                 SwTextFormatColl *pColl )
+                                 SwTextFormatColl *pColl, bool const bNewFrames)
 {
     OSL_ENSURE( pColl, "Collection pointer is 0." );
 
@@ -126,7 +126,8 @@ SwTextNode *SwNodes::MakeTextNode( const SwNodeIndex & rWhere,
 
     // if there is no layout or it is in a hidden section, MakeFrames is not needed
     const SwSectionNode* pSectNd;
-    if( !GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell() ||
+    if (!bNewFrames ||
+        !GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell() ||
         ( nullptr != (pSectNd = pNode->FindSectionNode()) &&
             pSectNd->GetSection().IsHiddenFlag() ))
         return pNode;
commit 65b1969cf3c85a498807a2f1300b5483953103f3
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Aug 21 15:42:26 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 2018 +0200

    sw_redlinehide_2: tiny optimisation in SwTextFrame::SwClientNotify()
    
    If there are no items left that affect the frame (which is hard to
    predict for merged frames, nCount only refers to the incoming item set),
    skip calling SwContentFrame::Modify().
    
    Change-Id: I10bdb6420bcff9b89e73b6d57ebb762aa43a0648

diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index ef7d80cc0226..dcb4a632ef58 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -2199,7 +2199,10 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint)
                         aOldSet.ClearItem( RES_PARATR_SPLIT );
                         aNewSet.ClearItem( RES_PARATR_SPLIT );
                     }
-                    SwContentFrame::Modify( &aOldSet, &aNewSet );
+                    if (aOldSet.Count() || aNewSet.Count())
+                    {
+                        SwContentFrame::Modify( &aOldSet, &aNewSet );
+                    }
                 }
                 else
                     SwContentFrame::Modify( pOld, pNew );
commit 6def0f3b962bc7ab2862ec8e3444f386bddf7d00
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Aug 20 17:24:18 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 18:58:50 2018 +0200

    sw_redlinehide_2, can have 0-length inserts from redlines
    
    Change-Id: I2f3df32c51af15b1d624e1457cdf7f021a546a09

diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 7728ae1409f1..ef7d80cc0226 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -727,10 +727,14 @@ TextFrameIndex UpdateMergedParaForInsert(MergedPara & rMerged,
         bool const isRealInsert,
         SwTextNode const& rNode, sal_Int32 const nIndex, sal_Int32 const nLen)
 {
-    assert(nLen); // can 0 happen?
+    assert(!isRealInsert || nLen); // can 0 happen? yes, for redline in empty node
     assert(nIndex <= rNode.Len());
     assert(nIndex + nLen <= rNode.Len());
     assert(rMerged.pFirstNode->GetIndex() <= rNode.GetIndex() && rNode.GetIndex() <= rMerged.pLastNode->GetIndex());
+    if (!nLen)
+    {
+        return TextFrameIndex(0);
+    }
     OUStringBuffer text(rMerged.mergedText);
     sal_Int32 nTFIndex(0);
     sal_Int32 nInserted(0);
commit 3f221b53bce2439d57b10c82770d38b4fd3fbb27

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list