tdf#155341 sw tracked table column: add insertion

All the inserted cells get a dummy redline to store
the change tracking metadata, setting also the
HasTextChangesOnly bit of the table box to FALSE.

Follow-up to commit ffd8d20d368a885d6d786749278fa438573227a7
"tdf#150673 sw xmloff: import/export tracked table column".

Change-Id: I55f5a44ac0ec040993a100156665f116355c235a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152336
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/extras/uiwriter/uiwriter5.cxx b/sw/qa/extras/uiwriter/uiwriter5.cxx
index ec76c25..c8927ff 100644
--- a/sw/qa/extras/uiwriter/uiwriter5.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter5.cxx
@@ -2691,6 +2691,52 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testRedlineTableColumnDeletionWithDOCXExpo
    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 1);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf155341_RedlineTableColumnInsertionWithExport)
{
    // load a table, and insert a new column with enabled change tracking
    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");

    // insert table column with enabled change tracking
    // (HasTextChangesOnly property of the cell will be false)
    dispatchCommand(mxComponent, ".uno:InsertColumnsAfter", {});

    // text content with change tracking (dummy redline)
    discardDumpedLayout();
    pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "//page[1]//body/tab");
    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 3);

    // Save it and load it back.
    reload("writer8", "tdf150673_tracked_column_insertion.odt");
    pDoc = getSwDoc();

    // reject the insertion of the hidden content of the cell
    SwEditShell* const pEditShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount());
    pEditShell->RejectRedline(0);

    // inserted table column was deleted
    // (working export/import of HasTextChangesOnly)
    discardDumpedLayout();
    pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "//page[1]//body/tab");
    assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf128335)
{
    // Load the bugdoc, which has 3 textboxes.
diff --git a/sw/source/core/table/swnewtable.cxx b/sw/source/core/table/swnewtable.cxx
index cd98b4f..6debaf7 100644
--- a/sw/source/core/table/swnewtable.cxx
+++ b/sw/source/core/table/swnewtable.cxx
@@ -18,6 +18,7 @@
 */

#include <swtable.hxx>
#include <swcrsr.hxx>
#include <tblsel.hxx>
#include <tblrwcl.hxx>
#include <ndtxt.hxx>
@@ -34,6 +35,7 @@
#include <IDocumentContentOperations.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <cstdlib>
#include <vector>
#include <set>
@@ -745,6 +747,20 @@ bool SwTable::NewInsertCol( SwDoc& rDoc, const SwSelBoxes& rBoxes,
        for( sal_uInt16 j = 0; j < nCnt; ++j )
        {
            SwTableBox *pCurrBox = pLine->GetTabBoxes()[nInsPos+j];

            // set tracked insertion by inserting a dummy redline
            if ( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
            {
                SwPosition aPos(*pCurrBox->GetSttNd());
                SwCursor aCursor( aPos, nullptr );
                SwNodeIndex aInsDummyPos(*pCurrBox->GetSttNd(), 1 );
                SwPaM aPaM(aInsDummyPos);
                rDoc.getIDocumentContentOperations().InsertString( aPaM,
                        OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
                SvxPrintItem aHasTextChangesOnly(RES_PRINT, false);
                rDoc.SetBoxAttr( aCursor, aHasTextChangesOnly );
            }

            if( bNewSpan )
            {
                pCurrBox->setRowSpan( nLastRowSpan );
diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx
index e5703eb..ee4753b 100644
--- a/sw/source/core/table/swtable.cxx
+++ b/sw/source/core/table/swtable.cxx
@@ -2981,15 +2981,22 @@ void SwTableBox::ActualiseValueBox()

SwRedlineTable::size_type SwTableBox::GetRedline() const
{
    const SwRedlineTable& aRedlineTable = GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
    const SwStartNode *pSttNd = GetSttNd();

    if ( !pSttNd || GetRedlineType() == RedlineType::None )
    if ( aRedlineTable.empty() || !pSttNd )
        return SwRedlineTable::npos;

    // check table row property "HasTextChangesOnly", if it's defined and its value is
    // false, return with the first redline of the cell
    const SvxPrintItem *pHasTextChangesOnlyProp =
            GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
    if ( !pHasTextChangesOnlyProp || pHasTextChangesOnlyProp->GetValue() )
        return SwRedlineTable::npos;

    SwPosition aCellStart( *GetSttNd(), SwNodeOffset(0) );
    SwPosition aCellEnd( *GetSttNd()->EndOfSectionNode(), SwNodeOffset(-1) );
    SwNodeIndex pEndNodeIndex(aCellEnd.GetNode());
    const SwRedlineTable& aRedlineTable = GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
    SwRedlineTable::size_type nRedlinePos = 0;
    for( ; nRedlinePos < aRedlineTable.size(); ++nRedlinePos )
    {
@@ -3012,18 +3019,17 @@ SwRedlineTable::size_type SwTableBox::GetRedline() const

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;

    SwRedlineTable::size_type nPos = GetRedline();
    if ( nPos != SwRedlineTable::npos )
    {
        const SwRedlineTable& aRedlineTable = GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
        const SwRangeRedline* pRedline = aRedlineTable[ nPos ];
        if ( RedlineType::Delete == pRedline->GetType() ||
             RedlineType::Insert == pRedline->GetType() )
        {
            return pRedline->GetType();
        }
    }
    return RedlineType::None;
}