summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx')
-rw-r--r--sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx808
1 files changed, 808 insertions, 0 deletions
diff --git a/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx b/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
new file mode 100644
index 000000000..9ae06a720
--- /dev/null
+++ b/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
@@ -0,0 +1,808 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "XMLChangeTrackingImportHelper.hxx"
+#include <formulacell.hxx>
+#include <document.hxx>
+#include <rangeutl.hxx>
+#include <tools/datetime.hxx>
+#include <osl/diagnose.h>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <sax/tools/converter.hxx>
+
+constexpr OStringLiteral SC_CHANGE_ID_PREFIX = "ct";
+
+ScMyCellInfo::ScMyCellInfo(
+ const ScCellValue& rCell, const OUString& rFormulaAddress, const OUString& rFormula,
+ const formula::FormulaGrammar::Grammar eTempGrammar, const OUString& rInputString,
+ const double& rValue, const sal_uInt16 nTempType, const ScMatrixMode nTempMatrixFlag, const sal_Int32 nTempMatrixCols,
+ const sal_Int32 nTempMatrixRows ) :
+ maCell(rCell),
+ sFormulaAddress(rFormulaAddress),
+ sFormula(rFormula),
+ sInputString(rInputString),
+ fValue(rValue),
+ nMatrixCols(nTempMatrixCols),
+ nMatrixRows(nTempMatrixRows),
+ eGrammar( eTempGrammar),
+ nType(nTempType),
+ nMatrixFlag(nTempMatrixFlag)
+{
+}
+
+ScMyCellInfo::~ScMyCellInfo() {}
+
+const ScCellValue& ScMyCellInfo::CreateCell(ScDocument& rDoc)
+{
+ if (!maCell.isEmpty())
+ return maCell;
+
+ if (!sFormula.isEmpty() && !sFormulaAddress.isEmpty())
+ {
+ ScAddress aPos;
+ sal_Int32 nOffset(0);
+ ScRangeStringConverter::GetAddressFromString(aPos, sFormulaAddress, rDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset);
+ maCell.meType = CELLTYPE_FORMULA;
+ maCell.mpFormula = new ScFormulaCell(rDoc, aPos, sFormula, eGrammar, nMatrixFlag);
+ maCell.mpFormula->SetMatColsRows(static_cast<SCCOL>(nMatrixCols), static_cast<SCROW>(nMatrixRows));
+ }
+
+ if ((nType == css::util::NumberFormat::DATE || nType == css::util::NumberFormat::TIME) && sInputString.isEmpty())
+ {
+ sal_uInt32 nFormat(0);
+ if (nType == css::util::NumberFormat::DATE)
+ nFormat = rDoc.GetFormatTable()->GetStandardFormat( SvNumFormatType::DATE, ScGlobal::eLnge );
+ else if (nType == css::util::NumberFormat::TIME)
+ nFormat = rDoc.GetFormatTable()->GetStandardFormat( SvNumFormatType::TIME, ScGlobal::eLnge );
+ rDoc.GetFormatTable()->GetInputLineString(fValue, nFormat, sInputString);
+ }
+
+ return maCell;
+}
+
+ScMyBaseAction::ScMyBaseAction(const ScChangeActionType nTempActionType)
+ : nActionNumber(0),
+ nRejectingNumber(0),
+ nPreviousAction(0),
+ nActionType(nTempActionType),
+ nActionState(SC_CAS_VIRGIN)
+{
+}
+
+ScMyBaseAction::~ScMyBaseAction()
+{
+}
+
+ScMyInsAction::ScMyInsAction(const ScChangeActionType nActionTypeP)
+ : ScMyBaseAction(nActionTypeP)
+{
+}
+
+ScMyInsAction::~ScMyInsAction()
+{
+}
+
+ScMyDelAction::ScMyDelAction(const ScChangeActionType nActionTypeP)
+ : ScMyBaseAction(nActionTypeP),
+ nD(0)
+{
+}
+
+ScMyDelAction::~ScMyDelAction()
+{
+}
+
+ScMyMoveAction::ScMyMoveAction()
+ : ScMyBaseAction(SC_CAT_MOVE)
+{
+}
+
+ScMyMoveAction::~ScMyMoveAction()
+{
+}
+
+ScMyContentAction::ScMyContentAction()
+ : ScMyBaseAction(SC_CAT_CONTENT)
+{
+}
+
+ScMyContentAction::~ScMyContentAction()
+{
+}
+
+ScMyRejAction::ScMyRejAction()
+ : ScMyBaseAction(SC_CAT_REJECT)
+{
+}
+
+ScMyRejAction::~ScMyRejAction()
+{
+}
+
+ScXMLChangeTrackingImportHelper::ScXMLChangeTrackingImportHelper() :
+ pTrack(nullptr),
+ nMultiSpanned(0),
+ nMultiSpannedSlaveCount(0)
+{
+}
+
+ScXMLChangeTrackingImportHelper::~ScXMLChangeTrackingImportHelper()
+{
+}
+
+void ScXMLChangeTrackingImportHelper::StartChangeAction(const ScChangeActionType nActionType)
+{
+ OSL_ENSURE(!pCurrentAction, "a not inserted action");
+ switch (nActionType)
+ {
+ case SC_CAT_INSERT_COLS:
+ case SC_CAT_INSERT_ROWS:
+ case SC_CAT_INSERT_TABS:
+ {
+ pCurrentAction = std::make_unique<ScMyInsAction>(nActionType);
+ }
+ break;
+ case SC_CAT_DELETE_COLS:
+ case SC_CAT_DELETE_ROWS:
+ case SC_CAT_DELETE_TABS:
+ {
+ pCurrentAction = std::make_unique<ScMyDelAction>(nActionType);
+ }
+ break;
+ case SC_CAT_MOVE:
+ {
+ pCurrentAction = std::make_unique<ScMyMoveAction>();
+ }
+ break;
+ case SC_CAT_CONTENT:
+ {
+ pCurrentAction = std::make_unique<ScMyContentAction>();
+ }
+ break;
+ case SC_CAT_REJECT:
+ {
+ pCurrentAction = std::make_unique<ScMyRejAction>();
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+sal_uInt32 ScXMLChangeTrackingImportHelper::GetIDFromString(std::string_view sID)
+{
+ sal_uInt32 nResult(0);
+ if (!sID.empty())
+ {
+ if (sID.substr(0, SC_CHANGE_ID_PREFIX.getLength()) == SC_CHANGE_ID_PREFIX)
+ {
+ sal_Int32 nValue;
+ ::sax::Converter::convertNumber(nValue, sID.substr(SC_CHANGE_ID_PREFIX.getLength()));
+ OSL_ENSURE(nValue > 0, "wrong change action ID");
+ nResult = nValue;
+ }
+ else
+ {
+ OSL_FAIL("wrong change action ID");
+ }
+ }
+ return nResult;
+}
+
+void ScXMLChangeTrackingImportHelper::SetActionInfo(const ScMyActionInfo& aInfo)
+{
+ pCurrentAction->aInfo = aInfo;
+ aUsers.insert(aInfo.sUser);
+}
+
+void ScXMLChangeTrackingImportHelper::SetPreviousChange(const sal_uInt32 nPreviousAction,
+ ScMyCellInfo* pCellInfo)
+{
+ OSL_ENSURE(pCurrentAction->nActionType == SC_CAT_CONTENT, "wrong action type");
+ ScMyContentAction* pAction = static_cast<ScMyContentAction*>(pCurrentAction.get());
+ pAction->nPreviousAction = nPreviousAction;
+ pAction->pCellInfo.reset( pCellInfo );
+}
+
+void ScXMLChangeTrackingImportHelper::SetPosition(const sal_Int32 nPosition, const sal_Int32 nCount, const sal_Int32 nTable)
+{
+ OSL_ENSURE(((pCurrentAction->nActionType != SC_CAT_MOVE) &&
+ (pCurrentAction->nActionType != SC_CAT_CONTENT) &&
+ (pCurrentAction->nActionType != SC_CAT_REJECT)), "wrong action type");
+ OSL_ENSURE(nCount > 0, "wrong count");
+ switch(pCurrentAction->nActionType)
+ {
+ case SC_CAT_INSERT_COLS:
+ case SC_CAT_DELETE_COLS:
+ {
+ pCurrentAction->aBigRange.Set(nPosition, ScBigRange::nRangeMin, nTable,
+ nPosition + nCount - 1, ScBigRange::nRangeMax, nTable);
+ }
+ break;
+ case SC_CAT_INSERT_ROWS:
+ case SC_CAT_DELETE_ROWS:
+ {
+ pCurrentAction->aBigRange.Set(ScBigRange::nRangeMin, nPosition, nTable,
+ ScBigRange::nRangeMax, nPosition + nCount - 1, nTable);
+ }
+ break;
+ case SC_CAT_INSERT_TABS:
+ case SC_CAT_DELETE_TABS:
+ {
+ pCurrentAction->aBigRange.Set(ScBigRange::nRangeMin, ScBigRange::nRangeMin, nPosition,
+ ScBigRange::nRangeMax, ScBigRange::nRangeMax, nPosition + nCount - 1);
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::AddDeleted(const sal_uInt32 nID)
+{
+ pCurrentAction->aDeletedList.emplace_back( nID, nullptr );
+}
+
+void ScXMLChangeTrackingImportHelper::AddDeleted(const sal_uInt32 nID, std::unique_ptr<ScMyCellInfo> pCellInfo)
+{
+ pCurrentAction->aDeletedList.emplace_back( nID, std::move(pCellInfo) );
+}
+
+void ScXMLChangeTrackingImportHelper::SetMultiSpanned(const sal_Int16 nTempMultiSpanned)
+{
+ if (nTempMultiSpanned)
+ {
+ OSL_ENSURE(((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS)), "wrong action type");
+ nMultiSpanned = nTempMultiSpanned;
+ nMultiSpannedSlaveCount = 0;
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::SetInsertionCutOff(const sal_uInt32 nID, const sal_Int32 nPosition)
+{
+ if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
+ {
+ static_cast<ScMyDelAction*>(pCurrentAction.get())->pInsCutOff.reset( new ScMyInsertionCutOff(nID, nPosition) );
+ }
+ else
+ {
+ OSL_FAIL("wrong action type");
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::AddMoveCutOff(const sal_uInt32 nID, const sal_Int32 nStartPosition, const sal_Int32 nEndPosition)
+{
+ if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
+ {
+ static_cast<ScMyDelAction*>(pCurrentAction.get())->aMoveCutOffs.push_back(ScMyMoveCutOff(nID, nStartPosition, nEndPosition));
+ }
+ else
+ {
+ OSL_FAIL("wrong action type");
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::SetMoveRanges(const ScBigRange& aSourceRange, const ScBigRange& aTargetRange)
+{
+ if (pCurrentAction->nActionType == SC_CAT_MOVE)
+ {
+ static_cast<ScMyMoveAction*>(pCurrentAction.get())->pMoveRanges.reset( new ScMyMoveRanges(aSourceRange, aTargetRange) );
+ }
+ else
+ {
+ OSL_FAIL("wrong action type");
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::GetMultiSpannedRange()
+{
+ if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
+ {
+ if (nMultiSpannedSlaveCount)
+ {
+ static_cast<ScMyDelAction*>(pCurrentAction.get())->nD = nMultiSpannedSlaveCount;
+ }
+ ++nMultiSpannedSlaveCount;
+ if (nMultiSpannedSlaveCount >= nMultiSpanned)
+ {
+ nMultiSpanned = 0;
+ nMultiSpannedSlaveCount = 0;
+ }
+ }
+ else
+ {
+ OSL_FAIL("wrong action type");
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::AddGenerated(std::unique_ptr<ScMyCellInfo> pCellInfo, const ScBigRange& aBigRange)
+{
+ ScMyGenerated aGenerated { aBigRange, 0, std::move(pCellInfo) };
+ if (pCurrentAction->nActionType == SC_CAT_MOVE)
+ {
+ static_cast<ScMyMoveAction*>(pCurrentAction.get())->aGeneratedList.push_back(std::move(aGenerated));
+ }
+ else if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
+ {
+ static_cast<ScMyDelAction*>(pCurrentAction.get())->aGeneratedList.push_back(std::move(aGenerated));
+ }
+ else
+ {
+ OSL_FAIL("try to insert a generated action to a wrong action");
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::EndChangeAction()
+{
+ if (!pCurrentAction)
+ {
+ OSL_FAIL("no current action");
+ return;
+ }
+
+ if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
+ GetMultiSpannedRange();
+
+ if (pCurrentAction->nActionNumber > 0)
+ aActions.push_back(std::move(pCurrentAction));
+ else
+ {
+ OSL_FAIL("no current action");
+ }
+
+ pCurrentAction = nullptr;
+}
+
+void ScXMLChangeTrackingImportHelper::ConvertInfo(const ScMyActionInfo& aInfo, OUString& rUser, DateTime& aDateTime)
+{
+ aDateTime = DateTime( aInfo.aDateTime);
+
+ // old files didn't store nanoseconds, enable again
+ if ( aInfo.aDateTime.NanoSeconds )
+ pTrack->SetTimeNanoSeconds( true );
+
+ const std::set<OUString>& rUsers = pTrack->GetUserCollection();
+ std::set<OUString>::const_iterator it = rUsers.find(aInfo.sUser);
+ if (it != rUsers.end())
+ {
+ // It's probably pointless to do this.
+ rUser = *it;
+ }
+ else
+ rUser = aInfo.sUser; // shouldn't happen
+}
+
+std::unique_ptr<ScChangeAction> ScXMLChangeTrackingImportHelper::CreateInsertAction(const ScMyInsAction* pAction)
+{
+ DateTime aDateTime( Date(0), tools::Time(0) );
+ OUString aUser;
+ ConvertInfo(pAction->aInfo, aUser, aDateTime);
+
+ OUString sComment (pAction->aInfo.sComment);
+
+ return std::make_unique<ScChangeActionIns>(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
+ pAction->aBigRange, aUser, aDateTime, sComment, pAction->nActionType);
+}
+
+std::unique_ptr<ScChangeAction> ScXMLChangeTrackingImportHelper::CreateDeleteAction(const ScMyDelAction* pAction)
+{
+ DateTime aDateTime( Date(0), tools::Time(0) );
+ OUString aUser;
+ ConvertInfo(pAction->aInfo, aUser, aDateTime);
+
+ OUString sComment (pAction->aInfo.sComment);
+
+ return std::make_unique<ScChangeActionDel>(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
+ pAction->aBigRange, aUser, aDateTime, sComment, pAction->nActionType, pAction->nD, pTrack);
+}
+
+std::unique_ptr<ScChangeAction> ScXMLChangeTrackingImportHelper::CreateMoveAction(const ScMyMoveAction* pAction)
+{
+ OSL_ENSURE(pAction->pMoveRanges, "no move ranges");
+ if (pAction->pMoveRanges)
+ {
+ DateTime aDateTime( Date(0), tools::Time(0) );
+ OUString aUser;
+ ConvertInfo(pAction->aInfo, aUser, aDateTime);
+
+ OUString sComment (pAction->aInfo.sComment);
+
+ return std::make_unique<ScChangeActionMove>(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
+ pAction->pMoveRanges->aTargetRange, aUser, aDateTime, sComment, pAction->pMoveRanges->aSourceRange , pTrack);
+ }
+ return nullptr;
+}
+
+std::unique_ptr<ScChangeAction> ScXMLChangeTrackingImportHelper::CreateRejectionAction(const ScMyRejAction* pAction)
+{
+ DateTime aDateTime( Date(0), tools::Time(0) );
+ OUString aUser;
+ ConvertInfo(pAction->aInfo, aUser, aDateTime);
+
+ OUString sComment (pAction->aInfo.sComment);
+
+ return std::make_unique<ScChangeActionReject>(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
+ pAction->aBigRange, aUser, aDateTime, sComment);
+}
+
+std::unique_ptr<ScChangeAction> ScXMLChangeTrackingImportHelper::CreateContentAction(const ScMyContentAction* pAction, ScDocument& rDoc)
+{
+ ScCellValue aCell;
+ OUString sInputString;
+ if (pAction->pCellInfo)
+ {
+ aCell = pAction->pCellInfo->CreateCell(rDoc);
+ sInputString = pAction->pCellInfo->sInputString;
+ }
+
+ DateTime aDateTime( Date(0), tools::Time(0) );
+ OUString aUser;
+ ConvertInfo(pAction->aInfo, aUser, aDateTime);
+
+ OUString sComment (pAction->aInfo.sComment);
+
+ return std::make_unique<ScChangeActionContent>(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
+ pAction->aBigRange, aUser, aDateTime, sComment, aCell, &rDoc, sInputString);
+}
+
+void ScXMLChangeTrackingImportHelper::CreateGeneratedActions(std::vector<ScMyGenerated>& rList, ScDocument& rDoc)
+{
+ for (ScMyGenerated & rGenerated : rList)
+ {
+ if (rGenerated.nID == 0)
+ {
+ ScCellValue aCell;
+ if (rGenerated.pCellInfo)
+ aCell = rGenerated.pCellInfo->CreateCell(rDoc);
+
+ if (!aCell.isEmpty())
+ {
+ rGenerated.nID = pTrack->AddLoadedGenerated(aCell, rGenerated.aBigRange, rGenerated.pCellInfo->sInputString);
+ OSL_ENSURE(rGenerated.nID, "could not insert generated action");
+ }
+ }
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::SetDeletionDependencies(ScMyDelAction* pAction, ScChangeActionDel* pDelAct)
+{
+ if (!pAction->aGeneratedList.empty())
+ {
+ OSL_ENSURE(((pAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pAction->nActionType == SC_CAT_DELETE_ROWS) ||
+ (pAction->nActionType == SC_CAT_DELETE_TABS)), "wrong action type");
+ if (pDelAct)
+ {
+ for (const ScMyGenerated & rGenerated : pAction->aGeneratedList)
+ {
+ OSL_ENSURE(rGenerated.nID, "a not inserted generated action");
+ pDelAct->SetDeletedInThis(rGenerated.nID, pTrack);
+ }
+ pAction->aGeneratedList.clear();
+ }
+ }
+ if (pAction->pInsCutOff)
+ {
+ OSL_ENSURE(((pAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pAction->nActionType == SC_CAT_DELETE_ROWS) ||
+ (pAction->nActionType == SC_CAT_DELETE_TABS)), "wrong action type");
+ ScChangeAction* pChangeAction = pTrack->GetAction(pAction->pInsCutOff->nID);
+ if (pChangeAction && pChangeAction->IsInsertType())
+ {
+ ScChangeActionIns* pInsAction = static_cast<ScChangeActionIns*>(pChangeAction);
+ if (pDelAct)
+ pDelAct->SetCutOffInsert(pInsAction, static_cast<sal_Int16>(pAction->pInsCutOff->nPosition));
+ }
+ else
+ {
+ OSL_FAIL("no cut off insert action");
+ }
+ }
+ if (pAction->aMoveCutOffs.empty())
+ return;
+
+ OSL_ENSURE(((pAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pAction->nActionType == SC_CAT_DELETE_ROWS) ||
+ (pAction->nActionType == SC_CAT_DELETE_TABS)), "wrong action type");
+ for (auto it = pAction->aMoveCutOffs.crbegin(); it != pAction->aMoveCutOffs.crend(); ++it)
+ {
+ const ScMyMoveCutOff & rCutOff = *it;
+ ScChangeAction* pChangeAction = pTrack->GetAction(rCutOff.nID);
+ if (pChangeAction && (pChangeAction->GetType() == SC_CAT_MOVE))
+ {
+ ScChangeActionMove* pMoveAction = static_cast<ScChangeActionMove*>(pChangeAction);
+ if (pDelAct)
+ pDelAct->AddCutOffMove(pMoveAction, static_cast<sal_Int16>(rCutOff.nStartPosition),
+ static_cast<sal_Int16>(rCutOff.nEndPosition));
+ }
+ else
+ {
+ OSL_FAIL("no cut off move action");
+ }
+ }
+ pAction->aMoveCutOffs.clear();
+}
+
+void ScXMLChangeTrackingImportHelper::SetMovementDependencies(ScMyMoveAction* pAction, ScChangeActionMove* pMoveAct)
+{
+ if (pAction->aGeneratedList.empty())
+ return;
+
+ if (pAction->nActionType == SC_CAT_MOVE)
+ {
+ if (pMoveAct)
+ {
+ for (const ScMyGenerated & rGenerated : pAction->aGeneratedList)
+ {
+ OSL_ENSURE(rGenerated.nID, "a not inserted generated action");
+ pMoveAct->SetDeletedInThis(rGenerated.nID, pTrack);
+ }
+ pAction->aGeneratedList.clear();
+ }
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::SetContentDependencies(const ScMyContentAction* pAction, ScChangeActionContent* pActContent, const ScDocument& rDoc)
+{
+ if (!pActContent || !pAction->nPreviousAction)
+ return;
+
+ OSL_ENSURE(pAction->nActionType == SC_CAT_CONTENT, "wrong action type");
+ ScChangeAction* pPrevAct = pTrack->GetAction(pAction->nPreviousAction);
+ if (!pPrevAct || pPrevAct->GetType() != SC_CAT_CONTENT)
+ return;
+
+ ScChangeActionContent* pPrevActContent = static_cast<ScChangeActionContent*>(pPrevAct);
+
+ pActContent->SetPrevContent(pPrevActContent);
+ pPrevActContent->SetNextContent(pActContent);
+ const ScCellValue& rOldCell = pActContent->GetOldCell();
+ if (rOldCell.isEmpty())
+ return;
+
+ pPrevActContent->SetNewCell(rOldCell, &rDoc, OUString());
+}
+
+void ScXMLChangeTrackingImportHelper::SetDependencies(ScMyBaseAction* pAction, ScDocument& rDoc)
+{
+ ScChangeAction* pAct = pTrack->GetAction(pAction->nActionNumber);
+ if (pAct)
+ {
+ if (!pAction->aDependencies.empty())
+ {
+ for (auto it = pAction->aDependencies.crbegin(); it != pAction->aDependencies.crend(); ++it)
+ pAct->AddDependent(*it, pTrack);
+ pAction->aDependencies.clear();
+ }
+ if (!pAction->aDeletedList.empty())
+ {
+ for (auto it = pAction->aDeletedList.crbegin(); it != pAction->aDeletedList.crend(); ++it)
+ {
+ const ScMyDeleted & rDeleted = *it;
+ pAct->SetDeletedInThis(rDeleted.nID, pTrack);
+ ScChangeAction* pDeletedAct = pTrack->GetAction(rDeleted.nID);
+ if ((pDeletedAct->GetType() == SC_CAT_CONTENT) && rDeleted.pCellInfo)
+ {
+ ScChangeActionContent* pContentAct = static_cast<ScChangeActionContent*>(pDeletedAct);
+ if (rDeleted.pCellInfo)
+ {
+ const ScCellValue& rCell = rDeleted.pCellInfo->CreateCell(rDoc);
+ if (!rCell.equalsWithoutFormat(pContentAct->GetNewCell()))
+ {
+ // #i40704# Don't overwrite SetNewCell result by calling SetNewValue,
+ // instead pass the input string to SetNewCell.
+ pContentAct->SetNewCell(rCell, &rDoc, rDeleted.pCellInfo->sInputString);
+ }
+ }
+ }
+ }
+ pAction->aDeletedList.clear();
+ }
+ if ((pAction->nActionType == SC_CAT_DELETE_COLS) ||
+ (pAction->nActionType == SC_CAT_DELETE_ROWS))
+ SetDeletionDependencies(static_cast<ScMyDelAction*>(pAction), static_cast<ScChangeActionDel*>(pAct));
+ else if (pAction->nActionType == SC_CAT_MOVE)
+ SetMovementDependencies(static_cast<ScMyMoveAction*>(pAction), static_cast<ScChangeActionMove*>(pAct));
+ else if (pAction->nActionType == SC_CAT_CONTENT)
+ SetContentDependencies(static_cast<ScMyContentAction*>(pAction), static_cast<ScChangeActionContent*>(pAct), rDoc);
+ }
+ else
+ {
+ OSL_FAIL("could not find the action");
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::SetNewCell(const ScMyContentAction* pAction, ScDocument& rDoc)
+{
+ ScChangeAction* pChangeAction = pTrack->GetAction(pAction->nActionNumber);
+ if (!pChangeAction)
+ return;
+
+ assert(dynamic_cast<ScChangeActionContent*>(pChangeAction));
+ ScChangeActionContent* pChangeActionContent = static_cast<ScChangeActionContent*>(pChangeAction);
+ if (!pChangeActionContent->IsTopContent() || pChangeActionContent->IsDeletedIn())
+ return;
+
+ sal_Int64 nCol, nRow, nTab, nCol2, nRow2, nTab2;
+ pAction->aBigRange.GetVars(nCol, nRow, nTab, nCol2, nRow2, nTab2);
+ if ((nCol >= 0) && (nCol <= rDoc.MaxCol()) &&
+ (nRow >= 0) && (nRow <= rDoc.MaxRow()) &&
+ (nTab >= 0) && (nTab <= MAXTAB))
+ {
+ ScAddress aAddress (static_cast<SCCOL>(nCol),
+ static_cast<SCROW>(nRow),
+ static_cast<SCTAB>(nTab));
+ ScCellValue aCell;
+ aCell.assign(rDoc, aAddress);
+ if (!aCell.isEmpty())
+ {
+ ScCellValue aNewCell;
+ if (aCell.meType != CELLTYPE_FORMULA)
+ {
+ aNewCell = aCell;
+ pChangeActionContent->SetNewCell(aNewCell, &rDoc, OUString());
+ pChangeActionContent->SetNewValue(aCell, &rDoc);
+ }
+ else
+ {
+ ScMatrixMode nMatrixFlag = aCell.mpFormula->GetMatrixFlag();
+ // With GRAM_ODFF reference detection is faster on compilation.
+ /* FIXME: new cell should be created with a clone
+ * of the token array instead. Any reason why this
+ * wasn't done? */
+ OUString sFormula = aCell.mpFormula->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
+
+ // #i87826# [Collaboration] Rejected move destroys formulas
+ // FIXME: adjust ScFormulaCell::GetFormula(), so that the right formula string
+ // is returned and no further string handling is necessary
+ OUString sFormula2;
+ if ( nMatrixFlag != ScMatrixMode::NONE )
+ {
+ sFormula2 = sFormula.copy( 2, sFormula.getLength() - 3 );
+ }
+ else
+ {
+ sFormula2 = sFormula.copy( 1 );
+ }
+
+ aNewCell.meType = CELLTYPE_FORMULA;
+ aNewCell.mpFormula = new ScFormulaCell(rDoc, aAddress, sFormula2,formula::FormulaGrammar::GRAM_ODFF, nMatrixFlag);
+ if (nMatrixFlag == ScMatrixMode::Formula)
+ {
+ SCCOL nCols;
+ SCROW nRows;
+ aCell.mpFormula->GetMatColsRows(nCols, nRows);
+ aNewCell.mpFormula->SetMatColsRows(nCols, nRows);
+ }
+ aNewCell.mpFormula->SetInChangeTrack(true);
+ pChangeActionContent->SetNewCell(aNewCell, &rDoc, OUString());
+ // #i40704# don't overwrite the formula string via SetNewValue()
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("wrong cell position");
+ }
+}
+
+void ScXMLChangeTrackingImportHelper::CreateChangeTrack(ScDocument* pDoc)
+{
+ if (!pDoc)
+ return;
+
+ pTrack = new ScChangeTrack(*pDoc, std::set(aUsers));
+ // old files didn't store nanoseconds, disable until encountered
+ pTrack->SetTimeNanoSeconds( false );
+
+ for (const auto & rAction : aActions)
+ {
+ std::unique_ptr<ScChangeAction> pAction;
+
+ switch (rAction->nActionType)
+ {
+ case SC_CAT_INSERT_COLS:
+ case SC_CAT_INSERT_ROWS:
+ case SC_CAT_INSERT_TABS:
+ {
+ pAction = CreateInsertAction(static_cast<ScMyInsAction*>(rAction.get()));
+ }
+ break;
+ case SC_CAT_DELETE_COLS:
+ case SC_CAT_DELETE_ROWS:
+ case SC_CAT_DELETE_TABS:
+ {
+ ScMyDelAction* pDelAct = static_cast<ScMyDelAction*>(rAction.get());
+ pAction = CreateDeleteAction(pDelAct);
+ CreateGeneratedActions(pDelAct->aGeneratedList, *pDoc);
+ }
+ break;
+ case SC_CAT_MOVE:
+ {
+ ScMyMoveAction* pMovAct = static_cast<ScMyMoveAction*>(rAction.get());
+ pAction = CreateMoveAction(pMovAct);
+ CreateGeneratedActions(pMovAct->aGeneratedList, *pDoc);
+ }
+ break;
+ case SC_CAT_CONTENT:
+ {
+ pAction = CreateContentAction(static_cast<ScMyContentAction*>(rAction.get()), *pDoc);
+ }
+ break;
+ case SC_CAT_REJECT:
+ {
+ pAction = CreateRejectionAction(static_cast<ScMyRejAction*>(rAction.get()));
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (pAction)
+ pTrack->AppendLoaded(std::move(pAction));
+ else
+ {
+ OSL_FAIL("no action");
+ }
+ }
+ if (pTrack->GetLast())
+ pTrack->SetActionMax(pTrack->GetLast()->GetActionNumber());
+
+ auto aItr = aActions.begin();
+ while (aItr != aActions.end())
+ {
+ SetDependencies(aItr->get(), *pDoc);
+
+ if ((*aItr)->nActionType == SC_CAT_CONTENT)
+ ++aItr;
+ else
+ aItr = aActions.erase(aItr);
+ }
+
+ for (const auto& rxAction : aActions)
+ {
+ OSL_ENSURE(rxAction->nActionType == SC_CAT_CONTENT, "wrong action type");
+ SetNewCell(static_cast<ScMyContentAction*>(rxAction.get()), *pDoc);
+ }
+ aActions.clear();
+ if (aProtect.hasElements())
+ pTrack->SetProtection(aProtect);
+ else if (pDoc->GetChangeTrack() && pDoc->GetChangeTrack()->IsProtected())
+ pTrack->SetProtection(pDoc->GetChangeTrack()->GetProtection());
+
+ if ( pTrack->GetLast() )
+ pTrack->SetLastSavedActionNumber(pTrack->GetLast()->GetActionNumber());
+
+ pDoc->SetChangeTrack(std::unique_ptr<ScChangeTrack>(pTrack));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */