diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-03-15 11:14:24 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-03-15 11:48:18 -0400 |
commit | 8b368d808e90561a9b34658e6b811a8fad83088f (patch) | |
tree | 7be36455e9f68310059d9181a77e553de0ad5134 /sc | |
parent | 3ced80133a171bc528ed4600f1d00daadfdbb21b (diff) |
Unregister all listeners first then re-register them.
It's safe this way in case we are transferring them within the same
column. Any empty broadcasters are checked and purged at the end.
Change-Id: Ib2d46e616cde4923720ad21cb101d3a97dc8c5d9
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/listenercontext.hxx | 12 | ||||
-rw-r--r-- | sc/source/core/data/column.cxx | 134 | ||||
-rw-r--r-- | sc/source/core/data/listenercontext.cxx | 44 |
3 files changed, 134 insertions, 56 deletions
diff --git a/sc/inc/listenercontext.hxx b/sc/inc/listenercontext.hxx index c0260ef8be1a..501f1d2023fd 100644 --- a/sc/inc/listenercontext.hxx +++ b/sc/inc/listenercontext.hxx @@ -58,6 +58,18 @@ public: void purgeEmptyBroadcasters(); }; +class PurgeListenerAction : public ColumnSpanSet::Action, boost::noncopyable +{ + ScDocument& mrDoc; + boost::scoped_ptr<ColumnBlockPosition> mpBlockPos; + +public: + PurgeListenerAction( ScDocument& rDoc ); + + virtual void startColumn( SCTAB nTab, SCCOL nCol ); + virtual void execute( const ScAddress& rPos, SCROW nLength, bool bVal ); +}; + } #endif diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 8b6aa9d0d8e4..9694790886f7 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -3478,27 +3478,113 @@ namespace { class TransferListenersHandler { - sc::BroadcasterStoreType& mrDestBroadcasters; - sc::BroadcasterStoreType::iterator miDestPos; - SCROW mnRowDelta; /// Add this to the source row to get the destination row. - public: - TransferListenersHandler( sc::BroadcasterStoreType& rDestBrd, SCROW nRowDelta ) : - mrDestBroadcasters(rDestBrd), miDestPos(rDestBrd.begin()), mnRowDelta(nRowDelta) {} + typedef std::vector<SvtListener*> ListenersType; + struct Entry + { + size_t mnRow; + ListenersType maListeners; + }; + typedef std::vector<Entry> ListenerListType; + + void swapListeners( std::vector<Entry>& rListenerList ) + { + maListenerList.swap(rListenerList); + } void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster ) { assert(pBroadcaster); - SvtBroadcaster::ListenersType& rLis = pBroadcaster->GetAllListeners(); - if (rLis.empty()) + // It's important to make a copy here. + SvtBroadcaster::ListenersType aLis = pBroadcaster->GetAllListeners(); + if (aLis.empty()) // No listeners to transfer. return; - SCROW nDestRow = nRow + mnRowDelta; + Entry aEntry; + aEntry.mnRow = nRow; + + SvtBroadcaster::ListenersType::iterator it = aLis.begin(), itEnd = aLis.end(); + for (; it != itEnd; ++it) + { + SvtListener* pLis = *it; + pLis->EndListening(*pBroadcaster); + aEntry.maListeners.push_back(pLis); + } + + maListenerList.push_back(aEntry); + + // At this point, the source broadcaster should have no more listeners. + assert(!pBroadcaster->HasListeners()); + } + +private: + ListenerListType maListenerList; +}; + +class RemoveEmptyBroadcasterHandler +{ + sc::ColumnSpanSet maSet; + ScDocument& mrDoc; + SCCOL mnCol; + SCTAB mnTab; + +public: + RemoveEmptyBroadcasterHandler( ScDocument& rDoc, SCCOL nCol, SCTAB nTab ) : + maSet(false), mrDoc(rDoc), mnCol(nCol), mnTab(nTab) {} + + void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster ) + { + if (!pBroadcaster->HasListeners()) + maSet.set(mnTab, mnCol, nRow, true); + } + + void purge() + { + sc::PurgeListenerAction aAction(mrDoc); + maSet.executeAction(aAction); + } +}; + +} + +void ScColumn::TransferListeners( + ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta ) +{ + if (nRow2 < nRow1) + return; + + if (!ValidRow(nRow1) || !ValidRow(nRow2)) + return; - sc::BroadcasterStoreType::position_type aPos = mrDestBroadcasters.position(miDestPos, nDestRow); - miDestPos = aPos.first; + if (nRowDelta <= 0 && !ValidRow(nRow1+nRowDelta)) + return; + + if (nRowDelta >= 0 && !ValidRow(nRow2+nRowDelta)) + return; + + // Collect all listeners from the source broadcasters. The listeners will + // be removed from their broadcasters as they are collected. + TransferListenersHandler aFunc; + sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc); + + TransferListenersHandler::ListenerListType aListenerList; + aFunc.swapListeners(aListenerList); + + // Re-register listeners with their destination broadcasters. + sc::BroadcasterStoreType::iterator itDestPos = rDestCol.maBroadcasters.begin(); + TransferListenersHandler::ListenerListType::iterator it = aListenerList.begin(), itEnd = aListenerList.end(); + for (; it != itEnd; ++it) + { + TransferListenersHandler::Entry& rEntry = *it; + + SCROW nDestRow = rEntry.mnRow + nRowDelta; + + sc::BroadcasterStoreType::position_type aPos = + rDestCol.maBroadcasters.position(itDestPos, nDestRow); + + itDestPos = aPos.first; SvtBroadcaster* pDestBrd = NULL; if (aPos.first->type == sc::element_type_broadcaster) { @@ -3510,32 +3596,22 @@ public: // No existing broadcaster. Create a new one. assert(aPos.first->type == sc::element_type_empty); pDestBrd = new SvtBroadcaster; - miDestPos = mrDestBroadcasters.set(miDestPos, nDestRow, pDestBrd); + itDestPos = rDestCol.maBroadcasters.set(itDestPos, nDestRow, pDestBrd); } // Transfer all listeners from the source to the destination. - SvtBroadcaster::ListenersType::iterator it = rLis.begin(), itEnd = rLis.end(); - for (; it != itEnd; ++it) + SvtBroadcaster::ListenersType::iterator it2 = rEntry.maListeners.begin(), it2End = rEntry.maListeners.end(); + for (; it2 != it2End; ++it2) { - SvtListener* pLis = *it; - pLis->EndListening(*pBroadcaster); + SvtListener* pLis = *it2; pLis->StartListening(*pDestBrd); } - - // At this point, the source broadcaster should have no more listeners. - assert(!pBroadcaster->HasListeners()); } -}; - -} - -void ScColumn::TransferListeners( - ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta ) -{ - TransferListenersHandler aFunc(rDestCol.maBroadcasters, nRowDelta); - sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc); - maBroadcasters.set_empty(nRow1, nRow2); // Remove all source broadcaster. + // Remove any broadcasters that have no listeners. + RemoveEmptyBroadcasterHandler aFuncRemoveEmpty(*pDocument, nCol, nTab); + sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFuncRemoveEmpty); + aFuncRemoveEmpty.purge(); } void ScColumn::CalcAll() diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx index 3dfe5edb0b37..add75a25a0e7 100644 --- a/sc/source/core/data/listenercontext.cxx +++ b/sc/source/core/data/listenercontext.cxx @@ -13,32 +13,6 @@ namespace sc { -namespace { - -class PurgeAction : public ColumnSpanSet::Action -{ - ScDocument& mrDoc; - sc::ColumnBlockPosition maBlockPos; - -public: - PurgeAction(ScDocument& rDoc) : mrDoc(rDoc) {} - - virtual void startColumn(SCTAB nTab, SCCOL nCol) - { - mrDoc.InitColumnBlockPosition(maBlockPos, nTab, nCol); - } - - virtual void execute(const ScAddress& rPos, SCROW nLength, bool bVal) - { - if (bVal) - { - mrDoc.DeleteBroadcasters(maBlockPos, rPos, nLength); - } - }; -}; - -} - StartListeningContext::StartListeningContext(ScDocument& rDoc) : mrDoc(rDoc), mpSet(new ColumnBlockPositionSet(rDoc)) {} @@ -92,10 +66,26 @@ void EndListeningContext::addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SC void EndListeningContext::purgeEmptyBroadcasters() { - PurgeAction aAction(mrDoc); + PurgeListenerAction aAction(mrDoc); maSet.executeAction(aAction); } +PurgeListenerAction::PurgeListenerAction(ScDocument& rDoc) : + mrDoc(rDoc), mpBlockPos(new ColumnBlockPosition) {} + +void PurgeListenerAction::startColumn( SCTAB nTab, SCCOL nCol ) +{ + mrDoc.InitColumnBlockPosition(*mpBlockPos, nTab, nCol); +} + +void PurgeListenerAction::execute( const ScAddress& rPos, SCROW nLength, bool bVal ) +{ + if (bVal) + { + mrDoc.DeleteBroadcasters(*mpBlockPos, rPos, nLength); + } +}; + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |