offapi/com/sun/star/text/CellProperties.idl   |    6 +
 sw/qa/extras/uiwriter/uiwriter5.cxx           |  103 ++++++++++++++++++++++++++
 sw/source/core/bastyp/init.cxx                |    4 -
 sw/source/core/doc/DocumentRedlineManager.cxx |   28 ++++++-
 sw/source/core/frmedt/fetab.cxx               |   49 +++++++++++-
 sw/source/core/unocore/unomap.cxx             |    1 
 6 files changed, 185 insertions(+), 6 deletions(-)

New commits:
commit d1004cdd6a445ae73673b0ca360ae034b0ec09f2
Author:     László Németh <[email protected]>
AuthorDate: Tue May 9 16:51:06 2023 +0200
Commit:     László Németh <[email protected]>
CommitDate: Thu May 11 13:51:47 2023 +0200

    tdf#150673 sw offapi: add change tracking of table column deletion
    
    This is a minimal extension of the text range based change
    tracking to record and apply table column deletions with full
    Undo/Redo support.
    
    Add property HasTextChangesOnly to com::sun::star::text::CellProperties.
    
    During recording of track changes, deletion of table columns wasn't
    recorded: columns were removed completely with their text content.
    Now the deletion deletes the cell content with change tracking,
    setting also HasTextChangesOnly property of table cells to FALSE. If
    a tracked deletion is accepted in a deleted column, and the result
    is an empty cell, the column will be removed, if HasTextChangesOnly
    property of the deleted cell is FALSE.
    
    Note: Deletion of empty columns isn't recorded. Hiding deleted
    columns hasn't been supported yet in the Hide Changes mode.
    
    Follow-up to commit 05366b8e6683363688de8708a3d88cf144c7a2bf
    "tdf#60382 sw offapi: add change tracking of table/row deletion".
    
    Change-Id: I36915d7a58f66b4a3bdaf90495cb998d29c36561
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151593
    Tested-by: Jenkins
    Reviewed-by: László Németh <[email protected]>

diff --git a/offapi/com/sun/star/text/CellProperties.idl 
b/offapi/com/sun/star/text/CellProperties.idl
index 2448c25c8439..58c9718c0dc2 100644
--- a/offapi/com/sun/star/text/CellProperties.idl
+++ b/offapi/com/sun/star/text/CellProperties.idl
@@ -130,6 +130,12 @@ published service CellProperties
         @since LibreOffice 6.3
      */
     [optional, readonly, property] com::sun::star::text::XText ParentText;
+
+    /** If TRUE, the table cell wasn't deleted or inserted with its tracked 
cell content
+
+        @since LibreOffice 7.6
+     */
+    [optional, property, maybevoid] boolean HasTextChangesOnly;
 };
 
 
diff --git a/sw/qa/extras/uiwriter/uiwriter5.cxx 
b/sw/qa/extras/uiwriter/uiwriter5.cxx
index ee7c041b78c5..38fe2143a992 100644
--- a/sw/qa/extras/uiwriter/uiwriter5.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter5.cxx
@@ -2453,6 +2453,109 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, 
testTdf147180_empty_rows)
     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables->getCount());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testRedlineTableColumnDeletion)
+{
+    // load a table, and delete the first column with enabled change tracking:
+    // now the column is not deleted silently, but keeps the deleted cell 
content,
+    // and only accepting it 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");
+    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
+
+    // delete table column with enabled change tracking
+    // (HasTextChangesOnly property of the cell will be false)
+    dispatchCommand(mxComponent, ".uno:DeleteColumns", {});
+
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab");
+    // This was 1 (deleted cell without change tracking)
+    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
+
+    // accept the deletion
+    SwEditShell* const pEditShell(pDoc->GetEditShell());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), 
pEditShell->GetRedlineCount());
+    pEditShell->AcceptRedline(0);
+
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab");
+    // deleted column
+    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 1);
+
+    // Undo, and repeat the previous test, but only with deletion of the text 
content of the cells
+    // (HasTextChangesOnly property will be removed by Undo)
+
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+
+    // first column exists again
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab");
+    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
+
+    // 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);
+
+    // accept 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 was still not deleted
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab");
+    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
+
+    // Undo, and delete the column without change tracking
+
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+
+    // table exists again
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab");
+    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
+
+    // disable change tracking
+    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::ShowDelete
+                                                      | 
RedlineFlags::ShowInsert);
+
+    CPPUNIT_ASSERT_MESSAGE("redlining should be off",
+                           !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+
+    // delete table column without change tracking
+    dispatchCommand(mxComponent, ".uno:DeleteColumns", {});
+
+    // the table column was deleted
+    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/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx
index a5bcd736966e..f2a4d974cfa1 100644
--- a/sw/source/core/bastyp/init.cxx
+++ b/sw/source/core/bastyp/init.cxx
@@ -204,8 +204,8 @@ WhichRangesContainer const aTableSetRange(svl::Items<
 
 WhichRangesContainer const aTableLineSetRange(svl::Items<
     RES_FILL_ORDER,     RES_FRM_SIZE,
-    // HasTextChangesOnly
     RES_LR_SPACE,       RES_UL_SPACE,
+    // HasTextChangesOnly
     RES_PRINT,          RES_PRINT,
     RES_PROTECT,        RES_PROTECT,
     RES_VERT_ORIENT,    RES_VERT_ORIENT,
@@ -218,6 +218,8 @@ WhichRangesContainer const aTableLineSetRange(svl::Items<
 WhichRangesContainer const aTableBoxSetRange(svl::Items<
     RES_FILL_ORDER,     RES_FRM_SIZE,
     RES_LR_SPACE,       RES_UL_SPACE,
+    // HasTextChangesOnly
+    RES_PRINT,          RES_PRINT,
     RES_PROTECT,        RES_PROTECT,
     RES_VERT_ORIENT,    RES_VERT_ORIENT,
     RES_BACKGROUND,     RES_SHADOW,
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index 4e9176cc340a..8ce8a4873aab 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -457,6 +457,30 @@ namespace
         if ( !pBox )
             return;
 
+        // tracked column deletion
+
+        const SvxPrintItem *pHasBoxTextChangesOnlyProp =
+                
pBox->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
+        // empty table cell with property "HasTextChangesOnly" = false
+        if ( pHasBoxTextChangesOnlyProp && 
!pHasBoxTextChangesOnlyProp->GetValue() )
+        {
+            SwCursor aCursor( *pPos, nullptr );
+            if ( pBox->IsEmpty() )
+            {
+                // TODO check the other cells of the column
+                // before removing the column
+                pPos->GetDoc().DeleteCol( aCursor );
+                return;
+            }
+            else
+            {
+                SvxPrintItem aHasTextChangesOnly(RES_PRINT, false);
+                pPos->GetDoc().SetBoxAttr( aCursor, aHasTextChangesOnly );
+            }
+        }
+
+        // tracked row deletion
+
         const SwTableLine* pLine = pBox->GetUpper();
         const SvxPrintItem *pHasTextChangesOnlyProp =
                 
pLine->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
@@ -2330,9 +2354,9 @@ DocumentRedlineManager::AppendRedline(SwRangeRedline* 
pNewRedl, bool const bCall
                     {
                         if ( aSttIdx.GetNode().IsTableNode() )
                         {
-                            SvxPrintItem aNotTracked(RES_PRINT, false);
+                            SvxPrintItem aHasTextChangesOnly(RES_PRINT, false);
                             SwCursor aCursor( SwPosition(aSttIdx), nullptr );
-                            m_rDoc.SetRowNotTracked( aCursor, aNotTracked, 
/*bAll=*/true );
+                            m_rDoc.SetRowNotTracked( aCursor, 
aHasTextChangesOnly, /*bAll=*/true );
                         }
                         ++aSttIdx;
                     }
diff --git a/sw/source/core/frmedt/fetab.cxx b/sw/source/core/frmedt/fetab.cxx
index c51413e3ba9b..daca7b86bc9c 100644
--- a/sw/source/core/frmedt/fetab.cxx
+++ b/sw/source/core/frmedt/fetab.cxx
@@ -276,6 +276,49 @@ bool SwFEShell::DeleteCol()
     }
 
     CurrShell aCurr( this );
+
+    // tracked deletion: remove only textbox content,
+    // and set IsNoTracked table box property to false
+    if ( GetDoc()->GetDocShell()->IsChangeRecording() )
+    {
+        StartUndo(SwUndoId::COL_DELETE);
+        StartAllAction();
+
+        if ( SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(this) )
+            pWrtShell->SelectTableCol();
+
+        // search boxes via the layout
+        SwSelBoxes aBoxes;
+        GetTableSel( *this, aBoxes, SwTableSearchType::Col );
+
+        TableWait aWait( 20, pFrame, *GetDoc()->GetDocShell(), aBoxes.size() );
+
+        for (size_t i = 0; i < aBoxes.size(); ++i)
+        {
+            SwTableBox *pBox = aBoxes[i];
+            if ( pBox->GetSttNd() )
+            {
+                SwNodeIndex aIdx( *pBox->GetSttNd(), 1 );
+                SwCursor aCursor( SwPosition(aIdx), nullptr );
+                SvxPrintItem aHasTextChangesOnly(RES_PRINT, false);
+                GetDoc()->SetBoxAttr( aCursor, aHasTextChangesOnly );
+            }
+        }
+
+        SwEditShell* pEditShell = GetDoc()->GetEditShell();
+        SwRedlineTable::size_type nPrev = pEditShell->GetRedlineCount();
+        pEditShell->Delete();
+
+        EndAllActionAndCall();
+        EndUndo(SwUndoId::COL_DELETE);
+
+        // track column deletion only if there were tracked text changes
+        // FIXME redline count can be the same in special cases, e.g. adding a
+        // new tracked deletion with removing an own tracked insertion...
+        if ( nPrev != pEditShell->GetRedlineCount() )
+            return true;
+    }
+
     StartAllAction();
 
     // search boxes via the layout
@@ -349,11 +392,11 @@ bool SwFEShell::DeleteRow(bool bCompleteTable)
     StartAllAction();
 
     // tracked deletion: remove only textbox content,
-    // and set IsNoTracked table line property to false
+    // and set HasTextChangesOnly table line property to false
     if ( bRecordChanges )
     {
-        SvxPrintItem aNotTracked(RES_PRINT, false);
-        GetDoc()->SetRowNotTracked( *getShellCursor( false ), aNotTracked );
+        SvxPrintItem aHasTextChangesOnly(RES_PRINT, false);
+        GetDoc()->SetRowNotTracked( *getShellCursor( false ), 
aHasTextChangesOnly );
 
         if ( SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(this) )
             pWrtShell->SelectTableRow();
diff --git a/sw/source/core/unocore/unomap.cxx 
b/sw/source/core/unocore/unomap.cxx
index 40223b34e474..68565eadaf6f 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -186,6 +186,7 @@ o3tl::span<const SfxItemPropertyMapEntry> 
SwUnoPropertyMapProvider::GetPropertyM
                     { UNO_NAME_ROW_SPAN,     FN_UNO_CELL_ROW_SPAN, 
cppu::UnoType<sal_Int32>::get(),  0, 0 },
                     { UNO_NAME_CELL_INTEROP_GRAB_BAG, RES_FRMATR_GRABBAG, 
cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), 
PROPERTY_NONE, 0 },
                     { UNO_NAME_PARENT_TEXT, FN_UNO_PARENT_TEXT, 
cppu::UnoType<text::XText>::get(), PropertyAttribute::MAYBEVOID | 
PropertyAttribute::READONLY, 0 },
+                    { UNO_NAME_HAS_TEXT_CHANGES_ONLY, RES_PRINT, 
cppu::UnoType<bool>::get()  , PropertyAttribute::MAYBEVOID, 0},
                     REDLINE_NODE_PROPERTIES
                 };
                 m_aMapEntriesArr[nPropertyId] = aCellMap_Impl;

Reply via email to