/* -*- 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>
#include <utility>
constexpr OString SC_CHANGE_ID_PREFIX = "ct"_ostr;
ScMyCellInfo::ScMyCellInfo(
ScCellValue aCell, OUString aFormulaAddress, OUString aFormula,
const formula::FormulaGrammar::Grammar eTempGrammar, OUString aInputString,
const double& rValue, const sal_uInt16 nTempType, const ScMatrixMode nTempMatrixFlag, const sal_Int32 nTempMatrixCols,
const sal_Int32 nTempMatrixRows ) :
maCell(std::move(aCell)),
sFormulaAddress(std::move(aFormulaAddress)),
sFormula(std::move(aFormula)),
sInputString(std::move(aInputString)),
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.set(new ScFormulaCell(rDoc, aPos, sFormula, eGrammar, nMatrixFlag));
maCell.getFormula()->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 );
sInputString = rDoc.GetFormatTable()->GetInputLineString(fValue, nFormat);
}
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;
if (::sax::Converter::convertNumber(nValue, sID.substr(SC_CHANGE_ID_PREFIX.getLength()),
0, SAL_MAX_INT32))
nResult = nValue;
OSL_ENSURE(nResult > 0, "wrong change action ID");
}
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())->moInsCutOff.emplace( 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(tools::Time::EMPTY) );
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(tools::Time::EMPTY) );
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(tools::Time::EMPTY) );
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(tools::Time::EMPTY) );
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(tools::Time::EMPTY) );
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)
continue;
if (!rGenerated.pCellInfo)
continue;
ScCellValue aCell = rGenerated.pCellInfo->CreateCell(rDoc);
if (aCell.isEmpty())
continue;
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->moInsCutOff)
{
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->moInsCutOff->nID);
if (pChangeAction && pChangeAction->IsInsertType())
{
ScChangeActionIns* pInsAction = static_cast<ScChangeActionIns*>(pChangeAction);
if (pDelAct)
pDelAct->SetCutOffInsert(pInsAction, static_cast<sal_Int16>(pAction->moInsCutOff->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.getType() != CELLTYPE_FORMULA)
{
aNewCell = aCell;
pChangeActionContent->SetNewCell(aNewCell, &rDoc, OUString());
pChangeActionContent->SetNewValue(aCell, &rDoc);
}
else
{
ScMatrixMode nMatrixFlag = aCell.getFormula()->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.getFormula()->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.set(new ScFormulaCell(rDoc, aAddress, sFormula2,formula::FormulaGrammar::GRAM_ODFF, nMatrixFlag));
if (nMatrixFlag == ScMatrixMode::Formula)
{
SCCOL nCols;
SCROW nRows;
aCell.getFormula()->GetMatColsRows(nCols, nRows);
aNewCell.getFormula()->SetMatColsRows(nCols, nRows);
}
aNewCell.getFormula()->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: */
↑ V547 Expression 'rDeleted.pCellInfo' is always true.