Kaydet (Commit) b9b0ac00 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

Use group area listeners when filling down formula cells via fill series.

Change-Id: Ib0d4f542986dc09968cad8b76da9d6e034eddd37
üst c0c685d1
...@@ -255,9 +255,6 @@ public: ...@@ -255,9 +255,6 @@ public:
void CopyFromClip( void CopyFromClip(
sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn ); 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 ); void RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow );
// Selection (?) of this document // Selection (?) of this document
...@@ -353,7 +350,7 @@ public: ...@@ -353,7 +350,7 @@ public:
void SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt ); void SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt );
void SetDirtyFromClip( SCROW nRow1, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans ); 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 SetDirtyVar();
void SetDirtyAfterLoad(); void SetDirtyAfterLoad();
void SetTableOpDirty( const ScRange& ); void SetTableOpDirty( const ScRange& );
...@@ -485,6 +482,14 @@ public: ...@@ -485,6 +482,14 @@ public:
bool TestTabRefAbs(SCTAB nTable) const; bool TestTabRefAbs(SCTAB nTable) const;
bool GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) 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 StartListening( SvtListener& rLst, SCROW nRow );
void EndListening( SvtListener& rLst, SCROW nRow ); void EndListening( SvtListener& rLst, SCROW nRow );
void StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rListener ); void StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rListener );
......
...@@ -3028,14 +3028,15 @@ void ScColumn::SetDirtyFromClip( SCROW nRow1, SCROW nRow2, sc::ColumnSpanSet& rB ...@@ -3028,14 +3028,15 @@ void ScColumn::SetDirtyFromClip( SCROW nRow1, SCROW nRow2, sc::ColumnSpanSet& rB
aHdl.fillBroadcastSpans(rBroadcastSpans); 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 // broadcasts everything within the range, with FormulaTracking
sc::AutoCalcSwitch aSwitch(*pDocument, false); sc::AutoCalcSwitch aSwitch(*pDocument, false);
SetDirtyOnRangeHandler aHdl(*this); SetDirtyOnRangeHandler aHdl(*this);
sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl); sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
aHdl.broadcast(); if (bBroadcast)
aHdl.broadcast();
} }
void ScColumn::SetTableOpDirty( const ScRange& rRange ) void ScColumn::SetTableOpDirty( const ScRange& rRange )
......
...@@ -1140,14 +1140,25 @@ bool ScColumn::HasFormulaCell( SCROW nRow1, SCROW nRow2 ) const ...@@ -1140,14 +1140,25 @@ bool ScColumn::HasFormulaCell( SCROW nRow1, SCROW nRow2 ) const
namespace { 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::StartListeningContext& mrStartCxt;
sc::EndListeningContext& mrEndCxt; sc::EndListeningContext& mrEndCxt;
SCROW mnStartRow;
SCROW mnEndRow;
public: public:
StartListeningFromClipHandler( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) : StartListeningFormulaCellsHandler( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) :
mrStartCxt(rStartCxt), mrEndCxt(rEndCxt) {} mrStartCxt(rStartCxt), mrEndCxt(rEndCxt), mnStartRow(-1), mnEndRow(-1) {}
void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize ) void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize )
{ {
...@@ -1155,6 +1166,8 @@ public: ...@@ -1155,6 +1166,8 @@ public:
// We are only interested in formulas. // We are only interested in formulas.
return; return;
mnStartRow = node.position + nOffset;
ScFormulaCell** ppBeg = &sc::formula_block::at(*node.data, nOffset); ScFormulaCell** ppBeg = &sc::formula_block::at(*node.data, nOffset);
ScFormulaCell** ppEnd = ppBeg + nDataSize; ScFormulaCell** ppEnd = ppBeg + nDataSize;
...@@ -1173,7 +1186,8 @@ public: ...@@ -1173,7 +1186,8 @@ public:
assert(static_cast<size_t>(nBackTrackSize) <= nOffset); assert(static_cast<size_t>(nBackTrackSize) <= nOffset);
for (SCROW i = 0; i < nBackTrackSize; ++i) for (SCROW i = 0; i < nBackTrackSize; ++i)
--pp; --pp;
endListening(pp, ppBeg); endListening(mrEndCxt, pp, ppBeg);
mnStartRow -= nBackTrackSize;
} }
} }
...@@ -1183,6 +1197,7 @@ public: ...@@ -1183,6 +1197,7 @@ public:
if (!pFC->IsSharedTop()) if (!pFC->IsSharedTop())
{ {
assert(!pFC->IsShared());
pFC->StartListeningTo(mrStartCxt); pFC->StartListeningTo(mrStartCxt);
continue; continue;
} }
...@@ -1191,12 +1206,13 @@ public: ...@@ -1191,12 +1206,13 @@ public:
// extends beyond the range, in which case have the excess // extends beyond the range, in which case have the excess
// formula cells stop listening. // formula cells stop listening.
size_t nEndGroupPos = (pp - ppBeg) + pFC->GetSharedLength(); 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) if (nEndGroupPos > nDataSize)
{ {
size_t nExcessSize = nEndGroupPos - nDataSize; size_t nExcessSize = nEndGroupPos - nDataSize;
ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength(); ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength();
ScFormulaCell** ppGrp = ppGrpEnd - nExcessSize; ScFormulaCell** ppGrp = ppGrpEnd - nExcessSize;
endListening(ppGrp, ppGrpEnd); endListening(mrEndCxt, ppGrp, ppGrpEnd);
// Register formula cells as a group. // Register formula cells as a group.
sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt, pp); sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt, pp);
...@@ -1211,24 +1227,132 @@ public: ...@@ -1211,24 +1227,132 @@ public:
} }
} }
SCROW getStartRow() const
{
return mnStartRow;
}
SCROW getEndRow() const
{
return mnEndRow;
}
private: 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) for (; pp != ppEnd; ++pp)
{ {
ScFormulaCell& rFC = **pp; pFC = *pp;
rFC.EndListeningTo(mrEndCxt);
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( void ScColumn::StartListeningFormulaCells(
sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, SCROW nRow1, SCROW nRow2 ) 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); 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: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -1061,7 +1061,7 @@ void ScTable::StartListeningFromClip( ...@@ -1061,7 +1061,7 @@ void ScTable::StartListeningFromClip(
if (nRow2 > MAXROW) nRow2 = MAXROW; if (nRow2 > MAXROW) nRow2 = MAXROW;
if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2)) if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
for (SCCOL i = nCol1; i <= nCol2; i++) for (SCCOL i = nCol1; i <= nCol2; i++)
aCol[i].StartListeningFromClip(rStartCxt, rEndCxt, nRow1, nRow2); aCol[i].StartListeningFormulaCells(rStartCxt, rEndCxt, nRow1, nRow2);
} }
void ScTable::CopyToTable( void ScTable::CopyToTable(
......
...@@ -1130,6 +1130,10 @@ void ScTable::FillFormulaVertical( ...@@ -1130,6 +1130,10 @@ void ScTable::FillFormulaVertical(
SCCOLROW& rInner, SCCOL nCol, SCROW nRow1, SCROW nRow2, SCCOLROW& rInner, SCCOL nCol, SCROW nRow1, SCROW nRow2,
ScProgress* pProgress, sal_uLong& rProgress ) 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; bool bHidden = false;
SCCOLROW nHiddenLast = -1; SCCOLROW nHiddenLast = -1;
...@@ -1163,9 +1167,24 @@ void ScTable::FillFormulaVertical( ...@@ -1163,9 +1167,24 @@ void ScTable::FillFormulaVertical(
aSpans.push_back(sc::RowSpan(nRowStart, nRowEnd)); aSpans.push_back(sc::RowSpan(nRowStart, nRowEnd));
} }
if (aSpans.empty())
return;
aCol[nCol].DeleteRanges(aSpans, IDF_CONTENTS, false); aCol[nCol].DeleteRanges(aSpans, IDF_CONTENTS, false);
sc::StartListeningContext aCxt(*pDocument); aCol[nCol].CloneFormulaCell(rSrcCell, aSpans, NULL);
aCol[nCol].CloneFormulaCell(rSrcCell, aSpans, &aCxt);
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; rProgress += nRow2 - nRow1 + 1;
if (pProgress) if (pProgress)
...@@ -1424,6 +1443,13 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ...@@ -1424,6 +1443,13 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits, double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
bool bAttribs, ScProgress* pProgress ) 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 // Detect direction
...@@ -1450,13 +1476,15 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ...@@ -1450,13 +1476,15 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nOEnd = nCol2; nOEnd = nCol2;
if (bPositive) if (bPositive)
{ {
nISource = nRow1; // downward fill
nIStart = nRow1 + 1; nISource = nRow1; // top row of the source range.
nIStart = nRow1 + 1; // first row where we start filling.
nIEnd = nRow1 + nFillCount; nIEnd = nRow1 + nFillCount;
aFillRange = ScRange(nCol1, nRow1 + 1, nTab, nCol2, nRow1 + nFillCount, nTab); aFillRange = ScRange(nCol1, nRow1 + 1, nTab, nCol2, nRow1 + nFillCount, nTab);
} }
else else
{ {
// upward fill
nISource = nRow2; nISource = nRow2;
nIStart = nRow2 - 1; nIStart = nRow2 - 1;
nIEnd = nRow2 - nFillCount; nIEnd = nRow2 - nFillCount;
...@@ -1472,6 +1500,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ...@@ -1472,6 +1500,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nOEnd = nRow2; nOEnd = nRow2;
if (bPositive) if (bPositive)
{ {
// to the right
nISource = nCol1; nISource = nCol1;
nIStart = nCol1 + 1; nIStart = nCol1 + 1;
nIEnd = nCol1 + nFillCount; nIEnd = nCol1 + nFillCount;
...@@ -1479,6 +1508,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ...@@ -1479,6 +1508,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
} }
else else
{ {
// to the left
nISource = nCol2; nISource = nCol2;
nIStart = nCol2 - 1; nIStart = nCol2 - 1;
nIEnd = nCol2 - nFillCount; nIEnd = nCol2 - nFillCount;
...@@ -1504,7 +1534,8 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ...@@ -1504,7 +1534,8 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if (pProgress) if (pProgress)
nProgress = pProgress->GetState(); nProgress = pProgress->GetState();
// execute // Perform the fill once per each 'outer' position i.e. one per column
// when filling vertically.
sal_uLong nActFormCnt = 0; sal_uLong nActFormCnt = 0;
for (rOuter = nOStart; rOuter <= nOEnd; rOuter++) for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment