tdf#132944 sw_redlinehide: delete of insert redline

Because of an existing insert redline with SwComparePosition::Equal
this hits the DeleteAndJoin() call in AppendRedline() and so what
happens on Undo is that the SwUndoDelete first creates all the layout
frames and then the SwUndoRedlineDelete creates the frames a 2nd time.

Because this can happen not only for Equal but also Inside case, it
appears best to prevent the "inner" Undo from recreating the frames;
it's always SwUndoDelete.

This is quite hacky...

Change-Id: I4438dd09bb6c2edf8154d333de403483768755fd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96233
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@cib.de>
(cherry picked from commit ad0351b84926075297fb74abbe9b31a0455782af)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96517
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index fb6a54d..d23a697 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -25,6 +25,8 @@
#include <fmtfld.hxx>
#include <frmtool.hxx>
#include <IDocumentUndoRedo.hxx>
#include <UndoManager.hxx>
#include <UndoDelete.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentState.hxx>
@@ -887,6 +889,21 @@ namespace
            static_cast<SwPaM&>(m_rRedline) = *m_pCursor;
        }
    };

    auto UndoDeleteDisableFrames(SwDoc & rDoc) -> void
    {
        // inside AppendRedline(), a SwUndoDelete was created;
        // prevent it from creating duplicate layout frames on Undo
        auto & rUndo(rDoc.GetUndoManager());
        if (rUndo.DoesUndo())
        {
            SwUndo *const pUndo(rUndo.GetLastUndo());
            assert(pUndo);
            SwUndoDelete *const pUndoDel(dynamic_cast<SwUndoDelete*>(pUndo));
            assert(pUndoDel);
            pUndoDel->DisableMakeFrames(); // tdf#132944
        }
    }
}

namespace sw
@@ -1556,12 +1573,14 @@ DocumentRedlineManager::AppendRedline(SwRangeRedline* pNewRedl, bool const bCall
                                }
                                else
                                    m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pNewRedl );
                                UndoDeleteDisableFrames(m_rDoc); // tdf#132944

                                bCompress = true;
                            }
                            if( !bCallDelete && !bDec && *pEnd == *pREnd )
                            {
                                m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pNewRedl );
                                UndoDeleteDisableFrames(m_rDoc);
                                bCompress = true;
                            }
                            else if ( bCallDelete || !bDec )
@@ -1581,6 +1600,7 @@ DocumentRedlineManager::AppendRedline(SwRangeRedline* pNewRedl, bool const bCall
                                {
                                    TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
                                    m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pRedl );
                                    UndoDeleteDisableFrames(m_rDoc);
                                    n = 0;      // re-initialize
                                }
                                delete pRedl;
@@ -1605,6 +1625,7 @@ DocumentRedlineManager::AppendRedline(SwRangeRedline* pNewRedl, bool const bCall
                                {
                                    TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
                                    m_rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
                                    UndoDeleteDisableFrames(m_rDoc);
                                    n = 0;      // re-initialize
                                }
                                bDec = true;
@@ -1627,6 +1648,7 @@ DocumentRedlineManager::AppendRedline(SwRangeRedline* pNewRedl, bool const bCall
                                {
                                    TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
                                    m_rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
                                    UndoDeleteDisableFrames(m_rDoc);
                                    n = 0;      // re-initialize
                                    bDec = true;
                                }
diff --git a/sw/source/core/inc/UndoDelete.hxx b/sw/source/core/inc/UndoDelete.hxx
index b9b5258..a0ff970 100644
--- a/sw/source/core/inc/UndoDelete.hxx
+++ b/sw/source/core/inc/UndoDelete.hxx
@@ -59,6 +59,7 @@ class SwUndoDelete
    bool m_bResetPgDesc : 1;   // TRUE: reset PgDsc on following node
    bool m_bResetPgBrk : 1;    // TRUE: reset PgBreak on following node
    bool const m_bFromTableCopy : 1; // TRUE: called by SwUndoTableCpyTable
    bool m_bDisableMakeFrames : 1;

    bool SaveContent( const SwPosition* pStt, const SwPosition* pEnd,
                    SwTextNode* pSttTextNd, SwTextNode* pEndTextNd );
@@ -98,6 +99,8 @@ public:

    // SwUndoTableCpyTable needs this information:
    bool IsDelFullPara() const { return m_bDelFullPara; }

    void DisableMakeFrames() { m_bDisableMakeFrames = true; };
};

#endif // INCLUDED_SW_SOURCE_CORE_INC_UNDODELETE_HXX
diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index 30298fe..0510ea6 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -190,6 +190,7 @@ SwUndoDelete::SwUndoDelete(
    m_bResetPgDesc( false ),
    m_bResetPgBrk( false ),
    m_bFromTableCopy( bCalledByTableCpy )
    , m_bDisableMakeFrames(false)
{

    m_bCacheComment = false;
@@ -1051,7 +1052,26 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
        SetSaveData(rDoc, *m_pRedlSaveData);

    sal_uLong delFullParaEndNode(m_nEndNode);
    if (m_bDelFullPara && m_pRedlSaveData)
    if (m_bDisableMakeFrames) // tdf#132944
    {
        assert(!m_bDelFullPara);
        SwTextNode *const pEndNode(aIdx.GetNodes()[m_nEndNode]->GetTextNode());
        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
        for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
        {
            o3tl::sorted_vector<SwRootFrame *> layouts;
            if (pFrame->getRootFrame()->IsHideRedlines())
            {
                assert(pFrame->GetTextNodeFirst() == pEndNode); // can't be merged with previous
                layouts.insert(pFrame->getRootFrame());
            }
            for (SwRootFrame const*const pLayout : layouts)
            {
                pEndNode->DelFrames(pLayout); // SwUndoRedlineDelete will create it
            }
        }
    }
    else if (m_bDelFullPara && m_pRedlSaveData)
    {
        SwTextNode * pFirstMergedDeletedTextNode(nullptr);
        SwTextNode *const pNextNode = FindFirstAndNextNode(rDoc, *this,
@@ -1098,7 +1118,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
    }

    // create frames after SetSaveData has recreated redlines
    if (0 != m_nNode)
    if (0 != m_nNode && !m_bDisableMakeFrames)
    {
        // tdf#121031 if the start node is a text node, it already has a frame;
        // if it's a table, it does not
@@ -1114,7 +1134,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
        ::MakeFrames(&rDoc, start, end);
    }

    if (pMovedNode)
    if (pMovedNode && !m_bDisableMakeFrames)
    {   // probably better do this after creating all frames
        lcl_MakeAutoFrames(*rDoc.GetSpzFrameFormats(), pMovedNode->GetIndex());
    }