[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - 290 commits - avmedia/README basic/source bin/distro-install-file-lists boost/boost.transform_width.patch boost/boost.wdeprecated-register.patch.0 boost/UnpackedTarball_boost.mk canvas/README chart2/AllLangResTarget_chartcontroller.mk chart2/Library_chartcontroller.mk chart2/Library_chartcore.mk chart2/source chart2/uiconfig config_host.mk.in configure.ac connectivity/source cppcanvas/README cppcanvas/source cppu/source cui/AllLangResTarget_cui.mk cui/source cui/uiconfig cui/UIConfig_cui.mk dbaccess/source desktop/source desktop/unx download.lst drawinglayer/source editeng/source extensions/source extras/source filter/inc filter/source filter/uiconfig filter/UIConfig_xsltdlg.mk forms/source framework/inc framework/source helpcontent2 i18nlangtag/source i18npool/source icon-themes/galaxy icon-themes/human icon-themes/oxygen idl/source include/drawinglayer include/editeng include/i18nlangtag include/oox include/osl inclu de/sal include/sfx2 include/sot include/svl include/svtools include/svx include/toolkit include/tools include/vcl include/xmloff ios/iosremote libexttextcat/android.patch libexttextcat/ExternalProject_exttextcat.mk libexttextcat/UnpackedTarball_exttextcat.mk libvisio/libvisio-0.0.29-remove_whitespace.patch.1 linguistic/source Makefile.fetch nss/nss.wheader-guard.patch.0 nss/UnpackedTarball_nss.mk offapi/com offapi/type_reference offapi/UnoApi_offapi.mk officecfg/registry oox/README oox/source package/source poppler/ExternalPackage_poppler.mk poppler/ExternalProject_poppler.mk poppler/Makefile poppler/Module_poppler.mk poppler/poppler-notests.patch.1 poppler/poppler-snprintf.patch.1 poppler/README poppler/UnpackedTarball_poppler.mk postprocess/CustomTarget_signing.mk postprocess/signing pyuno/Library_pyuno_wrapper.mk qadevOOo/objdsc qadevOOo/testdocs reportdesign/source RepositoryExternal.mk Repository.mk RepositoryModule_host.mk rsc/inc rsc/source sal/osl sax/source scaddins /source sc/CppunitTest_sc_filters_test.mk sc/CppunitTest_sc_subsequent_export_test.mk sc/CppunitTest_sc_subsequent_filters_test.mk sc/CppunitTest_sc_ucalc.mk sc/inc sc/Library_scqahelper.mk sc/Module_sc.mk scp2/source sc/qa sc/source sc/uiconfig sdext/Executable_xpdfimport.mk sdext/source sd/inc sd/README sd/source sd/uiconfig sfx2/inc sfx2/source slideshow/README solenv/gbuild sot/qa sot/source starmath/inc starmath/source starmath/uiconfig starmath/UIConfig_smath.mk svgio/source svl/Library_svl.mk svl/source svl/unx svtools/source svx/AllLangResTarget_svx.mk svx/AllLangResTarget_textconversiondlgs.mk svx/inc svx/source svx/uiconfig svx/UIConfig_svx.mk sw/AllLangResTarget_sw.mk swext/mediawiki sw/inc sw/qa sw/source sw/uiconfig sw/UIConfig_swriter.mk sysui/Package_osxicons.mk toolkit/AllLangResTarget_tk.mk toolkit/Library_tk.mk toolkit/Module_toolkit.mk toolkit/qa toolkit/source toolkit/util ucb/source unoxml/source unusedcode.easy uui/source vcl/generic vcl/inc vcl/README vcl/source vcl/unx wizards/com writerfilter/CustomTarget_source.mk writerfilter/Library_writerfilter.mk writerfilter/source xmloff/Library_xo.mk xmloff/source xpdf/ExternalPackage_xpdf.mk xpdf/ExternalProject_xpdf.mk xpdf/Makefile xpdf/Module_xpdf.mk xpdf/README xpdf/UnpackedTarball_xpdf.mk xpdf/xpdf-3.02-gfxColorMaxComps.patch xpdf/xpdf-3.02-ooopwd.patch xpdf/xpdf-3.02.patch xpdf/xpdf-no-writable-literals.patch

Kohei Yoshida kohei.yoshida at gmail.com
Mon Jul 8 21:41:30 PDT 2013


Rebased ref, commits from common ancestor:
commit 1bb50699c8524093d7ac08efd74bdbf3dc80894b
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 9 00:40:50 2013 -0400

    Add test for formula grouping during copy and paste.
    
    Change-Id: I19604b753801073366058527c19020cc5db812d0

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 8b2f6da..e592ccd 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -81,6 +81,17 @@
 
 #include "ucalc.hxx"
 
+FormulaGrammarSwitch::FormulaGrammarSwitch(ScDocument* pDoc, formula::FormulaGrammar::Grammar eGrammar) :
+    mpDoc(pDoc), meOldGrammar(pDoc->GetGrammar())
+{
+    mpDoc->SetGrammar(eGrammar);
+}
+
+FormulaGrammarSwitch::~FormulaGrammarSwitch()
+{
+    mpDoc->SetGrammar(meOldGrammar);
+}
+
 void printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption)
 {
     SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
@@ -123,26 +134,6 @@ ScRange insertRangeData(ScDocument* pDoc, const ScAddress& rPos, const char* aDa
     return aRange;
 }
 
-/**
- * Temporarily set formula grammar.
- */
-class FormulaGrammarSwitch
-{
-    ScDocument* mpDoc;
-    formula::FormulaGrammar::Grammar meOldGrammar;
-public:
-    FormulaGrammarSwitch(ScDocument* pDoc, formula::FormulaGrammar::Grammar eGrammar) :
-        mpDoc(pDoc), meOldGrammar(pDoc->GetGrammar())
-    {
-        mpDoc->SetGrammar(eGrammar);
-    }
-
-    ~FormulaGrammarSwitch()
-    {
-        mpDoc->SetGrammar(meOldGrammar);
-    }
-};
-
 class MeasureTimeSwitch
 {
     double& mrDiff;
@@ -5744,11 +5735,8 @@ void Test::testCopyPaste()
 
     //copy Sheet1.A1:C1 to Sheet2.A2:C2
     ScRange aRange(0,0,0,2,0,0);
-    ScClipParam aClipParam(aRange, false);
-    ScMarkData aMark;
-    aMark.SetMarkArea(aRange);
     ScDocument aClipDoc(SCDOCMODE_CLIP);
-    m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
+    copyToClip(m_pDoc, aRange, &aClipDoc);
 
     sal_uInt16 nFlags = IDF_ALL;
     aRange = ScRange(0,1,1,2,1,1);//target: Sheet2.A2:C2
@@ -6938,6 +6926,21 @@ void Test::clearRange(ScDocument* pDoc, const ScRange& rRange)
         rRange.aEnd.Col(), rRange.aEnd.Row(), aMarkData, IDF_CONTENTS);
 }
 
+void Test::copyToClip(ScDocument* pSrcDoc, const ScRange& rRange, ScDocument* pClipDoc)
+{
+    ScClipParam aClipParam(rRange, false);
+    ScMarkData aMark;
+    aMark.SetMarkArea(rRange);
+    pSrcDoc->CopyToClip(aClipParam, pClipDoc, &aMark);
+}
+
+void Test::pasteFromClip(ScDocument* pDestDoc, const ScRange& rDestRange, ScDocument* pClipDoc)
+{
+    ScMarkData aMark;
+    aMark.SetMarkArea(rDestRange);
+    pDestDoc->CopyFromClip(rDestRange, aMark, IDF_ALL, NULL, pClipDoc);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index ca5ddcf..1a141a0 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -12,11 +12,25 @@
 
 #include "helper/qahelper.hxx"
 
+/**
+ * Temporarily set formula grammar.
+ */
+class FormulaGrammarSwitch
+{
+    ScDocument* mpDoc;
+    formula::FormulaGrammar::Grammar meOldGrammar;
+public:
+    FormulaGrammarSwitch(ScDocument* pDoc, formula::FormulaGrammar::Grammar eGrammar);
+    ~FormulaGrammarSwitch();
+};
+
 class Test : public test::BootstrapFixture
 {
 public:
 
     static void clearRange(ScDocument* pDoc, const ScRange& rRange);
+    static void copyToClip(ScDocument* pSrcDoc, const ScRange& rRange, ScDocument* pClipDoc);
+    static void pasteFromClip(ScDocument* pDestDoc, const ScRange& rDestRange, ScDocument* pClipDoc);
 
     Test();
 
@@ -157,6 +171,7 @@ public:
     void testUpdateReference();
     void testSearchCells();
     void testSharedFormulas();
+    void testSharedFormulasCopyPaste();
     void testFormulaPosition();
 
     /**
@@ -275,6 +290,7 @@ public:
     CPPUNIT_TEST(testUpdateReference);
     CPPUNIT_TEST(testSearchCells);
     CPPUNIT_TEST(testSharedFormulas);
+    CPPUNIT_TEST(testSharedFormulasCopyPaste);
     CPPUNIT_TEST(testFormulaPosition);
     CPPUNIT_TEST(testJumpToPrecedentsDependents);
     CPPUNIT_TEST(testSetBackgroundColor);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index 3025b52..0ce78e9 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -9,6 +9,9 @@
 
 #include "ucalc.hxx"
 #include "editutil.hxx"
+#include "clipparam.hxx"
+
+#include "formula/grammar.hxx"
 
 void Test::testSharedFormulas()
 {
@@ -224,4 +227,43 @@ void Test::testSharedFormulas()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testSharedFormulasCopyPaste()
+{
+    m_pDoc->InsertTab(0, "Test");
+    FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
+
+    // Fill formula cells B1:B10.
+    for (SCROW i = 0; i <= 9; ++i)
+        m_pDoc->SetString(1, i, 0, "=RC[-1]");
+
+    ScAddress aPos(1, 8, 0); // B9
+    ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(0, pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(10, pFC->GetSharedLength());
+
+    // Copy formulas in B6:B9 to the clipboard doc.
+    ScRange aSrcRange(1,5,0,1,8,0); // B6:B9
+    ScDocument aClipDoc(SCDOCMODE_CLIP);
+    copyToClip(m_pDoc, aSrcRange, &aClipDoc);
+    pFC = aClipDoc.GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B9 in the clip doc should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(5, pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(4, pFC->GetSharedLength());
+
+    // Paste them to C2:C10.
+    ScRange aDestRange(2,1,0,2,9,0);
+    OUString aRS;
+    aDestRange.Format(aRS, SCR_ABS);
+    pasteFromClip(m_pDoc, aDestRange, &aClipDoc);
+    aPos.SetCol(2);
+    aPos.SetRow(1);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("C2 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(1, pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(9, pFC->GetSharedLength());
+
+    m_pDoc->DeleteTab(0);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 5d48fc6e493ff95df3f94a82658a5b21c65ae553
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 9 00:39:26 2013 -0400

    Group formula cells when copying to clip, prevent crash during pasting.
    
    Change-Id: I6a33301d74d9845e8c0fa77894fbd89bea40fd1b

diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index bd48bad..bb6677d 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1257,6 +1257,40 @@ class CopyToClipHandler
             maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
     }
 
+    void groupFormulaCells(std::vector<ScFormulaCell*>& rCells)
+    {
+        if (rCells.empty())
+            return;
+
+        std::vector<ScFormulaCell*>::iterator it = rCells.begin(), itEnd = rCells.end();
+        ScFormulaCell* pPrev = *it;
+        ScFormulaCell* pCur = NULL;
+        for (++it; it != itEnd; ++it, pPrev = pCur)
+        {
+            pCur = *it;
+            ScFormulaCell::CompareState eState = pPrev->CompareByTokenArray(*pPrev);
+            if (eState == ScFormulaCell::NotEqual)
+                continue;
+
+            ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup();
+            if (xGroup)
+            {
+                // Extend the group.
+                ++xGroup->mnLength;
+                pCur->SetCellGroup(xGroup);
+                continue;
+            }
+
+            // Create a new group.
+            xGroup.reset(new ScFormulaCellGroup);
+            xGroup->mnStart = pPrev->aPos.Row();
+            xGroup->mnLength = 2;
+            xGroup->mbInvariant = (eState == ScFormulaCell::EqualInvariant);
+            pPrev->SetCellGroup(xGroup);
+            pCur->SetCellGroup(xGroup);
+        }
+    }
+
 public:
     CopyToClipHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos) :
         mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos)
@@ -1336,6 +1370,9 @@ public:
                     aCloned.push_back(new ScFormulaCell(rOld, mrDestCol.GetDoc(), aDestPos));
                 }
 
+                // Group the cloned formula cells.
+                groupFormulaCells(aCloned);
+
                 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
                     maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
 
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index d99a6ec..8352d46 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -897,6 +897,7 @@ class CopyCellsFromClipHandler
     SCCOL mnCol;
     long mnRowOffset;
     sc::ColumnBlockPosition maDestBlockPos;
+    sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration.
 
     bool isDateCell(SCROW nSrcRow) const
     {
@@ -928,15 +929,22 @@ public:
         mrDestCol(rDestCol),
         mnTab(nDestTab),
         mnCol(nDestCol),
-        mnRowOffset(nRowOffset)
+        mnRowOffset(nRowOffset),
+        mpDestBlockPos(mrCxt.getBlockPosition(nDestTab, nDestCol))
     {
-        sc::ColumnBlockPosition* p = mrCxt.getBlockPosition(nDestTab, nDestCol);
-        if (p)
-            maDestBlockPos = *p;
+        if (mpDestBlockPos)
+            maDestBlockPos = *mpDestBlockPos;
         else
             mrDestCol.InitBlockPosition(maDestBlockPos);
     }
 
+    ~CopyCellsFromClipHandler()
+    {
+        if (mpDestBlockPos)
+            // Don't forget to save this to the context!
+            *mpDestBlockPos = maDestBlockPos;
+    }
+
     void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
     {
         if (node.type == sc::element_type_empty)
commit 4b381f3e4dd25157dd1463c604f0c7dd0b99473e
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 20:08:22 2013 -0400

    Fix linking problem with subsequent_filters-test.
    
    Change-Id: I5ccf8792ce0d3ffa9a0dffc1bc8976fe029808ab

diff --git a/sc/qa/unit/helper/qahelper.hxx b/sc/qa/unit/helper/qahelper.hxx
index 31e00a8..efbd3b9 100644
--- a/sc/qa/unit/helper/qahelper.hxx
+++ b/sc/qa/unit/helper/qahelper.hxx
@@ -71,7 +71,7 @@ struct FileFormat {
     const char* pName; const char* pFilterName; const char* pTypeName; unsigned int nFormatType;
 };
 
-extern FileFormat aFileFormats[];
+SC_DLLPUBLIC extern FileFormat aFileFormats[];
 
 // Why is this here and not in osl, and using the already existing file
 // handling APIs? Do we really want to add arbitrary new file handling
commit 0cea0cf1a43c5e2dc481f4672f2d78ea8ef1c4e2
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 18:28:43 2013 -0400

    Split ucalc.cxx into multiple source files.
    
    Change-Id: Ic46dcc8cb415fd3ea9062d477260cb6f120fb815

diff --git a/sc/CppunitTest_sc_ucalc.mk b/sc/CppunitTest_sc_ucalc.mk
index 702117f..8ab28b1 100644
--- a/sc/CppunitTest_sc_ucalc.mk
+++ b/sc/CppunitTest_sc_ucalc.mk
@@ -13,6 +13,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sc_ucalc))
 
 $(eval $(call gb_CppunitTest_add_exception_objects,sc_ucalc, \
     sc/qa/unit/ucalc \
+    sc/qa/unit/ucalc_sharedformula \
 ))
 
 $(eval $(call gb_CppunitTest_use_library_objects,sc_ucalc,sc))
diff --git a/sc/qa/unit/helper/qahelper.cxx b/sc/qa/unit/helper/qahelper.cxx
index b330f2c..ee806bc 100644
--- a/sc/qa/unit/helper/qahelper.cxx
+++ b/sc/qa/unit/helper/qahelper.cxx
@@ -14,6 +14,16 @@
 
 #include <fstream>
 
+FileFormat aFileFormats[] = {
+    { "ods" , "calc8", "", ODS_FORMAT_TYPE },
+    { "xls" , "MS Excel 97", "calc_MS_EXCEL_97", XLS_FORMAT_TYPE },
+    { "xlsx", "Calc MS Excel 2007 XML" , "MS Excel 2007 XML", XLSX_FORMAT_TYPE },
+    { "csv" , "Text - txt - csv (StarCalc)", "generic_Text", CSV_FORMAT_TYPE },
+    { "html" , "calc_HTML_WebQuery", "generic_HTML", HTML_FORMAT_TYPE },
+    { "123" , "Lotus", "calc_Lotus", LOTUS123_FORMAT_TYPE },
+    { "dif", "DIF", "calc_DIF", DIF_FORMAT_TYPE },
+};
+
 bool testEqualsWithTolerance( long nVal1, long nVal2, long nTol )
 {
     return ( labs( nVal1 - nVal2 ) <= nTol );
diff --git a/sc/qa/unit/helper/qahelper.hxx b/sc/qa/unit/helper/qahelper.hxx
index b01a581..31e00a8 100644
--- a/sc/qa/unit/helper/qahelper.hxx
+++ b/sc/qa/unit/helper/qahelper.hxx
@@ -71,15 +71,7 @@ struct FileFormat {
     const char* pName; const char* pFilterName; const char* pTypeName; unsigned int nFormatType;
 };
 
-FileFormat aFileFormats[] = {
-    { "ods" , "calc8", "", ODS_FORMAT_TYPE },
-    { "xls" , "MS Excel 97", "calc_MS_EXCEL_97", XLS_FORMAT_TYPE },
-    { "xlsx", "Calc MS Excel 2007 XML" , "MS Excel 2007 XML", XLSX_FORMAT_TYPE },
-    { "csv" , "Text - txt - csv (StarCalc)", "generic_Text", CSV_FORMAT_TYPE },
-    { "html" , "calc_HTML_WebQuery", "generic_HTML", HTML_FORMAT_TYPE },
-    { "123" , "Lotus", "calc_Lotus", LOTUS123_FORMAT_TYPE },
-    { "dif", "DIF", "calc_DIF", DIF_FORMAT_TYPE },
-};
+extern FileFormat aFileFormats[];
 
 // Why is this here and not in osl, and using the already existing file
 // handling APIs? Do we really want to add arbitrary new file handling
@@ -94,7 +86,9 @@ SC_DLLPUBLIC void testFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab, St
 //need own handler because conditional formatting strings must be generated
 SC_DLLPUBLIC void testCondFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab);
 
-std::string print(const ScAddress& rAddr)
+SC_DLLPUBLIC void clearRange(ScDocument* pDoc, const ScRange& rRange);
+
+inline std::string print(const ScAddress& rAddr)
 {
     std::ostringstream str;
     str << "Col: " << rAddr.Col();
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index f05872f..8b2f6da 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -54,7 +54,6 @@
 #include "tokenarray.hxx"
 #include "scopetools.hxx"
 #include "dociter.hxx"
-#include "editutil.hxx"
 
 #include "formula/IFunctionDescription.hxx"
 
@@ -80,309 +79,7 @@
 #include <sstream>
 #include <vector>
 
-#include "helper/qahelper.hxx"
-
-using namespace ::com::sun::star;
-
-using ::std::cout;
-using ::std::cerr;
-using ::std::endl;
-using ::std::vector;
-
-namespace {
-
-class Test : public test::BootstrapFixture {
-public:
-    Test();
-
-    virtual void setUp();
-    virtual void tearDown();
-
-    /**
-     * Basic performance regression test. Pick some actions that *should* take
-     * only a fraction of a second to complete, and make sure they stay that
-     * way. We set the threshold to 1 second for each action which should be
-     * large enough to accommodate slower machines or machines with high load.
-     */
-    void testPerf();
-    void testCollator();
-    void testRangeList();
-    void testInput();
-    void testFormulaHashAndTag();
-    void testFuncSUM();
-    void testFuncPRODUCT();
-    void testFuncN();
-    void testFuncCOUNTIF();
-    void testFuncNUMBERVALUE();
-    void testFuncVLOOKUP();
-    void testFuncMATCH();
-    void testFuncCELL();
-    void testFuncDATEDIF();
-    void testFuncINDIRECT();
-    void testFuncIFERROR();
-    void testCopyToDocument();
-    /**
-     * Make sure the SHEETS function gets properly updated during sheet
-     * insertion and removal.
-     */
-    void testSheetsFunc();
-    void testVolatileFunc();
-
-    void testHorizontalIterator();
-
-    /**
-     * Basic test for formula dependency tracking.
-     */
-    void testFormulaDepTracking();
-
-    /**
-     * Another test for formula dependency tracking, inspired by fdo#56278.
-     */
-    void testFormulaDepTracking2();
-
-    /**
-     * More direct test for cell broadcaster management, used to track formula
-     * dependencies.
-     */
-    void testCellBroadcaster();
-
-    void testFuncParam();
-    void testNamedRange();
-    void testCSV();
-    void testMatrix();
-    void testEnterMixedMatrix();
-
-    /**
-     * Basic test for pivot tables.
-     */
-    void testPivotTable();
-
-    /**
-     * Test against unwanted automatic format detection on field names and
-     * field members in pivot tables.
-     */
-    void testPivotTableLabels();
-
-    /**
-     * Make sure that we set cells displaying date values numeric cells,
-     * rather than text cells.  Grouping by date or number functionality
-     * depends on this.
-     */
-    void testPivotTableDateLabels();
-
-    /**
-     * Test for pivot table's filtering functionality by page fields.
-     */
-    void testPivotTableFilters();
-
-    /**
-     * Test for pivot table's named source range.
-     */
-    void testPivotTableNamedSource();
-
-    /**
-     * Test for pivot table cache.  Each dimension in the pivot cache stores
-     * only unique values that are sorted in ascending order.
-     */
-    void testPivotTableCache();
-
-    /**
-     * Test for pivot table containing data fields that reference the same
-     * source field but different functions.
-     */
-    void testPivotTableDuplicateDataFields();
-
-    void testPivotTableNormalGrouping();
-    void testPivotTableNumberGrouping();
-    void testPivotTableDateGrouping();
-    void testPivotTableEmptyRows();
-    void testPivotTableTextNumber();
-
-    /**
-     * Test for checking that pivot table treats strings in a case insensitive
-     * manner.
-     */
-    void testPivotTableCaseInsensitiveStrings();
-
-    /**
-     * Test for pivot table's handling of double-precision numbers that are
-     * very close together.
-     */
-    void testPivotTableNumStability();
-
-    /**
-     * Test for pivot table that include field with various non-default field
-     * refrences.
-     */
-    void testPivotTableFieldReference();
-
-    /**
-     * Test pivot table functionality performed via ScDBDocFunc.
-     */
-    void testPivotTableDocFunc();
-
-    void testSheetCopy();
-    void testSheetMove();
-    void testExternalRef();
-    void testExternalRefFunctions();
-    void testDataArea();
-    void testAutofilter();
-    void testCopyPaste();
-    void testMergedCells();
-    void testUpdateReference();
-    void testSearchCells();
-    void testSharedFormulas();
-    void testFormulaPosition();
-
-    /**
-     * Make sure the sheet streams are invalidated properly.
-     */
-    void testStreamValid();
-
-    /**
-     * Test built-in cell functions to make sure their categories and order
-     * are correct.
-     */
-    void testFunctionLists();
-
-    void testGraphicsInGroup();
-    void testGraphicsOnSheetMove();
-
-    void testPostIts();
-
-    /**
-     * Test toggling relative/absolute flag of cell and cell range references.
-     * This corresponds with hitting Shift-F4 while the cursor is on a formula
-     * cell.
-     */
-    void testToggleRefFlag();
-
-    /**
-     * Test to make sure correct precedent / dependent cells are obtained when
-     * preparing to jump to them.
-     */
-    void testJumpToPrecedentsDependents();
-
-    void testSetBackgroundColor();
-    void testRenameTable();
-
-    void testAutoFill();
-    void testCopyPasteFormulas();
-    void testCopyPasteFormulasExternalDoc();
-
-    void testFindAreaPosVertical();
-    void testFindAreaPosColRight();
-    void testSort();
-    void testSortWithFormulaRefs();
-    void testShiftCells();
-    void testDeleteRow();
-    void testDeleteCol();
-    void testAnchoredRotatedShape();
-    void testCellTextWidth();
-
-    /**
-     * Test formula & formula grouping
-     */
-    void testFormulaGrouping();
-    void testCondFormatINSDEL();
-
-    CPPUNIT_TEST_SUITE(Test);
-#if CALC_TEST_PERF
-    CPPUNIT_TEST(testPerf);
-#endif
-    CPPUNIT_TEST(testCollator);
-    CPPUNIT_TEST(testRangeList);
-    CPPUNIT_TEST(testInput);
-    CPPUNIT_TEST(testFormulaHashAndTag);
-    CPPUNIT_TEST(testFuncSUM);
-    CPPUNIT_TEST(testFuncPRODUCT);
-    CPPUNIT_TEST(testFuncN);
-    CPPUNIT_TEST(testFuncCOUNTIF);
-    CPPUNIT_TEST(testFuncNUMBERVALUE);
-    CPPUNIT_TEST(testFuncVLOOKUP);
-    CPPUNIT_TEST(testFuncMATCH);
-    CPPUNIT_TEST(testFuncCELL);
-    CPPUNIT_TEST(testFuncDATEDIF);
-    CPPUNIT_TEST(testFuncINDIRECT);
-    CPPUNIT_TEST(testFuncIFERROR);
-    CPPUNIT_TEST(testCopyToDocument);
-    CPPUNIT_TEST(testSheetsFunc);
-    CPPUNIT_TEST(testVolatileFunc);
-    CPPUNIT_TEST(testHorizontalIterator);
-    CPPUNIT_TEST(testFormulaDepTracking);
-    CPPUNIT_TEST(testFormulaDepTracking2);
-    CPPUNIT_TEST(testCellBroadcaster);
-    CPPUNIT_TEST(testFuncParam);
-    CPPUNIT_TEST(testNamedRange);
-    CPPUNIT_TEST(testCSV);
-    CPPUNIT_TEST(testMatrix);
-    CPPUNIT_TEST(testEnterMixedMatrix);
-    CPPUNIT_TEST(testPivotTable);
-    CPPUNIT_TEST(testPivotTableLabels);
-    CPPUNIT_TEST(testPivotTableDateLabels);
-    CPPUNIT_TEST(testPivotTableFilters);
-    CPPUNIT_TEST(testPivotTableNamedSource);
-    CPPUNIT_TEST(testPivotTableCache);
-    CPPUNIT_TEST(testPivotTableDuplicateDataFields);
-    CPPUNIT_TEST(testPivotTableNormalGrouping);
-    CPPUNIT_TEST(testPivotTableNumberGrouping);
-    CPPUNIT_TEST(testPivotTableDateGrouping);
-    CPPUNIT_TEST(testPivotTableEmptyRows);
-    CPPUNIT_TEST(testPivotTableTextNumber);
-    CPPUNIT_TEST(testPivotTableCaseInsensitiveStrings);
-    CPPUNIT_TEST(testPivotTableNumStability);
-    CPPUNIT_TEST(testPivotTableFieldReference);
-    CPPUNIT_TEST(testPivotTableDocFunc);
-    CPPUNIT_TEST(testSheetCopy);
-    CPPUNIT_TEST(testSheetMove);
-    CPPUNIT_TEST(testExternalRef);
-    CPPUNIT_TEST(testExternalRefFunctions);
-    CPPUNIT_TEST(testDataArea);
-    CPPUNIT_TEST(testGraphicsInGroup);
-    CPPUNIT_TEST(testGraphicsOnSheetMove);
-    CPPUNIT_TEST(testPostIts);
-    CPPUNIT_TEST(testStreamValid);
-    CPPUNIT_TEST(testFunctionLists);
-    CPPUNIT_TEST(testToggleRefFlag);
-    CPPUNIT_TEST(testAutofilter);
-    CPPUNIT_TEST(testCopyPaste);
-    CPPUNIT_TEST(testMergedCells);
-    CPPUNIT_TEST(testUpdateReference);
-    CPPUNIT_TEST(testSearchCells);
-    CPPUNIT_TEST(testSharedFormulas);
-    CPPUNIT_TEST(testFormulaPosition);
-    CPPUNIT_TEST(testJumpToPrecedentsDependents);
-    CPPUNIT_TEST(testSetBackgroundColor);
-    CPPUNIT_TEST(testRenameTable);
-    CPPUNIT_TEST(testAutoFill);
-    CPPUNIT_TEST(testCopyPasteFormulas);
-    CPPUNIT_TEST(testCopyPasteFormulasExternalDoc);
-    CPPUNIT_TEST(testFindAreaPosVertical);
-    CPPUNIT_TEST(testFindAreaPosColRight);
-    CPPUNIT_TEST(testSort);
-    CPPUNIT_TEST(testSortWithFormulaRefs);
-    CPPUNIT_TEST(testShiftCells);
-    CPPUNIT_TEST(testDeleteRow);
-    CPPUNIT_TEST(testDeleteCol);
-    CPPUNIT_TEST(testAnchoredRotatedShape);
-    CPPUNIT_TEST(testCellTextWidth);
-    CPPUNIT_TEST(testFormulaGrouping);
-    CPPUNIT_TEST(testCondFormatINSDEL);
-    CPPUNIT_TEST_SUITE_END();
-
-private:
-    ScDocument *m_pDoc;
-    ScDocShellRef m_xDocShRef;
-};
-
-void clearRange(ScDocument* pDoc, const ScRange& rRange)
-{
-    ScMarkData aMarkData;
-    aMarkData.SetMarkArea(rRange);
-    pDoc->DeleteArea(
-        rRange.aStart.Col(), rRange.aStart.Row(),
-        rRange.aEnd.Col(), rRange.aEnd.Row(), aMarkData, IDF_CONTENTS);
-}
+#include "ucalc.hxx"
 
 void printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption)
 {
@@ -407,7 +104,7 @@ ScRange insertRangeData(ScDocument* pDoc, const ScAddress& rPos, const char* aDa
     aRange.aEnd.SetCol(rPos.Col()+_Size-1);
     aRange.aEnd.SetRow(rPos.Row()+nRowCount-1);
 
-    clearRange(pDoc, aRange);
+    Test::clearRange(pDoc, aRange);
 
     for (size_t i = 0; i < _Size; ++i)
     {
@@ -4969,8 +4666,8 @@ void Test::testExternalRef()
 
 void testExtRefFuncT(ScDocument* pDoc, ScDocument* pExtDoc)
 {
-    clearRange(pDoc, ScRange(0, 0, 0, 1, 9, 0));
-    clearRange(pExtDoc, ScRange(0, 0, 0, 1, 9, 0));
+    Test::clearRange(pDoc, ScRange(0, 0, 0, 1, 9, 0));
+    Test::clearRange(pExtDoc, ScRange(0, 0, 0, 1, 9, 0));
 
     pExtDoc->SetString(0, 0, 0, OUString("'1.2"));
     pExtDoc->SetString(0, 1, 0, OUString("Foo"));
@@ -6313,220 +6010,6 @@ void Test::testSearchCells()
     m_pDoc->DeleteTab(0);
 }
 
-void Test::testSharedFormulas()
-{
-    m_pDoc->InsertTab(0, "Test");
-
-    ScAddress aPos(1, 9, 0); // B10
-    m_pDoc->SetString(aPos, "=A10*2"); // Insert into B10.
-    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("Expected to be a non-shared cell.", pFC && !pFC->IsShared());
-
-    aPos.SetRow(10); // B11
-    m_pDoc->SetString(aPos, "=A11*2");
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
-
-    aPos.SetRow(8); // B9
-    m_pDoc->SetString(aPos, "=A9*2");
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
-
-    aPos.SetRow(12); // B13
-    m_pDoc->SetString(aPos, "=A13*2");
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This formula cell shouldn't be shared yet.", pFC && !pFC->IsShared());
-
-    // Insert a formula to B12, and B9:B13 should be shared.
-    aPos.SetRow(11); // B12
-    m_pDoc->SetString(aPos, "=A12*2");
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedLength());
-
-    // Insert formulas to B15:B16.
-    aPos.SetRow(14); // B15
-    m_pDoc->SetString(aPos, "=A15*2");
-    aPos.SetRow(15); // B16
-    m_pDoc->SetString(aPos, "=A16*2");
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
-
-    // Insert a formula to B14, and B9:B16 should be shared.
-    aPos.SetRow(13); // B14
-    m_pDoc->SetString(aPos, "=A14*2");
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
-
-    // Insert an incompatible formula to B12, to split the shared range to B9:B11 and B13:B16.
-    aPos.SetRow(11); // B12
-    m_pDoc->SetString(aPos, "=$A$1*4");
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell shouldn't be shared.", pFC && !pFC->IsShared());
-
-    aPos.SetRow(8); // B9
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
-
-    aPos.SetRow(12); // B13
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
-
-    // Extend B13:B16 to B13:B20.
-    aPos.SetRow(16); // B17
-    m_pDoc->SetString(aPos, "=A17*2");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A18*2");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A19*2");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A20*2");
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
-    // B13:B20 shuld be shared.
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
-
-    // Empty B19. This should split it into B13:B18, and B20 non-shared.
-    aPos.SetRow(18);
-    m_pDoc->SetEmptyCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("This cell should have been emptied.", m_pDoc->GetCellType(aPos) == CELLTYPE_NONE);
-    aPos.SetRow(12); // B13
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    // B13:B18 should be shared.
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength());
-    // B20 shold be non-shared.
-    aPos.SetRow(19); // B20
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("B20 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared());
-
-    // Empty B14, to make B13 non-shared and B15:B18 shared.
-    aPos.SetRow(13); // B14
-    m_pDoc->SetEmptyCell(aPos);
-    aPos.SetRow(12); // B13
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    // B13 should be non-shared.
-    CPPUNIT_ASSERT_MESSAGE("B13 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared());
-    // B15:B18 should be shared.
-    aPos.SetRow(14); // B15
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
-
-    // Set numeric value to B15, to make B16:B18 shared.
-    aPos.SetRow(14);
-    m_pDoc->SetValue(aPos, 1.2);
-    aPos.SetRow(15);
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    // B16:B18 should be shared.
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(15), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
-
-    // Set string value to B16 to make B17:B18 shared.
-    aPos.SetRow(15);
-    ScCellValue aCell("Test");
-    CPPUNIT_ASSERT_MESSAGE("This should be a string value.", aCell.meType == CELLTYPE_STRING);
-    aCell.commit(*m_pDoc, aPos);
-    CPPUNIT_ASSERT_EQUAL(*aCell.mpString, m_pDoc->GetString(aPos));
-    aPos.SetRow(16);
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    // B17:B18 should be shared.
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(16), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
-
-    // Set edit text to B17. Now B18 should be non-shared.
-    ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine();
-    rEditEngine.SetText("Edit Text");
-    aPos.SetRow(16);
-    m_pDoc->SetEditText(aPos, rEditEngine.CreateTextObject());
-    CPPUNIT_ASSERT_EQUAL(CELLTYPE_EDIT, m_pDoc->GetCellType(aPos));
-    aPos.SetRow(17);
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("B18 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_MESSAGE("B18 should be non-shared.", !pFC->IsShared());
-
-    // Set up a new group for shared formulas in B2:B10.
-    clearRange(m_pDoc, ScRange(0,0,0,2,100,0));
-
-    aPos.SetRow(1);
-    m_pDoc->SetString(aPos, "=A2*10");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A3*10");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A4*10");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A5*10");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A6*10");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A7*10");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A8*10");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A9*10");
-    aPos.IncRow();
-    m_pDoc->SetString(aPos, "=A10*10");
-
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("B10 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength());
-
-    // Delete A4:B8. This should splite the grouping to B2:B3 and B9:B10.
-    clearRange(m_pDoc, ScRange(0,3,0,1,7,0));
-    aPos.SetRow(1);
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
-
-    aPos.SetRow(8);
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
-
-    // Delete rows 4:8 and shift row 9 and below up to row 4.  This should
-    // re-merge the two into a group of B2:B5.
-    m_pDoc->DeleteRow(ScRange(0,3,0,MAXCOL,7,0));
-    aPos.SetRow(1);
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
-
-    // Insert 2 rows at row 4, to split it into B2:B3 and B6:B7.
-    m_pDoc->InsertRow(ScRange(0,3,0,MAXCOL,4,0));
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
-
-    aPos.SetRow(5);
-    pFC = m_pDoc->GetFormulaCell(aPos);
-    CPPUNIT_ASSERT_MESSAGE("B6 should be a formula cell.", pFC);
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedTopRow());
-    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
-
-    m_pDoc->DeleteTab(0);
-}
-
 namespace {
 
 bool checkFormulaPosition(ScDocument& rDoc, const ScAddress& rPos)
@@ -7446,10 +6929,17 @@ void Test::testCondFormatINSDEL()
     m_pDoc->DeleteTab(0);
 }
 
-CPPUNIT_TEST_SUITE_REGISTRATION(Test);
-
+void Test::clearRange(ScDocument* pDoc, const ScRange& rRange)
+{
+    ScMarkData aMarkData;
+    aMarkData.SetMarkArea(rRange);
+    pDoc->DeleteArea(
+        rRange.aStart.Col(), rRange.aStart.Row(),
+        rRange.aEnd.Col(), rRange.aEnd.Row(), aMarkData, IDF_CONTENTS);
 }
 
+CPPUNIT_TEST_SUITE_REGISTRATION(Test);
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
new file mode 100644
index 0000000..ca5ddcf
--- /dev/null
+++ b/sc/qa/unit/ucalc.hxx
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef SC_UCALC_HXX
+#define SC_UCALC_HXX
+
+#include "helper/qahelper.hxx"
+
+class Test : public test::BootstrapFixture
+{
+public:
+
+    static void clearRange(ScDocument* pDoc, const ScRange& rRange);
+
+    Test();
+
+    virtual void setUp();
+    virtual void tearDown();
+
+    /**
+     * Basic performance regression test. Pick some actions that *should* take
+     * only a fraction of a second to complete, and make sure they stay that
+     * way. We set the threshold to 1 second for each action which should be
+     * large enough to accommodate slower machines or machines with high load.
+     */
+    void testPerf();
+    void testCollator();
+    void testRangeList();
+    void testInput();
+    void testFormulaHashAndTag();
+    void testFuncSUM();
+    void testFuncPRODUCT();
+    void testFuncN();
+    void testFuncCOUNTIF();
+    void testFuncNUMBERVALUE();
+    void testFuncVLOOKUP();
+    void testFuncMATCH();
+    void testFuncCELL();
+    void testFuncDATEDIF();
+    void testFuncINDIRECT();
+    void testFuncIFERROR();
+    void testCopyToDocument();
+    /**
+     * Make sure the SHEETS function gets properly updated during sheet
+     * insertion and removal.
+     */
+    void testSheetsFunc();
+    void testVolatileFunc();
+
+    void testHorizontalIterator();
+
+    /**
+     * Basic test for formula dependency tracking.
+     */
+    void testFormulaDepTracking();
+
+    /**
+     * Another test for formula dependency tracking, inspired by fdo#56278.
+     */
+    void testFormulaDepTracking2();
+
+    /**
+     * More direct test for cell broadcaster management, used to track formula
+     * dependencies.
+     */
+    void testCellBroadcaster();
+
+    void testFuncParam();
+    void testNamedRange();
+    void testCSV();
+    void testMatrix();
+    void testEnterMixedMatrix();
+
+    /**
+     * Basic test for pivot tables.
+     */
+    void testPivotTable();
+
+    /**
+     * Test against unwanted automatic format detection on field names and
+     * field members in pivot tables.
+     */
+    void testPivotTableLabels();
+
+    /**
+     * Make sure that we set cells displaying date values numeric cells,
+     * rather than text cells.  Grouping by date or number functionality
+     * depends on this.
+     */
+    void testPivotTableDateLabels();
+
+    /**
+     * Test for pivot table's filtering functionality by page fields.
+     */
+    void testPivotTableFilters();
+
+    /**
+     * Test for pivot table's named source range.
+     */
+    void testPivotTableNamedSource();
+
+    /**
+     * Test for pivot table cache.  Each dimension in the pivot cache stores
+     * only unique values that are sorted in ascending order.
+     */
+    void testPivotTableCache();
+
+    /**
+     * Test for pivot table containing data fields that reference the same
+     * source field but different functions.
+     */
+    void testPivotTableDuplicateDataFields();
+
+    void testPivotTableNormalGrouping();
+    void testPivotTableNumberGrouping();
+    void testPivotTableDateGrouping();
+    void testPivotTableEmptyRows();
+    void testPivotTableTextNumber();
+
+    /**
+     * Test for checking that pivot table treats strings in a case insensitive
+     * manner.
+     */
+    void testPivotTableCaseInsensitiveStrings();
+
+    /**
+     * Test for pivot table's handling of double-precision numbers that are
+     * very close together.
+     */
+    void testPivotTableNumStability();
+
+    /**
+     * Test for pivot table that include field with various non-default field
+     * refrences.
+     */
+    void testPivotTableFieldReference();
+
+    /**
+     * Test pivot table functionality performed via ScDBDocFunc.
+     */
+    void testPivotTableDocFunc();
+
+    void testSheetCopy();
+    void testSheetMove();
+    void testExternalRef();
+    void testExternalRefFunctions();
+    void testDataArea();
+    void testAutofilter();
+    void testCopyPaste();
+    void testMergedCells();
+    void testUpdateReference();
+    void testSearchCells();
+    void testSharedFormulas();
+    void testFormulaPosition();
+
+    /**
+     * Make sure the sheet streams are invalidated properly.
+     */
+    void testStreamValid();
+
+    /**
+     * Test built-in cell functions to make sure their categories and order
+     * are correct.
+     */
+    void testFunctionLists();
+
+    void testGraphicsInGroup();
+    void testGraphicsOnSheetMove();
+
+    void testPostIts();
+
+    /**
+     * Test toggling relative/absolute flag of cell and cell range references.
+     * This corresponds with hitting Shift-F4 while the cursor is on a formula
+     * cell.
+     */
+    void testToggleRefFlag();
+
+    /**
+     * Test to make sure correct precedent / dependent cells are obtained when
+     * preparing to jump to them.
+     */
+    void testJumpToPrecedentsDependents();
+
+    void testSetBackgroundColor();
+    void testRenameTable();
+
+    void testAutoFill();
+    void testCopyPasteFormulas();
+    void testCopyPasteFormulasExternalDoc();
+
+    void testFindAreaPosVertical();
+    void testFindAreaPosColRight();
+    void testSort();
+    void testSortWithFormulaRefs();
+    void testShiftCells();
+    void testDeleteRow();
+    void testDeleteCol();
+    void testAnchoredRotatedShape();
+    void testCellTextWidth();
+
+    /**
+     * Test formula & formula grouping
+     */
+    void testFormulaGrouping();
+    void testCondFormatINSDEL();
+
+    CPPUNIT_TEST_SUITE(Test);
+#if CALC_TEST_PERF
+    CPPUNIT_TEST(testPerf);
+#endif
+    CPPUNIT_TEST(testCollator);
+    CPPUNIT_TEST(testRangeList);
+    CPPUNIT_TEST(testInput);
+    CPPUNIT_TEST(testFormulaHashAndTag);
+    CPPUNIT_TEST(testFuncSUM);
+    CPPUNIT_TEST(testFuncPRODUCT);
+    CPPUNIT_TEST(testFuncN);
+    CPPUNIT_TEST(testFuncCOUNTIF);
+    CPPUNIT_TEST(testFuncNUMBERVALUE);
+    CPPUNIT_TEST(testFuncVLOOKUP);
+    CPPUNIT_TEST(testFuncMATCH);
+    CPPUNIT_TEST(testFuncCELL);
+    CPPUNIT_TEST(testFuncDATEDIF);
+    CPPUNIT_TEST(testFuncINDIRECT);
+    CPPUNIT_TEST(testFuncIFERROR);
+    CPPUNIT_TEST(testCopyToDocument);
+    CPPUNIT_TEST(testSheetsFunc);
+    CPPUNIT_TEST(testVolatileFunc);
+    CPPUNIT_TEST(testHorizontalIterator);
+    CPPUNIT_TEST(testFormulaDepTracking);
+    CPPUNIT_TEST(testFormulaDepTracking2);
+    CPPUNIT_TEST(testCellBroadcaster);
+    CPPUNIT_TEST(testFuncParam);
+    CPPUNIT_TEST(testNamedRange);
+    CPPUNIT_TEST(testCSV);
+    CPPUNIT_TEST(testMatrix);
+    CPPUNIT_TEST(testEnterMixedMatrix);
+    CPPUNIT_TEST(testPivotTable);
+    CPPUNIT_TEST(testPivotTableLabels);
+    CPPUNIT_TEST(testPivotTableDateLabels);
+    CPPUNIT_TEST(testPivotTableFilters);
+    CPPUNIT_TEST(testPivotTableNamedSource);
+    CPPUNIT_TEST(testPivotTableCache);
+    CPPUNIT_TEST(testPivotTableDuplicateDataFields);
+    CPPUNIT_TEST(testPivotTableNormalGrouping);
+    CPPUNIT_TEST(testPivotTableNumberGrouping);
+    CPPUNIT_TEST(testPivotTableDateGrouping);
+    CPPUNIT_TEST(testPivotTableEmptyRows);
+    CPPUNIT_TEST(testPivotTableTextNumber);
+    CPPUNIT_TEST(testPivotTableCaseInsensitiveStrings);
+    CPPUNIT_TEST(testPivotTableNumStability);
+    CPPUNIT_TEST(testPivotTableFieldReference);
+    CPPUNIT_TEST(testPivotTableDocFunc);
+    CPPUNIT_TEST(testSheetCopy);
+    CPPUNIT_TEST(testSheetMove);
+    CPPUNIT_TEST(testExternalRef);
+    CPPUNIT_TEST(testExternalRefFunctions);
+    CPPUNIT_TEST(testDataArea);
+    CPPUNIT_TEST(testGraphicsInGroup);
+    CPPUNIT_TEST(testGraphicsOnSheetMove);
+    CPPUNIT_TEST(testPostIts);
+    CPPUNIT_TEST(testStreamValid);
+    CPPUNIT_TEST(testFunctionLists);
+    CPPUNIT_TEST(testToggleRefFlag);
+    CPPUNIT_TEST(testAutofilter);
+    CPPUNIT_TEST(testCopyPaste);
+    CPPUNIT_TEST(testMergedCells);
+    CPPUNIT_TEST(testUpdateReference);
+    CPPUNIT_TEST(testSearchCells);
+    CPPUNIT_TEST(testSharedFormulas);
+    CPPUNIT_TEST(testFormulaPosition);
+    CPPUNIT_TEST(testJumpToPrecedentsDependents);
+    CPPUNIT_TEST(testSetBackgroundColor);
+    CPPUNIT_TEST(testRenameTable);
+    CPPUNIT_TEST(testAutoFill);
+    CPPUNIT_TEST(testCopyPasteFormulas);
+    CPPUNIT_TEST(testCopyPasteFormulasExternalDoc);
+    CPPUNIT_TEST(testFindAreaPosVertical);
+    CPPUNIT_TEST(testFindAreaPosColRight);
+    CPPUNIT_TEST(testSort);
+    CPPUNIT_TEST(testSortWithFormulaRefs);
+    CPPUNIT_TEST(testShiftCells);
+    CPPUNIT_TEST(testDeleteRow);
+    CPPUNIT_TEST(testDeleteCol);
+    CPPUNIT_TEST(testAnchoredRotatedShape);
+    CPPUNIT_TEST(testCellTextWidth);
+    CPPUNIT_TEST(testFormulaGrouping);
+    CPPUNIT_TEST(testCondFormatINSDEL);
+    CPPUNIT_TEST_SUITE_END();
+
+private:
+    ScDocument *m_pDoc;
+    ScDocShellRef m_xDocShRef;
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
new file mode 100644
index 0000000..3025b52
--- /dev/null
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ucalc.hxx"
+#include "editutil.hxx"
+
+void Test::testSharedFormulas()
+{
+    m_pDoc->InsertTab(0, "Test");
+
+    ScAddress aPos(1, 9, 0); // B10
+    m_pDoc->SetString(aPos, "=A10*2"); // Insert into B10.
+    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("Expected to be a non-shared cell.", pFC && !pFC->IsShared());
+
+    aPos.SetRow(10); // B11
+    m_pDoc->SetString(aPos, "=A11*2");
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    aPos.SetRow(8); // B9
+    m_pDoc->SetString(aPos, "=A9*2");
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
+
+    aPos.SetRow(12); // B13
+    m_pDoc->SetString(aPos, "=A13*2");
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This formula cell shouldn't be shared yet.", pFC && !pFC->IsShared());
+
+    // Insert a formula to B12, and B9:B13 should be shared.
+    aPos.SetRow(11); // B12
+    m_pDoc->SetString(aPos, "=A12*2");
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedLength());
+
+    // Insert formulas to B15:B16.
+    aPos.SetRow(14); // B15
+    m_pDoc->SetString(aPos, "=A15*2");
+    aPos.SetRow(15); // B16
+    m_pDoc->SetString(aPos, "=A16*2");
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    // Insert a formula to B14, and B9:B16 should be shared.
+    aPos.SetRow(13); // B14
+    m_pDoc->SetString(aPos, "=A14*2");
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
+
+    // Insert an incompatible formula to B12, to split the shared range to B9:B11 and B13:B16.
+    aPos.SetRow(11); // B12
+    m_pDoc->SetString(aPos, "=$A$1*4");
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell shouldn't be shared.", pFC && !pFC->IsShared());
+
+    aPos.SetRow(8); // B9
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
+
+    aPos.SetRow(12); // B13
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
+
+    // Extend B13:B16 to B13:B20.
+    aPos.SetRow(16); // B17
+    m_pDoc->SetString(aPos, "=A17*2");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A18*2");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A19*2");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A20*2");
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
+    // B13:B20 shuld be shared.
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
+
+    // Empty B19. This should split it into B13:B18, and B20 non-shared.
+    aPos.SetRow(18);
+    m_pDoc->SetEmptyCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("This cell should have been emptied.", m_pDoc->GetCellType(aPos) == CELLTYPE_NONE);
+    aPos.SetRow(12); // B13
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    // B13:B18 should be shared.
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength());
+    // B20 shold be non-shared.
+    aPos.SetRow(19); // B20
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B20 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared());
+
+    // Empty B14, to make B13 non-shared and B15:B18 shared.
+    aPos.SetRow(13); // B14
+    m_pDoc->SetEmptyCell(aPos);
+    aPos.SetRow(12); // B13
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    // B13 should be non-shared.
+    CPPUNIT_ASSERT_MESSAGE("B13 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared());
+    // B15:B18 should be shared.
+    aPos.SetRow(14); // B15
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
+
+    // Set numeric value to B15, to make B16:B18 shared.
+    aPos.SetRow(14);
+    m_pDoc->SetValue(aPos, 1.2);
+    aPos.SetRow(15);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    // B16:B18 should be shared.
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(15), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
+
+    // Set string value to B16 to make B17:B18 shared.
+    aPos.SetRow(15);
+    ScCellValue aCell("Test");
+    CPPUNIT_ASSERT_MESSAGE("This should be a string value.", aCell.meType == CELLTYPE_STRING);
+    aCell.commit(*m_pDoc, aPos);
+    CPPUNIT_ASSERT_EQUAL(*aCell.mpString, m_pDoc->GetString(aPos));
+    aPos.SetRow(16);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    // B17:B18 should be shared.
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(16), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    // Set edit text to B17. Now B18 should be non-shared.
+    ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine();
+    rEditEngine.SetText("Edit Text");
+    aPos.SetRow(16);
+    m_pDoc->SetEditText(aPos, rEditEngine.CreateTextObject());
+    CPPUNIT_ASSERT_EQUAL(CELLTYPE_EDIT, m_pDoc->GetCellType(aPos));
+    aPos.SetRow(17);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B18 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_MESSAGE("B18 should be non-shared.", !pFC->IsShared());
+
+    // Set up a new group for shared formulas in B2:B10.
+    clearRange(m_pDoc, ScRange(0,0,0,2,100,0));
+
+    aPos.SetRow(1);
+    m_pDoc->SetString(aPos, "=A2*10");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A3*10");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A4*10");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A5*10");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A6*10");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A7*10");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A8*10");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A9*10");
+    aPos.IncRow();
+    m_pDoc->SetString(aPos, "=A10*10");
+
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B10 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength());
+
+    // Delete A4:B8. This should splite the grouping to B2:B3 and B9:B10.
+    clearRange(m_pDoc, ScRange(0,3,0,1,7,0));
+    aPos.SetRow(1);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    aPos.SetRow(8);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    // Delete rows 4:8 and shift row 9 and below up to row 4.  This should
+    // re-merge the two into a group of B2:B5.
+    m_pDoc->DeleteRow(ScRange(0,3,0,MAXCOL,7,0));
+    aPos.SetRow(1);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
+
+    // Insert 2 rows at row 4, to split it into B2:B3 and B6:B7.
+    m_pDoc->InsertRow(ScRange(0,3,0,MAXCOL,4,0));
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    aPos.SetRow(5);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B6 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    m_pDoc->DeleteTab(0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 3de06a8ada935fc21bdfd0afe03ca49881d1609e
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 18:08:30 2013 -0400

    Create a new library to store shared qa code for sc.
    
    Change-Id: I38aa1461d05e3dee096e69b7cd95e2ddfccc9594

diff --git a/Repository.mk b/Repository.mk
index 51089bb..0fc2a92 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -432,6 +432,7 @@ $(eval $(call gb_Helper_register_libraries,PLAINLIBS_NONE, \
 	unobootstrapprotector \
 	unoexceptionprotector \
 	unotest \
+	scqahelper \
 ))
 
 $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_URE,ure, \
diff --git a/sc/CppunitTest_sc_filters_test.mk b/sc/CppunitTest_sc_filters_test.mk
index 56eb345..82a6cf7 100644
--- a/sc/CppunitTest_sc_filters_test.mk
+++ b/sc/CppunitTest_sc_filters_test.mk
@@ -44,6 +44,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_filters_test, \
     salhelper \
     sax \
     sc \
+    scqahelper \
     sfx \
     sot \
     svl \
diff --git a/sc/CppunitTest_sc_subsequent_export_test.mk b/sc/CppunitTest_sc_subsequent_export_test.mk
index 9681327..12565a5 100644
--- a/sc/CppunitTest_sc_subsequent_export_test.mk
+++ b/sc/CppunitTest_sc_subsequent_export_test.mk
@@ -38,6 +38,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_subsequent_export_test, \
     salhelper \
     sax \
     sc \
+    scqahelper \
     sfx \
     sot \
     svl \
diff --git a/sc/CppunitTest_sc_subsequent_filters_test.mk b/sc/CppunitTest_sc_subsequent_filters_test.mk
index 29bb4b8..4bc57c3 100644
--- a/sc/CppunitTest_sc_subsequent_filters_test.mk
+++ b/sc/CppunitTest_sc_subsequent_filters_test.mk
@@ -38,6 +38,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_subsequent_filters_test, \
     salhelper \
     sax \
     sc \
+    scqahelper \
     sfx \
     sot \
     svl \
diff --git a/sc/CppunitTest_sc_ucalc.mk b/sc/CppunitTest_sc_ucalc.mk
index b6e5e3e..702117f 100644
--- a/sc/CppunitTest_sc_ucalc.mk
+++ b/sc/CppunitTest_sc_ucalc.mk
@@ -51,6 +51,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_ucalc, \
     salhelper \
     sax \
     sb \
+    scqahelper \
     sfx \
     sot \
     svl \
diff --git a/sc/Library_scqahelper.mk b/sc/Library_scqahelper.mk
new file mode 100644
index 0000000..94ba7c6
--- /dev/null
+++ b/sc/Library_scqahelper.mk
@@ -0,0 +1,48 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,scqahelper))
+
+$(eval $(call gb_Library_set_include,scqahelper,\
+	-I$(SRCDIR)/sc/inc \
+	-I$(SRCDIR)/sc/source/ui/inc \
+	$$(INCLUDE) \
+))
+
+$(eval $(call gb_Library_use_externals,scqahelper, \
+	boost_headers \
+	mdds_headers \
+	orcus \
+	orcus-parser \
+	cppunit \
+))
+
+$(eval $(call gb_Library_use_sdk_api,scqahelper))
+
+$(eval $(call gb_Library_use_libraries,scqahelper,\
+	comphelper \
+	cppu \
+	cppuhelper \
+	sal \
+	sfx \
+	sot \
+	svl \
+	svt \
+	tl \
+	utl \
+	sc \
+	ucbhelper \
+	$(gb_UWINAPI) \
+))
+
+$(eval $(call gb_Library_add_exception_objects,scqahelper,\
+	sc/qa/unit/helper/qahelper \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk
index 0b3970f..29e53e9 100644
--- a/sc/Module_sc.mk
+++ b/sc/Module_sc.mk
@@ -16,6 +16,7 @@ $(eval $(call gb_Module_add_targets,sc,\
 	Library_scd \
 	Library_scfilt \
 	Library_scui \
+	Library_scqahelper \
 	UIConfig_scalc \
 ))
 
diff --git a/sc/qa/unit/filters-test.cxx b/sc/qa/unit/filters-test.cxx
index dfaecfd..44156ea 100644
--- a/sc/qa/unit/filters-test.cxx
+++ b/sc/qa/unit/filters-test.cxx
@@ -20,7 +20,6 @@
 #include <sfx2/sfxmodelfactory.hxx>
 #include <svl/stritem.hxx>
 
-#define CALC_DEBUG_OUTPUT 0
 #define TEST_BUG_FILES 0
 
 #include "helper/qahelper.hxx"
diff --git a/sc/qa/unit/helper/csv_handler.hxx b/sc/qa/unit/helper/csv_handler.hxx
index aa98257..0f4b018 100644
--- a/sc/qa/unit/helper/csv_handler.hxx
+++ b/sc/qa/unit/helper/csv_handler.hxx
@@ -7,6 +7,9 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#ifndef SC_QA_CSV_HANDLER_HXX
+#define SC_QA_CSV_HANDLER_HXX
+
 #include <iostream>
 
 #include "docsh.hxx"
@@ -17,6 +20,10 @@
 #include "cellform.hxx"
 #include "cellvalue.hxx"
 
+#include "rtl/strbuf.hxx"
+
+#include <test/bootstrapfixture.hxx>
+
 #define DEBUG_CSV_HANDLER 0
 
 namespace {
@@ -221,4 +228,6 @@ private:
     SCTAB mnTab;
 };
 
+#endif
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/helper/debughelper.hxx b/sc/qa/unit/helper/debughelper.hxx
index b9cf0a4..11dfc51 100644
--- a/sc/qa/unit/helper/debughelper.hxx
+++ b/sc/qa/unit/helper/debughelper.hxx
@@ -10,11 +10,6 @@
 #ifndef SC_DEBUG_HELPER_HXX
 #define SC_DEBUG_HELPER_HXX
 
-/**
- * Print nicely formatted sheet content to stdout.  Indispensable when
- * debugging the unit test code involving testing of sheet contents.
- */
-
 #include <rtl/strbuf.hxx>
 #include <rtl/ustring.hxx>
 
@@ -32,13 +27,19 @@
 
 #include <iostream>
 
+#define CALC_DEBUG_OUTPUT 0
+#define CALC_TEST_PERF 0
+
 using namespace ::com::sun::star;
 using ::std::cout;
 using ::std::cerr;
 using ::std::endl;
 using ::std::vector;
 
-
+/**
+ * Print nicely formatted sheet content to stdout.  Indispensable when
+ * debugging the unit test code involving testing of sheet contents.
+ */
 class SheetPrinter
 {
     typedef ::mdds::mixed_type_matrix<OUString, bool> MatrixType;
diff --git a/sc/qa/unit/helper/qahelper.cxx b/sc/qa/unit/helper/qahelper.cxx
new file mode 100644
index 0000000..b330f2c
--- /dev/null
+++ b/sc/qa/unit/helper/qahelper.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "qahelper.hxx"
+
+#define __ORCUS_STATIC_LIB
+#include <orcus/csv_parser.hpp>
+
+#include <fstream>
+
+bool testEqualsWithTolerance( long nVal1, long nVal2, long nTol )
+{
+    return ( labs( nVal1 - nVal2 ) <= nTol );
+}
+
+void loadFile(const OUString& aFileName, std::string& aContent)
+{
+    OString aOFileName = OUStringToOString(aFileName, RTL_TEXTENCODING_UTF8);
+
+#ifdef ANDROID
+    size_t size;
+    if (strncmp(aOFileName.getStr(), "/assets/", sizeof("/assets/")-1) == 0) {
+        const char *contents = (const char *) lo_apkentry(aOFileName.getStr(), &size);
+        if (contents != 0) {
+            aContent = std::string(contents, size);
+            return;
+        }
+    }
+#endif
+
+    std::ifstream aFile(aOFileName.getStr());
+
+    OStringBuffer aErrorMsg("Could not open csv file: ");
+    aErrorMsg.append(aOFileName);
+    CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), aFile);
+    std::ostringstream aOStream;
+    aOStream << aFile.rdbuf();
+    aFile.close();
+    aContent = aOStream.str();
+}
+
+void testFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab, StringType aStringFormat)
+{
+    csv_handler aHandler(pDoc, nTab, aStringFormat);
+    orcus::csv_parser_config aConfig;
+    aConfig.delimiters.push_back(',');
+    aConfig.delimiters.push_back(';');
+    aConfig.text_qualifier = '"';
+    aConfig.trim_cell_value = false;
+
+
+    std::string aContent;
+    loadFile(aFileName, aContent);
+    orcus::csv_parser<csv_handler> parser ( &aContent[0], aContent.size() , aHandler, aConfig);
+    try
+    {
+        parser.parse();
+    }
+    catch (const orcus::csv_parse_error& e)
+    {
+        std::cout << "reading csv content file failed: " << e.what() << std::endl;
+        OStringBuffer aErrorMsg("csv parser error: ");
+        aErrorMsg.append(e.what());
+        CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), false);
+    }
+}
+
+void testCondFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab)
+{
+    conditional_format_handler aHandler(pDoc, nTab);
+    orcus::csv_parser_config aConfig;
+    aConfig.delimiters.push_back(',');
+    aConfig.delimiters.push_back(';');
+    aConfig.text_qualifier = '"';
+    std::string aContent;
+    loadFile(aFileName, aContent);
+    orcus::csv_parser<conditional_format_handler> parser ( &aContent[0], aContent.size() , aHandler, aConfig);
+    try
+    {
+        parser.parse();
+    }
+    catch (const orcus::csv_parse_error& e)
+    {
+        std::cout << "reading csv content file failed: " << e.what() << std::endl;
+        OStringBuffer aErrorMsg("csv parser error: ");
+        aErrorMsg.append(e.what());
+        CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), false);
+    }
+}
+
+ScDocShellRef ScBootstrapFixture::load( bool bReadWrite,
+    const OUString& rURL, const OUString& rFilter, const OUString &rUserData,
+    const OUString& rTypeName, unsigned int nFilterFlags, unsigned int nClipboardID,
+    sal_uIntPtr nFilterVersion, const OUString* pPassword )
+{
+    SfxFilter* pFilter = new SfxFilter(
+        rFilter,
+        OUString(), nFilterFlags, nClipboardID, rTypeName, 0, OUString(),
+        rUserData, OUString("private:factory/scalc*"));
+    pFilter->SetVersion(nFilterVersion);
+
+    ScDocShellRef xDocShRef = new ScDocShell;
+    xDocShRef->GetDocument()->EnableUserInteraction(false);
+    SfxMedium* pSrcMed = new SfxMedium(rURL, bReadWrite ? STREAM_STD_READWRITE : STREAM_STD_READ );
+    pSrcMed->SetFilter(pFilter);
+    pSrcMed->UseInteractionHandler(false);
+    if (pPassword)
+    {
+        SfxItemSet* pSet = pSrcMed->GetItemSet();
+        pSet->Put(SfxStringItem(SID_PASSWORD, *pPassword));
+    }
+    printf("about to load %s\n", OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 ).getStr() );
+    if (!xDocShRef->DoLoad(pSrcMed))
+    {
+        xDocShRef->DoClose();
+        // load failed.
+        xDocShRef.Clear();
+    }
+
+    return xDocShRef;
+}
+
+ScDocShellRef ScBootstrapFixture::load(
+    const OUString& rURL, const OUString& rFilter, const OUString &rUserData,
+    const OUString& rTypeName, unsigned int nFilterFlags, unsigned int nClipboardID,
+    sal_uIntPtr nFilterVersion, const OUString* pPassword )
+{
+    return load( false, rURL, rFilter, rUserData, rTypeName, nFilterFlags, nClipboardID,  nFilterVersion, pPassword );
+}
+
+ScDocShellRef ScBootstrapFixture::loadDoc(
+    const OUString& rFileName, sal_Int32 nFormat, bool bReadWrite )
+{
+    OUString aFileExtension(aFileFormats[nFormat].pName, strlen(aFileFormats[nFormat].pName), RTL_TEXTENCODING_UTF8 );
+    OUString aFilterName(aFileFormats[nFormat].pFilterName, strlen(aFileFormats[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
+    OUString aFileName;
+    createFileURL( rFileName, aFileExtension, aFileName );
+    OUString aFilterType(aFileFormats[nFormat].pTypeName, strlen(aFileFormats[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
+    unsigned int nFormatType = aFileFormats[nFormat].nFormatType;
+    unsigned int nClipboardId = nFormatType ? SFX_FILTER_IMPORT | SFX_FILTER_USESOPTIONS : 0;
+
+    return load(bReadWrite, aFileName, aFilterName, OUString(), aFilterType, nFormatType, nClipboardId, nFormatType);
+}
+
+void ScBootstrapFixture::createFileURL(
+    const OUString& aFileBase, const OUString& aFileExtension, OUString& rFilePath)
+{
+    OUString aSep("/");
+    OUStringBuffer aBuffer( getSrcRootURL() );
+    aBuffer.append(m_aBaseString).append(aSep).append(aFileExtension);
+    aBuffer.append(aSep).append(aFileBase).append(aFileExtension);
+    rFilePath = aBuffer.makeStringAndClear();
+}
+
+void ScBootstrapFixture::createCSVPath(const OUString& aFileBase, OUString& rCSVPath)
+{
+    OUStringBuffer aBuffer( getSrcRootPath());
+    aBuffer.append(m_aBaseString).append(OUString("/contentCSV/"));
+    aBuffer.append(aFileBase).append(OUString("csv"));
+    rCSVPath = aBuffer.makeStringAndClear();
+}
+
+ScDocShellRef ScBootstrapFixture::saveAndReload(
+    ScDocShell* pShell, const OUString &rFilter,
+    const OUString &rUserData, const OUString& rTypeName, sal_uLong nFormatType)
+{
+
+    utl::TempFile aTempFile;
+    aTempFile.EnableKillingFile();
+    SfxMedium aStoreMedium( aTempFile.GetURL(), STREAM_STD_WRITE );
+    sal_uInt32 nExportFormat = 0;
+    if (nFormatType == ODS_FORMAT_TYPE)
+        nExportFormat = SFX_FILTER_EXPORT | SFX_FILTER_USESOPTIONS;
+    SfxFilter* pExportFilter = new SfxFilter(
+        rFilter,
+        OUString(), nFormatType, nExportFormat, rTypeName, 0, OUString(),
+        rUserData, OUString("private:factory/scalc*") );
+    pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
+    aStoreMedium.SetFilter(pExportFilter);
+    pShell->DoSaveAs( aStoreMedium );
+    pShell->DoClose();
+
+    //std::cout << "File: " << aTempFile.GetURL() << std::endl;
+
+    sal_uInt32 nFormat = 0;
+    if (nFormatType == ODS_FORMAT_TYPE)
+        nFormat = SFX_FILTER_IMPORT | SFX_FILTER_USESOPTIONS;
+
+    return load(aTempFile.GetURL(), rFilter, rUserData, rTypeName, nFormatType, nFormat );
+}
+
+ScDocShellRef ScBootstrapFixture::saveAndReload( ScDocShell* pShell, sal_Int32 nFormat )
+{
+    OUString aFilterName(aFileFormats[nFormat].pFilterName, strlen(aFileFormats[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
+    OUString aFilterType(aFileFormats[nFormat].pTypeName, strlen(aFileFormats[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
+    ScDocShellRef xDocSh = saveAndReload(pShell, aFilterName, OUString(), aFilterType, aFileFormats[nFormat].nFormatType);
+
+    CPPUNIT_ASSERT(xDocSh.Is());
+    return xDocSh;
+}
+
+void ScBootstrapFixture::miscRowHeightsTest( TestParam* aTestValues, unsigned int numElems )
+{
+    for ( unsigned int index=0; index<numElems; ++index )
+    {
+        OUString sFileName = OUString::createFromAscii( aTestValues[ index ].sTestDoc );
+        printf("aTestValues[%u] %s\n", index, OUStringToOString( sFileName, RTL_TEXTENCODING_UTF8 ).getStr() );
+        int nImportType =  aTestValues[ index ].nImportType;
+        int nExportType =  aTestValues[ index ].nExportType;
+        ScDocShellRef xShell = loadDoc( sFileName, nImportType );
+        CPPUNIT_ASSERT(xShell.Is());
+
+        if ( nExportType != -1 )
+            xShell = saveAndReload(&(*xShell), nExportType );
+
+        CPPUNIT_ASSERT(xShell.Is());
+
+        ScDocument* pDoc = xShell->GetDocument();
+
+        for (int i=0; i<aTestValues[ index ].nRowData; ++i)
+        {
+            SCROW nRow = aTestValues[ index ].pData[ i].nStartRow;
+            SCROW nEndRow = aTestValues[ index ].pData[ i ].nEndRow;
+            SCTAB nTab = aTestValues[ index ].pData[ i ].nTab;
+            int nExpectedHeight = aTestValues[ index ].pData[ i ].nExpectedHeight;
+            if ( nExpectedHeight == -1 )
+                nExpectedHeight =  sc::TwipsToHMM( ScGlobal::nStdRowHeight );
+            bool bCheckOpt = ( ( aTestValues[ index ].pData[ i ].nCheck & CHECK_OPTIMAL ) == CHECK_OPTIMAL );
+            for ( ; nRow <= nEndRow; ++nRow )
+            {
+                printf("\t checking row %" SAL_PRIdINT32 " for height %d\n", nRow, nExpectedHeight );
+                int nHeight = sc::TwipsToHMM( pDoc->GetRowHeight(nRow, nTab, false) );
+                if ( bCheckOpt )
+                {
+                    bool bOpt = !(pDoc->GetRowFlags( nRow, nTab ) & CR_MANUALSIZE);
+                    CPPUNIT_ASSERT_EQUAL(aTestValues[ index ].pData[ i ].bOptimal, bOpt);
+                }
+                CPPUNIT_ASSERT_EQUAL(nExpectedHeight, nHeight);
+            }
+        }
+        xShell->DoClose();
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/helper/qahelper.hxx b/sc/qa/unit/helper/qahelper.hxx
index ad25b74..b01a581 100644
--- a/sc/qa/unit/helper/qahelper.hxx
+++ b/sc/qa/unit/helper/qahelper.hxx
@@ -10,15 +10,11 @@
 #ifndef SC_QA_HELPER_HXX
 #define SC_QA_HELPER_HXX
 
-#include <test/bootstrapfixture.hxx>
-#define __ORCUS_STATIC_LIB
-#include "helper/csv_handler.hxx"
-#include "helper/debughelper.hxx"
-#include "orcus/csv_parser.hpp"
-#include <fstream>
-#include <string>
-#include <sstream>
+#include "scdllapi.h"
+#include "debughelper.hxx"
+#include "csv_handler.hxx"
 
+#include <test/bootstrapfixture.hxx>
 #include <comphelper/documentconstants.hxx>
 
 #include <osl/detail/android-bootstrap.h>
@@ -26,6 +22,11 @@
 #include <unotools/tempfile.hxx>
 #include <comphelper/storagehelper.hxx>
 #include <sfx2/docfilt.hxx>
+#include "sfx2/docfile.hxx"
+#include "svl/stritem.hxx"
+
+#include <string>
+#include <sstream>
 
 #define ODS_FORMAT_TYPE 50331943
 #define XLS_FORMAT_TYPE 318767171
@@ -43,14 +44,7 @@
 #define LOTUS123 5
 #define DIF      6
 
-bool testEqualsWithTolerance( long nVal1, long nVal2, long nTol )
-{
-    return ( labs( nVal1 - nVal2 ) <= nTol );
-}
-
-struct FileFormat {
-    const char* pName; const char* pFilterName; const char* pTypeName; unsigned int nFormatType;
-};
+SC_DLLPUBLIC bool testEqualsWithTolerance( long nVal1, long nVal2, long nTol );
 
 #define CHECK_OPTIMAL 0x1
 
@@ -73,6 +67,10 @@ struct TestParam
     RowData* pData;
 };
 
+struct FileFormat {
+    const char* pName; const char* pFilterName; const char* pTypeName; unsigned int nFormatType;
+};
+
 FileFormat aFileFormats[] = {
     { "ods" , "calc8", "", ODS_FORMAT_TYPE },
     { "xls" , "MS Excel 97", "calc_MS_EXCEL_97", XLS_FORMAT_TYPE },
@@ -89,35 +87,16 @@ FileFormat aFileFormats[] = {
 // eventually perhaps iOS) special cases here, too)?  Please move this to osl,
 // it sure looks gemerally useful. Or am I missing something?
 
-void loadFile(const OUString& aFileName, std::string& aContent)
-{
-    OString aOFileName = OUStringToOString(aFileName, RTL_TEXTENCODING_UTF8);
-
-#ifdef ANDROID
-    size_t size;
-    if (strncmp(aOFileName.getStr(), "/assets/", sizeof("/assets/")-1) == 0) {
-        const char *contents = (const char *) lo_apkentry(aOFileName.getStr(), &size);
-        if (contents != 0) {
-            aContent = std::string(contents, size);
-            return;
-        }
-    }
-#endif
+SC_DLLPUBLIC void loadFile(const OUString& aFileName, std::string& aContent);
 
-    std::ifstream aFile(aOFileName.getStr());
+SC_DLLPUBLIC void testFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab, StringType aStringFormat = StringValue);
 
-    OStringBuffer aErrorMsg("Could not open csv file: ");
-    aErrorMsg.append(aOFileName);
-    CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), aFile);
-    std::ostringstream aOStream;
-    aOStream << aFile.rdbuf();
-    aFile.close();
-    aContent = aOStream.str();
-}
+//need own handler because conditional formatting strings must be generated
+SC_DLLPUBLIC void testCondFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab);
 
 std::string print(const ScAddress& rAddr)
 {
-    std::stringstream str;
+    std::ostringstream str;
     str << "Col: " << rAddr.Col();
     str << " Row: " << rAddr.Row();
     str << " Tab: " << rAddr.Tab();
@@ -145,213 +124,38 @@ struct assertion_traits<ScRange>
 
 }
 
-class ScBootstrapFixture : public test::BootstrapFixture
+class SC_DLLPUBLIC ScBootstrapFixture : public test::BootstrapFixture
 {
 protected:
     OUString m_aBaseString;
-    ScDocShellRef load( bool bReadWrite,
-        const OUString& rURL, const OUString& rFilter, const OUString &rUserData,
-        const OUString& rTypeName, unsigned int nFilterFlags, unsigned int nClipboardID,  sal_uIntPtr nFilterVersion = SOFFICE_FILEFORMAT_CURRENT, const OUString* pPassword = NULL )
-    {
-        SfxFilter* pFilter = new SfxFilter(
-            rFilter,
-            OUString(), nFilterFlags, nClipboardID, rTypeName, 0, OUString(),
-            rUserData, OUString("private:factory/scalc*"));
-        pFilter->SetVersion(nFilterVersion);
-
-        ScDocShellRef xDocShRef = new ScDocShell;
-        xDocShRef->GetDocument()->EnableUserInteraction(false);
-        SfxMedium* pSrcMed = new SfxMedium(rURL, bReadWrite ? STREAM_STD_READWRITE : STREAM_STD_READ );
-        pSrcMed->SetFilter(pFilter);
-        pSrcMed->UseInteractionHandler(false);
-        if (pPassword)
-        {
-            SfxItemSet* pSet = pSrcMed->GetItemSet();
-            pSet->Put(SfxStringItem(SID_PASSWORD, *pPassword));
-        }
-        printf("about to load %s\n", OUStringToOString( rURL, RTL_TEXTENCODING_UTF8 ).getStr() );
-        if (!xDocShRef->DoLoad(pSrcMed))
-        {
-            xDocShRef->DoClose();
-            // load failed.
-            xDocShRef.Clear();
-        }
-
-        return xDocShRef;
-    }
 
     ScDocShellRef load(
-        const OUString& rURL, const OUString& rFilter, const OUString &rUserData,
-        const OUString& rTypeName, unsigned int nFilterFlags, unsigned int nClipboardID,  sal_uIntPtr nFilterVersion = SOFFICE_FILEFORMAT_CURRENT, const OUString* pPassword = NULL )
-    {
-        return load( false, rURL, rFilter, rUserData, rTypeName, nFilterFlags, nClipboardID,  nFilterVersion, pPassword );
-    }
+        bool bReadWrite, const OUString& rURL, const OUString& rFilter, const OUString &rUserData,
+        const OUString& rTypeName, unsigned int nFilterFlags, unsigned int nClipboardID,
+        sal_uIntPtr nFilterVersion = SOFFICE_FILEFORMAT_CURRENT, const OUString* pPassword = NULL );
 
-    ScDocShellRef loadDoc(const OUString& rFileName, sal_Int32 nFormat, bool bReadWrite = false )
-    {
-        OUString aFileExtension(aFileFormats[nFormat].pName, strlen(aFileFormats[nFormat].pName), RTL_TEXTENCODING_UTF8 );
-        OUString aFilterName(aFileFormats[nFormat].pFilterName, strlen(aFileFormats[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
-        OUString aFileName;
-        createFileURL( rFileName, aFileExtension, aFileName );
-        OUString aFilterType(aFileFormats[nFormat].pTypeName, strlen(aFileFormats[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
-        unsigned int nFormatType = aFileFormats[nFormat].nFormatType;
-        unsigned int nClipboardId = nFormatType ? SFX_FILTER_IMPORT | SFX_FILTER_USESOPTIONS : 0;
-
-        return load(bReadWrite, aFileName, aFilterName, OUString(), aFilterType, nFormatType, nClipboardId, nFormatType);
-    }
+    ScDocShellRef load(
+        const OUString& rURL, const OUString& rFilter, const OUString &rUserData,
+        const OUString& rTypeName, unsigned int nFilterFlags, unsigned int nClipboardID,
+        sal_uIntPtr nFilterVersion = SOFFICE_FILEFORMAT_CURRENT, const OUString* pPassword = NULL );
 
+    ScDocShellRef loadDoc(const OUString& rFileName, sal_Int32 nFormat, bool bReadWrite = false );
 
 public:
     ScBootstrapFixture( const OUString& rsBaseString ) : m_aBaseString( rsBaseString ) {}
-    void createFileURL(const OUString& aFileBase, const OUString& aFileExtension, OUString& rFilePath)
-    {
-        OUString aSep("/");
-        OUStringBuffer aBuffer( getSrcRootURL() );
-        aBuffer.append(m_aBaseString).append(aSep).append(aFileExtension);
-        aBuffer.append(aSep).append(aFileBase).append(aFileExtension);
-        rFilePath = aBuffer.makeStringAndClear();
-    }
 
-    void createCSVPath(const OUString& aFileBase, OUString& rCSVPath)
-    {
-        OUStringBuffer aBuffer( getSrcRootPath());
-        aBuffer.append(m_aBaseString).append(OUString("/contentCSV/"));
-        aBuffer.append(aFileBase).append(OUString("csv"));
-        rCSVPath = aBuffer.makeStringAndClear();
-    }
+    void createFileURL(const OUString& aFileBase, const OUString& aFileExtension, OUString& rFilePath);
 
-    ScDocShellRef saveAndReload(ScDocShell* pShell, const OUString &rFilter,
-    const OUString &rUserData, const OUString& rTypeName, sal_uLong nFormatType)
-    {
+    void createCSVPath(const OUString& aFileBase, OUString& rCSVPath);
 
-        utl::TempFile aTempFile;
-        aTempFile.EnableKillingFile();
-        SfxMedium aStoreMedium( aTempFile.GetURL(), STREAM_STD_WRITE );
-        sal_uInt32 nExportFormat = 0;
-        if (nFormatType == ODS_FORMAT_TYPE)
-            nExportFormat = SFX_FILTER_EXPORT | SFX_FILTER_USESOPTIONS;
-        SfxFilter* pExportFilter = new SfxFilter(
-            rFilter,
-            OUString(), nFormatType, nExportFormat, rTypeName, 0, OUString(),
-            rUserData, OUString("private:factory/scalc*") );
-        pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
-        aStoreMedium.SetFilter(pExportFilter);
-        pShell->DoSaveAs( aStoreMedium );
-        pShell->DoClose();
-
-        //std::cout << "File: " << aTempFile.GetURL() << std::endl;
-
-        sal_uInt32 nFormat = 0;
-        if (nFormatType == ODS_FORMAT_TYPE)
-            nFormat = SFX_FILTER_IMPORT | SFX_FILTER_USESOPTIONS;
-
-        return load(aTempFile.GetURL(), rFilter, rUserData, rTypeName, nFormatType, nFormat );
-    }
-    ScDocShellRef saveAndReload( ScDocShell* pShell, sal_Int32 nFormat )
-    {
-        OUString aFilterName(aFileFormats[nFormat].pFilterName, strlen(aFileFormats[nFormat].pFilterName), RTL_TEXTENCODING_UTF8) ;
-        OUString aFilterType(aFileFormats[nFormat].pTypeName, strlen(aFileFormats[nFormat].pTypeName), RTL_TEXTENCODING_UTF8);
-        ScDocShellRef xDocSh = saveAndReload(pShell, aFilterName, OUString(), aFilterType, aFileFormats[nFormat].nFormatType);
+    ScDocShellRef saveAndReload(ScDocShell* pShell, const OUString &rFilter,
+    const OUString &rUserData, const OUString& rTypeName, sal_uLong nFormatType);
 
-        CPPUNIT_ASSERT(xDocSh.Is());
-        return xDocSh;
-    }
+    ScDocShellRef saveAndReload( ScDocShell* pShell, sal_Int32 nFormat );
 
-    void miscRowHeightsTest( TestParam* aTestValues, unsigned int numElems )
-    {
-        for ( unsigned int index=0; index<numElems; ++index )
-        {
-            OUString sFileName = OUString::createFromAscii( aTestValues[ index ].sTestDoc );
-            printf("aTestValues[%u] %s\n", index, OUStringToOString( sFileName, RTL_TEXTENCODING_UTF8 ).getStr() );
-            int nImportType =  aTestValues[ index ].nImportType;
-            int nExportType =  aTestValues[ index ].nExportType;
-            ScDocShellRef xShell = loadDoc( sFileName, nImportType );
-            CPPUNIT_ASSERT(xShell.Is());
-
-            if ( nExportType != -1 )
-                xShell = saveAndReload(&(*xShell), nExportType );
-
-            CPPUNIT_ASSERT(xShell.Is());
-
-            ScDocument* pDoc = xShell->GetDocument();
-
-            for (int i=0; i<aTestValues[ index ].nRowData; ++i)
-            {
-                SCROW nRow = aTestValues[ index ].pData[ i].nStartRow;
-                SCROW nEndRow = aTestValues[ index ].pData[ i ].nEndRow;
-                SCTAB nTab = aTestValues[ index ].pData[ i ].nTab;
-                int nExpectedHeight = aTestValues[ index ].pData[ i ].nExpectedHeight;
-                if ( nExpectedHeight == -1 )
-                    nExpectedHeight =  sc::TwipsToHMM( ScGlobal::nStdRowHeight );
-                bool bCheckOpt = ( ( aTestValues[ index ].pData[ i ].nCheck & CHECK_OPTIMAL ) == CHECK_OPTIMAL );
-                for ( ; nRow <= nEndRow; ++nRow )
-                {
-                    printf("\t checking row %" SAL_PRIdINT32 " for height %d\n", nRow, nExpectedHeight );
-                    int nHeight = sc::TwipsToHMM( pDoc->GetRowHeight(nRow, nTab, false) );
-                    if ( bCheckOpt )
-                    {
-                        bool bOpt = !(pDoc->GetRowFlags( nRow, nTab ) & CR_MANUALSIZE);
-                        CPPUNIT_ASSERT_EQUAL(aTestValues[ index ].pData[ i ].bOptimal, bOpt);
-                    }
-                    CPPUNIT_ASSERT_EQUAL(nExpectedHeight, nHeight);
-                }
-            }
-            xShell->DoClose();
-        }
-    }
+    void miscRowHeightsTest( TestParam* aTestValues, unsigned int numElems );
 };
 
-void testFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab, StringType aStringFormat = StringValue)
-{
-    csv_handler aHandler(pDoc, nTab, aStringFormat);
-    orcus::csv_parser_config aConfig;
-    aConfig.delimiters.push_back(',');
-    aConfig.delimiters.push_back(';');
-    aConfig.text_qualifier = '"';
-    aConfig.trim_cell_value = false;
-
-
-    std::string aContent;
-    loadFile(aFileName, aContent);
-    orcus::csv_parser<csv_handler> parser ( &aContent[0], aContent.size() , aHandler, aConfig);
-    try
-    {
-        parser.parse();
-    }
-    catch (const orcus::csv_parse_error& e)
-    {
-        std::cout << "reading csv content file failed: " << e.what() << std::endl;
-        OStringBuffer aErrorMsg("csv parser error: ");
-        aErrorMsg.append(e.what());
-        CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), false);
-    }
-}
-
-//need own handler because conditional formatting strings must be generated
-void testCondFile(OUString& aFileName, ScDocument* pDoc, SCTAB nTab)
-{
-    conditional_format_handler aHandler(pDoc, nTab);
-    orcus::csv_parser_config aConfig;
-    aConfig.delimiters.push_back(',');
-    aConfig.delimiters.push_back(';');
-    aConfig.text_qualifier = '"';
-    std::string aContent;
-    loadFile(aFileName, aContent);
-    orcus::csv_parser<conditional_format_handler> parser ( &aContent[0], aContent.size() , aHandler, aConfig);
-    try
-    {
-        parser.parse();
-    }
-    catch (const orcus::csv_parse_error& e)
-    {
-        std::cout << "reading csv content file failed: " << e.what() << std::endl;
-        OStringBuffer aErrorMsg("csv parser error: ");
-        aErrorMsg.append(e.what());
-        CPPUNIT_ASSERT_MESSAGE(aErrorMsg.getStr(), false);
-    }
-
-}
-
 #define ASSERT_DOUBLES_EQUAL( expected, result )    \
     CPPUNIT_ASSERT_DOUBLES_EQUAL( (expected), (result), 1e-14 )
 
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index 2069920..d73ca8a 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -17,9 +17,6 @@
 #include <sfx2/sfxmodelfactory.hxx>
 #include <svl/stritem.hxx>
 
-
-#define CALC_DEBUG_OUTPUT 0
-
 #include "helper/qahelper.hxx"
 #include "helper/shared_test_impl.hxx"
 
diff --git a/sc/qa/unit/subsequent_filters-test.cxx b/sc/qa/unit/subsequent_filters-test.cxx
index a9ca9a2..8d27a75 100644
--- a/sc/qa/unit/subsequent_filters-test.cxx
+++ b/sc/qa/unit/subsequent_filters-test.cxx
@@ -53,7 +53,6 @@
 #include <com/sun/star/chart2/XChartDocument.hpp>
 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
 
-#define CALC_DEBUG_OUTPUT 0
 #define TEST_BUG_FILES 0
 
 #include "helper/qahelper.hxx"
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index c96d5b6..f05872f 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -80,14 +80,8 @@
 #include <sstream>
 #include <vector>
 
-#define CALC_DEBUG_OUTPUT 0
-#define CALC_TEST_PERF 0
-
-#include "helper/debughelper.hxx"
 #include "helper/qahelper.hxx"
 
-const int indeterminate = 2;
-
 using namespace ::com::sun::star;
 
 using ::std::cout;
commit b5512362716482698376940b18288ffe89b93893
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 15:32:42 2013 -0400

    Nobody uses this marker now.
    
    Change-Id: Ib7c8a7b7b1ce7f2b9afbb17a50848ae1d8e28907

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 37f67d5..9f96975 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -530,8 +530,6 @@ public:
      */
     void RegroupFormulaCells( SCROW nRow1, SCROW nRow2 );
 
-    void FormulaCellsUndecided( SCROW nRow1, SCROW nRow2 );
-
 #if DEBUG_COLUMN_STORAGE
     void DumpFormulaGroups() const;
 #endif
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index a651fa6..512dc8b7 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1538,10 +1538,6 @@ void ScColumn::RegroupFormulaCells( SCROW /*nRow1*/, SCROW /*nRow2*/ )
 {
 }
 
-void ScColumn::FormulaCellsUndecided( SCROW /*nRow1*/, SCROW /*nRow2*/ )
-{
-}
-
 #if DEBUG_COLUMN_STORAGE
 
 namespace {
commit 70059658781cf41b76b36d1befc2331863ae9b5a
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 15:29:40 2013 -0400

    Make update ref on copy a separate method.
    
    Change-Id: I95cb42845535532fca5622d8d4f8b394ff22d4d3

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 6bbfb6a..37f67d5 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -310,6 +310,9 @@ public:
 
     void        ResetChanged( SCROW nStartRow, SCROW nEndRow );
 
+    bool UpdateReferenceOnCopy(
+        const ScRange& rRange, SCCOL nDx, SCROW nDy, SCTAB nDz, ScDocument* pUndoDoc = NULL );
+
     /**
      * Update reference addresses in formula cell in response to mass cell
      * movement.
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 5bf6c21..bd48bad 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1991,8 +1991,7 @@ void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
             //  UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
 
             SCsTAB nDz = nTab - rSrcCol.nTab;
-            UpdateReference(
-                URM_COPY, ScRange(nCol, nStart, nTab, nCol, nEnd, nTab), 0, 0, nDz, NULL);
+            UpdateReferenceOnCopy(ScRange(nCol, nStart, nTab, nCol, nEnd, nTab), 0, 0, nDz, NULL);
             UpdateCompile();
         }
 
@@ -2020,8 +2019,8 @@ void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
             //  UpdateUsed not needed, is already done in TestCopyScenario (obsolete comment ?)
 
             SCsTAB nDz = rDestCol.nTab - nTab;
-            rDestCol.UpdateReference(
-                URM_COPY, ScRange(rDestCol.nCol, nStart, rDestCol.nTab, rDestCol.nCol, nEnd, rDestCol.nTab),
+            rDestCol.UpdateReferenceOnCopy(
+                ScRange(rDestCol.nCol, nStart, rDestCol.nTab, rDestCol.nCol, nEnd, rDestCol.nTab),
                 0, 0, nDz, NULL);
             rDestCol.UpdateCompile();
         }
@@ -2261,32 +2260,36 @@ public:
 
 }
 
-bool ScColumn::UpdateReference(
-    UpdateRefMode eUpdateRefMode, const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
-    ScDocument* pUndoDoc )
+bool ScColumn::UpdateReferenceOnCopy(
+    const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, ScDocument* pUndoDoc )
 {
-    if (eUpdateRefMode == URM_COPY)
-    {
-        // When copying, the range equals the destination range where cells
-        // are pasted, and the dx, dy, dz refer to the distance from the
-        // source range.
+    // When copying, the range equals the destination range where cells
+    // are pasted, and the dx, dy, dz refer to the distance from the
+    // source range.
 
-        UpdateRefOnCopy aHandler(rRange, nDx, nDy, nDz, pUndoDoc);
-        sc::CellStoreType::position_type aPos = maCells.position(rRange.aStart.Row());
-        sc::ProcessBlock(aPos.first, maCells, aHandler, rRange.aStart.Row(), rRange.aEnd.Row());
+    UpdateRefOnCopy aHandler(rRange, nDx, nDy, nDz, pUndoDoc);
+    sc::CellStoreType::position_type aPos = maCells.position(rRange.aStart.Row());
+    sc::ProcessBlock(aPos.first, maCells, aHandler, rRange.aStart.Row(), rRange.aEnd.Row());
 
-        // The formula groups at the top and bottom boundaries are expected to
-        // have been split prior to this call. Here, we only do the joining.
+    // The formula groups at the top and bottom boundaries are expected to
+    // have been split prior to this call. Here, we only do the joining.
+    JoinFormulaCellAbove(aPos);
+    if (rRange.aEnd.Row() < MAXROW)
+    {
+        aPos = maCells.position(aPos.first, rRange.aEnd.Row()+1);
         JoinFormulaCellAbove(aPos);
-        if (rRange.aEnd.Row() < MAXROW)
-        {
-            aPos = maCells.position(aPos.first, rRange.aEnd.Row()+1);
-            JoinFormulaCellAbove(aPos);
-        }
-
-        return aHandler.isUpdated();
     }
 
+    return aHandler.isUpdated();
+}
+
+bool ScColumn::UpdateReference(
+    UpdateRefMode eUpdateRefMode, const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+    ScDocument* pUndoDoc )
+{
+    if (eUpdateRefMode == URM_COPY)
+        return UpdateReferenceOnCopy(rRange, nDx, nDy, nDz, pUndoDoc);
+
     bool bThisColShifted = (rRange.aStart.Tab() <= nTab && nTab <= rRange.aEnd.Tab() && rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col());
     if (bThisColShifted)
     {
commit 8997b43420840ef27b6b7891dd331e689eb46c3c
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 15:19:04 2013 -0400

    Re-group formula cells on paste.
    
    Change-Id: Ia5251a3bc8387289056abacbb4836b77262aad12

diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 28ae418..5bf6c21 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2267,9 +2267,23 @@ bool ScColumn::UpdateReference(
 {
     if (eUpdateRefMode == URM_COPY)
     {
+        // When copying, the range equals the destination range where cells
+        // are pasted, and the dx, dy, dz refer to the distance from the
+        // source range.
+
         UpdateRefOnCopy aHandler(rRange, nDx, nDy, nDz, pUndoDoc);
-        FormulaCellsUndecided(rRange.aStart.Row(), rRange.aEnd.Row());
-        sc::ProcessBlock(maCells.begin(), maCells, aHandler, rRange.aStart.Row(), rRange.aEnd.Row());
+        sc::CellStoreType::position_type aPos = maCells.position(rRange.aStart.Row());
+        sc::ProcessBlock(aPos.first, maCells, aHandler, rRange.aStart.Row(), rRange.aEnd.Row());
+
+        // The formula groups at the top and bottom boundaries are expected to
+        // have been split prior to this call. Here, we only do the joining.
+        JoinFormulaCellAbove(aPos);
+        if (rRange.aEnd.Row() < MAXROW)
+        {
+            aPos = maCells.position(aPos.first, rRange.aEnd.Row()+1);
+            JoinFormulaCellAbove(aPos);
+        }
+
         return aHandler.isUpdated();
     }
 
commit 7d03070482a57a71a66f87126ec889a8550e49c7
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 13:50:23 2013 -0400

    Remove this marker.
    
    Change-Id: Iab8695f579abb009f12aa76f4e161f106527f493

diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index dd05798..28ae418 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2293,7 +2293,6 @@ bool ScColumn::UpdateReference(
     }
 
     UpdateRefOnNonCopy aHandler(nCol, nTab, rRange, nDx, nDy, nDz, eUpdateRefMode, pUndoDoc);
-    FormulaCellsUndecided(0, MAXROW);
     sc::ProcessFormula(maCells, aHandler);
     return aHandler.isUpdated();
 }
commit a331c0c1f718a364ba65cdeb897cd55206caae5a
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 13:48:07 2013 -0400

    Adjust formula grouping in InsertRow().
    
    Change-Id: I82723a30edc361b627246b66d21dc04cd639caa6

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index d854c59..c96d5b6 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -6517,8 +6517,20 @@ void Test::testSharedFormulas()
     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
 
-    m_pDoc->DeleteTab(0);
+    // Insert 2 rows at row 4, to split it into B2:B3 and B6:B7.
+    m_pDoc->InsertRow(ScRange(0,3,0,MAXCOL,4,0));
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
 
+    aPos.SetRow(5);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B6 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    m_pDoc->DeleteTab(0);
 }
 
 namespace {
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 91b3b75..dd05798 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2273,6 +2273,25 @@ bool ScColumn::UpdateReference(
         return aHandler.isUpdated();
     }
 
+    bool bThisColShifted = (rRange.aStart.Tab() <= nTab && nTab <= rRange.aEnd.Tab() && rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col());
+    if (bThisColShifted)
+    {
+        // Cells in this column is being shifted.  Split formula grouping at
+        // the top and bottom boundaries before they get shifted.
+        SCROW nSplitPos = rRange.aStart.Row();
+        if (ValidRow(nSplitPos))
+        {
+            sc::CellStoreType::position_type aPos = maCells.position(nSplitPos);
+            SplitFormulaCellGroup(aPos);
+            nSplitPos = rRange.aEnd.Row() + 1;
+            if (ValidRow(nSplitPos))
+            {
+                aPos = maCells.position(aPos.first, nSplitPos);
+                SplitFormulaCellGroup(aPos);
+            }
+        }
+    }
+
     UpdateRefOnNonCopy aHandler(nCol, nTab, rRange, nDx, nDy, nDz, eUpdateRefMode, pUndoDoc);
     FormulaCellsUndecided(0, MAXROW);
     sc::ProcessFormula(maCells, aHandler);
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 8d84221..288eaeb 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2084,6 +2084,9 @@ bool ScFormulaCell::UpdateReference(
         // This formula cell itself is being shifted during cell range
         // insertion or deletion. Update its position.
         aPos.Move(nDx, nDy, nDz);
+        if (xGroup && xGroup->mnStart == aOldPos.Row())
+            xGroup->mnStart += nDy;
+
         bCellStateChanged = aPos != aOldPos;
     }
     else if (rRange.In(aPos))
commit 95741621449ff1761bb3441f602972d4013ae49b
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 11:48:00 2013 -0400

    Add test for re-grouping of formulas in DeleteRow().
    
    Change-Id: Iea7fafedc2a5f1549a701d1fa768c127e3236246

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index baf957f..d854c59 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -6508,6 +6508,15 @@ void Test::testSharedFormulas()
     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
 
+    // Delete rows 4:8 and shift row 9 and below up to row 4.  This should
+    // re-merge the two into a group of B2:B5.
+    m_pDoc->DeleteRow(ScRange(0,3,0,MAXCOL,7,0));
+    aPos.SetRow(1);
+    pFC = m_pDoc->GetFormulaCell(aPos);
+    CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
+
     m_pDoc->DeleteTab(0);
 
 }
commit 4aa5157461538d39cf11c13bd55527355facbe16
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 8 11:09:00 2013 -0400

    Always use DoubleVectorRefToken when resolving a range reference.
    
    ResolveStaticReference is reserved for calculating invariant formula
    groups.
    
    Change-Id: I58aeabb01f11f98a5c300780734b31079417f4c7

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index f8928e5..8d84221 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3021,49 +3021,34 @@ public:
                 {
                     ScComplexRefData aRef = pToken->GetDoubleRef();
                     aRef.CalcAbsIfRel(mrCell.aPos);
-                    if (aRef.Ref1.IsRowRel() || aRef.Ref2.IsRowRel())
-                    {
-                        // Row reference is relative.
-                        bool bAbsFirst = !aRef.Ref1.IsRowRel();
-                        bool bAbsLast = !aRef.Ref2.IsRowRel();
-                        ScAddress aRefPos(aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab);
-                        size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1;
-                        std::vector<const double*> aArrays;
-                        aArrays.reserve(nCols);
-                        SCROW nArrayLength = mrCell.GetCellGroup()->mnLength;
-                        SCROW nRefRowSize = aRef.Ref2.nRow - aRef.Ref1.nRow + 1;
-                        if (!bAbsLast)
-                        {
-                            // range end position is relative. Extend the array length.
-                            nArrayLength += nRefRowSize - 1;
-                        }
-
-                        for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i)
-                        {
-                            aRefPos.SetCol(i);
-                            const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, nArrayLength);
-                            if (!pArray)
-                                return false;
 
-                            aArrays.push_back(pArray);
-                        }
-
-                        formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
-                        mrGroupTokens.AddToken(aTok);
-                    }
-                    else
+                    // Row reference is relative.
+                    bool bAbsFirst = !aRef.Ref1.IsRowRel();
+                    bool bAbsLast = !aRef.Ref2.IsRowRel();
+                    ScAddress aRefPos(aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab);
+                    size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1;
+                    std::vector<const double*> aArrays;
+                    aArrays.reserve(nCols);
+                    SCROW nArrayLength = mrCell.GetCellGroup()->mnLength;
+                    SCROW nRefRowSize = aRef.Ref2.nRow - aRef.Ref1.nRow + 1;
+                    if (!bAbsLast)
                     {
-                        // Absolute row reference.
-                        ScRange aRefRange(
-                            aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab,
-                            aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab);

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list