[Libreoffice-commits] core.git: Branch 'private/mst/sw_redlinehide_2' - 11 commits - sw/inc sw/qa sw/source
Libreoffice Gerrit user
logerrit at kemper.freedesktop.org
Thu Sep 6 11:04:58 UTC 2018
Rebased ref, commits from common ancestor:
commit d6d1cba65a87c83a2886482366914fe4436cf9cc
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Sep 6 12:58:18 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Thu Sep 6 12:58:18 2018 +0200
sw_redlinehide_2: update flys and footnotes on redline ops
Re-use some code that is already used elsewhere; for the
UpdateFramesForAddDeleteRedline(), the same code as for switching
the layout to Hide mode should work, for
UpdateFramesForRemoveDeleteRedline() use the code that is used for
SwTextNode::SplitContentNode().
Change-Id: I97601bfb63478cc999cf7017da0225b2dc62ad37
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index caec50025ef1..d27a579d3e43 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -140,25 +140,34 @@ void UpdateFramesForAddDeleteRedline(SwPaM const& rPam)
pFrame->SetMergedPara(nullptr);
pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
*pFrame, rFirstNode, sw::FrameMode::Existing));
+ // the first node of the new redline is not necessarily the first
+ // node of the merged frame, there could be another redline nearby
+ sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, *pStartNode, nullptr);
}
}
void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
{
+ SwTextNode *const pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
+ std::vector<SwTextFrame*> frames;
+ std::set<SwRootFrame*> layouts;
+ 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);
+ layouts.insert(pFrame->getRootFrame());
+ }
+ }
+ if (frames.empty())
+ {
+ return;
+ }
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())
@@ -173,11 +182,22 @@ void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
}
// 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
+ // note: this will also create frames for all currently hidden flys
+ // both on first and non-first nodes because it calls AppendAllObjs
+ ::MakeFrames(&rDoc, start, end);
+ // re-use this to move flys that are now on the wrong frame, with end
+ // of redline as "second" node; the nodes between start and end should
+ // be complete with MakeFrames already
+ sw::MoveMergedFlysAndFootnotes(frames, *pStartNode,
+ *rPam.End()->nNode.GetNode().GetTextNode(), false);
+ }
+ else
+ { // recreate flys in the one node the hard way...
+ for (auto const& pLayout : layouts)
{
- SwNodeIndex const start(*pStartNode, +1);
- SwNodeIndex const end(rPam.End()->nNode, +1); // end is exclusive
- ::MakeFrames(&rDoc, start, end);
+ AppendAllObjs(rDoc.GetSpzFrameFormats(), pLayout);
}
}
}
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index a52bf0f14fa0..0b19178734d2 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -105,12 +105,19 @@ TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged,
bool isRealDelete,
SwTextNode const& rNode, sal_Int32 nIndex, sal_Int32 nLen);
+void MoveMergedFlysAndFootnotes(std::vector<SwTextFrame*> const& rFrames,
+ SwTextNode const& rFirstNode, SwTextNode & rSecondNode, bool);
+
void MoveDeletedPrevFrames(SwTextNode & rDeletedPrev, SwTextNode & rNode);
void CheckResetRedlineMergeFlag(SwTextNode & rNode, bool bRecreateMerged);
void UpdateFramesForAddDeleteRedline(SwPaM const& rPam);
void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam);
+void AddRemoveFlysAnchoredToFrameStartingAtNode(
+ SwTextFrame & rFrame, SwTextNode & rTextNode,
+ std::set<sal_uLong> *pSkipped);
+
} // namespace sw
/// Represents the visualization of a paragraph. Typical upper is an
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 3e6ff2d4f565..e6fbd7c553dc 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4167,6 +4167,74 @@ void SwRootFrame::InvalidateAllObjPos()
}
}
+namespace sw {
+
+/// rTextNode is the first one of the "new" merge - if rTextNode isn't the same
+/// as MergedPara::pFirstNode, then nodes before rTextNode have their flys
+/// already properly attached, so only the other nodes need handling here.
+void AddRemoveFlysAnchoredToFrameStartingAtNode(
+ SwTextFrame & rFrame, SwTextNode & rTextNode,
+ std::set<sal_uLong> *const pSkipped)
+{
+ auto const pMerged(rFrame.GetMergedPara());
+ if (pMerged
+ // do this only *once*, for the *last* frame
+ // otherwise AppendObj would create multiple frames for fly-frames!
+ && !rFrame.GetFollow())
+ {
+ assert(pMerged->pFirstNode->GetIndex() <= rTextNode.GetIndex()
+ && rTextNode.GetIndex() <= pMerged->pLastNode->GetIndex());
+ // add visible flys in non-first node to merged frame
+ // (hidden flys remain and are deleted via DelFrames())
+ SwFrameFormats& rTable(*rTextNode.GetDoc()->GetSpzFrameFormats());
+ SwPageFrame *const pPage(rFrame.FindPageFrame());
+ std::vector<sw::Extent>::const_iterator iterFirst(pMerged->extents.begin());
+ std::vector<sw::Extent>::const_iterator iter(iterFirst);
+ SwTextNode const* pNode(pMerged->pFirstNode);
+ for ( ; ; ++iter)
+ {
+ if (iter == pMerged->extents.end()
+ || iter->pNode != pNode)
+ {
+ if (pNode == &rTextNode)
+ { // remove existing hidden at-char anchored flys
+ RemoveHiddenObjsOfNode(
+ rTextNode, &iterFirst, &iter);
+ }
+ else if (rTextNode.GetIndex() < pNode->GetIndex())
+ {
+ // pNode's frame has been deleted by CheckParaRedlineMerge()
+ AppendObjsOfNode(&rTable,
+ pNode->GetIndex(), &rFrame, pPage, rTextNode.GetDoc(),
+ &iterFirst, &iter);
+ if (pSkipped)
+ {
+ // if a fly has been added by AppendObjsOfNode, it must be skipped; if not, then it doesn't matter if it's skipped or not because it has no frames and because of that it would be skipped anyway
+ if (auto const pFlys = pNode->GetAnchoredFlys())
+ {
+ for (auto const pFly : *pFlys)
+ {
+ if (pFly->Which() != RES_DRAWFRMFMT)
+ {
+ pSkipped->insert(pFly->GetContent().GetContentIdx()->GetIndex());
+ }
+ }
+ }
+ }
+ }
+ if (iter == pMerged->extents.end())
+ {
+ break;
+ }
+ pNode = iter->pNode;
+ iterFirst = iter;
+ }
+ }
+ }
+}
+
+} // namespace sw
+
static void UnHideRedlines(SwRootFrame & rLayout,
SwNodes & rNodes, SwNode const& rEndOfSectionNode,
std::set<sal_uLong> *const pSkipped)
@@ -4226,59 +4294,7 @@ static void UnHideRedlines(SwRootFrame & rLayout,
}
}
}
- if (pMerged
- // do this only *once*, for the *last* frame
- // otherwise AppendObj would create multiple frames for fly-frames!
- && !pFrame->GetFollow())
- {
- // add visible flys in non-first node to merged frame
- // (hidden flys remain and are deleted via DelFrames())
- SwFrameFormats& rTable(*rTextNode.GetDoc()->GetSpzFrameFormats());
- SwPageFrame *const pPage(pFrame->FindPageFrame());
- std::vector<sw::Extent>::const_iterator iterFirst(pMerged->extents.begin());
- std::vector<sw::Extent>::const_iterator iter(iterFirst);
- SwTextNode const* pNode(&rTextNode);
- for ( ; ; ++iter)
- {
- if (iter == pMerged->extents.end()
- || iter->pNode != pNode)
- {
- if (pNode == &rTextNode)
- { // remove existing hidden at-char anchored flys
- RemoveHiddenObjsOfNode(
- rTextNode, &iterFirst, &iter);
- }
- else
- {
- // pNode's frame has been deleted by CheckParaRedlineMerge()
- AppendObjsOfNode(&rTable,
- pNode->GetIndex(), pFrame, pPage,
- rTextNode.GetDoc(),
- &iterFirst, &iter);
- if (pSkipped)
- {
- // if a fly has been added by AppendObjsOfNode, it must be skipped; if not, then it doesn't matter if it's skipped or not because it has no frames and because of that it would be skipped anyway
- if (auto const pFlys = pNode->GetAnchoredFlys())
- {
- for (auto const pFly : *pFlys)
- {
- if (pFly->Which() != RES_DRAWFRMFMT)
- {
- pSkipped->insert(pFly->GetContent().GetContentIdx()->GetIndex());
- }
- }
- }
- }
- }
- if (iter == pMerged->extents.end())
- {
- break;
- }
- pNode = iter->pNode;
- iterFirst = iter;
- }
- }
- }
+ sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, rTextNode, pSkipped);
}
}
else
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index a8d672dda16e..9c16f081eb69 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -365,13 +365,18 @@ static void lcl_ChangeFootnoteRef( SwTextNode &rNode )
}
}
-namespace {
+namespace sw {
// check if there are flys on the existing frames (now on "pNode")
// that need to be moved to the new frames of "this"
void MoveMergedFlysAndFootnotes(std::vector<SwTextFrame*> const& rFrames,
- SwTextNode const& rFirstNode, SwTextNode const& rSecondNode)
+ SwTextNode const& rFirstNode, SwTextNode & rSecondNode,
+ bool isSplitNode)
{
+ if (!isSplitNode)
+ {
+ lcl_ChangeFootnoteRef(rSecondNode);
+ }
int nLevel(0);
for (sal_uLong nIndex = rSecondNode.GetIndex() + 1; ; ++nIndex)
{
@@ -608,7 +613,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
}
if (eOldMergeFlag != SwNode::Merge::None)
{
- MoveMergedFlysAndFootnotes(frames, *pNode, *this);
+ MoveMergedFlysAndFootnotes(frames, *pNode, *this, true);
}
}
else
@@ -739,7 +744,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
if (bRecreateThis)
{
- MoveMergedFlysAndFootnotes(frames, *pNode, *this);
+ MoveMergedFlysAndFootnotes(frames, *pNode, *this, true);
}
}
commit 2d823c8846d0c1e254d29acf651b18dda8cf5f32
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Sep 6 12:50:05 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Thu Sep 6 12:50:05 2018 +0200
merge into: fix SplitNode handling of merged frames
Change-Id: I7e2cccf9cacb3cd69786632a02928668f07fc8f9
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 5474b1a479ad..a8d672dda16e 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -697,6 +697,13 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
// Update the extents with new node; also inits merge flag,
// so the MakeFramesForAdjacentContentNode below respects it
pFrame->RegisterToNode(*pNode);
+ if (pFrame->GetText().isEmpty())
+ {
+ // turns out it's empty - in this case, it was not
+ // invalidated because Cut didn't sent it any hints,
+ // so we have to invalidate it here!
+ pFrame->Prepare(PREP_CLEAR, nullptr, false);
+ }
if (!pFrame->GetMergedPara() ||
!pFrame->GetMergedPara()->listener.IsListeningTo(this))
{
commit a3b219b4c34300416f6674df0dff40cc67593921
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Sep 6 12:47:59 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Thu Sep 6 12:47:59 2018 +0200
merge into: update frames on Redline ops
Change-Id: If93a3fb41b5b58e7b885642089d679587f1f870e
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index 349ecad51cda..caec50025ef1 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -136,6 +136,8 @@ void UpdateFramesForAddDeleteRedline(SwPaM const& rPam)
? *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));
}
@@ -162,8 +164,11 @@ void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
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, *pMergedPara->pFirstNode, sw::FrameMode::Existing));
+ *pFrame, rFirstNode, sw::FrameMode::Existing));
}
}
// now start node until end of merge + 1 has proper flags; MakeFrames
commit 07866014ecf69fc0e8bb327dc8695218475481d3
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Sep 6 12:39:29 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Thu Sep 6 12:39:29 2018 +0200
merge into: handle delete-without-redline inside of redline
Change-Id: I49b8f2e9fc3bbd21cca56d1ac98bccd81daea98e
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 464f4609f81d..ef792d95d9ea 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -1893,7 +1893,8 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint)
}
else
{
- assert(!m_pMergedPara || !getRootFrame()->IsHideRedlines() || !pMoveText->pDestNode->getLayoutFrame(getRootFrame()));
+ // there is a situation where this is okay: from JoinNext, which will then call CheckResetRedlineMergeFlag, which will then create merged from scratch for this frame
+ // assert(!m_pMergedPara || !getRootFrame()->IsHideRedlines() || !pMoveText->pDestNode->getLayoutFrame(getRootFrame()));
}
}
else switch (nWhich)
commit afec87699398f18188f4b8c98222394888dd4f53
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Sep 6 12:37:53 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Thu Sep 6 12:37:53 2018 +0200
merge into : show/hide flys in redlines
Change-Id: Ifa39e2dcaf6306c411e96eecb5ed88ee4a2d5b29
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 697b96f718ff..1d0f23e4a800 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1039,6 +1039,7 @@ static bool IsShown(sal_uLong const nIndex,
std::vector<sw::Extent>::const_iterator *const pIter,
std::vector<sw::Extent>::const_iterator const*const pEnd)
{
+ assert(!pIter || *pIter == *pEnd || (*pIter)->pNode->GetIndex() == nIndex);
SwPosition const& rAnchor(*rAnch.GetContentAnchor());
if (rAnchor.nNode.GetIndex() != nIndex)
{
commit 88a1d6b5b757b9464d0728e92d451e8d64e98a15
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Sep 5 13:03:02 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Wed Sep 5 13:03:02 2018 +0200
sw: remove window invalidation from SwRedlineTable::DeleteAndDestroyAll()
This is called in 2 situations, from ClearDoc() and from SwDoc dtor.
In the latter case, there is no window any more, and in the former case,
surely something else must have invalidated it already.
Change-Id: Ideecdeb145171a4dafbec50a04d4ec5aa2acab82
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 56dfd57a82f9..6fe4e815dc69 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -605,9 +605,6 @@ void SwRedlineTable::Remove( size_type nP )
void SwRedlineTable::DeleteAndDestroyAll()
{
- if (maVector.empty())
- return;
- SwDoc *const pDoc = maVector.front()->GetDoc();
while (!maVector.empty())
{
auto const pRedline = maVector.back();
@@ -615,14 +612,6 @@ void SwRedlineTable::DeleteAndDestroyAll()
LOKRedlineNotification(RedlineNotification::Remove, pRedline);
delete pRedline;
}
- if (pDoc && !pDoc->IsInDtor())
- {
- SwViewShell* pSh(pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() );
- if (pSh)
- {
- pSh->InvalidateWindows(SwRect(0, 0, SAL_MAX_INT32, SAL_MAX_INT32));
- }
- }
}
void SwRedlineTable::DeleteAndDestroy(size_type const nP)
commit 5ca03ed57b3dc27b10f04ba2fcaa905ee5ec2d31
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Sep 4 18:59:01 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Wed Sep 5 10:24:04 2018 +0200
sw: SwDocTest: adjust this so it actually tests something interesting
* test more than 1 paragraph, by calling SplitNode()
* enable Undo, because that's the more usual situation
* remove one mode that is identical to the previous one
* use SwUnoCursor because plain SwCursor isn't corrected when nodes
are deleted
* create a selection before calling Delete functions
Change-Id: If406bd8c37b005e431fbaebe82f297b051da1ed3
diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx
index 1a6d18d35c3a..cc95e3ce1da2 100644
--- a/sw/qa/core/uwriter.cxx
+++ b/sw/qa/core/uwriter.cxx
@@ -35,6 +35,7 @@
#include <breakit.hxx>
#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentStatistics.hxx>
@@ -1067,7 +1068,6 @@ void SwDocTest::randomTest()
RedlineFlags::NONE,
RedlineFlags::On | RedlineFlags::ShowMask,
RedlineFlags::On | RedlineFlags::Ignore,
- RedlineFlags::On | RedlineFlags::Ignore | RedlineFlags::ShowMask,
RedlineFlags::On | RedlineFlags::ShowInsert,
RedlineFlags::On | RedlineFlags::ShowDelete
};
@@ -1077,6 +1077,7 @@ void SwDocTest::randomTest()
for( size_t rlm = 0; rlm < SAL_N_ELEMENTS(modes); rlm++ )
{
+ m_pDoc->GetIDocumentUndoRedo().DoUndo(true);
m_pDoc->ClearDoc();
// setup redlining
@@ -1085,15 +1086,31 @@ void SwDocTest::randomTest()
for( int i = 0; i < 2000; i++ )
{
- SwCursor aCrs(getRandomPosition(m_pDoc, i/20), nullptr);
- aCrs.SetMark();
+ std::shared_ptr<SwUnoCursor> pCrs(
+ m_pDoc->CreateUnoCursor(getRandomPosition(m_pDoc, i/20)));
switch (getRand (i < 50 ? 3 : 6)) {
// insert ops first
case 0: {
- if (!m_pDoc->getIDocumentContentOperations().InsertString(aCrs, getRandString())) {
-// fprintf (stderr, "failed to insert string !\n");
+ OUString const tmp(getRandString());
+ sal_Int32 current(0);
+ sal_Int32 nextBreak(tmp.indexOf('\n'));
+ do
+ {
+ sal_Int32 const len((nextBreak == -1 ? tmp.getLength() : nextBreak - current));
+ if (0 < len)
+ {
+ m_pDoc->getIDocumentContentOperations().InsertString(
+ *pCrs, tmp.copy(current, len));
+ }
+ if (nextBreak != -1)
+ {
+ m_pDoc->getIDocumentContentOperations().SplitNode(*pCrs->GetPoint(), false);
+ current = nextBreak + 1;
+ nextBreak = tmp.indexOf('\n', current);
+ }
}
+ while (nextBreak != -1);
break;
}
case 1:
@@ -1106,19 +1123,27 @@ void SwDocTest::randomTest()
// movement / deletion ops later
case 3: // deletion
+ pCrs->SetMark();
switch (getRand(6)) {
case 0:
- m_pDoc->getIDocumentContentOperations().DelFullPara(aCrs);
+ *pCrs->GetMark() = getRandomPosition(m_pDoc, 42);
+ m_pDoc->getIDocumentContentOperations().DelFullPara(*pCrs);
break;
case 1:
- m_pDoc->getIDocumentContentOperations().DeleteRange(aCrs);
+ *pCrs->GetMark() = getRandomPosition(m_pDoc, 42);
+ m_pDoc->getIDocumentContentOperations().DeleteRange(*pCrs);
break;
case 2:
- m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aCrs, !!getRand(1));
+ *pCrs->GetMark() = getRandomPosition(m_pDoc, 42);
+ m_pDoc->getIDocumentContentOperations().DeleteAndJoin(*pCrs, !!getRand(1));
break;
case 3:
default:
- m_pDoc->getIDocumentContentOperations().Overwrite(aCrs, getRandString());
+ OUString const tmp(getRandString());
+ if (tmp.getLength())
+ {
+ m_pDoc->getIDocumentContentOperations().Overwrite(*pCrs, tmp);
+ }
break;
}
break;
@@ -1131,7 +1156,7 @@ void SwDocTest::randomTest()
SwMoveFlags::REDLINES |
SwMoveFlags::NO_DELFRMS;
SwPosition aTo(getRandomPosition(m_pDoc, i/10));
- m_pDoc->getIDocumentContentOperations().MoveRange(aCrs, aTo, nFlags);
+ m_pDoc->getIDocumentContentOperations().MoveRange(*pCrs, aTo, nFlags);
break;
}
commit 30aedc48b24679a0b9911a4f5f1a9e21e48eff2f
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Sep 4 18:55:13 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Wed Sep 5 10:24:04 2018 +0200
sw: SwRedlineTable::DeleteAndDestroy() is surprisingly dangerous
At least with the randomised test, it can happen that deleting one
redline will recursively delete other redlines that are located in
the hidden content section of the redline, or at least try to and
crash because those have already been deleted before.
The callers will either delete 1 redline, or delete all of them
via DeleteAndDestroyAll(), so put a safer loop into
DeleteAndDestroyAll() and have DeleteAndDestroy() only delete 1.
Change-Id: I9c4225544a43a4a03f4eb7b6f56e7fe848c8ca54
diff --git a/sw/inc/docary.hxx b/sw/inc/docary.hxx
index 20871385fa97..940789ad262e 100644
--- a/sw/inc/docary.hxx
+++ b/sw/inc/docary.hxx
@@ -345,7 +345,7 @@ public:
void Remove( size_type nPos );
void Remove( const SwRangeRedline* p );
- void DeleteAndDestroy( size_type nPos, size_type nLen = 1 );
+ void DeleteAndDestroy(size_type nPos);
void DeleteAndDestroyAll();
void dumpAsXml(struct _xmlTextWriter* pWriter) const;
@@ -389,7 +389,7 @@ public:
void Insert( SwExtraRedline* p );
- void DeleteAndDestroy( sal_uInt16 nPos, sal_uInt16 nLen = 1 );
+ void DeleteAndDestroy( sal_uInt16 nPos);
void DeleteAndDestroyAll();
void dumpAsXml(struct _xmlTextWriter* pWriter) const;
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 950526187efc..56dfd57a82f9 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -605,26 +605,32 @@ void SwRedlineTable::Remove( size_type nP )
void SwRedlineTable::DeleteAndDestroyAll()
{
- DeleteAndDestroy(0, size());
-}
-
-void SwRedlineTable::DeleteAndDestroy( size_type nP, size_type nL )
-{
- SwDoc* pDoc = nullptr;
- if( !nP && nL && nL == size() )
- pDoc = maVector.front()->GetDoc();
-
- for( vector_type::const_iterator it = maVector.begin() + nP; it != maVector.begin() + nP + nL; ++it )
+ if (maVector.empty())
+ return;
+ SwDoc *const pDoc = maVector.front()->GetDoc();
+ while (!maVector.empty())
+ {
+ auto const pRedline = maVector.back();
+ maVector.erase(maVector.back());
+ LOKRedlineNotification(RedlineNotification::Remove, pRedline);
+ delete pRedline;
+ }
+ if (pDoc && !pDoc->IsInDtor())
{
- LOKRedlineNotification(RedlineNotification::Remove, *it);
- delete *it;
+ SwViewShell* pSh(pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() );
+ if (pSh)
+ {
+ pSh->InvalidateWindows(SwRect(0, 0, SAL_MAX_INT32, SAL_MAX_INT32));
+ }
}
- maVector.erase( maVector.begin() + nP, maVector.begin() + nP + nL );
+}
- SwViewShell* pSh;
- if( pDoc && !pDoc->IsInDtor() &&
- nullptr != ( pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() ) )
- pSh->InvalidateWindows( SwRect( 0, 0, SAL_MAX_INT32, SAL_MAX_INT32 ) );
+void SwRedlineTable::DeleteAndDestroy(size_type const nP)
+{
+ auto const pRedline = maVector[nP];
+ maVector.erase(maVector.begin() + nP);
+ LOKRedlineNotification(RedlineNotification::Remove, pRedline);
+ delete pRedline;
}
SwRedlineTable::size_type SwRedlineTable::FindNextOfSeqNo( size_type nSttPos ) const
@@ -1883,7 +1889,7 @@ void SwExtraRedlineTable::Insert( SwExtraRedline* p )
//p->CallDisplayFunc();
}
-void SwExtraRedlineTable::DeleteAndDestroy( sal_uInt16 nPos, sal_uInt16 nLen )
+void SwExtraRedlineTable::DeleteAndDestroy(sal_uInt16 const nPos)
{
/*
SwDoc* pDoc = 0;
@@ -1891,10 +1897,8 @@ void SwExtraRedlineTable::DeleteAndDestroy( sal_uInt16 nPos, sal_uInt16 nLen )
pDoc = front()->GetDoc();
*/
- for( std::vector<SwExtraRedline*>::iterator it = m_aExtraRedlines.begin() + nPos; it != m_aExtraRedlines.begin() + nPos + nLen; ++it )
- delete *it;
-
- m_aExtraRedlines.erase( m_aExtraRedlines.begin() + nPos, m_aExtraRedlines.begin() + nPos + nLen );
+ delete m_aExtraRedlines[nPos];
+ m_aExtraRedlines.erase(m_aExtraRedlines.begin() + nPos);
/*
SwViewShell* pSh;
@@ -1906,7 +1910,12 @@ void SwExtraRedlineTable::DeleteAndDestroy( sal_uInt16 nPos, sal_uInt16 nLen )
void SwExtraRedlineTable::DeleteAndDestroyAll()
{
- DeleteAndDestroy(0, m_aExtraRedlines.size());
+ while (!m_aExtraRedlines.empty())
+ {
+ auto const pRedline = m_aExtraRedlines.back();
+ m_aExtraRedlines.pop_back();
+ delete pRedline;
+ }
}
SwExtraRedline::~SwExtraRedline()
commit 77b52e90d12fabf68e9885a873a5f845e28489c5
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Sep 4 18:52:56 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Wed Sep 5 10:24:04 2018 +0200
sw: SwUndoOverwrite ctor shouldn't DeleteRedline if ...
... it's at the end of the node already, similar to CanGrouping().
Change-Id: Ic7c6f5caa6e69e9414112cb245db97fd5d79e87d
diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx
index bee06b365dd4..d5652ce85e6e 100644
--- a/sw/source/core/undo/unovwr.cxx
+++ b/sw/source/core/undo/unovwr.cxx
@@ -43,6 +43,13 @@ SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& rPos,
: SwUndo(SwUndoId::OVERWRITE, pDoc),
pRedlSaveData( nullptr ), bGroup( false )
{
+ SwTextNode *const pTextNd = rPos.nNode.GetNode().GetTextNode();
+ assert(pTextNd);
+ sal_Int32 const nTextNdLen = pTextNd->GetText().getLength();
+
+ nSttNode = rPos.nNode.GetIndex();
+ nSttContent = rPos.nContent.GetIndex();
+
if( !pDoc->getIDocumentRedlineAccess().IsIgnoreRedline() && !pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty() )
{
SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
@@ -52,16 +59,13 @@ SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& rPos,
{
pRedlSaveData.reset();
}
+ if (nSttContent < nTextNdLen)
+ {
+ pDoc->getIDocumentRedlineAccess().DeleteRedline(aPam, false, USHRT_MAX);
+ }
}
- nSttNode = rPos.nNode.GetIndex();
- nSttContent = rPos.nContent.GetIndex();
-
- SwTextNode* pTextNd = rPos.nNode.GetNode().GetTextNode();
- OSL_ENSURE( pTextNd, "Overwrite not in a TextNode?" );
-
bInsChar = true;
- sal_Int32 nTextNdLen = pTextNd->GetText().getLength();
if( nSttContent < nTextNdLen ) // no pure insert?
{
aDelStr += OUStringLiteral1( pTextNd->GetText()[nSttContent] );
commit 2c064b0beed84325635e25e0ad99fa20fa503a49
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Sep 4 16:21:56 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Wed Sep 5 10:24:04 2018 +0200
sw: SwUndoOverwrite::CanGrouping() should ignore redlines for inserted
... characters; if the character is inserted at the end of the node,
the aPam end position will have an invalid index Len()+1 and
the DeleteRedline() will correct existing redlines onto that index,
which will assert later.
Change-Id: Ia31cd1937385fb10fd284e7add61c39f96b917ab
diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx
index e2fb76a19f63..bee06b365dd4 100644
--- a/sw/source/core/undo/unovwr.cxx
+++ b/sw/source/core/undo/unovwr.cxx
@@ -120,6 +120,7 @@ bool SwUndoOverwrite::CanGrouping( SwDoc* pDoc, SwPosition& rPos,
rCC.isLetterNumeric( aInsStr, aInsStr.getLength()-1 ) )
return false;
+ if (!bInsChar && rPos.nContent.GetIndex() < pDelTextNd->GetText().getLength())
{
SwRedlineSaveDatas aTmpSav;
SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
commit 697c9321decd0ecbe5c4cc0d45f604a31fd4cb2e
Author: Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Sep 4 14:34:03 2018 +0200
Commit: Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Wed Sep 5 10:24:04 2018 +0200
sw: avoid updating redlines to be empty in Overwrite()
The problem is that SwIndexReg::Update will correct a 1-character
redline in the middle of the newly-inserted part of the overwrite string
into a 0-length redline, which then a later SwTextNode::Update() will
correct in such a way that the whole thing becomes unsorted.
Just delete redlines in the entire overwrite range, which should help;
the aPam actually deletes them in the *last* character only which
seems rather unintentional anyway.
Change-Id: I61b6b312998e0779651d30f636312ef13556428c
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 1bb52e00e186..dc45775cbf25 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -2357,8 +2357,12 @@ bool DocumentContentOperationsManager::MoveAndJoin( SwPaM& rPaM, SwPosition& rPo
return bRet;
}
+// Overwrite only uses the point of the PaM, the mark is ignored; characters
+// are replaced from point until the end of the node; at the end of the node,
+// characters are inserted.
bool DocumentContentOperationsManager::Overwrite( const SwPaM &rRg, const OUString &rStr )
{
+ assert(rStr.getLength());
SwPosition& rPt = *const_cast<SwPosition*>(rRg.GetPoint());
if( m_rDoc.GetAutoCorrExceptWord() ) // Add to AutoCorrect
{
@@ -2382,6 +2386,7 @@ bool DocumentContentOperationsManager::Overwrite( const SwPaM &rRg, const OUStri
? pNode->GetpSwpHints()->Count() : 0;
SwDataChanged aTmp( rRg );
SwIndex& rIdx = rPt.nContent;
+ sal_Int32 const nActualStart(rIdx.GetIndex());
sal_Int32 nStart = 0;
bool bOldExpFlg = pNode->IsIgnoreDontExpand();
@@ -2443,14 +2448,14 @@ bool DocumentContentOperationsManager::Overwrite( const SwPaM &rRg, const OUStri
if (!m_rDoc.GetIDocumentUndoRedo().DoesUndo() &&
!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
{
- SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
+ SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, rPt.nContent.GetIndex());
m_rDoc.getIDocumentRedlineAccess().DeleteRedline( aPam, true, USHRT_MAX );
}
else if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
{
// FIXME: this redline is WRONG: there is no DELETE, and the skipped
// characters are also included in aPam
- SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
+ SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, rPt.nContent.GetIndex());
m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
}
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index db1dcabb5d80..349ecad51cda 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -82,6 +82,8 @@ using namespace com::sun::star;
for(SwRangeRedline* j : rTable)
{
// check for empty redlines
+ // note: these can destroy sorting in SwTextNode::Update()
+ // if there's another one wihout mark on the same pos.
OSL_ENSURE( ( *(j->GetPoint()) != *(j->GetMark()) ) ||
( j->GetContentIdx() != nullptr ),
ERROR_PREFIX "empty redline" );
More information about the Libreoffice-commits
mailing list