Kaydet (Commit) b92fdaa1 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

bnc#885548: Initial work on importing revisions from xlsx.

Change-Id: Ie0528490d024093cbabf38541fe70be96a9caa2e
üst ffeb0362
...@@ -199,6 +199,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\ ...@@ -199,6 +199,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\
sc/source/filter/oox/pivottablefragment \ sc/source/filter/oox/pivottablefragment \
sc/source/filter/oox/querytablebuffer \ sc/source/filter/oox/querytablebuffer \
sc/source/filter/oox/querytablefragment \ sc/source/filter/oox/querytablefragment \
sc/source/filter/oox/revisionfragment \
sc/source/filter/oox/richstringcontext \ sc/source/filter/oox/richstringcontext \
sc/source/filter/oox/richstring \ sc/source/filter/oox/richstring \
sc/source/filter/oox/scenariobuffer \ sc/source/filter/oox/scenariobuffer \
......
...@@ -1099,7 +1099,7 @@ public: ...@@ -1099,7 +1099,7 @@ public:
sal_uLong nOldFormat, ScDocument* pRefDoc = NULL ); sal_uLong nOldFormat, ScDocument* pRefDoc = NULL );
// after new value was set in the document, // after new value was set in the document,
// old value from pOldCell, format from Doc // 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, // after new values were set in the document,
// old values from RefDoc/UndoDoc. // old values from RefDoc/UndoDoc.
// All contents with a cell in RefDoc // All contents with a cell in RefDoc
......
/* -*- 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: */
/* -*- 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: */
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "pivotcachebuffer.hxx" #include "pivotcachebuffer.hxx"
#include "sharedstringsbuffer.hxx" #include "sharedstringsbuffer.hxx"
#include "sharedstringsfragment.hxx" #include "sharedstringsfragment.hxx"
#include "revisionfragment.hxx"
#include "stylesfragment.hxx" #include "stylesfragment.hxx"
#include "tablebuffer.hxx" #include "tablebuffer.hxx"
#include "themebuffer.hxx" #include "themebuffer.hxx"
...@@ -293,7 +294,7 @@ public: ...@@ -293,7 +294,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 */ ); sal_Int32 nThreads = std::min( rSheets.size(), (size_t) 4 /* FIXME: ncpus/2 */ );
...@@ -490,6 +491,14 @@ void WorkbookFragment::finalizeImport() ...@@ -490,6 +491,14 @@ void WorkbookFragment::finalizeImport()
// final conversions, e.g. calculation settings and view settings // final conversions, e.g. calculation settings and view settings
finalizeWorkbookImport(); 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 -------------------------------------------------------------------- // private --------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment