diff options
author | László Németh <nemeth@numbertext.org> | 2021-12-15 12:31:27 +0100 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2021-12-17 14:02:29 +0100 |
commit | 8c028b7e41e3d350d0e67005b16faf0159cc5c12 (patch) | |
tree | ded0eab6cb1caada2f74d541a464f708fff3c37d /sw | |
parent | b58dbb862296b63f3f2395c59d30fba40fa5f59f (diff) |
tdf#146244 sw: update HasTextChangesOnly in modified rows
It's not forbidden to write in rows deleted or
inserted with change tracking, also Accept/Reject
only part of the text changes here. Improve to
handle these in SwTableLine::UpdateTextChangesOnly()
by keeping property HasTextChangesOnly = false
(tracked row change) only if
1) there is an insert redline, which is the oldest redline in
the row (tracked row insertion) or
2) there is a delete redline, which is the newest redline in
the row, and no text outside of redlines, and no insert
redline in the row, i.e. whole text content is deleted
(tracked row deletion).
Also update HasTextChangesOnly table row property at accepting
SwRangeRedlines in changed table rows.
Change-Id: I426c445da760f36f718d737f34ccdb904e87aac3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126919
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/qa/extras/uiwriter/uiwriter4.cxx | 75 | ||||
-rw-r--r-- | sw/source/core/doc/DocumentRedlineManager.cxx | 16 | ||||
-rw-r--r-- | sw/source/core/docnode/ndtbl1.cxx | 4 | ||||
-rw-r--r-- | sw/source/core/table/swtable.cxx | 95 |
4 files changed, 161 insertions, 29 deletions
diff --git a/sw/qa/extras/uiwriter/uiwriter4.cxx b/sw/qa/extras/uiwriter/uiwriter4.cxx index bddc76755920..bafc66489929 100644 --- a/sw/qa/extras/uiwriter/uiwriter4.cxx +++ b/sw/qa/extras/uiwriter/uiwriter4.cxx @@ -201,6 +201,7 @@ public: void testTdf104425(); void testTdf104814(); void testTableRedlineRedoCrash(); + void testTableRemoveHasTextChangesOnly(); void testTdf66405(); void testTdf35021_tabOverMarginDemo(); void testTdf106701_tabOverMarginAutotab(); @@ -324,6 +325,7 @@ public: CPPUNIT_TEST(testTdf104425); CPPUNIT_TEST(testTdf104814); CPPUNIT_TEST(testTableRedlineRedoCrash); + CPPUNIT_TEST(testTableRemoveHasTextChangesOnly); CPPUNIT_TEST(testTdf66405); CPPUNIT_TEST(testTdf35021_tabOverMarginDemo); CPPUNIT_TEST(testTdf106701_tabOverMarginAutotab); @@ -1678,6 +1680,79 @@ void SwUiWriterTest4::testTableRedlineRedoCrash() rIDRA.AcceptAllRedline(true); } +void SwUiWriterTest4::testTableRemoveHasTextChangesOnly() +{ + //createSwDoc(DATA_DIRECTORY, "tdf91292_paraBackground.docx"); + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "TC-table-del-add.docx"); + CPPUNIT_ASSERT(pDoc); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + CPPUNIT_ASSERT(pWrtShell); + + // disable Record Changes + dispatchCommand(mxComponent, ".uno:TrackChanges", {}); + CPPUNIT_ASSERT_MESSAGE("redlining should be off", + !pDoc->getIDocumentRedlineAccess().IsRedlineOn()); + + // 4 rows in Show Changes mode + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4); + + // Accepting tracked deletions results 3 rows + IDocumentRedlineAccess& rIDRA(pDoc->getIDocumentRedlineAccess()); + rIDRA.AcceptAllRedline(/*bAccept=*/true); + Scheduler::ProcessEventsToIdle(); + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3); + + // Undo: 4 rows again + pDoc->GetIDocumentUndoRedo().Undo(); + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4); + + // Accepting again: 3 rows (Undo of HasTextChangesOnly is correct) + rIDRA.AcceptAllRedline(/*bAccept=*/true); + Scheduler::ProcessEventsToIdle(); + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3); + + // Undo: 4 rows again + pDoc->GetIDocumentUndoRedo().Undo(); + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4); + + // Move the cursor after the redline, and insert some text without change tracking + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false); + pWrtShell->Insert("X"); + + // Accepting again: 4 rows (extra text keeps the deleted row) + rIDRA.AcceptAllRedline(/*bAccept=*/true); + Scheduler::ProcessEventsToIdle(); + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4); + + // delete the extra text with change tracking: + // this resulted tracked row deletion again, because of missing + // removing of HasTextChangeOnly SwTabLine property at accepting deletions previously + + // disable Record Changes + dispatchCommand(mxComponent, ".uno:TrackChanges", {}); + CPPUNIT_ASSERT_MESSAGE("redlining should be on", + pDoc->getIDocumentRedlineAccess().IsRedlineOn()); + + dispatchCommand(mxComponent, ".uno:SwBackSpace", {}); + rIDRA.AcceptAllRedline(/*bAccept=*/true); + Scheduler::ProcessEventsToIdle(); + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + // This was 3 + assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4); +} + void SwUiWriterTest4::testTdf66405() { // Imported formula should have zero margins diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index 5211dff34147..ae5dc4c437e5 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -445,11 +445,19 @@ namespace const SvxPrintItem *pHasTextChangesOnlyProp = pLine->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT); // empty table row with property "HasTextChangesOnly" = false - if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() && - pLine->IsEmpty() ) + if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() ) { - SwCursor aCursor( *pPos, nullptr ); - pPos->GetDoc().DeleteRow( aCursor ); + if ( pLine->IsEmpty() ) + { + SwCursor aCursor( *pPos, nullptr ); + pPos->GetDoc().DeleteRow( aCursor ); + } + else + { + // update property "HasTextChangesOnly" + SwRedlineTable::size_type nPos = 0; + pLine->UpdateTextChangesOnly(nPos); + } } } diff --git a/sw/source/core/docnode/ndtbl1.cxx b/sw/source/core/docnode/ndtbl1.cxx index d7f3c5419590..f300cec48c5d 100644 --- a/sw/source/core/docnode/ndtbl1.cxx +++ b/sw/source/core/docnode/ndtbl1.cxx @@ -573,7 +573,9 @@ void SwDoc::SetRowNotTracked( const SwCursor& rCursor, const SvxPrintItem &rNew, // add a redline with invisible text CH_TXT_TRACKED_DUMMY_CHAR // (unless the table is part of a bigger deletion, where the // new redline can cause a problem) - if (!bAll && pLn->IsEmpty()) + if ( !bAll && + // HasTextChangesOnly == false, i.e. a tracked row insertion or deletion + !rNew.GetValue() && pLn->IsEmpty() ) { SwNodeIndex aInsPos( *(pLn->GetTabBoxes()[0]->GetSttNd()), 1 ); RedlineFlags eOld = getIDocumentRedlineAccess().GetRedlineFlags(); diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx index 63d60625fea9..9033fdccbac5 100644 --- a/sw/source/core/table/swtable.cxx +++ b/sw/source/core/table/swtable.cxx @@ -38,6 +38,7 @@ #include <docary.hxx> #include <frame.hxx> #include <swtable.hxx> +#include <swcrsr.hxx> #include <ndtxt.hxx> #include <tabcol.hxx> #include <tabfrm.hxx> @@ -1602,8 +1603,6 @@ SwRedlineTable::size_type SwTableLine::UpdateTextChangesOnly(SwRedlineTable::siz { SwRedlineTable::size_type nRet = SwRedlineTable::npos; const SwRedlineTable& aRedlineTable = GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable(); - if ( aRedlineTable.empty() ) - return nRet; // check table row property "HasTextChangesOnly", if it's defined and its // value is false, and all text content is in delete redlines, the row is deleted @@ -1614,7 +1613,9 @@ SwRedlineTable::size_type SwTableLine::UpdateTextChangesOnly(SwRedlineTable::siz const SwTableBoxes & rBoxes = GetTabBoxes(); size_t nBoxes = rBoxes.size(); bool bInsertion = false; - + bool bPlainTextInLine = false; + SwRedlineTable::size_type nOldestRedline = SwRedlineTable::npos; + SwRedlineTable::size_type nNewestRedline = SwRedlineTable::npos; for (size_t nBoxIndex = 0; nBoxIndex < nBoxes && rRedlinePos < aRedlineTable.size(); ++nBoxIndex) { auto pBox = rBoxes[nBoxIndex]; @@ -1624,10 +1625,11 @@ SwRedlineTable::size_type SwTableLine::UpdateTextChangesOnly(SwRedlineTable::siz continue; } - bool bHasRedline = false; + bool bHasRedlineInBox = false; SwPosition aCellStart( SwNodeIndex( *pBox->GetSttNd(), 0 ) ); SwPosition aCellEnd( SwNodeIndex( *pBox->GetSttNd()->EndOfSectionNode(), -1 ) ); SwNodeIndex pEndNodeIndex(aCellEnd.nNode.GetNode()); + SwRangeRedline* pPreviousDeleteRedline = nullptr; for( ; rRedlinePos < aRedlineTable.size(); ++rRedlinePos ) { const SwRangeRedline* pRedline = aRedlineTable[ rRedlinePos ]; @@ -1642,42 +1644,87 @@ SwRedlineTable::size_type SwTableLine::UpdateTextChangesOnly(SwRedlineTable::siz // redline in the cell if ( aCellStart <= *pRedline->Start() ) { - bHasRedline = true; + if ( !bHasRedlineInBox ) + { + bHasRedlineInBox = true; + // plain text before the first redline in the text + if ( pRedline->Start()->nContent.GetIndex() > 0 ) + bPlainTextInLine = true; + } + RedlineType nType = pRedline->GetType(); // first insert redline - if ( !bInsertion && RedlineType::Insert == nType ) + if ( !bInsertion ) { - bInsertion = true; - nRet = rRedlinePos; - continue; - // TODO check older delete redlines to remove row change, if needed + if ( RedlineType::Insert == nType ) + { + bInsertion = true; + } + else + { + // plain text between the delete redlines + if ( pPreviousDeleteRedline && + *pPreviousDeleteRedline->End() < *pRedline->Start() ) + { + bPlainTextInLine = true; + } + pPreviousDeleteRedline = const_cast<SwRangeRedline*>(pRedline); + } } - // search newest deletion or oldest insertion - if ( ( !bInsertion && RedlineType::Delete == nType && - ( nRet == SwRedlineTable::npos || - aRedlineTable[nRet]->GetRedlineData().GetTimeStamp() < - pRedline->GetRedlineData().GetTimeStamp() ) ) || - ( bInsertion && RedlineType::Insert == nType && - ( nRet == SwRedlineTable::npos || - aRedlineTable[nRet]->GetRedlineData().GetTimeStamp() > - pRedline->GetRedlineData().GetTimeStamp() ) ) ) + // search newest and oldest redlines + if ( nNewestRedline == SwRedlineTable::npos || + aRedlineTable[nNewestRedline]->GetRedlineData().GetTimeStamp() < + pRedline->GetRedlineData().GetTimeStamp() ) { - nRet = rRedlinePos; + nNewestRedline = rRedlinePos; + } + if ( nOldestRedline == SwRedlineTable::npos || + aRedlineTable[nOldestRedline]->GetRedlineData().GetTimeStamp() > + pRedline->GetRedlineData().GetTimeStamp() ) + { + nOldestRedline = rRedlinePos; } } } - if ( !bHasRedline && !bInsertion ) + // there is text content outside of redlines: not a deletion + if ( !bInsertion && ( !bHasRedlineInBox || ( pPreviousDeleteRedline && + ( pPreviousDeleteRedline->End()->nNode < aCellEnd.nNode || + pPreviousDeleteRedline->End()->nContent.GetIndex() < + aCellEnd.nNode.GetNode().GetContentNode()->Len() ) ) ) ) { + bPlainTextInLine = true; // not deleted cell content: the row is not empty // maybe insertion of a row, try to search it bInsertion = true; - // drop collected deletion - nRet = SwRedlineTable::npos; } - // TODO: check also text outside of the redlines + } + + // choose return redline, if it exists or remove changed row attribute + if ( bInsertion && SwRedlineTable::npos != nOldestRedline && + RedlineType::Insert == aRedlineTable[ nOldestRedline ]->GetType() ) + { + // there is an insert redline, which is the oldest redline in the row + nRet = nOldestRedline; + } + else if ( !bInsertion && !bPlainTextInLine && SwRedlineTable::npos != nNewestRedline && + RedlineType::Delete == aRedlineTable[ nNewestRedline ]->GetType() ) + { + // there is a delete redline, which is the newest redline in the row, + // and no text outside of redlines, and no insert redline in the row, + // i.e. whole text content is deleted + nRet = nNewestRedline; + } + else + { + // no longer tracked row insertion or deletion + nRet = SwRedlineTable::npos; + // set TextChangesOnly = true to remove the tracked deletion + SvxPrintItem aUnsetTracking(RES_PRINT, true); + SwFrameFormat *pNew = const_cast<SwTableLine*>(this)->ClaimFrameFormat(); + pNew->SetFormatAttr( aUnsetTracking ); } } |