summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2015-02-26 12:54:13 +0100
committerEike Rathke <erack@redhat.com>2015-02-26 16:17:38 +0100
commit0cd15b4494f8e8abe67a258fb10189135bf5a8ac (patch)
treeb1cea6b4af68a4a0a775a838aac20eca4528e67d
parentc6d42c265f8a30b64f12275b1da643ccb6fa81cc (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.hxx3
-rw-r--r--sc/source/core/data/column.cxx29
-rw-r--r--sc/source/core/tool/token.cxx93
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 )