sw/qa/extras/uiwriter/uiwriter2.cxx          |   59 ++++++++++++++++++++++++++
 sw/source/core/unocore/unocrsrhelper.cxx     |   16 ++++++-
 sw/source/filter/ww8/docxattributeoutput.cxx |   60 ++++++++++++++++++++++++++-
 3 files changed, 133 insertions(+), 2 deletions(-)

New commits:
commit e04725c24b8f3ab6a6e1daf70be5fc7e2b9cbc1f
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Thu Jun 3 12:13:49 2021 +0200
Commit:     Gabor Kelemen <kelemen.gab...@nisz.hu>
CommitDate: Thu Aug 19 21:07:18 2021 +0200

    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 <nem...@numbertext.org>
    (cherry picked from commit 896c2199d9f0a28bd405dd2d1068f5e2973cdf06)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120723
    Tested-by: Gabor Kelemen <kelemen.gab...@nisz.hu>
    Reviewed-by: Gabor Kelemen <kelemen.gab...@nisz.hu>

diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx 
b/sw/qa/extras/uiwriter/uiwriter2.cxx
index ebe526a4ffc8..3bd70a0d970a 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -3543,6 +3543,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 8c09a63113fa..f18f05a5f02f 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>
@@ -1390,7 +1391,8 @@ void makeTableRowRedline( SwTableLine& rTableLine,
     const OUString& 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 == "TableRowInsert" )
@@ -1400,6 +1402,18 @@ void makeTableRowRedline( SwTableLine& rTableLine,
     else if ( rRedlineType == "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 585c58142e08..c8aa253c1d30 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -89,6 +89,8 @@
 #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>
 #include <svx/xflclit.hxx>
@@ -4309,7 +4311,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 )
     {

Reply via email to