[Libreoffice-commits] core.git: 4 commits - sc/inc sc/qa sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Mon Jul 14 13:12:12 PDT 2014


 sc/inc/chgtrack.hxx                                       |   72 ++----
 sc/qa/unit/data/xls/track-changes/simple-cell-changes.xls |binary
 sc/qa/unit/subsequent_export-test.cxx                     |  162 +++++++++++++-
 sc/source/core/tool/chgtrack.cxx                          |  100 +++++++-
 sc/source/filter/inc/XclExpChangeTrack.hxx                |    5 
 sc/source/filter/inc/XclImpChangeTrack.hxx                |    2 
 sc/source/filter/xcl97/XclExpChangeTrack.cxx              |   17 +
 sc/source/filter/xcl97/XclImpChangeTrack.cxx              |   11 
 8 files changed, 292 insertions(+), 77 deletions(-)

New commits:
commit adf0d7b1fb8eed88f4fcd6d31662ae6f59d00812
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Jul 14 15:24:19 2014 -0400

    Preserve the "end of list" flag for xls round-tripping.
    
    This "end of list" flag determines whether the row insertion was an
    automatic insertion at the bottom.  Calc doesn't use this at the moment
    but Excel uses it to differentiate a normal row insertion from an
    automatic one.
    
    Change-Id: I6b28669d816c54d1dc1e4c106918ba688415788d

diff --git a/sc/inc/chgtrack.hxx b/sc/inc/chgtrack.hxx
index b2b6cf9..59b4058 100644
--- a/sc/inc/chgtrack.hxx
+++ b/sc/inc/chgtrack.hxx
@@ -421,7 +421,9 @@ class ScChangeActionIns : public ScChangeAction
 {
     friend class ScChangeTrack;
 
-                                ScChangeActionIns( const ScRange& rRange );
+    bool mbEndOfList; /// whether or not a row was auto-inserted at the bottom.
+
+    ScChangeActionIns( const ScRange& rRange, bool bEndOfList = false );
     virtual                     ~ScChangeActionIns();
 
     virtual void                AddContent( ScChangeActionContent* ) SAL_OVERRIDE {}
@@ -432,17 +434,21 @@ class ScChangeActionIns : public ScChangeAction
     virtual const ScChangeTrack*    GetChangeTrack() const SAL_OVERRIDE { return 0; }
 
 public:
-    ScChangeActionIns(const sal_uLong nActionNumber,
-            const ScChangeActionState eState,
-            const sal_uLong nRejectingNumber,
-            const ScBigRange& aBigRange,
-            const OUString& aUser,
-            const DateTime& aDateTime,
-            const OUString &sComment,
-            const ScChangeActionType eType); // only to use in the XML import
+    ScChangeActionIns(
+        const sal_uLong nActionNumber,
+        const ScChangeActionState eState,
+        const sal_uLong nRejectingNumber,
+        const ScBigRange& aBigRange,
+        const OUString& aUser,
+        const DateTime& aDateTime,
+        const OUString &sComment,
+        const ScChangeActionType eType,
+        bool bEndOfList = false );
 
     virtual void GetDescription(
         OUString& rStr, ScDocument* pDoc, bool bSplitRange = false, bool bWarning = true) const SAL_OVERRIDE;
+
+    SC_DLLPUBLIC bool IsEndOfList() const;
 };
 
 //  ScChangeActionDel
@@ -1113,7 +1119,7 @@ public:
     // Only use the following two if there is no different solution! (Assign
     // string for NewValue or creation of a formula respectively)
 
-    SC_DLLPUBLIC void AppendInsert( const ScRange& );
+    SC_DLLPUBLIC void AppendInsert( const ScRange& rRange, bool bEndOfList = false );
 
                                 // pRefDoc may be NULL => no lookup of contents
                                 // => no generation of deleted contents
diff --git a/sc/source/core/tool/chgtrack.cxx b/sc/source/core/tool/chgtrack.cxx
index 4b57b71..a18d0d3 100644
--- a/sc/source/core/tool/chgtrack.cxx
+++ b/sc/source/core/tool/chgtrack.cxx
@@ -652,8 +652,9 @@ void ScChangeAction::AddDependent( sal_uLong nActionNumber,
 }
 
 //  ScChangeActionIns
-ScChangeActionIns::ScChangeActionIns( const ScRange& rRange )
-        : ScChangeAction( SC_CAT_NONE, rRange )
+ScChangeActionIns::ScChangeActionIns( const ScRange& rRange, bool bEndOfList ) :
+    ScChangeAction(SC_CAT_NONE, rRange),
+    mbEndOfList(bEndOfList)
 {
     if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL )
     {
@@ -684,8 +685,10 @@ ScChangeActionIns::ScChangeActionIns(
     const sal_uLong nActionNumber, const ScChangeActionState eStateP,
     const sal_uLong nRejectingNumber, const ScBigRange& aBigRangeP,
     const OUString& aUserP, const DateTime& aDateTimeP,
-    const OUString& sComment, const ScChangeActionType eTypeP) :
-    ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment)
+    const OUString& sComment, const ScChangeActionType eTypeP,
+    bool bEndOfList ) :
+    ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
+    mbEndOfList(bEndOfList)
 {
 }
 
@@ -728,6 +731,11 @@ void ScChangeActionIns::GetDescription(
     }
 }
 
+bool ScChangeActionIns::IsEndOfList() const
+{
+    return mbEndOfList;
+}
+
 bool ScChangeActionIns::Reject( ScDocument* pDoc )
 {
     if ( !aBigRange.IsValid( pDoc ) )
@@ -2848,9 +2856,9 @@ ScChangeActionContent* ScChangeTrack::AppendContentOnTheFly(
     return pAct;
 }
 
-void ScChangeTrack::AppendInsert( const ScRange& rRange )
+void ScChangeTrack::AppendInsert( const ScRange& rRange, bool bEndOfList )
 {
-    ScChangeActionIns* pAct = new ScChangeActionIns( rRange );
+    ScChangeActionIns* pAct = new ScChangeActionIns(rRange, bEndOfList);
     Append( pAct );
 }
 
@@ -4477,18 +4485,20 @@ ScChangeTrack* ScChangeTrack::Clone( ScDocument* pDocument ) const
             case SC_CAT_INSERT_COLS:
             case SC_CAT_INSERT_ROWS:
             case SC_CAT_INSERT_TABS:
-                {
-                    pClonedAction = new ScChangeActionIns(
-                        pAction->GetActionNumber(),
-                        pAction->GetState(),
-                        pAction->GetRejectAction(),
-                        pAction->GetBigRange(),
-                        pAction->GetUser(),
-                        pAction->GetDateTimeUTC(),
-                        pAction->GetComment(),
-                        pAction->GetType() );
-                }
-                break;
+            {
+                bool bEndOfList = static_cast<const ScChangeActionIns*>(pAction)->IsEndOfList();
+                pClonedAction = new ScChangeActionIns(
+                    pAction->GetActionNumber(),
+                    pAction->GetState(),
+                    pAction->GetRejectAction(),
+                    pAction->GetBigRange(),
+                    pAction->GetUser(),
+                    pAction->GetDateTimeUTC(),
+                    pAction->GetComment(),
+                    pAction->GetType(),
+                    bEndOfList );
+            }
+            break;
             case SC_CAT_DELETE_COLS:
             case SC_CAT_DELETE_ROWS:
             case SC_CAT_DELETE_TABS:
diff --git a/sc/source/filter/inc/XclExpChangeTrack.hxx b/sc/source/filter/inc/XclExpChangeTrack.hxx
index 18b0409..2bfa1bb 100644
--- a/sc/source/filter/inc/XclExpChangeTrack.hxx
+++ b/sc/source/filter/inc/XclExpChangeTrack.hxx
@@ -472,11 +472,12 @@ public:
 
 class XclExpChTrInsert : public XclExpChTrAction
 {
+    bool mbEndOfList;
+
 protected:
     ScRange                     aRange;
 
-                                XclExpChTrInsert( const XclExpChTrInsert& rCopy ) :
-                                    XclExpChTrAction( rCopy ), aRange( rCopy.aRange ) {}
+    XclExpChTrInsert( const XclExpChTrInsert& rCopy );
 
     virtual void                SaveActionData( XclExpStream& rStrm ) const SAL_OVERRIDE;
     virtual void                PrepareSaveAction( XclExpStream& rStrm ) const SAL_OVERRIDE;
diff --git a/sc/source/filter/inc/XclImpChangeTrack.hxx b/sc/source/filter/inc/XclImpChangeTrack.hxx
index 0d1dc70..ac589b9 100644
--- a/sc/source/filter/inc/XclImpChangeTrack.hxx
+++ b/sc/source/filter/inc/XclImpChangeTrack.hxx
@@ -65,7 +65,7 @@ private:
     void                        DoAcceptRejectAction( ScChangeAction* pAction );
     void                        DoAcceptRejectAction( sal_uInt32 nFirst, sal_uInt32 nLast );
 
-    void                        DoInsertRange( const ScRange& rRange );
+    void DoInsertRange( const ScRange& rRange, bool bEndOfList );
     void                        DoDeleteRange( const ScRange& rRange );
 
     inline sal_uInt8            LookAtuInt8();
diff --git a/sc/source/filter/xcl97/XclExpChangeTrack.cxx b/sc/source/filter/xcl97/XclExpChangeTrack.cxx
index bb47f2a..a307382 100644
--- a/sc/source/filter/xcl97/XclExpChangeTrack.cxx
+++ b/sc/source/filter/xcl97/XclExpChangeTrack.cxx
@@ -992,19 +992,31 @@ void XclExpChTrCellContent::SaveXml( XclExpXmlStream& rRevisionLogStrm )
     pStream->endElement( XML_rcc );
 }
 
+XclExpChTrInsert::XclExpChTrInsert( const XclExpChTrInsert& rCopy ) :
+    XclExpChTrAction(rCopy),
+    mbEndOfList(rCopy.mbEndOfList),
+    aRange(rCopy.aRange) {}
+
 XclExpChTrInsert::XclExpChTrInsert(
         const ScChangeAction& rAction,
         const XclExpRoot& rRoot,
         const XclExpChTrTabIdBuffer& rTabIdBuffer,
         ScChangeTrack& rChangeTrack ) :
     XclExpChTrAction( rAction, rRoot, rTabIdBuffer ),
+    mbEndOfList(false),
     aRange( rAction.GetBigRange().MakeRange() )
 {
     nLength = 0x00000030;
     switch( rAction.GetType() )
     {
         case SC_CAT_INSERT_COLS:    nOpCode = EXC_CHTR_OP_INSCOL;   break;
-        case SC_CAT_INSERT_ROWS:    nOpCode = EXC_CHTR_OP_INSROW;   break;
+        case SC_CAT_INSERT_ROWS:
+        {
+            const ScChangeActionIns& rIns = static_cast<const ScChangeActionIns&>(rAction);
+            mbEndOfList = rIns.IsEndOfList();
+            nOpCode = EXC_CHTR_OP_INSROW;
+        }
+        break;
         case SC_CAT_DELETE_COLS:    nOpCode = EXC_CHTR_OP_DELCOL;   break;
         case SC_CAT_DELETE_ROWS:    nOpCode = EXC_CHTR_OP_DELROW;   break;
         default:
@@ -1036,7 +1048,8 @@ XclExpChTrInsert::~XclExpChTrInsert()
 void XclExpChTrInsert::SaveActionData( XclExpStream& rStrm ) const
 {
     WriteTabId( rStrm, aRange.aStart.Tab() );
-    rStrm   << (sal_uInt16) 0x0000;
+    sal_uInt16 nFlagVal = mbEndOfList ? 0x0001 : 0x0000;
+    rStrm << nFlagVal;
     Write2DRange( rStrm, aRange );
     rStrm   << (sal_uInt32) 0x00000000;
 }
diff --git a/sc/source/filter/xcl97/XclImpChangeTrack.cxx b/sc/source/filter/xcl97/XclImpChangeTrack.cxx
index b6e4180..f453208 100644
--- a/sc/source/filter/xcl97/XclImpChangeTrack.cxx
+++ b/sc/source/filter/xcl97/XclImpChangeTrack.cxx
@@ -93,10 +93,10 @@ void XclImpChangeTrack::DoAcceptRejectAction( sal_uInt32 nFirst, sal_uInt32 nLas
         DoAcceptRejectAction( pChangeTrack->GetAction( nIndex ) );
 }
 
-void XclImpChangeTrack::DoInsertRange( const ScRange& rRange )
+void XclImpChangeTrack::DoInsertRange( const ScRange& rRange, bool bEndOfList )
 {
     sal_uInt32 nFirst = pChangeTrack->GetActionMax() + 1;
-    pChangeTrack->AppendInsert( rRange );
+    pChangeTrack->AppendInsert(rRange, bEndOfList);
     sal_uInt32 nLast = pChangeTrack->GetActionMax();
     DoAcceptRejectAction( nFirst, nLast );
 }
@@ -297,7 +297,8 @@ void XclImpChangeTrack::ReadChTrInsert()
         ScRange aRange;
         aRange.aStart.SetTab( ReadTabNum() );
         aRange.aEnd.SetTab( aRange.aStart.Tab() );
-        pStrm->Ignore( 2 );
+        sal_uInt16 nFlags = pStrm->ReaduInt16();
+        bool bEndOfList = (nFlags & 0x0001); // row auto-inserted at the bottom.
         Read2DRange( aRange );
 
         if( aRecHeader.nOpCode & EXC_CHTR_OP_COLFLAG )
@@ -314,7 +315,7 @@ void XclImpChangeTrack::ReadChTrInsert()
             if( aRecHeader.nOpCode & EXC_CHTR_OP_DELFLAG )
                 DoDeleteRange( aRange );
             else
-                DoInsertRange( aRange );
+                DoInsertRange(aRange, bEndOfList);
         }
     }
 }
@@ -426,7 +427,7 @@ void XclImpChangeTrack::ReadChTrInsertTab()
         if( pStrm->IsValid() )
         {
             nTabIdCount++;
-            DoInsertRange( ScRange( 0, 0, nTab, MAXCOL, MAXROW, nTab ) );
+            DoInsertRange(ScRange(0, 0, nTab, MAXCOL, MAXROW, nTab), false);
         }
     }
 }
commit d873fd9fa28a26c6f2b177d26dbbc76c9bd827a3
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Jul 14 12:58:43 2014 -0400

    Move this header to the source file.
    
    refupdat.hxx is under the ui directory.  Not everyone has access to it.
    
    Change-Id: I3f60761e1105946ed5bd6bddb339ee9a9e7705ad

diff --git a/sc/inc/chgtrack.hxx b/sc/inc/chgtrack.hxx
index 94a94f3..b2b6cf9 100644
--- a/sc/inc/chgtrack.hxx
+++ b/sc/inc/chgtrack.hxx
@@ -33,7 +33,6 @@
 #include "global.hxx"
 #include "bigrange.hxx"
 #include "scdllapi.h"
-#include "refupdat.hxx"
 #include "cellvalue.hxx"
 
 class ScDocument;
diff --git a/sc/source/core/tool/chgtrack.cxx b/sc/source/core/tool/chgtrack.cxx
index 3abdc45..4b57b71 100644
--- a/sc/source/core/tool/chgtrack.cxx
+++ b/sc/source/core/tool/chgtrack.cxx
@@ -33,6 +33,7 @@
 #include "editutil.hxx"
 #include "tokenarray.hxx"
 #include "refupdatecontext.hxx"
+#include <refupdat.hxx>
 
 #include <tools/shl.hxx>
 #include <tools/rtti.hxx>
commit 953d606b99017195249823c30c2bf19c83f10a44
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Jul 14 12:29:15 2014 -0400

    Make these non inline.
    
    Change-Id: Ieb54e895f334361978cfc22956ab65687fb74adf

diff --git a/sc/inc/chgtrack.hxx b/sc/inc/chgtrack.hxx
index dc5f36c..94a94f3 100644
--- a/sc/inc/chgtrack.hxx
+++ b/sc/inc/chgtrack.hxx
@@ -1029,42 +1029,13 @@ public:
     ScChangeAction*     GetFirst() const { return pFirst; }
     ScChangeAction*     GetLast() const { return pLast; }
     sal_uLong               GetActionMax() const { return nActionMax; }
-    bool IsGenerated( sal_uLong nAction ) const
-        { return nAction >= nGeneratedMin; }
-    ScChangeAction*     GetAction( sal_uLong nAction ) const
-    {
-        ScChangeActionMap::const_iterator it = aMap.find( nAction );
-        if( it != aMap.end() )
-            return it->second;
-        else
-            return NULL;
-    }
-    ScChangeAction*     GetGenerated( sal_uLong nGenerated ) const
-    {
-        ScChangeActionMap::const_iterator it = aGeneratedMap.find( nGenerated );
-        if( it != aGeneratedMap.end() )
-            return it->second;
-        else
-            return NULL;
-    }
-    ScChangeAction*     GetActionOrGenerated( sal_uLong nAction ) const
-                            {
-                                return IsGenerated( nAction ) ?
-                                    GetGenerated( nAction ) :
-                                    GetAction( nAction );
-                            }
-    sal_uLong               GetLastSavedActionNumber() const
-                            { return nMarkLastSaved; }
-    void                SetLastSavedActionNumber(sal_uLong nNew)
-                            { nMarkLastSaved = nNew; }
-    ScChangeAction*     GetLastSaved() const
-    {
-        ScChangeActionMap::const_iterator it = aMap.find( nMarkLastSaved );
-        if( it != aMap.end() )
-            return it->second;
-        else
-            return NULL;
-    }
+    bool IsGenerated( sal_uLong nAction ) const;
+    SC_DLLPUBLIC ScChangeAction* GetAction( sal_uLong nAction ) const;
+    ScChangeAction* GetGenerated( sal_uLong nGenerated ) const;
+    ScChangeAction* GetActionOrGenerated( sal_uLong nAction ) const;
+    sal_uLong GetLastSavedActionNumber() const;
+    void SetLastSavedActionNumber(sal_uLong nNew);
+    ScChangeAction* GetLastSaved() const;
     ScChangeActionContent** GetContentSlots() const { return ppContentSlots; }
 
     bool IsLoadSave() const { return bLoadSave; }
@@ -1220,7 +1191,7 @@ public:
     void                SetModifiedLink( const Link& r )
                             { aModifiedLink = r; ClearMsgQueue(); }
     const Link&         GetModifiedLink() const { return aModifiedLink; }
-    ScChangeTrackMsgQueue& GetMsgQueue() { return aMsgQueue; }
+    ScChangeTrackMsgQueue& GetMsgQueue();
 
     void                NotifyModified( ScChangeTrackMsgType eMsgType,
                             sal_uLong nStartAction, sal_uLong nEndAction );
diff --git a/sc/source/core/tool/chgtrack.cxx b/sc/source/core/tool/chgtrack.cxx
index 8f1691d..3abdc45 100644
--- a/sc/source/core/tool/chgtrack.cxx
+++ b/sc/source/core/tool/chgtrack.cxx
@@ -2196,6 +2196,54 @@ void ScChangeTrack::Clear()
     Init();
 }
 
+bool ScChangeTrack::IsGenerated( sal_uLong nAction ) const
+{
+    return nAction >= nGeneratedMin;
+}
+
+ScChangeAction* ScChangeTrack::GetAction( sal_uLong nAction ) const
+{
+    ScChangeActionMap::const_iterator it = aMap.find( nAction );
+    if( it != aMap.end() )
+        return it->second;
+    else
+        return NULL;
+}
+
+ScChangeAction* ScChangeTrack::GetGenerated( sal_uLong nGenerated ) const
+{
+    ScChangeActionMap::const_iterator it = aGeneratedMap.find( nGenerated );
+    if( it != aGeneratedMap.end() )
+        return it->second;
+    else
+        return NULL;
+}
+
+ScChangeAction* ScChangeTrack::GetActionOrGenerated( sal_uLong nAction ) const
+{
+    return IsGenerated( nAction ) ?
+        GetGenerated( nAction ) :
+        GetAction( nAction );
+}
+sal_uLong ScChangeTrack::GetLastSavedActionNumber() const
+{
+    return nMarkLastSaved;
+}
+
+void ScChangeTrack::SetLastSavedActionNumber(sal_uLong nNew)
+{
+    nMarkLastSaved = nNew;
+}
+
+ScChangeAction* ScChangeTrack::GetLastSaved() const
+{
+    ScChangeActionMap::const_iterator it = aMap.find( nMarkLastSaved );
+    if( it != aMap.end() )
+        return it->second;
+    else
+        return NULL;
+}
+
 void ScChangeTrack::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 )
 {
     if ( !pDoc->IsInDtorClear() )
@@ -2282,6 +2330,11 @@ void ScChangeTrack::EndBlockModify( sal_uLong nEndAction )
     }
 }
 
+ScChangeTrackMsgQueue& ScChangeTrack::GetMsgQueue()
+{
+    return aMsgQueue;
+}
+
 void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType,
         sal_uLong nStartAction, sal_uLong nEndAction )
 {
commit b63b6c63fdba944331ba4fcd6fe9a459c563d696
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Jul 11 18:40:43 2014 -0400

    Write test for change track round-tripping for xls file format.
    
    Change-Id: I127879c4f1b6d3605ff800c3f3aa3929a098fead

diff --git a/sc/qa/unit/data/xls/track-changes/simple-cell-changes.xls b/sc/qa/unit/data/xls/track-changes/simple-cell-changes.xls
new file mode 100755
index 0000000..8def117
Binary files /dev/null and b/sc/qa/unit/data/xls/track-changes/simple-cell-changes.xls differ
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index 9fa0bc2..103b962 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -33,6 +33,7 @@
 #include "cellvalue.hxx"
 #include <postit.hxx>
 #include <tokenstringcontext.hxx>
+#include <chgtrack.hxx>
 
 #include <svx/svdoole2.hxx>
 #include "tabprotection.hxx"
@@ -92,7 +93,7 @@ public:
 
     void testCellBordersXLS();
     void testCellBordersXLSX();
-
+    void testTrackChangesSimpleXLS();
     void testSheetTabColorsXLSX();
 
     void testSharedFormulaExportXLS();
@@ -131,6 +132,7 @@ public:
     CPPUNIT_TEST(testSheetProtectionXLSX);
     CPPUNIT_TEST(testCellBordersXLS);
     CPPUNIT_TEST(testCellBordersXLSX);
+    CPPUNIT_TEST(testTrackChangesSimpleXLS);
     CPPUNIT_TEST(testSheetTabColorsXLSX);
     CPPUNIT_TEST(testSharedFormulaExportXLS);
     CPPUNIT_TEST(testSharedFormulaExportXLSX);
@@ -1305,6 +1307,164 @@ void ScExportTest::testCellBordersXLSX()
     testExcelCellBorders(XLSX);
 }
 
+OUString toString( const ScBigRange& rRange )
+{
+    OUStringBuffer aBuf;
+    aBuf.appendAscii("(columns:");
+    aBuf.append(rRange.aStart.Col());
+    aBuf.append('-');
+    aBuf.append(rRange.aEnd.Col());
+    aBuf.appendAscii(";rows:");
+    aBuf.append(rRange.aStart.Row());
+    aBuf.append('-');
+    aBuf.append(rRange.aEnd.Row());
+    aBuf.appendAscii(";sheets:");
+    aBuf.append(rRange.aStart.Tab());
+    aBuf.append('-');
+    aBuf.append(rRange.aEnd.Tab());
+    aBuf.append(')');
+
+    return aBuf.makeStringAndClear();
+}
+
+void ScExportTest::testTrackChangesSimpleXLS()
+{
+    struct CheckItem
+    {
+        sal_uLong mnActionId;
+        ScChangeActionType meType;
+
+        sal_Int32 mnStartCol;
+        sal_Int32 mnStartRow;
+        sal_Int32 mnStartTab;
+        sal_Int32 mnEndCol;
+        sal_Int32 mnEndRow;
+        sal_Int32 mnEndTab;
+
+        bool mbRowInsertedAtBottom;
+    };
+
+    struct
+    {
+        bool checkRange( ScChangeActionType eType, const ScBigRange& rExpected, const ScBigRange& rActual )
+        {
+            ScBigRange aExpected(rExpected), aActual(rActual);
+
+            switch (eType)
+            {
+                case SC_CAT_INSERT_ROWS:
+                {
+                    // Ignore columns.
+                    aExpected.aStart.SetCol(0);
+                    aExpected.aEnd.SetCol(0);
+                    aActual.aStart.SetCol(0);
+                    aActual.aEnd.SetCol(0);
+                }
+                break;
+                default:
+                    ;
+            }
+
+            return aExpected == aActual;
+        }
+
+        bool check( ScDocument& rDoc )
+        {
+            CheckItem aChecks[] =
+            {
+                {  1, SC_CAT_CONTENT     , 1, 1, 0, 1, 1, 0, false },
+                {  2, SC_CAT_INSERT_ROWS , 0, 2, 0, 0, 2, 0, true },
+                {  3, SC_CAT_CONTENT     , 1, 2, 0, 1, 2, 0, false },
+                {  4, SC_CAT_INSERT_ROWS , 0, 3, 0, 0, 3, 0, true  },
+                {  5, SC_CAT_CONTENT     , 1, 3, 0, 1, 3, 0, false },
+                {  6, SC_CAT_INSERT_ROWS , 0, 4, 0, 0, 4, 0, true  },
+                {  7, SC_CAT_CONTENT     , 1, 4, 0, 1, 4, 0, false },
+                {  8, SC_CAT_INSERT_ROWS , 0, 5, 0, 0, 5, 0, true  },
+                {  9, SC_CAT_CONTENT     , 1, 5, 0, 1, 5, 0, false },
+                { 10, SC_CAT_INSERT_ROWS , 0, 6, 0, 0, 6, 0, true  },
+                { 11, SC_CAT_CONTENT     , 1, 6, 0, 1, 6, 0, false },
+                { 12, SC_CAT_INSERT_ROWS , 0, 7, 0, 0, 7, 0, true  },
+                { 13, SC_CAT_CONTENT     , 1, 7, 0, 1, 7, 0, false },
+            };
+
+            ScChangeTrack* pCT = rDoc.GetChangeTrack();
+            if (!pCT)
+            {
+                cerr << "Change track instance doesn't exist." << endl;
+                return false;
+            }
+
+            sal_uLong nActionMax = pCT->GetActionMax();
+            if (nActionMax != 13)
+            {
+                cerr << "Unexpected highest action ID value." << endl;
+                return false;
+            }
+
+            for (size_t i = 0, n = SAL_N_ELEMENTS(aChecks); i < n; ++i)
+            {
+                sal_uInt16 nActId = aChecks[i].mnActionId;
+                const ScChangeAction* pAction = pCT->GetAction(nActId);
+                if (!pAction)
+                {
+                    cerr << "No action for action number " << nActId << " found." << endl;
+                    return false;
+                }
+
+                if (pAction->GetType() != aChecks[i].meType)
+                {
+                    cerr << "Unexpected action type for action number " << nActId << "." << endl;
+                    return false;
+                }
+
+                const ScBigRange& rRange = pAction->GetBigRange();
+                ScBigRange aCheck(aChecks[i].mnStartCol, aChecks[i].mnStartRow, aChecks[i].mnStartTab,
+                                  aChecks[i].mnEndCol, aChecks[i].mnEndRow, aChecks[i].mnEndTab);
+
+                if (!checkRange(pAction->GetType(), aCheck, rRange))
+                {
+                    cerr << "Unexpected range for action number " << nActId
+                        << ": expected=" << toString(aCheck) << " actual=" << toString(rRange) << endl;
+                    return false;
+                }
+
+                switch (pAction->GetType())
+                {
+                    case SC_CAT_INSERT_ROWS:
+                    {
+                        const ScChangeActionIns* p = static_cast<const ScChangeActionIns*>(pAction);
+                        if (p->IsEndOfList() != aChecks[i].mbRowInsertedAtBottom)
+                        {
+                            cerr << "Unexpected end-of-list flag for action number " << nActId << "." << endl;
+                            return false;
+                        }
+                    }
+                    break;
+                    default:
+                        ;
+                }
+            }
+
+            return true;
+        }
+
+    } aTest;
+
+    ScDocShellRef xDocSh = loadDoc("track-changes/simple-cell-changes.", XLS);
+    CPPUNIT_ASSERT(xDocSh.Is());
+    ScDocument* pDoc = &xDocSh->GetDocument();
+    bool bGood = aTest.check(*pDoc);
+    CPPUNIT_ASSERT_MESSAGE("Initial check failed.", bGood);
+
+    ScDocShellRef xDocSh2 = saveAndReload(xDocSh, XLS);
+    xDocSh->DoClose();
+    pDoc = &xDocSh2->GetDocument();
+    bGood = aTest.check(*pDoc);
+    CPPUNIT_ASSERT_MESSAGE("Check after reload failed.", bGood);
+
+    xDocSh2->DoClose();
+}
+
 void ScExportTest::testSheetTabColorsXLSX()
 {
     struct


More information about the Libreoffice-commits mailing list