summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sc/inc/formulacell.hxx1
-rw-r--r--sc/inc/sharedformula.hxx4
-rw-r--r--sc/inc/tokenarray.hxx3
-rw-r--r--sc/source/core/data/column.cxx63
-rw-r--r--sc/source/core/data/formulacell.cxx8
-rw-r--r--sc/source/core/tool/sharedformula.cxx5
-rw-r--r--sc/source/core/tool/token.cxx82
7 files changed, 160 insertions, 6 deletions
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 0d258a062a99..3318dd2ffddc 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -336,6 +336,7 @@ public:
bool IsShared() const;
bool IsSharedInvariant() const;
+ bool IsSharedTop() const;
SCROW GetSharedTopRow() const;
SCROW GetSharedLength() const;
ScTokenArray* GetSharedCode();
diff --git a/sc/inc/sharedformula.hxx b/sc/inc/sharedformula.hxx
index 232c4bc59be1..9423384faab3 100644
--- a/sc/inc/sharedformula.hxx
+++ b/sc/inc/sharedformula.hxx
@@ -13,6 +13,8 @@
#include "formulacell.hxx"
#include "mtvelements.hxx"
+#include <vector>
+
namespace sc {
class SharedFormulaUtil
@@ -61,6 +63,8 @@ public:
*/
static void splitFormulaCellGroup(const CellStoreType::position_type& aPos);
+ static void splitFormulaCellGroups(CellStoreType& rCells, const std::vector<SCROW>& rBounds);
+
/**
* See if two specified adjacent formula cells can be merged, and if they
* can, merge them into the same group.
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 09a9798a214b..00f192d2e045 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -166,6 +166,9 @@ public:
sc::RefUpdateResult AdjustReferenceOnMovedTab( sc::RefUpdateMoveTabContext& rCxt, const ScAddress& rOldPos );
+ void CheckRelativeReferenceBounds(
+ const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector<SCROW>& rBounds ) const;
+
#if DEBUG_FORMULA_COMPILER
void Dump() const;
#endif
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 0171fab7a1c7..a395c78b4753 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2295,6 +2295,46 @@ public:
bool isUpdated() const { return mbUpdated; }
};
+class UpdateRefGroupBoundChecker : std::unary_function<sc::CellStoreType::value_type, void>
+{
+ const sc::RefUpdateContext& mrCxt;
+ std::vector<SCROW>& mrBounds;
+public:
+ UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
+ mrCxt(rCxt), mrBounds(rBounds) {}
+
+ void operator() (const sc::CellStoreType::value_type& node)
+ {
+ if (node.type != sc::element_type_formula)
+ return;
+
+ sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
+ sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
+
+ // Only pick shared formula cells that are the top cells of their
+ // respective shared ranges.
+ for (; it != itEnd; ++it)
+ {
+ const ScFormulaCell& rCell = **it;
+ if (!rCell.IsShared())
+ continue;
+
+ if (rCell.IsSharedTop())
+ {
+ // Check its tokens and record its reference boundaries.
+ const ScTokenArray& rCode = *rCell.GetCode();
+ rCode.CheckRelativeReferenceBounds(
+ mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
+
+ // Move to the last cell in the group, to get incremented to
+ // the next cell in the next iteration.
+ size_t nOffsetToLast = rCell.GetSharedLength() - 1;
+ std::advance(it, nOffsetToLast);
+ }
+ }
+ }
+};
+
}
bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
@@ -2324,6 +2364,8 @@ bool ScColumn::UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pU
if (rCxt.meMode == URM_COPY)
return UpdateReferenceOnCopy(rCxt, pUndoDoc);
+ std::vector<SCROW> aBounds;
+
bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
rCxt.maRange.aStart.Col() <= nCol && nCol <= rCxt.maRange.aEnd.Col());
if (bThisColShifted)
@@ -2333,17 +2375,26 @@ bool ScColumn::UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pU
SCROW nSplitPos = rCxt.maRange.aStart.Row();
if (ValidRow(nSplitPos))
{
- sc::CellStoreType::position_type aPos = maCells.position(nSplitPos);
- sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
+ aBounds.push_back(nSplitPos);
nSplitPos = rCxt.maRange.aEnd.Row() + 1;
if (ValidRow(nSplitPos))
- {
- aPos = maCells.position(aPos.first, nSplitPos);
- sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
- }
+ aBounds.push_back(nSplitPos);
}
}
+ // Check the row positions at which the group must be split per relative
+ // references.
+ UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
+ std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
+
+ // Sort and remove duplicates.
+ std::sort(aBounds.begin(), aBounds.end());
+ std::vector<SCROW>::iterator it = std::unique(aBounds.begin(), aBounds.end());
+ aBounds.erase(it, aBounds.end());
+
+ // Do the actual splitting.
+ sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+
UpdateRefOnNonCopy aHandler(nCol, nTab, rCxt, pUndoDoc);
sc::ProcessFormula(maCells, aHandler);
return aHandler.isUpdated();
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 06fb6dc9bae7..1753153ca3ad 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3824,6 +3824,14 @@ bool ScFormulaCell::IsSharedInvariant() const
return mxGroup ? mxGroup->mbInvariant : false;
}
+bool ScFormulaCell::IsSharedTop() const
+{
+ if (!mxGroup)
+ return false;
+
+ return mxGroup->mnStart == aPos.Row();
+}
+
SCROW ScFormulaCell::GetSharedTopRow() const
{
return mxGroup ? mxGroup->mnStart : -1;
diff --git a/sc/source/core/tool/sharedformula.cxx b/sc/source/core/tool/sharedformula.cxx
index 3e77934f894d..d9f3a2595f67 100644
--- a/sc/source/core/tool/sharedformula.cxx
+++ b/sc/source/core/tool/sharedformula.cxx
@@ -64,6 +64,11 @@ void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type
}
}
+void SharedFormulaUtil::splitFormulaCellGroups(CellStoreType& rCells, const std::vector<SCROW>& rBounds)
+{
+ // TODO: Implement this.
+}
+
void SharedFormulaUtil::joinFormulaCells(const CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2)
{
ScFormulaCell::CompareState eState = rCell1.CompareByTokenArray(rCell2);
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index d74182d9a065..1fbf32581dbf 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2934,6 +2934,88 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa
return aRes;
}
+namespace {
+
+void checkBounds(
+ const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen,
+ const ScSingleRefData& rRef, std::vector<SCROW>& rBounds)
+{
+ if (!rRef.IsRowRel())
+ return;
+
+ ScRange aAbs(rRef.toAbs(rPos));
+ aAbs.aEnd.IncRow(nGroupLen-1);
+ if (!rCxt.maRange.Intersects(aAbs))
+ return;
+
+ // Get the boundary row positions.
+ if (aAbs.aEnd.Row() < rCxt.maRange.aStart.Row())
+ // No intersections.
+ return;
+
+ if (aAbs.aEnd.Row() <= rCxt.maRange.aEnd.Row())
+ {
+ // +-+ <---- top
+ // | |
+ // +--+-+--+ <---- boundary row position
+ // | | | |
+ // | +-+ |
+ // +-------+
+
+ // Add offset from the reference top to the cell position.
+ SCROW nOffset = rCxt.maRange.aStart.Row() - aAbs.aStart.Row();
+ rBounds.push_back(rPos.Row()+nOffset);
+ return;
+ }
+
+ // +-+ <---- top
+ // | |
+ // +--+-+--+ <---- boundary row position
+ // | | | |
+ // | | | |
+ // +--+-+--+ <---- boundary row position
+ // | |
+ // +-+
+
+ // Add offset from the reference top to the cell position.
+ SCROW nOffset = rCxt.maRange.aStart.Row() - aAbs.aStart.Row();
+ rBounds.push_back(rPos.Row()+nOffset);
+ // Ditto.
+ nOffset = rCxt.maRange.aEnd.Row() - aAbs.aStart.Row();
+ rBounds.push_back(rPos.Row()+nOffset);
+}
+
+}
+
+void ScTokenArray::CheckRelativeReferenceBounds(
+ const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, 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);
+ checkBounds(rCxt, rPos, nGroupLen, pToken->GetSingleRef(), rBounds);
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ const ScComplexRefData& rRef = pToken->GetDoubleRef();
+ checkBounds(rCxt, rPos, nGroupLen, rRef.Ref1, rBounds);
+ checkBounds(rCxt, rPos, nGroupLen, rRef.Ref2, rBounds);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
#if DEBUG_FORMULA_COMPILER
void ScTokenArray::Dump() const
{