nss: upgrade to release 3.73
[LibreOffice.git] / sc / source / filter / oox / revisionfragment.cxx
blobf6fee91c4051915ca488d2f5f9cd299f86586711
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sal/config.h>
12 #include <memory>
14 #include <revisionfragment.hxx>
15 #include <oox/core/relations.hxx>
16 #include <oox/core/xmlfilterbase.hxx>
17 #include <oox/core/fastparser.hxx>
18 #include <oox/helper/attributelist.hxx>
19 #include <oox/token/namespaces.hxx>
20 #include <oox/token/tokens.hxx>
21 #include <svl/sharedstringpool.hxx>
22 #include <sax/tools/converter.hxx>
23 #include <editeng/editobj.hxx>
25 #include <chgtrack.hxx>
26 #include <document.hxx>
27 #include <compiler.hxx>
28 #include <editutil.hxx>
29 #include <formulacell.hxx>
30 #include <chgviset.hxx>
31 #include <richstringcontext.hxx>
32 #include <tokenarray.hxx>
34 #include <com/sun/star/util/DateTime.hpp>
36 using namespace com::sun::star;
38 namespace oox::xls {
40 namespace {
42 enum RevisionType
44 REV_UNKNOWN = 0,
45 REV_CELLCHANGE,
46 REV_INSERTROW
49 /**
50 * For nc (new cell) or oc (old cell) elements under rcc (cell content
51 * revision).
53 class RCCCellValueContext : public WorkbookContextBase
55 sal_Int32 mnSheetIndex;
56 ScAddress& mrPos;
57 ScCellValue& mrCellValue;
58 sal_Int32 mnType;
60 RichStringRef mxRichString;
62 public:
63 RCCCellValueContext(
64 RevisionLogFragment& rParent, sal_Int32 nSheetIndex, ScAddress& rPos, ScCellValue& rCellValue ) :
65 WorkbookContextBase(rParent),
66 mnSheetIndex(nSheetIndex),
67 mrPos(rPos),
68 mrCellValue(rCellValue),
69 mnType(-1) {}
71 protected:
72 virtual oox::core::ContextHandlerRef onCreateContext(
73 sal_Int32 nElement, const AttributeList& /*rAttribs*/ ) override
75 if (nElement == XLS_TOKEN(is))
77 mxRichString = std::make_shared<RichString>(*this);
78 return new RichStringContext(*this, mxRichString);
81 return this;
84 virtual void onStartElement( const AttributeList& rAttribs ) override
86 switch (getCurrentElement())
88 case XLS_TOKEN(nc):
89 case XLS_TOKEN(oc):
90 importCell(rAttribs);
91 break;
92 default:
97 virtual void onCharacters( const OUString& rChars ) override
99 switch (getCurrentElement())
101 case XLS_TOKEN(v):
103 if (mnType == XML_n || mnType == XML_b)
104 mrCellValue.set(rChars.toDouble());
106 break;
107 case XLS_TOKEN(t):
109 if (mnType == XML_inlineStr)
111 ScDocument& rDoc = getScDocument();
112 svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
113 mrCellValue.set(rPool.intern(rChars));
116 break;
117 case XLS_TOKEN(f):
119 // formula string
120 ScDocument& rDoc = getScDocument();
121 ScCompiler aComp(rDoc, mrPos, formula::FormulaGrammar::GRAM_OOXML);
122 std::unique_ptr<ScTokenArray> pArray = aComp.CompileString(rChars);
123 if (!pArray)
124 break;
126 mrCellValue.set(new ScFormulaCell(rDoc, mrPos, std::move(pArray)));
128 break;
129 default:
134 virtual void onEndElement() override
136 switch (getCurrentElement())
138 case XLS_TOKEN(nc):
139 case XLS_TOKEN(oc):
141 if (mrCellValue.isEmpty() && mxRichString)
143 // The value is a rich text string.
144 ScDocument& rDoc = getScDocument();
145 std::unique_ptr<EditTextObject> pTextObj = mxRichString->convert(rDoc.GetEditEngine(), nullptr);
146 if (pTextObj)
148 svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
149 pTextObj->NormalizeString(rPool);
150 mrCellValue.set(pTextObj.release());
154 break;
155 default:
160 private:
161 void importCell( const AttributeList& rAttribs )
163 mnType = rAttribs.getToken(XML_t, XML_n);
164 OUString aRefStr = rAttribs.getString(XML_r, OUString());
165 if (!aRefStr.isEmpty())
167 mrPos.Parse(aRefStr, getScDocument(), formula::FormulaGrammar::CONV_XL_OOX);
168 if (mnSheetIndex != -1)
169 mrPos.SetTab(mnSheetIndex-1);
174 struct RevisionMetadata
176 OUString maUserName;
177 DateTime maDateTime;
179 RevisionMetadata() : maDateTime(DateTime::EMPTY) {}
180 RevisionMetadata( const RevisionMetadata& r ) :
181 maUserName(r.maUserName), maDateTime(r.maDateTime) {}
186 struct RevisionHeadersFragment::Impl
188 std::map<OUString, RevisionMetadata> maRevData;
190 Impl() {}
193 RevisionHeadersFragment::RevisionHeadersFragment(
194 const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
195 WorkbookFragmentBase(rHelper, rFragmentPath),
196 mpImpl(new Impl) {}
198 RevisionHeadersFragment::~RevisionHeadersFragment()
202 oox::core::ContextHandlerRef RevisionHeadersFragment::onCreateContext(
203 sal_Int32 /*nElement*/, const AttributeList& /*rAttribs*/ )
205 return this;
208 void RevisionHeadersFragment::onStartElement( const AttributeList& rAttribs )
210 switch (getCurrentElement())
212 case XLS_TOKEN(headers):
213 break;
214 case XLS_TOKEN(header):
215 importHeader(rAttribs);
216 break;
217 case XLS_TOKEN(sheetIdMap):
218 break;
219 case XLS_TOKEN(sheetId):
220 break;
221 default:
226 void RevisionHeadersFragment::onCharacters( const OUString& /*rChars*/ ) {}
228 void RevisionHeadersFragment::onEndElement()
230 switch (getCurrentElement())
232 case XLS_TOKEN(headers):
233 break;
234 case XLS_TOKEN(header):
235 break;
236 case XLS_TOKEN(sheetIdMap):
237 break;
238 case XLS_TOKEN(sheetId):
239 break;
240 default:
245 void RevisionHeadersFragment::finalizeImport()
247 ScDocument& rDoc = getScDocument();
248 std::unique_ptr<ScChangeTrack> pCT(new ScChangeTrack(rDoc));
249 OUString aSelfUser = pCT->GetUser(); // owner of this document.
250 pCT->SetUseFixDateTime(true);
252 const oox::core::Relations& rRels = getRelations();
253 for (const auto& [rRelId, rData] : mpImpl->maRevData)
255 OUString aPath = rRels.getFragmentPathFromRelId(rRelId);
256 if (aPath.isEmpty())
257 continue;
259 // Parse each revision log fragment.
260 pCT->SetUser(rData.maUserName);
261 pCT->SetFixDateTimeLocal(rData.maDateTime);
262 std::unique_ptr<oox::core::FastParser> xParser(oox::core::XmlFilterBase::createParser());
263 rtl::Reference<oox::core::FragmentHandler> xFragment(new RevisionLogFragment(*this, aPath, *pCT));
264 importOoxFragment(xFragment, *xParser);
267 pCT->SetUser(aSelfUser); // set the default user to the document owner.
268 pCT->SetUseFixDateTime(false);
269 rDoc.SetChangeTrack(std::move(pCT));
271 // Turn on visibility of tracked changes.
272 ScChangeViewSettings aSettings;
273 aSettings.SetShowChanges(true);
274 rDoc.SetChangeViewSettings(aSettings);
277 void RevisionHeadersFragment::importHeader( const AttributeList& rAttribs )
279 OUString aRId = rAttribs.getString(R_TOKEN(id), OUString());
280 if (aRId.isEmpty())
281 // All bets are off if we don't have a relation ID.
282 return;
284 RevisionMetadata aMetadata;
285 OUString aDateTimeStr = rAttribs.getString(XML_dateTime, OUString());
286 if (!aDateTimeStr.isEmpty())
288 util::DateTime aDateTime;
289 sax::Converter::parseDateTime(aDateTime, aDateTimeStr);
290 Date aDate(aDateTime);
291 tools::Time aTime(aDateTime);
292 aMetadata.maDateTime.SetDate(aDate.GetDate());
293 aMetadata.maDateTime.SetTime(aTime.GetTime());
296 aMetadata.maUserName = rAttribs.getString(XML_userName, OUString());
298 mpImpl->maRevData.emplace(aRId, aMetadata);
301 struct RevisionLogFragment::Impl
303 ScChangeTrack& mrChangeTrack;
305 sal_Int32 mnSheetIndex;
307 RevisionType meType;
309 // rcc
310 ScAddress maOldCellPos;
311 ScAddress maNewCellPos;
312 ScCellValue maOldCellValue;
313 ScCellValue maNewCellValue;
315 // rrc
316 ScRange maRange;
318 bool mbEndOfList;
320 explicit Impl( ScChangeTrack& rChangeTrack ) :
321 mrChangeTrack(rChangeTrack),
322 mnSheetIndex(-1),
323 meType(REV_UNKNOWN),
324 mbEndOfList(false) {}
327 RevisionLogFragment::RevisionLogFragment(
328 const WorkbookHelper& rHelper, const OUString& rFragmentPath, ScChangeTrack& rChangeTrack ) :
329 WorkbookFragmentBase(rHelper, rFragmentPath),
330 mpImpl(new Impl(rChangeTrack)) {}
332 RevisionLogFragment::~RevisionLogFragment()
336 oox::core::ContextHandlerRef RevisionLogFragment::onCreateContext(
337 sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
339 switch (nElement)
341 case XLS_TOKEN(nc):
342 return new RCCCellValueContext(*this, mpImpl->mnSheetIndex, mpImpl->maNewCellPos, mpImpl->maNewCellValue);
343 case XLS_TOKEN(oc):
344 return new RCCCellValueContext(*this, mpImpl->mnSheetIndex, mpImpl->maOldCellPos, mpImpl->maOldCellValue);
345 default:
348 return this;
351 void RevisionLogFragment::onStartElement( const AttributeList& rAttribs )
353 switch (getCurrentElement())
355 case XLS_TOKEN(rcc):
356 mpImpl->maNewCellPos.SetInvalid();
357 mpImpl->maOldCellPos.SetInvalid();
358 mpImpl->maNewCellValue.clear();
359 mpImpl->maOldCellValue.clear();
360 importRcc(rAttribs);
361 break;
362 case XLS_TOKEN(rrc):
363 importRrc(rAttribs);
364 break;
365 default:
370 void RevisionLogFragment::onCharacters( const OUString& /*rChars*/ ) {}
372 void RevisionLogFragment::onEndElement()
374 switch (getCurrentElement())
376 case XLS_TOKEN(rcc):
377 case XLS_TOKEN(rrc):
378 pushRevision();
379 break;
380 default:
385 void RevisionLogFragment::finalizeImport() {}
387 void RevisionLogFragment::importCommon( const AttributeList& rAttribs )
389 mpImpl->mnSheetIndex = rAttribs.getInteger(XML_sId, -1);
392 void RevisionLogFragment::importRcc( const AttributeList& rAttribs )
394 importCommon(rAttribs);
396 mpImpl->meType = REV_CELLCHANGE;
399 void RevisionLogFragment::importRrc( const AttributeList& rAttribs )
401 importCommon(rAttribs);
403 if (mpImpl->mnSheetIndex == -1)
404 // invalid sheet index, or sheet index not given.
405 return;
407 mpImpl->meType = REV_UNKNOWN;
408 sal_Int32 nAction = rAttribs.getToken(XML_action, -1);
409 if (nAction == -1)
410 return;
412 OUString aRefStr = rAttribs.getString(XML_ref, OUString());
413 mpImpl->maRange.Parse(aRefStr, getScDocument(), formula::FormulaGrammar::CONV_XL_OOX);
414 if (!mpImpl->maRange.IsValid())
415 return;
417 switch (nAction)
419 case XML_insertRow:
420 mpImpl->meType = REV_INSERTROW;
421 mpImpl->maRange.aEnd.SetCol(getScDocument().MaxCol());
422 mpImpl->maRange.aStart.SetTab(mpImpl->mnSheetIndex-1);
423 mpImpl->maRange.aEnd.SetTab(mpImpl->mnSheetIndex-1);
424 break;
425 default:
426 // Unknown action type. Ignore it.
427 return;
430 mpImpl->mbEndOfList = rAttribs.getBool(XML_eol, false);
433 void RevisionLogFragment::pushRevision()
435 switch (mpImpl->meType)
437 case REV_CELLCHANGE:
438 mpImpl->mrChangeTrack.AppendContentOnTheFly(
439 mpImpl->maNewCellPos, mpImpl->maOldCellValue, mpImpl->maNewCellValue);
440 break;
441 case REV_INSERTROW:
442 mpImpl->mrChangeTrack.AppendInsert(mpImpl->maRange, mpImpl->mbEndOfList);
443 break;
444 default:
451 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */