diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-08-10 23:31:38 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-08-12 19:46:29 -0400 |
commit | 30503611efc30ac7a3b09744913f048bf28ef70a (patch) | |
tree | 6ed4cbb0ae787d6fb807c8d5d559a70d25586fae /sc/source | |
parent | bbb2d8c660b515c98624a41a39ffe94d3a7ecc00 (diff) |
Collect all boundaries at which to split the formula group.
Change-Id: Ic78d7a06991b983e625b161f11fbbabce02334f3
Diffstat (limited to 'sc/source')
-rw-r--r-- | sc/source/core/data/column.cxx | 63 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 8 | ||||
-rw-r--r-- | sc/source/core/tool/sharedformula.cxx | 5 | ||||
-rw-r--r-- | sc/source/core/tool/token.cxx | 82 |
4 files changed, 152 insertions, 6 deletions
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 { |