sw/inc/ndtxt.hxx | 2 + sw/qa/extras/uiwriter/data/tdf150824.fodt | 48 ++++++++++++++++++++++++++++++ sw/qa/extras/uiwriter/uiwriter5.cxx | 36 ++++++++++++++++++++++ sw/source/core/doc/docredln.cxx | 43 ++++++++++++++++++++------ 4 files changed, 118 insertions(+), 11 deletions(-)
New commits: commit 4d3d1527c4cf8ab6675d42d02cf313796398b220 Author: László Németh <nem...@numbertext.org> AuthorDate: Fri May 5 14:44:11 2023 +0200 Commit: László Németh <nem...@numbertext.org> CommitDate: Mon May 8 13:33:51 2023 +0200 tdf#147180 sw: fix lost change tracking of empty rows during partitionating the redline of a tracked text containing tables. Empty tracked table rows use a dummy redline to store tracking data. Insert this, when tracked tables in a single redline are partitionated after modifying its text content, deleting its rows, or using tabulator to move cursor in the next cell. Follow-up to commit a9cf949efcfdb9eb459cabe1b9e15f993e789c73 "tdf#147180 sw: fix lost change tracking of modified tables". Tests: 1) Load a tracked empty table, and insert a character in the first cell; 2) Insert a tracked empty table with multiple rows, and insert two paragraphs in the first cell; 3) Insert a tracked empty table with multiple rows, and delete the first row. 4. Insert a tracked empty table with multiple rows, insert a character and press tabulator (which triggers partitionating as a new regression). Change-Id: I8bf0f6b201a892a4f54d0bcdde33de440e5be67b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151425 Tested-by: Jenkins Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index a22d1afeb2c1..c16a643ec76c 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -278,6 +278,8 @@ public: OUString InsertText( const OUString & rStr, const SwPosition & rIdx, const SwInsertFlags nMode = SwInsertFlags::DEFAULT ); + /// Add a dummy character to the redline of the table changes + void InsertDummy() { m_Text = OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR); } /** delete text content ATTENTION: must not be called with a range that overlaps the start of diff --git a/sw/qa/extras/uiwriter/data/tdf150824.fodt b/sw/qa/extras/uiwriter/data/tdf150824.fodt new file mode 100644 index 000000000000..c1e437a12198 --- /dev/null +++ b/sw/qa/extras/uiwriter/data/tdf150824.fodt @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:c alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns: meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:body> + <office:text> + <text:tracked-changes text:track-changes="false"> + <text:changed-region xml:id="ct94228217946240" text:id="ct94228217946240"> + <text:insertion> + <office:change-info> + <dc:creator>Unknown Author</dc:creator> + <dc:date>2022-09-06T14:47:25</dc:date> + </office:change-info> + </text:insertion> + </text:changed-region> + </text:tracked-changes> + <text:change-start text:change-id="ct94228217946240"/> + <table:table table:name="Table1" table:style-name="Table1"> + <table:table-column table:style-name="Table1.A"/> + <table:table-column table:style-name="Table1.B"/> + <table:table-row> + <table:table-cell table:style-name="Table1.A1" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + <table:table-cell table:style-name="Table1.B1" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + </table:table-row> + <table:table-row> + <table:table-cell table:style-name="Table1.A2" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + <table:table-cell table:style-name="Table1.B2" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + </table:table-row> + <table:table-row> + <table:table-cell table:style-name="Table1.A2" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + <table:table-cell table:style-name="Table1.B2" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + </table:table-row> + </table:table> + <text:p text:style-name="Standard"><text:change-end text:change-id="ct94228217946240"/></text:p> + </office:text> + </office:body> +</office:document> diff --git a/sw/qa/extras/uiwriter/uiwriter5.cxx b/sw/qa/extras/uiwriter/uiwriter5.cxx index ec2d8386d711..ee7c041b78c5 100644 --- a/sw/qa/extras/uiwriter/uiwriter5.cxx +++ b/sw/qa/extras/uiwriter/uiwriter5.cxx @@ -2417,6 +2417,42 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf147180) CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables->getCount()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf147180_empty_rows) +{ + // load a tracked table insertion (single redline) with empty rows + createSwDoc("tdf150824.fodt"); + SwDoc* pDoc = getSwDoc(); + + // turn on red-lining and show changes + pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete + | RedlineFlags::ShowInsert); + CPPUNIT_ASSERT_MESSAGE("redlining should be on", + pDoc->getIDocumentRedlineAccess().IsRedlineOn()); + CPPUNIT_ASSERT_MESSAGE( + "redlines should be visible", + IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags())); + + uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), + uno::UNO_QUERY); + // there is a table in the text + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount()); + + // insert a character in the first cell with change tracking + SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("x"); + + // reject all the changes, including table insertion + + IDocumentRedlineAccess& rIDRA(pDoc->getIDocumentRedlineAccess()); + rIDRA.AcceptAllRedline(/*bAccept=*/false); + + // no table left in the text + + // This was 1 (lost tracking of the empty rows after modifying table text content) + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables->getCount()); +} + CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf128335) { // Load the bugdoc, which has 3 textboxes. diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx index 5987667a26b3..54d853065629 100644 --- a/sw/source/core/doc/docredln.cxx +++ b/sw/source/core/doc/docredln.cxx @@ -530,6 +530,16 @@ std::vector<std::unique_ptr<SwRangeRedline>> GetAllValidRanges(std::unique_ptr<S } while( pTab ); // If there is another table we have to repeat our step backwards } + // insert dummy character to the empty table rows to keep their changes + SwNode& rBoxNode = pNew->GetMark()->GetNode(); + if ( rBoxNode.GetDoc().GetIDocumentUndoRedo().DoesUndo() && rBoxNode.GetTableBox() && + rBoxNode.GetTableBox()->GetUpper()->IsEmpty() && rBoxNode.GetTextNode() ) + { + ::sw::UndoGuard const undoGuard(rBoxNode.GetDoc().GetIDocumentUndoRedo()); + rBoxNode.GetTextNode()->InsertDummy(); + pNew->GetMark()->SetContent( 1 ); + } + if( *pNew->GetPoint() > *pEnd ) { pC = nullptr; @@ -582,11 +592,32 @@ std::vector<std::unique_ptr<SwRangeRedline>> GetAllValidRanges(std::unique_ptr<S } // namespace sw +static void lcl_setRowNotTracked(SwNode& rNode) +{ + SwDoc& rDoc = rNode.GetDoc(); + if ( rDoc.GetIDocumentUndoRedo().DoesUndo() && rNode.GetTableBox() ) + { + SvxPrintItem aSetTracking(RES_PRINT, false); + SwNodeIndex aInsPos( *(rNode.GetTableBox()->GetSttNd()), 1); + SwCursor aCursor( SwPosition(aInsPos), nullptr ); + ::sw::UndoGuard const undoGuard(rNode.GetDoc().GetIDocumentUndoRedo()); + rDoc.SetRowNotTracked( aCursor, aSetTracking ); + } +} + bool SwRedlineTable::InsertWithValidRanges(SwRangeRedline*& p, size_type* pInsPos) { bool bAnyIns = false; + bool bInsert = RedlineType::Insert == p->GetType(); + SwNode* pSttNode = &p->Start()->GetNode(); + std::vector<std::unique_ptr<SwRangeRedline>> redlines( GetAllValidRanges(std::unique_ptr<SwRangeRedline>(p))); + + // tdf#147180 set table change tracking in the empty row with text insertion + if ( bInsert ) + lcl_setRowNotTracked(*pSttNode); + for (std::unique_ptr<SwRangeRedline> & pRedline : redlines) { assert(pRedline->HasValidRange()); @@ -595,17 +626,7 @@ bool SwRedlineTable::InsertWithValidRanges(SwRangeRedline*& p, size_type* pInsPo if (Insert(pTmpRedline, nInsPos)) { // tdf#147180 set table tracking to the table row - // TODO handle also empty rows - SwDoc& rDoc = pTmpRedline->GetDoc(); - if ( rDoc.GetIDocumentUndoRedo().DoesUndo() && - pTmpRedline->GetPointNode().GetTableBox() ) - { - SvxPrintItem aSetTracking(RES_PRINT, false); - SwNodeIndex aInsPos( *(pTmpRedline->GetPointNode().GetTableBox()->GetSttNd()), 1); - SwCursor aCursor( SwPosition(aInsPos), nullptr ); - ::sw::UndoGuard const undoGuard(pTmpRedline->GetDoc().GetIDocumentUndoRedo()); - rDoc.SetRowNotTracked( aCursor, aSetTracking ); - } + lcl_setRowNotTracked(pTmpRedline->GetPointNode()); pTmpRedline->CallDisplayFunc(nInsPos); bAnyIns = true;