[Libreoffice-commits] core.git: Branch 'libreoffice-4-2' - include/svl sc/inc sc/Library_sc.mk sc/source svl/source

Kohei Yoshida kohei.yoshida at collabora.com
Mon Mar 17 06:43:04 PDT 2014


 include/svl/listener.hxx                |    2 
 sc/Library_sc.mk                        |    1 
 sc/inc/brdcst.hxx                       |    6 -
 sc/inc/cellsuno.hxx                     |    2 
 sc/inc/chartlis.hxx                     |    2 
 sc/inc/column.hxx                       |    3 
 sc/inc/document.hxx                     |    2 
 sc/inc/formulacell.hxx                  |    2 
 sc/inc/listenercontext.hxx              |   12 ++
 sc/inc/lookupcache.hxx                  |    2 
 sc/inc/mtvcellfunc.hxx                  |   10 +
 sc/inc/refhint.hxx                      |   62 +++++++++++
 sc/inc/simplehintids.hxx                |   22 ++++
 sc/inc/table.hxx                        |   10 +
 sc/inc/tokenarray.hxx                   |   10 +
 sc/source/core/data/bcaslot.cxx         |   49 +++++++++
 sc/source/core/data/colorscale.cxx      |    4 
 sc/source/core/data/column.cxx          |  168 ++++++++++++++++++++++++++++++++
 sc/source/core/data/documen7.cxx        |   52 +++++++++
 sc/source/core/data/formulacell.cxx     |   25 ++++
 sc/source/core/data/listenercontext.cxx |   44 +++-----
 sc/source/core/data/table2.cxx          |   20 +++
 sc/source/core/inc/bcaslot.hxx          |   14 ++
 sc/source/core/tool/chartlis.cxx        |    2 
 sc/source/core/tool/lookupcache.cxx     |    2 
 sc/source/core/tool/refhint.cxx         |   36 ++++++
 sc/source/core/tool/token.cxx           |   39 +++++++
 sc/source/ui/docshell/servobj.cxx       |    2 
 sc/source/ui/inc/servobj.hxx            |    2 
 sc/source/ui/undo/undoblk.cxx           |   13 ++
 sc/source/ui/unoobj/cellsuno.cxx        |    2 
 svl/source/notify/broadcast.cxx         |    2 
 svl/source/notify/listener.cxx          |   10 -
 33 files changed, 577 insertions(+), 57 deletions(-)

New commits:
commit b85f07986dc005ea0a74baa3d14ee0fd1ec99609
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Mar 14 23:15:32 2014 -0400

    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 at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/include/svl/listener.hxx b/include/svl/listener.hxx
index c871023..1c98458 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 296761e..b7041b8 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 beef774..b328bec 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 e4a245f..f8e6b4d 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 9fa6a1d8..83a1dd5 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 756b4c4..e6a69e1 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 9603ae5..04ffa47 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 2cfdbb9..8548867 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 c0260ef..501f1d2 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 0b6c53b..2f73930 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 d5e7921..092dcf7 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 0000000..ec56735
--- /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 0000000..ecf2f93
--- /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 4f30cae..eda54721 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 5f04a9a..58ff8d4 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 4578fd9..2dfc9a7 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 5481d99..29d53b7 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 2bcc710..7914fdf 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 ac3f3cf..02a75fb 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 2768d22..395adfd 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 3dfe5ed..add75a2 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 076087f..b0fba9c 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 ca11dd9..b8587d6 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 d5193fa..f0ba1ce 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 914b188..ac92fe6 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 0000000..eb07b4fe
--- /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 2b03db3..77cc06d 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 a82c719..0564b1a 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 d0be4d6..86e39e2 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 aebdb3e..cb4f25a 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 8da1198..a9cf2eb 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 24b5790..f13721e 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 59d3ef9..66207bf 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: */


More information about the Libreoffice-commits mailing list