From dc3a21333fc9c0f98385ccc54035512c5a73dac9 Mon Sep 17 00:00:00 2001 From: Kohei Yoshida Date: Mon, 17 Nov 2014 17:37:07 -0500 Subject: Use group-area listeners during copy & paste if we can. This should reduce the number of area listeners generated esp. when replicating tons of formula cells down the column. Change-Id: I1ea8f51f667e6b0e1a646f84d79f5e8430b478d5 --- sc/inc/column.hxx | 3 +- sc/inc/table.hxx | 3 +- sc/source/core/data/column3.cxx | 22 --------- sc/source/core/data/column4.cxx | 93 +++++++++++++++++++++++++++++++++++++ sc/source/core/data/document.cxx | 9 +++- sc/source/core/data/formulacell.cxx | 6 +++ sc/source/core/data/table2.cxx | 5 +- 7 files changed, 113 insertions(+), 28 deletions(-) diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 86dbd39fd14f..6d8b09199582 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -255,7 +255,8 @@ public: void CopyFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn ); - void StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 ); + void StartListeningInArea( + sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, SCROW nRow1, SCROW nRow2 ); void RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow ); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index ea1e2a30ea26..b1e06e102f28 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -437,7 +437,8 @@ public: SCsCOL nDx, SCsROW nDy, ScTable* pTable ); void StartListeningInArea( - sc::StartListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); + sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, + SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); void SetDirtyFromClip( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans ); diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 73c031102b28..b2a115ff6031 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -1535,28 +1535,6 @@ void ScColumn::StartNeededListeners() namespace { -class StartListeningInAreaHandler -{ - sc::StartListeningContext& mrCxt; -public: - StartListeningInAreaHandler(sc::StartListeningContext& rCxt) : mrCxt(rCxt) {} - - void operator() (size_t /*nRow*/, ScFormulaCell* p) - { - p->StartListeningTo(mrCxt); - } -}; - -} - -void ScColumn::StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 ) -{ - StartListeningInAreaHandler aFunc(rCxt); - sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc); -} - -namespace { - void applyTextNumFormat( ScColumn& rCol, SCROW nRow, SvNumberFormatter* pFormatter ) { sal_uInt32 nFormat = pFormatter->GetStandardFormat(NUMBERFORMAT_TEXT); diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx index f0d28eb82dd5..925bb4cabb56 100644 --- a/sc/source/core/data/column4.cxx +++ b/sc/source/core/data/column4.cxx @@ -1135,4 +1135,97 @@ bool ScColumn::HasFormulaCell( SCROW nRow1, SCROW nRow2 ) const return aRet.first != maCells.end(); } +namespace { + +class StartListeningInAreaHandler +{ + sc::StartListeningContext& mrStartCxt; + sc::EndListeningContext& mrEndCxt; + +public: + StartListeningInAreaHandler( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) : + mrStartCxt(rStartCxt), mrEndCxt(rEndCxt) {} + + 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; + + 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, and have all the extra + // formula cells stop listening. + + ScFormulaCell* pFC = *pp; + if (pFC->IsShared() && !pFC->IsSharedTop()) + { + SCROW nBackTrackSize = pFC->aPos.Row() - pFC->GetSharedTopRow(); + if (nBackTrackSize > 0) + { + assert(static_cast(nBackTrackSize) <= nOffset); + for (SCROW i = 0; i < nBackTrackSize; ++i) + --pp; + endListening(pp, ppBeg); + } + } + + for (; pp != ppEnd; ++pp) + { + pFC = *pp; + + if (!pFC->IsSharedTop()) + { + pFC->StartListeningTo(mrStartCxt); + continue; + } + + // If This is the last group in the range, see if the group + // extends beyond the range, in which case have the excess + // formula cells stop listening. + size_t nEndGroupPos = (pp - ppBeg) + pFC->GetSharedLength(); + if (nEndGroupPos > nDataSize) + { + size_t nExcessSize = nEndGroupPos - nDataSize; + ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength(); + ScFormulaCell** ppGrp = ppGrpEnd - nExcessSize; + endListening(ppGrp, ppGrpEnd); + + // Register formula cells as a group. + sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt, pp); + pp = ppEnd - 1; // Move to the one before the end position. + } + else + { + // Register formula cells as a group. + sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt, pp); + pp += pFC->GetSharedLength() - 1; // Move to the last one in the group. + } + } + } + +private: + void endListening( ScFormulaCell** pp, ScFormulaCell** ppEnd ) + { + for (; pp != ppEnd; ++pp) + { + ScFormulaCell& rFC = **pp; + rFC.EndListeningTo(mrEndCxt); + } + } +}; + +} + +void ScColumn::StartListeningInArea( + sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, SCROW nRow1, SCROW nRow2 ) +{ + StartListeningInAreaHandler aFunc(rStartCxt, rEndCxt); + sc::ProcessBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index abfe1b0bbeba..77e57aaad333 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -2420,12 +2420,17 @@ void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1, { if (nInsFlag & IDF_CONTENTS) { - sc::StartListeningContext aCxt(*this); + boost::shared_ptr pSet( + new sc::ColumnBlockPositionSet(*this)); + + sc::StartListeningContext aStartCxt(*this, pSet); + sc::EndListeningContext aEndCxt(*this, pSet, NULL); + SCTAB nMax = static_cast(maTabs.size()); ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end(); for (; itr != itrEnd && *itr < nMax; ++itr) if (maTabs[*itr]) - maTabs[*itr]->StartListeningInArea(aCxt, nCol1, nRow1, nCol2, nRow2); + maTabs[*itr]->StartListeningInArea(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2); } } diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 0a2226f52ba0..ea08c1a91f83 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -3941,6 +3941,9 @@ void ScFormulaCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr, if (pDoc->IsClipOrUndo() || IsInChangeTrack()) return; + if (!HasBroadcaster()) + return; + pDoc->SetDetectiveDirty(true); // It has changed something if ( GetCode()->IsRecalcModeAlways() ) @@ -3983,6 +3986,9 @@ void ScFormulaCell::EndListeningTo( sc::EndListeningContext& rCxt ) if (rCxt.getDoc().IsClipOrUndo() || IsInChangeTrack()) return; + if (!HasBroadcaster()) + return; + ScDocument& rDoc = rCxt.getDoc(); rDoc.SetDetectiveDirty(true); // It has changed something diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 8a27333ba240..b6f1441898c1 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -1060,13 +1060,14 @@ void ScTable::SetDirtyFromClip( } void ScTable::StartListeningInArea( - sc::StartListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) + sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, + SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) { if (nCol2 > MAXCOL) nCol2 = MAXCOL; if (nRow2 > MAXROW) nRow2 = MAXROW; if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2)) for (SCCOL i = nCol1; i <= nCol2; i++) - aCol[i].StartListeningInArea(rCxt, nRow1, nRow2); + aCol[i].StartListeningInArea(rStartCxt, rEndCxt, nRow1, nRow2); } void ScTable::CopyToTable( -- cgit