summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLászló Németh <nemeth@numbertext.org>2021-06-03 12:13:49 +0200
committerLászló Németh <nemeth@numbertext.org>2021-06-03 19:10:59 +0200
commit896c2199d9f0a28bd405dd2d1068f5e2973cdf06 (patch)
tree240ddbe66c7282f8bfd1d66ee01cebafce098354
parent06a983b213b8fb71fdac1004868d7b4fdd6a9833 (diff)
tdf#79069 DOCX: support tracked table (row) deletion
Only DOCX round-trip was supported for tracked table and table row deletions. Now change tracking of newly deleted tables and table rows is exported in DOCX. Also the DOCX import is handled by Manage Changes now: accepting the deleted ranges of a deleted row removes also the table row, not only its text content. Follow-up to commit 05366b8e6683363688de8708a3d88cf144c7a2bf "tdf#60382 sw offapi: add change tracking of table/row deletion". Change-Id: Ic02e0adbda11032acb9616c262c2fce134f6b07c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116652 Tested-by: Jenkins Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r--sw/qa/extras/uiwriter/uiwriter2.cxx59
-rw-r--r--sw/source/core/unocore/unocrsrhelper.cxx16
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx59
3 files changed, 132 insertions, 2 deletions
diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index d91c89848495..de0c06f5d6bb 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -3822,6 +3822,65 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testRedlineTableRowDeletionWithExport)
assertXPath(pXmlDoc, "//page[1]//body/tab", 0);
}
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testRedlineTableRowDeletionWithDOCXExport)
+{
+ // load a 1-row table, and delete the row with enabled change tracking:
+ // now the row is not deleted silently, but keeps the deleted cell contents,
+ // and only accepting all of them will result the deletion of the table row.
+ SwDoc* pDoc = createDoc("tdf118311.fodt");
+
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+
+ // 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 row with enabled change tracking
+ // (HasTextChangesOnly property of the row will be false)
+ dispatchCommand(mxComponent, ".uno:DeleteRows", {});
+
+ // Deleted text content with change tracking,
+ // but not table deletion
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "//page[1]//body/tab");
+
+ // Save it to a DOCX and load it back.
+ // Exporting change tracking of the row wasn't supported.
+ // Also Manage Changes for the import.
+ reload("Office Open XML Text", "tdf79069_tracked_table_deletion.docx");
+ pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pDoc = pTextDoc->GetDocShell()->GetWrtShell()->GetDoc();
+
+ // accept the deletion of the content of the first cell
+ SwEditShell* const pEditShell(pDoc->GetEditShell());
+ CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(2), pEditShell->GetRedlineCount());
+ pEditShell->AcceptRedline(0);
+
+ // table row was still not deleted
+ pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "//page[1]//body/tab");
+
+ // accept last redline
+ pEditShell->AcceptRedline(0);
+
+ // table row (and the 1-row table) was deleted finally
+ // (working export/import of HasTextChangesOnly)
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "//page[1]//body/tab", 0);
+}
+
CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf128335)
{
// Load the bugdoc, which has 3 textboxes.
diff --git a/sw/source/core/unocore/unocrsrhelper.cxx b/sw/source/core/unocore/unocrsrhelper.cxx
index 32b449b97403..58d5dbf6b11e 100644
--- a/sw/source/core/unocore/unocrsrhelper.cxx
+++ b/sw/source/core/unocore/unocrsrhelper.cxx
@@ -72,6 +72,7 @@
#include <fchrfmt.hxx>
#include <editeng/editids.hrc>
#include <editeng/flstitem.hxx>
+#include <editeng/prntitem.hxx>
#include <vcl/metric.hxx>
#include <svtools/ctrltool.hxx>
#include <sfx2/docfilt.hxx>
@@ -1388,7 +1389,8 @@ void makeTableRowRedline( SwTableLine& rTableLine,
std::u16string_view rRedlineType,
const uno::Sequence< beans::PropertyValue >& rRedlineProperties )
{
- IDocumentRedlineAccess* pRedlineAccess = &rTableLine.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess();
+ SwDoc* pDoc = rTableLine.GetFrameFormat()->GetDoc();
+ IDocumentRedlineAccess* pRedlineAccess = &pDoc->getIDocumentRedlineAccess();
RedlineType eType;
if ( rRedlineType == u"TableRowInsert" )
@@ -1398,6 +1400,18 @@ void makeTableRowRedline( SwTableLine& rTableLine,
else if ( rRedlineType == u"TableRowDelete" )
{
eType = RedlineType::TableRowDelete;
+
+ // set table row property "HasTextChangesOnly" to false
+ // to handle tracked deletion of the table row on the UI
+ const SvxPrintItem *pHasTextChangesOnlyProp =
+ rTableLine.GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
+ if ( !pHasTextChangesOnlyProp || pHasTextChangesOnlyProp->GetValue() )
+ {
+ SvxPrintItem aSetTracking(RES_PRINT, false);
+ SwPosition aPos( *rTableLine.GetTabBoxes()[0]->GetSttNd() );
+ SwCursor aCursor( aPos, nullptr );
+ pDoc->SetRowNotTracked( aCursor, aSetTracking );
+ }
}
else
{
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 1690e567fd7e..c0faa7a00fff 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -90,6 +90,7 @@
#include <editeng/editobj.hxx>
#include <editeng/keepitem.hxx>
#include <editeng/borderline.hxx>
+#include <editeng/prntitem.hxx>
#include <sax/tools/converter.hxx>
#include <svx/xdef.hxx>
#include <svx/xfillit0.hxx>
@@ -4348,7 +4349,63 @@ void DocxAttributeOutput::TableRowRedline( ww8::WW8TableNodeInfoInner::Pointer_t
const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
const SwTableLine * pTabLine = pTabBox->GetUpper();
- // search next Redline
+ // check table row property "HasTextChangesOnly" (used only for tracked deletion, yet)
+ const SwRedlineTable& aRedlineTable = m_rExport.m_rDoc.getIDocumentRedlineAccess().GetRedlineTable();
+ const SvxPrintItem *pHasTextChangesOnlyProp =
+ pTabLine->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
+ if ( !aRedlineTable.empty() && pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() )
+ {
+ // Tracked row deletion is associated to the newest redline range in the row.
+ // Search it to get the date and the mandatory author.
+ const SwTableBoxes & rBoxes = pTabLine->GetTabBoxes();
+ SwPosition aRowStart( SwNodeIndex( *rBoxes[0]->GetSttNd(), 0 ) );
+ SwPosition aRowEnd( SwNodeIndex( *rBoxes[rBoxes.size() - 1]->GetSttNd()->EndOfSectionNode(), -1 ) );
+ SwNodeIndex pEndNodeIndex(aRowEnd.nNode.GetNode());
+
+ SwRedlineTable::size_type nLastDeletion = SwRedlineTable::npos;
+ for( SwRedlineTable::size_type n = 0; n < aRedlineTable.size(); ++n )
+ {
+ const SwRangeRedline* pRedline = aRedlineTable[ n ];
+
+ if ( pRedline->Start()->nNode > pEndNodeIndex )
+ break;
+
+ if( RedlineType::Delete != pRedline->GetType() )
+ continue;
+
+ // redline is in the table row, and newer, than the previous
+ if ( aRowStart <= *pRedline->Start() )
+ {
+ if ( nLastDeletion == SwRedlineTable::npos ||
+ aRedlineTable [ nLastDeletion ]->GetRedlineData().GetTimeStamp() <
+ pRedline->GetRedlineData().GetTimeStamp() )
+ {
+ nLastDeletion = n;
+ }
+ }
+ }
+
+ if ( nLastDeletion != SwRedlineTable::npos )
+ {
+ const SwRedlineData& aRedlineData = aRedlineTable[ nLastDeletion ]->GetRedlineData();
+ // Note: all redline ranges and table row redline (with the same author and timestamp)
+ // use the same redline id in OOXML exported by MSO, but it seems, the recent solution
+ // (different IDs for different ranges, also row changes) is also portable.
+ OString aId( OString::number( m_nRedlineId++ ) );
+ const OUString &rAuthor( SW_MOD()->GetRedlineAuthor( aRedlineData.GetAuthor() ) );
+ OString aAuthor( OUStringToOString( rAuthor, RTL_TEXTENCODING_UTF8 ) );
+
+ OString aDate( DateTimeToOString( aRedlineData.GetTimeStamp() ) );
+
+ m_pSerializer->singleElementNS( XML_w, XML_del,
+ FSNS( XML_w, XML_id ), aId,
+ FSNS( XML_w, XML_author ), aAuthor,
+ FSNS( XML_w, XML_date ), aDate );
+ return;
+ }
+ }
+
+ // search next Redline (only deletion of empty rows and all insertions imported from a DOCX)
const SwExtraRedlineTable& aExtraRedlineTable = m_rExport.m_rDoc.getIDocumentRedlineAccess().GetExtraRedlineTable();
for(sal_uInt16 nCurRedlinePos = 0; nCurRedlinePos < aExtraRedlineTable.GetSize(); ++nCurRedlinePos )
{