[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - 3 commits - sc/inc sc/Library_sc.mk sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Mon May 13 18:26:57 PDT 2013


 sc/Library_sc.mk                        |    2 
 sc/inc/column.hxx                       |    3 
 sc/inc/columnspanset.hxx                |   53 ++++++++++++++
 sc/inc/document.hxx                     |    7 +
 sc/inc/formulacell.hxx                  |    7 +
 sc/inc/listenercontext.hxx              |   38 ++++++++++
 sc/inc/refdata.hxx                      |    2 
 sc/inc/table.hxx                        |    3 
 sc/source/core/data/column2.cxx         |   18 +++++
 sc/source/core/data/column3.cxx         |   18 -----
 sc/source/core/data/columnspanset.cxx   |  115 ++++++++++++++++++++++++++++++++
 sc/source/core/data/documen7.cxx        |   22 ++++++
 sc/source/core/data/document.cxx        |    8 ++
 sc/source/core/data/formulacell.cxx     |   59 ++++++++++++++++
 sc/source/core/data/listenercontext.cxx |   51 ++++++++++++++
 sc/source/core/data/table1.cxx          |    8 ++
 sc/source/core/data/table5.cxx          |    8 ++
 sc/source/core/tool/refdata.cxx         |   11 +++
 18 files changed, 418 insertions(+), 15 deletions(-)

New commits:
commit f0032ca881efd4b3b38da5e8db5830d6c258a304
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 13 21:25:38 2013 -0400

    Keep track of empty broadcaster segments, and delete them all in one go.
    
    This massively speeds up the deletion of a large group of adjacent formula
    cells. As an example, on machine, deletion of formula cells over B2:B109101
    (109100 cells in total) got reduced from 4.7 seconds to 0.09 seconds).
    
    Change-Id: Ib72da42a6644421601111907cf7c899d828c2996

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index deb9b285..6f322ee 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -95,6 +95,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
 	sc/source/core/data/column2 \
 	sc/source/core/data/column3 \
 	sc/source/core/data/columniterator \
+	sc/source/core/data/columnspanset \
 	sc/source/core/data/compressedarray \
 	sc/source/core/data/colorscale \
 	sc/source/core/data/conditio \
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 8895031..9ee830b 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -474,6 +474,7 @@ public:
 
     SvtBroadcaster* GetBroadcaster( SCROW nRow );
     const SvtBroadcaster* GetBroadcaster( SCROW nRow ) const;
+    void DeleteBroadcasters( SCROW nRow1, SCROW nRow2 );
 
 private:
     void DeleteRange(
diff --git a/sc/inc/columnspanset.hxx b/sc/inc/columnspanset.hxx
new file mode 100644
index 0000000..afd1797
--- /dev/null
+++ b/sc/inc/columnspanset.hxx
@@ -0,0 +1,53 @@
+/* -*- 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_COLUMNSPANSET_HXX
+#define SC_COLUMNSPANSET_HXX
+
+#include "address.hxx"
+
+#include <vector>
+#include <mdds/flat_segment_tree.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace sc {
+
+/**
+ * Structure that stores segments of boolean flags per column, and perform
+ * custom action on those segments.
+ */
+class ColumnSpanSet : boost::noncopyable
+{
+    typedef mdds::flat_segment_tree<SCROW, bool> ColumnSpansType;
+    typedef std::vector<ColumnSpansType*> TableType;
+    typedef std::vector<TableType*> DocType;
+
+    DocType maDoc;
+
+public:
+    class Action
+    {
+    public:
+        virtual ~Action() = 0;
+        virtual void execute(const ScAddress& rPos, SCROW nLength, bool bVal) = 0;
+    };
+
+    ~ColumnSpanSet();
+
+    void set(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bVal);
+
+    void executeFromTop(Action& ac) const;
+    void executeFromBottom(Action& ac) const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index eeec349..0c59a67 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1958,6 +1958,7 @@ public:
 
     SvtBroadcaster* GetBroadcaster( const ScAddress& rPos );
     const SvtBroadcaster* GetBroadcaster( const ScAddress& rPos ) const;
+    void DeleteBroadcasters( const ScAddress& rTopPos, SCROW nLength );
 
 private: // CLOOK-Impl-methods
 
diff --git a/sc/inc/listenercontext.hxx b/sc/inc/listenercontext.hxx
index 5846713..2fc55a7 100644
--- a/sc/inc/listenercontext.hxx
+++ b/sc/inc/listenercontext.hxx
@@ -11,14 +11,18 @@
 #define SC_LISTENERCONTEXT_HXX
 
 #include "address.hxx"
+#include "columnspanset.hxx"
+
+#include <boost/noncopyable.hpp>
 
 class ScDocument;
 
 namespace sc {
 
-class EndListeningContext
+class EndListeningContext : boost::noncopyable
 {
     ScDocument& mrDoc;
+    ColumnSpanSet maSet;
 public:
     EndListeningContext(ScDocument& rDoc);
     ScDocument& getDoc();
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index f805cf4..543bdc9 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -834,6 +834,7 @@ public:
 
     SvtBroadcaster* GetBroadcaster( SCCOL nCol, SCROW nRow );
     const SvtBroadcaster* GetBroadcaster( SCCOL nCol, SCROW nRow ) const;
+    void DeleteBroadcasters( SCCOL nCol, SCROW nRow1, SCROW nRow2 );
 
     /** Replace behaves differently to the Search; adjust the rCol and rRow accordingly.
 
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index d5dee57..1df0d9d 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1518,6 +1518,11 @@ const SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow) const
     return maBroadcasters.get<SvtBroadcaster*>(nRow);
 }
 
+void ScColumn::DeleteBroadcasters( SCROW nRow1, SCROW nRow2 )
+{
+    maBroadcasters.set_empty(nRow1, nRow2);
+}
+
 sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
 {
     return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnTextWidth;
diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
new file mode 100644
index 0000000..de78539
--- /dev/null
+++ b/sc/source/core/data/columnspanset.cxx
@@ -0,0 +1,115 @@
+/* -*- 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 "columnspanset.hxx"
+#include "stlalgorithm.hxx"
+
+#include <algorithm>
+
+namespace sc {
+
+ColumnSpanSet::Action::~Action() {}
+
+ColumnSpanSet::~ColumnSpanSet()
+{
+    DocType::iterator itTab = maDoc.begin(), itTabEnd = maDoc.end();
+    for (; itTab != itTabEnd; ++itTab)
+    {
+        TableType* pTab = *itTab;
+        if (!pTab)
+            continue;
+
+        std::for_each(pTab->begin(), pTab->end(), ScDeleteObjectByPtr<ColumnSpansType>());
+        delete pTab;
+    }
+}
+
+void ColumnSpanSet::set(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bVal)
+{
+    if (!ValidTab(nTab) || !ValidCol(nCol) || !ValidRow(nRow))
+        return;
+
+    if (static_cast<size_t>(nTab) >= maDoc.size())
+        maDoc.resize(nTab+1, NULL);
+
+    if (!maDoc[nTab])
+        maDoc[nTab] = new TableType;
+
+    TableType& rTab = *maDoc[nTab];
+    if (static_cast<size_t>(nCol) >= rTab.size())
+        rTab.resize(nCol+1, NULL);
+
+    if (!rTab[nCol])
+        rTab[nCol] = new ColumnSpansType(0, MAXROW+1, false);
+
+    ColumnSpansType& rCol = *rTab[nCol];
+    rCol.insert_back(nRow, nRow+1, bVal);
+}
+
+void ColumnSpanSet::executeFromTop(Action& ac) const
+{
+    for (size_t nTab = 0; nTab < maDoc.size(); ++nTab)
+    {
+        if (!maDoc[nTab])
+            continue;
+
+        const TableType& rTab = *maDoc[nTab];
+        for (size_t nCol = 0; nCol < rTab.size(); ++nCol)
+        {
+            if (!rTab[nCol])
+                continue;
+
+            ColumnSpansType& rCol = *rTab[nCol];
+            ColumnSpansType::const_iterator it = rCol.begin(), itEnd = rCol.end();
+            SCROW nRow1, nRow2;
+            nRow1 = it->first;
+            for (++it; it != itEnd; ++it)
+            {
+                nRow2 = it->first-1;
+                bool bVal = it->second;
+                ac.execute(ScAddress(nCol, nRow1, nTab), nRow2-nRow1+1, bVal);
+
+                nRow1 = nRow2+1; // for the next iteration.
+            }
+        }
+    }
+}
+
+void ColumnSpanSet::executeFromBottom(Action& ac) const
+{
+    for (size_t nTab = 0; nTab < maDoc.size(); ++nTab)
+    {
+        if (!maDoc[nTab])
+            continue;
+
+        const TableType& rTab = *maDoc[nTab];
+        for (size_t nCol = 0; nCol < rTab.size(); ++nCol)
+        {
+            if (!rTab[nCol])
+                continue;
+
+            ColumnSpansType& rCol = *rTab[nCol];
+            ColumnSpansType::const_reverse_iterator it = rCol.rbegin(), itEnd = rCol.rend();
+            SCROW nRow1, nRow2;
+            nRow2 = it->first-1;
+            for (++it; it != itEnd; ++it)
+            {
+                nRow1 = it->first;
+                bool bVal = it->second;
+                ac.execute(ScAddress(nCol, nRow1, nTab), nRow2-nRow1+1, bVal);
+
+                nRow2 = nRow1-1; // for the next iteration.
+            }
+        }
+    }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 8da6a51..3cfdaa6 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2218,6 +2218,14 @@ const SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos ) const
     return maTabs[rPos.Tab()]->GetBroadcaster(rPos.Col(), rPos.Row());
 }
 
+void ScDocument::DeleteBroadcasters( const ScAddress& rTopPos, SCROW nLength )
+{
+    if (!TableExists(rTopPos.Tab()) || nLength <= 0)
+        return;
+
+    maTabs[rTopPos.Tab()]->DeleteBroadcasters(rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
+}
+
 bool ScDocument::TableExists( SCTAB nTab ) const
 {
     return ValidTab(nTab) && static_cast<size_t>(nTab) < maTabs.size() && maTabs[nTab];
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
index 439f09b..4d8afb3 100644
--- a/sc/source/core/data/listenercontext.cxx
+++ b/sc/source/core/data/listenercontext.cxx
@@ -12,6 +12,22 @@
 
 namespace sc {
 
+namespace {
+
+class PurgeAction : public ColumnSpanSet::Action
+{
+    ScDocument& mrDoc;
+public:
+    PurgeAction(ScDocument& rDoc) : mrDoc(rDoc) {}
+    virtual void execute(const ScAddress& rPos, SCROW nLength, bool bVal)
+    {
+        if (bVal)
+            mrDoc.DeleteBroadcasters(rPos, nLength);
+    };
+};
+
+}
+
 EndListeningContext::EndListeningContext(ScDocument& rDoc) : mrDoc(rDoc) {}
 
 ScDocument& EndListeningContext::getDoc()
@@ -21,10 +37,13 @@ ScDocument& EndListeningContext::getDoc()
 
 void EndListeningContext::addEmptyBroadcasterPosition(SCCOL nCol, SCROW nRow, SCTAB nTab)
 {
+    maSet.set(nCol, nRow, nTab, true);
 }
 
 void EndListeningContext::purgeEmptyBroadcasters()
 {
+    PurgeAction aAction(mrDoc);
+    maSet.executeFromBottom(aAction);
 }
 
 }
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 57315b7..4c50eaf 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2168,6 +2168,14 @@ SvtBroadcaster* ScTable::GetBroadcaster( SCCOL nCol, SCROW nRow )
     return aCol[nCol].GetBroadcaster(nRow);
 }
 
+void ScTable::DeleteBroadcasters( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
+{
+    if (!ValidCol(nCol))
+        return;
+
+    aCol[nCol].DeleteBroadcasters(nRow1, nRow2);
+}
+
 const SvtBroadcaster* ScTable::GetBroadcaster( SCCOL nCol, SCROW nRow ) const
 {
     if (!ValidColRow(nCol, nRow))
commit 2a71d6d10d2f8e9e5a2746bac9e7feacea80d9f9
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 13 16:13:46 2013 -0400

    Collect all empty broadcasters and remove them in one go later.
    
    This is to avoid repeated calls to set_empty() on the broadcaster array
    which causes array reallocation on each call. Instead, we can store the
    segments of broadcasters to be deleted later, and call set_empty() on
    those segments to reduce the number of calls to set_empty().
    
    The meat of this is not implemented yet, as EndListeningContext is still
    empty.
    
    Change-Id: I914bc2881acee3902c4fec0f6c21aaf4d2489df8

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index ccd8ebe..deb9b285 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -139,6 +139,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
 	sc/source/core/data/global \
 	sc/source/core/data/global2 \
 	sc/source/core/data/globalx \
+	sc/source/core/data/listenercontext \
 	sc/source/core/data/markarr \
 	sc/source/core/data/markdata \
 	sc/source/core/data/mtvelements \
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 1fe28909..8895031 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -48,6 +48,7 @@ namespace editeng { class SvxBorderLine; }
 
 namespace sc {
     struct FormulaGroupContext;
+    class EndListeningContext;
 }
 
 class Fraction;
@@ -439,6 +440,7 @@ public:
 
     void        StartListening( SvtListener& rLst, SCROW nRow );
     void        EndListening( SvtListener& rLst, SCROW nRow );
+    void EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener );
     void        MoveListeners( SvtBroadcaster& rSource, SCROW nDestRow );
     void        StartAllListeners();
     void        StartNeededListeners(); // only for cells where NeedsListening()==true
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 454cca8..eeec349 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -49,6 +49,7 @@
 namespace editeng { class SvxBorderLine; }
 namespace sc {
     struct FormulaGroupContext;
+    class EndListeningContext;
 }
 class SvxFontItem;
 
@@ -1754,6 +1755,8 @@ public:
     void                EndListeningCell( const ScAddress& rAddress,
                                             SvtListener* pListener );
 
+    void EndListeningCell( sc::EndListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener );
+
     void EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells );
 
     void                PutInFormulaTree( ScFormulaCell* pCell );
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 2d0d04c..e081353 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -28,6 +28,12 @@
 
 #include <set>
 
+namespace sc {
+
+class EndListeningContext;
+
+}
+
 class ScTokenArray;
 struct ScSimilarFormulaDelta;
 
@@ -309,6 +315,7 @@ public:
     void StartListeningTo( ScDocument* pDoc );
     void EndListeningTo(
         ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() );
+    void EndListeningTo( sc::EndListeningContext& rCxt );
 };
 
 #endif
diff --git a/sc/inc/listenercontext.hxx b/sc/inc/listenercontext.hxx
new file mode 100644
index 0000000..5846713
--- /dev/null
+++ b/sc/inc/listenercontext.hxx
@@ -0,0 +1,34 @@
+/* -*- 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_LISTENERCONTEXT_HXX
+#define SC_LISTENERCONTEXT_HXX
+
+#include "address.hxx"
+
+class ScDocument;
+
+namespace sc {
+
+class EndListeningContext
+{
+    ScDocument& mrDoc;
+public:
+    EndListeningContext(ScDocument& rDoc);
+    ScDocument& getDoc();
+
+    void addEmptyBroadcasterPosition(SCCOL nCol, SCROW nRow, SCTAB nTab);
+    void purgeEmptyBroadcasters();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/refdata.hxx b/sc/inc/refdata.hxx
index a19f1df..6d6fe79 100644
--- a/sc/inc/refdata.hxx
+++ b/sc/inc/refdata.hxx
@@ -91,6 +91,8 @@ struct SC_DLLPUBLIC ScSingleRefData        // Single reference (one address) int
     /// In external references nTab is -1
     inline  bool ValidExternal() const;
 
+    ScAddress toAbs( const ScAddress& rPos ) const;
+
             void SmartRelAbs( const ScAddress& rPos );
             void CalcRelFromAbs( const ScAddress& rPos );
             void CalcAbsIfRel( const ScAddress& rPos );
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index c581228..f805cf4 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -49,6 +49,7 @@ namespace com { namespace sun { namespace star {
 
 namespace sc {
     struct FormulaGroupContext;
+    class EndListeningContext;
 }
 
 class SfxItemSet;
@@ -932,6 +933,7 @@ private:
 
     void        StartListening( const ScAddress& rAddress, SvtListener* pListener );
     void        EndListening( const ScAddress& rAddress, SvtListener* pListener );
+    void EndListening( sc::EndListeningContext& rCxt, SCCOL nCol, SCROW nRow, SvtListener& rListener );
     void        StartAllListeners();
     void        StartNeededListeners(); // only for cells where NeedsListening()==TRUE
     void        SetRelNameDirty();
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index cc590e0..d5dee57 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -58,6 +58,7 @@
 #include "tokenarray.hxx"
 #include "globalnames.hxx"
 #include "formulagroup.hxx"
+#include "listenercontext.hxx"
 
 #include <math.h>
 
@@ -1902,6 +1903,18 @@ void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
         maBroadcasters.set_empty(nRow, nRow);
 }
 
+void ScColumn::EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener )
+{
+    SvtBroadcaster* pBC = GetBroadcaster(nRow);
+    if (!pBC)
+        return;
+
+    rListener.EndListening(*pBC);
+    if (!pBC->HasListeners())
+        // There is no more listeners for this cell. Add it to the purge list for later purging.
+        rCxt.addEmptyBroadcasterPosition(nCol, nRow, nTab);
+}
+
 void ScColumn::CompileDBFormula()
 {
     if ( !maItems.empty() )
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
index 6cc51cc..b240633 100644
--- a/sc/source/core/data/documen7.cxx
+++ b/sc/source/core/data/documen7.cxx
@@ -36,6 +36,7 @@
 #include "colorscale.hxx"
 #include "sheetevents.hxx"
 #include "tokenarray.hxx"
+#include "listenercontext.hxx"
 
 #include <tools/shl.hxx>
 
@@ -200,14 +201,26 @@ void ScDocument::EndListeningCell( const ScAddress& rAddress,
         maTabs[nTab]->EndListening( rAddress, pListener );
 }
 
+void ScDocument::EndListeningCell(
+    sc::EndListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
+{
+    if (!TableExists(rPos.Tab()))
+        return;
+
+    maTabs[rPos.Tab()]->EndListening(rCxt, rPos.Col(), rPos.Row(), rListener);
+}
+
 void ScDocument::EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells )
 {
     if (rCells.empty())
         return;
 
+    sc::EndListeningContext aCxt(*this);
     std::vector<ScFormulaCell*>::iterator it = rCells.begin(), itEnd = rCells.end();
     for (; it != itEnd; ++it)
-        (*it)->EndListeningTo(this);
+        (*it)->EndListeningTo(aCxt);
+
+    aCxt.purgeEmptyBroadcasters();
 }
 
 void ScDocument::PutInFormulaTree( ScFormulaCell* pCell )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index cb13563..a91722f 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -44,6 +44,7 @@
 #include "svl/intitem.hxx"
 #include "rtl/strbuf.hxx"
 #include "formulagroup.hxx"
+#include "listenercontext.hxx"
 
 #include <boost/bind.hpp>
 
@@ -3329,4 +3330,62 @@ void ScFormulaCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr,
     }
 }
 
+void ScFormulaCell::EndListeningTo( sc::EndListeningContext& rCxt )
+{
+    if (rCxt.getDoc().IsClipOrUndo() || IsInChangeTrack())
+        return;
+
+    ScDocument& rDoc = rCxt.getDoc();
+    rDoc.SetDetectiveDirty(true);  // It has changed something
+
+    if (pCode->IsRecalcModeAlways())
+    {
+        rDoc.EndListeningArea(BCA_LISTEN_ALWAYS, this);
+        return;
+    }
+
+    pCode->Reset();
+    ScToken* t;
+    while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL )
+    {
+        StackVar eType = t->GetType();
+        ScSingleRefData& rRef1 = t->GetSingleRef();
+        ScSingleRefData& rRef2 = (eType == svDoubleRef ? t->GetDoubleRef().Ref2 : rRef1);
+        switch (eType)
+        {
+            case svSingleRef:
+            {
+                ScAddress aCell = rRef1.toAbs(aPos);
+                if (aCell.IsValid())
+                    rDoc.EndListeningCell(rCxt, aCell, *this);
+            }
+            break;
+            case svDoubleRef:
+            {
+                ScAddress aCell1 = rRef1.toAbs(aPos);
+                ScAddress aCell2 = rRef2.toAbs(aPos);
+                if (aCell1.IsValid() && aCell2.IsValid())
+                {
+                    if (t->GetOpCode() == ocColRowNameAuto)
+                    {   // automagically
+                        if ( rRef1.IsColRel() )
+                        {   // ColName
+                            aCell2.SetRow(MAXROW);
+                        }
+                        else
+                        {   // RowName
+                            aCell2.SetCol(MAXCOL);
+                        }
+                    }
+
+                    rDoc.EndListeningArea(ScRange(aCell1, aCell2), this);
+                }
+            }
+            break;
+            default:
+                ;   // nothing
+        }
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
new file mode 100644
index 0000000..439f09b
--- /dev/null
+++ b/sc/source/core/data/listenercontext.cxx
@@ -0,0 +1,32 @@
+/* -*- 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 "listenercontext.hxx"
+#include "document.hxx"
+
+namespace sc {
+
+EndListeningContext::EndListeningContext(ScDocument& rDoc) : mrDoc(rDoc) {}
+
+ScDocument& EndListeningContext::getDoc()
+{
+    return mrDoc;
+}
+
+void EndListeningContext::addEmptyBroadcasterPosition(SCCOL nCol, SCROW nRow, SCTAB nTab)
+{
+}
+
+void EndListeningContext::purgeEmptyBroadcasters()
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/table5.cxx b/sc/source/core/data/table5.cxx
index f24c56c..9468352 100644
--- a/sc/source/core/data/table5.cxx
+++ b/sc/source/core/data/table5.cxx
@@ -1097,6 +1097,14 @@ void ScTable::EndListening( const ScAddress& rAddress, SvtListener* pListener )
     aCol[rAddress.Col()].EndListening( *pListener, rAddress.Row() );
 }
 
+void ScTable::EndListening( sc::EndListeningContext& rCxt, SCCOL nCol, SCROW nRow, SvtListener& rListener )
+{
+    if (!ValidCol(nCol))
+        return;
+
+    aCol[nCol].EndListening(rCxt, nRow, rListener);
+}
+
 void ScTable::SetPageStyle( const OUString& rName )
 {
     if ( aPageStyle != rName )
diff --git a/sc/source/core/tool/refdata.cxx b/sc/source/core/tool/refdata.cxx
index 8ebcf8e..7277011 100644
--- a/sc/source/core/tool/refdata.cxx
+++ b/sc/source/core/tool/refdata.cxx
@@ -27,6 +27,17 @@ void ScSingleRefData::CalcRelFromAbs( const ScAddress& rPos )
     nRelTab = nTab - rPos.Tab();
 }
 
+ScAddress ScSingleRefData::toAbs( const ScAddress& rPos ) const
+{
+    SCCOL nRetCol = Flags.bColRel ? nRelCol + rPos.Col() : nCol;
+    SCROW nRetRow = Flags.bRowRel ? nRelRow + rPos.Row() : nRow;
+    SCTAB nRetTab = Flags.bTabRel ? nRelTab + rPos.Tab() : nTab;
+
+    if (!ValidCol(nRetCol) || !ValidRow(nRetRow) || !ValidTab(nRetTab))
+        return ScAddress(ScAddress::INITIALIZE_INVALID);
+
+    return ScAddress(nRetCol, nRetRow, nRetTab);
+}
 
 void ScSingleRefData::SmartRelAbs( const ScAddress& rPos )
 {
commit e9bd43ee863aba444bdcbe63bfa6a955bb7bae37
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 13 14:18:17 2013 -0400

    Move this code into ScDocument, for later refactoring.
    
    Change-Id: I4c34cd4b352dfafe7f423ab8e85f0d93c0368349

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index adca7d5..454cca8 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1753,6 +1753,9 @@ public:
                                             SvtListener* pListener );
     void                EndListeningCell( const ScAddress& rAddress,
                                             SvtListener* pListener );
+
+    void EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells );
+
     void                PutInFormulaTree( ScFormulaCell* pCell );
     void                RemoveFromFormulaTree( ScFormulaCell* pCell );
 
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index dc26882..1d5d146 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -331,8 +331,7 @@ void ScColumn::DeleteRange(
         drawing undo. */
 
     // cache all formula cells, they will be deleted at end of this function
-    typedef ::std::vector< ScFormulaCell* > FormulaCellVector;
-    FormulaCellVector aDelCells;
+    std::vector<ScFormulaCell*> aDelCells;
     aDelCells.reserve( nEndIndex - nStartIndex + 1 );
 
     typedef mdds::flat_segment_tree<SCSIZE, bool> RemovedSegments_t;
@@ -437,19 +436,8 @@ void ScColumn::DeleteRange(
         }
     }
 
-    // *** delete all formula cells ***
-    if (!aDelCells.empty())
-    {
-        // First, all cells stop listening, may save unneeded broadcasts and
-        // recalcualtions.
-        // NOTE: this actually may remove ScNoteCell entries from maItems if
-        // the last listener is removed from a broadcaster.
-        for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt )
-        {
-            (*aIt)->EndListeningTo( pDocument );
-            (*aIt)->Delete();
-        }
-    }
+    pDocument->EndListeningFormulaCells(aDelCells);
+    std::for_each(aDelCells.begin(), aDelCells.end(), ScDeleteObjectByPtr<ScFormulaCell>());
 }
 
 void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
index 3a1d635..6cc51cc 100644
--- a/sc/source/core/data/documen7.cxx
+++ b/sc/source/core/data/documen7.cxx
@@ -200,6 +200,15 @@ void ScDocument::EndListeningCell( const ScAddress& rAddress,
         maTabs[nTab]->EndListening( rAddress, pListener );
 }
 
+void ScDocument::EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells )
+{
+    if (rCells.empty())
+        return;
+
+    std::vector<ScFormulaCell*>::iterator it = rCells.begin(), itEnd = rCells.end();
+    for (; it != itEnd; ++it)
+        (*it)->EndListeningTo(this);
+}
 
 void ScDocument::PutInFormulaTree( ScFormulaCell* pCell )
 {


More information about the Libreoffice-commits mailing list