[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - 791 commits - apple_remote/source basctl/source basegfx/source basic/source bean/test boost/boost.3093.warnings.patch boost/boost.libcdr.warnings.patch.1 boost/UnpackedTarball_boost.mk bridges/inc bridges/test canvas/source chart2/CppunitTest_chart2_export.mk chart2/CppunitTest_chart2_exporttest.mk chart2/CppunitTest_chart2_import.mk chart2/CppunitTest_chart2_importtest.mk chart2/Module_chart2.mk chart2/qa chart2/source clucene/UnpackedTarball_clucene.mk codemaker/source comphelper/Library_comphelper.mk comphelper/source config_host/config_vclplug.h.in config_host.mk.in configmgr/source configure.ac connectivity/source cppcanvas/source cppuhelper/qa cppuhelper/source cui/source cui/uiconfig cui/UIConfig_cui.mk dbaccess/JunitTest_dbaccess_complex.mk dbaccess/JunitTest_dbaccess_unoapi.mk dbaccess/Library_dba.mk dbaccess/source desktop/Executable_oosplash.mk desktop/Library_sofficeapp.mk desktop/Package_branding_custom.mk desktop/Package_branding.mk desktop/Package_pagein_install.mk desktop/Package_scripts_install.mk desktop/source desktop/unx dictionaries distro-configs/LibreOfficeAndroid.conf distro-configs/LibreOfficeAndroidX86.conf distro-configs/LibreOfficeLinux.conf distro-configs/LibreOfficeOpenBSD.conf distro-configs/OxygenOfficeLinux.conf download.lst drawinglayer/source dtrans/source editeng/source embeddedobj/test eventattacher/source extensions/qa extensions/source external/wine extras/CustomTarget_autocorr.mk extras/Gallery_arrows.mk extras/Gallery_computers.mk extras/Gallery_diagrams.mk extras/Gallery_education.mk extras/Gallery_environment.mk extras/Gallery_finance.mk extras/Gallery_people.mk extras/Gallery_sound.mk extras/Gallery_symbols.mk extras/Gallery_transportation.mk extras/Gallery_txtshapes.mk extras/Module_extras.mk extras/Package_autocorr.mk extras/Package_gallmytheme.mk extras/Package_gallsound.mk extras/Package_gallsounds.mk extras/Package_gallsystem.mk extras/READ ME extras/source filter/source forms/source formula/source fpicker/source framework/inc framework/Library_fwk.mk framework/source framework/util harfbuzz/ExternalProject_harfbuzz.mk harfbuzz/harfbuzz-0.9.16-winxp.patch.1 harfbuzz/UnpackedTarball_harfbuzz.mk helpcontent2 i18nlangtag/source i18npool/source icon-themes/galaxy icon-themes/hicontrast icon-themes/tango icu/ExternalProject_icu.mk icu/icu4c-build.patch idlc/Executable_idlc.mk idlc/inc idlc/source include/basegfx include/comphelper include/drawinglayer include/editeng include/filter include/framework include/i18nlangtag include/jvmfwk include/linguistic include/osl include/rtl include/sal include/sfx2 include/shell include/svl include/svtools include/svx include/toolkit include/tools include/unoidl include/unotools include/vcl include/xmloff include/xmlreader instsetoo_native/CustomTarget_install.mk instsetoo_native/Package_config.mk instsetoo_native/Package_rdb.mk instsetoo_native/Package_setup.mk jurt/workbench jvm fwk/distributions jvmfwk/plugins l10ntools/inc l10ntools/source lcms2/ExternalPackage_lcms2.mk libcdr/ExternalPackage_libcdr.mk libcdr/ExternalProject_libcdr.mk libcdr/libcdr-0.0.13.patch libcdr/UnpackedTarball_libcdr.mk libcmis/libcmis-0.3.0.patch liblangtag/liblangtag-0.5.1-unistd.patch liblangtag/UnpackedTarball_langtag.mk libmariadb/mariadb-trunk-40.patch libmspub/ExternalPackage_libmspub.mk libmspub/ExternalProject_libmspub.mk libmwaw/ExternalPackage_libmwaw.mk libmwaw/libmwaw-0.1.7-autotools.patch libmwaw/libmwaw-0.1.8-cctype.patch libmwaw/libmwaw-0.1.9.patch.1 libmwaw/UnpackedTarball_libmwaw.mk Library_urelibs.mk libvisio/ExternalPackage_libvisio.mk libvisio/ExternalProject_libvisio.mk libwpd/ExternalPackage_libwpd.mk libxmlsec/xmlsec1-noverify.patch lingucomponent/source linguistic/inc linguistic/source linguistic/workben lotuswordpro/source Makefile.in moz/ExternalPackage_runtime.mk mysqlc/source nlpsolver/ThirdParty nss/ExternalProject_nss.mk nss/nss-3.13.5-zlib-we rror.patch odk/examples odk/source offapi/com offapi/type_reference offapi/UnoApi_offapi.mk officecfg/Configuration_officecfg.mk officecfg/files.mk officecfg/registry oovbaapi/ooo oox/source openssl/ExternalProject_openssl.mk padmin/Package_padmin.mk padmin/source padmin/uiconfig postprocess/CustomTarget_registry.mk python3/ExternalPackage_python3.mk python3/GeneratedPackage_python3.mk python3/Zip_PythonFramework.mk pyuno/CustomTarget_python_bin.mk pyuno/Package_python_bin.mk pyuno/Package_python_scripts_install.mk pyuno/source qadevOOo/runner qadevOOo/tests README.cross redland/ExternalProject_redland.mk redland/Library_raptor.mk registry/source reportdesign/source RepositoryExternal.mk Repository.mk RepositoryModule_build.mk rhino/OfficeScriptInfo.java ridljar/com rsc/source sal/Library_sal.mk sal/osl sal/qa sax/source sc/AllLangResTarget_sc.mk sc/inc sc/Library_sc.mk scp2/inc scp2/InstallModule_gnome.mk scp2/InstallModule_graphicfilter.mk scp2/InstallModule_ooo.mk scp2/Mo dule_scp2.mk scp2/source sc/qa scripting/Package_scriptproviderforpython.mk scripting/source sc/sdi sc/source sc/uiconfig sc/UIConfig_scalc.mk sc/util sd/CppunitTest_sd_import_tests.mk sd/CppunitTest_sd_regression_test.mk sdext/source sd/inc sd/Library_sd.mk sd/Module_sd.mk sd/qa sd/res sd/sdi sd/source sd/uiconfig sd/util setup_native/source sfx2/AllLangResTarget_sfx2.mk sfx2/doc sfx2/Library_sfx.mk sfx2/README sfx2/sdi sfx2/source sfx2/workben shell/Package_scripts_gnome.mk shell/Package_scripts_kde.mk shell/Package_scripts.mk shell/Package_senddoc.mk slideshow/source solenv/bin solenv/gbuild solenv/inc solenv/Package_gdb_install.mk soltools/Executable_cpp.mk soltools/Executable_makedepend.mk soltools/mkdepend soltools/Module_soltools.mk soltools/Package_inc.mk soltools/winunistd sot/source starmath/inc starmath/Library_sm.mk starmath/sdi starmath/source starmath/uiconfig stoc/source svl/AllLangResTarget_svl.mk svl/CppunitTest_svl_lngmisc.mk svl/Library_svl.mk svl/qa svl/R EADME svl/source svtools/inc svtools/source svx/AllLangResTarget_svx.mk svx/inc svx/Library_svxcore.mk svx/Library_svx.mk svx/sdi svx/source svx/util sw/AllLangResTarget_sw.mk sw/CppunitTest_sw_macros_test.mk swext/mediawiki sw/inc sw/Library_sw.mk sw/qa sw/sdi sw/source sw/uiconfig sw/util sysui/CustomTarget_deb.mk sysui/CustomTarget_rpm.mk sysui/CustomTarget_share.mk sysui/CustomTarget_slackware.mk sysui/CustomTarget_solaris.mk sysui/desktop sysui/Package_desktop.mk sysui/Package_share.mk sysui/productlist.mk TEMPLATE.SOURCECODE.HEADER test/source tomcat/build.xml toolkit/source toolkit/test tools/source translations udkapi/com udkapi/type_reference udkapi/UnoApi_udkapi.mk unodevtools/source unoidl/README unoidl/source unotools/source vcl/aqua vcl/coretext vcl/generic vcl/headless vcl/inc vcl/Library_vcl.mk vcl/Library_vclplug_tde.mk vcl/qa vcl/source vcl/uiconfig vcl/unx vcl/win wizards/com wizards/source writerfilter/source xmloff/source xmlreader/source xmlsecurity/sour ce xmlsecurity/test_docs

Kohei Yoshida kohei.yoshida at gmail.com
Mon May 20 17:27:18 PDT 2013


Rebased ref, commits from common ancestor:
commit f61aa0df67c440f9d201a0b10eccac9729ed7aca
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 19:21:21 2013 -0400

    Rehash the 0.8.1 package due to a last minute oops.
    
    Change-Id: Idea947e8b6674d436cc1a1d92f29279d2c03fc58

diff --git a/download.lst b/download.lst
index fea1f3e..f02392e 100644
--- a/download.lst
+++ b/download.lst
@@ -63,7 +63,7 @@ export LIBXML_TARBALL := 7740a8ec23878a2f50120e1faa2730f2-libxml2-2.7.6.tar.gz
 export LIBXSLT_TARBALL := e61d0364a30146aaa3001296f853b2b9-libxslt-1.1.26.tar.gz
 export LPSOLVE_TARBALL := 26b3e95ddf3d9c077c480ea45874b3b8-lp_solve_5.5.tar.gz
 export MARIADB_TARBALL := 05f84c95b610c21c5fd510d10debcabf-mariadb-native-client-1.0.0.tar.bz2
-export MDDS_TARBALL := 5c7060bfa4ebb77b86026c268e9681fa-mdds_0.8.1.tar.bz2
+export MDDS_TARBALL := 08c85a6d6d793daee14e10e22eefdc4b-mdds_0.8.1.tar.bz2
 export MYSQLCPPCONN_TARBALL := 0981bda6548a8c8233ffce2b6e4b2a23-mysql-connector-c++-1.1.0.tar.gz
 export MYTHES_TARBALL := 46e92b68e31e858512b680b3b61dc4c1-mythes-1.2.3.tar.gz
 export NEON_TARBALL := ff369e69ef0f0143beb5626164e87ae2-neon-0.29.5.tar.gz
commit fc3f0a25661e371f1f561ee21b8ba4c67a1a2173
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 18:23:10 2013 -0400

    We don't need this patch anymore.
    
    Change-Id: Id6b787096d15c40903661fa3d309e8131b655752

diff --git a/mdds/0001-Remove-disambiguation-of-a-integer-type.patch b/mdds/0001-Remove-disambiguation-of-a-integer-type.patch
deleted file mode 100644
index e23d057..0000000
--- a/mdds/0001-Remove-disambiguation-of-a-integer-type.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 46cf3188790b821b359e13b14e2211898ab2139b Mon Sep 17 00:00:00 2001
-From: Kohei Yoshida <kohei.yoshida at gmail.com>
-Date: Thu, 9 May 2013 14:48:41 -0400
-Subject: [PATCH] Remove disambiguation of a integer type.
-
----
- include/mdds/multi_type_vector_def.inl | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/include/mdds/multi_type_vector_def.inl b/include/mdds/multi_type_vector_def.inl
-index 2299a7b..f443e08 100644
---- a/include/mdds/multi_type_vector_def.inl
-+++ misc/build/mdds_0.8.0/include/mdds/multi_type_vector_def.inl
-@@ -1479,7 +1479,7 @@ multi_type_vector<_CellBlockFunc>::transfer_single_block(
- 
-         // Insert two new blocks below current.
-         size_type blk2_size = blk_dest->m_size - dest_pos_in_block - len;
--        dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index+1, 2, NULL);
-+        dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index+1, 2u, NULL);
-         dest.m_blocks[dest_block_index+1] = new block(len);
-         dest.m_blocks[dest_block_index+2] = new block(blk2_size);
-         blk_dest->m_size = dest_pos_in_block;
--- 
-1.8.0
-
diff --git a/mdds/UnpackedTarball_mdds.mk b/mdds/UnpackedTarball_mdds.mk
index 11a6a23..b33bc1b 100644
--- a/mdds/UnpackedTarball_mdds.mk
+++ b/mdds/UnpackedTarball_mdds.mk
@@ -17,7 +17,6 @@ $(eval $(call gb_UnpackedTarball_add_patches,mdds,\
 	mdds/mdds_0.6.0.patch \
 	mdds/0001-Workaround-for-gcc-bug.patch \
 	mdds/mdds_0.7.0_unreachable_warning.patch.1 \
-	mdds/0001-Remove-disambiguation-of-a-integer-type.patch \
 ))
 
 # vim: set noet sw=4 ts=4:
commit 9785579ed0ec8e2e3e826c7e4cbbcaf51f8cb0d4
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 18:19:48 2013 -0400

    Update mdds to 0.8.1.
    
    Change-Id: If6c1a8a88e9996527d3fcf350a00a72a3866ef4f

diff --git a/configure.ac b/configure.ac
index eb83414..10782ff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8046,7 +8046,7 @@ AC_SUBST(SYSTEM_BOOST)
 dnl ===================================================================
 dnl Check for system mdds
 dnl ===================================================================
-libo_CHECK_SYSTEM_MODULE([mdds], [MDDS], [mdds >= 0.8.0])
+libo_CHECK_SYSTEM_MODULE([mdds], [MDDS], [mdds >= 0.8.1])
 
 dnl ===================================================================
 dnl Determine which hash container mdds shall use
diff --git a/download.lst b/download.lst
index 4e0fa28..fea1f3e 100644
--- a/download.lst
+++ b/download.lst
@@ -63,7 +63,7 @@ export LIBXML_TARBALL := 7740a8ec23878a2f50120e1faa2730f2-libxml2-2.7.6.tar.gz
 export LIBXSLT_TARBALL := e61d0364a30146aaa3001296f853b2b9-libxslt-1.1.26.tar.gz
 export LPSOLVE_TARBALL := 26b3e95ddf3d9c077c480ea45874b3b8-lp_solve_5.5.tar.gz
 export MARIADB_TARBALL := 05f84c95b610c21c5fd510d10debcabf-mariadb-native-client-1.0.0.tar.bz2
-export MDDS_TARBALL := b0bba8c768f3d92608a07149039510e5-mdds_0.8.0.tar.bz2
+export MDDS_TARBALL := 5c7060bfa4ebb77b86026c268e9681fa-mdds_0.8.1.tar.bz2
 export MYSQLCPPCONN_TARBALL := 0981bda6548a8c8233ffce2b6e4b2a23-mysql-connector-c++-1.1.0.tar.gz
 export MYTHES_TARBALL := 46e92b68e31e858512b680b3b61dc4c1-mythes-1.2.3.tar.gz
 export NEON_TARBALL := ff369e69ef0f0143beb5626164e87ae2-neon-0.29.5.tar.gz
commit 876504529cf450482b8450ef97fbf1d0a1d1ed67
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 17:24:50 2013 -0400

    Test performance of pasting of formula cells as well.
    
    Undo and redo of this are still a bit slow. Not fast enough to be
    reliably tested.
    
    Change-Id: I0e0b4c16e55bae60f8d7b1db71347a93eb977de8

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 62d6546..59201d4 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -702,6 +702,100 @@ void Test::testPerf()
         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
     }
 
+    clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
+    CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
+    CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
+
+    {
+        // Measure the performance of repeat-pasting 2 adjacent cells to a
+        // large cell range, undoing it, and redoing it.  The bottom one of
+        // the two source cells is empty.  In this scenario, the non-empty
+        // cell is a formula cell referencing a cell to the right, which
+        // inserts a broadcaster to cell it references. So it has a higher
+        // overhead than the previous scenario.
+
+        ScRange aSrcRange(0,0,0,0,1,0); // A1:A2
+
+        ScAddress aPos(0,0,0);
+        m_pDoc->SetString(aPos, "=B1");
+        ScMarkData aMark;
+        aMark.SetMarkArea(aSrcRange);
+
+        // Copy to clipboard.
+        ScDocument aClipDoc(SCDOCMODE_CLIP);
+        ScClipParam aParam(aSrcRange, false);
+        m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
+
+        ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
+        pUndoDoc->InitUndo(m_pDoc, 0, 0);
+        m_pDoc->CopyToDocument(aSrcRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
+
+        // Paste it to A3:A50001, and measure its duration.
+        ScRange aPasteRange(0,2,0,0,50000,0);
+        aMark.SetMarkArea(aPasteRange);
+
+        {
+            MeasureTimeSwitch aTime(diff);
+            m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
+        }
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Pasting took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
+        pRedoDoc->InitUndo(m_pDoc, 0, 0);
+        m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
+
+        // Create an undo object for this.
+        ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
+        ScUndoPaste aUndo(&(*m_xDocShRef), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
+
+        // Make sure it did what it's supposed to do.
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aEnd));
+        ScAddress aTmp = aPasteRange.aStart;
+        aTmp.IncRow();
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aTmp));
+
+#if 0 // TODO: Undo and redo of this scenario is currently not fast enough to be tested reliably.
+        {
+            MeasureTimeSwitch aTime(diff);
+            aUndo.Undo();
+        }
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Undoing took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        // Make sure it's really undone.
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPos));
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
+
+        // Now redo.
+        {
+            MeasureTimeSwitch aTime(diff);
+            aUndo.Redo();
+        }
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Redoing took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        // Make sure it's really redone.
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aEnd));
+#endif
+    }
+
     m_pDoc->DeleteTab(0);
 }
 
commit 1cd034088c8e0d44ba51b3b3b247a05ad309e0ed
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 17:01:12 2013 -0400

    Another performance scenario. Pasting of cells interspersed with empty ones.
    
    Change-Id: Ia03af65dc1daf13e1228cacc20ce931839305ab8

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 3506a29..62d6546 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -535,6 +535,9 @@ void Test::testPerf()
     CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
 
     {
+        // Measure the performance of repeat-pasting a single cell to a large
+        // cell range, undoing it, and redoing it.
+
         ScAddress aPos(0,0,0);
         m_pDoc->SetString(aPos, "test");
         ScMarkData aMark;
@@ -610,6 +613,95 @@ void Test::testPerf()
         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
     }
 
+    clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
+    CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
+    CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
+
+    {
+        // Measure the performance of repeat-pasting 2 adjacent cells to a
+        // large cell range, undoing it, and redoing it.  The bottom one of
+        // the two source cells is empty.
+
+        ScRange aSrcRange(0,0,0,0,1,0); // A1:A2
+
+        ScAddress aPos(0,0,0);
+        m_pDoc->SetValue(aPos, 12);
+        ScMarkData aMark;
+        aMark.SetMarkArea(aSrcRange);
+
+        // Copy to clipboard.
+        ScDocument aClipDoc(SCDOCMODE_CLIP);
+        ScClipParam aParam(aSrcRange, false);
+        m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
+
+        ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
+        pUndoDoc->InitUndo(m_pDoc, 0, 0);
+        m_pDoc->CopyToDocument(aSrcRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
+
+        // Paste it to A3:A100001, and measure its duration.
+        ScRange aPasteRange(0,2,0,0,100000,0);
+        aMark.SetMarkArea(aPasteRange);
+
+        {
+            MeasureTimeSwitch aTime(diff);
+            m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
+        }
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Pasting A1:A2 to A3:A100001 took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
+        pRedoDoc->InitUndo(m_pDoc, 0, 0);
+        m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
+
+        // Create an undo object for this.
+        ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
+        ScUndoPaste aUndo(&(*m_xDocShRef), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
+
+        // Make sure it did what it's supposed to do.
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
+        ScAddress aTmp = aPasteRange.aStart;
+        aTmp.IncRow();
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aTmp));
+
+        {
+            MeasureTimeSwitch aTime(diff);
+            aUndo.Undo();
+        }
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Undoing took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        // Make sure it's really undone.
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE, m_pDoc->GetCellType(aPos));
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
+
+        // Now redo.
+        {
+            MeasureTimeSwitch aTime(diff);
+            aUndo.Redo();
+        }
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Redoing took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        // Make sure it's really redone.
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
+    }
+
     m_pDoc->DeleteTab(0);
 }
 
commit 42855ef3a1c78f8dbd10ab8cad6d3cdbc7e8fc9e
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 16:35:20 2013 -0400

    A bit cleaner way to measure time segment.
    
    Change-Id: I999baaa3acba5513a148542fa28f7ae43dd7ee4f

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index cbd2752..3506a29 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -442,6 +442,25 @@ public:
     }
 };
 
+class MeasureTimeSwitch
+{
+    double& mrDiff;
+    TimeValue maTimeBefore;
+public:
+    MeasureTimeSwitch(double& rDiff) : mrDiff(rDiff)
+    {
+        mrDiff = 9999.0;
+        osl_getSystemTime(&maTimeBefore);
+    }
+
+    ~MeasureTimeSwitch()
+    {
+        TimeValue aTimeAfter;
+        osl_getSystemTime(&aTimeAfter);
+        mrDiff = getTimeDiff(aTimeAfter, maTimeBefore);
+    }
+};
+
 Test::Test()
     : m_pDoc(0)
 {
@@ -471,15 +490,15 @@ void Test::testPerf()
 {
     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
 
-    TimeValue aTimeBefore, aTimeAfter;
+    double diff = 9999.0;
 
     // Clearing an already empty sheet should finish in a fraction of a
     // second.  Flag failure if it takes more than one second.  Clearing 100
     // columns should be large enough to flag if something goes wrong.
-    osl_getSystemTime(&aTimeBefore);
-    clearRange(m_pDoc, ScRange(0,0,0,99,MAXROW,0));
-    osl_getSystemTime(&aTimeAfter);
-    double diff = getTimeDiff(aTimeAfter, aTimeBefore);
+    {
+        MeasureTimeSwitch aTime(diff);
+        clearRange(m_pDoc, ScRange(0,0,0,99,MAXROW,0));
+    }
     if (diff >= 1.0)
     {
         std::ostringstream os;
@@ -499,10 +518,10 @@ void Test::testPerf()
 
         // Now, Delete B2:B100000. This should complete in a fraction of a second
         // (0.06 sec on my machine).
-        osl_getSystemTime(&aTimeBefore);
-        clearRange(m_pDoc, ScRange(1,1,0,1,99999,0));
-        osl_getSystemTime(&aTimeAfter);
-        diff = getTimeDiff(aTimeAfter, aTimeBefore);
+        {
+            MeasureTimeSwitch aTime(diff);
+            clearRange(m_pDoc, ScRange(1,1,0,1,99999,0));
+        }
         if (diff >= 1.0)
         {
             std::ostringstream os;
@@ -535,10 +554,10 @@ void Test::testPerf()
         ScRange aPasteRange(0,1,0,0,99999,0);
         aMark.SetMarkArea(aPasteRange);
 
-        osl_getSystemTime(&aTimeBefore);
-        m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
-        osl_getSystemTime(&aTimeAfter);
-        diff = getTimeDiff(aTimeAfter, aTimeBefore);
+        {
+            MeasureTimeSwitch aTime(diff);
+            m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
+        }
         if (diff >= 1.0)
         {
             std::ostringstream os;
@@ -558,10 +577,10 @@ void Test::testPerf()
         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
 
-        osl_getSystemTime(&aTimeBefore);
-        aUndo.Undo();
-        osl_getSystemTime(&aTimeAfter);
-        diff = getTimeDiff(aTimeAfter, aTimeBefore);
+        {
+            MeasureTimeSwitch aTime(diff);
+            aUndo.Undo();
+        }
         if (diff >= 1.0)
         {
             std::ostringstream os;
@@ -575,10 +594,10 @@ void Test::testPerf()
         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
 
         // Now redo.
-        osl_getSystemTime(&aTimeBefore);
-        aUndo.Redo();
-        osl_getSystemTime(&aTimeAfter);
-        diff = getTimeDiff(aTimeAfter, aTimeBefore);
+        {
+            MeasureTimeSwitch aTime(diff);
+            aUndo.Redo();
+        }
         if (diff >= 1.0)
         {
             std::ostringstream os;
commit 42901096de15311d828696aabfc3f0b45655e237
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 16:19:04 2013 -0400

    Make these stack variables & fix one memory leak with the undo object.
    
    Change-Id: I1dd2bf0fc843394502119928c921913131c86f7e

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 5ebf6b6..cbd2752 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -5684,8 +5684,8 @@ void Test::testCopyPaste()
     ScClipParam aClipParam(aRange, false);
     ScMarkData aMark;
     aMark.SetMarkArea(aRange);
-    ScDocument* pClipDoc = new ScDocument(SCDOCMODE_CLIP);
-    m_pDoc->CopyToClip(aClipParam, pClipDoc, &aMark);
+    ScDocument aClipDoc(SCDOCMODE_CLIP);
+    m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
 
     sal_uInt16 nFlags = IDF_ALL;
     aRange = ScRange(0,1,1,2,1,1);//target: Sheet2.A2:C2
@@ -5694,9 +5694,9 @@ void Test::testCopyPaste()
     ScMarkData aMarkData2;
     aMarkData2.SetMarkArea(aRange);
     ScRefUndoData* pRefUndoData= new ScRefUndoData(m_pDoc);
-    SfxUndoAction* pUndo = new ScUndoPaste(
+    ScUndoPaste aUndo(
         &m_xDocShRef, ScRange(0, 1, 1, 2, 1, 1), aMarkData2, pUndoDoc, NULL, IDF_ALL, pRefUndoData, false);
-    m_pDoc->CopyFromClip(aRange, aMarkData2, nFlags, NULL, pClipDoc);
+    m_pDoc->CopyFromClip(aRange, aMarkData2, nFlags, NULL, &aClipDoc);
 
     //check values after copying
     OUString aString;
@@ -5718,13 +5718,13 @@ void Test::testCopyPaste()
 
 
     //check undo and redo
-    pUndo->Undo();
+    aUndo.Undo();
     m_pDoc->GetValue(1,1,1, aValue);
     ASSERT_DOUBLES_EQUAL_MESSAGE("after undo formula should return nothing", aValue, 0);
     aString = m_pDoc->GetString(2, 1, 1);
     CPPUNIT_ASSERT_MESSAGE("after undo string should be removed", aString.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("")));
 
-    pUndo->Redo();
+    aUndo.Redo();
     m_pDoc->GetValue(1,1,1, aValue);
     ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 2 after redo", aValue, 2);
     aString = m_pDoc->GetString(2, 1, 1);
@@ -5732,9 +5732,6 @@ void Test::testCopyPaste()
     m_pDoc->GetFormula(1,1,1, aString);
     CPPUNIT_ASSERT_MESSAGE("Formula should be correct again", aString == aFormulaString);
 
-    //clear all variables
-    delete pClipDoc;
-    delete pUndoDoc;
     m_pDoc->DeleteTab(1);
     m_pDoc->DeleteTab(0);
 }
commit 266e71c7b89234b9e8722c24dfc9ee7d4ccbd74f
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 16:13:32 2013 -0400

    Add performance test for repeat-pasting cell to a large cell range.
    
    Change-Id: I98dcdb1e0a72f2c3ad6f33c7b6b7d4a4bcf89096

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index d1492eb..dfc46b0 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -472,6 +472,7 @@ public:
     SvtBroadcaster* GetBroadcaster( SCROW nRow );
     const SvtBroadcaster* GetBroadcaster( SCROW nRow ) const;
     void DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 );
+    bool HasBroadcaster() const;
 
 private:
     void UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index ff525a6..f5d3414 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1972,6 +1972,11 @@ public:
     const SvtBroadcaster* GetBroadcaster( const ScAddress& rPos ) const;
     void DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const ScAddress& rTopPos, SCROW nLength );
 
+    /**
+     * See if specified column has any broadcaster at all.
+     */
+    bool HasBroadcaster( SCTAB nTab, SCCOL nCol ) const;
+
 private: // CLOOK-Impl-methods
 
     /**
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 6038311..b62fa1e 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -851,6 +851,7 @@ public:
     SvtBroadcaster* GetBroadcaster( SCCOL nCol, SCROW nRow );
     const SvtBroadcaster* GetBroadcaster( SCCOL nCol, SCROW nRow ) const;
     void DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCCOL nCol, SCROW nRow1, SCROW nRow2 );
+    bool HasBroadcaster( SCCOL nCol ) const;
 
     /** Replace behaves differently to the Search; adjust the rCol and rRow accordingly.
 
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 07fa33f..5ebf6b6 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -511,6 +511,86 @@ void Test::testPerf()
         }
     }
 
+    clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
+    CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
+    CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
+
+    {
+        ScAddress aPos(0,0,0);
+        m_pDoc->SetString(aPos, "test");
+        ScMarkData aMark;
+        aMark.SelectOneTable(0);
+
+        // Copy cell A1 to clipboard.
+        ScDocument aClipDoc(SCDOCMODE_CLIP);
+        ScClipParam aParam(aPos, false);
+        m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
+
+        ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
+        pUndoDoc->InitUndo(m_pDoc, 0, 0);
+        m_pDoc->CopyToDocument(ScRange(aPos), IDF_CONTENTS, false, pUndoDoc, &aMark);
+
+        // Paste it to A2:A100000, and measure its duration.
+        ScRange aPasteRange(0,1,0,0,99999,0);
+        aMark.SetMarkArea(aPasteRange);
+
+        osl_getSystemTime(&aTimeBefore);
+        m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
+        osl_getSystemTime(&aTimeAfter);
+        diff = getTimeDiff(aTimeAfter, aTimeBefore);
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Pasting a single cell to A2:A100000 took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
+        pRedoDoc->InitUndo(m_pDoc, 0, 0);
+        m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
+
+        // Create an undo object for this.
+        ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
+        ScUndoPaste aUndo(&(*m_xDocShRef), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
+
+        // Make sure it did what it's supposed to do.
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
+
+        osl_getSystemTime(&aTimeBefore);
+        aUndo.Undo();
+        osl_getSystemTime(&aTimeAfter);
+        diff = getTimeDiff(aTimeAfter, aTimeBefore);
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Undoing a pasting of a cell to A2:A100000 took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        // Make sure it's really undone.
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, m_pDoc->GetCellType(aPos));
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
+
+        // Now redo.
+        osl_getSystemTime(&aTimeBefore);
+        aUndo.Redo();
+        osl_getSystemTime(&aTimeAfter);
+        diff = getTimeDiff(aTimeAfter, aTimeBefore);
+        if (diff >= 1.0)
+        {
+            std::ostringstream os;
+            os << "Redoing a pasting of a cell to A2:A100000 took " << diff << " seconds. It should be instant.";
+            CPPUNIT_FAIL(os.str().c_str());
+        }
+
+        // Make sure it's really redone.
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
+    }
+
     m_pDoc->DeleteTab(0);
 }
 
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 375752c..fbd0c0a 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1611,6 +1611,18 @@ void ScColumn::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCROW nRo
         maBroadcasters.set_empty(rBlockPos.miBroadcasterPos, nRow1, nRow2);
 }
 
+bool ScColumn::HasBroadcaster() const
+{
+    sc::BroadcasterStoreType::const_iterator it = maBroadcasters.begin(), itEnd = maBroadcasters.end();
+    for (; it != itEnd; ++it)
+    {
+        if (it->type == sc::element_type_broadcaster)
+            // Having a broadcaster block automatically means there is at least one broadcaster.
+            return true;
+    }
+    return false;
+}
+
 sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
 {
     return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnTextWidth;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 901476e..34ae049 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2257,6 +2257,15 @@ void ScDocument::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const S
     pTab->DeleteBroadcasters(rBlockPos, rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
 }
 
+bool ScDocument::HasBroadcaster( SCTAB nTab, SCCOL nCol ) const
+{
+    const ScTable* pTab = FetchTable(nTab);
+    if (!pTab)
+        return false;
+
+    return pTab->HasBroadcaster(nCol);
+}
+
 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/table1.cxx b/sc/source/core/data/table1.cxx
index 9c380c8..c0e2c3f 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2186,6 +2186,14 @@ void ScTable::DeleteBroadcasters(
     aCol[nCol].DeleteBroadcasters(rBlockPos, nRow1, nRow2);
 }
 
+bool ScTable::HasBroadcaster( SCCOL nCol ) const
+{
+    if (!ValidCol(nCol))
+        return false;
+
+    return aCol[nCol].HasBroadcaster();
+}
+
 const SvtBroadcaster* ScTable::GetBroadcaster( SCCOL nCol, SCROW nRow ) const
 {
     if (!ValidColRow(nCol, nRow))
commit 02304b8fc917a8af4230ddf3e26a45000550768a
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 13:17:28 2013 -0400

    Ditto when purging broadcasters.
    
    Change-Id: I632d617cad76485f7e1f57daa7db4d4cfa775e8b

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 6db56d4..d1492eb 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -471,7 +471,7 @@ public:
 
     SvtBroadcaster* GetBroadcaster( SCROW nRow );
     const SvtBroadcaster* GetBroadcaster( SCROW nRow ) const;
-    void DeleteBroadcasters( SCROW nRow1, SCROW nRow2 );
+    void DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 );
 
 private:
     void UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow );
diff --git a/sc/inc/columnspanset.hxx b/sc/inc/columnspanset.hxx
index 35d94bf..ab24828 100644
--- a/sc/inc/columnspanset.hxx
+++ b/sc/inc/columnspanset.hxx
@@ -47,7 +47,6 @@ public:
     void set(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool bVal);
 
     void executeFromTop(Action& ac) const;
-    void executeFromBottom(Action& ac) const;
 };
 
 }
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 544c9b5..ff525a6 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1970,7 +1970,7 @@ public:
 
     SvtBroadcaster* GetBroadcaster( const ScAddress& rPos );
     const SvtBroadcaster* GetBroadcaster( const ScAddress& rPos ) const;
-    void DeleteBroadcasters( const ScAddress& rTopPos, SCROW nLength );
+    void DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const ScAddress& rTopPos, SCROW nLength );
 
 private: // CLOOK-Impl-methods
 
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 48fca53..6038311 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -850,7 +850,7 @@ public:
 
     SvtBroadcaster* GetBroadcaster( SCCOL nCol, SCROW nRow );
     const SvtBroadcaster* GetBroadcaster( SCCOL nCol, SCROW nRow ) const;
-    void DeleteBroadcasters( SCCOL nCol, SCROW nRow1, SCROW nRow2 );
+    void DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, 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 fa603f5..375752c 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1605,9 +1605,10 @@ const SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow) const
     return maBroadcasters.get<SvtBroadcaster*>(nRow);
 }
 
-void ScColumn::DeleteBroadcasters( SCROW nRow1, SCROW nRow2 )
+void ScColumn::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
 {
-    maBroadcasters.set_empty(nRow1, nRow2);
+    rBlockPos.miBroadcasterPos =
+        maBroadcasters.set_empty(rBlockPos.miBroadcasterPos, nRow1, nRow2);
 }
 
 sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
index ea4f706..9b63dc7 100644
--- a/sc/source/core/data/columnspanset.cxx
+++ b/sc/source/core/data/columnspanset.cxx
@@ -85,43 +85,14 @@ void ColumnSpanSet::executeFromTop(Action& ac) const
             ColumnSpansType::const_iterator it = rCol.begin(), itEnd = rCol.end();
             SCROW nRow1, nRow2;
             nRow1 = it->first;
+            bool bVal = it->second;
             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;
-
-            ac.startColumn(nTab, nCol);
-            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.
+                bVal = it->second;
             }
         }
     }
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index f74a946..901476e 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2241,20 +2241,20 @@ SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos )
 
 const SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos ) const
 {
-    ScTable* pTab = FetchTable(rPos.Tab());
+    const ScTable* pTab = FetchTable(rPos.Tab());
     if (!pTab)
         return NULL;
 
     return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
 }
 
-void ScDocument::DeleteBroadcasters( const ScAddress& rTopPos, SCROW nLength )
+void ScDocument::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const ScAddress& rTopPos, SCROW nLength )
 {
     ScTable* pTab = FetchTable(rTopPos.Tab());
     if (!pTab || nLength <= 0)
         return;
 
-    pTab->DeleteBroadcasters(rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
+    pTab->DeleteBroadcasters(rBlockPos, rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
 }
 
 bool ScDocument::TableExists( SCTAB nTab ) const
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
index f53f1bc..1f4c995 100644
--- a/sc/source/core/data/listenercontext.cxx
+++ b/sc/source/core/data/listenercontext.cxx
@@ -17,12 +17,22 @@ 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(rPos, nLength);
+        {
+            mrDoc.DeleteBroadcasters(maBlockPos, rPos, nLength);
+        }
     };
 };
 
@@ -60,7 +70,7 @@ void EndListeningContext::addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SC
 void EndListeningContext::purgeEmptyBroadcasters()
 {
     PurgeAction aAction(mrDoc);
-    maSet.executeFromBottom(aAction);
+    maSet.executeFromTop(aAction);
 }
 
 }
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index d1654a6..9c380c8 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2177,12 +2177,13 @@ SvtBroadcaster* ScTable::GetBroadcaster( SCCOL nCol, SCROW nRow )
     return aCol[nCol].GetBroadcaster(nRow);
 }
 
-void ScTable::DeleteBroadcasters( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
+void ScTable::DeleteBroadcasters(
+    sc::ColumnBlockPosition& rBlockPos, SCCOL nCol, SCROW nRow1, SCROW nRow2 )
 {
     if (!ValidCol(nCol))
         return;
 
-    aCol[nCol].DeleteBroadcasters(nRow1, nRow2);
+    aCol[nCol].DeleteBroadcasters(rBlockPos, nRow1, nRow2);
 }
 
 const SvtBroadcaster* ScTable::GetBroadcaster( SCCOL nCol, SCROW nRow ) const
commit 96d56b9cc6a3e00faf231e92bffbfff7e73a7ee5
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 12:35:05 2013 -0400

    A bit of cleanup.
    
    Change-Id: I9f200377c1f5bf44eb4ba60c272b02ae3d632a19

diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 0535388..f74a946 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2232,26 +2232,29 @@ ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
 
 SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos )
 {
-    if (!TableExists(rPos.Tab()))
+    ScTable* pTab = FetchTable(rPos.Tab());
+    if (!pTab)
         return NULL;
 
-    return maTabs[rPos.Tab()]->GetBroadcaster(rPos.Col(), rPos.Row());
+    return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
 }
 
 const SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos ) const
 {
-    if (!TableExists(rPos.Tab()))
+    ScTable* pTab = FetchTable(rPos.Tab());
+    if (!pTab)
         return NULL;
 
-    return maTabs[rPos.Tab()]->GetBroadcaster(rPos.Col(), rPos.Row());
+    return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
 }
 
 void ScDocument::DeleteBroadcasters( const ScAddress& rTopPos, SCROW nLength )
 {
-    if (!TableExists(rTopPos.Tab()) || nLength <= 0)
+    ScTable* pTab = FetchTable(rTopPos.Tab());
+    if (!pTab || nLength <= 0)
         return;
 
-    maTabs[rTopPos.Tab()]->DeleteBroadcasters(rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
+    pTab->DeleteBroadcasters(rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
 }
 
 bool ScDocument::TableExists( SCTAB nTab ) const
commit a3d2a042916edf54db544db34f89c1f841e69bf5
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 12:25:19 2013 -0400

    Do the same trick when getting broadcasters during mass formula cell deletion.
    
    Change-Id: Iee1b3ff637d10c6bd2d2342db518a2fc986327b7

diff --git a/sc/inc/listenercontext.hxx b/sc/inc/listenercontext.hxx
index 2503e72..f4fbb0f 100644
--- a/sc/inc/listenercontext.hxx
+++ b/sc/inc/listenercontext.hxx
@@ -35,10 +35,13 @@ class EndListeningContext : boost::noncopyable
 {
     ScDocument& mrDoc;
     ColumnSpanSet maSet;
+    ColumnBlockPositionSet maPosSet;
 public:
     EndListeningContext(ScDocument& rDoc);
     ScDocument& getDoc();
 
+    ColumnBlockPosition* getBlockPosition(SCTAB nTab, SCCOL nCol);
+
     void addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SCROW nRow);
     void purgeEmptyBroadcasters();
 };
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 828dbe1..fa603f5 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2107,10 +2107,19 @@ void ScColumn::StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtL
 
 void ScColumn::EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener )
 {
-    SvtBroadcaster* pBC = GetBroadcaster(nRow);
-    if (!pBC)
+    sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
+    if (!p)
+        return;
+
+    sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
+    std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
+    it = aPos.first; // store the block position for next iteration.
+    if (it->type != sc::element_type_broadcaster)
         return;
 
+    SvtBroadcaster* pBC = sc::custom_broadcaster_block::at(*it->data, aPos.second);
+    OSL_ASSERT(pBC);
+
     rListener.EndListening(*pBC);
     if (!pBC->HasListeners())
         // There is no more listeners for this cell. Add it to the purge list for later purging.
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
index 7ab3799..f53f1bc 100644
--- a/sc/source/core/data/listenercontext.cxx
+++ b/sc/source/core/data/listenercontext.cxx
@@ -40,13 +40,18 @@ ColumnBlockPosition* StartListeningContext::getBlockPosition(SCTAB nTab, SCCOL n
     return maSet.getBlockPosition(nTab, nCol);
 }
 
-EndListeningContext::EndListeningContext(ScDocument& rDoc) : mrDoc(rDoc) {}
+EndListeningContext::EndListeningContext(ScDocument& rDoc) : mrDoc(rDoc), maPosSet(rDoc) {}
 
 ScDocument& EndListeningContext::getDoc()
 {
     return mrDoc;
 }
 
+ColumnBlockPosition* EndListeningContext::getBlockPosition(SCTAB nTab, SCCOL nCol)
+{
+    return maPosSet.getBlockPosition(nTab, nCol);
+}
+
 void EndListeningContext::addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SCROW nRow)
 {
     maSet.set(nTab, nCol, nRow, true);
commit d5b4cb00bedd08ad72885defbc35c971b573ecd8
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon May 20 11:12:49 2013 -0400

    Keep track of column block positions when mass-pasting formula cells.
    
    This speeds up the following scenario:
    
    1) type =B1 in A1. Leave A2 empty.
    2) Select A1:A2 and Ctrl-C to copy.
    3) Select A3:A50000 (or longer if you so wish), and ctrl-V to paste.
    
    This causes the broadcaster storage array in column B to be heavily
    partitioned due to the empty cells interspersed between formula cells
    in column A.  Without tracking the column position this would cause a
    O(n^2) complexity algorithm.
    
    Change-Id: Ic2f23c2c2bea3353c517faa73fe5412c7528bd95

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 46ffbd9..6db56d4 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -37,6 +37,7 @@ namespace editeng { class SvxBorderLine; }
 
 namespace sc {
     struct FormulaGroupContext;
+    class StartListeningContext;
     class EndListeningContext;
     class CopyFromClipContext;
     class CopyToClipContext;
@@ -226,7 +227,7 @@ public:
     void CopyFromClip(
         sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn );
 
-    void        StartListeningInArea( SCROW nRow1, SCROW nRow2 );
+    void StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 );
     void        BroadcastInArea( SCROW nRow1, SCROW nRow2 );
 
     void        RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow );
@@ -433,6 +434,7 @@ public:
 
     void        StartListening( SvtListener& rLst, SCROW nRow );
     void        EndListening( SvtListener& rLst, SCROW nRow );
+    void StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rListener );
     void EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener );
     void        MoveListeners( SvtBroadcaster& rSource, SCROW nDestRow );
     void        StartAllListeners();
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index f01e811..544c9b5 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -49,6 +49,7 @@
 namespace editeng { class SvxBorderLine; }
 namespace sc {
     struct FormulaGroupContext;
+    class StartListeningContext;
     class EndListeningContext;
     class CopyFromClipContext;
     struct ColumnBlockPosition;
@@ -1765,6 +1766,7 @@ public:
     void                EndListeningCell( const ScAddress& rAddress,
                                             SvtListener* pListener );
 
+    void StartListeningCell( sc::StartListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener );
     void EndListeningCell( sc::EndListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener );
 
     void EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells );
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index e081353..4760062 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -30,6 +30,7 @@
 
 namespace sc {
 
+class StartListeningContext;
 class EndListeningContext;
 
 }
@@ -313,6 +314,7 @@ public:
 
     // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
     void StartListeningTo( ScDocument* pDoc );
+    void StartListeningTo( sc::StartListeningContext& rCxt );
     void EndListeningTo(
         ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() );
     void EndListeningTo( sc::EndListeningContext& rCxt );
diff --git a/sc/inc/listenercontext.hxx b/sc/inc/listenercontext.hxx
index 36f26d8..2503e72 100644
--- a/sc/inc/listenercontext.hxx
+++ b/sc/inc/listenercontext.hxx
@@ -12,6 +12,7 @@
 
 #include "address.hxx"
 #include "columnspanset.hxx"
+#include "mtvelements.hxx"
 
 #include <boost/noncopyable.hpp>
 
@@ -19,6 +20,17 @@ class ScDocument;
 
 namespace sc {
 
+class StartListeningContext : boost::noncopyable
+{
+    ScDocument& mrDoc;
+    ColumnBlockPositionSet maSet;
+public:
+    StartListeningContext(ScDocument& rDoc);
+    ScDocument& getDoc();
+
+    ColumnBlockPosition* getBlockPosition(SCTAB nTab, SCCOL nCol);
+};
+
 class EndListeningContext : boost::noncopyable
 {
     ScDocument& mrDoc;
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index f04a9bb..48fca53 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 StartListeningContext;
     class EndListeningContext;
     class CopyFromClipContext;
     class CopyToClipContext;
@@ -393,8 +394,9 @@ public:
         sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         SCsCOL nDx, SCsROW nDy, ScTable* pTable );
 
-    void        StartListeningInArea( SCCOL nCol1, SCROW nRow1,
-                                        SCCOL nCol2, SCROW nRow2 );
+    void StartListeningInArea(
+        sc::StartListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
+
     void        BroadcastInArea( SCCOL nCol1, SCROW nRow1,
                                     SCCOL nCol2, SCROW nRow2 );
 
@@ -948,6 +950,7 @@ private:
 
     void        StartListening( const ScAddress& rAddress, SvtListener* pListener );
     void        EndListening( const ScAddress& rAddress, SvtListener* pListener );
+    void StartListening( sc::StartListeningContext& rCxt, SCCOL nCol, SCROW nRow, SvtListener& rListener );
     void EndListening( sc::EndListeningContext& rCxt, SCCOL nCol, SCROW nRow, SvtListener& rListener );
     void        StartAllListeners();
     void        StartNeededListeners(); // only for cells where NeedsListening()==TRUE
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 3b28d61..828dbe1 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2013,17 +2013,18 @@ void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, bool* pUsed ) const
     }
 }
 
-void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
+namespace {
+
+void startListening(
+    sc::BroadcasterStoreType& rStore, sc::BroadcasterStoreType::iterator& itBlockPos, size_t nElemPos,
+    SCROW nRow, SvtListener& rLst)
 {
-    std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(nRow);
-    sc::BroadcasterStoreType::iterator it = aPos.first; // block position.
-    size_t nElemPos = aPos.second; // element position within the block.
-    switch (it->type)
+    switch (itBlockPos->type)
     {
         case sc::element_type_broadcaster:
         {
             // Broadcaster already exists here.
-            SvtBroadcaster* pBC = sc::custom_broadcaster_block::at(*it->data, nElemPos);
+            SvtBroadcaster* pBC = sc::custom_broadcaster_block::at(*itBlockPos->data, nElemPos);
             rLst.StartListening(*pBC);
         }
         break;
@@ -2032,7 +2033,7 @@ void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
             // No broadcaster exists at this position yet.
             SvtBroadcaster* pBC = new SvtBroadcaster;
             rLst.StartListening(*pBC);
-            maBroadcasters.set(it, nRow, pBC);
+            itBlockPos = rStore.set(itBlockPos, nRow, pBC); // Store the block position for next iteration.
         }
         break;
         default:
@@ -2046,6 +2047,14 @@ void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
     }
 }
 
+}
+
+void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
+{
+    std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(nRow);
+    startListening(maBroadcasters, aPos.first, aPos.second, nRow, rLst);
+}
+
 void ScColumn::MoveListeners( SvtBroadcaster& rSource, SCROW nDestRow )
 {
     // Move listeners from the source position to the destination position.
@@ -2081,6 +2090,21 @@ void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
         maBroadcasters.set_empty(nRow, nRow);
 }
 
+void ScColumn::StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rLst )
+{
+    if (!ValidRow(nRow))
+        return;
+
+    sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
+    if (!p)
+        return;
+
+    sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
+    std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
+    it = aPos.first; // store the block position for next iteration.
+    startListening(maBroadcasters, it, aPos.second, nRow, rLst);
+}
+
 void ScColumn::EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener )
 {
     SvtBroadcaster* pBC = GetBroadcaster(nRow);
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 70d007d..60eb8e3 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1166,7 +1166,7 @@ void ScColumn::BroadcastInArea( SCROW nRow1, SCROW nRow2 )
 }
 
 
-void ScColumn::StartListeningInArea( SCROW nRow1, SCROW nRow2 )
+void ScColumn::StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
 {
     if (maItems.empty())
         return;
@@ -1178,7 +1178,7 @@ void ScColumn::StartListeningInArea( SCROW nRow1, SCROW nRow2 )
     {
         ScBaseCell* pCell = maItems[nIndex].pCell;
         if ( pCell->GetCellType() == CELLTYPE_FORMULA )
-            ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
+            ((ScFormulaCell*)pCell)->StartListeningTo(rCxt);
         if ( nRow != maItems[nIndex].nRow )
             Search( nRow, nIndex ); // Inserted via Listening
 
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
index b240633..1c3f665 100644
--- a/sc/source/core/data/documen7.cxx
+++ b/sc/source/core/data/documen7.cxx
@@ -201,13 +201,24 @@ void ScDocument::EndListeningCell( const ScAddress& rAddress,
         maTabs[nTab]->EndListening( rAddress, pListener );
 }
 
+void ScDocument::StartListeningCell(
+    sc::StartListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
+{
+    ScTable* pTab = FetchTable(rPos.Tab());
+    if (!pTab)
+        return;
+
+    pTab->StartListening(rCxt, rPos.Col(), rPos.Row(), rListener);
+}
+
 void ScDocument::EndListeningCell(
     sc::EndListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
 {
-    if (!TableExists(rPos.Tab()))
+    ScTable* pTab = FetchTable(rPos.Tab());
+    if (!pTab)
         return;
 
-    maTabs[rPos.Tab()]->EndListening(rCxt, rPos.Col(), rPos.Row(), rListener);
+    pTab->EndListening(rCxt, rPos.Col(), rPos.Row(), rListener);
 }
 
 void ScDocument::EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells )
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index f41a715..0535388 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -91,6 +91,7 @@
 #include "formulaiter.hxx"
 #include "formulacell.hxx"
 #include "clipcontext.hxx"
+#include "listenercontext.hxx"
 
 #include <map>
 #include <limits>
@@ -2314,11 +2315,12 @@ void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
 {
     if (nInsFlag & IDF_CONTENTS)
     {
+        sc::StartListeningContext aCxt(*this);
         SCTAB nMax = static_cast<SCTAB>(maTabs.size());
         ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
         for (; itr != itrEnd && *itr < nMax; ++itr)
             if (maTabs[*itr])
-                maTabs[*itr]->StartListeningInArea( nCol1, nRow1, nCol2, nRow2 );
+                maTabs[*itr]->StartListeningInArea(aCxt, nCol1, nRow1, nCol2, nRow2);
     }
 }
 
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 30810df..98df69a 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3162,6 +3162,34 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup()
     return true;
 }
 
+namespace {
+
+void startListeningArea(
+    ScFormulaCell* pCell, ScDocument& rDoc, const ScAddress& rPos, const ScToken& rToken)
+{
+    const ScSingleRefData& rRef1 = rToken.GetSingleRef();
+    const ScSingleRefData& rRef2 = rToken.GetSingleRef2();
+    ScAddress aCell1 = rRef1.toAbs(rPos);
+    ScAddress aCell2 = rRef2.toAbs(rPos);
+    if (aCell1.IsValid() && aCell2.IsValid())
+    {
+        if (rToken.GetOpCode() == ocColRowNameAuto)
+        {   // automagically
+            if ( rRef1.IsColRel() )
+            {   // ColName
+                aCell2.SetRow(MAXROW);
+            }
+            else
+            {   // RowName
+                aCell2.SetCol(MAXCOL);
+            }
+        }
+        rDoc.StartListeningArea(ScRange(aCell1, aCell2), pCell);
+    }
+}
+
+}
+
 void ScFormulaCell::StartListeningTo( ScDocument* pDoc )
 {
     if (pDoc->IsClipOrUndo() || pDoc->GetNoListening() || IsInChangeTrack())
@@ -3181,40 +3209,58 @@ void ScFormulaCell::StartListeningTo( ScDocument* pDoc )
     ScToken* t;
     while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
     {
-        StackVar eType = t->GetType();
-        ScSingleRefData& rRef1 = t->GetSingleRef();
-        ScSingleRefData& rRef2 = (eType == svDoubleRef ?
-            t->GetDoubleRef().Ref2 : rRef1);
-        switch( eType )
+        switch (t->GetType())
         {
             case svSingleRef:
             {
-                ScAddress aCell = rRef1.toAbs(aPos);
+                ScAddress aCell =  t->GetSingleRef().toAbs(aPos);
                 if (aCell.IsValid())
                     pDoc->StartListeningCell(aCell, this);
             }
             break;
             case svDoubleRef:
+                startListeningArea(this, *pDoc, aPos, *t);
+            break;
+            default:
+                ;   // nothing
+        }
+    }
+    SetNeedsListening( false);
+}
+
+void ScFormulaCell::StartListeningTo( sc::StartListeningContext& rCxt )
+{
+    ScDocument& rDoc = rCxt.getDoc();
+
+    if (rDoc.IsClipOrUndo() || rDoc.GetNoListening() || IsInChangeTrack())
+        return;
+
+    rDoc.SetDetectiveDirty(true);  // It has changed something
+
+    ScTokenArray* pArr = GetCode();
+    if( pArr->IsRecalcModeAlways() )
+    {
+        rDoc.StartListeningArea(BCA_LISTEN_ALWAYS, this);
+        SetNeedsListening( false);
+        return;
+    }
+
+    pArr->Reset();
+    ScToken* t;
+    while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
+    {
+        switch (t->GetType())
+        {
+            case svSingleRef:
             {
-                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);
-                        }
-                    }
-                    pDoc->StartListeningArea(ScRange(aCell1, aCell2), this);
-                }
+                ScAddress aCell = t->GetSingleRef().toAbs(aPos);
+                if (aCell.IsValid())
+                    rDoc.StartListeningCell(rCxt, aCell, *this);
             }
             break;
+            case svDoubleRef:
+                startListeningArea(this, rDoc, aPos, *t);
+            break;
             default:
                 ;   // nothing
         }
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
index a288494..7ab3799 100644
--- a/sc/source/core/data/listenercontext.cxx
+++ b/sc/source/core/data/listenercontext.cxx
@@ -28,6 +28,18 @@ public:
 
 }
 
+StartListeningContext::StartListeningContext(ScDocument& rDoc) : mrDoc(rDoc), maSet(rDoc) {}
+
+ScDocument& StartListeningContext::getDoc()
+{
+    return mrDoc;
+}
+
+ColumnBlockPosition* StartListeningContext::getBlockPosition(SCTAB nTab, SCCOL nCol)
+{
+    return maSet.getBlockPosition(nTab, nCol);
+}
+
 EndListeningContext::EndListeningContext(ScDocument& rDoc) : mrDoc(rDoc) {}
 
 ScDocument& EndListeningContext::getDoc()
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 51801af..0f5d458 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1010,14 +1010,14 @@ void ScTable::BroadcastInArea( SCCOL nCol1, SCROW nRow1,
 }
 
 
-void ScTable::StartListeningInArea( SCCOL nCol1, SCROW nRow1,
-        SCCOL nCol2, SCROW nRow2 )
+void ScTable::StartListeningInArea(
+    sc::StartListeningContext& rCxt, 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].StartListeningInArea( nRow1, nRow2 );
+            aCol[i].StartListeningInArea(rCxt, nRow1, nRow2);
 }
 
 
diff --git a/sc/source/core/data/table5.cxx b/sc/source/core/data/table5.cxx
index 9468352..ed15086 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::StartListening( sc::StartListeningContext& rCxt, SCCOL nCol, SCROW nRow, SvtListener& rListener )
+{
+    if (!ValidCol(nCol))
+        return;
+
+    aCol[nCol].StartListening(rCxt, nRow, rListener);
+}
+
 void ScTable::EndListening( sc::EndListeningContext& rCxt, SCCOL nCol, SCROW nRow, SvtListener& rListener )
 {
     if (!ValidCol(nCol))
commit fc470416281b92e6b481885b64d59bc01ea4c3a6
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri May 17 23:33:30 2013 -0400

    A bit of cleanup before refactoring.
    
    Change-Id: I3627a83669b6a69c299aef96b8b2ead1352eabe2

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index b243ea2..30810df 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3188,53 +3188,32 @@ void ScFormulaCell::StartListeningTo( ScDocument* pDoc )
         switch( eType )
         {
             case svSingleRef:
-                rRef1.CalcAbsIfRel(aPos);
-                if ( rRef1.Valid() )
-                {
-                    pDoc->StartListeningCell(
-                        ScAddress( rRef1.nCol,
-                                   rRef1.nRow,
-                                   rRef1.nTab ), this );
-                }
+            {
+                ScAddress aCell = rRef1.toAbs(aPos);
+                if (aCell.IsValid())
+                    pDoc->StartListeningCell(aCell, this);
+            }
             break;
             case svDoubleRef:
-                t->CalcAbsIfRel(aPos);
-                if ( rRef1.Valid() && rRef2.Valid() )
+            {
+                ScAddress aCell1 = rRef1.toAbs(aPos);
+                ScAddress aCell2 = rRef2.toAbs(aPos);
+                if (aCell1.IsValid() && aCell2.IsValid())
                 {
-                    if ( t->GetOpCode() == ocColRowNameAuto )
+                    if (t->GetOpCode() == ocColRowNameAuto)
                     {   // automagically
                         if ( rRef1.IsColRel() )
                         {   // ColName
-                            pDoc->StartListeningArea( ScRange (
-                                rRef1.nCol,
-                                rRef1.nRow,
-                                rRef1.nTab,
-                                rRef2.nCol,
-                                MAXROW,
-                                rRef2.nTab ), this );
+                            aCell2.SetRow(MAXROW);
                         }
                         else
                         {   // RowName
-                            pDoc->StartListeningArea( ScRange (
-                                rRef1.nCol,
-                                rRef1.nRow,
-                                rRef1.nTab,
-                                MAXCOL,
-                                rRef2.nRow,
-                                rRef2.nTab ), this );
+                            aCell2.SetCol(MAXCOL);
                         }
                     }
-                    else
-                    {
-                        pDoc->StartListeningArea( ScRange (
-                            rRef1.nCol,
-                            rRef1.nRow,
-                            rRef1.nTab,
-                            rRef2.nCol,
-                            rRef2.nRow,
-                            rRef2.nTab ), this );
-                    }
+                    pDoc->StartListeningArea(ScRange(aCell1, aCell2), this);
                 }
+            }
             break;
             default:
                 ;   // nothing
commit c2e28f50354d4e95b2202aebe1764d81fdbfd27e
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri May 17 22:45:43 2013 -0400

    Prefer early bail-out.
    
    Change-Id: I112a4be56910c07007b28715336fcd82d56bb313

diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index f573011..70d007d 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1103,38 +1103,40 @@ ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) c
 
 void ScColumn::StartAllListeners()
 {
-    if ( !maItems.empty() )
-        for (SCSIZE i = 0; i < maItems.size(); i++)
+    if (maItems.empty())
+        return;
+
+    for (SCSIZE i = 0; i < maItems.size(); i++)
+    {
+        ScBaseCell* pCell = maItems[i].pCell;
+        if ( pCell->GetCellType() == CELLTYPE_FORMULA )
         {
-            ScBaseCell* pCell = maItems[i].pCell;
-            if ( pCell->GetCellType() == CELLTYPE_FORMULA )
-            {
-                SCROW nRow = maItems[i].nRow;
-                ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
-                if ( nRow != maItems[i].nRow )
-                    Search( nRow, i ); // Insert Listener?
-            }
+            SCROW nRow = maItems[i].nRow;
+            ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
+            if ( nRow != maItems[i].nRow )
+                Search( nRow, i ); // Insert Listener?
         }
+    }
 }
 
 
 void ScColumn::StartNeededListeners()
 {
-    if ( !maItems.empty() )
+    if (maItems.empty())
+        return;
+
+    for (SCSIZE i = 0; i < maItems.size(); i++)
     {
-        for (SCSIZE i = 0; i < maItems.size(); i++)
+        ScBaseCell* pCell = maItems[i].pCell;
+        if ( pCell->GetCellType() == CELLTYPE_FORMULA )
         {
-            ScBaseCell* pCell = maItems[i].pCell;
-            if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+            ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
+            if (pFCell->NeedsListening())
             {
-                ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
-                if (pFCell->NeedsListening())
-                {
-                    SCROW nRow = maItems[i].nRow;
-                    pFCell->StartListeningTo( pDocument );
-                    if ( nRow != maItems[i].nRow )
-                        Search( nRow, i ); // Insert Listener?
-                }
+                SCROW nRow = maItems[i].nRow;
+                pFCell->StartListeningTo( pDocument );
+                if ( nRow != maItems[i].nRow )
+                    Search( nRow, i ); // Insert Listener?
             }
         }
     }
@@ -1166,20 +1168,21 @@ void ScColumn::BroadcastInArea( SCROW nRow1, SCROW nRow2 )
 
 void ScColumn::StartListeningInArea( SCROW nRow1, SCROW nRow2 )
 {
-    if ( !maItems.empty() )
+    if (maItems.empty())
+        return;
+
+    SCROW nRow;
+    SCSIZE nIndex;
+    Search( nRow1, nIndex );
+    while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRow2 )
     {
-        SCROW nRow;
-        SCSIZE nIndex;
-        Search( nRow1, nIndex );
-        while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRow2 )
-        {
-            ScBaseCell* pCell = maItems[nIndex].pCell;
-            if ( pCell->GetCellType() == CELLTYPE_FORMULA )
-                ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
-            if ( nRow != maItems[nIndex].nRow )
-                Search( nRow, nIndex ); // Inserted via Listening
-            nIndex++;
-        }
+        ScBaseCell* pCell = maItems[nIndex].pCell;
+        if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+            ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
+        if ( nRow != maItems[nIndex].nRow )
+            Search( nRow, nIndex ); // Inserted via Listening
+
+        ++nIndex;
     }
 }
 
commit 0e25fe33f0114dc8723a7a9af4cdd11f07a55ec5
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri May 17 22:16:45 2013 -0400

    Compiler warning.
    
    Change-Id: I6f358f89348a23b3c70f8b7db8a1f01d659393ba

diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 9339e8b..f573011 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -906,8 +906,7 @@ void ScColumn::MixData(
     SCSIZE nIndex;
     Search( nRow1, nIndex );
 
-//  SCSIZE nSrcIndex = 0;
-    SCSIZE nSrcIndex, nDestIndex;
+    SCSIZE nSrcIndex = 0, nDestIndex = 0;
     rSrcCol.Search( nRow1, nSrcIndex ); // See if data is at the beginning
 
     SCROW nNextThis = MAXROW+1;
commit f7d037c2288cacaedf221404b5c9d4b7f2a0b7cb
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri May 17 21:23:22 2013 -0400

    Optimize ScColumn::MixData() to remove several bottlenecks.
    
    The use case that would previously make Calc freeze.
    
    1) type in "test" in A1.
    2) Select A1:A2 and Ctrl-C to copy to the clipboard.
    3) select the whole column B.
    4) paste special, select "Add" operation and click OK to paste.
    
    With this change, the above scenario no longer freezes Calc.
    
    Change-Id: I98b1f1e6c25b853aa884e7598c04b1457fab4636

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index c71ffea..46ffbd9 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -497,6 +497,12 @@ private:
     void SetCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pNewCell );
     void SetCell( SCROW nRow, ScBaseCell* pNewCell );
     void PostSetCell( SCROW nRow, ScBaseCell* pNewCell );
+
+    /**
+     * Clear and re-populate the cell text attribute array from the non-empty
+     * cells stored in the cell array.
+     */
+    void ResetCellTextAttrs();
 };
 
 
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index d4fe479..3b28d61 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1569,6 +1569,32 @@ void ScColumn::PostSetCell( SCROW nRow, ScBaseCell* pNewCell )
     }
 }
 
+namespace {
+
+class SetEmptyAttr : std::unary_function<ColEntry, void>
+{
+    sc::CellTextAttrStoreType& mrAttrStore;
+    sc::CellTextAttrStoreType::iterator miPos;
+public:
+    SetEmptyAttr(sc::CellTextAttrStoreType& rAttrStore) :
+        mrAttrStore(rAttrStore), miPos(rAttrStore.begin()) {}
+
+    void operator() (const ColEntry& rEntry)
+    {
+        miPos = mrAttrStore.set(miPos, rEntry.nRow, sc::CellTextAttr());
+    }
+};
+
+}
+
+void ScColumn::ResetCellTextAttrs()
+{
+    maCellTextAttrs.clear();
+    maCellTextAttrs.resize(MAXROWCOUNT);
+
+    std::for_each(maItems.begin(), maItems.end(), SetEmptyAttr(maCellTextAttrs));
+}
+
 SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow)
 {
     return maBroadcasters.get<SvtBroadcaster*>(nRow);
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index b530184..9339e8b 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -842,11 +842,12 @@ void ScColumn::MixMarked(
     }
 }
 
+namespace {
 
 // Result in rVal1
-static sal_Bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
+bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
 {
-    sal_Bool bOk = false;
+    bool bOk = false;
     switch (nFunction)
     {
         case PASTE_ADD:
@@ -866,8 +867,7 @@ static sal_Bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunctio
     return bOk;
 }
 
-
-static void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
+void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
 {
     rArr.AddOpCode(ocOpen);
 
@@ -885,6 +885,15 @@ static void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
     rArr.AddOpCode(ocClose);
 }
 
+struct FindRemovedCell : std::unary_function<ColEntry, bool>
+{
+    bool operator() (const ColEntry& rEntry) const
+    {
+        return rEntry.pCell == NULL;
+    }
+};
+
+}
 
 void ScColumn::MixData(
     sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction,
@@ -892,11 +901,13 @@ void ScColumn::MixData(
 {
     SCSIZE nSrcCount = rSrcCol.maItems.size();
 
+    sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
+
     SCSIZE nIndex;
     Search( nRow1, nIndex );
 
 //  SCSIZE nSrcIndex = 0;
-    SCSIZE nSrcIndex;
+    SCSIZE nSrcIndex, nDestIndex;
     rSrcCol.Search( nRow1, nSrcIndex ); // See if data is at the beginning
 
     SCROW nNextThis = MAXROW+1;
@@ -906,6 +917,7 @@ void ScColumn::MixData(
     if ( nSrcIndex < nSrcCount )
         nNextSrc = rSrcCol.maItems[nSrcIndex].nRow;
 
+    bool bDeferredDelete = false;
     while ( nNextThis <= nRow2 || nNextSrc <= nRow2 )
     {
         SCROW nRow = std::min( nNextThis, nNextSrc );
@@ -913,13 +925,16 @@ void ScColumn::MixData(
         ScBaseCell* pSrc = NULL;
         ScBaseCell* pDest = NULL;
         ScBaseCell* pNew = NULL;
-        sal_Bool bDelete = false;
+        bool bDelete = false;
 
         if ( nSrcIndex < nSrcCount && nNextSrc == nRow )
             pSrc = rSrcCol.maItems[nSrcIndex].pCell;
 
         if ( nIndex < maItems.size() && nNextThis == nRow )
+        {
             pDest = maItems[nIndex].pCell;
+            nDestIndex = nIndex;
+        }
 
         OSL_ENSURE( pSrc || pDest, "What happened?" );
 
@@ -1024,10 +1039,18 @@ void ScColumn::MixData(
 
         if ( pNew || bDelete ) // New result?
         {
-            sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
             if (pDest && !pNew) // Old cell present?
             {
-                Delete(nRow); // -> Delete
+                // Delete the destination cell because the cell was originally
+                // empty.  Don't erase its slot in the cell array yet.
+                OSL_ASSERT(pDest == maItems[nDestIndex].pCell);
+                maItems[nDestIndex].pCell = NULL;
+
+                if (pDest->GetCellType() == CELLTYPE_FORMULA)
+                    static_cast<ScFormulaCell*>(pDest)->EndListeningTo(pDocument);
+                pDest->Delete();
+
+                bDeferredDelete = true;
             }
             if (pNew)
             {
@@ -1057,6 +1080,19 @@ void ScColumn::MixData(
                             MAXROW+1;
         }
     }
+
+    if (bDeferredDelete)
+    {
+        // Erase all the slots in the cell array where the deleted cells
+        // previously occupied.
+        std::vector<ColEntry>::iterator it =
+            std::remove_if(maItems.begin(), maItems.end(), FindRemovedCell());
+
+        maItems.erase(it, maItems.end());
+
+        // Reset the cell text attriute array to keep it in sync again.
+        ResetCellTextAttrs();
+    }
 }
 
 
diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx
index ced0936..ec5b1c4 100644
--- a/sc/source/core/data/documentimport.cxx
+++ b/sc/source/core/data/documentimport.cxx
@@ -118,14 +118,7 @@ void ScDocumentImport::finalize()
         for (; pCol != pColEnd; ++pCol)
         {
             ScColumn& rCol = *pCol;
-            if (rCol.maItems.empty())
-                // Column has no cells. Skip it.
-                continue;
-
-            sc::CellTextAttrStoreType::iterator itCTAPos = rCol.maCellTextAttrs.begin();
-            std::vector<ColEntry>::iterator itCell = rCol.maItems.begin(), itCellEnd = rCol.maItems.end();
-            for (; itCell != itCellEnd; ++itCell)
-                itCTAPos = rCol.maCellTextAttrs.set<sc::CellTextAttr>(itCTAPos, itCell->nRow, sc::CellTextAttr());
+            rCol.ResetCellTextAttrs();
         }
     }
 }
commit edddbde921bf977dc1e7104956d204622b0449dd
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri May 17 16:48:25 2013 -0400

    A bit of a cleanup.
    
    Change-Id: Iaa7003cabee4630e4fbb8fb1cd114d04b4e9e33c

diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx
index 599da6e..84b1fcc 100644
--- a/sc/inc/clipcontext.hxx
+++ b/sc/inc/clipcontext.hxx
@@ -22,13 +22,7 @@ namespace sc {
 
 class ClipContextBase
 {
-    typedef boost::unordered_map<SCCOL, ColumnBlockPosition> ColumnsType;
-    typedef std::vector<ColumnsType> TablesType;
-
-    ScDocument& mrDoc;
-    TablesType maTables;
-    SCTAB mnTabStart;
-    SCTAB mnTabEnd;
+    sc::ColumnBlockPositionSet maSet;
 
     ClipContextBase(); // disabled
 
@@ -36,16 +30,13 @@ public:
     ClipContextBase(ScDocument& rDoc);
     virtual ~ClipContextBase();
 
-    void setTabRange(SCTAB nStart, SCTAB nEnd);
-
-    SCTAB getTabStart() const;
-    SCTAB getTabEnd() const;
-
     ColumnBlockPosition* getBlockPosition(SCTAB nTab, SCCOL nCol);
 };
 
 class CopyFromClipContext : public ClipContextBase
 {
+    SCTAB mnTabStart;
+    SCTAB mnTabEnd;
     ScDocument* mpRefUndoDoc;
     ScDocument* mpClipDoc;
     sal_uInt16  mnInsertFlag;
@@ -61,6 +52,11 @@ public:
 
     virtual ~CopyFromClipContext();
 
+    void setTabRange(SCTAB nStart, SCTAB nEnd);
+
+    SCTAB getTabStart() const;
+    SCTAB getTabEnd() const;
+
     ScDocument* getUndoDoc();
     ScDocument* getClipDoc();
     sal_uInt16 getInsertFlag() const;
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index 2c7abdf..2b51076 100644
--- a/sc/source/core/data/clipcontext.cxx
+++ b/sc/source/core/data/clipcontext.cxx
@@ -13,62 +13,20 @@
 namespace sc {
 
 ClipContextBase::ClipContextBase(ScDocument& rDoc) :
-    mrDoc(rDoc), mnTabStart(-1), mnTabEnd(-1) {}
+    maSet(rDoc) {}
 
 ClipContextBase::~ClipContextBase() {}
 
-void ClipContextBase::setTabRange(SCTAB nStart, SCTAB nEnd)
-{
-    mnTabStart = nStart;
-    mnTabEnd = nEnd;
-}
-
-SCTAB ClipContextBase::getTabStart() const
-{
-    return mnTabStart;
-}
-
-SCTAB ClipContextBase::getTabEnd() const
-{
-    return mnTabEnd;
-}
-
 ColumnBlockPosition* ClipContextBase::getBlockPosition(SCTAB nTab, SCCOL nCol)
 {
-    if (mnTabStart < 0 || mnTabEnd < 0 || mnTabStart > mnTabEnd)
-        return NULL;
-
-    size_t nTabIndex = nTab - mnTabStart;
-    if (nTabIndex >= maTables.size())
-        maTables.resize(nTabIndex+1);
-
-    ColumnsType& rCols = maTables[nTabIndex];
-
-    ColumnsType::iterator it = rCols.find(nCol);
-    if (it != rCols.end())
-        // Block position for this column has already been fetched.
-        return &it->second;
-
-    std::pair<ColumnsType::iterator,bool> r =
-        rCols.insert(
-            ColumnsType::value_type(nCol, ColumnBlockPosition()));
-
-    if (!r.second)
-        // insertion failed.
-        return NULL;
-
-    it = r.first;
-
-    if (!mrDoc.InitColumnBlockPosition(it->second, nTab, nCol))
-        return NULL;
-
-    return &it->second;
+    return maSet.getBlockPosition(nTab, nCol);
 }
 
 CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
     ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_uInt16 nInsertFlag,
     bool bAsLink, bool bSkipAttrForEmptyCells) :
     ClipContextBase(rDoc),
+    mnTabStart(-1), mnTabEnd(-1),
     mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc), mnInsertFlag(nInsertFlag),
     mbAsLink(bAsLink), mbSkipAttrForEmptyCells(bSkipAttrForEmptyCells) {}
 
@@ -76,6 +34,22 @@ CopyFromClipContext::~CopyFromClipContext()
 {
 }
 
+void CopyFromClipContext::setTabRange(SCTAB nStart, SCTAB nEnd)
+{
+    mnTabStart = nStart;
+    mnTabEnd = nEnd;
+}
+
+SCTAB CopyFromClipContext::getTabStart() const
+{
+    return mnTabStart;
+}
+
+SCTAB CopyFromClipContext::getTabEnd() const
+{
+    return mnTabEnd;
+}
+
 ScDocument* CopyFromClipContext::getUndoDoc()
 {
     return mpRefUndoDoc;
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 94cd257..10d36b6 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1514,7 +1514,6 @@ void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
 {
     //  This is the scenario table, the data is copied into it
     sc::CopyToDocContext aCxt(*pDocument);
-    aCxt.setTabRange(nTab, nTab);
     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
     SCROW nStart = -1, nEnd = -1;
     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
@@ -1546,7 +1545,6 @@ void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
 {
     //  This is the scenario table, the data is copied to the other
     sc::CopyToDocContext aCxt(*rDestCol.pDocument);
-    aCxt.setTabRange(rDestCol.nTab, rDestCol.nTab);
     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
     SCROW nStart = -1, nEnd = -1;
     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 0229c52..dcdae98 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -857,7 +857,6 @@ bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyM
     if (bValid)
     {
         sc::CopyToDocContext aCxt(*this);
-        aCxt.setTabRange(nNewPos, nNewPos);
         SetNoListening( true );     // noch nicht bei CopyToTable/Insert
         maTabs[nOldPos]->CopyToTable(aCxt, 0, 0, MAXCOL, MAXROW, IDF_ALL, (pOnlyMarked != NULL),
                                         maTabs[nNewPos], pOnlyMarked );
@@ -965,7 +964,6 @@ sal_uLong ScDocument::TransferTab( ScDocument* pSrcDoc, SCTAB nSrcPos,
             NumFmtMergeHandler aNumFmtMergeHdl(this, pSrcDoc);
 
             sc::CopyToDocContext aCxt(*this);
-            aCxt.setTabRange(nDestPos, nDestPos);
             nDestPos = std::min(nDestPos, (SCTAB)(GetTableCount() - 1));
             {   // scope for bulk broadcast
                 ScBulkBroadcast aBulkBroadcast( pBASM);
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 5fbc1ac0..f41a715 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1843,7 +1843,6 @@ void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
     if (ValidTab(nTab1) && ValidTab(nTab2))
     {
         sc::CopyToDocContext aCxt(*pDestDoc);
-        aCxt.setTabRange(nTab1, nTab2);
         bool bOldAutoCalc = pDestDoc->GetAutoCalc();
         pDestDoc->SetAutoCalc( false );     // avoid multiple calculations
         SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pDestDoc->maTabs.size()));
@@ -1875,7 +1874,6 @@ void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
             CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
 
         sc::CopyToDocContext aCxt(*pDestDoc);
-        aCxt.setTabRange(nTab1, nTab2);
         OSL_ASSERT( nTab2 < static_cast<SCTAB>(maTabs.size()) && nTab2 < static_cast<SCTAB>(pDestDoc->maTabs.size()));
         for (SCTAB i = nTab1; i <= nTab2; i++)
         {
@@ -1903,7 +1901,6 @@ void ScDocument::CopyToDocument(const ScRange& rRange,
     bool bOldAutoCalc = pDestDoc->GetAutoCalc();
     pDestDoc->SetAutoCalc( false );     // avoid multiple calculations
     sc::CopyToDocContext aCxt(*pDestDoc);
-    aCxt.setTabRange(aNewRange.aStart.Tab(), aNewRange.aEnd.Tab());
     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++)
     {
@@ -1931,7 +1928,6 @@ void ScDocument::UndoToDocument(const ScRange& rRange,
     bool bOldAutoCalc = pDestDoc->GetAutoCalc();
     pDestDoc->SetAutoCalc( false );     // avoid multiple calculations
     sc::CopyToDocContext aCxt(*pDestDoc);
-    aCxt.setTabRange(nTab1, nTab2);
     if (nTab1 > 0)
         CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
 
@@ -2009,7 +2005,6 @@ void ScDocument::CopyToClip(const ScClipParam& rClipParam,
         pClipDoc->ResetClip(this, pMarks);
 
     sc::CopyToClipContext aCxt(*pClipDoc, bKeepScenarioFlags, bCloneNoteCaptions);
-    aCxt.setTabRange(i, nEndTab-1);
     CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
 
     for ( ; i < nEndTab; ++i)
@@ -2107,7 +2102,6 @@ void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
         pClipDoc->ResetClip( this, nTab );
 
         sc::CopyToClipContext aCxt(*pClipDoc, false, true);
-        aCxt.setTabRange(nTab, nTab);
         if (nTab < static_cast<SCTAB>(maTabs.size()) && nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()))
             if (maTabs[nTab] && pClipDoc->maTabs[nTab])
                 maTabs[nTab]->CopyToClip(aCxt, nCol1, nRow1, nCol2, nRow2, pClipDoc->maTabs[nTab]);
@@ -2866,7 +2860,6 @@ void ScDocument::MixDocument( const ScRange& rRange, sal_uInt16 nFunction, bool
     SCTAB nTab1 = rRange.aStart.Tab();
     SCTAB nTab2 = rRange.aEnd.Tab();
     sc::MixDocContext aCxt(*this);
-    aCxt.setTabRange(nTab1, nTab2);
     SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pSrcDoc->maTabs.size()));
     for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
     {
@@ -2905,9 +2898,7 @@ void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
         SetAutoCalc( false );                   // avoid multiple calculations
 
         sc::CopyToDocContext aCxt(*this);
-        aCxt.setTabRange(rMark.GetFirstSelected(), rMark.GetLastSelected());
         sc::MixDocContext aMixDocCxt(*this);
-        aMixDocCxt.setTabRange(rMark.GetFirstSelected(), rMark.GetLastSelected());
 
         SCTAB nCount = static_cast<SCTAB>(maTabs.size());
         ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
@@ -2927,7 +2918,6 @@ void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
 
                     // context used for copying content to the temporary mix document.
                     sc::CopyToDocContext aMixCxt(*pMixDoc);
-                    aMixCxt.setTabRange(i, i);
                     maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
                                             IDF_CONTENTS, false, pMixDoc->maTabs[i] );
                 }
@@ -2973,9 +2963,7 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
         SCROW nEndRow = aArea.aEnd.Row();
 
         sc::CopyToDocContext aCxt(*this);
-        aCxt.setTabRange(rMark.GetFirstSelected(), rMark.GetLastSelected());
         sc::MixDocContext aMixDocCxt(*this);
-        aMixDocCxt.setTabRange(rMark.GetFirstSelected(), rMark.GetLastSelected());
         SCTAB nCount = static_cast<SCTAB>(maTabs.size());
         ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
         for (; itr != itrEnd && *itr < nCount; ++itr)
@@ -2993,7 +2981,6 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
                         pMixDoc->AddUndoTab( i, i );
 
                     sc::CopyToDocContext aMixCxt(*pMixDoc);
-                    aMixCxt.setTabRange(i, i);
                     maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
                                             IDF_CONTENTS, true, pMixDoc->maTabs[i], &rMark );
                 }
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 4af76be..51801af 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -407,7 +407,6 @@ void ScTable::InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE
         nWhichArray[2] = 0;
 
         sc::CopyToDocContext aCxt(*pDocument);
-        aCxt.setTabRange(nTab, nTab);
         for (SCSIZE i=0; i<nSize; i++)
         {
             aCol[nStartCol-1].CopyToColumn(aCxt, nStartRow, nEndRow, IDF_ATTRIB,
commit 252a30609357a5b2691b7796cc8f3f4f1319f655
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri May 17 16:39:15 2013 -0400

    Keep track of column block positions in ScDocumentImport too.
    
    This currently only affects document import via orcus, but it'll be
    good to put this in place.
    
    Change-Id: I8cc6d54aba6fab1f2774127f92c2a764f7b690fb

diff --git a/sc/inc/documentimport.hxx b/sc/inc/documentimport.hxx
index eeafbba..afd954b 100644
--- a/sc/inc/documentimport.hxx
+++ b/sc/inc/documentimport.hxx
@@ -15,10 +15,13 @@
 
 #include "rtl/ustring.hxx"
 
+#include <boost/noncopyable.hpp>
+
 class ScDocument;
 class ScAddress;
 class ScTokenArray;
 class ScBaseCell;
+struct ScDocumentImportImpl;
 
 /**
  * Accessor class to ScDocument.  Its purpose is to allow import filter to
@@ -27,15 +30,15 @@ class ScBaseCell;
  * position calculation, or anything else that requires expensive
  * computation which are unnecessary and undesirable during import.
  */
-class SC_DLLPUBLIC ScDocumentImport
+class SC_DLLPUBLIC ScDocumentImport : boost::noncopyable
 {
-    ScDocument& mrDoc;
+    ScDocumentImportImpl* mpImpl;
 
     ScDocumentImport(); // disabled
 
 public:
     ScDocumentImport(ScDocument& rDoc);
-    ScDocumentImport(const ScDocumentImport& r);
+    ~ScDocumentImport();
 
     ScDocument& getDoc();
     const ScDocument& getDoc() const;
diff --git a/sc/inc/mtvelements.hxx b/sc/inc/mtvelements.hxx
index b21f7c7..1628381 100644
--- a/sc/inc/mtvelements.hxx
+++ b/sc/inc/mtvelements.hxx
@@ -10,6 +10,7 @@
 #ifndef SC_MTVELEMENTS_HXX
 #define SC_MTVELEMENTS_HXX
 
+#include "address.hxx"
 #include "svl/broadcast.hxx"
 
 #define DEBUG_COLUMN_STORAGE 0
@@ -25,6 +26,10 @@
 #include <mdds/multi_type_vector.hpp>
 #include <mdds/multi_type_vector_custom_func1.hpp>
 
+#include <boost/unordered_map.hpp>
+
+class ScDocument;
+
 namespace sc {
 
 struct CellTextAttr
@@ -74,6 +79,20 @@ struct ColumnBlockPosition
     CellTextAttrStoreType::iterator miCellTextAttrPos;
 };
 
+class ColumnBlockPositionSet
+{
+    typedef boost::unordered_map<SCCOL, ColumnBlockPosition> ColumnsType;
+    typedef boost::unordered_map<SCTAB, ColumnsType> TablesType;
+
+    ScDocument& mrDoc;
+    TablesType maTables;
+
+public:
+    ColumnBlockPositionSet(ScDocument& rDoc);
+
+    ColumnBlockPosition* getBlockPosition(SCTAB nTab, SCCOL nCol);
+};
+
 }
 
 #endif
diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx
index c92688f..ced0936 100644
--- a/sc/source/core/data/documentimport.cxx
+++ b/sc/source/core/data/documentimport.cxx
@@ -15,24 +15,36 @@
 #include "formulacell.hxx"
 #include "docoptio.hxx"
 #include "globalnames.hxx"
+#include "mtvelements.hxx"
 
-ScDocumentImport::ScDocumentImport(ScDocument& rDoc) : mrDoc(rDoc) {}
-ScDocumentImport::ScDocumentImport(const ScDocumentImport& r) : mrDoc(r.mrDoc) {}
+struct ScDocumentImportImpl
+{
+    ScDocument& mrDoc;
+    sc::ColumnBlockPositionSet maBlockPosSet;
+
+    ScDocumentImportImpl(ScDocument& rDoc) : mrDoc(rDoc), maBlockPosSet(rDoc) {}
+};
+
+ScDocumentImport::ScDocumentImport(ScDocument& rDoc) : mpImpl(new ScDocumentImportImpl(rDoc)) {}
+ScDocumentImport::~ScDocumentImport()
+{
+    delete mpImpl;
+}
 
 ScDocument& ScDocumentImport::getDoc()
 {
-    return mrDoc;
+    return mpImpl->mrDoc;
 }
 
 const ScDocument& ScDocumentImport::getDoc() const
 {
-    return mrDoc;
+    return mpImpl->mrDoc;
 }
 
 SCTAB ScDocumentImport::getSheetIndex(const OUString& rName) const
 {
     SCTAB nTab = -1;
-    if (!mrDoc.GetTable(rName, nTab))
+    if (!mpImpl->mrDoc.GetTable(rName, nTab))
         return -1;
 
     return nTab;
@@ -40,33 +52,34 @@ SCTAB ScDocumentImport::getSheetIndex(const OUString& rName) const
 
 SCTAB ScDocumentImport::getSheetCount() const
 {
-    return mrDoc.maTabs.size();
+    return mpImpl->mrDoc.maTabs.size();
 }
 
 bool ScDocumentImport::appendSheet(const OUString& rName)
 {
-    SCTAB nTabCount = mrDoc.maTabs.size();
+    SCTAB nTabCount = mpImpl->mrDoc.maTabs.size();
     if (!ValidTab(nTabCount))
         return false;
 
-    mrDoc.maTabs.push_back(new ScTable(&mrDoc, nTabCount, rName));
+    mpImpl->mrDoc.maTabs.push_back(new ScTable(&mpImpl->mrDoc, nTabCount, rName));
     return true;
 }
 
 void ScDocumentImport::setOriginDate(sal_uInt16 nYear, sal_uInt16 nMonth, sal_uInt16 nDay)
 {
-    if (!mrDoc.pDocOptions)
-        mrDoc.pDocOptions = new ScDocOptions;
+    if (!mpImpl->mrDoc.pDocOptions)
+        mpImpl->mrDoc.pDocOptions = new ScDocOptions;
 
-    mrDoc.pDocOptions->SetDate(nDay, nMonth, nYear);
+    mpImpl->mrDoc.pDocOptions->SetDate(nDay, nMonth, nYear);
 }
 
 void ScDocumentImport::setAutoInput(const ScAddress& rPos, const OUString& rStr)
 {
-    if (!mrDoc.TableExists(rPos.Tab()))
+    if (!mpImpl->mrDoc.TableExists(rPos.Tab()))
         return;
 
-    mrDoc.maTabs[rPos.Tab()]->aCol[rPos.Col()].SetString(rPos.Row(), rPos.Tab(), rStr, mrDoc.GetAddressConvention());
+    mpImpl->mrDoc.maTabs[rPos.Tab()]->aCol[rPos.Col()].SetString(
+        rPos.Row(), rPos.Tab(), rStr, mpImpl->mrDoc.GetAddressConvention());
 }
 
 void ScDocumentImport::setNumericCell(const ScAddress& rPos, double fVal)
@@ -82,18 +95,18 @@ void ScDocumentImport::setStringCell(const ScAddress& rPos, const OUString& rStr
 void ScDocumentImport::setFormulaCell(
     const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar)
 {
-    insertCell(rPos, new ScFormulaCell(&mrDoc, rPos, rFormula, eGrammar));
+    insertCell(rPos, new ScFormulaCell(&mpImpl->mrDoc, rPos, rFormula, eGrammar));
 }
 
 void ScDocumentImport::setFormulaCell(const ScAddress& rPos, const ScTokenArray& rArray)
 {
-    insertCell(rPos, new ScFormulaCell(&mrDoc, rPos, &rArray));
+    insertCell(rPos, new ScFormulaCell(&mpImpl->mrDoc, rPos, &rArray));
 }
 
 void ScDocumentImport::finalize()
 {
     // Populate the text width and script type arrays in all columns.
-    ScDocument::TableContainer::iterator itTab = mrDoc.maTabs.begin(), itTabEnd = mrDoc.maTabs.end();
+    ScDocument::TableContainer::iterator itTab = mpImpl->mrDoc.maTabs.begin(), itTabEnd = mpImpl->mrDoc.maTabs.end();
     for (; itTab != itTabEnd; ++itTab)
     {
         if (!*itTab)
@@ -119,14 +132,18 @@ void ScDocumentImport::finalize()
 
 void ScDocumentImport::insertCell(const ScAddress& rPos, ScBaseCell* pCell)
 {
-    if (!mrDoc.TableExists(rPos.Tab()))
+    if (!mpImpl->mrDoc.TableExists(rPos.Tab()))
     {
         pCell->Delete();
         return;
     }
 
-    ScColumn& rCol = mrDoc.maTabs[rPos.Tab()]->aCol[rPos.Col()];
-    rCol.SetCell(rPos.Row(), pCell);
+    ScColumn& rCol = mpImpl->mrDoc.maTabs[rPos.Tab()]->aCol[rPos.Col()];
+    sc::ColumnBlockPosition* p = mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
+    if (p)
+        rCol.SetCell(*p, rPos.Row(), pCell);
+    else
+        rCol.SetCell(rPos.Row(), pCell);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/mtvelements.cxx b/sc/source/core/data/mtvelements.cxx
index 45c06dd..efe07cf 100644
--- a/sc/source/core/data/mtvelements.cxx
+++ b/sc/source/core/data/mtvelements.cxx
@@ -9,6 +9,7 @@
 
 #include "mtvelements.hxx"
 #include "globalnames.hxx"
+#include "document.hxx"
 
 namespace sc {
 
@@ -24,6 +25,45 @@ CellTextAttr::CellTextAttr(sal_uInt16 nTextWidth, sal_uInt8 nScriptType) :
     mnTextWidth(nTextWidth),
     mnScriptType(nScriptType) {}
 
+ColumnBlockPositionSet::ColumnBlockPositionSet(ScDocument& rDoc) : mrDoc(rDoc) {}
+
+ColumnBlockPosition* ColumnBlockPositionSet::getBlockPosition(SCTAB nTab, SCCOL nCol)
+{
+    TablesType::iterator itTab = maTables.find(nTab);
+    if (itTab == maTables.end())
+    {
+        std::pair<TablesType::iterator,bool> r =
+            maTables.insert(TablesType::value_type(nTab, ColumnsType()));
+        if (!r.second)
+            // insertion failed.
+            return NULL;
+
+        itTab = r.first;
+    }
+
+    ColumnsType& rCols = itTab->second;
+
+    ColumnsType::iterator it = rCols.find(nCol);
+    if (it != rCols.end())
+        // Block position for this column has already been fetched.
+        return &it->second;
+
+    std::pair<ColumnsType::iterator,bool> r =
+        rCols.insert(
+            ColumnsType::value_type(nCol, ColumnBlockPosition()));
+
+    if (!r.second)
+        // insertion failed.
+        return NULL;
+
+    it = r.first;
+
+    if (!mrDoc.InitColumnBlockPosition(it->second, nTab, nCol))
+        return NULL;
+
+    return &it->second;
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 430d81e1fd44f51a91b81da91504a004ab7373d8
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri May 17 15:08:23 2013 -0400

    Same with MixDocument(). But this one has additional bottleneck...
    
    With the removal of existing cells. So, this change is not enough to
    make this operation fly.
    
    Change-Id: Ic468375f6d0c28e2cc7d5391fb0565d53ee7fb4e

diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx
index 4d9224f..599da6e 100644
--- a/sc/inc/clipcontext.hxx
+++ b/sc/inc/clipcontext.hxx
@@ -90,6 +90,13 @@ public:
     virtual ~CopyToDocContext();
 };
 
+class MixDocContext : public ClipContextBase
+{
+public:
+    MixDocContext(ScDocument& rDoc);
+    virtual ~MixDocContext();
+};
+
 }
 
 #endif
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 0e7ed53..c71ffea 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -41,6 +41,7 @@ namespace sc {
     class CopyFromClipContext;
     class CopyToClipContext;
     class CopyToDocContext;
+    class MixDocContext;
     struct ColumnBlockPosition;
 }
 
@@ -231,10 +232,12 @@ public:
     void        RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow );
 
                 //  Selection (?) of this document
-    void        MixMarked( const ScMarkData& rMark, sal_uInt16 nFunction,
-                            bool bSkipEmpty, ScColumn& rSrcCol );
-    void        MixData( SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction, bool bSkipEmpty,
-                            ScColumn& rSrcCol );
+    void MixMarked(
+        sc::MixDocContext& rCxt, const ScMarkData& rMark, sal_uInt16 nFunction,
+        bool bSkipEmpty, const ScColumn& rSrcCol );
+    void MixData(
+        sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction, bool bSkipEmpty,
+        const ScColumn& rSrcCol );
 
     ScFormulaCell*  CreateRefCell( ScDocument* pDestDoc, const ScAddress& rDestPos,
                                     SCSIZE nIndex, sal_uInt16 nFlags ) const;
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 5f63d85..f01e811 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1988,6 +1988,8 @@ private: // CLOOK-Impl-methods
     };
 
     bool TableExists( SCTAB nTab ) const;
+    ScTable* FetchTable( SCTAB nTab );
+    const ScTable* FetchTable( SCTAB nTab ) const;
 
     void    MergeNumberFormatter(ScDocument* pSrcDoc);
 
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 7d0836f..f04a9bb 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -53,6 +53,7 @@ namespace sc {
     class CopyFromClipContext;
     class CopyToClipContext;
     class CopyToDocContext;
+    class MixDocContext;
     struct ColumnBlockPosition;
 }
 
@@ -412,10 +413,13 @@ public:
                                 ScTable* pTransClip, sal_uInt16 nFlags, bool bAsLink );
 
                 // mark of this document
-    void        MixMarked( const ScMarkData& rMark, sal_uInt16 nFunction,
-                            bool bSkipEmpty, ScTable* pSrcTab );
-    void        MixData( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
-                            sal_uInt16 nFunction, bool bSkipEmpty, ScTable* pSrcTab );
+    void MixMarked(
+        sc::MixDocContext& rCxt, const ScMarkData& rMark, sal_uInt16 nFunction,
+        bool bSkipEmpty, const ScTable* pSrcTab );
+
+    void MixData(
+        sc::MixDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+        sal_uInt16 nFunction, bool bSkipEmpty, const ScTable* pSrcTab );
 
     void        CopyData( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
                             SCCOL nDestCol, SCROW nDestRow, SCTAB nDestTab );
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index 8777aa3..2c7abdf 100644
--- a/sc/source/core/data/clipcontext.cxx
+++ b/sc/source/core/data/clipcontext.cxx
@@ -120,6 +120,9 @@ bool CopyToClipContext::isCloneNotes() const
 CopyToDocContext::CopyToDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {}
 CopyToDocContext::~CopyToDocContext() {}
 
+MixDocContext::MixDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {}
+MixDocContext::~MixDocContext() {}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index a29f791..b530184 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -828,8 +828,9 @@ ScBaseCell* ScColumn::CloneCell(
 }
 
 
-void ScColumn::MixMarked( const ScMarkData& rMark, sal_uInt16 nFunction,
-                            bool bSkipEmpty, ScColumn& rSrcCol )
+void ScColumn::MixMarked(
+    sc::MixDocContext& rCxt, const ScMarkData& rMark, sal_uInt16 nFunction,
+    bool bSkipEmpty, const ScColumn& rSrcCol )
 {
     SCROW nRow1, nRow2;
 
@@ -837,7 +838,7 @@ void ScColumn::MixMarked( const ScMarkData& rMark, sal_uInt16 nFunction,
     {
         ScMarkArrayIter aIter( rMark.GetArray()+nCol );
         while (aIter.Next( nRow1, nRow2 ))
-            MixData( nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol );
+            MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol);
     }
 }
 
@@ -885,9 +886,9 @@ static void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
 }
 
 
-void ScColumn::MixData( SCROW nRow1, SCROW nRow2,
-                            sal_uInt16 nFunction, bool bSkipEmpty,
-                            ScColumn& rSrcCol )
+void ScColumn::MixData(
+    sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction,
+    bool bSkipEmpty, const ScColumn& rSrcCol )
 {
     SCSIZE nSrcCount = rSrcCol.maItems.size();
 
@@ -1023,12 +1024,18 @@ void ScColumn::MixData( SCROW nRow1, SCROW nRow2,
 
         if ( pNew || bDelete ) // New result?
         {
+            sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
             if (pDest && !pNew) // Old cell present?
             {
                 Delete(nRow); // -> Delete
             }
             if (pNew)
-                Insert(nRow, pNew); // Insert new one
+            {
+                if (p)
+                    Insert(*p, nRow, pNew);
+                else
+                    Insert(nRow, pNew); // Insert new one
+            }
 
             Search( nRow, nIndex ); // Everything could have moved
             if (pNew)
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 6ca6fc0..5fbc1ac0 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2264,6 +2264,22 @@ bool ScDocument::TableExists( SCTAB nTab ) const

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list