summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-11-14 21:51:39 -0500
committerKohei Yoshida <kohei.yoshida@collabora.com>2014-11-14 21:51:39 -0500
commiteee4f852e112acabbe1117caa88825497c13ec24 (patch)
treeb120205f9334719faaf9b5768089c5e17b21205a
parente8184b4bda4f8ce0bfa676d592e1f493ca9e3eeb (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
-rw-r--r--sc/inc/address.hxx3
-rw-r--r--sc/source/core/data/bcaslot.cxx100
-rw-r--r--sc/source/core/data/documen7.cxx62
-rw-r--r--sc/source/core/data/document.cxx10
-rw-r--r--sc/source/core/inc/bcaslot.hxx2
-rw-r--r--sc/source/core/tool/address.cxx15
6 files changed, 178 insertions, 14 deletions
diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index 7fcdee159da9..527cba2447c2 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 57d2b26b63ae..8e55be73447b 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 c8c8f185125b..c03a190d7744 100644
--- a/sc/source/core/tool/address.cxx
+++ b/sc/source/core/tool/address.cxx
@@ -1373,6 +1373,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();