summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stahl <Michael.Stahl@cib.de>2020-04-02 17:18:37 +0200
committerMichael Stahl <michael.stahl@cib.de>2020-04-03 17:20:22 +0200
commit166b5010b402a41b192b1659093a25acf9065fd9 (patch)
tree58a783dfc1800c604979380c121337ada3e5ad6f
parent27aa4b16bf704d0246595750daf57b57ff2577b3 (diff)
tdf#130685 sw_redlinehide: fix copying to position following redline
In DocumentContentOperationsManager::CopyWithFlyInFly(), first CopyNodes() also creates all layout frames, then SaveRedlEndPosForRestore fixes the end position of all redlines that were moved by CopyNodes() (they were moved not by changing their position but by inserting new nodes before their end position). Of course this means that the layout frames are created with redlines that have only a temporary end position, and then things go wrong when the end positions are adjusted, so add something similar to SwUndoDelete::UndoImpl() to recreate the frames in CopyWithFlyInFly(). This hit the assert: sw/source/core/text/redlnitr.cxx:94: std::unique_ptr<sw::MergedPara> sw::CheckParaRedlineMerge(SwTextFrame&, SwTextNode&, sw::FrameMode): Assertion `pNode != &rTextNode || &pStart->nNode.GetNode() == &rTextNode' failed. (regression from ... sw_redlinehide) Change-Id: I82e0f5b320cab201e762f58800f83e08f4f01048 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91596 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@cib.de>
-rw-r--r--sw/source/core/doc/DocumentContentOperationsManager.cxx36
-rw-r--r--sw/source/core/inc/txtfrm.hxx2
-rw-r--r--sw/source/core/layout/frmtool.cxx32
-rw-r--r--sw/source/core/undo/undel.cxx25
4 files changed, 64 insertions, 31 deletions
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 7cb7901912cb..98c39021af17 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -44,6 +44,7 @@
#include <redline.hxx>
#include <txtfrm.hxx>
#include <rootfrm.hxx>
+#include <frmtool.hxx>
#include <unocrsr.hxx>
#include <mvsave.hxx>
#include <ndtxt.hxx>
@@ -3407,22 +3408,43 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
assert(!pCopiedPaM || pCopiedPaM->second.nNode <= rInsPos);
SwDoc* pDest = rInsPos.GetNode().GetDoc();
- SwNodeIndex aSavePos( rInsPos, -1 );
- bool bEndIsEqualEndPos = rInsPos == rRg.aEnd;
+ SwNodeIndex aSavePos( rInsPos );
if (rRg.aStart != rRg.aEnd)
{
+ bool bEndIsEqualEndPos = rInsPos == rRg.aEnd;
+ --aSavePos;
SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 );
// insert behind the already copied start node
- m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, bMakeNewFrames, true );
+ m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, false, true );
aRedlRest.Restore();
+ if (bMakeNewFrames) // tdf#130685 only after aRedlRest
+ { // recreate from previous node (could be merged now)
+ if (SwTextNode *const pNode = aSavePos.GetNode().GetTextNode())
+ {
+ sw::RecreateStartTextFrames(*pNode);
+ }
+ }
+ bool const isAtStartOfSection(aSavePos.GetNode().IsStartNode());
+ ++aSavePos;
+ if (bMakeNewFrames)
+ {
+ // it's possible that CheckParaRedlineMerge() deleted frames
+ // on rInsPos so have to include it, but it must not be included
+ // if it was the first node in the document so that MakeFrames()
+ // will find the existing (wasn't deleted) frame on it
+ SwNodeIndex const end(rInsPos,
+ (rInsPos.GetNode().IsEndNode() || isAtStartOfSection)
+ ? 0 : +1);
+ ::MakeFrames(pDest, aSavePos, end);
+ }
+ if (bEndIsEqualEndPos)
+ {
+ const_cast<SwNodeIndex&>(rRg.aEnd) = aSavePos;
+ }
}
- ++aSavePos;
- if( bEndIsEqualEndPos )
- const_cast<SwNodeIndex&>(rRg.aEnd) = aSavePos;
-
#if OSL_DEBUG_LEVEL > 0
{
//JP 17.06.99: Bug 66973 - check count only if the selection is in
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index a1a7833e21a3..61377d2a73ca 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -142,6 +142,8 @@ bool IsMarkHidden(SwRootFrame const& rLayout, ::sw::mark::IMark const& rMark);
bool IsMarkHintHidden(SwRootFrame const& rLayout,
SwTextNode const& rNode, SwTextAttrEnd const& rHint);
+void RecreateStartTextFrames(SwTextNode & rNode);
+
} // namespace sw
/// Represents the visualization of a paragraph. Typical upper is an
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index c7424c95d4a8..c99eb61b82d8 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1356,6 +1356,38 @@ void AppendAllObjs(const SwFrameFormats* pTable, const SwFrame* pSib)
}
}
+namespace sw {
+
+void RecreateStartTextFrames(SwTextNode & rNode)
+{
+ std::vector<SwTextFrame*> frames;
+ SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rNode);
+ for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+ {
+ if (pFrame->getRootFrame()->IsHideRedlines())
+ {
+ frames.push_back(pFrame);
+ }
+ }
+ auto eMode(sw::FrameMode::Existing);
+ 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
+ : rNode);
+ assert(rFirstNode.GetIndex() <= rNode.GetIndex());
+ pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
+ *pFrame, rFirstNode, eMode));
+ eMode = sw::FrameMode::New; // Existing is not idempotent!
+ // note: this may or may not delete frames on the end node
+ }
+}
+
+} // namespace sw
+
/** local method to set 'working' position for newly inserted frames
OD 12.08.2003 #i17969#
diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index a93a34bb0257..ba1d9210359d 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -1080,30 +1080,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
// frames
SwTextNode *const pStartNode(aIdx.GetNodes()[m_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);
- }
- }
- auto eMode(sw::FrameMode::Existing);
- 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, eMode));
- eMode = sw::FrameMode::New; // Existing is not idempotent!
- // note: this may or may not delete frames on the end node
- }
+ sw::RecreateStartTextFrames(*pStartNode);
}
// create frames after SetSaveData has recreated redlines