[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-4.2' - 2 commits - sc/inc sc/Library_scfilt.mk sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Fri Jul 18 12:00:14 PDT 2014


 sc/Library_scfilt.mk                         |    1 
 sc/inc/cellvalue.hxx                         |    1 
 sc/inc/chgtrack.hxx                          |    2 
 sc/source/core/data/cellvalue.cxx            |    7 
 sc/source/filter/excel/xestream.cxx          |    7 
 sc/source/filter/inc/XclExpChangeTrack.hxx   |   84 +++-
 sc/source/filter/inc/revisionfragment.hxx    |   79 ++++
 sc/source/filter/inc/xestream.hxx            |   10 
 sc/source/filter/oox/revisionfragment.cxx    |  462 +++++++++++++++++++++++++++
 sc/source/filter/oox/workbookfragment.cxx    |   11 
 sc/source/filter/xcl97/XclExpChangeTrack.cxx |  346 ++++++++++++--------
 11 files changed, 852 insertions(+), 158 deletions(-)

New commits:
commit ca20a53315eaea218c693e0de2026eb6f957331f
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Jul 17 20:20:16 2014 -0400

    bnc#885548: Adjust xlsx export of revisions to get it to work in Excel.
    
    (cherry picked from commit fa44673e154ed4fb0b518b8850e2f6e4b9069531)
    
    Conflicts:
    	sc/source/filter/inc/XclExpChangeTrack.hxx
    	sc/source/filter/xcl97/XclExpChangeTrack.cxx
    	sc/inc/cellvalue.hxx
    	sc/source/core/data/cellvalue.cxx
    
    Change-Id: I0058d9ddfea545390e615a3030171a366e333c85

diff --git a/sc/inc/cellvalue.hxx b/sc/inc/cellvalue.hxx
index c2606b5..8e2e64a 100644
--- a/sc/inc/cellvalue.hxx
+++ b/sc/inc/cellvalue.hxx
@@ -53,6 +53,7 @@ struct SC_DLLPUBLIC ScCellValue
     void set( double fValue );
     void set( const svl::SharedString& rStr );
     void set( const EditTextObject& rEditText );
+    void set( EditTextObject* pEditText );
     void set( const ScFormulaCell& rFormula );
     void set( ScFormulaCell* pFormula );
 
diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx
index 12ef302..92298cf 100644
--- a/sc/source/core/data/cellvalue.cxx
+++ b/sc/source/core/data/cellvalue.cxx
@@ -248,6 +248,13 @@ void ScCellValue::set( const EditTextObject& rEditText )
     mpEditText = rEditText.Clone();
 }
 
+void ScCellValue::set( EditTextObject* pEditText )
+{
+    clear();
+    meType = CELLTYPE_EDIT;
+    mpEditText = pEditText;
+}
+
 void ScCellValue::set( const ScFormulaCell& rFormula )
 {
     clear();
diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx
index df08d2c..47dba9e 100644
--- a/sc/source/filter/excel/xestream.cxx
+++ b/sc/source/filter/excel/xestream.cxx
@@ -842,6 +842,13 @@ const char* XclXmlUtils::ToPsz( bool b )
     return b ? "true" : "false";
 }
 
+const char* XclXmlUtils::ToPsz10( bool b )
+{
+    // xlsx seems to use "1" or "0" for boolean values.  I wonder it ever uses
+    // the "true" "false" variant.
+    return b ? "1" : "0";
+}
+
 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int32 nValue )
 {
     pStream->startElement( nElement, FSEND );
diff --git a/sc/source/filter/inc/XclExpChangeTrack.hxx b/sc/source/filter/inc/XclExpChangeTrack.hxx
index 3818535..c7ee389 100644
--- a/sc/source/filter/inc/XclExpChangeTrack.hxx
+++ b/sc/source/filter/inc/XclExpChangeTrack.hxx
@@ -29,7 +29,16 @@
 #include "ftools.hxx"
 #include "excrecds.hxx"
 
-//___________________________________________________________________
+#include <boost/ptr_container/ptr_vector.hpp>
+
+class ExcXmlRecord : public ExcRecord
+{
+public:
+    virtual sal_Size    GetLen() const SAL_OVERRIDE;
+    virtual sal_uInt16  GetNum() const SAL_OVERRIDE;
+    virtual void        Save( XclExpStream& rStrm ) SAL_OVERRIDE;
+};
+
 // XclExpUserBView - one UserBView record for each user
 
 class XclExpUserBView : public ExcRecord
@@ -238,42 +247,61 @@ public:
     virtual void                SaveXml( XclExpXmlStream& rStrm );
 };
 
-//___________________________________________________________________
+class XclExpXmlChTrHeaders : public ExcXmlRecord
+{
+    sal_uInt8 maGUID[16];
+public:
+    void SetGUID( const sal_uInt8* pGUID );
+
+    virtual void SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+};
+
+class XclExpChTrTabIdBuffer;
+class XclExpChTrAction;
+
+class XclExpXmlChTrHeader : public ExcXmlRecord
+{
+    OUString maUserName;
+    DateTime maDateTime;
+    sal_uInt8 maGUID[16];
+    sal_Int32 mnLogNumber;
+    sal_uInt32 mnMinAction;
+    sal_uInt32 mnMaxAction;
+
+    std::vector<sal_uInt16> maTabBuffer;
+    std::vector<XclExpChTrAction*> maActions;
+
+public:
+    XclExpXmlChTrHeader(
+        const OUString& rUserName, const DateTime& rDateTime, const sal_uInt8* pGUID,
+        sal_Int32 nLogNumber, const XclExpChTrTabIdBuffer& rBuf );
+
+    virtual void SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+
+    void AppendAction( XclExpChTrAction* pAction );
+};
+
 // XclExpChTrInfo - header of action group of a user
 
 class XclExpChTrInfo : public ExcRecord
 {
 private:
     XclExpString                sUsername;
-    sal_Int32                   mnLogNumber;
     DateTime                    aDateTime;
     sal_uInt8                   aGUID[ 16 ];
 
     virtual void                SaveCont( XclExpStream& rStrm );
 
 public:
-    inline                      XclExpChTrInfo(
-                                    const OUString& rUsername,
-                                    const DateTime& rDateTime,
-                                    const sal_uInt8* pGUID,
-                                    sal_Int32 nLogNumber );
+    XclExpChTrInfo( const OUString& rUsername, const DateTime& rDateTime,
+                    const sal_uInt8* pGUID );
+
     virtual                     ~XclExpChTrInfo();
 
     virtual sal_uInt16              GetNum() const;
     virtual sal_Size            GetLen() const;
-
-    virtual void                SaveXml( XclExpXmlStream& rStrm );
 };
 
-inline XclExpChTrInfo::XclExpChTrInfo( const OUString& rUsername, const DateTime& rDateTime, const sal_uInt8* pGUID, sal_Int32 nLogNumber ) :
-    sUsername( rUsername ),
-    mnLogNumber( nLogNumber ),
-    aDateTime( rDateTime )
-{
-    memcpy( aGUID, pGUID, 16 );
-}
-
-//___________________________________________________________________
 // XclExpChTrTabIdBuffer - buffer for tab id's
 
 class XclExpChTrTabIdBuffer
@@ -309,7 +337,6 @@ class XclExpChTrTabId : public ExcRecord
 private:
     sal_uInt16*                 pBuffer;
     sal_uInt16                  nTabCount;
-    bool                        mbInRevisionHeaders;
 
     inline void                 Clear() { if( pBuffer ) delete[] pBuffer; pBuffer = NULL; }
 
@@ -317,16 +344,14 @@ private:
 
 public:
     inline                      XclExpChTrTabId( sal_uInt16 nCount ) :
-                                    pBuffer( NULL ), nTabCount( nCount ), mbInRevisionHeaders( false ) {}
-                                XclExpChTrTabId( const XclExpChTrTabIdBuffer& rBuffer, bool bInRevisionHeaders = false );
+                                    pBuffer( NULL ), nTabCount( nCount ) {}
+                                XclExpChTrTabId( const XclExpChTrTabIdBuffer& rBuffer );
     virtual                     ~XclExpChTrTabId();
 
     void                        Copy( const XclExpChTrTabIdBuffer& rBuffer );
 
     virtual sal_uInt16              GetNum() const;
     virtual sal_Size            GetLen() const;
-
-    virtual void                SaveXml( XclExpXmlStream& rStrm );
 };
 
 //___________________________________________________________________
@@ -375,8 +400,7 @@ protected:
                                 // do something after writing the record
     virtual void                CompleteSaveAction( XclExpStream& rStrm ) const;
 
-    inline sal_uInt32           GetActionNumber() const { return nIndex; }
-    inline sal_Bool             GetAccepted() const { return bAccepted; }
+    inline bool                 GetAccepted() const { return bAccepted; }
 
 public:
                                 XclExpChTrAction(
@@ -399,6 +423,7 @@ public:
     virtual sal_Size            GetLen() const;
 
     inline XclExpChTrAction*    GetAddAction() { return pAddAction; }
+    inline sal_uInt32           GetActionNumber() const { return nIndex; }
 };
 
 inline void XclExpChTrAction::Write2DAddress( XclExpStream& rStrm, const ScAddress& rAddress ) const
@@ -590,11 +615,12 @@ public:
 
 class XclExpChangeTrack : protected XclExpRoot
 {
-private:
-    std::vector<ExcRecord*>       aRecList;           // list of "Revision Log" stream records
+    typedef boost::ptr_vector<ExcRecord> RecListType;
+    typedef boost::ptr_vector<XclExpChTrTabIdBuffer> TabIdBufferType;
+    RecListType maRecList;           // list of "Revision Log" stream records
     std::stack<XclExpChTrAction*> aActionStack;
     XclExpChTrTabIdBuffer*        pTabIdBuffer;
-    std::vector<XclExpChTrTabIdBuffer*> maBuffers;
+    TabIdBufferType maBuffers;
 
     ScDocument*                 pTempDoc;           // empty document
 
diff --git a/sc/source/filter/inc/xestream.hxx b/sc/source/filter/inc/xestream.hxx
index e29ed1a..f33f0c0 100644
--- a/sc/source/filter/inc/xestream.hxx
+++ b/sc/source/filter/inc/xestream.hxx
@@ -286,8 +286,18 @@ public:
     static OUString ToOUString( const ScfUInt16Vec& rBuffer, sal_Int32 nStart = 0, sal_Int32 nLength = -1 );
     static OUString ToOUString( ScDocument& rDocument, const ScAddress& rAddress, const ScTokenArray* pTokenArray );
     static OUString ToOUString( const XclExpString& s );
+
+    /**
+     * @return const char* literal "true" for true value, or literal "false"
+     *         for false value.
+     */
     static const char* ToPsz( bool b );
 
+    /**
+     * @return literal "1" for true value, or literal "0" for false value.
+     */
+    static const char* ToPsz10( bool b );
+
     static sax_fastparser::FSHelperPtr  WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int32 nValue );
     static sax_fastparser::FSHelperPtr  WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int64 nValue );
     static sax_fastparser::FSHelperPtr  WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, const char* sValue );
diff --git a/sc/source/filter/xcl97/XclExpChangeTrack.cxx b/sc/source/filter/xcl97/XclExpChangeTrack.cxx
index 3a3655d..fe27e92 100644
--- a/sc/source/filter/xcl97/XclExpChangeTrack.cxx
+++ b/sc/source/filter/xcl97/XclExpChangeTrack.cxx
@@ -40,7 +40,7 @@ static OString lcl_GuidToOString( sal_uInt8 aGuid[ 16 ] )
 {
     char sBuf[ 40 ];
     snprintf( sBuf, sizeof( sBuf ),
-            "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+            "{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
             aGuid[ 0 ], aGuid[ 1 ], aGuid[ 2 ], aGuid[ 3 ], aGuid[ 4 ], aGuid[ 5 ], aGuid[ 6 ], aGuid[ 7 ],
             aGuid[ 8 ], aGuid[ 9 ], aGuid[ 10 ], aGuid[ 11 ], aGuid[ 12 ], aGuid[ 13 ], aGuid[ 14 ], aGuid[ 15 ] );
     return OString( sBuf );
@@ -394,7 +394,149 @@ void XclExpChTrHeader::SaveXml( XclExpXmlStream& rRevisionHeadersStrm )
     pHeaders->write( ">" );
 }
 
-//___________________________________________________________________
+void XclExpXmlChTrHeaders::SetGUID( const sal_uInt8* pGUID )
+{
+    memcpy(maGUID, pGUID, 16);
+}
+
+void XclExpXmlChTrHeaders::SaveXml( XclExpXmlStream& rStrm )
+{
+    sax_fastparser::FSHelperPtr pHeaders = rStrm.GetCurrentStream();
+
+    pHeaders->write("<")->writeId(XML_headers);
+
+    rStrm.WriteAttributes(
+        XML_xmlns,              "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+        FSNS(XML_xmlns, XML_r), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
+        XML_guid,               lcl_GuidToOString(maGUID).getStr(),
+        XML_lastGuid,           NULL,   // OOXTODO
+        XML_shared,             NULL,   // OOXTODO
+        XML_diskRevisions,      NULL,   // OOXTODO
+        XML_history,            NULL,   // OOXTODO
+        XML_trackRevisions,     NULL,   // OOXTODO
+        XML_exclusive,          NULL,   // OOXTODO
+        XML_revisionId,         NULL,   // OOXTODO
+        XML_version,            NULL,   // OOXTODO
+        XML_keepChangeHistory,  NULL,   // OOXTODO
+        XML_protected,          NULL,   // OOXTODO
+        XML_preserveHistory,    NULL,   // OOXTODO
+        FSEND);
+
+    pHeaders->write(">");
+}
+
+XclExpXmlChTrHeader::XclExpXmlChTrHeader(
+    const OUString& rUserName, const DateTime& rDateTime, const sal_uInt8* pGUID,
+    sal_Int32 nLogNumber, const XclExpChTrTabIdBuffer& rBuf ) :
+    maUserName(rUserName), maDateTime(rDateTime), mnLogNumber(nLogNumber),
+    mnMinAction(0), mnMaxAction(0)
+{
+    memcpy(maGUID, pGUID, 16);
+    if (rBuf.GetBufferCount())
+    {
+        maTabBuffer.resize(rBuf.GetBufferCount());
+        rBuf.GetBufferCopy(&maTabBuffer[0]);
+    }
+}
+
+void XclExpXmlChTrHeader::SaveXml( XclExpXmlStream& rStrm )
+{
+    sax_fastparser::FSHelperPtr pHeader = rStrm.GetCurrentStream();
+
+    pHeader->write("<")->writeId(XML_header);
+
+    OUString aRelId;
+    sax_fastparser::FSHelperPtr pRevLogStrm = rStrm.CreateOutputStream(
+            XclXmlUtils::GetStreamName("xl/revisions/", "revisionLog", mnLogNumber),
+            XclXmlUtils::GetStreamName(NULL, "revisionLog", mnLogNumber),
+            rStrm.GetCurrentStream()->getOutputStream(),
+            "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml",
+            CREATE_OFFICEDOC_RELATION_TYPE("revisionLog"),
+            &aRelId);
+
+    rStrm.WriteAttributes(
+        XML_guid, lcl_GuidToOString(maGUID).getStr(),
+        XML_dateTime, lcl_DateTimeToOString(maDateTime).getStr(),
+        XML_userName, XclXmlUtils::ToOString(maUserName).getStr(),
+        FSNS(XML_r, XML_id),  XclXmlUtils::ToOString(aRelId).getStr(),
+        FSEND);
+
+    if (mnMinAction)
+        rStrm.WriteAttributes(XML_minRId, OString::number(mnMinAction).getStr(), FSEND);
+
+    if (mnMaxAction)
+        rStrm.WriteAttributes(XML_maxRId, OString::number(mnMaxAction).getStr(), FSEND);
+
+    if (!maTabBuffer.empty())
+        // next available sheet index.
+        rStrm.WriteAttributes(XML_maxSheetId, OString::number(maTabBuffer.back()+1).getStr(), FSEND);
+
+    pHeader->write(">");
+
+    if (!maTabBuffer.empty())
+    {
+        // Write sheet index map.
+        size_t n = maTabBuffer.size();
+        pHeader->startElement(
+            XML_sheetIdMap,
+            XML_count, OString::number(n).getStr(),
+            FSEND);
+
+        for (size_t i = 0; i < n; ++i)
+        {
+            pHeader->singleElement(
+                XML_sheetId,
+                XML_val, OString::number(maTabBuffer[i]).getStr(),
+                FSEND);
+        }
+        pHeader->endElement(XML_sheetIdMap);
+    }
+
+    // Write all revision logs in a separate stream.
+
+    rStrm.PushStream(pRevLogStrm);
+
+    pRevLogStrm->write("<")->writeId(XML_revisions);
+
+    rStrm.WriteAttributes(
+        XML_xmlns,              "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+        FSNS(XML_xmlns, XML_r), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
+        FSEND);
+
+    pRevLogStrm->write(">");
+
+    std::vector<XclExpChTrAction*>::iterator it = maActions.begin(), itEnd = maActions.end();
+    for (; it != itEnd; ++it)
+    {
+        XclExpChTrAction* p = *it;
+        p->SaveXml(rStrm);
+    }
+
+    pRevLogStrm->write("</")->writeId(XML_revisions)->write(">");
+
+    rStrm.PopStream();
+
+    pHeader->write("</")->writeId(XML_header)->write(">");
+}
+
+void XclExpXmlChTrHeader::AppendAction( XclExpChTrAction* pAction )
+{
+    sal_uInt32 nActionNum = pAction->GetActionNumber();
+    if (!mnMinAction || mnMinAction > nActionNum)
+        mnMinAction = nActionNum;
+
+    if (!mnMaxAction || mnMaxAction < nActionNum)
+        mnMaxAction = nActionNum;
+
+    maActions.push_back(pAction);
+}
+
+XclExpChTrInfo::XclExpChTrInfo( const OUString& rUsername, const DateTime& rDateTime, const sal_uInt8* pGUID ) :
+    sUsername( rUsername ),
+    aDateTime( rDateTime )
+{
+    memcpy( aGUID, pGUID, 16 );
+}
 
 XclExpChTrInfo::~XclExpChTrInfo()
 {
@@ -424,35 +566,6 @@ sal_Size XclExpChTrInfo::GetLen() const
     return 158;
 }
 
-void XclExpChTrInfo::SaveXml( XclExpXmlStream& rRevisionHeadersStrm )
-{
-    sax_fastparser::FSHelperPtr pHeader = rRevisionHeadersStrm.GetCurrentStream();
-
-    OUString sRelationshipId;
-    sax_fastparser::FSHelperPtr pRevisionLog = rRevisionHeadersStrm.CreateOutputStream(
-            XclXmlUtils::GetStreamName( "xl/revisions/", "revisionLog", mnLogNumber ),
-            XclXmlUtils::GetStreamName( NULL, "revisionLog", mnLogNumber ),
-            rRevisionHeadersStrm.GetCurrentStream()->getOutputStream(),
-            "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml",
-            "http://schemas.openxmlformats.org/officeDocument/2006/relationships/revisionLog",
-            &sRelationshipId );
-
-    rRevisionHeadersStrm.WriteAttributes(
-            XML_guid,               lcl_GuidToOString( aGUID ).getStr(),
-            XML_dateTime,           lcl_DateTimeToOString( aDateTime ).getStr(),
-            XML_maxSheetId,         NULL,   // OOXTODO
-            XML_userName,           XclXmlUtils::ToOString( sUsername ).getStr(),
-            FSNS( XML_r, XML_id ),  XclXmlUtils::ToOString( sRelationshipId ).getStr(),
-            XML_minRId,             NULL,   // OOXTODO
-            XML_maxRId,             NULL,   // OOXTODO
-            FSEND );
-    pHeader->write( ">" );
-
-    rRevisionHeadersStrm.PushStream( pRevisionLog );
-}
-
-//___________________________________________________________________
-
 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( sal_uInt16 nCount ) :
     nBufSize( nCount ),
     nLastId( nCount )
@@ -523,11 +636,8 @@ void XclExpChTrTabIdBuffer::Remove()
     nLastId--;
 }
 
-//___________________________________________________________________
-
-XclExpChTrTabId::XclExpChTrTabId( const XclExpChTrTabIdBuffer& rBuffer, bool bInRevisionHeaders )
+XclExpChTrTabId::XclExpChTrTabId( const XclExpChTrTabIdBuffer& rBuffer )
     : nTabCount( rBuffer.GetBufferCount() )
-    , mbInRevisionHeaders( bInRevisionHeaders )
 {
     pBuffer = new sal_uInt16[ nTabCount ];
     rBuffer.GetBufferCopy( pBuffer );
@@ -567,31 +677,6 @@ sal_Size XclExpChTrTabId::GetLen() const
     return nTabCount << 1;
 }
 
-void XclExpChTrTabId::SaveXml( XclExpXmlStream& rRevisionLogStrm )
-{
-    if( !mbInRevisionHeaders )
-        return;
-
-    sax_fastparser::FSHelperPtr pRevisionLog = rRevisionLogStrm.GetCurrentStream();
-    rRevisionLogStrm.PopStream();
-
-    sax_fastparser::FSHelperPtr pHeader = rRevisionLogStrm.GetCurrentStream();
-    pHeader->startElement( XML_sheetIdMap,
-            XML_count,  OString::number( nTabCount ).getStr(),
-            FSEND );
-    for( int i = 0; i < nTabCount; ++i )
-    {
-        pHeader->singleElement( XML_sheetId,
-                XML_val,    OString::number( pBuffer[ i ] ).getStr(),
-                FSEND );
-    }
-    pHeader->endElement( XML_sheetIdMap );
-
-    rRevisionLogStrm.PushStream( pRevisionLog );
-}
-
-//___________________________________________________________________
-
 // ! does not copy additional actions
 XclExpChTrAction::XclExpChTrAction( const XclExpChTrAction& rCopy ) :
     ExcRecord( rCopy ),
@@ -1137,11 +1222,12 @@ void XclExpChTrInsert::SaveXml( XclExpXmlStream& rRevisionLogStrm )
             XML_ua,     XclXmlUtils::ToPsz( GetAccepted () ),   // OOXTODO? bAccepted == ua or ra; not sure.
             XML_ra,     NULL,       // OOXTODO: RRD.fUndoAction?  Or RRD.fAccepted?
             XML_sId,    OString::number(  GetTabId( aRange.aStart.Tab() ) ).getStr(),
-            XML_eol,    NULL,       // OOXTODO: not supported?
+            XML_eol,    XclXmlUtils::ToPsz10(mbEndOfList),
             XML_ref,    XclXmlUtils::ToOString( aRange ).getStr(),
             XML_action, lcl_GetAction( nOpCode ),
             XML_edge,   NULL,       // OOXTODO: ???
             FSEND );
+
     // OOXTODO: does this handle XML_rfmt, XML_undo?
     XclExpChTrAction* pAction = GetAddAction();
     while( pAction != NULL )
@@ -1329,17 +1415,6 @@ void XclExpChTr0x014A::SaveXml( XclExpXmlStream& rStrm )
     pStream->endElement( XML_rfmt );
 }
 
-//___________________________________________________________________
-
-class ExcXmlRecord : public ExcRecord
-{
-public:
-    virtual sal_Size    GetLen() const;
-    virtual sal_uInt16  GetNum() const;
-    virtual void        Save( XclExpStream& rStrm );
-    virtual void        SaveXml( XclExpXmlStream& rStrm ) = 0;
-};
-
 sal_Size ExcXmlRecord::GetLen() const
 {
     return 0;
@@ -1458,66 +1533,83 @@ XclExpChangeTrack::XclExpChangeTrack( const XclExpRoot& rRoot ) :
     }
 
     // build record list
-    pHeader = new XclExpChTrHeader;
-    aRecList.push_back( new StartXmlElement( XML_headers, StartXmlElement::WRITE_NAMESPACES ) );
-    aRecList.push_back( pHeader );
-    aRecList.push_back( new XclExpChTr0x0195 );
-    aRecList.push_back( new XclExpChTr0x0194( *pTempChangeTrack ) );
-
-    OUString sLastUsername;
-    DateTime aLastDateTime( DateTime::EMPTY );
-    sal_uInt32 nIndex = 1;
-    sal_Int32 nLogNumber = 1;
-    while( !aActionStack.empty() )
+    if (GetOutput() == EXC_OUTPUT_BINARY)
     {
-        XclExpChTrAction* pAction = aActionStack.top();
-        aActionStack.pop();
-
-        if( (nIndex == 1) || pAction->ForceInfoRecord() ||
-            (pAction->GetUsername() != sLastUsername) ||
-            (pAction->GetDateTime() != aLastDateTime) )
+        pHeader = new XclExpChTrHeader;
+        maRecList.push_back( pHeader );
+        maRecList.push_back( new XclExpChTr0x0195 );
+        maRecList.push_back( new XclExpChTr0x0194( *pTempChangeTrack ) );
+
+        OUString sLastUsername;
+        DateTime aLastDateTime( DateTime::EMPTY );
+        sal_uInt32 nIndex = 1;
+        sal_Int32 nLogNumber = 1;
+        while( !aActionStack.empty() )
         {
-            if( nIndex != 1 )
+            XclExpChTrAction* pAction = aActionStack.top();
+            aActionStack.pop();
+
+            if( (nIndex == 1) || pAction->ForceInfoRecord() ||
+                (pAction->GetUsername() != sLastUsername) ||
+                (pAction->GetDateTime() != aLastDateTime) )
             {
-                aRecList.push_back( new EndXmlElement( XML_revisions ) );
-                aRecList.push_back( new EndHeaderElement() );
+                lcl_GenerateGUID( aGUID, bValidGUID );
+                sLastUsername = pAction->GetUsername();
+                aLastDateTime = pAction->GetDateTime();
+
+                nLogNumber++;
+                maRecList.push_back( new XclExpChTrInfo(sLastUsername, aLastDateTime, aGUID) );
+                maRecList.push_back( new XclExpChTrTabId(pAction->GetTabIdBuffer()) );
+                pHeader->SetGUID( aGUID );
             }
+            pAction->SetIndex( nIndex );
+            maRecList.push_back( pAction );
+        }
 
-            lcl_GenerateGUID( aGUID, bValidGUID );
-            sLastUsername = pAction->GetUsername();
-            aLastDateTime = pAction->GetDateTime();
+        pHeader->SetGUID( aGUID );
+        pHeader->SetCount( nIndex - 1 );
+        maRecList.push_back( new ExcEof );
+    }
+    else
+    {
+        XclExpXmlChTrHeaders* pHeaders = new XclExpXmlChTrHeaders;
+        maRecList.push_back(pHeaders);
+
+        OUString sLastUsername;
+        DateTime aLastDateTime(DateTime::EMPTY);
+        sal_uInt32 nIndex = 1;
+        sal_Int32 nLogNumber = 1;
+        XclExpXmlChTrHeader* pCurHeader = NULL;
+
+        while (!aActionStack.empty())
+        {
+            XclExpChTrAction* pAction = aActionStack.top();
+            aActionStack.pop();
 
-            aRecList.push_back( new StartXmlElement( XML_header, 0 ) );
-            aRecList.push_back( new XclExpChTrInfo( sLastUsername, aLastDateTime, aGUID, nLogNumber++ ) );
-            aRecList.push_back( new XclExpChTrTabId( pAction->GetTabIdBuffer(), true ) );
-            aRecList.push_back( new StartXmlElement( XML_revisions, StartXmlElement::WRITE_NAMESPACES | StartXmlElement::CLOSE_ELEMENT ) );
-            pHeader->SetGUID( aGUID );
+            if( (nIndex == 1) || pAction->ForceInfoRecord() ||
+                (pAction->GetUsername() != sLastUsername) ||
+                (pAction->GetDateTime() != aLastDateTime) )
+            {
+                lcl_GenerateGUID( aGUID, bValidGUID );
+                sLastUsername = pAction->GetUsername();
+                aLastDateTime = pAction->GetDateTime();
+
+                pCurHeader = new XclExpXmlChTrHeader(sLastUsername, aLastDateTime, aGUID, nLogNumber, pAction->GetTabIdBuffer());
+                maRecList.push_back(pCurHeader);
+                nLogNumber++;
+                pHeaders->SetGUID(aGUID);
+            }
+            pAction->SetIndex(nIndex);
+            pCurHeader->AppendAction(pAction);
         }
-        pAction->SetIndex( nIndex );
-        aRecList.push_back( pAction );
-    }
 
-    pHeader->SetGUID( aGUID );
-    pHeader->SetCount( nIndex - 1 );
-    if( nLogNumber > 1 )
-    {
-        aRecList.push_back( new EndXmlElement( XML_revisions ) );
-        aRecList.push_back( new EndHeaderElement() );
+        pHeaders->SetGUID(aGUID);
+        maRecList.push_back(new EndXmlElement(XML_headers));
     }
-    aRecList.push_back( new EndXmlElement( XML_headers ) );
-    aRecList.push_back( new ExcEof );
 }
 
 XclExpChangeTrack::~XclExpChangeTrack()
 {
-    std::vector<ExcRecord*>::iterator prIter;
-    for ( prIter = aRecList.begin(); prIter != aRecList.end(); ++prIter )
-        delete *prIter;
-
-    std::vector<XclExpChTrTabIdBuffer*>::iterator pIter;
-    for ( pIter = maBuffers.begin(); pIter != maBuffers.end(); ++pIter )
-        delete *pIter;
-
     while( !aActionStack.empty() )
     {
         delete aActionStack.top();
@@ -1613,7 +1705,7 @@ sal_Bool XclExpChangeTrack::WriteUserNamesStream()
 
 void XclExpChangeTrack::Write()
 {
-    if( aRecList.empty() )
+    if (maRecList.empty())
         return;
 
     if( WriteUserNamesStream() )
@@ -1624,9 +1716,9 @@ void XclExpChangeTrack::Write()
         {
             XclExpStream aXclStrm( *xSvStrm, GetRoot(), EXC_MAXRECSIZE_BIFF8 + 8 );
 
-            std::vector<ExcRecord*>::iterator pIter;
-            for ( pIter = aRecList.begin(); pIter != aRecList.end(); ++pIter )
-                (*pIter)->Save(aXclStrm);
+            RecListType::iterator pIter;
+            for (pIter = maRecList.begin(); pIter != maRecList.end(); ++pIter)
+                pIter->Save(aXclStrm);
 
             xSvStrm->Commit();
         }
@@ -1654,7 +1746,7 @@ static void lcl_WriteUserNamesXml( XclExpXmlStream& rWorkbookStrm )
 
 void XclExpChangeTrack::WriteXml( XclExpXmlStream& rWorkbookStrm )
 {
-    if( aRecList.empty() )
+    if (maRecList.empty())
         return;
 
     lcl_WriteUserNamesXml( rWorkbookStrm );
@@ -1670,9 +1762,9 @@ void XclExpChangeTrack::WriteXml( XclExpXmlStream& rWorkbookStrm )
     //          contents of XclExpChangeTrack::WriteUserNamesStream()).
     rWorkbookStrm.PushStream( pRevisionHeaders );
 
-    std::vector<ExcRecord*>::iterator pIter;
-    for ( pIter = aRecList.begin(); pIter != aRecList.end(); ++pIter )
-        (*pIter)->SaveXml(rWorkbookStrm);
+    RecListType::iterator pIter;
+    for (pIter = maRecList.begin(); pIter != maRecList.end(); ++pIter)
+        pIter->SaveXml(rWorkbookStrm);
 
     rWorkbookStrm.PopStream();
 }
commit 6c24bf4cab7e2a9514cf99160a31728835198741
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Jul 16 19:59:35 2014 -0400

    bnc#885548: Initial work on importing revisions from xlsx.
    
    Change-Id: Ie0528490d024093cbabf38541fe70be96a9caa2e
    (cherry picked from commit b92fdaa1a40bd54d279b4ac2faf19bf15468cc2f)

diff --git a/sc/Library_scfilt.mk b/sc/Library_scfilt.mk
index eb0d5d2..c034e61 100644
--- a/sc/Library_scfilt.mk
+++ b/sc/Library_scfilt.mk
@@ -198,6 +198,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\
 	sc/source/filter/oox/pivottablefragment \
 	sc/source/filter/oox/querytablebuffer \
 	sc/source/filter/oox/querytablefragment \
+	sc/source/filter/oox/revisionfragment \
 	sc/source/filter/oox/richstringcontext \
 	sc/source/filter/oox/richstring \
 	sc/source/filter/oox/scenariobuffer \
diff --git a/sc/inc/chgtrack.hxx b/sc/inc/chgtrack.hxx
index 3d4026b..f035de4 100644
--- a/sc/inc/chgtrack.hxx
+++ b/sc/inc/chgtrack.hxx
@@ -1128,7 +1128,7 @@ public:
                         sal_uLong nOldFormat, ScDocument* pRefDoc = NULL );
                         // after new value was set in the document,
                         // old value from pOldCell, format from Doc
-    void AppendContent( const ScAddress& rPos, const ScCellValue& rOldCell );
+    SC_DLLPUBLIC void AppendContent( const ScAddress& rPos, const ScCellValue& rOldCell );
                         // after new values were set in the document,
                         // old values from RefDoc/UndoDoc.
                         // All contents with a cell in RefDoc
diff --git a/sc/source/filter/inc/revisionfragment.hxx b/sc/source/filter/inc/revisionfragment.hxx
new file mode 100644
index 0000000..473549e
--- /dev/null
+++ b/sc/source/filter/inc/revisionfragment.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SC_OOX_XLS_REVISIONFRAGMENT_HXX
+#define INCLUDED_SC_OOX_XLS_REVISIONFRAGMENT_HXX
+
+#include <excelhandlers.hxx>
+
+class ScChangeTrack;
+
+namespace oox { namespace xls {
+
+class RevisionHeadersFragment : public WorkbookFragmentBase
+{
+    struct Impl;
+    Impl* mpImpl;
+
+public:
+    explicit RevisionHeadersFragment(
+        const WorkbookHelper& rHelper, const OUString& rFragmentPath );
+
+    virtual ~RevisionHeadersFragment();
+
+protected:
+    virtual oox::core::ContextHandlerRef onCreateContext(
+        sal_Int32 nElement, const AttributeList& rAttribs ) SAL_OVERRIDE;
+
+    virtual void onStartElement( const AttributeList& rAttribs ) SAL_OVERRIDE;
+    virtual void onCharacters( const OUString& rChars ) SAL_OVERRIDE;
+    virtual void onEndElement() SAL_OVERRIDE;
+
+    virtual void finalizeImport() SAL_OVERRIDE;
+
+private:
+    void importHeaders( const AttributeList& rAttribs );
+    void importHeader( const AttributeList& rAttribs );
+};
+
+class RevisionLogFragment : public WorkbookFragmentBase
+{
+    struct Impl;
+    Impl* mpImpl;
+
+public:
+    explicit RevisionLogFragment(
+        const WorkbookHelper& rHelper, const OUString& rFragmentPath, ScChangeTrack& rChangeTrack );
+
+    virtual ~RevisionLogFragment();
+
+protected:
+    virtual oox::core::ContextHandlerRef onCreateContext(
+        sal_Int32 nElement, const AttributeList& rAttribs ) SAL_OVERRIDE;
+
+    virtual void onStartElement( const AttributeList& rAttribs ) SAL_OVERRIDE;
+    virtual void onCharacters( const OUString& rChars ) SAL_OVERRIDE;
+    virtual void onEndElement() SAL_OVERRIDE;
+
+    virtual void finalizeImport() SAL_OVERRIDE;
+
+private:
+    void importCommon( const AttributeList& rAttribs );
+    void importRcc( const AttributeList& rAttribs );
+    void importRrc( const AttributeList& rAttribs );
+
+    void pushRevision();
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/sc/source/filter/oox/revisionfragment.cxx b/sc/source/filter/oox/revisionfragment.cxx
new file mode 100644
index 0000000..dd8cc4b
--- /dev/null
+++ b/sc/source/filter/oox/revisionfragment.cxx
@@ -0,0 +1,462 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <revisionfragment.hxx>
+#include <oox/core/relations.hxx>
+#include <oox/core/xmlfilterbase.hxx>
+#include <oox/core/fastparser.hxx>
+#include <o3tl/heap_ptr.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <sax/tools/converter.hxx>
+#include <editeng/editobj.hxx>
+
+#include <chgtrack.hxx>
+#include <document.hxx>
+#include <compiler.hxx>
+#include <editutil.hxx>
+#include <formulacell.hxx>
+#include <chgviset.hxx>
+#include <richstringcontext.hxx>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <com/sun/star/util/DateTime.hpp>
+
+using namespace com::sun::star;
+
+namespace oox { namespace xls {
+
+namespace {
+
+enum RevisionType
+{
+    REV_UNKNOWN = 0,
+    REV_CELLCHANGE,
+    REV_INSERTROW,
+    REV_DELETEROW,
+    REV_INSERTCOL,
+    REV_DELETECOL
+};
+
+/**
+ * For nc (new cell) or oc (old cell) elements under rcc (cell content
+ * revision).
+ */
+class RCCCellValueContext : public WorkbookContextBase
+{
+    sal_Int32 mnSheetIndex;
+    ScAddress& mrPos;
+    ScCellValue& mrCellValue;
+    sal_Int32 mnType;
+
+    RichStringRef mxRichString;
+
+public:
+    RCCCellValueContext(
+        RevisionLogFragment& rParent, sal_Int32 nSheetIndex, ScAddress& rPos, ScCellValue& rCellValue ) :
+        WorkbookContextBase(rParent),
+        mnSheetIndex(nSheetIndex),
+        mrPos(rPos),
+        mrCellValue(rCellValue),
+        mnType(-1) {}
+
+protected:
+    virtual oox::core::ContextHandlerRef onCreateContext(
+        sal_Int32 nElement, const AttributeList& /*rAttribs*/ ) SAL_OVERRIDE
+    {
+        if (nElement == XLS_TOKEN(is))
+        {
+            mxRichString.reset(new RichString(*this));
+            return new RichStringContext(*this, mxRichString);
+        }
+
+        return this;
+    }
+
+    virtual void onStartElement( const AttributeList& rAttribs ) SAL_OVERRIDE
+    {
+        switch (getCurrentElement())
+        {
+            case XLS_TOKEN(nc):
+            case XLS_TOKEN(oc):
+                importCell(rAttribs);
+            break;
+            default:
+                ;
+        }
+    }
+
+    virtual void onCharacters( const OUString& rChars ) SAL_OVERRIDE
+    {
+        switch (getCurrentElement())
+        {
+            case XLS_TOKEN(v):
+            {
+                if (mnType == XML_n || mnType == XML_b)
+                    mrCellValue.set(rChars.toDouble());
+            }
+            break;
+            case XLS_TOKEN(t):
+            {
+                if (mnType == XML_inlineStr)
+                {
+                    ScDocument& rDoc = getScDocument();
+                    svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
+                    mrCellValue.set(rPool.intern(rChars));
+                }
+            }
+            break;
+            case XLS_TOKEN(f):
+            {
+                // formula string
+                ScDocument& rDoc = getScDocument();
+                ScCompiler aComp(&rDoc, mrPos);
+                aComp.SetGrammar(formula::FormulaGrammar::GRAM_OOXML);
+                ScTokenArray* pArray = aComp.CompileString(rChars);
+                if (!pArray)
+                    break;
+
+                mrCellValue.set(new ScFormulaCell(&rDoc, mrPos, pArray));
+            }
+            break;
+            default:
+                ;
+        }
+    }
+
+    virtual void onEndElement() SAL_OVERRIDE
+    {
+        switch (getCurrentElement())
+        {
+            case XLS_TOKEN(nc):
+            case XLS_TOKEN(oc):
+            {
+                if (mrCellValue.isEmpty() && mxRichString)
+                {
+                    // The value is a rich text string.
+                    ScDocument& rDoc = getScDocument();
+                    EditTextObject* pTextObj = mxRichString->convert(rDoc.GetEditEngine(), NULL);
+                    if (pTextObj)
+                    {
+                        svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
+                        pTextObj->NormalizeString(rPool);
+                        mrCellValue.set(pTextObj);
+                    }
+                }
+            }
+            break;
+            default:
+                ;
+        }
+    }
+
+private:
+    void importCell( const AttributeList& rAttribs )
+    {
+        mnType = rAttribs.getToken(XML_t, XML_n);
+        OUString aRefStr = rAttribs.getString(XML_r, OUString());
+        if (!aRefStr.isEmpty())
+        {
+            mrPos.Parse(aRefStr, NULL, formula::FormulaGrammar::CONV_XL_OOX);
+            if (mnSheetIndex != -1)
+                mrPos.SetTab(mnSheetIndex-1);
+        }
+    }
+};
+
+struct RevisionMetadata
+{
+    OUString maUserName;
+    DateTime maDateTime;
+
+    RevisionMetadata() : maDateTime(DateTime::EMPTY) {}
+    RevisionMetadata( const RevisionMetadata& r ) :
+        maUserName(r.maUserName), maDateTime(r.maDateTime) {}
+};
+
+}
+
+typedef std::map<OUString, RevisionMetadata> RevDataType;
+
+struct RevisionHeadersFragment::Impl
+{
+    RevDataType maRevData;
+
+    Impl() {}
+};
+
+RevisionHeadersFragment::RevisionHeadersFragment(
+    const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+    WorkbookFragmentBase(rHelper, rFragmentPath),
+    mpImpl(new Impl) {}
+
+RevisionHeadersFragment::~RevisionHeadersFragment()
+{
+    delete mpImpl;
+}
+
+oox::core::ContextHandlerRef RevisionHeadersFragment::onCreateContext(
+    sal_Int32 /*nElement*/, const AttributeList& /*rAttribs*/ )
+{
+    return this;
+}
+
+void RevisionHeadersFragment::onStartElement( const AttributeList& rAttribs )
+{
+    switch (getCurrentElement())
+    {
+        case XLS_TOKEN(headers):
+            importHeaders(rAttribs);
+        break;
+        case XLS_TOKEN(header):
+            importHeader(rAttribs);
+        break;
+        case XLS_TOKEN(sheetIdMap):
+        break;
+        case XLS_TOKEN(sheetId):
+        break;
+        default:
+            ;
+    }
+}
+
+void RevisionHeadersFragment::onCharacters( const OUString& /*rChars*/ ) {}
+
+void RevisionHeadersFragment::onEndElement()
+{
+    switch (getCurrentElement())
+    {
+        case XLS_TOKEN(headers):
+        break;
+        case XLS_TOKEN(header):
+        break;
+        case XLS_TOKEN(sheetIdMap):
+        break;
+        case XLS_TOKEN(sheetId):
+        break;
+        default:
+            ;
+    }
+}
+
+void RevisionHeadersFragment::finalizeImport()
+{
+    ScDocument& rDoc = getScDocument();
+    o3tl::heap_ptr<ScChangeTrack> pCT(new ScChangeTrack(&rDoc));
+    pCT->SetUseFixDateTime(true);
+
+    const oox::core::Relations& rRels = getRelations();
+    RevDataType::const_iterator it = mpImpl->maRevData.begin(), itEnd = mpImpl->maRevData.end();
+    for (; it != itEnd; ++it)
+    {
+        OUString aPath = rRels.getFragmentPathFromRelId(it->first);
+        if (aPath.isEmpty())
+            continue;
+
+        // Parse each reivison log fragment.
+        const RevisionMetadata& rData = it->second;
+        pCT->SetUser(rData.maUserName);
+        pCT->SetFixDateTimeLocal(rData.maDateTime);
+        boost::scoped_ptr<oox::core::FastParser> xParser(getOoxFilter().createParser());
+        rtl::Reference<oox::core::FragmentHandler> xFragment(new RevisionLogFragment(*this, aPath, *pCT));
+        importOoxFragment(xFragment, *xParser);
+    }
+
+    rDoc.SetChangeTrack(pCT.release());
+
+    // Turn on visibility of tracked changes.
+    ScChangeViewSettings aSettings;
+    aSettings.SetShowChanges(true);
+    rDoc.SetChangeViewSettings(aSettings);
+}
+
+void RevisionHeadersFragment::importHeaders( const AttributeList& /*rAttribs*/ )
+{
+    // Nothing for now.
+}
+
+void RevisionHeadersFragment::importHeader( const AttributeList& rAttribs )
+{
+    OUString aRId = rAttribs.getString(R_TOKEN(id), OUString());
+    if (aRId.isEmpty())
+        // All bets are off if we don't have a relation ID.
+        return;
+
+    RevisionMetadata aMetadata;
+    OUString aDateTimeStr = rAttribs.getString(XML_dateTime, OUString());
+    if (!aDateTimeStr.isEmpty())
+    {
+        util::DateTime aDateTime;
+        sax::Converter::parseDateTime(aDateTime, 0, aDateTimeStr);
+        Date aDate(aDateTime.Day, aDateTime.Month, aDateTime.Year);
+        Time aTime(aDateTime.Hours, aDateTime.Minutes, aDateTime.Seconds, aDateTime.NanoSeconds);
+        aMetadata.maDateTime.SetDate(aDate.GetDate());
+        aMetadata.maDateTime.SetTime(aTime.GetTime());
+    }
+
+    aMetadata.maUserName = rAttribs.getString(XML_userName, OUString());
+
+    mpImpl->maRevData.insert(RevDataType::value_type(aRId, aMetadata));
+}
+
+struct RevisionLogFragment::Impl
+{
+    ScChangeTrack& mrChangeTrack;
+
+    sal_Int32 mnRevIndex;
+    sal_Int32 mnSheetIndex;
+
+    RevisionType meType;
+
+    // rcc
+    ScAddress maOldCellPos;
+    ScAddress maNewCellPos;
+    ScCellValue maOldCellValue;
+    ScCellValue maNewCellValue;
+
+    // rrc
+    ScRange maRange;
+
+    bool mbEndOfList;
+
+    Impl( ScChangeTrack& rChangeTrack ) :
+        mrChangeTrack(rChangeTrack),
+        mnRevIndex(-1),
+        mnSheetIndex(-1),
+        meType(REV_UNKNOWN),
+        mbEndOfList(false) {}
+};
+
+RevisionLogFragment::RevisionLogFragment(
+    const WorkbookHelper& rHelper, const OUString& rFragmentPath, ScChangeTrack& rChangeTrack ) :
+    WorkbookFragmentBase(rHelper, rFragmentPath),
+    mpImpl(new Impl(rChangeTrack)) {}
+
+RevisionLogFragment::~RevisionLogFragment()
+{
+    delete mpImpl;
+}
+
+oox::core::ContextHandlerRef RevisionLogFragment::onCreateContext(
+    sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
+{
+    switch (nElement)
+    {
+        case XLS_TOKEN(nc):
+            return new RCCCellValueContext(*this, mpImpl->mnSheetIndex, mpImpl->maNewCellPos, mpImpl->maNewCellValue);
+        case XLS_TOKEN(oc):
+            return new RCCCellValueContext(*this, mpImpl->mnSheetIndex, mpImpl->maOldCellPos, mpImpl->maOldCellValue);
+        default:
+            ;
+    }
+    return this;
+}
+
+void RevisionLogFragment::onStartElement( const AttributeList& rAttribs )
+{
+    switch (getCurrentElement())
+    {
+        case XLS_TOKEN(rcc):
+            mpImpl->maNewCellPos.SetInvalid();
+            mpImpl->maOldCellPos.SetInvalid();
+            mpImpl->maNewCellValue.clear();
+            mpImpl->maOldCellValue.clear();
+            importRcc(rAttribs);
+        break;
+        case XLS_TOKEN(rrc):
+            importRrc(rAttribs);
+        break;
+        default:
+            ;
+    }
+}
+
+void RevisionLogFragment::onCharacters( const OUString& /*rChars*/ ) {}
+
+void RevisionLogFragment::onEndElement()
+{
+    switch (getCurrentElement())
+    {
+        case XLS_TOKEN(rcc):
+        case XLS_TOKEN(rrc):
+            pushRevision();
+        break;
+        default:
+            ;
+    }
+}
+
+void RevisionLogFragment::finalizeImport() {}
+
+void RevisionLogFragment::importCommon( const AttributeList& rAttribs )
+{
+    mpImpl->mnRevIndex   = rAttribs.getInteger(XML_rId, -1);
+    mpImpl->mnSheetIndex = rAttribs.getInteger(XML_sId, -1);
+}
+
+void RevisionLogFragment::importRcc( const AttributeList& rAttribs )
+{
+    importCommon(rAttribs);
+
+    mpImpl->meType = REV_CELLCHANGE;
+}
+
+void RevisionLogFragment::importRrc( const AttributeList& rAttribs )
+{
+    importCommon(rAttribs);
+
+    if (mpImpl->mnSheetIndex == -1)
+        // invalid sheet index, or sheet index not given.
+        return;
+
+    mpImpl->meType = REV_UNKNOWN;
+    sal_Int32 nAction = rAttribs.getToken(XML_action, -1);
+    if (nAction == -1)
+        return;
+
+    OUString aRefStr = rAttribs.getString(XML_ref, OUString());
+    mpImpl->maRange.Parse(aRefStr, &getScDocument(), formula::FormulaGrammar::CONV_XL_OOX);
+    if (!mpImpl->maRange.IsValid())
+        return;
+
+    switch (nAction)
+    {
+        case XML_insertRow:
+            mpImpl->meType = REV_INSERTROW;
+            mpImpl->maRange.aEnd.SetCol(MAXCOL);
+            mpImpl->maRange.aStart.SetTab(mpImpl->mnSheetIndex-1);
+            mpImpl->maRange.aEnd.SetTab(mpImpl->mnSheetIndex-1);
+        break;
+        default:
+            // Unknown action type.  Ignore it.
+            return;
+    }
+
+    mpImpl->mbEndOfList = rAttribs.getBool(XML_eol, false);
+}
+
+void RevisionLogFragment::pushRevision()
+{
+    switch (mpImpl->meType)
+    {
+        case REV_CELLCHANGE:
+            mpImpl->mrChangeTrack.AppendContentOnTheFly(
+                mpImpl->maNewCellPos, mpImpl->maOldCellValue, mpImpl->maNewCellValue);
+        break;
+        case REV_INSERTROW:
+            mpImpl->mrChangeTrack.AppendInsert(mpImpl->maRange, mpImpl->mbEndOfList);
+        break;
+        default:
+            ;
+    }
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/workbookfragment.cxx b/sc/source/filter/oox/workbookfragment.cxx
index bf42f46..283aa74 100644
--- a/sc/source/filter/oox/workbookfragment.cxx
+++ b/sc/source/filter/oox/workbookfragment.cxx
@@ -36,6 +36,7 @@
 #include "pivotcachebuffer.hxx"
 #include "sharedstringsbuffer.hxx"
 #include "sharedstringsfragment.hxx"
+#include "revisionfragment.hxx"
 #include "stylesfragment.hxx"
 #include "tablebuffer.hxx"
 #include "themebuffer.hxx"
@@ -300,7 +301,7 @@ public:
     }
 };
 
-static void importSheetFragments( WorkbookFragment& rWorkbookHandler, SheetFragmentVector& rSheets )
+void importSheetFragments( WorkbookFragment& rWorkbookHandler, SheetFragmentVector& rSheets )
 {
     sal_Int32 nThreads = std::min( rSheets.size(), (size_t) 4 /* FIXME: ncpus/2 */ );
 
@@ -499,6 +500,14 @@ void WorkbookFragment::finalizeImport()
 
     // final conversions, e.g. calculation settings and view settings
     finalizeWorkbookImport();
+
+    OUString aRevHeadersPath = getFragmentPathFromFirstType(CREATE_OFFICEDOC_RELATION_TYPE("revisionHeaders"));
+    if (!aRevHeadersPath.isEmpty())
+    {
+        boost::scoped_ptr<oox::core::FastParser> xParser(getOoxFilter().createParser());
+        rtl::Reference<oox::core::FragmentHandler> xFragment(new RevisionHeadersFragment(*this, aRevHeadersPath));
+        importOoxFragment(xFragment, *xParser);
+    }
 }
 
 // private --------------------------------------------------------------------


More information about the Libreoffice-commits mailing list