Kaydet (Commit) 5a80701d authored tarafından Michael Stahl's avatar Michael Stahl Kaydeden (comit) Thorsten Behrens

tdf#109376 sw: fix redline SwUndoDelete with end pos on SwTableNode crash

... that happens when you accept a delete redline (or reject an insert
redline) with such end pos.

The problem is that first a DeleteRange() will move the anchor position
onto the table node (because check in SwUndoSaveContent::DelContentIndex()
is surprisingly asymmetric and so the fly not deleted by the previous
bugfix), then DelFullPara() creates a second SwUndoDelete then deleting
the fly crashes because its anchors was moved.

The code in lcl_AcceptRedline() / lcl_RejectRedline() doesn't make much
sense (but always was like this), if we just call DeleteFullPara() once
instead, the problem is avoided, and we don't even have to worry about
why DelContentIndex() is so asymmetric (is "selection direction"
really a meaningful concept?).

Reportedly this started to crash with commit
e07feb94, previously it was just wrong.

Change-Id: Ib3d4b31e0255a6f4e7b49b40f204dec168ea3006
Reviewed-on: https://gerrit.libreoffice.org/70836
Tested-by: Jenkins
Reviewed-by: 's avatarMichael Stahl <Michael.Stahl@cib.de>
(cherry picked from commit f83e22f5)
Reviewed-on: https://gerrit.libreoffice.org/70865Tested-by: 's avatarXisco Faulí <xiscofauli@libreoffice.org>
Reviewed-by: 's avatarThorsten Behrens <Thorsten.Behrens@CIB.de>
üst ca0ac393
...@@ -39,6 +39,7 @@ public: ...@@ -39,6 +39,7 @@ public:
void testRedlineInHiddenSection(); void testRedlineInHiddenSection();
void testTdf101534(); void testTdf101534();
void testTdf54819(); void testTdf54819();
void testTdf109376_redline();
void testTdf109376(); void testTdf109376();
void testTdf108687_tabstop(); void testTdf108687_tabstop();
void testTdf119571(); void testTdf119571();
...@@ -55,6 +56,7 @@ public: ...@@ -55,6 +56,7 @@ public:
CPPUNIT_TEST(testRedlineInHiddenSection); CPPUNIT_TEST(testRedlineInHiddenSection);
CPPUNIT_TEST(testTdf101534); CPPUNIT_TEST(testTdf101534);
CPPUNIT_TEST(testTdf54819); CPPUNIT_TEST(testTdf54819);
CPPUNIT_TEST(testTdf109376_redline);
CPPUNIT_TEST(testTdf109376); CPPUNIT_TEST(testTdf109376);
CPPUNIT_TEST(testTdf108687_tabstop); CPPUNIT_TEST(testTdf108687_tabstop);
CPPUNIT_TEST(testTdf119571); CPPUNIT_TEST(testTdf119571);
...@@ -255,6 +257,57 @@ void SwUiWriterTest2::testTdf54819() ...@@ -255,6 +257,57 @@ void SwUiWriterTest2::testTdf54819()
getProperty<OUString>(getParagraph(1), "ParaStyleName")); getProperty<OUString>(getParagraph(1), "ParaStyleName"));
} }
void SwUiWriterTest2::testTdf109376_redline()
{
SwDoc* pDoc = createDoc();
SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
CPPUNIT_ASSERT(pWrtShell);
// need 2 paragraphs to get to the bMoveNds case
pWrtShell->Insert("foo");
pWrtShell->SplitNode();
pWrtShell->Insert("bar");
pWrtShell->SplitNode();
pWrtShell->StartOfSection(false);
// add AT_PARA fly at 1st to be deleted node
SwFormatAnchor anchor(RndStdIds::FLY_AT_PARA);
anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
SfxItemSet flySet(pDoc->GetAttrPool(),
svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
flySet.Put(anchor);
SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
flySet.Put(size); // set a size, else we get 1 char per line...
SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
CPPUNIT_ASSERT(pFly != nullptr);
pWrtShell->SttEndDoc(false);
SwInsertTableOptions tableOpt(SwInsertTableFlags::DefaultBorder, 0);
const SwTable& rTable = pWrtShell->InsertTable(tableOpt, 1, 1);
pWrtShell->StartOfSection(false);
SwPaM pam(*pWrtShell->GetCursor()->GetPoint());
pam.SetMark();
pam.GetPoint()->nNode = *rTable.GetTableNode();
pam.GetPoint()->nContent.Assign(nullptr, 0);
pam.Exchange(); // same selection direction as in doc compare...
IDocumentRedlineAccess& rIDRA(pDoc->getIDocumentRedlineAccess());
rIDRA.SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowInsert | RedlineFlags::ShowDelete);
rIDRA.AppendRedline(new SwRangeRedline(nsRedlineType_t::REDLINE_DELETE, pam), true);
// this used to assert/crash with m_pAnchoredFlys mismatch because the
// fly was not deleted but its anchor was moved to the SwTableNode
rIDRA.AcceptAllRedline(true);
CPPUNIT_ASSERT_EQUAL(size_t(0), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
rUndoManager.Undo();
CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
rUndoManager.Redo();
CPPUNIT_ASSERT_EQUAL(size_t(0), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
rUndoManager.Undo();
CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
}
void SwUiWriterTest2::testTdf109376() void SwUiWriterTest2::testTdf109376()
{ {
SwDoc* pDoc = createDoc(); SwDoc* pDoc = createDoc();
......
...@@ -422,17 +422,15 @@ namespace ...@@ -422,17 +422,15 @@ namespace
if( pCSttNd && pCEndNd ) if( pCSttNd && pCEndNd )
rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
else else if (pCSttNd && !pCEndNd)
{
rDoc.getIDocumentContentOperations().DeleteRange( aPam );
if( pCSttNd && !pCEndNd )
{ {
aPam.GetBound().nContent.Assign( nullptr, 0 ); aPam.GetBound().nContent.Assign( nullptr, 0 );
aPam.GetBound( false ).nContent.Assign( nullptr, 0 ); aPam.GetBound( false ).nContent.Assign( nullptr, 0 );
aPam.DeleteMark();
rDoc.getIDocumentContentOperations().DelFullPara( aPam ); rDoc.getIDocumentContentOperations().DelFullPara( aPam );
} }
else
{
rDoc.getIDocumentContentOperations().DeleteRange(aPam);
} }
rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
} }
...@@ -536,17 +534,15 @@ namespace ...@@ -536,17 +534,15 @@ namespace
if( pCSttNd && pCEndNd ) if( pCSttNd && pCEndNd )
rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
else else if (pCSttNd && !pCEndNd)
{
rDoc.getIDocumentContentOperations().DeleteRange( aPam );
if( pCSttNd && !pCEndNd )
{ {
aPam.GetBound().nContent.Assign( nullptr, 0 ); aPam.GetBound().nContent.Assign( nullptr, 0 );
aPam.GetBound( false ).nContent.Assign( nullptr, 0 ); aPam.GetBound( false ).nContent.Assign( nullptr, 0 );
aPam.DeleteMark();
rDoc.getIDocumentContentOperations().DelFullPara( aPam ); rDoc.getIDocumentContentOperations().DelFullPara( aPam );
} }
else
{
rDoc.getIDocumentContentOperations().DeleteRange(aPam);
} }
rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment