forked from amazingfate/loongoffice
For cut paste transposed, references are not anymore updated during UpdateReference(), but all these references will be updated during UpdateTranspose(). In previous implementation, some references were moved (i.e. updated). This caused problems in UpdateTranspose(). A transposed flag is added to the clipparam. This flag is checked during UpdateReference(). UpdateTranspose() must only operate on (i.e. transpose) references pointing to the source area. That's why updates must not be made during UpdateReference(). Otherwise references pointing to the destination range will be transposed wrongly during UpdateTranspose(). References in formulas as well as in named ranges are fixed and tested. I've added unit tests for all these cases and I've enhanced my previous copy/paste test framework (6491c205acb3c166d93ef6a41199d344e21d98ac) for cut/paste tests, incl. undo. Before LibreOffice 7.2, adjusting of references in cut paste transposed was completely broken (tdf#71058, tdf#68976, tdf#142065 and tdf#142201). Change-Id: I8a8d295f1cc683572905ae9633e16d010cfb8792 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116073 Tested-by: Jenkins Reviewed-by: Eike Rathke <erack@redhat.com>
140 lines
4.3 KiB
C++
140 lines
4.3 KiB
C++
/* -*- 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 <refupdatecontext.hxx>
|
|
#include <algorithm>
|
|
#include <clipparam.hxx>
|
|
#include <mtvelements.hxx>
|
|
|
|
namespace sc {
|
|
|
|
void UpdatedRangeNames::setUpdatedName(SCTAB nTab, sal_uInt16 nIndex)
|
|
{
|
|
// Map anything <-1 to global names. Unless we really want to come up with
|
|
// some classification there...
|
|
if (nTab < -1)
|
|
nTab = -1;
|
|
|
|
UpdatedNamesType::iterator it = maUpdatedNames.find(nTab);
|
|
if (it == maUpdatedNames.end())
|
|
{
|
|
// Insert a new container for this sheet index.
|
|
NameIndicesType aIndices;
|
|
std::pair<UpdatedNamesType::iterator,bool> r =
|
|
maUpdatedNames.emplace( nTab, aIndices);
|
|
|
|
if (!r.second)
|
|
// Insertion failed for whatever reason.
|
|
return;
|
|
|
|
it = r.first;
|
|
}
|
|
|
|
NameIndicesType& rIndices = it->second;
|
|
rIndices.insert(nIndex);
|
|
}
|
|
|
|
bool UpdatedRangeNames::isNameUpdated(SCTAB nTab, sal_uInt16 nIndex) const
|
|
{
|
|
UpdatedNamesType::const_iterator it = maUpdatedNames.find(nTab);
|
|
if (it == maUpdatedNames.end())
|
|
return false;
|
|
|
|
const NameIndicesType& rIndices = it->second;
|
|
return rIndices.count(nIndex) > 0;
|
|
}
|
|
|
|
UpdatedRangeNames::NameIndicesType UpdatedRangeNames::getUpdatedNames(SCTAB nTab) const
|
|
{
|
|
UpdatedNamesType::const_iterator it = maUpdatedNames.find(nTab);
|
|
if (it == maUpdatedNames.end())
|
|
return NameIndicesType();
|
|
return it->second;
|
|
}
|
|
|
|
bool UpdatedRangeNames::isEmpty(SCTAB nTab) const
|
|
{
|
|
UpdatedNamesType::const_iterator it = maUpdatedNames.find(nTab);
|
|
return it == maUpdatedNames.end();
|
|
}
|
|
|
|
RefUpdateContext::RefUpdateContext(ScDocument& rDoc, ScDocument* pClipdoc)
|
|
: mrDoc(rDoc)
|
|
, meMode(URM_INSDEL)
|
|
, mbTransposed(pClipdoc != nullptr && pClipdoc->GetClipParam().isTransposed())
|
|
, mnColDelta(0)
|
|
, mnRowDelta(0)
|
|
, mnTabDelta(0)
|
|
, mpBlockPos(nullptr)
|
|
{
|
|
assert((pClipdoc == nullptr || pClipdoc->IsClipboard()) && "only nullptr or clipdoc allowed");
|
|
}
|
|
|
|
bool RefUpdateContext::isInserted() const
|
|
{
|
|
return (meMode == URM_INSDEL) && (mnColDelta > 0 || mnRowDelta > 0 || mnTabDelta > 0);
|
|
}
|
|
|
|
bool RefUpdateContext::isDeleted() const
|
|
{
|
|
return (meMode == URM_INSDEL) && (mnColDelta < 0 || mnRowDelta < 0 || mnTabDelta < 0);
|
|
}
|
|
|
|
void RefUpdateContext::setBlockPositionReference( ColumnBlockPositionSet* blockPos )
|
|
{
|
|
mpBlockPos = blockPos;
|
|
}
|
|
|
|
ColumnBlockPosition* RefUpdateContext::getBlockPosition(SCTAB nTab, SCCOL nCol)
|
|
{
|
|
return mpBlockPos ? mpBlockPos->getBlockPosition(nTab, nCol) : nullptr;
|
|
}
|
|
|
|
RefUpdateResult::RefUpdateResult() : mbValueChanged(false), mbReferenceModified(false), mbNameModified(false) {}
|
|
|
|
RefUpdateInsertTabContext::RefUpdateInsertTabContext(ScDocument& rDoc, SCTAB nInsertPos, SCTAB nSheets) :
|
|
mrDoc(rDoc), mnInsertPos(nInsertPos), mnSheets(nSheets) {}
|
|
|
|
RefUpdateDeleteTabContext::RefUpdateDeleteTabContext(ScDocument& rDoc, SCTAB nDeletePos, SCTAB nSheets) :
|
|
mrDoc(rDoc), mnDeletePos(nDeletePos), mnSheets(nSheets) {}
|
|
|
|
RefUpdateMoveTabContext::RefUpdateMoveTabContext(ScDocument& rDoc, SCTAB nOldPos, SCTAB nNewPos) :
|
|
mrDoc(rDoc), mnOldPos(nOldPos), mnNewPos(nNewPos) {}
|
|
|
|
SCTAB RefUpdateMoveTabContext::getNewTab(SCTAB nOldTab) const
|
|
{
|
|
// Sheets below the lower bound or above the upper bound will not change.
|
|
SCTAB nLowerBound = std::min(mnOldPos, mnNewPos);
|
|
SCTAB nUpperBound = std::max(mnOldPos, mnNewPos);
|
|
|
|
if (nOldTab < nLowerBound || nUpperBound < nOldTab)
|
|
// Outside the boundary. Nothing to adjust.
|
|
return nOldTab;
|
|
|
|
if (nOldTab == mnOldPos)
|
|
return mnNewPos;
|
|
|
|
// It's somewhere in between.
|
|
if (mnOldPos < mnNewPos)
|
|
{
|
|
// Moving a sheet to the right. The rest of the sheets shifts to the left.
|
|
return nOldTab - 1;
|
|
}
|
|
|
|
// Moving a sheet to the left. The rest of the sheets shifts to the right.
|
|
return nOldTab + 1;
|
|
}
|
|
|
|
SetFormulaDirtyContext::SetFormulaDirtyContext() :
|
|
mnTabDeletedStart(-1), mnTabDeletedEnd(-1), mbClearTabDeletedFlag(false) {}
|
|
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|