summaryrefslogtreecommitdiff
path: root/sc/source
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-05-01 01:15:02 -0400
committerKohei Yoshida <kohei.yoshida@collabora.com>2014-05-01 01:18:50 -0400
commit3c4fb52d8fc89fe43983991ed2339295b2e0ef8c (patch)
treee1f5f8f6f047edad2d610394c737ff2f1ceca44c /sc/source
parent0e443b773454fa153827753812757d88eea932c5 (diff)
fdo#78079: Re-work sort by column to get it to do the right thing.
Also fixed reference update problem. Change-Id: I06e6115ef969a011fdd5c92d5eb1927fb7ae789b
Diffstat (limited to 'sc/source')
-rw-r--r--sc/source/core/data/column.cxx60
-rw-r--r--sc/source/core/data/column4.cxx129
-rw-r--r--sc/source/core/data/formulacell.cxx24
-rw-r--r--sc/source/core/data/table3.cxx95
-rw-r--r--sc/source/core/tool/refhint.cxx25
-rw-r--r--sc/source/core/tool/token.cxx160
6 files changed, 393 insertions, 100 deletions
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index a2435989dd3a..208c04688e53 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -836,66 +836,6 @@ const sc::CellTextAttr* ScColumn::GetCellTextAttr( sc::ColumnBlockConstPosition&
return &sc::celltextattr_block::at(*aPos.first->data, aPos.second);
}
-namespace {
-
-/**
- * Adjust references in formula cell with respect to column-wise relocation.
- */
-void updateRefInFormulaCell( ScDocument* pDoc, ScFormulaCell& rCell, SCCOL nCol, SCTAB nTab, SCCOL nColDiff )
-{
- rCell.aPos.SetCol(nCol);
- sc::RefUpdateContext aCxt(*pDoc);
- aCxt.meMode = URM_MOVE;
- aCxt.maRange = ScRange(ScAddress(nCol, 0, nTab), ScAddress(nCol, MAXROW, nTab));
- aCxt.mnColDelta = nColDiff;
- rCell.UpdateReference(aCxt);
-}
-
-}
-
-void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
-{
- sc::CellStoreType::position_type aPos1 = maCells.position(nRow);
- sc::CellStoreType::position_type aPos2 = rCol.maCells.position(nRow);
-
- if (aPos1.first->type == sc::element_type_formula)
- {
- ScFormulaCell& rCell = *sc::formula_block::at(*aPos1.first->data, aPos1.second);
- updateRefInFormulaCell(pDocument, rCell, rCol.nCol, nTab, rCol.nCol - nCol);
- sc::SharedFormulaUtil::unshareFormulaCell(aPos1, rCell);
- }
-
- if (aPos2.first->type == sc::element_type_formula)
- {
- ScFormulaCell& rCell = *sc::formula_block::at(*aPos2.first->data, aPos2.second);
- updateRefInFormulaCell(pDocument, rCell, nCol, nTab, nCol - rCol.nCol);
- sc::SharedFormulaUtil::unshareFormulaCell(aPos2, rCell);
- }
-
- maCells.swap(nRow, nRow, rCol.maCells, nRow);
- maCellTextAttrs.swap(nRow, nRow, rCol.maCellTextAttrs, nRow);
- maCellNotes.swap(nRow, nRow, rCol.maCellNotes, nRow);
-
- aPos1 = maCells.position(nRow);
- aPos2 = rCol.maCells.position(nRow);
-
- if (aPos1.first->type == sc::element_type_formula)
- {
- ScFormulaCell& rCell = *sc::formula_block::at(*aPos1.first->data, aPos1.second);
- JoinNewFormulaCell(aPos1, rCell);
- }
-
- if (aPos2.first->type == sc::element_type_formula)
- {
- ScFormulaCell& rCell = *sc::formula_block::at(*aPos2.first->data, aPos2.second);
- rCol.JoinNewFormulaCell(aPos2, rCell);
- }
-
- CellStorageModified();
- rCol.CellStorageModified();
-}
-
-
bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
{
if (IsEmpty())
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index b9553448e669..cf9cd1e2f00a 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -28,6 +28,7 @@
#include <globalnames.hxx>
#include <scitems.hxx>
#include <cellform.hxx>
+#include <sharedformula.hxx>
#include <svl/sharedstringpool.hxx>
@@ -830,4 +831,132 @@ void ScColumn::UpdateScriptTypes( SCROW nRow1, SCROW nRow2 )
CellStorageModified();
}
+void ScColumn::Swap( ScColumn& rOther, SCROW nRow1, SCROW nRow2, bool bPattern )
+{
+ maCells.swap(nRow1, nRow2, rOther.maCells, nRow1);
+ maCellTextAttrs.swap(nRow1, nRow2, rOther.maCellTextAttrs, nRow1);
+ maCellNotes.swap(nRow1, nRow2, rOther.maCellNotes, nRow1);
+ maBroadcasters.swap(nRow1, nRow2, rOther.maBroadcasters, nRow1);
+
+ if (bPattern)
+ {
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ const ScPatternAttr* pPat1 = GetPattern(nRow);
+ const ScPatternAttr* pPat2 = rOther.GetPattern(nRow);
+ if (pPat1 != pPat2)
+ {
+ SetPattern(nRow, *pPat2, true);
+ rOther.SetPattern(nRow, *pPat1, true);
+ }
+ }
+ }
+
+ CellStorageModified();
+ rOther.CellStorageModified();
+}
+
+namespace {
+
+class FormulaColPosSetter
+{
+ SCCOL mnCol;
+public:
+ FormulaColPosSetter( SCCOL nCol ) : mnCol(nCol) {}
+
+ void operator() ( size_t nRow, ScFormulaCell* pCell )
+ {
+ if (!pCell->IsShared() || pCell->IsSharedTop())
+ {
+ // Ensure that the references still point to the same locations
+ // after the position change.
+ ScAddress aOldPos = pCell->aPos;
+ pCell->aPos.SetCol(mnCol);
+ pCell->aPos.SetRow(nRow);
+ pCell->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, pCell->aPos);
+ }
+ else
+ {
+ pCell->aPos.SetCol(mnCol);
+ pCell->aPos.SetRow(nRow);
+ }
+ }
+};
+
+}
+
+void ScColumn::ResetFormulaCellPositions( SCROW nRow1, SCROW nRow2 )
+{
+ FormulaColPosSetter aFunc(nCol);
+ sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+}
+
+namespace {
+
+class RelativeRefBoundChecker
+{
+ std::vector<SCROW> maBounds;
+ ScRange maBoundRange;
+
+public:
+ RelativeRefBoundChecker( const ScRange& rBoundRange ) :
+ maBoundRange(rBoundRange) {}
+
+ void operator() ( size_t /*nRow*/, ScFormulaCell* pCell )
+ {
+ if (!pCell->IsSharedTop())
+ return;
+
+ pCell->GetCode()->CheckRelativeReferenceBounds(
+ pCell->aPos, pCell->GetSharedLength(), maBoundRange, maBounds);
+ }
+
+ void swapBounds( std::vector<SCROW>& rBounds )
+ {
+ rBounds.swap(maBounds);
+ }
+};
+
+}
+
+void ScColumn::SplitFormulaGroupByRelativeRef( const ScRange& rBoundRange )
+{
+ std::vector<SCROW> aBounds;
+
+ // Cut at row boundaries first.
+ aBounds.push_back(rBoundRange.aStart.Row());
+ aBounds.push_back(rBoundRange.aEnd.Row()+1);
+ sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+
+ RelativeRefBoundChecker aFunc(rBoundRange);
+ sc::ProcessFormula(
+ maCells.begin(), maCells, rBoundRange.aStart.Row(), rBoundRange.aEnd.Row(), aFunc);
+ aFunc.swapBounds(aBounds);
+ sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+}
+
+namespace {
+
+class ListenerCollector
+{
+ std::vector<SvtListener*>& mrListeners;
+public:
+ ListenerCollector( std::vector<SvtListener*>& rListener ) :
+ mrListeners(rListener) {}
+
+ void operator() ( size_t /*nRow*/, SvtBroadcaster* p )
+ {
+ SvtBroadcaster::ListenersType& rLis = p->GetAllListeners();
+ std::copy(rLis.begin(), rLis.end(), std::back_inserter(mrListeners));
+ }
+};
+
+}
+
+void ScColumn::CollectListeners( std::vector<SvtListener*>& rListeners, SCROW nRow1, SCROW nRow2 )
+{
+ ListenerCollector aFunc(rListeners);
+ sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index aa52450b576d..d7cef22772b6 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -1898,12 +1898,28 @@ void ScFormulaCell::Notify( const SfxHint& rHint )
{
const sc::RefHint& rRefHint = static_cast<const sc::RefHint&>(rHint);
- if (rRefHint.getType() == sc::RefHint::Moved)
+ switch (rRefHint.getType())
{
- // One of the references has moved.
+ case sc::RefHint::Moved:
+ {
+ // One of the references has moved.
- const sc::RefMovedHint& rRefMoved = static_cast<const sc::RefMovedHint&>(rRefHint);
- pCode->MoveReference(aPos, rRefMoved.getRange(), rRefMoved.getDelta());
+ const sc::RefMovedHint& rRefMoved = static_cast<const sc::RefMovedHint&>(rRefHint);
+ if (!IsShared() || IsSharedTop())
+ pCode->MoveReference(aPos, rRefMoved.getRange(), rRefMoved.getDelta());
+ }
+ break;
+ case sc::RefHint::ColumnReordered:
+ {
+ const sc::RefColReorderHint& rRefColReorder =
+ static_cast<const sc::RefColReorderHint&>(rRefHint);
+ if (!IsShared() || IsSharedTop())
+ pCode->MoveReference(
+ aPos, rRefColReorder.getTab(), rRefColReorder.getStartRow(), rRefColReorder.getEndRow(), rRefColReorder.getColMap());
+ }
+ break;
+ default:
+ ;
}
return;
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 2cf6c1b26401..f32d5597c2ca 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -60,6 +60,7 @@
#include <fstalgorithm.hxx>
#include <listenercontext.hxx>
#include <sharedformula.hxx>
+#include <refhint.hxx>
#include "svl/sharedstringpool.hxx"
@@ -257,6 +258,7 @@ private:
SCCOLROW mnLastIndex; /// index of last non-empty cell position.
sal_uInt16 nUsedSorts;
+ std::vector<SCCOLROW> maOldIndices;
bool mbKeepQuery;
public:
@@ -274,6 +276,9 @@ public:
ppInfo[j] = new ScSortInfo;
pppInfo[nSort] = ppInfo;
}
+
+ for (size_t i = 0; i < nCount; ++i)
+ maOldIndices.push_back(i+nStart);
}
~ScSortInfoArray()
@@ -310,6 +315,8 @@ public:
ppInfo[n2] = pTmp;
}
+ std::swap(maOldIndices[n1], maOldIndices[n2]);
+
if (mpRows)
{
// Swap rows in data table.
@@ -324,6 +331,8 @@ public:
SCCOLROW GetLast() const { return mnLastIndex; }
SCSIZE GetCount() const { return nCount; }
+ const std::vector<SCCOLROW>& GetOldIndices() const { return maOldIndices; }
+
RowsType& InitDataRows( size_t nRowSize, size_t nColSize )
{
mpRows.reset(new RowsType);
@@ -520,6 +529,22 @@ void ScTable::DestroySortCollator()
}
}
+namespace {
+
+class ColReorderNotifier : std::unary_function<SvtListener*, void>
+{
+ sc::RefColReorderHint maHint;
+public:
+ ColReorderNotifier( const sc::ColReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ) :
+ maHint(rColMap, nTab, nRow1, nRow2) {}
+
+ void operator() ( SvtListener* p )
+ {
+ p->Notify(maHint);
+ }
+};
+
+}
void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
{
@@ -531,20 +556,28 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
size_t nCount = pArray->GetCount();
SCCOLROW nStart = pArray->GetStart();
+ SCCOLROW nLast = pArray->GetLast();
ScSortInfo** ppInfo = pArray->GetFirstArray();
std::vector<ScSortInfo*> aTable(nCount);
+
SCSIZE nPos;
for ( nPos = 0; nPos < nCount; nPos++ )
aTable[ppInfo[nPos]->nOrg - nStart] = ppInfo[nPos];
+ // Cut formula grouping at row and reference boundaries before the reordering.
+ ScRange aSortRange(nStart, aSortParam.nRow1, nTab, nLast, aSortParam.nRow2, nTab);
+ for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
+ aCol[nCol].SplitFormulaGroupByRelativeRef(aSortRange);
+
SCCOLROW nDest = nStart;
for ( nPos = 0; nPos < nCount; nPos++, nDest++ )
{
SCCOLROW nOrg = ppInfo[nPos]->nOrg;
if ( nDest != nOrg )
{
- SwapCol( static_cast<SCCOL>(nDest), static_cast<SCCOL>(nOrg) );
+ aCol[nDest].Swap(aCol[nOrg], aSortParam.nRow1, aSortParam.nRow2, aSortParam.bIncludePattern);
+
// neue Position des weggeswapten eintragen
ScSortInfo* p = ppInfo[nPos];
p->nOrg = nDest;
@@ -556,6 +589,44 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
if(pProgress)
pProgress->SetStateOnPercent( nPos );
}
+
+ // Reset formula cell positions which became out-of-sync after column reordering.
+ for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
+ aCol[nCol].ResetFormulaCellPositions(aSortParam.nRow1, aSortParam.nRow2);
+
+ // Set up column reorder map (for later broadcasting of reference updates).
+ sc::ColReorderMapType aColMap;
+ const std::vector<SCCOLROW>& rOldIndices = pArray->GetOldIndices();
+ for (size_t i = 0, n = rOldIndices.size(); i < n; ++i)
+ {
+ SCCOL nNew = i + nStart;
+ SCROW nOld = rOldIndices[i];
+ aColMap.insert(sc::ColReorderMapType::value_type(nOld, nNew));
+ }
+
+ // Collect all listeners within sorted range ahead of time.
+ std::vector<SvtListener*> aListeners;
+ for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
+ aCol[nCol].CollectListeners(aListeners, aSortParam.nRow1, aSortParam.nRow2);
+
+ // Remove any duplicate listener entries and notify all listeners
+ // afterward. We must ensure that we notify each unique listener only
+ // once.
+ std::sort(aListeners.begin(), aListeners.end());
+ aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end());
+ ColReorderNotifier aFunc(aColMap, nTab, aSortParam.nRow1, aSortParam.nRow2);
+ std::for_each(aListeners.begin(), aListeners.end(), aFunc);
+
+ // Re-join formulas at row boundaries now that all the references have
+ // been adjusted for column reordering.
+ for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
+ {
+ sc::CellStoreType& rCells = aCol[nCol].maCells;
+ sc::CellStoreType::position_type aPos = rCells.position(aSortParam.nRow1);
+ sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
+ aPos = rCells.position(aPos.first, aSortParam.nRow2+1);
+ sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
+ }
}
void ScTable::SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress )
@@ -913,28 +984,6 @@ void ScTable::QuickSort( ScSortInfoArray* pArray, SCsCOLROW nLo, SCsCOLROW nHi )
}
}
-void ScTable::SwapCol(SCCOL nCol1, SCCOL nCol2)
-{
- SCROW nRowStart = aSortParam.nRow1;
- SCROW nRowEnd = aSortParam.nRow2;
- for (SCROW nRow = nRowStart; nRow <= nRowEnd; nRow++)
- {
- aCol[nCol1].SwapCell(nRow, aCol[nCol2]);
- if (aSortParam.bIncludePattern)
- {
- const ScPatternAttr* pPat1 = GetPattern(nCol1, nRow);
- const ScPatternAttr* pPat2 = GetPattern(nCol2, nRow);
- if (pPat1 != pPat2)
- {
- pDocument->GetPool()->Put(*pPat1);
- SetPattern(nCol1, nRow, *pPat2, true);
- SetPattern(nCol2, nRow, *pPat1, true);
- pDocument->GetPool()->Remove(*pPat1);
- }
- }
- }
-}
-
short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
{
short nRes;
diff --git a/sc/source/core/tool/refhint.cxx b/sc/source/core/tool/refhint.cxx
index eb07b4fe3565..0e70b4f22ac3 100644
--- a/sc/source/core/tool/refhint.cxx
+++ b/sc/source/core/tool/refhint.cxx
@@ -31,6 +31,31 @@ const ScAddress& RefMovedHint::getDelta() const
return maMoveDelta;
}
+RefColReorderHint::RefColReorderHint( const sc::ColReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ) :
+ RefHint(ColumnReordered), mrColMap(rColMap), mnTab(nTab), mnRow1(nRow1), mnRow2(nRow2) {}
+
+RefColReorderHint::~RefColReorderHint() {}
+
+const sc::ColReorderMapType& RefColReorderHint::getColMap() const
+{
+ return mrColMap;
+}
+
+SCTAB RefColReorderHint::getTab() const
+{
+ return mnTab;
+}
+
+SCROW RefColReorderHint::getStartRow() const
+{
+ return mnRow1;
+}
+
+SCROW RefColReorderHint::getEndRow() const
+{
+ return mnRow2;
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 016ff7942d77..bd884eb0246c 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2879,6 +2879,70 @@ void ScTokenArray::MoveReference(
}
}
+void ScTokenArray::MoveReference(
+ const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, const sc::ColReorderMapType& rColMap )
+{
+ FormulaToken** p = pCode;
+ FormulaToken** pEnd = p + static_cast<size_t>(nLen);
+ for (; p != pEnd; ++p)
+ {
+ switch ((*p)->GetType())
+ {
+ case svSingleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ ScSingleRefData& rRef = pToken->GetSingleRef();
+ ScAddress aAbs = rRef.toAbs(rPos);
+
+ if (aAbs.Tab() == nTab && nRow1 <= aAbs.Row() && aAbs.Row() <= nRow2)
+ {
+ // Inside reordered row range.
+ sc::ColReorderMapType::const_iterator it = rColMap.find(aAbs.Col());
+ if (it != rColMap.end())
+ {
+ // This column is reordered.
+ SCCOL nNewCol = it->second;
+ aAbs.SetCol(nNewCol);
+ rRef.SetAddress(aAbs, rPos);
+ }
+ }
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ ScComplexRefData& rRef = pToken->GetDoubleRef();
+ ScRange aAbs = rRef.toAbs(rPos);
+
+ if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
+ // Must be a single-sheet reference.
+ break;
+
+ if (aAbs.aStart.Col() != aAbs.aEnd.Col())
+ // Whole range must fit in a single column.
+ break;
+
+ if (aAbs.aStart.Tab() == nTab && nRow1 <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= nRow2)
+ {
+ // Inside reordered row range.
+ sc::ColReorderMapType::const_iterator it = rColMap.find(aAbs.aStart.Col());
+ if (it != rColMap.end())
+ {
+ // This column is reordered.
+ SCCOL nNewCol = it->second;
+ aAbs.aStart.SetCol(nNewCol);
+ aAbs.aEnd.SetCol(nNewCol);
+ rRef.SetRange(aAbs, rPos);
+ }
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
namespace {
bool adjustSingleRefInName(
@@ -3292,6 +3356,36 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa
return aRes;
}
+void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const ScAddress& rNewPos )
+{
+ FormulaToken** p = pCode;
+ FormulaToken** pEnd = p + static_cast<size_t>(nLen);
+ for (; p != pEnd; ++p)
+ {
+ switch ((*p)->GetType())
+ {
+ case svSingleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ ScSingleRefData& rRef = pToken->GetSingleRef();
+ ScAddress aAbs = rRef.toAbs(rOldPos);
+ rRef.SetAddress(aAbs, rNewPos);
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ ScComplexRefData& rRef = pToken->GetDoubleRef();
+ ScRange aAbs = rRef.toAbs(rOldPos);
+ rRef.SetRange(aAbs, rNewPos);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
namespace {
void clearTabDeletedFlag( ScSingleRefData& rRef, const ScAddress& rPos, SCTAB nStartTab, SCTAB nEndTab )
@@ -3341,28 +3435,23 @@ void ScTokenArray::ClearTabDeleted( const ScAddress& rPos, SCTAB nStartTab, SCTA
namespace {
void checkBounds(
- const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen,
- const ScSingleRefData& rRef, std::vector<SCROW>& rBounds)
+ const ScAddress& rPos, SCROW nGroupLen, const ScRange& rCheckRange,
+ const ScSingleRefData& rRef, std::vector<SCROW>& rBounds )
{
if (!rRef.IsRowRel())
return;
- ScRange aCheckRange = rCxt.maRange;
- if (rCxt.meMode == URM_MOVE)
- // Check bounds against the old range prior to the move.
- aCheckRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta);
-
ScRange aAbs(rRef.toAbs(rPos));
aAbs.aEnd.IncRow(nGroupLen-1);
- if (!aCheckRange.Intersects(aAbs))
+ if (!rCheckRange.Intersects(aAbs))
return;
// Get the boundary row positions.
- if (aAbs.aEnd.Row() < aCheckRange.aStart.Row())
+ if (aAbs.aEnd.Row() < rCheckRange.aStart.Row())
// No intersections.
return;
- if (aAbs.aStart.Row() <= aCheckRange.aStart.Row())
+ if (aAbs.aStart.Row() <= rCheckRange.aStart.Row())
{
// +-+ <---- top
// | |
@@ -3372,11 +3461,11 @@ void checkBounds(
// +-------+
// Add offset from the reference top to the cell position.
- SCROW nOffset = aCheckRange.aStart.Row() - aAbs.aStart.Row();
+ SCROW nOffset = rCheckRange.aStart.Row() - aAbs.aStart.Row();
rBounds.push_back(rPos.Row()+nOffset);
}
- if (aAbs.aEnd.Row() >= aCheckRange.aEnd.Row())
+ if (aAbs.aEnd.Row() >= rCheckRange.aEnd.Row())
{
// only check for end range
@@ -3388,11 +3477,26 @@ void checkBounds(
// +-+
// Ditto.
- SCROW nOffset = aCheckRange.aEnd.Row() + 1 - aAbs.aStart.Row();
+ SCROW nOffset = rCheckRange.aEnd.Row() + 1 - aAbs.aStart.Row();
rBounds.push_back(rPos.Row()+nOffset);
}
}
+void checkBounds(
+ const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen,
+ const ScSingleRefData& rRef, std::vector<SCROW>& rBounds)
+{
+ if (!rRef.IsRowRel())
+ return;
+
+ ScRange aCheckRange = rCxt.maRange;
+ if (rCxt.meMode == URM_MOVE)
+ // Check bounds against the old range prior to the move.
+ aCheckRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta);
+
+ checkBounds(rPos, nGroupLen, aCheckRange, rRef, rBounds);
+}
+
}
void ScTokenArray::CheckRelativeReferenceBounds(
@@ -3424,6 +3528,36 @@ void ScTokenArray::CheckRelativeReferenceBounds(
}
}
+void ScTokenArray::CheckRelativeReferenceBounds(
+ const ScAddress& rPos, SCROW nGroupLen, const ScRange& rRange, std::vector<SCROW>& rBounds ) const
+{
+ FormulaToken** p = pCode;
+ FormulaToken** pEnd = p + static_cast<size_t>(nLen);
+ for (; p != pEnd; ++p)
+ {
+ switch ((*p)->GetType())
+ {
+ case svSingleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ const ScSingleRefData& rRef = pToken->GetSingleRef();
+ checkBounds(rPos, nGroupLen, rRange, rRef, rBounds);
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ const ScComplexRefData& rRef = pToken->GetDoubleRef();
+ checkBounds(rPos, nGroupLen, rRange, rRef.Ref1, rBounds);
+ checkBounds(rPos, nGroupLen, rRange, rRef.Ref2, rBounds);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
namespace {
void appendDouble( sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, double fVal )