summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-03-14 23:15:32 -0400
committerAndras Timar <andras.timar@collabora.com>2014-03-17 13:42:40 +0000
commitb85f07986dc005ea0a74baa3d14ee0fd1ec99609 (patch)
treea76e58b024d05e3363f2d31d6c86bfd3c1732839
parentdde6049fe4abc03b8f98ffca1a940d6f2f446095 (diff)
fdo#71491: Adjust reference during undo of drag-n-drop of cell range.
Also with this commit, the signature of SvtListener::Notify() changes, by dropping the first argument which nobody uses. This change was necessary in order to call it directly without needing to pass any broadcaster instance. (cherry picked from commit 88955714d345d8584e86ae34bf5f5d1f3f4af9f7) (cherry picked from commit 99809b246c5dd2be548668032fac4f3c65fb962a) (cherry picked from commit 8b368d808e90561a9b34658e6b811a8fad83088f) (cherry picked from commit 83ee6b640eaf86f9aef6f42a4dd9c8a930cf9135) Conflicts: sc/inc/table.hxx sc/source/core/data/table2.cxx sc/source/ui/undo/undoblk.cxx svl/source/notify/broadcast.cxx Change-Id: I6a1e97f0fb1e070d1d8f7db614690b04c9e8024e Reviewed-on: https://gerrit.libreoffice.org/8600 Reviewed-by: Andras Timar <andras.timar@collabora.com> Tested-by: Andras Timar <andras.timar@collabora.com>
-rw-r--r--include/svl/listener.hxx2
-rw-r--r--sc/Library_sc.mk1
-rw-r--r--sc/inc/brdcst.hxx6
-rw-r--r--sc/inc/cellsuno.hxx2
-rw-r--r--sc/inc/chartlis.hxx2
-rw-r--r--sc/inc/column.hxx3
-rw-r--r--sc/inc/document.hxx2
-rw-r--r--sc/inc/formulacell.hxx2
-rw-r--r--sc/inc/listenercontext.hxx12
-rw-r--r--sc/inc/lookupcache.hxx2
-rw-r--r--sc/inc/mtvcellfunc.hxx10
-rw-r--r--sc/inc/refhint.hxx62
-rw-r--r--sc/inc/simplehintids.hxx22
-rw-r--r--sc/inc/table.hxx10
-rw-r--r--sc/inc/tokenarray.hxx10
-rw-r--r--sc/source/core/data/bcaslot.cxx49
-rw-r--r--sc/source/core/data/colorscale.cxx4
-rw-r--r--sc/source/core/data/column.cxx168
-rw-r--r--sc/source/core/data/documen7.cxx52
-rw-r--r--sc/source/core/data/formulacell.cxx25
-rw-r--r--sc/source/core/data/listenercontext.cxx44
-rw-r--r--sc/source/core/data/table2.cxx20
-rw-r--r--sc/source/core/inc/bcaslot.hxx14
-rw-r--r--sc/source/core/tool/chartlis.cxx2
-rw-r--r--sc/source/core/tool/lookupcache.cxx2
-rw-r--r--sc/source/core/tool/refhint.cxx36
-rw-r--r--sc/source/core/tool/token.cxx39
-rw-r--r--sc/source/ui/docshell/servobj.cxx2
-rw-r--r--sc/source/ui/inc/servobj.hxx2
-rw-r--r--sc/source/ui/undo/undoblk.cxx13
-rw-r--r--sc/source/ui/unoobj/cellsuno.cxx2
-rw-r--r--svl/source/notify/broadcast.cxx2
-rw-r--r--svl/source/notify/listener.cxx10
33 files changed, 577 insertions, 57 deletions
diff --git a/include/svl/listener.hxx b/include/svl/listener.hxx
index c8710230c9a7..1c9845843bd1 100644
--- a/include/svl/listener.hxx
+++ b/include/svl/listener.hxx
@@ -45,7 +45,7 @@ public:
bool HasBroadcaster() const;
- virtual void Notify( SvtBroadcaster& rBC, const SfxHint& rHint );
+ virtual void Notify( const SfxHint& rHint );
};
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 296761e5cd0b..b7041b88af5d 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -255,6 +255,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
sc/source/core/tool/recursionhelper \
sc/source/core/tool/refdata \
sc/source/core/tool/reffind \
+ sc/source/core/tool/refhint \
sc/source/core/tool/refreshtimer \
sc/source/core/tool/reftokenhelper \
sc/source/core/tool/refupdat \
diff --git a/sc/inc/brdcst.hxx b/sc/inc/brdcst.hxx
index beef7749b440..b328becc244a 100644
--- a/sc/inc/brdcst.hxx
+++ b/sc/inc/brdcst.hxx
@@ -21,16 +21,12 @@
#include "global.hxx"
#include "address.hxx"
+#include <simplehintids.hxx>
#include <tools/rtti.hxx>
#include <svl/hint.hxx>
-#include <svl/smplhint.hxx>
class SvtBroadcaster;
-#define SC_HINT_DATACHANGED SFX_HINT_DATACHANGED
-#define SC_HINT_TABLEOPDIRTY SFX_HINT_USER00
-#define SC_HINT_CALCALL SFX_HINT_USER01
-
class ScHint : public SfxSimpleHint
{
ScAddress aAddress;
diff --git a/sc/inc/cellsuno.hxx b/sc/inc/cellsuno.hxx
index e4a245fa78c7..f8e6b4d44e0f 100644
--- a/sc/inc/cellsuno.hxx
+++ b/sc/inc/cellsuno.hxx
@@ -115,7 +115,7 @@ class ScLinkListener : public SvtListener
public:
ScLinkListener(const Link& rL) : aLink(rL) {}
virtual ~ScLinkListener();
- virtual void Notify( SvtBroadcaster& rBC, const SfxHint& rHint );
+ virtual void Notify( const SfxHint& rHint );
};
typedef ::com::sun::star::uno::Reference<
diff --git a/sc/inc/chartlis.hxx b/sc/inc/chartlis.hxx
index 9fa6a1d85e24..83a1dd599d26 100644
--- a/sc/inc/chartlis.hxx
+++ b/sc/inc/chartlis.hxx
@@ -93,7 +93,7 @@ public:
bool IsUno() const { return (pUnoData != NULL); }
- virtual void Notify( SvtBroadcaster& rBC, const SfxHint& rHint );
+ virtual void Notify( const SfxHint& rHint );
void StartListeningTo();
void EndListeningTo();
void ChangeListening( const ScRangeListRef& rRangeListRef,
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 756b4c4a1448..e6a69e15ea4a 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -58,6 +58,7 @@ struct NoteEntry;
class DocumentStreamAccess;
class CompileFormulaContext;
struct SetFormulaDirtyContext;
+class RefMovedHint;
}
@@ -455,6 +456,8 @@ public:
void StartNeededListeners(); // only for cells where NeedsListening()==true
void SetDirtyIfPostponed();
void BroadcastRecalcOnRefMove();
+ void BroadcastRefMoved( const sc::RefMovedHint& rHint );
+ void TransferListeners( ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta );
void CompileDBFormula( sc::CompileFormulaContext& rCxt );
void CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 9603ae5db3a3..04ffa47268ac 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -74,6 +74,7 @@ struct FormulaGroupContext;
class DocumentStreamAccess;
class DocumentLinkManager;
struct SetFormulaDirtyContext;
+class RefMovedHint;
}
@@ -1822,6 +1823,7 @@ public:
void Broadcast( const ScHint& rHint );
void BroadcastCells( const ScRange& rRange, sal_uLong nHint );
+ void BroadcastRefMoved( const sc::RefMovedHint& rHint );
/// only area, no cell broadcast
void AreaBroadcast( const ScHint& rHint );
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 2cfdbb9bc623..854886776a8a 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -314,7 +314,7 @@ public:
void SetPreviousTrack( ScFormulaCell* pF );
void SetNextTrack( ScFormulaCell* pF );
- virtual void Notify( SvtBroadcaster& rBC, const SfxHint& rHint);
+ virtual void Notify( const SfxHint& rHint );
void SetCompile( bool bVal );
ScDocument* GetDocument() const;
void SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag=true );
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/inc/lookupcache.hxx b/sc/inc/lookupcache.hxx
index 0b6c53baec4f..2f73930e2e64 100644
--- a/sc/inc/lookupcache.hxx
+++ b/sc/inc/lookupcache.hxx
@@ -120,7 +120,7 @@ public:
ScLookupCache( ScDocument * pDoc, const ScRange & rRange );
virtual ~ScLookupCache();
/// Remove from document structure and delete (!) cache on modify hint.
- virtual void Notify( SvtBroadcaster & rBC, const SfxHint & rHint );
+ virtual void Notify( const SfxHint& rHint );
/// @returns document address in o_rAddress if Result==FOUND
Result lookup( ScAddress & o_rResultAddress,
diff --git a/sc/inc/mtvcellfunc.hxx b/sc/inc/mtvcellfunc.hxx
index d5e79218a350..092dcf7a54c1 100644
--- a/sc/inc/mtvcellfunc.hxx
+++ b/sc/inc/mtvcellfunc.hxx
@@ -187,6 +187,16 @@ ProcessNote(
CellNoteStoreType, cellnote_block, _FuncElem, FuncElseNoOp<size_t> >(it, rStore, nRow1, nRow2, rFuncElem, aElse);
}
+template<typename _FuncElem>
+typename BroadcasterStoreType::iterator
+ProcessBroadcaster(
+ const BroadcasterStoreType::iterator& it, BroadcasterStoreType& rStore, SCROW nRow1, SCROW nRow2, _FuncElem& rFuncElem)
+{
+ FuncElseNoOp<size_t> aElse;
+ return ProcessElements1<
+ BroadcasterStoreType, broadcaster_block, _FuncElem, FuncElseNoOp<size_t> >(it, rStore, nRow1, nRow2, rFuncElem, aElse);
+}
+
}
#endif
diff --git a/sc/inc/refhint.hxx b/sc/inc/refhint.hxx
new file mode 100644
index 000000000000..ec56735faaf3
--- /dev/null
+++ b/sc/inc/refhint.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef SC_REFHINT_HXX
+#define SC_REFHINT_HXX
+
+#include <address.hxx>
+#include <simplehintids.hxx>
+
+namespace sc {
+
+class RefHint : public SfxSimpleHint
+{
+public:
+ enum Type { Moved };
+
+private:
+ Type meType;
+
+ RefHint(); // disabled
+
+protected:
+ RefHint( Type eType );
+
+public:
+ virtual ~RefHint() = 0;
+
+ Type getType() const;
+};
+
+class RefMovedHint : public RefHint
+{
+ ScRange maRange;
+ ScAddress maMoveDelta;
+
+public:
+
+ RefMovedHint( const ScRange& rRange, const ScAddress& rMove );
+ virtual ~RefMovedHint();
+
+ /**
+ * Get the source range from which the references have moved.
+ */
+ const ScRange& getRange() const;
+
+ /**
+ * Get the movement vector.
+ */
+ const ScAddress& getDelta() const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/simplehintids.hxx b/sc/inc/simplehintids.hxx
new file mode 100644
index 000000000000..ecf2f9357c2d
--- /dev/null
+++ b/sc/inc/simplehintids.hxx
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef SC_SIMPLEHINTIDS_HXX
+#define SC_SIMPLEHINTIDS_HXX
+
+#include <svl/smplhint.hxx>
+
+#define SC_HINT_DATACHANGED SFX_HINT_DATACHANGED
+#define SC_HINT_TABLEOPDIRTY SFX_HINT_USER00
+#define SC_HINT_CALCALL SFX_HINT_USER01
+#define SC_HINT_REFERENCE SFX_HINT_USER02
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 4f30caeb4398..eda54721c39d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -70,6 +70,7 @@ struct NoteEntry;
class DocumentStreamAccess;
class CompileFormulaContext;
struct SetFormulaDirtyContext;
+class RefMovedHint;
}
@@ -898,6 +899,15 @@ public:
*/
void BroadcastRecalcOnRefMove();
+ /**
+ * Broadcast all listeners of specified range that the range have moved.
+ */
+ void BroadcastRefMoved( const sc::RefMovedHint& rHint );
+
+ void TransferListeners(
+ ScTable& rDestTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ SCCOL nColDelta, SCROW nRowDelta );
+
#if DEBUG_COLUMN_STORAGE
void DumpFormulaGroups( SCCOL nCol ) const;
#endif
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 5f04a9ab41c7..58ff8d46e437 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -145,6 +145,16 @@ public:
const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos );
/**
+ * Move reference positions that are within specified moved range.
+ *
+ * @param rPos position of this formula cell
+ * @param rMovedRange range that has been moved.
+ * @param rDelta movement vector.
+ */
+ void MoveReference(
+ const ScAddress& rPos, const ScRange& rMovedRange, const ScAddress& rDelta );
+
+ /**
* Adjust all references in named expression. In named expression, we only
* update absolute positions, and leave relative positions intact.
*
diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx
index 4578fd9e55cd..2dfc9a7d6ac6 100644
--- a/sc/source/core/data/bcaslot.cxx
+++ b/sc/source/core/data/bcaslot.cxx
@@ -446,6 +446,30 @@ void ScBroadcastAreaSlot::EraseArea( ScBroadcastAreas::iterator& rIter )
}
}
+void ScBroadcastAreaSlot::GetAllListeners( const ScRange& rRange, std::vector<sc::AreaListener>& rListeners )
+{
+ for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
+ aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
+ {
+ if (isMarkedErased( aIter))
+ continue;
+
+ ScBroadcastArea* pArea = (*aIter).mpArea;
+ const ScRange& rAreaRange = pArea->GetRange();
+ if (!rRange.In(rAreaRange))
+ continue;
+
+ SvtBroadcaster::ListenersType& rLst = pArea->GetBroadcaster().GetAllListeners();
+ SvtBroadcaster::ListenersType::iterator itLst = rLst.begin(), itLstEnd = rLst.end();
+ for (; itLst != itLstEnd; ++itLst)
+ {
+ sc::AreaListener aEntry;
+ aEntry.maArea = rAreaRange;
+ aEntry.mpListener = *itLst;
+ rListeners.push_back(aEntry);
+ }
+ }
+}
void ScBroadcastAreaSlot::FinallyEraseAreas()
{
@@ -976,4 +1000,29 @@ void ScBroadcastAreaSlotMachine::FinallyEraseAreas( ScBroadcastAreaSlot* pSlot )
maAreasToBeErased.swap( aCopy);
}
+std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners( const ScRange& rRange )
+{
+ std::vector<sc::AreaListener> aRet;
+
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ for (TableSlotsMap::const_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 )
+ {
+ ScBroadcastAreaSlot* p = *pp;
+ p->GetAllListeners(rRange, aRet);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
+ }
+ }
+
+ return aRet;
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/colorscale.cxx b/sc/source/core/data/colorscale.cxx
index 5481d993561a..29d53b7adb11 100644
--- a/sc/source/core/data/colorscale.cxx
+++ b/sc/source/core/data/colorscale.cxx
@@ -33,7 +33,7 @@ public:
ScFormulaListener(ScFormulaCell* pCell);
virtual ~ScFormulaListener();
- void Notify( SvtBroadcaster& rBC, const SfxHint& rHint );
+ void Notify( const SfxHint& rHint );
bool NeedsRepaint() const;
};
@@ -129,7 +129,7 @@ ScFormulaListener::~ScFormulaListener()
std::for_each(maCells.begin(), maCells.end(), StopListeningCell(mpDoc, this));
}
-void ScFormulaListener::Notify(SvtBroadcaster&, const SfxHint&)
+void ScFormulaListener::Notify( const SfxHint& )
{
mbDirty = true;
}
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 2bcc710b8bf4..7914fdfced9d 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -42,6 +42,7 @@
#include "sharedformula.hxx"
#include "refupdatecontext.hxx"
#include <listenercontext.hxx>
+#include <refhint.hxx>
#include <svl/poolcach.hxx>
#include <svl/zforlist.hxx>
@@ -3435,6 +3436,173 @@ void ScColumn::BroadcastRecalcOnRefMove()
BroadcastCells(aFunc.getDirtyRows(), SC_HINT_DATACHANGED);
}
+namespace {
+
+class BroadcastRefMovedHandler
+{
+ const sc::RefMovedHint& mrHint;
+public:
+ BroadcastRefMovedHandler( const sc::RefMovedHint& rHint ) : mrHint(rHint) {}
+
+ void operator() ( size_t, SvtBroadcaster* p )
+ {
+ p->Broadcast(mrHint);
+ }
+};
+
+}
+
+void ScColumn::BroadcastRefMoved( const sc::RefMovedHint& rHint )
+{
+ const ScRange& rRange = rHint.getRange();
+ SCROW nRow1 = rRange.aStart.Row();
+ SCROW nRow2 = rRange.aEnd.Row();
+
+ // Notify all listeners within specified rows.
+ BroadcastRefMovedHandler aFunc(rHint);
+ sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
+}
+
+namespace {
+
+class TransferListenersHandler
+{
+public:
+ 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);
+
+ // It's important to make a copy here.
+ SvtBroadcaster::ListenersType aLis = pBroadcaster->GetAllListeners();
+ if (aLis.empty())
+ // No listeners to transfer.
+ return;
+
+ 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;
+
+ 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)
+ {
+ // Existing broadcaster.
+ pDestBrd = sc::broadcaster_block::at(*aPos.first->data, aPos.second);
+ }
+ else
+ {
+ // No existing broadcaster. Create a new one.
+ assert(aPos.first->type == sc::element_type_empty);
+ pDestBrd = new SvtBroadcaster;
+ itDestPos = rDestCol.maBroadcasters.set(itDestPos, nDestRow, pDestBrd);
+ }
+
+ // Transfer all listeners from the source to the destination.
+ SvtBroadcaster::ListenersType::iterator it2 = rEntry.maListeners.begin(), it2End = rEntry.maListeners.end();
+ for (; it2 != it2End; ++it2)
+ {
+ SvtListener* pLis = *it2;
+ pLis->StartListening(*pDestBrd);
+ }
+ }
+
+ // 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()
{
CalcAllHandler aFunc;
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
index ac3f3cf2ed69..02a75fb2add2 100644
--- a/sc/source/core/data/documen7.cxx
+++ b/sc/source/core/data/documen7.cxx
@@ -37,6 +37,7 @@
#include "tokenarray.hxx"
#include "listenercontext.hxx"
#include "formulagroup.hxx"
+#include <refhint.hxx>
#include <tools/shl.hxx>
@@ -129,6 +130,57 @@ void ScDocument::BroadcastCells( const ScRange& rRange, sal_uLong nHint )
BroadcastUno(SfxSimpleHint(SC_HINT_DATACHANGED));
}
+void ScDocument::BroadcastRefMoved( const sc::RefMovedHint& rHint )
+{
+ if (!pBASM)
+ // clipboard or undo document.
+ return;
+
+ const ScRange& rSrcRange = rHint.getRange(); // old range
+ const ScAddress& rDelta = rHint.getDelta();
+
+ // Get all area listeners that listens on the old range, and end their listening.
+ std::vector<sc::AreaListener> aAreaListeners = pBASM->GetAllListeners(rSrcRange);
+ {
+ std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
+ for (; it != itEnd; ++it)
+ {
+ pBASM->EndListeningArea(it->maArea, it->mpListener);
+ it->mpListener->Notify(rHint); // Adjust the references.
+ }
+ }
+
+ for (SCTAB nTab = rSrcRange.aStart.Tab(); nTab <= rSrcRange.aEnd.Tab(); ++nTab)
+ {
+ ScTable* pTab = FetchTable(nTab);
+ if (!pTab)
+ continue;
+
+ SCTAB nDestTab = nTab + rDelta.Tab();
+ ScTable* pDestTab = FetchTable(nDestTab);
+ if (!pDestTab)
+ continue;
+
+ // Adjust the references.
+ pTab->BroadcastRefMoved(rHint);
+ // Move the listeners from the old location to the new.
+ pTab->TransferListeners(
+ *pDestTab, rSrcRange.aStart.Col(), rSrcRange.aStart.Row(),
+ rSrcRange.aEnd.Col(), rSrcRange.aEnd.Row(), rDelta.Col(), rDelta.Row());
+ }
+
+ // Re-start area listeners on the new range.
+ {
+ std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
+ for (; it != itEnd; ++it)
+ {
+ ScRange aNewRange = it->maArea;
+ aNewRange.Move(rDelta.Col(), rDelta.Row(), rDelta.Tab());
+ pBASM->StartListeningArea(aNewRange, it->mpListener);
+ }
+ }
+}
+
void ScDocument::AreaBroadcast( const ScHint& rHint )
{
if ( !pBASM )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 2768d22a7381..395adfd8db25 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -51,6 +51,7 @@
#include "scopetools.hxx"
#include "refupdatecontext.hxx"
#include <tokenstringcontext.hxx>
+#include <refhint.hxx>
#include <boost/scoped_ptr.hpp>
@@ -1857,12 +1858,30 @@ bool ScFormulaCell::IsInChangeTrack() const
return bInChangeTrack;
}
-void ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint)
+void ScFormulaCell::Notify( const SfxHint& rHint )
{
+ const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
+ if (!pSimpleHint)
+ return;
+
+ sal_uLong nHint = pSimpleHint->GetId();
+ if (nHint == SC_HINT_REFERENCE)
+ {
+ const sc::RefHint& rRefHint = static_cast<const sc::RefHint&>(rHint);
+
+ if (rRefHint.getType() == sc::RefHint::Moved)
+ {
+ // One of the references has moved.
+
+ const sc::RefMovedHint& rRefMoved = static_cast<const sc::RefMovedHint&>(rRefHint);
+ pCode->MoveReference(aPos, rRefMoved.getRange(), rRefMoved.getDelta());
+ }
+
+ return;
+ }
+
if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() )
{
- const ScHint* p = PTR_CAST( ScHint, &rHint );
- sal_uLong nHint = (p ? p->GetId() : 0);
if (nHint & (SC_HINT_DATACHANGED | SC_HINT_TABLEOPDIRTY))
{
bool bForceTrack = false;
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: */
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 076087fda883..b0fba9c50b27 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -49,6 +49,7 @@
#include "mtvcellfunc.hxx"
#include "refupdatecontext.hxx"
#include "scopetools.hxx"
+#include <refhint.hxx>
#include "scitems.hxx"
#include <editeng/boxitem.hxx>
@@ -1708,6 +1709,25 @@ void ScTable::BroadcastRecalcOnRefMove()
aCol[i].BroadcastRecalcOnRefMove();
}
+void ScTable::BroadcastRefMoved( const sc::RefMovedHint& rHint )
+{
+ const ScRange& rRange = rHint.getRange();
+ for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
+ aCol[nCol].BroadcastRefMoved(rHint);
+}
+
+void ScTable::TransferListeners(
+ ScTable& rDestTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ SCCOL nColDelta, SCROW nRowDelta )
+{
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ ScColumn& rSrcCol = aCol[nCol];
+ ScColumn& rDestCol = rDestTab.aCol[nCol+nColDelta];
+ rSrcCol.TransferListeners(rDestCol, nRow1, nRow2, nRowDelta);
+ }
+}
+
void ScTable::SetLoadingMedium(bool bLoading)
{
mpRowHeights->enableTreeSearch(!bLoading);
diff --git a/sc/source/core/inc/bcaslot.hxx b/sc/source/core/inc/bcaslot.hxx
index ca11dd975096..b8587d6f4506 100644
--- a/sc/source/core/inc/bcaslot.hxx
+++ b/sc/source/core/inc/bcaslot.hxx
@@ -28,6 +28,16 @@
#include "global.hxx"
#include "brdcst.hxx"
+namespace sc {
+
+struct AreaListener
+{
+ ScRange maArea;
+ SvtListener* mpListener;
+};
+
+}
+
/**
Used in a Unique Associative Container.
*/
@@ -210,6 +220,8 @@ public:
Meant to be used internally and from ScBroadcastAreaSlotMachine only.
*/
void EraseArea( ScBroadcastAreas::iterator& rIter );
+
+ void GetAllListeners( const ScRange& rRange, std::vector<sc::AreaListener>& rListeners );
};
@@ -304,6 +316,8 @@ public:
ScBroadcastAreas::iterator& rIter );
// only for ScBroadcastAreaSlot
void FinallyEraseAreas( ScBroadcastAreaSlot* pSlot );
+
+ std::vector<sc::AreaListener> GetAllListeners( const ScRange& rRange );
};
diff --git a/sc/source/core/tool/chartlis.cxx b/sc/source/core/tool/chartlis.cxx
index d5193fa58e49..f0ba1cea22fa 100644
--- a/sc/source/core/tool/chartlis.cxx
+++ b/sc/source/core/tool/chartlis.cxx
@@ -203,7 +203,7 @@ uno::Reference< chart::XChartData > ScChartListener::GetUnoSource() const
return uno::Reference< chart::XChartData >();
}
-void ScChartListener::Notify( SvtBroadcaster&, const SfxHint& rHint )
+void ScChartListener::Notify( const SfxHint& rHint )
{
const ScHint* p = dynamic_cast<const ScHint*>(&rHint);
if (p && (p->GetId() & SC_HINT_DATACHANGED))
diff --git a/sc/source/core/tool/lookupcache.cxx b/sc/source/core/tool/lookupcache.cxx
index 914b188a851d..ac92fe627309 100644
--- a/sc/source/core/tool/lookupcache.cxx
+++ b/sc/source/core/tool/lookupcache.cxx
@@ -110,7 +110,7 @@ bool ScLookupCache::insert( const ScAddress & rResultAddress,
}
-void ScLookupCache::Notify( SvtBroadcaster & /* rBC */ , const SfxHint & rHint )
+void ScLookupCache::Notify( const SfxHint& rHint )
{
if (!mpDoc->IsInDtorClear())
{
diff --git a/sc/source/core/tool/refhint.cxx b/sc/source/core/tool/refhint.cxx
new file mode 100644
index 000000000000..eb07b4fe3565
--- /dev/null
+++ b/sc/source/core/tool/refhint.cxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <refhint.hxx>
+
+namespace sc {
+
+RefHint::RefHint( Type eType ) : SfxSimpleHint(SC_HINT_REFERENCE), meType(eType) {}
+RefHint::~RefHint() {}
+
+RefHint::Type RefHint::getType() const { return meType; }
+
+RefMovedHint::RefMovedHint( const ScRange& rRange, const ScAddress& rMove ) :
+ RefHint(Moved), maRange(rRange), maMoveDelta(rMove) {}
+
+RefMovedHint::~RefMovedHint() {}
+
+const ScRange& RefMovedHint::getRange() const
+{
+ return maRange;
+}
+
+const ScAddress& RefMovedHint::getDelta() const
+{
+ return maMoveDelta;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 2b03db3e7795..77cc06d3a2a6 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2845,6 +2845,45 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove(
return aRes;
}
+void ScTokenArray::MoveReference(
+ const ScAddress& rPos, const ScRange& rMovedRange, const ScAddress& rDelta )
+{
+ FormulaToken** p = pCode;
+ FormulaToken** pEnd = p + static_cast<size_t>(nLen);
+ for (; p != pEnd; ++p)
+ {
+ switch ((*p)->GetType())
+ {
+ case svSingleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ ScSingleRefData& rRef = pToken->GetSingleRef();
+ ScAddress aAbs = rRef.toAbs(rPos);
+ if (rMovedRange.In(aAbs))
+ {
+ aAbs.Move(rDelta.Col(), rDelta.Row(), rDelta.Tab());
+ rRef.SetAddress(aAbs, rPos);
+ }
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ ScComplexRefData& rRef = pToken->GetDoubleRef();
+ ScRange aAbs = rRef.toAbs(rPos);
+ if (rMovedRange.In(aAbs))
+ {
+ aAbs.Move(rDelta.Col(), rDelta.Row(), rDelta.Tab());
+ rRef.SetRange(aAbs, rPos);
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
namespace {
bool adjustSingleRefInName(
diff --git a/sc/source/ui/docshell/servobj.cxx b/sc/source/ui/docshell/servobj.cxx
index a82c7191a663..0564b1ac8195 100644
--- a/sc/source/ui/docshell/servobj.cxx
+++ b/sc/source/ui/docshell/servobj.cxx
@@ -61,7 +61,7 @@ ScServerObjectSvtListenerForwarder::~ScServerObjectSvtListenerForwarder()
//! do NOT access pObj
}
-void ScServerObjectSvtListenerForwarder::Notify( SvtBroadcaster& /* rBC */, const SfxHint& rHint)
+void ScServerObjectSvtListenerForwarder::Notify( const SfxHint& rHint )
{
pObj->Notify( aBroadcaster, rHint);
}
diff --git a/sc/source/ui/inc/servobj.hxx b/sc/source/ui/inc/servobj.hxx
index d0be4d692ec0..86e39e242175 100644
--- a/sc/source/ui/inc/servobj.hxx
+++ b/sc/source/ui/inc/servobj.hxx
@@ -36,7 +36,7 @@ class ScServerObjectSvtListenerForwarder : public SvtListener
public:
ScServerObjectSvtListenerForwarder( ScServerObject* pObjP);
virtual ~ScServerObjectSvtListenerForwarder();
- virtual void Notify( SvtBroadcaster& rBC, const SfxHint& rHint);
+ virtual void Notify( const SfxHint& rHint );
};
class ScServerObject : public ::sfx2::SvLinkSource, public SfxListener
diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
index aebdb3ee9afc..cb4f25ab9fcb 100644
--- a/sc/source/ui/undo/undoblk.cxx
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -47,6 +47,7 @@
#include "undoolk.hxx"
#include "clipparam.hxx"
#include "sc.hrc"
+#include <refhint.hxx>
#include <set>
@@ -1254,6 +1255,18 @@ void ScUndoDragDrop::Undo()
maPaintRanges.RemoveAll();
BeginUndo();
+
+ if (bCut)
+ {
+ // Notify all listeners of the destination range, and have them update their references.
+ ScDocument* pDoc = pDocShell->GetDocument();
+ SCCOL nColDelta = aSrcRange.aStart.Col() - aDestRange.aStart.Col();
+ SCROW nRowDelta = aSrcRange.aStart.Row() - aDestRange.aStart.Row();
+ SCTAB nTabDelta = aSrcRange.aStart.Tab() - aDestRange.aStart.Tab();
+ sc::RefMovedHint aHint(aDestRange, ScAddress(nColDelta, nRowDelta, nTabDelta));
+ pDoc->BroadcastRefMoved(aHint);
+ }
+
DoUndo(aDestRange);
if (bCut)
DoUndo(aSrcRange);
diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx
index 8da119885af9..a9cf2eb2eafe 100644
--- a/sc/source/ui/unoobj/cellsuno.cxx
+++ b/sc/source/ui/unoobj/cellsuno.cxx
@@ -890,7 +890,7 @@ ScLinkListener::~ScLinkListener()
{
}
-void ScLinkListener::Notify( SvtBroadcaster&, const SfxHint& rHint )
+void ScLinkListener::Notify( const SfxHint& rHint )
{
aLink.Call( (SfxHint*)&rHint );
}
diff --git a/svl/source/notify/broadcast.cxx b/svl/source/notify/broadcast.cxx
index 24b5790c0336..f13721e3a440 100644
--- a/svl/source/notify/broadcast.cxx
+++ b/svl/source/notify/broadcast.cxx
@@ -56,7 +56,7 @@ public:
void operator() ( SvtListener* p )
{
- p->Notify(mrBC, mrHint);
+ p->Notify(mrHint);
}
};
diff --git a/svl/source/notify/listener.cxx b/svl/source/notify/listener.cxx
index 59d3ef9f3352..66207bf4c0bc 100644
--- a/svl/source/notify/listener.cxx
+++ b/svl/source/notify/listener.cxx
@@ -80,15 +80,7 @@ bool SvtListener::HasBroadcaster() const
return !maBroadcasters.empty();
}
-void SvtListener::Notify( SvtBroadcaster&
-#ifdef DBG_UTIL
-rBC
-#endif
-, const SfxHint& )
-{
- DBG_ASSERT( IsListening( rBC ),
- "notification from unregistered broadcaster" );
-}
+void SvtListener::Notify( const SfxHint& ) {}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */