diff options
author | Eike Rathke <erack@redhat.com> | 2015-02-26 12:54:13 +0100 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2015-02-26 16:17:38 +0100 |
commit | 0cd15b4494f8e8abe67a258fb10189135bf5a8ac (patch) | |
tree | b1cea6b4af68a4a0a775a838aac20eca4528e67d | |
parent | c6d42c265f8a30b64f12275b1da643ccb6fa81cc (diff) |
split formula grouping for reference edge expansion, tdf#81659 related
Edge expansion may change expressions individually, which must be split
off the group.
Change-Id: Id4328bd8c42f2ff9f83d2edc845537971f3a39d3
-rw-r--r-- | sc/inc/tokenarray.hxx | 3 | ||||
-rw-r--r-- | sc/source/core/data/column.cxx | 29 | ||||
-rw-r--r-- | sc/source/core/tool/token.cxx | 93 |
3 files changed, 125 insertions, 0 deletions
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 9dc94b9a9c4a..40687455bac9 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -233,6 +233,9 @@ public: void CheckRelativeReferenceBounds( const ScAddress& rPos, SCROW nGroupLen, const ScRange& rRange, std::vector<SCROW>& rBounds ) const; + void CheckExpandReferenceBounds( + const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector<SCROW>& rBounds ) const; + /** * Create a string representation of formula token array without modifying * the internal state of the token array. diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index ab7cd69c17d5..94d753d0681f 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2279,6 +2279,27 @@ public: } }; +class UpdateRefExpandGroupBoundChecker : public SharedTopFormulaCellPicker +{ + const sc::RefUpdateContext& mrCxt; + std::vector<SCROW>& mrBounds; + +public: + UpdateRefExpandGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) : + mrCxt(rCxt), mrBounds(rBounds) {} + + virtual ~UpdateRefExpandGroupBoundChecker() {} + + virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) SAL_OVERRIDE + { + // Check its tokens and record its reference boundaries. + ScFormulaCell& rCell = **ppCells; + const ScTokenArray& rCode = *rCell.GetCode(); + rCode.CheckExpandReferenceBounds( + mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds); + } +}; + class FormulaGroupPicker : public SharedTopFormulaCellPicker { std::vector<sc::FormulaGroupEntry>& mrGroups; @@ -2364,6 +2385,14 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds); std::for_each(maCells.begin(), maCells.end(), aBoundChecker); + // If expand reference edges is on, splitting groups may happen anywhere + // where a reference points to an adjacent row of the insertion. + if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs()) + { + UpdateRefExpandGroupBoundChecker aExpandChecker(rCxt, aBounds); + std::for_each(maCells.begin(), maCells.end(), aExpandChecker); + } + // Do the actual splitting. sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds); diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index b5dbee07701e..77489fda72c9 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -3682,6 +3682,99 @@ void ScTokenArray::CheckRelativeReferenceBounds( } } +void ScTokenArray::CheckExpandReferenceBounds( + const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector<SCROW>& rBounds ) const +{ + const SCROW nInsRow = rCxt.maRange.aStart.Row(); + const FormulaToken* const * p = pCode; + const FormulaToken* const * pEnd = p + static_cast<size_t>(nLen); + for (; p != pEnd; ++p) + { + switch ((*p)->GetType()) + { + case svDoubleRef: + { + const formula::FormulaToken* pToken = *p; + const ScComplexRefData& rRef = *pToken->GetDoubleRef(); + bool bStartRowRelative = rRef.Ref1.IsRowRel(); + bool bEndRowRelative = rRef.Ref2.IsRowRel(); + + // For absolute references nothing needs to be done, they stay + // the same for all and if to be expanded the group will be + // adjusted later. + if (!bStartRowRelative && !bEndRowRelative) + break; // switch + + ScRange aAbsStart(rRef.toAbs(rPos)); + ScAddress aPos(rPos); + aPos.IncRow(nGroupLen); + ScRange aAbsEnd(rRef.toAbs(aPos)); + // References must be at least two rows to be expandable. + if ((aAbsStart.aEnd.Row() - aAbsStart.aStart.Row() < 1) && + (aAbsEnd.aEnd.Row() - aAbsEnd.aStart.Row() < 1)) + break; // switch + + // Only need to process if an edge may be touching the + // insertion row anywhere within the run of the group. + if (!((aAbsStart.aStart.Row() <= nInsRow && nInsRow <= aAbsEnd.aStart.Row()) || + (aAbsStart.aEnd.Row() <= nInsRow && nInsRow <= aAbsEnd.aEnd.Row()))) + break; // switch + + SCROW nStartRow = aAbsStart.aStart.Row(); + SCROW nEndRow = aAbsStart.aEnd.Row(); + // Position on first relevant range. + SCROW nOffset = 0; + if (nEndRow + 1 < nInsRow) + { + if (bEndRowRelative) + { + nOffset = nInsRow - nEndRow - 1; + nEndRow += nOffset; + if (bStartRowRelative) + nStartRow += nOffset; + } + else // bStartRowRelative==true + { + nOffset = nInsRow - nStartRow; + nStartRow += nOffset; + // Start is overtaking End, swap. + bStartRowRelative = false; + bEndRowRelative = true; + } + } + for (SCROW i = nOffset; i < nGroupLen; ++i) + { + bool bSplit = (nStartRow == nInsRow || nEndRow + 1 == nInsRow); + if (bSplit) + rBounds.push_back( rPos.Row() + i); + + if (bEndRowRelative) + ++nEndRow; + if (bStartRowRelative) + { + ++nStartRow; + if (!bEndRowRelative && nStartRow == nEndRow) + { + // Start is overtaking End, swap. + bStartRowRelative = false; + bEndRowRelative = true; + } + } + if (nInsRow < nStartRow || (!bStartRowRelative && nInsRow <= nEndRow)) + { + if (bSplit && (++i < nGroupLen)) + rBounds.push_back( rPos.Row() + i); + break; // for, out of range now + } + } + } + break; + default: + ; + } + } +} + namespace { void appendDouble( sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, double fVal ) |