[Libreoffice-commits] core.git: offapi/com sw/inc sw/qa sw/source

László Németh (via logerrit) logerrit at kemper.freedesktop.org
Wed May 19 22:02:21 UTC 2021


 offapi/com/sun/star/text/TextTableRow.idl     |    8 ++
 sw/inc/doc.hxx                                |    2 
 sw/inc/swtable.hxx                            |    2 
 sw/inc/unoprnms.hxx                           |    1 
 sw/qa/extras/uiwriter/uiwriter2.cxx           |   77 ++++++++++++++++++++++++++
 sw/source/core/bastyp/init.cxx                |    2 
 sw/source/core/doc/DocumentRedlineManager.cxx |   34 +++++++++++
 sw/source/core/docnode/ndtbl1.cxx             |   26 ++++++++
 sw/source/core/frmedt/fetab.cxx               |   30 ++++++++++
 sw/source/core/table/swtable.cxx              |   15 +++++
 sw/source/core/unocore/unomap.cxx             |    1 
 sw/source/filter/html/htmltab.cxx             |   17 -----
 12 files changed, 199 insertions(+), 16 deletions(-)

New commits:
commit 05366b8e6683363688de8708a3d88cf144c7a2bf
Author:     László Németh <nemeth at numbertext.org>
AuthorDate: Wed May 19 12:22:24 2021 +0200
Commit:     László Németh <nemeth at numbertext.org>
CommitDate: Thu May 20 00:01:37 2021 +0200

    tdf#60382 sw offapi: add change tracking of table/row deletion
    
    This is a minimal extension of the text range based change
    tracking to record and apply table row and table deletions
    with full Undo/Redo support.
    
    Add property IsNotTracked to com::sun::star::text::TextTableRow.
    
    During recording of track changes, deletion of table rows wasn't
    recorded: the rows removed completely with their text content.
    Now the deletion deletes the cell content with change tracking,
    setting also IsNotTracked property of table rows to FALSE. If
    all tracked deletions were accepted in a row, and the result is
    an empty row, the row will be removed, if its IsNotTracked
    property is FALSE.
    
    Note: Deletion of empty lines isn't recorded (they are simply
    deleted). Hiding deleted rows hasn't been supported yet in
    the Hide Changes mode.
    
    OpenDocument supports only track changes of text ranges, but
    not changes of the table structure, e.g. deletion of table
    rows. For the native export it needs to extend ODF, and
    depending on this future extension, can be based also on
    SwExtraRedlineTable (which lacks of recording and Undo/Redo,
    but supports OOXML round-trip of tracked table changes).
    See also commit d688069023959ab97d14eb1dbfd5bf6ad3c1b160
    "Add support for 'Table Row Redlines' in SW core" and its
    follow-up commits.
    
    Change-Id: I2e3807cf8ae8212bd51c210ef1c20c85878d0da8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115804
    Tested-by: László Németh <nemeth at numbertext.org>
    Reviewed-by: László Németh <nemeth at numbertext.org>

diff --git a/offapi/com/sun/star/text/TextTableRow.idl b/offapi/com/sun/star/text/TextTableRow.idl
index d640d1c06cce..77191c9f57d1 100644
--- a/offapi/com/sun/star/text/TextTableRow.idl
+++ b/offapi/com/sun/star/text/TextTableRow.idl
@@ -105,6 +105,14 @@ published service TextTableRow
         @since LibreOffice 6.1
      */
     [optional, property] com::sun::star::graphic::XGraphic BackGraphic;
+
+    /** If TRUE, the table row wasn't deleted or inserted with its tracked cell content
+
+        @since LibreOffice 7.2
+     */
+
+        [optional, property, maybevoid] boolean IsNotTracked;
+
 };
 
 
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 08510f634569..19a2b6af64b1 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -1489,6 +1489,8 @@ public:
     bool BalanceRowHeight( const SwCursor& rCursor, bool bTstOnly, const bool bOptimize );
     void SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew );
     static bool GetRowBackground( const SwCursor& rCursor, std::unique_ptr<SvxBrushItem>& rToFill );
+    /// rNotTracked = false means that the row was deleted or inserted with its tracked cell content
+    void SetRowNotTracked( const SwCursor& rCursor, const SvxPrintItem &rNotTracked );
     void SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet );
     void SetTabLineStyle( const SwCursor& rCursor,
                           const Color* pColor, bool bSetLine,
diff --git a/sw/inc/swtable.hxx b/sw/inc/swtable.hxx
index 5432a24d60e4..6696c94d6cfc 100644
--- a/sw/inc/swtable.hxx
+++ b/sw/inc/swtable.hxx
@@ -444,6 +444,8 @@ public:
     void RemoveFromTable();
     const SwStartNode *GetSttNd() const { return m_pStartNode; }
     sal_uLong GetSttIdx() const;
+    // it doesn't contain box content
+    bool IsEmpty() const;
 
     // Search next/previous box with content.
     SwTableBox* FindNextBox( const SwTable&, const SwTableBox*,
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 9cceac0f8d0f..317ad79fa8ed 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -736,6 +736,7 @@
 #define UNO_NAME_ITEMS "Items"
 #define UNO_NAME_SELITEM "SelectedItem"
 #define UNO_NAME_IS_SPLIT_ALLOWED "IsSplitAllowed"
+#define UNO_NAME_IS_NOT_TRACKED "IsNotTracked"
 #define UNO_NAME_CHAR_HIDDEN "CharHidden"
 #define UNO_NAME_IS_FOLLOWING_TEXT_FLOW "IsFollowingTextFlow"
 #define UNO_NAME_WIDTH_TYPE "WidthType"
diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index 02d8163cc95e..d1323c8104d5 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -3666,6 +3666,83 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf118311)
     assertXPath(pXmlDoc, "//page[1]//body/tab", 0);
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testRedlineTableRowDeletion)
+{
+    // 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
+    dispatchCommand(mxComponent, ".uno:DeleteRows", {});
+
+    // This was deleted without change tracking
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab");
+
+    // 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
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab");
+
+    // accept last redline
+    pEditShell->AcceptRedline(0);
+
+    // table row (and the 1-row table) was deleted finally
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab", 0);
+
+    // Undo, and delete the row without change tracking
+
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+
+    // table exists again
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    assertXPath(pXmlDoc, "//page[1]//body/tab");
+
+    // disable change tracking
+    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::ShowDelete
+                                                      | RedlineFlags::ShowInsert);
+
+    CPPUNIT_ASSERT_MESSAGE("redlining should be off",
+                           !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+
+    // delete table row without change tracking
+    dispatchCommand(mxComponent, ".uno:DeleteRows", {});
+
+    // the table (row) was deleted
+    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/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx
index 19d2f12d9a3a..f1b86f8dfdc0 100644
--- a/sw/source/core/bastyp/init.cxx
+++ b/sw/source/core/bastyp/init.cxx
@@ -206,6 +206,8 @@ sal_uInt16 const aTableSetRange[] = {
 
 sal_uInt16 const aTableLineSetRange[] = {
     RES_FILL_ORDER,     RES_FRM_SIZE,
+    // IsNotTracked
+    RES_PRINT,          RES_PRINT,
     RES_LR_SPACE,       RES_UL_SPACE,
     RES_BACKGROUND,     RES_SHADOW,
     RES_ROW_SPLIT,      RES_ROW_SPLIT,
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index 1c63619a8e1b..0e92f16034a5 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -38,6 +38,7 @@
 #include <strings.hrc>
 #include <swmodule.hxx>
 #include <osl/diagnose.h>
+#include <editeng/prntitem.hxx>
 
 using namespace com::sun::star;
 
@@ -430,6 +431,36 @@ namespace
         return nullptr;
     }
 
+    // delete the empty tracked table row (i.e. if it's last tracked deletion was accepted)
+    void lcl_DeleteTrackedTableRow ( SwPosition* pPos )
+    {
+        if ( const SwTableBox* pBox = pPos->nNode.GetNode().GetTableBox() )
+        {
+            const SwTableLine* pLine = pBox->GetUpper();
+            const SvxPrintItem *pIsNoTrackedProp =
+                    pLine->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
+            // table row property "IsNotTracked" is set and its value is false
+            if ( pIsNoTrackedProp && !pIsNoTrackedProp->GetValue() )
+            {
+                bool bEmptyLine = true;
+                const SwTableBoxes & rBoxes = pLine->GetTabBoxes();
+                for (size_t nBox = 0; nBox < rBoxes.size(); ++nBox)
+                {
+                    if ( !rBoxes[nBox]->IsEmpty() )
+                    {
+                        bEmptyLine = false;
+                        break;
+                    }
+                }
+                if ( bEmptyLine )
+                {
+                    SwCursor aCursor( *pPos, nullptr );
+                    pPos->GetDoc().DeleteRow( aCursor );
+                }
+            }
+        }
+    }
+
     bool lcl_AcceptRedline( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
                             bool bCallDelete,
                             const SwPosition* pSttRng = nullptr,
@@ -565,7 +596,10 @@ namespace
                     rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld & ~RedlineFlags(RedlineFlags::On | RedlineFlags::Ignore));
 
                     if( pCSttNd && pCEndNd )
+                    {
                         rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
+                        lcl_DeleteTrackedTableRow( aPam.End() );
+                    }
                     else if (pCSttNd && !pCEndNd)
                         {
                             aPam.GetBound().nContent.Assign( nullptr, 0 );
diff --git a/sw/source/core/docnode/ndtbl1.cxx b/sw/source/core/docnode/ndtbl1.cxx
index 6d2a677712be..9a4f80ee995a 100644
--- a/sw/source/core/docnode/ndtbl1.cxx
+++ b/sw/source/core/docnode/ndtbl1.cxx
@@ -536,6 +536,32 @@ bool SwDoc::GetRowBackground( const SwCursor& rCursor, std::unique_ptr<SvxBrushI
     return bRet;
 }
 
+void SwDoc::SetRowNotTracked( const SwCursor& rCursor, const SvxPrintItem &rNew )
+{
+    SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
+    if( !pTableNd )
+        return;
+
+    std::vector<SwTableLine*> aRowArr; // For Lines collecting
+    ::lcl_CollectLines( aRowArr, rCursor, true );
+
+    if( aRowArr.empty() )
+        return;
+
+    if (GetIDocumentUndoRedo().DoesUndo())
+    {
+        GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
+    }
+
+    std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
+    aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
+
+    for( auto pLn : aRowArr )
+        ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew );
+
+    getIDocumentState().SetModified();
+}
+
 static void InsertCell( std::vector<SwCellFrame*>& rCellArr, SwCellFrame* pCellFrame )
 {
     if( rCellArr.end() == std::find( rCellArr.begin(), rCellArr.end(), pCellFrame ) )
diff --git a/sw/source/core/frmedt/fetab.cxx b/sw/source/core/frmedt/fetab.cxx
index 1a44707f43c3..bf7f1d2d618e 100644
--- a/sw/source/core/frmedt/fetab.cxx
+++ b/sw/source/core/frmedt/fetab.cxx
@@ -32,7 +32,9 @@
 #include <fmtornt.hxx>
 #include <frmatr.hxx>
 #include <fesh.hxx>
+#include <wrtsh.hxx>
 #include <doc.hxx>
+#include <docsh.hxx>
 #include <IDocumentState.hxx>
 #include <IDocumentLayoutAccess.hxx>
 #include <cntfrm.hxx>
@@ -325,6 +327,34 @@ bool SwFEShell::DeleteRow(bool bCompleteTable)
     }
 
     CurrShell aCurr( this );
+
+    // tracked deletion: remove only textbox content,
+    // and set IsNoTracked table line property to false
+    if ( GetDoc()->GetDocShell()->IsChangeRecording() )
+    {
+        StartUndo(bCompleteTable ? SwUndoId::UI_TABLE_DELETE : SwUndoId::ROW_DELETE);
+        StartAllAction();
+
+        SvxPrintItem aNotTracked(RES_PRINT, false);
+        GetDoc()->SetRowNotTracked( *getShellCursor( false ), aNotTracked );
+
+        if ( SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(this) )
+            pWrtShell->SelectTableRow();
+
+        SwEditShell* pEditShell = GetDoc()->GetEditShell();
+        SwRedlineTable::size_type nPrev = pEditShell->GetRedlineCount();
+        pEditShell->Delete();
+
+        EndAllActionAndCall();
+        EndUndo(bCompleteTable ? SwUndoId::UI_TABLE_DELETE : SwUndoId::ROW_DELETE);
+
+        // track row 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 for boxes via the layout
diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx
index 65f39748fd34..fda4da0b85d9 100644
--- a/sw/source/core/table/swtable.cxx
+++ b/sw/source/core/table/swtable.cxx
@@ -1868,6 +1868,21 @@ sal_uLong SwTableBox::GetSttIdx() const
     return m_pStartNode ? m_pStartNode->GetIndex() : 0;
 }
 
+bool SwTableBox::IsEmpty() const
+{
+    const SwStartNode *pSttNd = GetSttNd();
+    if( pSttNd &&
+        pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() )
+    {
+        const SwContentNode *pCNd =
+            pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetContentNode();
+        if( pCNd && !pCNd->Len() )
+            return true;
+    }
+
+    return false;
+}
+
     // retrieve information from the client
 bool SwTable::GetInfo( SfxPoolItem& rInfo ) const
 {
diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx
index 247f3d84ece5..55b948a1eafe 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -542,6 +542,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s
                     { u"" UNO_NAME_SIZE_TYPE, RES_FRM_SIZE,           cppu::UnoType<sal_Int16>::get()  ,         PROPERTY_NONE,   MID_FRMSIZE_SIZE_TYPE  },
                     { u"" UNO_NAME_WIDTH_TYPE, RES_FRM_SIZE,          cppu::UnoType<sal_Int16>::get()  ,         PROPERTY_NONE,   MID_FRMSIZE_WIDTH_TYPE },
                     { u"" UNO_NAME_IS_SPLIT_ALLOWED, RES_ROW_SPLIT,       cppu::UnoType<bool>::get()  , PropertyAttribute::MAYBEVOID, 0},
+                    { u"" UNO_NAME_IS_NOT_TRACKED, RES_PRINT, cppu::UnoType<bool>::get()  , PropertyAttribute::MAYBEVOID, 0},
                     { u"" UNO_NAME_ROW_INTEROP_GRAB_BAG, RES_FRMATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0 },
                     { u"", 0, css::uno::Type(), 0, 0 }
                 };
diff --git a/sw/source/filter/html/htmltab.cxx b/sw/source/filter/html/htmltab.cxx
index b56a016e8d74..5149640c6bdd 100644
--- a/sw/source/filter/html/htmltab.cxx
+++ b/sw/source/filter/html/htmltab.cxx
@@ -1226,21 +1226,6 @@ const SwStartNode* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 n
     return pTable->GetPrevBoxStartNode(USHRT_MAX, USHRT_MAX);
 }
 
-static bool IsBoxEmpty( const SwTableBox *pBox )
-{
-    const SwStartNode *pSttNd = pBox->GetSttNd();
-    if( pSttNd &&
-        pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() )
-    {
-        const SwContentNode *pCNd =
-            pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetContentNode();
-        if( pCNd && !pCNd->Len() )
-            return true;
-    }
-
-    return false;
-}
-
 sal_uInt16 HTMLTable::GetTopCellSpace( sal_uInt16 nRow ) const
 {
     sal_uInt16 nSpace = m_nCellPadding;
@@ -1413,7 +1398,7 @@ void HTMLTable::FixFrameFormat( SwTableBox *pBox,
                 pFrameFormat->ResetFormatAttr( RES_BACKGROUND );
 
             // Only set format if there's a value or the box is empty
-            if( bHasNumFormat && (bHasValue || IsBoxEmpty(pBox)) )
+            if( bHasNumFormat && (bHasValue || pBox->IsEmpty()) )
             {
                 bool bLock = pFrameFormat->GetDoc()->GetNumberFormatter()
                                      ->IsTextFormat( nNumFormat );


More information about the Libreoffice-commits mailing list