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

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Mon Sep 3 16:13:29 UTC 2018


 sw/inc/hints.hxx                                        |   13 +
 sw/source/core/attr/hints.cxx                           |    5 
 sw/source/core/doc/DocumentContentOperationsManager.cxx |  151 ++++++++--------
 sw/source/core/doc/DocumentRedlineManager.cxx           |   73 +++++++
 sw/source/core/inc/txtfrm.hxx                           |    3 
 sw/source/core/text/txtfrm.cxx                          |   95 +++++++++-
 sw/source/core/txtnode/ndtxt.cxx                        |    2 
 sw/source/core/undo/unredln.cxx                         |   13 +
 8 files changed, 283 insertions(+), 72 deletions(-)

New commits:
commit 62a030a71f267b65ca7b188cf97df21bd71d17bd
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 18:12:15 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..4088a497f989 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,72 @@ using namespace com::sun::star;
 
 #endif
 
+namespace sw {
+
+void UpdateFramesForAddDeleteRedline(SwPaM const& rPam)
+{
+    if (rPam.GetPoint()->nNode != rPam.GetMark()->nNode)
+    {
+        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 +361,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 +377,6 @@ namespace
         {
         case nsRedlineType_t::REDLINE_INSERT:
             {
-                SwDoc& rDoc = *pRedl->GetDoc();
                 const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
                 bool bDelRedl = false;
                 switch( eCmp )
@@ -390,6 +457,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 +542,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 9c47d5d4ad9e442edc5d459cfa0b442d930f188a
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Sep 3 17:20:37 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Mon Sep 3 17:20:37 2018 +0200

    incorrect call to lcl_SetWrong - must not move indexes for redline ops
    
    Change-Id: I965c60dad691128125ef9cdacdb388b30c9d52f3

diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 9c1a6a0f0f55..58f28195010e 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -1838,7 +1838,7 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint)
             {
                 InvalidateRange( SwCharRange(nPos, TextFrameIndex(1)), m );
             }
-            lcl_SetWrong( *this, rNode, nNPos, m, true );
+            lcl_SetWrong( *this, rNode, nNPos, m, false );
             if (nLen)
             {
                 lcl_SetScriptInval( *this, nPos );
@@ -1869,7 +1869,7 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint)
                 else
                     InvalidateRange_( SwCharRange( nPos, nLen ), nNLen );
             }
-            lcl_SetWrong( *this, rNode, nNPos, nNLen, true );
+            lcl_SetWrong( *this, rNode, nNPos, nNLen, false );
             lcl_SetScriptInval( *this, nPos );
             bSetFieldsDirty = true;
             if (HasFollow())
commit 488cddbc8c9b09f4243e91263d857efea30ddde7
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 15:19:17 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 582ca30a29c5b2b7df2b5ae9826f071119a5b2aa
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 14:49:05 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 c8bdae109b06..9c1a6a0f0f55 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, true);
+            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 b9e44c32cbc6..491eed4af7ff 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 1ef0af94217ea3d79da496edf15a5fc5d4aff3a3
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: Fri Aug 31 19:14:58 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;


More information about the Libreoffice-commits mailing list