schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 9 + sw/inc/swtable.hxx | 2 sw/qa/extras/uiwriter/uiwriter5.cxx | 85 ++++++++++++ sw/source/core/doc/DocumentRedlineManager.cxx | 15 ++ sw/source/core/layout/paintfrm.cxx | 12 + sw/source/core/table/swtable.cxx | 17 ++ sw/source/filter/xml/xmlitemm.cxx | 3 sw/source/filter/xml/xmltble.cxx | 21 ++ 8 files changed, 161 insertions(+), 3 deletions(-)
New commits: commit 1fdb056ef034109f330b79c85da39af44c3a8251 Author: László Németh <[email protected]> AuthorDate: Wed May 10 15:24:24 2023 +0200 Commit: László Németh <[email protected]> CommitDate: Thu May 11 13:52:26 2023 +0200 tdf#150673 sw tracked table column: color deletion Reset also HasTextChangesOnly property of the table cell at rejecting the deletion. Follow-up to commit f348440e17debacbcba9153e238e010e8c020bdc "tdf#146120 sw: show tracked table changes with different color". Change-Id: I7bc1643b13a54934d1538f39e0a0d4516c88fa31 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151638 Tested-by: Jenkins Reviewed-by: László Németh <[email protected]> diff --git a/sw/inc/swtable.hxx b/sw/inc/swtable.hxx index bd674486278f..0e01f1caecb5 100644 --- a/sw/inc/swtable.hxx +++ b/sw/inc/swtable.hxx @@ -552,6 +552,8 @@ public: sal_uInt16 nMaxStep ) const { return const_cast<SwTableBox*>(this)->FindEndOfRowSpan( rTable, nMaxStep ); } void RegisterToFormat( SwFormat& rFormat ) ; + // get redline type + RedlineType GetRedlineType() const; }; class SwCellFrame; diff --git a/sw/qa/extras/uiwriter/uiwriter5.cxx b/sw/qa/extras/uiwriter/uiwriter5.cxx index 52fefec9194a..4dd0a42d83c0 100644 --- a/sw/qa/extras/uiwriter/uiwriter5.cxx +++ b/sw/qa/extras/uiwriter/uiwriter5.cxx @@ -2603,6 +2603,42 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf150673_RedlineTableColumnDeletionWi pXmlDoc = parseLayoutDump(); assertXPath(pXmlDoc, "//page[1]//body/tab"); assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 1); + + // check removing HasTextChangesOnly at acceptance of the deletion + + // Undo, and delete the column without change tracking + dispatchCommand(mxComponent, ".uno:Undo", {}); + + // table column exists again + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2); + + // reject deletion, setting HasTextChangesOnly to TRUE + CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount()); + pEditShell->RejectRedline(0); + CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(0), pEditShell->GetRedlineCount()); + + // delete table column with enabled change tracking + dispatchCommand(mxComponent, ".uno:SelectColumn", {}); + dispatchCommand(mxComponent, ".uno:Delete", {}); + + // Table column still exists + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2); + + // reject the deletion of the content of the first cell + CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount()); + pEditShell->AcceptRedline(0); + + // table column is still not deleted + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf128335) diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index 8ce8a4873aab..ac0bfe547e90 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -509,6 +509,21 @@ namespace if ( !pBox ) return; + // tracked column deletion + + const SvxPrintItem *pHasBoxTextChangesOnlyProp = + pBox->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT); + // table cell property "HasTextChangesOnly" is set and its value is false + if ( bRejectDeletion && pHasBoxTextChangesOnlyProp && + !pHasBoxTextChangesOnlyProp->GetValue() ) + { + SvxPrintItem aUnsetTracking(RES_PRINT, true); + SwCursor aCursor( *pPos, nullptr ); + pPos->GetDoc().SetBoxAttr( aCursor, aUnsetTracking ); + } + + // tracked row deletion + const SwTableLine* pLine = pBox->GetUpper(); const SvxPrintItem *pHasTextChangesOnlyProp = pLine->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT); diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index c4134fbfa2ee..47e56b390712 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -6540,7 +6540,17 @@ void SwFrame::PaintSwFrameBackground( const SwRect &rRect, const SwPageFrame *pP bBack = true; } } - else if ( bBack && IsCellFrame() && !getRootFrame()->IsHideRedlines() && + else if ( IsCellFrame() && !getRootFrame()->IsHideRedlines() ) + { + RedlineType eType = static_cast<const SwCellFrame*>(this)->GetTabBox()->GetRedlineType(); + if ( RedlineType::Delete == eType || RedlineType::Insert == eType ) + { + pCol = RedlineType::Delete == eType ? COL_AUTHOR_TABLE_DEL : COL_AUTHOR_TABLE_INS; + bBack = true; + } + } + + if ( bBack && IsCellFrame() && !getRootFrame()->IsHideRedlines() && // skip cell background to show the row colored according to its tracked change RedlineType::None != static_cast<const SwRowFrame*>(GetUpper())->GetTabLine()->GetRedlineType() ) { diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx index d4881974e5df..83cb70fc0a65 100644 --- a/sw/source/core/table/swtable.cxx +++ b/sw/source/core/table/swtable.cxx @@ -2960,6 +2960,23 @@ void SwTableBox::ActualiseValueBox() } } +RedlineType SwTableBox::GetRedlineType() const +{ + const SwRedlineTable& aRedlineTable = GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable(); + if ( aRedlineTable.empty() ) + return RedlineType::None; + + // check table row property "HasTextChangesOnly", if it's defined and its value is + // false, return with RedlineType::Delete + // TODO add support for RedlineType::Insert + const SvxPrintItem *pHasTextChangesOnlyProp = + GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT); + if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() ) + return RedlineType::Delete; + + return RedlineType::None; +} + struct SwTableCellInfo::Impl { const SwTable * m_pTable; commit ffd8d20d368a885d6d786749278fa438573227a7 Author: László Németh <[email protected]> AuthorDate: Wed May 10 11:39:49 2023 +0200 Commit: László Németh <[email protected]> CommitDate: Thu May 11 13:52:16 2023 +0200 tdf#150673 sw xmloff: import/export tracked table column to OpenDocument format using <style:table-cell-properties loext:text-changes-only="false"/> Follow-up to commit 05366b8e6683363688de8708a3d88cf144c7a2bf "tdf#60382 sw offapi: add change tracking of table/row deletion" and commit 48898a72066ff9982feafebb26708c4e779fd460 "tdf#60382 sw xmloff: import/export tracked table/row deletion". Change-Id: I6fb37322056a42a6746db0e4144b0848b0754b0f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151606 Tested-by: László Németh <[email protected]> Reviewed-by: László Németh <[email protected]> diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index 5fe259dbd5e5..c0a983f46aab 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -3210,6 +3210,15 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:optional> </rng:define> + <!-- TODO no proposal --> + <rng:define name="style-table-cell-properties-attlist" combine="interleave"> + <rng:optional> + <rng:attribute name="loext:text-changes-only"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + </rng:define> + <!-- https://issues.oasis-open.org/browse/OFFICE-4108 --> <rng:define name="common-num-format-prefix-suffix-attlist" combine="interleave"> <rng:optional> diff --git a/sw/qa/extras/uiwriter/uiwriter5.cxx b/sw/qa/extras/uiwriter/uiwriter5.cxx index 38fe2143a992..52fefec9194a 100644 --- a/sw/qa/extras/uiwriter/uiwriter5.cxx +++ b/sw/qa/extras/uiwriter/uiwriter5.cxx @@ -2556,6 +2556,55 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testRedlineTableColumnDeletion) assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 1); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf150673_RedlineTableColumnDeletionWithExport) +{ + // load a table, and delete the first column with enabled change tracking: + // now the column is not deleted silently, but keeps the deleted cell contents, + // and only accepting all of them will result the deletion of the table column. + createSwDoc("tdf118311.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())); + + // check table + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + + // delete table column with enabled change tracking + // (HasTextChangesOnly property of the cell will be false) + dispatchCommand(mxComponent, ".uno:DeleteColumns", {}); + + // Deleted text content with change tracking, + // but not table deletion + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2); + + // Save it and load it back. + reload("writer8", "tdf150673_tracked_column_deletion.odt"); + pDoc = getSwDoc(); + + // accept the deletion of the content of the first cell + SwEditShell* const pEditShell(pDoc->GetEditShell()); + CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount()); + pEditShell->AcceptRedline(0); + + // first table column was deleted finally + // (working export/import of HasTextChangesOnly) + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 1); +} + CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf128335) { // Load the bugdoc, which has 3 textboxes. diff --git a/sw/source/filter/xml/xmlitemm.cxx b/sw/source/filter/xml/xmlitemm.cxx index 1d610b6a9966..a8de955916e9 100644 --- a/sw/source/filter/xml/xmlitemm.cxx +++ b/sw/source/filter/xml/xmlitemm.cxx @@ -219,7 +219,8 @@ const SvXMLItemMapEntry aTableCellItemMap[] = // RES_FOOTER // not required // RES_PRINT - // not required + // M_E_SE( STYLE, TEXT_CHANGES_ONLY, RES_PRINT, 0 ), + M_E_SE( LO_EXT, TEXT_CHANGES_ONLY, RES_PRINT, 0 ), // RES_OPAQUE // not required // RES_PROTECT diff --git a/sw/source/filter/xml/xmltble.cxx b/sw/source/filter/xml/xmltble.cxx index 4181a869ce45..31b24dc02005 100644 --- a/sw/source/filter/xml/xmltble.cxx +++ b/sw/source/filter/xml/xmltble.cxx @@ -334,9 +334,11 @@ static OUString lcl_xmltble_appendBoxPrefix(std::u16string_view rNamePrefix, false ); const SvXMLAttrContainerItem *pAttCnt = rItemSet.GetItemIfSet( RES_UNKNOWNATR_CONTAINER, false ); + const SvxPrintItem *pHasTextChangesOnly = rItemSet.GetItemIfSet( RES_PRINT, false); // empty styles have not to be exported - if( !pVertOrient && !pBrush && !pBox && !pNumFormat && !pFrameDir && !pAttCnt ) + if( !pVertOrient && !pBrush && !pBox && !pNumFormat && !pFrameDir && !pAttCnt && + !pHasTextChangesOnly ) { m_rFormatMap.try_emplace(&rFrameFormat); // empty just to enable assert return {}; @@ -357,6 +359,7 @@ static OUString lcl_xmltble_appendBoxPrefix(std::u16string_view rNamePrefix, const SwTableBoxNumFormat *pTestNumFormat = nullptr; const SvxFrameDirectionItem *pTestFrameDir = nullptr; const SvXMLAttrContainerItem *pTestAttCnt = nullptr; + const SvxPrintItem *pTestHasTextChangesOnly = rItemSet.GetItemIfSet( RES_PRINT, false); const SwFrameFormat* pTestFormat = *i; const SfxItemSet& rTestSet = pTestFormat->GetAttrSet(); if( const SwFormatVertOrient* pItem = rTestSet.GetItemIfSet( RES_VERT_ORIENT, false ) ) @@ -443,6 +446,19 @@ static OUString lcl_xmltble_appendBoxPrefix(std::u16string_view rNamePrefix, } + if( const SvxPrintItem* pItem = rTestSet.GetItemIfSet( RES_PRINT, false ) ) + { + if( !pHasTextChangesOnly ) + break; + + pTestHasTextChangesOnly = pItem; + } + else + { + if( pHasTextChangesOnly ) + continue; + } + if( pVertOrient && pVertOrient->GetVertOrient() != pTestVertOrient->GetVertOrient() ) continue; @@ -462,6 +478,9 @@ static OUString lcl_xmltble_appendBoxPrefix(std::u16string_view rNamePrefix, if( pAttCnt && ( *pAttCnt != *pTestAttCnt ) ) continue; + if( pHasTextChangesOnly && (!pHasTextChangesOnly->GetValue() != !pTestHasTextChangesOnly->GetValue()) ) + continue; + // found! auto const oName(m_rFormatMap.find(pTestFormat)->second); assert(oName);
