summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-11-18 20:08:53 -0500
committerKohei Yoshida <kohei.yoshida@collabora.com>2014-11-18 20:11:02 -0500
commit600d900e6c52bde98ed38370b104e5268689c5dd (patch)
tree6282b1a9ad63066e0d929ba80307cd60bcf3d05c
parentfa355e25b70b5e6892cd4840d9fad0a39d7a63c1 (diff)
Use group area listeners when filling down formula cells via fill series.
Change-Id: Ib0d4f542986dc09968cad8b76da9d6e034eddd37
-rw-r--r--sc/inc/column.hxx13
-rw-r--r--sc/source/core/data/column.cxx5
-rw-r--r--sc/source/core/data/column4.cxx146
-rw-r--r--sc/source/core/data/table2.cxx2
-rw-r--r--sc/source/core/data/table4.cxx41
5 files changed, 184 insertions, 23 deletions
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 972ed89f44d2..07ef1e52c7c2 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -255,9 +255,6 @@ public:
void CopyFromClip(
sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn );
- void StartListeningFromClip(
- sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, SCROW nRow1, SCROW nRow2 );
-
void RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow );
// Selection (?) of this document
@@ -355,7 +352,7 @@ public:
void SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt );
void SetDirtyFromClip( SCROW nRow1, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans );
- void SetDirty( SCROW nRow1, SCROW nRow2 );
+ void SetDirty( SCROW nRow1, SCROW nRow2, bool bBroadcast = true );
void SetDirtyVar();
void SetDirtyAfterLoad();
void SetTableOpDirty( const ScRange& );
@@ -487,6 +484,14 @@ public:
bool TestTabRefAbs(SCTAB nTable) const;
bool GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const;
+ void StartListeningFormulaCells(
+ sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, SCROW nRow1, SCROW nRow2,
+ SCROW* pStartRow = NULL, SCROW* pEndRow = NULL );
+
+ void EndListeningFormulaCells(
+ sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2,
+ SCROW* pStartRow = NULL, SCROW* pEndRow = NULL );
+
void StartListening( SvtListener& rLst, SCROW nRow );
void EndListening( SvtListener& rLst, SCROW nRow );
void StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rListener );
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 3354a4984f20..1100d920f31e 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -3054,14 +3054,15 @@ void ScColumn::SetDirtyFromClip( SCROW nRow1, SCROW nRow2, sc::ColumnSpanSet& rB
aHdl.fillBroadcastSpans(rBroadcastSpans);
}
-void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2 )
+void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2, bool bBroadcast )
{
// broadcasts everything within the range, with FormulaTracking
sc::AutoCalcSwitch aSwitch(*pDocument, false);
SetDirtyOnRangeHandler aHdl(*this);
sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
- aHdl.broadcast();
+ if (bBroadcast)
+ aHdl.broadcast();
}
void ScColumn::SetTableOpDirty( const ScRange& rRange )
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index b0d1d50d8d46..0a437e70d8ba 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -1140,14 +1140,25 @@ bool ScColumn::HasFormulaCell( SCROW nRow1, SCROW nRow2 ) const
namespace {
-class StartListeningFromClipHandler
+void endListening( sc::EndListeningContext& rCxt, ScFormulaCell** pp, ScFormulaCell** ppEnd )
+{
+ for (; pp != ppEnd; ++pp)
+ {
+ ScFormulaCell& rFC = **pp;
+ rFC.EndListeningTo(rCxt);
+ }
+}
+
+class StartListeningFormulaCellsHandler
{
sc::StartListeningContext& mrStartCxt;
sc::EndListeningContext& mrEndCxt;
+ SCROW mnStartRow;
+ SCROW mnEndRow;
public:
- StartListeningFromClipHandler( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) :
- mrStartCxt(rStartCxt), mrEndCxt(rEndCxt) {}
+ StartListeningFormulaCellsHandler( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) :
+ mrStartCxt(rStartCxt), mrEndCxt(rEndCxt), mnStartRow(-1), mnEndRow(-1) {}
void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize )
{
@@ -1155,6 +1166,8 @@ public:
// We are only interested in formulas.
return;
+ mnStartRow = node.position + nOffset;
+
ScFormulaCell** ppBeg = &sc::formula_block::at(*node.data, nOffset);
ScFormulaCell** ppEnd = ppBeg + nDataSize;
@@ -1173,7 +1186,8 @@ public:
assert(static_cast<size_t>(nBackTrackSize) <= nOffset);
for (SCROW i = 0; i < nBackTrackSize; ++i)
--pp;
- endListening(pp, ppBeg);
+ endListening(mrEndCxt, pp, ppBeg);
+ mnStartRow -= nBackTrackSize;
}
}
@@ -1183,6 +1197,7 @@ public:
if (!pFC->IsSharedTop())
{
+ assert(!pFC->IsShared());
pFC->StartListeningTo(mrStartCxt);
continue;
}
@@ -1191,12 +1206,13 @@ public:
// extends beyond the range, in which case have the excess
// formula cells stop listening.
size_t nEndGroupPos = (pp - ppBeg) + pFC->GetSharedLength();
+ mnEndRow = node.position + nOffset + nEndGroupPos - 1; // absolute row position of the last one in the group.
if (nEndGroupPos > nDataSize)
{
size_t nExcessSize = nEndGroupPos - nDataSize;
ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength();
ScFormulaCell** ppGrp = ppGrpEnd - nExcessSize;
- endListening(ppGrp, ppGrpEnd);
+ endListening(mrEndCxt, ppGrp, ppGrpEnd);
// Register formula cells as a group.
sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt, pp);
@@ -1211,24 +1227,132 @@ public:
}
}
+ SCROW getStartRow() const
+ {
+ return mnStartRow;
+ }
+
+ SCROW getEndRow() const
+ {
+ return mnEndRow;
+ }
+
private:
- void endListening( ScFormulaCell** pp, ScFormulaCell** ppEnd )
+};
+
+class EndListeningFormulaCellsHandler
+{
+ sc::EndListeningContext& mrEndCxt;
+ SCROW mnStartRow;
+ SCROW mnEndRow;
+
+public:
+ EndListeningFormulaCellsHandler( sc::EndListeningContext& rEndCxt ) :
+ mrEndCxt(rEndCxt), mnStartRow(-1), mnEndRow(-1) {}
+
+ void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize )
{
+ if (node.type != sc::element_type_formula)
+ // We are only interested in formulas.
+ return;
+
+ mnStartRow = node.position + nOffset;
+
+ ScFormulaCell** ppBeg = &sc::formula_block::at(*node.data, nOffset);
+ ScFormulaCell** ppEnd = ppBeg + nDataSize;
+
+ ScFormulaCell** pp = ppBeg;
+
+ // If the first formula cell belongs to a group and it's not the top
+ // cell, move up to the top cell of the group.
+
+ ScFormulaCell* pFC = *pp;
+ if (pFC->IsShared() && !pFC->IsSharedTop())
+ {
+ SCROW nBackTrackSize = pFC->aPos.Row() - pFC->GetSharedTopRow();
+ if (nBackTrackSize > 0)
+ {
+ assert(static_cast<size_t>(nBackTrackSize) <= nOffset);
+ for (SCROW i = 0; i < nBackTrackSize; ++i)
+ --pp;
+ mnStartRow -= nBackTrackSize;
+ }
+ }
+
for (; pp != ppEnd; ++pp)
{
- ScFormulaCell& rFC = **pp;
- rFC.EndListeningTo(mrEndCxt);
+ pFC = *pp;
+
+ if (!pFC->IsSharedTop())
+ {
+ assert(!pFC->IsShared());
+ pFC->EndListeningTo(mrEndCxt);
+ continue;
+ }
+
+ size_t nEndGroupPos = (pp - ppBeg) + pFC->GetSharedLength();
+ mnEndRow = node.position + nOffset + nEndGroupPos - 1; // absolute row position of the last one in the group.
+
+ ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength();
+ endListening(mrEndCxt, pp, ppGrpEnd);
+
+ if (nEndGroupPos > nDataSize)
+ {
+ // The group goes beyond the specified end row. Move to the
+ // one before the end postion to finish the loop.
+ pp = ppEnd - 1;
+ }
+ else
+ {
+ // Move to the last one in the group.
+ pp += pFC->GetSharedLength() - 1;
+ }
}
}
+
+ SCROW getStartRow() const
+ {
+ return mnStartRow;
+ }
+
+ SCROW getEndRow() const
+ {
+ return mnEndRow;
+ }
};
}
-void ScColumn::StartListeningFromClip(
- sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, SCROW nRow1, SCROW nRow2 )
+void ScColumn::StartListeningFormulaCells(
+ sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt,
+ SCROW nRow1, SCROW nRow2, SCROW* pStartRow, SCROW* pEndRow )
{
- StartListeningFromClipHandler aFunc(rStartCxt, rEndCxt);
+ StartListeningFormulaCellsHandler aFunc(rStartCxt, rEndCxt);
sc::ProcessBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
+
+ if (pStartRow)
+ // start row position may be smaller than nRow1 in case the formula
+ // group starts before nRow1 position.
+ *pStartRow = aFunc.getStartRow();
+
+ if (pEndRow)
+ // row position of the last cell that started listening, which may be
+ // greater than nRow2 in case the formula group extends beyond nRow2.
+ *pEndRow = aFunc.getEndRow();
+}
+
+void ScColumn::EndListeningFormulaCells(
+ sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2,
+ SCROW* pStartRow, SCROW* pEndRow )
+{
+ EndListeningFormulaCellsHandler aFunc(rCxt);
+ sc::ProcessBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
+
+ if (pStartRow)
+ *pStartRow = aFunc.getStartRow();
+
+ if (pEndRow)
+ *pEndRow = aFunc.getEndRow();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 7e7507c51705..a00c5c372789 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1061,7 +1061,7 @@ void ScTable::StartListeningFromClip(
if (nRow2 > MAXROW) nRow2 = MAXROW;
if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
for (SCCOL i = nCol1; i <= nCol2; i++)
- aCol[i].StartListeningFromClip(rStartCxt, rEndCxt, nRow1, nRow2);
+ aCol[i].StartListeningFormulaCells(rStartCxt, rEndCxt, nRow1, nRow2);
}
void ScTable::CopyToTable(
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 3561a040920e..13a7baf84785 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -1130,6 +1130,10 @@ void ScTable::FillFormulaVertical(
SCCOLROW& rInner, SCCOL nCol, SCROW nRow1, SCROW nRow2,
ScProgress* pProgress, sal_uLong& rProgress )
{
+ // rInner is the row position when filling vertically. Also, when filling
+ // across hidden regions, it may create multiple dis-jointed spans of
+ // formula cells.
+
bool bHidden = false;
SCCOLROW nHiddenLast = -1;
@@ -1163,9 +1167,24 @@ void ScTable::FillFormulaVertical(
aSpans.push_back(sc::RowSpan(nRowStart, nRowEnd));
}
+ if (aSpans.empty())
+ return;
+
aCol[nCol].DeleteRanges(aSpans, IDF_CONTENTS, false);
- sc::StartListeningContext aCxt(*pDocument);
- aCol[nCol].CloneFormulaCell(rSrcCell, aSpans, &aCxt);
+ aCol[nCol].CloneFormulaCell(rSrcCell, aSpans, NULL);
+
+ boost::shared_ptr<sc::ColumnBlockPositionSet> pSet(new sc::ColumnBlockPositionSet(*pDocument));
+ sc::StartListeningContext aStartCxt(*pDocument, pSet);
+ sc::EndListeningContext aEndCxt(*pDocument, pSet);
+
+ SCROW nStartRow = aSpans.front().mnRow1;
+ SCROW nEndRow = aSpans.back().mnRow2;
+ aCol[nCol].EndListeningFormulaCells(aEndCxt, nStartRow, nEndRow, &nStartRow, &nEndRow);
+ aCol[nCol].StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow);
+
+ std::vector<sc::RowSpan>::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
+ for (; it != itEnd; ++it)
+ aCol[nCol].SetDirty(it->mnRow1, it->mnRow2, false);
rProgress += nRow2 - nRow1 + 1;
if (pProgress)
@@ -1424,6 +1443,13 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
bool bAttribs, ScProgress* pProgress )
{
+ // The term 'inner' here refers to the loop in the filling direction i.e.
+ // when filling vertically, the inner position is the row position whereas
+ // when filling horizontally the column position becomes the inner
+ // position. The term 'outer' refers to the column position when filling
+ // vertically, or the row positon when filling horizontally. The fill is
+ // performed once in each 'outer' position e.g. when filling vertically,
+ // we perform the fill once in each column.
// Detect direction
@@ -1450,13 +1476,15 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nOEnd = nCol2;
if (bPositive)
{
- nISource = nRow1;
- nIStart = nRow1 + 1;
+ // downward fill
+ nISource = nRow1; // top row of the source range.
+ nIStart = nRow1 + 1; // first row where we start filling.
nIEnd = nRow1 + nFillCount;
aFillRange = ScRange(nCol1, nRow1 + 1, nTab, nCol2, nRow1 + nFillCount, nTab);
}
else
{
+ // upward fill
nISource = nRow2;
nIStart = nRow2 - 1;
nIEnd = nRow2 - nFillCount;
@@ -1472,6 +1500,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nOEnd = nRow2;
if (bPositive)
{
+ // to the right
nISource = nCol1;
nIStart = nCol1 + 1;
nIEnd = nCol1 + nFillCount;
@@ -1479,6 +1508,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
else
{
+ // to the left
nISource = nCol2;
nIStart = nCol2 - 1;
nIEnd = nCol2 - nFillCount;
@@ -1504,7 +1534,8 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if (pProgress)
nProgress = pProgress->GetState();
- // execute
+ // Perform the fill once per each 'outer' position i.e. one per column
+ // when filling vertically.
sal_uLong nActFormCnt = 0;
for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)