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/+/96496
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index b8b85c9..6bce5c1 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>
@@ -889,6 +891,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
@@ -1558,12 +1575,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 )
@@ -1583,6 +1602,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;
@@ -1607,6 +1627,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;
@@ -1629,6 +1650,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 c99939a..ce38a4d 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 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 f285e88..739597cf 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -186,6 +186,7 @@ SwUndoDelete::SwUndoDelete(
m_bResetPgDesc( false ),
m_bResetPgBrk( false ),
m_bFromTableCopy( bCalledByTableCpy )
, m_bDisableMakeFrames(false)
{
m_bCacheComment = false;
@@ -1047,7 +1048,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,
@@ -1094,7 +1114,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
@@ -1110,7 +1130,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());
}