Files
loongoffice/sc/source/core/data/refupdatecontext.cxx
scito bda9929821 tdf#142201 tdf#142065 fix cut paste transpose references, incl. undo
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>
2021-05-29 22:46:11 +02:00

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: */