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 7b2b9aa..45010c2 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>
@@ -3632,6 +3633,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 327ad96..631b35e 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -19,6 +19,7 @@
#include <DocumentRedlineManager.hxx>
#include <frmfmt.hxx>
#include <rootfrm.hxx>
#include <txtfrm.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <IDocumentState.hxx>
@@ -113,6 +114,74 @@ using namespace com::sun::star;

#endif

namespace sw {

void UpdateFramesForAddDeleteRedline(SwPaM const& rPam)
{
    SwTextNode *const pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
    std::vector<SwTextFrame*> frames;
    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pStartNode);
    for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
    {
        if (pFrame->getRootFrame()->IsHideRedlines())
        {
            frames.push_back(pFrame);
        }
    }
    for (SwTextFrame * pFrame : frames)
    {
        SwTextNode & rFirstNode(pFrame->GetMergedPara()
            ? *pFrame->GetMergedPara()->pFirstNode
            : *pStartNode);
        assert(rFirstNode.GetIndex() <= pStartNode->GetIndex());
        // clear old one first to avoid DelFrames confusing updates & asserts...
        pFrame->SetMergedPara(nullptr);
        pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
            *pFrame, rFirstNode, sw::FrameMode::Existing));
    }
}

void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
{
    if (rPam.GetPoint()->nNode != rPam.GetMark()->nNode)
    {
        // first, call CheckParaRedlineMerge on the first paragraph,
        // to init flag on new merge range (if any) + 1st node post the merge
        SwTextNode *const pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
        std::vector<SwTextFrame*> frames;
        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pStartNode);
        for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
        {
            if (pFrame->getRootFrame()->IsHideRedlines())
            {
                frames.push_back(pFrame);
            }
        }
        for (SwTextFrame * pFrame : frames)
        {
            if (auto const pMergedPara = pFrame->GetMergedPara())
            {
                assert(pMergedPara->pFirstNode->GetIndex() <= pStartNode->GetIndex());
                // clear old one first to avoid DelFrames confusing updates & asserts...
                SwTextNode & rFirstNode(*pMergedPara->pFirstNode);
                pFrame->SetMergedPara(nullptr);
                pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
                    *pFrame, rFirstNode, sw::FrameMode::Existing));
            }
        }
        // now start node until end of merge + 1 has proper flags; MakeFrames
        // should pick up from the next node in need of frames by checking flags
        if (!frames.empty())
        {
            SwNodeIndex const start(*pStartNode, +1);
            SwNodeIndex const end(rPam.End()->nNode, +1); // end is exclusive
            ::MakeFrames(&rDoc, start, end);
        }
    }
}

} // namespace sw

namespace
{
    inline bool IsPrevPos( const SwPosition & rPos1, const SwPosition & rPos2 )
@@ -294,6 +363,7 @@ namespace
    {
        bool bRet = true;
        SwRangeRedline* pRedl = rArr[ rPos ];
        SwDoc& rDoc = *pRedl->GetDoc();
        SwPosition *pRStt = nullptr, *pREnd = nullptr;
        SwComparePosition eCmp = SwComparePosition::Outside;
        if( pSttRng && pEndRng )
@@ -309,7 +379,6 @@ namespace
        {
        case nsRedlineType_t::REDLINE_INSERT:
            {
                SwDoc& rDoc = *pRedl->GetDoc();
                const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
                bool bDelRedl = false;
                switch( eCmp )
@@ -390,6 +459,8 @@ namespace
            {
                SwRangeRedline* pNew = nullptr;
                bool bCheck = false, bReplace = false;
                SwPaM const updatePaM(pSttRng ? *pSttRng : *pRedl->Start(),
                                      pEndRng ? *pEndRng : *pRedl->End());

                switch( eCmp )
                {
@@ -473,6 +544,8 @@ namespace
                    rArr.Remove( pRedl );
                    rArr.Insert( pRedl );
                }

                sw::UpdateFramesForRemoveDeleteRedline(rDoc, updatePaM);
            }
            break;

diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 10bde32..a52bf0f 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 3866e55..a2eaa3f 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 )