diff options
author | Eike Rathke <erack@redhat.com> | 2015-02-26 12:54:13 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2015-02-27 12:05:35 +0000 |
commit | e8f059f918faf8a44787f8f0bdf61217f4439d7f (patch) | |
tree | 23943157aa9a619653e359297bbde1e81a43ec4e | |
parent | 8a58579a35bb275c985ff0fd412c92f10cd8a085 (diff) |
Resolves: tdf#81659 handle expand reference edge correctly
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
(cherry picked from commit 0cd15b4494f8e8abe67a258fb10189135bf5a8ac)
tdf#81659 check that references are at least 2 cols/rows to expand edge
Needs also 0cd15b4494f8e8abe67a258fb10189135bf5a8ac if edges are to be
expanded and formula grouping is affected.
Change-Id: Ib3cee8dd214d216907248316a2ac5a290399b169
(cherry picked from commit 23b0112ecea2f8796a4e237e9061de1a36997a30)
Reviewed-on: https://gerrit.libreoffice.org/14655
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
-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 | 132 |
3 files changed, 158 insertions, 6 deletions
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 412ecfefe71d..54f1d1e65c1e 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -232,6 +232,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 b60fcc228114..5e975c704973 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 9218498d7342..7710f309f2d5 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -2476,9 +2476,18 @@ bool expandRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const Sc // Selected range is only partially overlapping in vertical direction. Bail out. return false; - if (!rCxt.mrDoc.IsExpandRefs() && rSelectedRange.aStart.Col() <= rRefRange.aStart.Col()) - // Selected range is at the left end and the edge expansion is turned off. No expansion. - return false; + if (rCxt.mrDoc.IsExpandRefs()) + { + if (rRefRange.aEnd.Col() - rRefRange.aStart.Col() < 1) + // Reference must be at least two columns wide. + return false; + } + else + { + if (rSelectedRange.aStart.Col() <= rRefRange.aStart.Col()) + // Selected range is at the left end and the edge expansion is turned off. No expansion. + return false; + } // Move the last column position to the right. SCCOL nDelta = rSelectedRange.aEnd.Col() - rSelectedRange.aStart.Col() + 1; @@ -2492,9 +2501,18 @@ bool expandRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const Sc // Selected range is only partially overlapping in horizontal direction. Bail out. return false; - if (!rCxt.mrDoc.IsExpandRefs() && rSelectedRange.aStart.Row() <= rRefRange.aStart.Row()) - // Selected range is at the top end and the edge expansion is turned off. No expansion. - return false; + if (rCxt.mrDoc.IsExpandRefs()) + { + if (rRefRange.aEnd.Row() - rRefRange.aStart.Row() < 1) + // Reference must be at least two rows tall. + return false; + } + else + { + if (rSelectedRange.aStart.Row() <= rRefRange.aStart.Row()) + // Selected range is at the top end and the edge expansion is turned off. No expansion. + return false; + } // Move the last row position down. SCROW nDelta = rSelectedRange.aEnd.Row() - rSelectedRange.aStart.Row() + 1; @@ -2521,6 +2539,11 @@ bool expandRangeByEdge( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, co if (rCxt.mnColDelta > 0) { // Insert and shift right. + + if (rRefRange.aEnd.Col() - rRefRange.aStart.Col() < 1) + // Reference must be at least two columns wide. + return false; + if (rRefRange.aStart.Row() < rSelectedRange.aStart.Row() || rSelectedRange.aEnd.Row() < rRefRange.aEnd.Row()) // Selected range is only partially overlapping in vertical direction. Bail out. return false; @@ -2536,6 +2559,10 @@ bool expandRangeByEdge( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, co } else if (rCxt.mnRowDelta > 0) { + if (rRefRange.aEnd.Row() - rRefRange.aStart.Row() < 1) + // Reference must be at least two rows tall. + return false; + if (rRefRange.aStart.Col() < rSelectedRange.aStart.Col() || rSelectedRange.aEnd.Col() < rRefRange.aEnd.Col()) // Selected range is only partially overlapping in horizontal direction. Bail out. return false; @@ -3679,6 +3706,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 ) |