diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-11-14 21:51:39 -0500 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-11-18 08:31:56 -0500 |
commit | 34c8c0bb878be82a25cdaf1d7e623843f00fed6c (patch) | |
tree | e1f86eac1ee8147a452127c43b37ab2964f9e5e7 /sc | |
parent | c55a5b242585824d3c6c217f813dc9acfc3228b2 (diff) |
Send broadcast range to the area broadcast slot machine.
Rather than iterating through cells in the range and broadcasting by
cells individually. This way we can take advantage of the new group
based area listeners and it's much faster this way.
Change-Id: I8a4b49bce69d89b5b4698790befe4390871c755d
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/address.hxx | 3 | ||||
-rw-r--r-- | sc/source/core/data/bcaslot.cxx | 100 | ||||
-rw-r--r-- | sc/source/core/data/documen7.cxx | 62 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 10 | ||||
-rw-r--r-- | sc/source/core/inc/bcaslot.hxx | 2 | ||||
-rw-r--r-- | sc/source/core/tool/address.cxx | 15 |
6 files changed, 178 insertions, 14 deletions
diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx index 07ebe02c2537..bf4132821404 100644 --- a/sc/inc/address.hxx +++ b/sc/inc/address.hxx @@ -563,6 +563,9 @@ public: SC_DLLPUBLIC void Justify(); SC_DLLPUBLIC void ExtendTo( const ScRange& rRange ); SC_DLLPUBLIC bool Intersects( const ScRange& rRange ) const; // do two ranges intersect? + + ScRange Union( const ScRange& rOther ) const; + void PutInOrder(); inline bool operator==( const ScRange& rRange ) const; inline bool operator!=( const ScRange& rRange ) const; diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx index 9af7c19e2304..ee6f17ae7cfd 100644 --- a/sc/source/core/data/bcaslot.cxx +++ b/sc/source/core/data/bcaslot.cxx @@ -258,6 +258,83 @@ ScBroadcastAreas::const_iterator ScBroadcastAreaSlot::FindBroadcastArea( return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea); } +namespace { + +void broadcastRangeByCell( SvtBroadcaster& rBC, const ScRange& rRange, sal_uLong nHint ) +{ + ScHint aHint(nHint, ScAddress()); + ScAddress& rPos = aHint.GetAddress(); + for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab) + { + rPos.SetTab(nTab); + for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol) + { + rPos.SetCol(nCol); + for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow) + { + rPos.SetRow(nRow); + rBC.Broadcast(aHint); + } + } + } +} + +} + +bool ScBroadcastAreaSlot::AreaBroadcast( const ScRange& rRange, sal_uLong nHint ) +{ + if (aBroadcastAreaTbl.empty()) + return false; + + bool bInBroadcast = mbInBroadcastIteration; + mbInBroadcastIteration = true; + bool bIsBroadcasted = false; + + mbHasErasedArea = false; + + for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()), + aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter ) + { + if (mbHasErasedArea && isMarkedErased( aIter)) + continue; + + ScBroadcastArea* pArea = (*aIter).mpArea; + const ScRange& rAreaRange = pArea->GetRange(); + + // Take the union of the area range and the broadcast range. + ScRange aUnion = rAreaRange.Union(rRange); + if (!aUnion.IsValid()) + continue; + + if (pArea->IsGroupListening()) + { + if (pBASM->IsInBulkBroadcast()) + { + pBASM->InsertBulkGroupArea(pArea, aUnion); + } + else + { + broadcastRangeByCell(pArea->GetBroadcaster(), aUnion, nHint); + bIsBroadcasted = true; + } + } + else if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea)) + { + broadcastRangeByCell(pArea->GetBroadcaster(), aUnion, nHint); + bIsBroadcasted = true; + } + } + + mbInBroadcastIteration = bInBroadcast; + + // A Notify() during broadcast may call EndListeningArea() and thus dispose + // an area if it was the last listener, which would invalidate an iterator + // pointing to it, hence the real erase is done afterwards. + FinallyEraseAreas(); + + return bIsBroadcasted; +} + bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) { if (aBroadcastAreaTbl.empty()) @@ -758,6 +835,29 @@ void ScBroadcastAreaSlotMachine::EndListeningArea( } } +bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScRange& rRange, sal_uLong nHint ) +{ + bool bBroadcasted = false; + SCTAB nEndTab = rRange.aEnd.Tab(); + for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab())); + iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab) + { + ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots(); + SCSIZE nStart, nEnd, nRowBreak; + ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak ); + SCSIZE nOff = nStart; + SCSIZE nBreak = nOff + nRowBreak; + ScBroadcastAreaSlot** pp = ppSlots + nOff; + while ( nOff <= nEnd ) + { + if ( *pp ) + bBroadcasted |= (*pp)->AreaBroadcast( rRange, nHint ); + ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak); + } + } + return bBroadcasted; +} + bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const { const ScAddress& rAddress = rHint.GetAddress(); diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx index 5ea4ce59f338..b7bdf3070a48 100644 --- a/sc/source/core/data/documen7.cxx +++ b/sc/source/core/data/documen7.cxx @@ -100,24 +100,72 @@ void ScDocument::BroadcastCells( const ScRange& rRange, sal_uLong nHint ) { ClearFormulaContext(); - ScBulkBroadcast aBulkBroadcast(pBASM); + if (!pBASM) + return; // Clipboard or Undo + + SCTAB nTab1 = rRange.aStart.Tab(); + SCTAB nTab2 = rRange.aEnd.Tab(); + SCROW nRow1 = rRange.aStart.Row(); + SCROW nRow2 = rRange.aEnd.Row(); + SCCOL nCol1 = rRange.aStart.Col(); + SCCOL nCol2 = rRange.aEnd.Col(); ScHint aHint(nHint, ScAddress()); ScAddress& rPos = aHint.GetAddress(); - for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab) + + if (!bHardRecalcState) { - rPos.SetTab(nTab); - for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol) + ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast + bool bIsBroadcasted = false; + + for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab) { - rPos.SetCol(nCol); - for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow) + rPos.SetTab(nTab); + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) { rPos.SetRow(nRow); - Broadcast(aHint); + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + rPos.SetCol(nCol); + SvtBroadcaster* pBC = GetBroadcaster(rPos); + if (pBC) + { + pBC->Broadcast(aHint); + bIsBroadcasted = true; + } + } + } + } + + if (pBASM->AreaBroadcast(rRange, nHint) || bIsBroadcasted) + TrackFormulas(nHint); + } + + // Repaint fuer bedingte Formate mit relativen Referenzen: + for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab) + { + ScTable* pTab = FetchTable(nTab); + if (!pTab) + continue; + + ScConditionalFormatList* pCondFormList = GetCondFormList(nTab); + if (pCondFormList) + { + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + pCondFormList->SourceChanged(ScAddress(nCol,nRow,nTab)); } } } + for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab) + { + ScTable* pTab = FetchTable(nTab); + if (pTab) + pTab->SetStreamValid(false); + } + BroadcastUno(SfxSimpleHint(SC_HINT_DATACHANGED)); } diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 2b6219284d4f..8b5821719008 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -2590,7 +2590,6 @@ class BroadcastAction : public sc::ColumnSpanSet::ColumnAction { ScDocument& mrDoc; ScColumn* mpCol; - std::vector<SCROW> maRows; public: BroadcastAction( ScDocument& rDoc ) : mrDoc(rDoc), mpCol(NULL) {} @@ -2606,12 +2605,9 @@ public: return; assert(mpCol); - maRows.clear(); - maRows.reserve(nRow2-nRow1+1); - for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) - maRows.push_back(nRow); - - mpCol->BroadcastCells(maRows, SC_HINT_DATACHANGED); + ScRange aRange(mpCol->GetCol(), nRow1, mpCol->GetTab()); + aRange.aEnd.SetRow(nRow2); + mrDoc.BroadcastCells(aRange, SC_HINT_DATACHANGED); }; }; diff --git a/sc/source/core/inc/bcaslot.hxx b/sc/source/core/inc/bcaslot.hxx index bf9890834cf7..27c87f8157da 100644 --- a/sc/source/core/inc/bcaslot.hxx +++ b/sc/source/core/inc/bcaslot.hxx @@ -211,6 +211,7 @@ public: void EndListeningArea( const ScRange& rRange, bool bGroupListening, SvtListener* pListener, ScBroadcastArea*& rpArea ); + bool AreaBroadcast( const ScRange& rRange, sal_uLong nHint ); bool AreaBroadcast( const ScHint& rHint ); /// @return true if at least one broadcast occurred. bool AreaBroadcastInRange( const ScRange& rRange, @@ -312,6 +313,7 @@ public: void EndListeningArea( const ScRange& rRange, bool bGroupListening, SvtListener* pListener ); + bool AreaBroadcast( const ScRange& rRange, sal_uLong nHint ); bool AreaBroadcast( const ScHint& rHint ) const; // return: at least one broadcast occurred bool AreaBroadcastInRange( const ScRange& rRange, const ScHint& rHint ) const; diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx index 6ed9449afcf7..7cb29351e1f2 100644 --- a/sc/source/core/tool/address.cxx +++ b/sc/source/core/tool/address.cxx @@ -1374,6 +1374,21 @@ bool ScRange::Intersects( const ScRange& rRange ) const ); } +ScRange ScRange::Union( const ScRange& rOther ) const +{ + SCCOL nCol1 = std::max(aStart.Col(), rOther.aStart.Col()); + SCCOL nCol2 = std::min(aEnd.Col(), rOther.aEnd.Col()); + SCROW nRow1 = std::max(aStart.Row(), rOther.aStart.Row()); + SCROW nRow2 = std::min(aEnd.Row(), rOther.aEnd.Row()); + SCTAB nTab1 = std::max(aStart.Tab(), rOther.aStart.Tab()); + SCTAB nTab2 = std::min(aEnd.Tab(), rOther.aEnd.Tab()); + + if (nCol1 > nCol2 || nRow1 > nRow2 || nTab1 > nTab2) + return ScRange(ScAddress::INITIALIZE_INVALID); + + return ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); +} + void ScRange::PutInOrder() { SCCOL nCol1 = aStart.Col(), nCol2 = aEnd.Col(); |