1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <sal/config.h>
14 #include <revisionfragment.hxx>
15 #include <oox/core/relations.hxx>
16 #include <oox/core/xmlfilterbase.hxx>
17 #include <oox/core/fastparser.hxx>
18 #include <svl/sharedstringpool.hxx>
19 #include <sax/tools/converter.hxx>
20 #include <editeng/editobj.hxx>
22 #include <chgtrack.hxx>
23 #include <document.hxx>
24 #include <compiler.hxx>
25 #include <editutil.hxx>
26 #include <formulacell.hxx>
27 #include <chgviset.hxx>
28 #include <richstringcontext.hxx>
30 #include <boost/scoped_ptr.hpp>
32 #include <com/sun/star/util/DateTime.hpp>
34 using namespace com::sun::star
;
36 namespace oox
{ namespace xls
{
51 * For nc (new cell) or oc (old cell) elements under rcc (cell content
54 class RCCCellValueContext
: public WorkbookContextBase
56 sal_Int32 mnSheetIndex
;
58 ScCellValue
& mrCellValue
;
61 RichStringRef mxRichString
;
65 RevisionLogFragment
& rParent
, sal_Int32 nSheetIndex
, ScAddress
& rPos
, ScCellValue
& rCellValue
) :
66 WorkbookContextBase(rParent
),
67 mnSheetIndex(nSheetIndex
),
69 mrCellValue(rCellValue
),
73 virtual oox::core::ContextHandlerRef
onCreateContext(
74 sal_Int32 nElement
, const AttributeList
& /*rAttribs*/ ) SAL_OVERRIDE
76 if (nElement
== XLS_TOKEN(is
))
78 mxRichString
.reset(new RichString(*this));
79 return new RichStringContext(*this, mxRichString
);
85 virtual void onStartElement( const AttributeList
& rAttribs
) SAL_OVERRIDE
87 switch (getCurrentElement())
98 virtual void onCharacters( const OUString
& rChars
) SAL_OVERRIDE
100 switch (getCurrentElement())
104 if (mnType
== XML_n
|| mnType
== XML_b
)
105 mrCellValue
.set(rChars
.toDouble());
110 if (mnType
== XML_inlineStr
)
112 ScDocument
& rDoc
= getScDocument();
113 svl::SharedStringPool
& rPool
= rDoc
.GetSharedStringPool();
114 mrCellValue
.set(rPool
.intern(rChars
));
121 ScDocument
& rDoc
= getScDocument();
122 ScCompiler
aComp(&rDoc
, mrPos
);
123 aComp
.SetGrammar(formula::FormulaGrammar::GRAM_OOXML
);
124 ScTokenArray
* pArray
= aComp
.CompileString(rChars
);
128 mrCellValue
.set(new ScFormulaCell(&rDoc
, mrPos
, pArray
));
136 virtual void onEndElement() SAL_OVERRIDE
138 switch (getCurrentElement())
143 if (mrCellValue
.isEmpty() && mxRichString
)
145 // The value is a rich text string.
146 ScDocument
& rDoc
= getScDocument();
147 EditTextObject
* pTextObj
= mxRichString
->convert(rDoc
.GetEditEngine(), NULL
);
150 svl::SharedStringPool
& rPool
= rDoc
.GetSharedStringPool();
151 pTextObj
->NormalizeString(rPool
);
152 mrCellValue
.set(pTextObj
);
163 void importCell( const AttributeList
& rAttribs
)
165 mnType
= rAttribs
.getToken(XML_t
, XML_n
);
166 OUString aRefStr
= rAttribs
.getString(XML_r
, OUString());
167 if (!aRefStr
.isEmpty())
169 mrPos
.Parse(aRefStr
, NULL
, formula::FormulaGrammar::CONV_XL_OOX
);
170 if (mnSheetIndex
!= -1)
171 mrPos
.SetTab(mnSheetIndex
-1);
176 struct RevisionMetadata
181 RevisionMetadata() : maDateTime(DateTime::EMPTY
) {}
182 RevisionMetadata( const RevisionMetadata
& r
) :
183 maUserName(r
.maUserName
), maDateTime(r
.maDateTime
) {}
188 typedef std::map
<OUString
, RevisionMetadata
> RevDataType
;
190 struct RevisionHeadersFragment::Impl
192 RevDataType maRevData
;
197 RevisionHeadersFragment::RevisionHeadersFragment(
198 const WorkbookHelper
& rHelper
, const OUString
& rFragmentPath
) :
199 WorkbookFragmentBase(rHelper
, rFragmentPath
),
202 RevisionHeadersFragment::~RevisionHeadersFragment()
207 oox::core::ContextHandlerRef
RevisionHeadersFragment::onCreateContext(
208 sal_Int32
/*nElement*/, const AttributeList
& /*rAttribs*/ )
213 void RevisionHeadersFragment::onStartElement( const AttributeList
& rAttribs
)
215 switch (getCurrentElement())
217 case XLS_TOKEN(headers
):
219 case XLS_TOKEN(header
):
220 importHeader(rAttribs
);
222 case XLS_TOKEN(sheetIdMap
):
224 case XLS_TOKEN(sheetId
):
231 void RevisionHeadersFragment::onCharacters( const OUString
& /*rChars*/ ) {}
233 void RevisionHeadersFragment::onEndElement()
235 switch (getCurrentElement())
237 case XLS_TOKEN(headers
):
239 case XLS_TOKEN(header
):
241 case XLS_TOKEN(sheetIdMap
):
243 case XLS_TOKEN(sheetId
):
250 void RevisionHeadersFragment::finalizeImport()
252 ScDocument
& rDoc
= getScDocument();
253 std::unique_ptr
<ScChangeTrack
> pCT(new ScChangeTrack(&rDoc
));
254 OUString aSelfUser
= pCT
->GetUser(); // owner of this document.
255 pCT
->SetUseFixDateTime(true);
257 const oox::core::Relations
& rRels
= getRelations();
258 RevDataType::const_iterator it
= mpImpl
->maRevData
.begin(), itEnd
= mpImpl
->maRevData
.end();
259 for (; it
!= itEnd
; ++it
)
261 OUString aPath
= rRels
.getFragmentPathFromRelId(it
->first
);
265 // Parse each reivison log fragment.
266 const RevisionMetadata
& rData
= it
->second
;
267 pCT
->SetUser(rData
.maUserName
);
268 pCT
->SetFixDateTimeLocal(rData
.maDateTime
);
269 boost::scoped_ptr
<oox::core::FastParser
> xParser(getOoxFilter().createParser());
270 rtl::Reference
<oox::core::FragmentHandler
> xFragment(new RevisionLogFragment(*this, aPath
, *pCT
));
271 importOoxFragment(xFragment
, *xParser
);
274 pCT
->SetUser(aSelfUser
); // set the default user to the document owner.
275 pCT
->SetUseFixDateTime(false);
276 rDoc
.SetChangeTrack(pCT
.release());
278 // Turn on visibility of tracked changes.
279 ScChangeViewSettings aSettings
;
280 aSettings
.SetShowChanges(true);
281 rDoc
.SetChangeViewSettings(aSettings
);
284 void RevisionHeadersFragment::importHeader( const AttributeList
& rAttribs
)
286 OUString aRId
= rAttribs
.getString(R_TOKEN(id
), OUString());
288 // All bets are off if we don't have a relation ID.
291 RevisionMetadata aMetadata
;
292 OUString aDateTimeStr
= rAttribs
.getString(XML_dateTime
, OUString());
293 if (!aDateTimeStr
.isEmpty())
295 util::DateTime aDateTime
;
296 sax::Converter::parseDateTime(aDateTime
, 0, aDateTimeStr
);
297 Date
aDate(aDateTime
);
298 tools::Time
aTime(aDateTime
);
299 aMetadata
.maDateTime
.SetDate(aDate
.GetDate());
300 aMetadata
.maDateTime
.SetTime(aTime
.GetTime());
303 aMetadata
.maUserName
= rAttribs
.getString(XML_userName
, OUString());
305 mpImpl
->maRevData
.insert(RevDataType::value_type(aRId
, aMetadata
));
308 struct RevisionLogFragment::Impl
310 ScChangeTrack
& mrChangeTrack
;
312 sal_Int32 mnRevIndex
;
313 sal_Int32 mnSheetIndex
;
318 ScAddress maOldCellPos
;
319 ScAddress maNewCellPos
;
320 ScCellValue maOldCellValue
;
321 ScCellValue maNewCellValue
;
328 Impl( ScChangeTrack
& rChangeTrack
) :
329 mrChangeTrack(rChangeTrack
),
333 mbEndOfList(false) {}
336 RevisionLogFragment::RevisionLogFragment(
337 const WorkbookHelper
& rHelper
, const OUString
& rFragmentPath
, ScChangeTrack
& rChangeTrack
) :
338 WorkbookFragmentBase(rHelper
, rFragmentPath
),
339 mpImpl(new Impl(rChangeTrack
)) {}
341 RevisionLogFragment::~RevisionLogFragment()
346 oox::core::ContextHandlerRef
RevisionLogFragment::onCreateContext(
347 sal_Int32 nElement
, const AttributeList
& /*rAttribs*/ )
352 return new RCCCellValueContext(*this, mpImpl
->mnSheetIndex
, mpImpl
->maNewCellPos
, mpImpl
->maNewCellValue
);
354 return new RCCCellValueContext(*this, mpImpl
->mnSheetIndex
, mpImpl
->maOldCellPos
, mpImpl
->maOldCellValue
);
361 void RevisionLogFragment::onStartElement( const AttributeList
& rAttribs
)
363 switch (getCurrentElement())
366 mpImpl
->maNewCellPos
.SetInvalid();
367 mpImpl
->maOldCellPos
.SetInvalid();
368 mpImpl
->maNewCellValue
.clear();
369 mpImpl
->maOldCellValue
.clear();
380 void RevisionLogFragment::onCharacters( const OUString
& /*rChars*/ ) {}
382 void RevisionLogFragment::onEndElement()
384 switch (getCurrentElement())
395 void RevisionLogFragment::finalizeImport() {}
397 void RevisionLogFragment::importCommon( const AttributeList
& rAttribs
)
399 mpImpl
->mnRevIndex
= rAttribs
.getInteger(XML_rId
, -1);
400 mpImpl
->mnSheetIndex
= rAttribs
.getInteger(XML_sId
, -1);
403 void RevisionLogFragment::importRcc( const AttributeList
& rAttribs
)
405 importCommon(rAttribs
);
407 mpImpl
->meType
= REV_CELLCHANGE
;
410 void RevisionLogFragment::importRrc( const AttributeList
& rAttribs
)
412 importCommon(rAttribs
);
414 if (mpImpl
->mnSheetIndex
== -1)
415 // invalid sheet index, or sheet index not given.
418 mpImpl
->meType
= REV_UNKNOWN
;
419 sal_Int32 nAction
= rAttribs
.getToken(XML_action
, -1);
423 OUString aRefStr
= rAttribs
.getString(XML_ref
, OUString());
424 mpImpl
->maRange
.Parse(aRefStr
, &getScDocument(), formula::FormulaGrammar::CONV_XL_OOX
);
425 if (!mpImpl
->maRange
.IsValid())
431 mpImpl
->meType
= REV_INSERTROW
;
432 mpImpl
->maRange
.aEnd
.SetCol(MAXCOL
);
433 mpImpl
->maRange
.aStart
.SetTab(mpImpl
->mnSheetIndex
-1);
434 mpImpl
->maRange
.aEnd
.SetTab(mpImpl
->mnSheetIndex
-1);
437 // Unknown action type. Ignore it.
441 mpImpl
->mbEndOfList
= rAttribs
.getBool(XML_eol
, false);
444 void RevisionLogFragment::pushRevision()
446 switch (mpImpl
->meType
)
449 mpImpl
->mrChangeTrack
.AppendContentOnTheFly(
450 mpImpl
->maNewCellPos
, mpImpl
->maOldCellValue
, mpImpl
->maNewCellValue
);
453 mpImpl
->mrChangeTrack
.AppendInsert(mpImpl
->maRange
, mpImpl
->mbEndOfList
);
462 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */