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

Kohei Yoshida kohei.yoshida at collabora.com
Tue Nov 25 07:01:53 PST 2014


 include/svl/broadcast.hxx                 |   10 +-
 sc/inc/cellvalue.hxx                      |    2 
 sc/inc/clipcontext.hxx                    |    5 +
 sc/inc/column.hxx                         |   17 +++--
 sc/inc/document.hxx                       |    2 
 sc/inc/formulacell.hxx                    |    9 +-
 sc/inc/grouparealistener.hxx              |    6 +
 sc/inc/stringutil.hxx                     |    3 
 sc/inc/table.hxx                          |    5 +
 sc/inc/types.hxx                          |    7 ++
 sc/qa/unit/ucalc.hxx                      |   25 ++++++-
 sc/qa/unit/ucalc_sharedformula.cxx        |  101 ++++++++++++++++++++++++++++++
 sc/source/core/data/bcaslot.cxx           |   24 +++++++
 sc/source/core/data/cellvalue.cxx         |    4 -
 sc/source/core/data/clipcontext.cxx       |   14 +++-
 sc/source/core/data/column.cxx            |   36 ++++++++--
 sc/source/core/data/column3.cxx           |   43 ++++++++----
 sc/source/core/data/column4.cxx           |    2 
 sc/source/core/data/document.cxx          |   28 ++++----
 sc/source/core/data/document10.cxx        |   34 ++++++++++
 sc/source/core/data/formulacell.cxx       |   59 +++++++++++++++--
 sc/source/core/data/table2.cxx            |   14 +++-
 sc/source/core/inc/bcaslot.hxx            |    5 +
 sc/source/core/tool/grouparealistener.cxx |   17 ++++-
 sc/source/core/tool/stringutil.cxx        |    3 
 sc/source/ui/undo/refundo.cxx             |   38 ++++++-----
 svl/source/notify/broadcast.cxx           |    4 -
 27 files changed, 435 insertions(+), 82 deletions(-)

New commits:
commit 7d52a5dff557117c0f8710eb27e61b328323ac90
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Nov 25 00:02:21 2014 -0500

    Adjust ref undo to ensure group area listeners are used.
    
    When undoing row deletion (and possibly other similar undo's).  And
    write test for it.
    
    Change-Id: I04b4fd9932f4236f124dcd25967355c6055dec33
    (cherry picked from commit 0dae7466fff1e742543ef7512b7dd22472c75624)

diff --git a/include/svl/broadcast.hxx b/include/svl/broadcast.hxx
index 5615255..a73abea 100644
--- a/include/svl/broadcast.hxx
+++ b/include/svl/broadcast.hxx
@@ -41,7 +41,7 @@ private:
      * entries. As a side effect, the listeners get sorted by pointer values
      * after this call.
      */
-    void Normalize();
+    void Normalize() const;
 
     void Add( SvtListener* p );
     void Remove( SvtListener* p );
@@ -74,16 +74,16 @@ public:
     void PrepareForDestruction();
 
 private:
-    ListenersType maListeners;
+    mutable ListenersType maListeners;
 
     /// When the broadcaster is about to die, collect listeners that asked for removal.
-    ListenersType maDestructedListeners;
+    mutable ListenersType maDestructedListeners;
 
     /// Indicate that this broadcaster will be destructed (we indicate this on all ScColumn's broadcasters during the ScTable destruction, eg.)
     bool mbAboutToDie:1;
     bool mbDisposing:1;
-    bool mbNormalized:1;
-    bool mbDestNormalized:1;
+    mutable bool mbNormalized:1;
+    mutable bool mbDestNormalized:1;
 };
 
 
diff --git a/sc/inc/cellvalue.hxx b/sc/inc/cellvalue.hxx
index 9154e30..3a2d3c8 100644
--- a/sc/inc/cellvalue.hxx
+++ b/sc/inc/cellvalue.hxx
@@ -76,7 +76,7 @@ struct SC_DLLPUBLIC ScCellValue
      */
     void release( ScDocument& rDoc, const ScAddress& rPos );
 
-    void release( ScColumn& rColumn, SCROW nRow );
+    void release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType = sc::SingleCellListening );
 
     OUString getString( const ScDocument* pDoc );
 
diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx
index 3891274..aa783e4 100644
--- a/sc/inc/clipcontext.hxx
+++ b/sc/inc/clipcontext.hxx
@@ -144,9 +144,14 @@ public:
 
 class CopyToDocContext : public ClipContextBase
 {
+    bool mbStartListening;
+
 public:
     CopyToDocContext(ScDocument& rDoc);
     virtual ~CopyToDocContext();
+
+    void setStartListening( bool b );
+    bool isStartListening() const;
 };
 
 class MixDocContext : public ClipContextBase
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 102af12..7f883a6 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -314,8 +314,12 @@ public:
      * @return pCell if it was successfully inserted, NULL otherwise. pCell
      *         is deleted automatically on failure to insert.
      */
-    ScFormulaCell* SetFormulaCell( SCROW nRow, ScFormulaCell* pCell, bool bSingle = false );
-    ScFormulaCell* SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell );
+    ScFormulaCell* SetFormulaCell(
+        SCROW nRow, ScFormulaCell* pCell,
+        sc::StartListeningType eListenType = sc::SingleCellListening );
+    ScFormulaCell* SetFormulaCell(
+        sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell,
+        sc::StartListeningType eListenType = sc::SingleCellListening );
 
     bool SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells );
 
@@ -639,10 +643,15 @@ private:
 
     sc::CellStoreType::iterator GetPositionToInsert( SCROW nRow );
     sc::CellStoreType::iterator GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow );
+
     void AttachNewFormulaCell(
-        const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, bool bJoin = true, bool bSingle = false );
+        const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell,
+        bool bJoin = true, sc::StartListeningType eListenType = sc::SingleCellListening );
+
     void AttachNewFormulaCell(
-        const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, bool bJoin = true, bool bSingle = false );
+        const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
+        bool bJoin = true, sc::StartListeningType eListenType = sc::SingleCellListening );
+
     void AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength );
     void BroadcastNewCell( SCROW nRow );
     bool UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, const sc::CellStoreType::iterator& itr );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 554ee3a..31fde4d 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1916,6 +1916,8 @@ public:
     void                SetHardRecalcState( bool bVal ) { bHardRecalcState = bVal; }
     void                StartAllListeners();
     void StartNeededListeners();
+    void StartAllListeners( const ScRange& rRange );
+    void EndAllListeners( const ScRange& rRange );
     const ScFormulaCell*    GetFormulaTree() const { return pFormulaTree; }
     bool                HasForcedFormulas() const { return bHasForcedFormulas; }
     void                SetForcedFormulas( bool bVal ) { bHasForcedFormulas = bVal; }
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 50a6f6c..86b8045 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -23,7 +23,6 @@
 #include <set>
 
 #include <boost/noncopyable.hpp>
-#include <boost/ptr_container/ptr_vector.hpp>
 
 #include <formula/tokenarray.hxx>
 #include <osl/conditn.hxx>
@@ -58,7 +57,11 @@ class ScTokenArray;
 
 struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable
 {
-    typedef boost::ptr_vector<sc::FormulaGroupAreaListener> AreaListenersType;
+private:
+    struct Impl;
+    Impl* mpImpl;
+
+public:
 
     mutable size_t mnRefCount;
 
@@ -73,8 +76,6 @@ struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable
     sal_uInt8 meCalcState;
     sal_uInt8 meKernelState;
 
-    AreaListenersType maAreaListeners;
-
     ScFormulaCellGroup();
     ~ScFormulaCellGroup();
 
diff --git a/sc/inc/grouparealistener.hxx b/sc/inc/grouparealistener.hxx
index 5abb0e8..2c6ea50 100644
--- a/sc/inc/grouparealistener.hxx
+++ b/sc/inc/grouparealistener.hxx
@@ -32,6 +32,7 @@ class FormulaGroupAreaListener : public SvtListener
     FormulaGroupAreaListener(); // disabled
 
 public:
+
     FormulaGroupAreaListener(
         const ScRange& rRange, ScFormulaCell** ppTopCell, SCROW nGroupLen, bool bStartFixed, bool bEndFixed );
 
@@ -52,10 +53,11 @@ public:
      */
     void collectFormulaCells( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, std::vector<ScFormulaCell*>& rCells ) const;
 
-#if DEBUG_AREA_BROADCASTER
     ScAddress getTopCellPos() const;
+    const ScRange& getRange() const;
     SCROW getGroupLength() const;
-#endif
+    bool isStartFixed() const;
+    bool isEndFixed() const;
 
 private:
     void notifyCellChange( const SfxHint& rHint, const ScAddress& rPos );
diff --git a/sc/inc/stringutil.hxx b/sc/inc/stringutil.hxx
index 0d536db..ef7bd50 100644
--- a/sc/inc/stringutil.hxx
+++ b/sc/inc/stringutil.hxx
@@ -23,6 +23,7 @@
 #include <rtl/ustring.hxx>
 #include "scdllapi.h"
 #include <i18nlangtag/lang.h>
+#include <types.hxx>
 
 class SvNumberFormatter;
 
@@ -79,6 +80,8 @@ struct SC_DLLPUBLIC ScSetStringParam
      */
     bool mbHandleApostrophe;
 
+    sc::StartListeningType meStartListening;
+
     ScSetStringParam();
 
     /**
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 0d0a5c4..df3372e 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -437,10 +437,13 @@ public:
         sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         SCsCOL nDx, SCsROW nDy, ScTable* pTable );
 
-    void StartListeningFromClip(
+    void StartListeningFormulaCells(
         sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt,
         SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
 
+    void EndListeningFormulaCells(
+        sc::EndListeningContext& rEndCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
+
     void SetDirtyFromClip(
         SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans );
 
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index e483b1e..d92c9b5 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -108,6 +108,13 @@ enum AreaOverlapType
     OneColumnInsideArea
 };
 
+enum StartListeningType
+{
+    ConvertToGroupListening,
+    SingleCellListening,
+    NoListening
+};
+
 }
 
 #endif
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 7cad0ad..e20b069 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -12,6 +12,7 @@
 
 #include "helper/qahelper.hxx"
 #include "document.hxx"
+#include <stringutil.hxx>
 
 struct TestImpl;
 class ScUndoPaste;
@@ -55,9 +56,16 @@ public:
 
     static void setCalcAsShown(ScDocument* pDoc, bool bCalcAsShown);
 
+
     template<size_t _Size>
-    static ScRange insertRangeData(ScDocument* pDoc, const ScAddress& rPos, const char* aData[][_Size], size_t nRowCount)
+    static ScRange insertRangeData(
+        ScDocument* pDoc, const ScAddress& rPos, const char* aData[][_Size], size_t nRowCount,
+        bool bGroupListening = false )
     {
+        // TODO : Ideally bGroupListening should be always true for all tests.
+        // Eventually we want to drop this parameter once all tests pass with
+        // group listening turned on.
+
         ScRange aRange(rPos);
         aRange.aEnd.SetCol(rPos.Col()+_Size-1);
         aRange.aEnd.SetRow(rPos.Row()+nRowCount-1);
@@ -73,10 +81,21 @@ public:
 
                 SCCOL nCol = i + rPos.Col();
                 SCROW nRow = j + rPos.Row();
-                pDoc->SetString(nCol, nRow, rPos.Tab(), OUString(aData[j][i], strlen(aData[j][i]), RTL_TEXTENCODING_UTF8));
+                OUString aStr(aData[j][i], strlen(aData[j][i]), RTL_TEXTENCODING_UTF8);
+                if (bGroupListening)
+                {
+                    ScSetStringParam aParam; // Leave default.
+                    aParam.meStartListening = sc::NoListening;
+                    pDoc->SetString(nCol, nRow, rPos.Tab(), aStr, &aParam);
+                }
+                else
+                    pDoc->SetString(nCol, nRow, rPos.Tab(), aStr, NULL);
             }
         }
 
+        if (bGroupListening)
+            pDoc->StartAllListeners(aRange);
+
         printRange(pDoc, aRange, "Range data content");
         return aRange;
     }
@@ -300,6 +319,7 @@ public:
     void testSharedFormulasRefUpdateMove();
     void testSharedFormulasRefUpdateMove2();
     void testSharedFormulasRefUpdateRange();
+    void testSharedFormulasRefUpdateRangeDeleteRow();
     void testSharedFormulasRefUpdateExternal();
     void testSharedFormulasInsertRow();
     void testSharedFormulasDeleteRows();
@@ -529,6 +549,7 @@ public:
     CPPUNIT_TEST(testSharedFormulasRefUpdateMove);
     CPPUNIT_TEST(testSharedFormulasRefUpdateMove2);
     CPPUNIT_TEST(testSharedFormulasRefUpdateRange);
+    CPPUNIT_TEST(testSharedFormulasRefUpdateRangeDeleteRow);
     CPPUNIT_TEST(testSharedFormulasRefUpdateExternal);
     CPPUNIT_TEST(testSharedFormulasInsertRow);
     CPPUNIT_TEST(testSharedFormulasDeleteRows);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index 16d5577..8116123 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -21,6 +21,7 @@
 #include <tokenstringcontext.hxx>
 #include <globalnames.hxx>
 #include <dbdata.hxx>
+#include <bcaslot.hxx>
 
 #include <svl/sharedstring.hxx>
 
@@ -580,6 +581,106 @@ void Test::testSharedFormulasRefUpdateRange()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testSharedFormulasRefUpdateRangeDeleteRow()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
+    m_pDoc->InsertTab(0, "Formula");
+
+    ScRange aWholeArea(0, 0, 0, 100, 100, 0); // Large enough for all references used in the test.
+
+    const char* aData[][3] = {
+        { "1", "2", "=SUM(A1:B1)" },
+        { "3", "4", "=SUM(A2:B2)" },
+        { 0, 0, 0 },
+        { "5", "6", "=SUM(A4:B4)" },
+        { "7", "8", "=SUM(A5:B5)" }
+    };
+
+    insertRangeData(m_pDoc, ScAddress(0,0,0), aData, SAL_N_ELEMENTS(aData), true);
+
+    // Check initial formula values.
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 7.0, m_pDoc->GetValue(ScAddress(2,1,0)));
+    CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,3,0)));
+    CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,4,0)));
+
+    // Check the area listener status.
+    ScBroadcastAreaSlotMachine* pBASM = m_pDoc->GetBASM();
+    CPPUNIT_ASSERT(pBASM);
+    std::vector<sc::AreaListener> aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaInside);
+    std::sort(aListeners.begin(), aListeners.end(), sc::AreaListener::SortByArea());
+
+    CPPUNIT_ASSERT_MESSAGE("There should only be 2 area listeners.", aListeners.size() == 2);
+    // First one should be group-listening on A1:B2.
+    CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B2.", aListeners[0].maArea == ScRange(0,0,0,1,1,0));
+    CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
+    // Second one should be group-listening on A4:B5.
+    CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B2.", aListeners[0].maArea == ScRange(0,0,0,1,1,0));
+    CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
+
+    // Make sure that C1:C2 and C4:C5 are formula groups.
+    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    pFC = m_pDoc->GetFormulaCell(ScAddress(2,3,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    // Delete row 3.  This will merge the two formula groups.
+    ScDocFunc& rFunc = getDocShell().GetDocFunc();
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+    rFunc.DeleteCells(ScRange(0,2,0,MAXCOL,2,0), &aMark, DEL_DELROWS, true, true);
+
+    // Make sure C1:C4 belong to the same group.
+    pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
+
+    // We should only have one listener group-listening on A1:B4.
+    aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaInside);
+    CPPUNIT_ASSERT_MESSAGE("There should only be 1 area listener.", aListeners.size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B4.", aListeners[0].maArea == ScRange(0,0,0,1,3,0));
+    CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
+
+    // Change the value of B4 and make sure the value of C4 changes.
+    rFunc.SetValueCell(ScAddress(1,3,0), 100.0, false);
+    CPPUNIT_ASSERT_EQUAL(107.0, m_pDoc->GetValue(ScAddress(2,3,0)));
+
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    CPPUNIT_ASSERT(pUndoMgr);
+
+    // Undo the value change in B4, and make sure C4 follows.
+    pUndoMgr->Undo();
+    CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,3,0)));
+
+    // Undo the deletion of row 3.
+    pUndoMgr->Undo();
+
+    // Check the values of formula cells again.
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 7.0, m_pDoc->GetValue(ScAddress(2,1,0)));
+    CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,3,0)));
+    CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,4,0)));
+
+    aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaInside);
+    std::sort(aListeners.begin(), aListeners.end(), sc::AreaListener::SortByArea());
+
+    CPPUNIT_ASSERT_MESSAGE("There should only be 2 area listeners.", aListeners.size() == 2);
+    // First one should be group-listening on A1:B2.
+    CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B2.", aListeners[0].maArea == ScRange(0,0,0,1,1,0));
+    CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
+    // Second one should be group-listening on A4:B5.
+    CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B2.", aListeners[0].maArea == ScRange(0,0,0,1,1,0));
+    CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening);
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testSharedFormulasRefUpdateExternal()
 {
     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx
index 0678a7f..4290fbd 100644
--- a/sc/source/core/data/bcaslot.cxx
+++ b/sc/source/core/data/bcaslot.cxx
@@ -64,6 +64,30 @@
 
 // STATIC DATA -----------------------------------------------------------
 
+namespace sc {
+
+bool AreaListener::SortByArea::operator ()( const AreaListener& rLeft, const AreaListener& rRight ) const
+{
+    if (rLeft.maArea.aStart.Tab() != rRight.maArea.aStart.Tab())
+        return rLeft.maArea.aStart.Tab() < rRight.maArea.aStart.Tab();
+
+    if (rLeft.maArea.aStart.Col() != rRight.maArea.aStart.Col())
+        return rLeft.maArea.aStart.Col() < rRight.maArea.aStart.Col();
+
+    if (rLeft.maArea.aStart.Row() != rRight.maArea.aStart.Row())
+        return rLeft.maArea.aStart.Row() < rRight.maArea.aStart.Row();
+
+    if (rLeft.maArea.aEnd.Tab() != rRight.maArea.aEnd.Tab())
+        return rLeft.maArea.aEnd.Tab() < rRight.maArea.aEnd.Tab();
+
+    if (rLeft.maArea.aEnd.Col() != rRight.maArea.aEnd.Col())
+        return rLeft.maArea.aEnd.Col() < rRight.maArea.aEnd.Col();
+
+    return rLeft.maArea.aEnd.Row() < rRight.maArea.aEnd.Row();
+}
+
+}
+
 struct ScSlotData
 {
     SCROW  nStartRow;   // first row of this segment
diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx
index b9eb32b..8a69d12 100644
--- a/sc/source/core/data/cellvalue.cxx
+++ b/sc/source/core/data/cellvalue.cxx
@@ -440,7 +440,7 @@ void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos )
     mfValue = 0.0;
 }
 
-void ScCellValue::release( ScColumn& rColumn, SCROW nRow )
+void ScCellValue::release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType )
 {
     switch (meType)
     {
@@ -460,7 +460,7 @@ void ScCellValue::release( ScColumn& rColumn, SCROW nRow )
         break;
         case CELLTYPE_FORMULA:
             // This formula cell instance is directly placed in the document without copying.
-            rColumn.SetFormulaCell(nRow, mpFormula);
+            rColumn.SetFormulaCell(nRow, mpFormula, eListenType);
         break;
         default:
             rColumn.Delete(nRow);
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index 5fd08da..8300327 100644
--- a/sc/source/core/data/clipcontext.cxx
+++ b/sc/source/core/data/clipcontext.cxx
@@ -327,9 +327,21 @@ bool CopyToClipContext::isCloneNotes() const
     return mbCloneNotes;
 }
 
-CopyToDocContext::CopyToDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {}
+CopyToDocContext::CopyToDocContext(ScDocument& rDoc) :
+    ClipContextBase(rDoc), mbStartListening(true) {}
+
 CopyToDocContext::~CopyToDocContext() {}
 
+void CopyToDocContext::setStartListening( bool b )
+{
+    mbStartListening = b;
+}
+
+bool CopyToDocContext::isStartListening() const
+{
+    return mbStartListening;
+}
+
 MixDocContext::MixDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {}
 MixDocContext::~MixDocContext() {}
 
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index c0e2991..d953230 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1232,6 +1232,8 @@ class CopyAsLinkHandler
     sc::ColumnBlockPosition* mpDestPos;
     InsertDeleteFlags mnCopyFlags;
 
+    sc::StartListeningType meListenType;
+
     void setDefaultAttrToDest(size_t nRow)
     {
         maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
@@ -1263,7 +1265,7 @@ class CopyAsLinkHandler
         for (size_t i = 0; i < nDataSize; ++i)
         {
             SCROW nRow = nTopRow + i;
-            mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow));
+            mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow), meListenType);
         }
 
         setDefaultAttrsToDest(nTopRow, nDataSize);
@@ -1276,7 +1278,11 @@ class CopyAsLinkHandler
 
 public:
     CopyAsLinkHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, InsertDeleteFlags nCopyFlags) :
-        mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mnCopyFlags(nCopyFlags)
+        mrSrcCol(rSrcCol),
+        mrDestCol(rDestCol),
+        mpDestPos(pDestPos),
+        mnCopyFlags(nCopyFlags),
+        meListenType(sc::SingleCellListening)
     {
         if (mpDestPos)
             maDestPos = *mpDestPos;
@@ -1288,6 +1294,11 @@ public:
             *mpDestPos = maDestPos;
     }
 
+    void setStartListening( bool b )
+    {
+        meListenType = b ? sc::SingleCellListening : sc::NoListening;
+    }
+
     void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
     {
         size_t nRow = aNode.position + nOffset;
@@ -1353,6 +1364,8 @@ class CopyByCloneHandler
     svl::SharedStringPool* mpSharedStringPool;
     InsertDeleteFlags mnCopyFlags;
 
+    sc::StartListeningType meListenType;
+
     void setDefaultAttrToDest(size_t nRow)
     {
         maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
@@ -1396,7 +1409,7 @@ class CopyByCloneHandler
             // Clone as formula cell.
             ScFormulaCell* pCell = new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos);
             pCell->SetDirtyVar();
-            mrDestCol.SetFormulaCell(maDestPos, nRow, pCell);
+            mrDestCol.SetFormulaCell(maDestPos, nRow, pCell, meListenType);
             setDefaultAttrToDest(nRow);
             return;
         }
@@ -1412,7 +1425,7 @@ class CopyByCloneHandler
                 // error codes are cloned with values
                 ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
                 pErrCell->SetErrCode(nErr);
-                mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell);
+                mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell, meListenType);
                 setDefaultAttrToDest(nRow);
                 return;
             }
@@ -1466,8 +1479,12 @@ class CopyByCloneHandler
 public:
     CopyByCloneHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos,
             InsertDeleteFlags nCopyFlags, svl::SharedStringPool* pSharedStringPool) :
-        mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mpSharedStringPool(pSharedStringPool),
-        mnCopyFlags(nCopyFlags)
+        mrSrcCol(rSrcCol),
+        mrDestCol(rDestCol),
+        mpDestPos(pDestPos),
+        mpSharedStringPool(pSharedStringPool),
+        mnCopyFlags(nCopyFlags),
+        meListenType(sc::SingleCellListening)
     {
         if (mpDestPos)
             maDestPos = *mpDestPos;
@@ -1479,6 +1496,11 @@ public:
             *mpDestPos = maDestPos;
     }
 
+    void setStartListening( bool b )
+    {
+        meListenType = b ? sc::SingleCellListening : sc::NoListening;
+    }
+
     void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
     {
         size_t nRow = aNode.position + nOffset;
@@ -1642,6 +1664,7 @@ void ScColumn::CopyToColumn(
         if (bAsLink)
         {
             CopyAsLinkHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags);
+            aFunc.setStartListening(rCxt.isStartListening());
             sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
         }
         else
@@ -1653,6 +1676,7 @@ void ScColumn::CopyToColumn(
                 &rColumn.pDocument->GetSharedStringPool() : NULL;
             CopyByCloneHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags,
                     pSharedStringPool);
+            aFunc.setStartListening(rCxt.isStartListening());
             sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
         }
 
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index ae58aec..803bd35 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -377,13 +377,15 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreTy
 }
 
 void ScColumn::AttachNewFormulaCell(
-    const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, bool bJoin, bool bSingle )
+    const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell,
+    bool bJoin, sc::StartListeningType eListenType )
 {
-    AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin, bSingle);
+    AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin, eListenType);
 }
 
 void ScColumn::AttachNewFormulaCell(
-    const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, bool bJoin, bool bSingle )
+    const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
+    bool bJoin, sc::StartListeningType eListenType )
 {
     if (bJoin)
         // See if this new formula cell can join an existing shared formula group.
@@ -394,9 +396,12 @@ void ScColumn::AttachNewFormulaCell(
     // we call StartListeningFromClip and BroadcastFromClip.
     // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
     // After Import we call CalcAfterLoad and in there Listening.
-    if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc())
+    if (pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc())
+        return;
+
+    switch (eListenType)
     {
-        if (bSingle)
+        case sc::ConvertToGroupListening:
         {
             boost::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*pDocument));
             sc::StartListeningContext aStartCxt(*pDocument, pPosSet);
@@ -404,12 +409,18 @@ void ScColumn::AttachNewFormulaCell(
             SCROW nRow = aPos.first->position + aPos.second;
             StartListeningFormulaCells(aStartCxt, aEndCxt, nRow, nRow);
         }
-        else
+        break;
+        case sc::SingleCellListening:
             rCell.StartListeningTo(pDocument);
+        break;
+        case sc::NoListening:
+        default:
+            ;
 
-        if (!pDocument->IsCalcingAfterLoad())
-            rCell.SetDirty();
     }
+
+    if (!pDocument->IsCalcingAfterLoad())
+        rCell.SetDirty();
 }
 
 void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength )
@@ -1734,7 +1745,10 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString,
 
     ScCellValue aNewCell;
     bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam);
-    aNewCell.release(*this, nRow);
+    if (pParam)
+        aNewCell.release(*this, nRow, pParam->meStartListening);
+    else
+        aNewCell.release(*this, nRow);
 
     // Do not set Formats and Formulas here anymore!
     // These are queried during output
@@ -1834,7 +1848,8 @@ void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::Formul
     AttachNewFormulaCell(it, nRow, *pCell);
 }
 
-ScFormulaCell* ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell, bool bSingle )
+ScFormulaCell* ScColumn::SetFormulaCell(
+    SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType )
 {
     sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
     sal_uInt32 nCellFormat = GetNumberFormat(nRow);
@@ -1845,11 +1860,13 @@ ScFormulaCell* ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell, bool
 
     CellStorageModified();
 
-    AttachNewFormulaCell(it, nRow, *pCell, true, bSingle);
+    AttachNewFormulaCell(it, nRow, *pCell, true, eListenType);
     return pCell;
 }
 
-ScFormulaCell* ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell )
+ScFormulaCell* ScColumn::SetFormulaCell(
+    sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell,
+    sc::StartListeningType eListenType )
 {
     rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
     sal_uInt32 nCellFormat = GetNumberFormat(nRow);
@@ -1861,7 +1878,7 @@ ScFormulaCell* ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCR
 
     CellStorageModified();
 
-    AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell);
+    AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, true, eListenType);
     return pCell;
 }
 
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 42d166a..ab804dd 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -1240,8 +1240,6 @@ public:
     {
         return mnEndRow;
     }
-
-private:
 };
 
 class EndListeningFormulaCellsHandler
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index a206c09..660b394 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1960,8 +1960,8 @@ void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
     PutInOrder( nTab1, nTab2 );
     if (ValidTab(nTab1) && ValidTab(nTab2))
     {
-        bool bOldAutoCalc = pDestDoc->GetAutoCalc();
-        pDestDoc->SetAutoCalc( false );     // avoid multiple calculations
+        sc::AutoCalcSwitch aACSwitch(*pDestDoc, false); // avoid multiple calculations
+
         if (nTab1 > 0)
             CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
 
@@ -1976,7 +1976,6 @@ void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
 
         if (nTab2 < MAXTAB)
             CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, false, pDestDoc, pMarks );
-        pDestDoc->SetAutoCalc( bOldAutoCalc );
     }
 }
 
@@ -1989,21 +1988,26 @@ void ScDocument::CopyToDocument(const ScRange& rRange,
 
     if( pDestDoc->aDocName.isEmpty() )
         pDestDoc->aDocName = aDocName;
-    bool bOldAutoCalc = pDestDoc->GetAutoCalc();
-    pDestDoc->SetAutoCalc( false );     // avoid multiple calculations
+
+    sc::AutoCalcSwitch aACSwitch(*pDestDoc, false); // avoid multiple calculations
+
     sc::CopyToDocContext aCxt(*pDestDoc);
+    aCxt.setStartListening(false);
+
     SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pDestDoc->maTabs.size()));
     for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab() && i < nMinSizeBothTabs; i++)
     {
-        if (!TableExists(i) || !pDestDoc->TableExists(i))
+        ScTable* pTab = FetchTable(i);
+        ScTable* pDestTab = pDestDoc->FetchTable(i);
+        if (!pTab || !pDestTab)
             continue;
 
-        maTabs[i]->CopyToTable(aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(),
-                               aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
-                               nFlags, bOnlyMarked, pDestDoc->maTabs[i],
-                               pMarks, false, bColRowFlags);
+        pTab->CopyToTable(
+            aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
+            nFlags, bOnlyMarked, pDestTab, pMarks, false, bColRowFlags);
     }
-    pDestDoc->SetAutoCalc( bOldAutoCalc );
+
+    pDestDoc->StartAllListeners(aNewRange);
 }
 
 void ScDocument::UndoToDocument(const ScRange& rRange,
@@ -2452,7 +2456,7 @@ void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
         ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
         for (; itr != itrEnd && *itr < nMax; ++itr)
             if (maTabs[*itr])
-                maTabs[*itr]->StartListeningFromClip(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2);
+                maTabs[*itr]->StartListeningFormulaCells(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2);
     }
 }
 
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index d1b4168..c01b264 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -423,4 +423,38 @@ void ScDocument::StartNeededListeners()
     std::for_each(maTabs.begin(), maTabs.end(), StartNeededListenersHandler(*this));
 }
 
+void ScDocument::StartAllListeners( const ScRange& rRange )
+{
+    boost::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*this));
+    sc::StartListeningContext aStartCxt(*this, pPosSet);
+    sc::EndListeningContext aEndCxt(*this, pPosSet);
+
+    for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
+    {
+        ScTable* pTab = FetchTable(nTab);
+        if (!pTab)
+            continue;
+
+        pTab->StartListeningFormulaCells(
+            aStartCxt, aEndCxt,
+            rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
+    }
+}
+
+void ScDocument::EndAllListeners( const ScRange& rRange )
+{
+    sc::EndListeningContext aEndCxt(*this);
+
+    for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
+    {
+        ScTable* pTab = FetchTable(nTab);
+        if (!pTab)
+            continue;
+
+        pTab->EndListeningFormulaCells(
+            aEndCxt,
+            rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index dfeda72..a34d3fb 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -61,6 +61,7 @@
 #include <grouparealistener.hxx>
 
 #include <boost/scoped_ptr.hpp>
+#include <boost/ptr_container/ptr_map.hpp>
 
 using namespace formula;
 
@@ -382,6 +383,40 @@ void adjustDBRange(formula::FormulaToken* pToken, ScDocument& rNewDoc, const ScD
     pToken->SetIndex(pNewDBData->GetIndex());
 }
 
+struct AreaListenerKey
+{
+    ScRange maRange;
+    bool mbStartFixed;
+    bool mbEndFixed;
+
+    AreaListenerKey( const ScRange& rRange, bool bStartFixed, bool bEndFixed ) :
+        maRange(rRange), mbStartFixed(bStartFixed), mbEndFixed(bEndFixed) {}
+
+    bool operator < ( const AreaListenerKey& r ) const
+    {
+        if (maRange.aStart.Tab() != r.maRange.aStart.Tab())
+            return maRange.aStart.Tab() < r.maRange.aStart.Tab();
+        if (maRange.aStart.Col() != r.maRange.aStart.Col())
+            return maRange.aStart.Col() < r.maRange.aStart.Col();
+        if (maRange.aStart.Row() != r.maRange.aStart.Row())
+            return maRange.aStart.Row() < r.maRange.aStart.Row();
+        if (maRange.aEnd.Tab() != r.maRange.aEnd.Tab())
+            return maRange.aEnd.Tab() < r.maRange.aEnd.Tab();
+        if (maRange.aEnd.Col() != r.maRange.aEnd.Col())
+            return maRange.aEnd.Col() < r.maRange.aEnd.Col();
+        if (maRange.aEnd.Row() != r.maRange.aEnd.Row())
+            return maRange.aEnd.Row() < r.maRange.aEnd.Row();
+        if (mbStartFixed != r.mbStartFixed)
+            return r.mbStartFixed;
+        if (mbEndFixed != r.mbEndFixed)
+            return r.mbEndFixed;
+
+        return false;
+    }
+};
+
+typedef boost::ptr_map<AreaListenerKey, sc::FormulaGroupAreaListener> AreaListenersType;
+
 }
 
 #if ENABLE_THREADED_OPENCL_KERNEL_COMPILATION
@@ -406,7 +441,13 @@ int ScFormulaCellGroup::snCount = 0;
 rtl::Reference<sc::CLBuildKernelThread> ScFormulaCellGroup::sxCompilationThread;
 #endif
 
+struct ScFormulaCellGroup::Impl
+{
+    AreaListenersType maAreaListeners;
+};
+
 ScFormulaCellGroup::ScFormulaCellGroup() :
+    mpImpl(new Impl),
     mnRefCount(0),
     mpCode(NULL),
     mpCompiledFormula(NULL),
@@ -450,6 +491,7 @@ ScFormulaCellGroup::~ScFormulaCellGroup()
 #endif
     delete mpCode;
     delete mpCompiledFormula;
+    delete mpImpl;
 }
 
 void ScFormulaCellGroup::scheduleCompilation()
@@ -512,24 +554,29 @@ void ScFormulaCellGroup::compileOpenCLKernel()
 sc::FormulaGroupAreaListener* ScFormulaCellGroup::getAreaListener(
     ScFormulaCell** ppTopCell, const ScRange& rRange, bool bStartFixed, bool bEndFixed )
 {
-    // TODO : Find existing one with the same criteria.
-    maAreaListeners.push_back(new sc::FormulaGroupAreaListener(rRange, ppTopCell, mnLength, bStartFixed, bEndFixed));
-    return &maAreaListeners.back();
+    AreaListenerKey aKey(rRange, bStartFixed, bEndFixed);
+
+    std::pair<AreaListenersType::iterator, bool> r =
+        mpImpl->maAreaListeners.insert(
+            aKey, new sc::FormulaGroupAreaListener(
+                rRange, ppTopCell, mnLength, bStartFixed, bEndFixed));
+
+    return r.first->second;
 }
 
 void ScFormulaCellGroup::endAllGroupListening( ScDocument& rDoc )
 {
-    AreaListenersType::iterator it = maAreaListeners.begin(), itEnd = maAreaListeners.end();
+    AreaListenersType::iterator it = mpImpl->maAreaListeners.begin(), itEnd = mpImpl->maAreaListeners.end();
     for (; it != itEnd; ++it)
     {
-        sc::FormulaGroupAreaListener* pListener = &(*it);
+        sc::FormulaGroupAreaListener* pListener = it->second;
         ScRange aListenRange = pListener->getListeningRange();
         // This "always listen" special range is never grouped.
         bool bGroupListening = (aListenRange != BCA_LISTEN_ALWAYS);
         rDoc.EndListeningArea(aListenRange, bGroupListening, pListener);
     }
 
-    maAreaListeners.clear();
+    mpImpl->maAreaListeners.clear();
 }
 
 ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos ) :
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 9735542..608ec13 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1057,7 +1057,7 @@ void ScTable::SetDirtyFromClip(
             aCol[i].SetDirtyFromClip(nRow1, nRow2, rBroadcastSpans);
 }
 
-void ScTable::StartListeningFromClip(
+void ScTable::StartListeningFormulaCells(
     sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt,
     SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
 {
@@ -1068,6 +1068,16 @@ void ScTable::StartListeningFromClip(
             aCol[i].StartListeningFormulaCells(rStartCxt, rEndCxt, nRow1, nRow2);
 }
 
+void ScTable::EndListeningFormulaCells(
+    sc::EndListeningContext& rEndCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+    if (nCol2 > MAXCOL) nCol2 = MAXCOL;
+    if (nRow2 > MAXROW) nRow2 = MAXROW;
+    if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+        for (SCCOL i = nCol1; i <= nCol2; ++i)
+            aCol[i].EndListeningFormulaCells(rEndCxt, nRow1, nRow2);
+}
+
 void ScTable::CopyToTable(
     sc::CopyToDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     InsertDeleteFlags nFlags, bool bMarked, ScTable* pDestTab, const ScMarkData* pMarkData,
@@ -1413,7 +1423,7 @@ ScFormulaCell* ScTable::SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* p
         return NULL;
     }
 
-    return aCol[nCol].SetFormulaCell(nRow, pCell, true);
+    return aCol[nCol].SetFormulaCell(nRow, pCell, sc::ConvertToGroupListening);
 }
 
 bool ScTable::SetFormulaCells( SCCOL nCol, SCROW nRow, std::vector<ScFormulaCell*>& rCells )
diff --git a/sc/source/core/inc/bcaslot.hxx b/sc/source/core/inc/bcaslot.hxx
index 63e5a6b..7eea136 100644
--- a/sc/source/core/inc/bcaslot.hxx
+++ b/sc/source/core/inc/bcaslot.hxx
@@ -40,6 +40,11 @@ struct AreaListener
     ScRange maArea;
     bool mbGroupListening;
     SvtListener* mpListener;
+
+    struct SortByArea : std::binary_function<AreaListener, AreaListener, bool>
+    {
+        bool operator() ( const AreaListener& rLeft, const AreaListener& rRight ) const;
+    };
 };
 
 }
diff --git a/sc/source/core/tool/grouparealistener.cxx b/sc/source/core/tool/grouparealistener.cxx
index e93d2fc..4a13398 100644
--- a/sc/source/core/tool/grouparealistener.cxx
+++ b/sc/source/core/tool/grouparealistener.cxx
@@ -219,18 +219,31 @@ void FormulaGroupAreaListener::collectFormulaCells(
     }
 }
 
-#if DEBUG_AREA_BROADCASTER
 ScAddress FormulaGroupAreaListener::getTopCellPos() const
 {
     const ScFormulaCell& rFC = **mppTopCell;
     return rFC.aPos;
 }
 
+const ScRange& FormulaGroupAreaListener::getRange() const
+{
+    return maRange;
+}
+
 SCROW FormulaGroupAreaListener::getGroupLength() const
 {
     return mnGroupLen;
 }
-#endif
+
+bool FormulaGroupAreaListener::isStartFixed() const
+{
+    return mbStartFixed;
+}
+
+bool FormulaGroupAreaListener::isEndFixed() const
+{
+    return mbEndFixed;
+}
 
 void FormulaGroupAreaListener::notifyCellChange( const SfxHint& rHint, const ScAddress& rPos )
 {
diff --git a/sc/source/core/tool/stringutil.cxx b/sc/source/core/tool/stringutil.cxx
index ce83c33..158b54f 100644
--- a/sc/source/core/tool/stringutil.cxx
+++ b/sc/source/core/tool/stringutil.cxx
@@ -29,7 +29,8 @@ ScSetStringParam::ScSetStringParam() :
     mpNumFormatter(NULL),
     mbDetectNumberFormat(true),
     meSetTextNumFormat(Never),
-    mbHandleApostrophe(true)
+    mbHandleApostrophe(true),
+    meStartListening(sc::SingleCellListening)
 {
 }
 
diff --git a/sc/source/ui/undo/refundo.cxx b/sc/source/ui/undo/refundo.cxx
index 623e7b6..a5c3854 100644
--- a/sc/source/ui/undo/refundo.cxx
+++ b/sc/source/ui/undo/refundo.cxx
@@ -35,28 +35,36 @@
 #include <refupdatecontext.hxx>
 
 ScRefUndoData::ScRefUndoData( const ScDocument* pDoc ) :
-    pUnoRefs( NULL )
+    pDBCollection(NULL),
+    pRangeName(NULL),
+    pPrintRanges(pDoc->CreatePrintRangeSaver()),
+    pDPCollection(NULL),
+    pDetOpList(NULL),
+    pChartListenerCollection(NULL),
+    pAreaLinks(NULL),
+    pUnoRefs(NULL)
 {
-    ScDBCollection* pOldDBColl = pDoc->GetDBCollection();
-    pDBCollection = pOldDBColl ? new ScDBCollection(*pOldDBColl) : NULL;
+    const ScDBCollection* pOldDBColl = pDoc->GetDBCollection();
+    if (pOldDBColl && !pOldDBColl->empty())
+        pDBCollection = new ScDBCollection(*pOldDBColl);
 
-    ScRangeName* pOldRanges = ((ScDocument*)pDoc)->GetRangeName();          //! const
-    pRangeName = pOldRanges ? new ScRangeName(*pOldRanges) : NULL;
-
-    pPrintRanges = pDoc->CreatePrintRangeSaver();       // recreated
+    const ScRangeName* pOldRanges = pDoc->GetRangeName();
+    if (pOldRanges && !pOldRanges->empty())
+        pRangeName = new ScRangeName(*pOldRanges);
 
     // when handling Pivot solely keep the range?
 
-    ScDPCollection* pOldDP = ((ScDocument*)pDoc)->GetDPCollection();        //! const
-    pDPCollection = pOldDP ? new ScDPCollection(*pOldDP) : NULL;
+    const ScDPCollection* pOldDP = pDoc->GetDPCollection();
+    if (pOldDP && pOldDP->GetCount())
+        pDPCollection = new ScDPCollection(*pOldDP);
 
-    ScDetOpList* pOldDetOp = pDoc->GetDetOpList();
-    pDetOpList = pOldDetOp ? new ScDetOpList(*pOldDetOp) : 0;
+    const ScDetOpList* pOldDetOp = pDoc->GetDetOpList();
+    if (pOldDetOp && pOldDetOp->Count())
+        pDetOpList = new ScDetOpList(*pOldDetOp);
 
-    ScChartListenerCollection* pOldChartListenerCollection =
-        pDoc->GetChartListenerCollection();
-    pChartListenerCollection = pOldChartListenerCollection ?
-        new ScChartListenerCollection( *pOldChartListenerCollection ) : NULL;
+    const ScChartListenerCollection* pOldChartLisColl = pDoc->GetChartListenerCollection();
+    if (pOldChartLisColl)
+        pChartListenerCollection = new ScChartListenerCollection(*pOldChartLisColl);
 
     pAreaLinks = ScAreaLinkSaveCollection::CreateFromDoc(pDoc);     // returns NULL if empty
 
diff --git a/svl/source/notify/broadcast.cxx b/svl/source/notify/broadcast.cxx
index c0dfe4f..8399a79 100644
--- a/svl/source/notify/broadcast.cxx
+++ b/svl/source/notify/broadcast.cxx
@@ -21,7 +21,7 @@
 #include <svl/listener.hxx>
 #include <svl/smplhint.hxx>
 
-void SvtBroadcaster::Normalize()
+void SvtBroadcaster::Normalize() const
 {
     if (!mbNormalized)
     {
@@ -140,11 +140,13 @@ void SvtBroadcaster::ListenersGone() {}
 
 SvtBroadcaster::ListenersType& SvtBroadcaster::GetAllListeners()
 {
+    Normalize();
     return maListeners;
 }
 
 const SvtBroadcaster::ListenersType& SvtBroadcaster::GetAllListeners() const
 {
+    Normalize();
     return maListeners;
 }
 


More information about the Libreoffice-commits mailing list