[Libreoffice-commits] core.git: 32 commits - configure.ac download.lst sc/inc sc/qa sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Wed Apr 23 18:08:35 PDT 2014


 configure.ac                                      |    2 
 download.lst                                      |    2 
 sc/inc/cellvalues.hxx                             |   18 
 sc/inc/column.hxx                                 |   20 
 sc/inc/document.hxx                               |    3 
 sc/inc/formulacell.hxx                            |    1 
 sc/inc/fstalgorithm.hxx                           |  108 ++++
 sc/inc/table.hxx                                  |   15 
 sc/qa/unit/data/ods/shared-formula/sort-crash.ods |binary
 sc/qa/unit/filters-test.cxx                       |   54 ++
 sc/qa/unit/ucalc.cxx                              |  212 +++++++-
 sc/qa/unit/ucalc.hxx                              |    2 
 sc/source/core/data/cellvalues.cxx                |   70 ++
 sc/source/core/data/column.cxx                    |  393 +---------------
 sc/source/core/data/column2.cxx                   |  128 -----
 sc/source/core/data/column3.cxx                   |   65 ++
 sc/source/core/data/column4.cxx                   |  135 +++++
 sc/source/core/data/document10.cxx                |   18 
 sc/source/core/data/formulacell.cxx               |    5 
 sc/source/core/data/table2.cxx                    |   21 
 sc/source/core/data/table3.cxx                    |  529 ++++++++++++++++++----
 sc/source/core/data/table7.cxx                    |   31 +
 sc/source/ui/docshell/dbdocfun.cxx                |   23 
 sc/source/ui/inc/dbdocfun.hxx                     |    4 
 24 files changed, 1241 insertions(+), 618 deletions(-)

New commits:
commit bff954c0c4e5f9acf18bfd9ae796bc5a937b7ff6
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Apr 23 21:07:14 2014 -0400

    Now these two methods are unused.
    
    Chuck 'em.
    
    Change-Id: Ifdf504c64e63e8e437abdcadd14f668d2c577555

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 4bbdb63..80d9189 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -608,10 +608,6 @@ private:
     void CellStorageModified();
 
     void CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const;
-    void SwapCellTextAttrs( SCROW nRow1, SCROW nRow2 );
-
-    // cell notes
-    void SwapCellNotes( SCROW nRow1, SCROW nRow2 );
 
     void DeleteCells(
         sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, sal_uInt16 nDelFlag,
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 521b538..151f6b0 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1678,112 +1678,6 @@ void ScColumn::DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn& rDest
     maDestBlockPos.miCellNotePos = rDestCol.maCellNotes.begin();
 }
 
-void ScColumn::SwapCellTextAttrs( SCROW nRow1, SCROW nRow2 )
-{
-    if (nRow1 == nRow2)
-        return;
-
-    if (nRow1 > nRow2)
-        std::swap(nRow1, nRow2);
-
-    sc::CellTextAttrStoreType::position_type aPos1 = maCellTextAttrs.position(nRow1);
-    if (aPos1.first == maCellTextAttrs.end())
-        return;
-
-    sc::CellTextAttrStoreType::position_type aPos2 = maCellTextAttrs.position(aPos1.first, nRow2);
-    if (aPos2.first == maCellTextAttrs.end())
-        return;
-
-    sc::CellTextAttrStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
-    if (it1->type == it2->type)
-    {
-        if (it1->type == sc::element_type_empty)
-            // Both are empty. Nothing to swap.
-            return;
-
-        // Both are non-empty. Simply swap their values.
-        std::swap(
-            sc::celltextattr_block::at(*it1->data, aPos1.second),
-            sc::celltextattr_block::at(*it2->data, aPos2.second));
-
-        return;
-    }
-
-    // One is empty while the other isn't.
-    if (it1->type == sc::element_type_empty)
-    {
-        // row 1 is empty while row 2 is non-empty.
-        const sc::CellTextAttr& rVal2 = sc::celltextattr_block::at(*it2->data, aPos2.second);
-        it1 = maCellTextAttrs.set(it1, nRow1, rVal2);
-        maCellTextAttrs.set_empty(it1, nRow2, nRow2);
-        return;
-    }
-
-    // row 1 is non-empty while row 2 is empty.
-    sc::CellTextAttr aVal1 = sc::celltextattr_block::at(*it1->data, aPos1.second); // make a copy.
-    it1 = maCellTextAttrs.set_empty(it1, nRow1, nRow1);
-    maCellTextAttrs.set(it1, nRow2, aVal1);
-
-    CellStorageModified();
-}
-
-void ScColumn::SwapCellNotes( SCROW nRow1, SCROW nRow2 )
-{
-    if (nRow1 == nRow2)
-        return;
-
-    if (nRow1 > nRow2)
-        std::swap(nRow1, nRow2);
-
-    sc::CellNoteStoreType::position_type aPos1 = maCellNotes.position(nRow1);
-    if (aPos1.first == maCellNotes.end())
-        return;
-
-    sc::CellNoteStoreType::position_type aPos2 = maCellNotes.position(aPos1.first, nRow2);
-    if (aPos2.first == maCellNotes.end())
-        return;
-
-    sc::CellNoteStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
-    if (it1->type == it2->type)
-    {
-        if (it1->type == sc::element_type_empty)
-            // Both are empty. Nothing to swap.
-            return;
-
-        // Both are non-empty. Simply swap their values.
-        std::swap(
-            sc::cellnote_block::at(*it1->data, aPos1.second),
-            sc::cellnote_block::at(*it2->data, aPos2.second));
-
-        //update Note caption with position
-        ScPostIt* pNote = sc::cellnote_block::at(*it1->data, aPos1.second);
-        pNote->UpdateCaptionPos(ScAddress(nCol,nRow2,nTab));
-        pNote = sc::cellnote_block::at(*it2->data, aPos2.second);
-        pNote->UpdateCaptionPos(ScAddress(nCol,nRow1,nTab));
-
-        return;
-    }
-
-    // One is empty while the other isn't.
-    if (it1->type == sc::element_type_empty)
-    {
-        // row 1 is empty while row 2 is non-empty.
-        ScPostIt* pVal2 = sc::cellnote_block::at(*it2->data, aPos2.second);
-        it1 = maCellNotes.set(it1, nRow1, pVal2);
-        maCellNotes.release(it1, nRow2, pVal2);
-        pVal2->UpdateCaptionPos(ScAddress(nCol,nRow1,nTab)); //update Note caption with position
-
-        return;
-    }
-
-    // row 1 is non-empty while row 2 is empty.
-    ScPostIt* pVal1 = NULL;
-    it1 = maCellNotes.release(it1, nRow1, pVal1);
-    assert(pVal1);
-    maCellNotes.set(it1, nRow2, pVal1);
-    pVal1->UpdateCaptionPos(ScAddress(nCol,nRow1,nTab));     //update Note caption with position
-}
-
 SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow)
 {
     return maBroadcasters.get<SvtBroadcaster*>(nRow);
commit dec7179d9396263c99882128208e895b1b603564
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Apr 23 15:58:05 2014 -0400

    These are not needed.
    
    Change-Id: I032cc877ecc6b6ce1e9ecfa03020f8dfd41461ac

diff --git a/sc/inc/cellvalues.hxx b/sc/inc/cellvalues.hxx
index 3bc3782..4263250 100644
--- a/sc/inc/cellvalues.hxx
+++ b/sc/inc/cellvalues.hxx
@@ -13,12 +13,10 @@
 #include <address.hxx>
 
 class ScColumn;
-struct ScRefCellValue;
 
 namespace sc {
 
 struct CellValuesImpl;
-struct CellTextAttr;
 
 /**
  * Think of this as a mini-ScColumn like storage that only stores cell
commit 6cc799181c34e41a408af1ba22ecf35dbd65292d
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Apr 23 15:40:05 2014 -0400

    Remove compiler warnings.
    
    Change-Id: I050dee872e0f85efe1f96729cbcc96966c73c25b

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index b1223fa..6b5585a 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -4629,7 +4629,7 @@ void Test::testSortWithFormulaRefs()
         m_pDoc->SetString( 0, i, 0, OUString::createFromAscii(aTextData[i-1]) );
 
     // Insert forumulas in A1:A6 on the 2nd sheet.
-    for (SCROW i = 0; i < SAL_N_ELEMENTS(aFormulaData); ++i)
+    for (size_t i = 0; i < SAL_N_ELEMENTS(aFormulaData); ++i)
         m_pDoc->SetString( 0, i, 1, OUString::createFromAscii(aFormulaData[i]) );
 
     // Sort data in A2:A8 on the 1st sheet. No column header.
@@ -4643,7 +4643,7 @@ void Test::testSortWithFormulaRefs()
 
     m_pDoc->Sort(0, aSortData, false, NULL);
 
-    for (SCROW i = 0; i < SAL_N_ELEMENTS(aResults); ++i)
+    for (size_t i = 0; i < SAL_N_ELEMENTS(aResults); ++i)
     {
         OUString sResult = m_pDoc->GetString(0, i + 1, 0);
         CPPUNIT_ASSERT_EQUAL( OUString::createFromAscii( aResults[i] ), sResult );
commit c72f76fcd1107a2e5542b9a43fc535914a210b17
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Apr 23 15:29:56 2014 -0400

    Set mdds 0.10.3 as the new package requirement.
    
    Change-Id: Ide0e10fa528d53a7e732d00b54c940111beebe19

diff --git a/configure.ac b/configure.ac
index 6db63ce..e14c6f2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8614,7 +8614,7 @@ AC_SUBST(SYSTEM_BOOST)
 dnl ===================================================================
 dnl Check for system mdds
 dnl ===================================================================
-libo_CHECK_SYSTEM_MODULE([mdds], [MDDS], [mdds >= 0.10.2], ["-I${WORKDIR}/UnpackedTarball/mdds/include"])
+libo_CHECK_SYSTEM_MODULE([mdds], [MDDS], [mdds >= 0.10.3], ["-I${WORKDIR}/UnpackedTarball/mdds/include"])
 
 dnl ===================================================================
 dnl Check for system glm
diff --git a/download.lst b/download.lst
index 2a16e7e..45cc0be 100644
--- a/download.lst
+++ b/download.lst
@@ -95,7 +95,7 @@ export LIBXML_TARBALL := 9c0cfef285d5c4a5c80d00904ddab380-libxml2-2.9.1.tar.gz
 export LIBXSLT_TARBALL := 9667bf6f9310b957254fdcf6596600b7-libxslt-1.1.28.tar.gz
 export LPSOLVE_TARBALL := 26b3e95ddf3d9c077c480ea45874b3b8-lp_solve_5.5.tar.gz
 export MARIADB_TARBALL := 05f84c95b610c21c5fd510d10debcabf-mariadb-native-client-1.0.0.tar.bz2
-export MDDS_TARBALL := 47203e7cade74e5c385aa812f21e7932-mdds_0.10.2.tar.bz2
+export MDDS_TARBALL := aa5ca9d1ed1082890835afab26400a39-mdds_0.10.3.tar.bz2
 export MYSQLCPPCONN_TARBALL := 0981bda6548a8c8233ffce2b6e4b2a23-mysql-connector-c++-1.1.0.tar.gz
 export MYTHES_TARBALL := 46e92b68e31e858512b680b3b61dc4c1-mythes-1.2.3.tar.gz
 export NEON_TARBALL := ff369e69ef0f0143beb5626164e87ae2-neon-0.29.5.tar.gz
commit 91303658fb33066c57aed04ac31fd3998f11f069
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Apr 23 12:31:14 2014 -0400

    Add unit test for sorting with cell formats.
    
    Change-Id: Ie1ec0308f72efe3bc46564d81f0cf37c0d606114

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index beb1bf1..b1223fa 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -59,6 +59,7 @@
 #include <docoptio.hxx>
 #include <patattr.hxx>
 #include <docpool.hxx>
+#include <globalnames.hxx>
 
 #include "formula/IFunctionDescription.hxx"
 
@@ -4847,6 +4848,167 @@ void Test::testSortInFormulaGroup()
     m_pDoc->DeleteTab( 0 );
 }
 
+void Test::testSortWithCellFormats()
+{
+    struct
+    {
+        bool isBold( const ScPatternAttr* pPat ) const
+        {
+            if (!pPat)
+            {
+                cerr << "Pattern is NULL!" << endl;
+                return false;
+            }
+
+            const SfxPoolItem* pItem = NULL;
+            if (!pPat->GetItemSet().HasItem(ATTR_FONT_WEIGHT, &pItem))
+            {
+                cerr << "Pattern does not have a font weight item, but it should." << endl;
+                return false;
+            }
+
+            if (static_cast<const SvxWeightItem*>(pItem)->GetEnumValue() != WEIGHT_BOLD)
+            {
+                cerr << "Font weight should be bold." << endl;
+                return false;
+            }
+
+            return true;
+        }
+
+        bool isItalic( const ScPatternAttr* pPat ) const
+        {
+            if (!pPat)
+            {
+                cerr << "Pattern is NULL!" << endl;
+                return false;
+            }
+
+            const SfxPoolItem* pItem = NULL;
+            if (!pPat->GetItemSet().HasItem(ATTR_FONT_POSTURE, &pItem))
+            {
+                cerr << "Pattern does not have a font posture item, but it should." << endl;
+                return false;
+            }
+
+            if (static_cast<const SvxPostureItem*>(pItem)->GetEnumValue() != ITALIC_NORMAL)
+            {
+                cerr << "Italic should be applied.." << endl;
+                return false;
+            }
+
+            return true;
+        }
+
+        bool isNormal( const ScPatternAttr* pPat ) const
+        {
+            if (!pPat)
+            {
+                cerr << "Pattern is NULL!" << endl;
+                return false;
+            }
+
+            const SfxPoolItem* pItem = NULL;
+            if (pPat->GetItemSet().HasItem(ATTR_FONT_WEIGHT))
+            {
+                // Check if the font weight is applied.
+                if (static_cast<const SvxWeightItem*>(pItem)->GetEnumValue() == WEIGHT_BOLD)
+                {
+                    cerr << "This cell is bold, but shouldn't." << endl;
+                    return false;
+                }
+            }
+
+            if (pPat->GetItemSet().HasItem(ATTR_FONT_POSTURE))
+            {
+                // Check if the italics is applied.
+                if (static_cast<const SvxPostureItem*>(pItem)->GetEnumValue() == ITALIC_NORMAL)
+                {
+                    cerr << "This cell is bold, but shouldn't." << endl;
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+    } aCheck;
+
+    m_pDoc->InsertTab(0, "Test");
+
+    // Insert some values into A1:A4.
+    m_pDoc->SetString(ScAddress(0,0,0), "Header");
+    m_pDoc->SetString(ScAddress(0,1,0), "Normal");
+    m_pDoc->SetString(ScAddress(0,2,0), "Bold");
+    m_pDoc->SetString(ScAddress(0,3,0), "Italic");
+
+    // Set A3 bold and A4 italic.
+    const ScPatternAttr* pPat = m_pDoc->GetPattern(ScAddress(0,2,0));
+    CPPUNIT_ASSERT(pPat);
+    {
+        ScPatternAttr aNewPat(*pPat);
+        SfxItemSet& rSet = aNewPat.GetItemSet();
+        rSet.Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT));
+        m_pDoc->ApplyPattern(0, 2, 0, aNewPat);
+
+        // Make sure it's really in.
+        bool bGood = aCheck.isBold(m_pDoc->GetPattern(ScAddress(0,2,0)));
+        CPPUNIT_ASSERT_MESSAGE("A3 is not bold but it should.", bGood);
+    }
+
+    pPat = m_pDoc->GetPattern(ScAddress(0,3,0));
+    CPPUNIT_ASSERT(pPat);
+    {
+        ScPatternAttr aNewPat(*pPat);
+        SfxItemSet& rSet = aNewPat.GetItemSet();
+        rSet.Put(SvxPostureItem(ITALIC_NORMAL, ATTR_FONT_POSTURE));
+        m_pDoc->ApplyPattern(0, 3, 0, aNewPat);
+
+        bool bGood = aCheck.isItalic(m_pDoc->GetPattern(ScAddress(0,3,0)));
+        CPPUNIT_ASSERT_MESSAGE("A4 is not italic but it should.", bGood);
+    }
+
+    // Define A1:A4 as sheet-local anonymous database range, else sort wouldn't run.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 3));
+
+    // Sort A1:A4 ascending with cell formats.
+    ScDBDocFunc aFunc(getDocShell());
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 0;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 3;
+    aSortData.bHasHeader = true;
+    aSortData.bIncludePattern = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, false, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Check the sort result.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Bold"),   m_pDoc->GetString(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Italic"), m_pDoc->GetString(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Normal"), m_pDoc->GetString(ScAddress(0,3,0)));
+
+    // A2 should be bold now.
+    bool bBold = aCheck.isBold(m_pDoc->GetPattern(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_MESSAGE("A2 should be bold after the sort.", bBold);
+
+    // and A3 should be italic.
+    bool bItalic = aCheck.isItalic(m_pDoc->GetPattern(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_MESSAGE("A3 should be italic.", bItalic);
+
+    // A4 should have neither bold nor italic.
+    bool bNormal = aCheck.isNormal(m_pDoc->GetPattern(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_MESSAGE("A4 should be neither bold nor italic.", bNormal);
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testShiftCells()
 {
     m_pDoc->InsertTab(0, "foo");
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 56eaf73..2939ac5 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -322,6 +322,7 @@ public:
     void testSortWithFormulaRefs();
     void testSortWithStrings();
     void testSortInFormulaGroup();
+    void testSortWithCellFormats();
     void testShiftCells();
 
     void testNoteBasic();
@@ -473,6 +474,7 @@ public:
     CPPUNIT_TEST(testSortWithFormulaRefs);
     CPPUNIT_TEST(testSortWithStrings);
     CPPUNIT_TEST(testSortInFormulaGroup);
+    CPPUNIT_TEST(testSortWithCellFormats);
     CPPUNIT_TEST(testShiftCells);
     CPPUNIT_TEST(testNoteBasic);
     CPPUNIT_TEST(testNoteDeleteRow);
commit 09bf5e8093ffafa08cd3e8b22a7a792be70fba7c
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Apr 23 10:06:53 2014 -0400

    fdo#76607: Writer unit test for this.
    
    Change-Id: Ia69283a9998c233784c0da0f7a65f58a6c102596

diff --git a/sc/qa/unit/data/ods/shared-formula/sort-crash.ods b/sc/qa/unit/data/ods/shared-formula/sort-crash.ods
new file mode 100644
index 0000000..21f3d2e
Binary files /dev/null and b/sc/qa/unit/data/ods/shared-formula/sort-crash.ods differ
diff --git a/sc/qa/unit/filters-test.cxx b/sc/qa/unit/filters-test.cxx
index 6f84075..796a01d 100644
--- a/sc/qa/unit/filters-test.cxx
+++ b/sc/qa/unit/filters-test.cxx
@@ -32,6 +32,9 @@
 #include "userdat.hxx"
 #include "formulacell.hxx"
 #include "tabprotection.hxx"
+#include <dbdocfun.hxx>
+#include <globalnames.hxx>
+#include <dbdata.hxx>
 
 #include <svx/svdpage.hxx>
 
@@ -72,6 +75,7 @@ public:
     void testLegacyCellAnchoredRotatedShape();
     void testEnhancedProtectionXLS();
     void testEnhancedProtectionXLSX();
+    void testSortWithSharedFormulasODS();
 
     CPPUNIT_TEST_SUITE(ScFiltersTest);
     CPPUNIT_TEST(testCVEs);
@@ -88,6 +92,7 @@ public:
     CPPUNIT_TEST(testLegacyCellAnchoredRotatedShape);
     CPPUNIT_TEST(testEnhancedProtectionXLS);
     CPPUNIT_TEST(testEnhancedProtectionXLSX);
+    CPPUNIT_TEST(testSortWithSharedFormulasODS);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -541,6 +546,55 @@ void ScFiltersTest::testEnhancedProtectionXLSX()
     xDocSh->DoClose();
 }
 
+void ScFiltersTest::testSortWithSharedFormulasODS()
+{
+    ScDocShellRef xDocSh = loadDoc("shared-formula/sort-crash.", ODS, true);
+    CPPUNIT_ASSERT(xDocSh.Is());
+    ScDocument* pDoc = xDocSh->GetDocument();
+
+    // E2:E10 should be shared.
+    const ScFormulaCell* pFC = pDoc->GetFormulaCell(ScAddress(4,1,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength());
+
+    // E12:E17 should be shared.
+    pFC = pDoc->GetFormulaCell(ScAddress(4,11,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(11), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength());
+
+    // Set A1:E17 as an anonymous database range to sheet, or else Calc would
+    // refuse to sort the range.
+    ScDBData* pDBData = new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 4, 16, true, true);
+    pDoc->SetAnonymousDBData(0, pDBData);
+
+    // Sort ascending by Column E.
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 4;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 16;
+    aSortData.bHasHeader = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 4;
+    aSortData.maKeyState[0].bAscending = true;
+
+    // Do the sorting.  This should not crash.
+    ScDBDocFunc aFunc(*xDocSh);
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // After the sort, E2:E16 should be shared.
+    pFC = pDoc->GetFormulaCell(ScAddress(4,1,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(15), pFC->GetSharedLength());
+
+    xDocSh->DoClose();
+}
+
 ScFiltersTest::ScFiltersTest()
       : ScBootstrapFixture( "/sc/qa/unit/data" )
 {
diff --git a/sc/source/ui/inc/dbdocfun.hxx b/sc/source/ui/inc/dbdocfun.hxx
index 0831490..13fd9bc 100644
--- a/sc/source/ui/inc/dbdocfun.hxx
+++ b/sc/source/ui/inc/dbdocfun.hxx
@@ -70,8 +70,8 @@ public:
 
     static void     ShowInBeamer( const ScImportParam& rParam, SfxViewFrame* pFrame );
 
-    bool            Sort( SCTAB nTab, const ScSortParam& rSortParam,
-                            bool bRecord, bool bPaint, bool bApi );
+    SC_DLLPUBLIC bool Sort(
+        SCTAB nTab, const ScSortParam& rSortParam, bool bRecord, bool bPaint, bool bApi );
 
     SC_DLLPUBLIC bool           Query( SCTAB nTab, const ScQueryParam& rQueryParam,
                             const ScRange* pAdvSource, bool bRecord, bool bApi );
commit 3f41b12c6685b82b5c2674bd9b9d5991adebeaf9
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Apr 22 23:07:34 2014 -0400

    SwapRow() is no more!
    
    Good riddance.  It was optimized for the old cell storage.
    
    Change-Id: I374194fe211d5b13dd60dbb68b9511a366fb32bd

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 51ddaf4..4bbdb63 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -186,7 +186,6 @@ public:
 
     void        Delete( SCROW nRow );
     void        FreeAll();
-    void        SwapRow( SCROW nRow1, SCROW nRow2 );
     void        SwapCell( SCROW nRow, ScColumn& rCol);
 
     bool        HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const;
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 7610eb7..b13e7d1 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1007,7 +1007,6 @@ private:
     bool        IsSorted(SCCOLROW nStart, SCCOLROW nEnd) const;
     void        DecoladeRow( ScSortInfoArray*, SCROW nRow1, SCROW nRow2 );
     void        SwapCol(SCCOL nCol1, SCCOL nCol2);
-    void        SwapRow(SCROW nRow1, SCROW nRow2);
     short CompareCell(
         sal_uInt16 nSort,
         ScRefCellValue& rCell1, SCCOL nCell1Col, SCROW nCell1Row,
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index de9f65e..89d998b 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -841,338 +841,6 @@ const sc::CellTextAttr* ScColumn::GetCellTextAttr( sc::ColumnBlockConstPosition&
 
 namespace {
 
-ScFormulaCell* cloneFormulaCell(ScDocument* pDoc, const ScAddress& rNewPos, ScFormulaCell& rOldCell)
-{
-    ScFormulaCell* pNew = new ScFormulaCell(rOldCell, *pDoc, rNewPos, SC_CLONECELL_ADJUST3DREL);
-    rOldCell.EndListeningTo(pDoc);
-    pNew->StartListeningTo(pDoc);
-    pNew->SetDirty();
-    return pNew;
-}
-
-}
-
-void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
-{
-    if (nRow1 == nRow2)
-        // Nothing to swap.
-        return;
-
-    // Ensure that nRow1 < nRow2.
-    if (nRow2 < nRow1)
-        std::swap(nRow1, nRow2);
-
-    // Broadcasters (if exist) should NOT be swapped.
-
-    sc::CellStoreType::position_type aPos1 = maCells.position(nRow1);
-    if (aPos1.first == maCells.end())
-        return;
-
-    sc::CellStoreType::position_type aPos2 = maCells.position(aPos1.first, nRow2);
-    if (aPos2.first == maCells.end())
-        return;
-
-    std::vector<SCROW> aRows;
-    aRows.reserve(2);
-    aRows.push_back(nRow1);
-    aRows.push_back(nRow2);
-
-    sc::CellStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
-
-    if (it1->type == it2->type)
-    {
-        // Both positions are of the same type. Do a simple value swap.
-        switch (it1->type)
-        {
-            case sc::element_type_empty:
-                // Both are empty. Nothing to swap.
-                return;
-            case sc::element_type_numeric:
-                std::swap(
-                    sc::numeric_block::at(*it1->data, aPos1.second),
-                    sc::numeric_block::at(*it2->data, aPos2.second));
-            break;
-            case sc::element_type_string:
-                std::swap(
-                    sc::string_block::at(*it1->data, aPos1.second),
-                    sc::string_block::at(*it2->data, aPos2.second));
-            break;
-            case sc::element_type_edittext:
-                std::swap(
-                    sc::edittext_block::at(*it1->data, aPos1.second),
-                    sc::edittext_block::at(*it2->data, aPos2.second));
-            break;
-            case sc::element_type_formula:
-            {
-                // Swapping of formula cells involve adjustment of references wrt their positions.
-                sc::formula_block::iterator itf1 = sc::formula_block::begin(*it1->data);
-                sc::formula_block::iterator itf2 = sc::formula_block::begin(*it2->data);
-                std::advance(itf1, aPos1.second);
-                std::advance(itf2, aPos2.second);
-
-                // Is it an identical formula in the same group - if so,
-                // take a shortcut to swap the result data:
-                if(!(*itf1)->SwapWithinGroup(*itf2))
-                {
-                    // otherwise we need to really move the formula &
-                    // re-write dependencies etc.
-                    boost::scoped_ptr<ScFormulaCell> pOld1(*itf1);
-                    boost::scoped_ptr<ScFormulaCell> pOld2(*itf2);
-
-                    DetachFormulaCell(aPos1, **itf1);
-                    DetachFormulaCell(aPos2, **itf2);
-                    ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *pOld2);
-                    ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *pOld1);
-                    *itf1 = pNew1;
-                    *itf2 = pNew2;
-
-                    ActivateNewFormulaCell(aPos1, *pNew1);
-                    ActivateNewFormulaCell(aPos2, *pNew2);
-                }
-            }
-            break;
-            default:
-                ;
-        }
-
-        SwapCellTextAttrs(nRow1, nRow2);
-        SwapCellNotes(nRow1, nRow2);
-        CellStorageModified();
-        BroadcastCells(aRows, SC_HINT_DATACHANGED);
-        return;
-    }
-
-    // The two cells are of different types.
-
-    ScRefCellValue aCell1 = GetCellValue(aPos1.first, aPos1.second);
-    ScRefCellValue aCell2 = GetCellValue(aPos2.first, aPos2.second);
-
-    // Make sure to put cells in row 1 first then row 2!
-
-    if (aCell1.meType == CELLTYPE_NONE)
-    {
-        // cell 1 is empty and cell 2 is not.
-        switch (aCell2.meType)
-        {
-            case CELLTYPE_VALUE:
-                it1 = maCells.set(it1, nRow1, aCell2.mfValue); // it2 becomes invalid.
-                maCells.set_empty(it1, nRow2, nRow2);
-            break;
-            case CELLTYPE_STRING:
-                it1 = maCells.set(it1, nRow1, *aCell2.mpString);
-                maCells.set_empty(it1, nRow2, nRow2);
-            break;
-            case CELLTYPE_EDIT:
-            {
-                it1 = maCells.set(
-                    it1, nRow1, const_cast<EditTextObject*>(aCell2.mpEditText));
-                EditTextObject* p;
-                maCells.release(it1, nRow2, p);
-            }
-            break;
-            case CELLTYPE_FORMULA:
-            {
-                // cell 1 is empty and cell 2 is a formula cell.
-                ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
-                DetachFormulaCell(aPos2, *aCell2.mpFormula);
-                it1 = maCells.set(it1, nRow1, pNew);
-                maCells.set_empty(it1, nRow2, nRow2); // original formula cell gets deleted.
-                ActivateNewFormulaCell(it1, nRow1, *pNew);
-            }
-            break;
-            default:
-                ;
-        }
-
-        SwapCellTextAttrs(nRow1, nRow2);
-        SwapCellNotes(nRow1, nRow2);
-        CellStorageModified();
-        BroadcastCells(aRows, SC_HINT_DATACHANGED);
-        return;
-    }
-
-    if (aCell2.meType == CELLTYPE_NONE)
-    {
-        // cell 1 is not empty and cell 2 is empty.
-        switch (aCell1.meType)
-        {
-            case CELLTYPE_VALUE:
-                // Value is copied in Cell1.
-                it1 = maCells.set_empty(it1, nRow1, nRow1);
-                maCells.set(it1, nRow2, aCell1.mfValue);
-            break;
-            case CELLTYPE_STRING:
-            {
-                svl::SharedString aStr = *aCell1.mpString; // make a copy.
-                it1 = maCells.set_empty(it1, nRow1, nRow1); // original string is gone.
-                maCells.set(it1, nRow2, aStr);
-            }
-            break;
-            case CELLTYPE_EDIT:
-            {
-                EditTextObject* p;
-                it1 = maCells.release(it1, nRow1, p);
-                maCells.set(it1, nRow2, p);
-            }
-            break;
-            case CELLTYPE_FORMULA:
-            {
-                // cell 1 is a formula cell and cell 2 is empty.
-                ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *aCell1.mpFormula);
-                DetachFormulaCell(aPos1, *aCell1.mpFormula);
-                it1 = maCells.set_empty(it1, nRow1, nRow1); // original formula cell is gone.
-                it1 = maCells.set(it1, nRow2, pNew);
-                ActivateNewFormulaCell(it1, nRow2, *pNew);
-            }
-            break;
-            default:
-                ;
-        }
-
-        SwapCellTextAttrs(nRow1, nRow2);
-        SwapCellNotes(nRow1, nRow2);
-        CellStorageModified();
-        BroadcastCells(aRows, SC_HINT_DATACHANGED);
-        return;
-    }
-
-    // Neither cells are empty, and they are of different types.
-    switch (aCell1.meType)
-    {
-        case CELLTYPE_VALUE:
-        {
-            switch (aCell2.meType)
-            {
-                case CELLTYPE_STRING:
-                    it1 = maCells.set(it1, nRow1, *aCell2.mpString);
-                break;
-                case CELLTYPE_EDIT:
-                {
-                    it1 = maCells.set(
-                        it1, nRow1, const_cast<EditTextObject*>(aCell2.mpEditText));
-                    EditTextObject* p;
-                    it1 = maCells.release(it1, nRow2, p);
-                }
-                break;
-                case CELLTYPE_FORMULA:
-                {
-                    DetachFormulaCell(aPos2, *aCell2.mpFormula);
-                    ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
-                    it1 = maCells.set(it1, nRow1, pNew);
-                    ActivateNewFormulaCell(it1, nRow1, *pNew);
-                    // The old formula cell will get overwritten below.
-                }
-                break;
-                default:
-                    ;
-            }
-
-            maCells.set(it1, nRow2, aCell1.mfValue);
-
-        }
-        break;
-        case CELLTYPE_STRING:
-        {
-            svl::SharedString aStr = *aCell1.mpString; // make a copy.
-            switch (aCell2.meType)
-            {
-                case CELLTYPE_VALUE:
-                    it1 = maCells.set(it1, nRow1, aCell2.mfValue);
-                break;
-                case CELLTYPE_EDIT:
-                {
-                    it1 = maCells.set(
-                        it1, nRow1, const_cast<EditTextObject*>(aCell2.mpEditText));
-                    EditTextObject* p;
-                    it1 = maCells.release(it1, nRow2, p); // prevent it being overwritten.
-                }
-                break;
-                case CELLTYPE_FORMULA:
-                {
-                    // cell 1 - string, cell 2 - formula
-                    DetachFormulaCell(aPos2, *aCell2.mpFormula);
-                    ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
-                    it1 = maCells.set(it1, nRow1, pNew);
-                    ActivateNewFormulaCell(it1, nRow1, *pNew);
-                    // Old formula cell will get overwritten below.
-                }
-                break;
-                default:
-                    ;
-            }
-
-            maCells.set(it1, nRow2, aStr);
-        }
-        break;
-        case CELLTYPE_EDIT:
-        {
-            EditTextObject* p;
-            it1 = maCells.release(it1, nRow1, p);
-
-            switch (aCell2.meType)
-            {
-                case CELLTYPE_VALUE:
-                    it1 = maCells.set(it1, nRow1, aCell2.mfValue);
-                break;
-                case CELLTYPE_STRING:
-                    it1 = maCells.set(it1, nRow1, *aCell2.mpString);
-                break;
-                case CELLTYPE_FORMULA:
-                {
-                    DetachFormulaCell(aPos2, *aCell2.mpFormula);
-                    ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
-                    it1 = maCells.set(it1, nRow1, pNew);
-                    ActivateNewFormulaCell(it1, nRow1, *pNew);
-                    // Old formula cell will get overwritten below.
-                }
-                break;
-                default:
-                    ;
-            }
-
-            maCells.set(it1, nRow2, const_cast<EditTextObject*>(aCell1.mpEditText));
-        }
-        break;
-        case CELLTYPE_FORMULA:
-        {
-            // cell 1 is a formula cell and cell 2 is not.
-            DetachFormulaCell(aPos1, *aCell1.mpFormula);
-            ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *aCell1.mpFormula);
-            switch (aCell2.meType)
-            {
-                case CELLTYPE_VALUE:
-                    it1 = maCells.set(it1, nRow1, aCell2.mfValue);
-                break;
-                case CELLTYPE_STRING:
-                    it1 = maCells.set(it1, nRow1, *aCell2.mpString);
-                break;
-                case CELLTYPE_EDIT:
-                {
-                    it1 = maCells.set(it1, nRow1, aCell2.mpEditText);
-                    EditTextObject* p;
-                    it1 = maCells.release(it1, nRow2, p);
-                }
-                break;
-                default:
-                    ;
-            }
-
-            it1 = maCells.set(it1, nRow2, pNew);
-            ActivateNewFormulaCell(it1, nRow2, *pNew);
-        }
-        break;
-        default:
-            ;
-    }
-
-    SwapCellTextAttrs(nRow1, nRow2);
-    SwapCellNotes(nRow1, nRow2);
-    CellStorageModified();
-    BroadcastCells(aRows, SC_HINT_DATACHANGED);
-}
-
-namespace {
-
 /**
  * Adjust references in formula cell with respect to column-wise relocation.
  */
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index f39bbbe..acd8f5e 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -935,40 +935,6 @@ void ScTable::SwapCol(SCCOL nCol1, SCCOL nCol2)
     }
 }
 
-void ScTable::SwapRow(SCROW nRow1, SCROW nRow2)
-{
-    SCCOL nColStart = aSortParam.nCol1;
-    SCCOL nColEnd = aSortParam.nCol2;
-    for (SCCOL nCol = nColStart; nCol <= nColEnd; nCol++)
-    {
-        aCol[nCol].SwapRow(nRow1, nRow2);
-        if (aSortParam.bIncludePattern)
-        {
-            const ScPatternAttr* pPat1 = GetPattern(nCol, nRow1);
-            const ScPatternAttr* pPat2 = GetPattern(nCol, nRow2);
-            if (pPat1 != pPat2)
-            {
-                pDocument->GetPool()->Put(*pPat1);
-                SetPattern(nCol, nRow1, *pPat2, true);
-                SetPattern(nCol, nRow2, *pPat1, true);
-                pDocument->GetPool()->Remove(*pPat1);
-            }
-        }
-    }
-    if (bGlobalKeepQuery)
-    {
-        bool bRow1Hidden = RowHidden(nRow1);
-        bool bRow2Hidden = RowHidden(nRow2);
-        SetRowHidden(nRow1, nRow1, bRow2Hidden);
-        SetRowHidden(nRow2, nRow2, bRow1Hidden);
-
-        bool bRow1Filtered = RowFiltered(nRow1);
-        bool bRow2Filtered = RowFiltered(nRow2);
-        SetRowFiltered(nRow1, nRow1, bRow2Filtered);
-        SetRowFiltered(nRow2, nRow2, bRow1Filtered);
-    }
-}
-
 short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
 {
     short nRes;
commit bd532483b67e4fd2d1f26df545cc525de5522f10
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Apr 22 22:54:25 2014 -0400

    Use scoped_ptr for this.
    
    Change-Id: I54d0bbe460f95ada7632d7c9cbedb8a677995fd4

diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 88f3ea7..f39bbbe 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -2063,9 +2063,9 @@ void ScTable::TopTenQuery( ScQueryParam& rParam )
                     bSortCollatorInitialized = true;
                     InitSortCollator( aLocalSortParam );
                 }
-                ScSortInfoArray* pArray = CreateSortInfoArray(nRow1, rParam.nRow2, bGlobalKeepQuery);
-                DecoladeRow( pArray, nRow1, rParam.nRow2 );
-                QuickSort( pArray, nRow1, rParam.nRow2 );
+                boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(nRow1, rParam.nRow2, bGlobalKeepQuery));
+                DecoladeRow( pArray.get(), nRow1, rParam.nRow2 );
+                QuickSort( pArray.get(), nRow1, rParam.nRow2 );
                 ScSortInfo** ppInfo = pArray->GetFirstArray();
                 SCSIZE nValidCount = nCount;
                 // keine Note-/Leerzellen zaehlen, sind ans Ende sortiert
@@ -2142,7 +2142,6 @@ void ScTable::TopTenQuery( ScQueryParam& rParam )
                     rItem.meType = ScQueryEntry::ByValue;
                     rItem.mfVal = 0;
                 }
-                delete pArray;
             }
             break;
             default:
commit 68fccdc9872c1bf36b2851d58929d6cdcc2e2b2e
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Apr 22 22:47:48 2014 -0400

    New method SortReorderByRow() for the new row-based reordering.
    
    Easier to follow this way.
    
    Change-Id: Idf7e93106f1e1927967f4917062ee619ed71d694

diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index f6e2583..7610eb7 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1016,7 +1016,8 @@ private:
     short       Compare( ScSortInfoArray*, SCCOLROW nIndex1, SCCOLROW nIndex2) const;
     ScSortInfoArray* CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2, bool bKeepQuery );
     void        QuickSort( ScSortInfoArray*, SCsCOLROW nLo, SCsCOLROW nHi);
-    void        SortReorder( ScSortInfoArray*, ScProgress* );
+    void SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress );
+    void SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress );
 
     bool        CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam);
     bool        CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam);
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index bedbb62..88f3ea7 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -523,224 +523,228 @@ void ScTable::DestroySortCollator()
 
 void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
 {
+    if (aSortParam.bByRow)
+    {
+        SortReorderByRow(pArray, pProgress);
+        return;
+    }
+
     size_t nCount = pArray->GetCount();
     SCCOLROW nStart = pArray->GetStart();
     ScSortInfo** ppInfo = pArray->GetFirstArray();
 
-    if (aSortParam.bByRow)
-    {
-        SCROW nRow1 = pArray->GetStart();
-        SCROW nRow2 = pArray->GetLast();
-        ScSortInfoArray::RowsType* pRows = pArray->GetDataRows();
-        assert(pRows); // In sort-by-row mode we must have data rows already populated.
+    std::vector<ScSortInfo*> aTable(nCount);
+    SCSIZE nPos;
+    for ( nPos = 0; nPos < nCount; nPos++ )
+        aTable[ppInfo[nPos]->nOrg - nStart] = ppInfo[nPos];
+
+    SCCOLROW nDest = nStart;
+    for ( nPos = 0; nPos < nCount; nPos++, nDest++ )
+    {
+        SCCOLROW nOrg = ppInfo[nPos]->nOrg;
+        if ( nDest != nOrg )
+        {
+            SwapCol( static_cast<SCCOL>(nDest), static_cast<SCCOL>(nOrg) );
+            // neue Position des weggeswapten eintragen
+            ScSortInfo* p = ppInfo[nPos];
+            p->nOrg = nDest;
+            ::std::swap(p, aTable[nDest-nStart]);
+            p->nOrg = nOrg;
+            ::std::swap(p, aTable[nOrg-nStart]);
+            OSL_ENSURE( p == ppInfo[nPos], "SortReorder: nOrg MisMatch" );
+        }
+        if(pProgress)
+            pProgress->SetStateOnPercent( nPos );
+    }
+}
+
+void ScTable::SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress )
+{
+    SCROW nRow1 = pArray->GetStart();
+    SCROW nRow2 = pArray->GetLast();
+    ScSortInfoArray::RowsType* pRows = pArray->GetDataRows();
+    assert(pRows); // In sort-by-row mode we must have data rows already populated.
 
-        // Detach all formula cells within the sorted range first.
-        sc::EndListeningContext aCxt(*pDocument);
-        DetachFormulaCells(aCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, nRow2);
+    // Detach all formula cells within the sorted range first.
+    sc::EndListeningContext aCxt(*pDocument);
+    DetachFormulaCells(aCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, nRow2);
 
-        // Cells in the data rows only reference values in the document. Make
-        // a copy before updating the document.
+    // Cells in the data rows only reference values in the document. Make
+    // a copy before updating the document.
 
-        size_t nColCount = aSortParam.nCol2 - aSortParam.nCol1 + 1;
-        boost::ptr_vector<SortedColumn> aSortedCols; // storage for copied cells.
-        SortedRowFlags aRowFlags;
-        aSortedCols.reserve(nColCount);
-        for (size_t i = 0; i < nColCount; ++i)
-        {
-            // In the sorted column container, element positions and row
-            // positions must match, else formula cells may mis-behave during
-            // grouping.
-            aSortedCols.push_back(new SortedColumn(nRow1));
-        }
+    size_t nColCount = aSortParam.nCol2 - aSortParam.nCol1 + 1;
+    boost::ptr_vector<SortedColumn> aSortedCols; // storage for copied cells.
+    SortedRowFlags aRowFlags;
+    aSortedCols.reserve(nColCount);
+    for (size_t i = 0; i < nColCount; ++i)
+    {
+        // In the sorted column container, element positions and row
+        // positions must match, else formula cells may mis-behave during
+        // grouping.
+        aSortedCols.push_back(new SortedColumn(nRow1));
+    }
 
-        for (size_t i = 0; i < pRows->size(); ++i)
+    for (size_t i = 0; i < pRows->size(); ++i)
+    {
+        ScSortInfoArray::Row* pRow = (*pRows)[i];
+        for (size_t j = 0; j < pRow->maCells.size(); ++j)
         {
-            ScSortInfoArray::Row* pRow = (*pRows)[i];
-            for (size_t j = 0; j < pRow->maCells.size(); ++j)
-            {
-                ScAddress aCellPos(aSortParam.nCol1 + j, nRow1 + i, nTab);
+            ScAddress aCellPos(aSortParam.nCol1 + j, nRow1 + i, nTab);
 
-                ScSortInfoArray::Cell& rCell = pRow->maCells[j];
+            ScSortInfoArray::Cell& rCell = pRow->maCells[j];
 
-                sc::CellStoreType& rCellStore = aSortedCols.at(j).maCells;
-                switch (rCell.maCell.meType)
+            sc::CellStoreType& rCellStore = aSortedCols.at(j).maCells;
+            switch (rCell.maCell.meType)
+            {
+                case CELLTYPE_STRING:
+                    assert(rCell.mpAttr);
+                    rCellStore.push_back(*rCell.maCell.mpString);
+                break;
+                case CELLTYPE_VALUE:
+                    assert(rCell.mpAttr);
+                    rCellStore.push_back(rCell.maCell.mfValue);
+                break;
+                case CELLTYPE_EDIT:
+                    assert(rCell.mpAttr);
+                    rCellStore.push_back(rCell.maCell.mpEditText->Clone());
+                break;
+                case CELLTYPE_FORMULA:
                 {
-                    case CELLTYPE_STRING:
-                        assert(rCell.mpAttr);
-                        rCellStore.push_back(*rCell.maCell.mpString);
-                    break;
-                    case CELLTYPE_VALUE:
-                        assert(rCell.mpAttr);
-                        rCellStore.push_back(rCell.maCell.mfValue);
-                    break;
-                    case CELLTYPE_EDIT:
-                        assert(rCell.mpAttr);
-                        rCellStore.push_back(rCell.maCell.mpEditText->Clone());
-                    break;
-                    case CELLTYPE_FORMULA:
-                    {
-                        assert(rCell.mpAttr);
-                        size_t n = rCellStore.size();
-                        sc::CellStoreType::iterator itBlk = rCellStore.push_back(rCell.maCell.mpFormula->Clone(aCellPos));
-
-                        // Join the formula cells as we fill the container.
-                        size_t nOffset = n - itBlk->position;
-                        sc::CellStoreType::position_type aPos(itBlk, nOffset);
-                        sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
-                    }
-                    break;
-                    default:
-                        assert(!rCell.mpAttr);
-                        rCellStore.push_back_empty();
+                    assert(rCell.mpAttr);
+                    size_t n = rCellStore.size();
+                    sc::CellStoreType::iterator itBlk = rCellStore.push_back(rCell.maCell.mpFormula->Clone(aCellPos));
+
+                    // Join the formula cells as we fill the container.
+                    size_t nOffset = n - itBlk->position;
+                    sc::CellStoreType::position_type aPos(itBlk, nOffset);
+                    sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
                 }
+                break;
+                default:
+                    assert(!rCell.mpAttr);
+                    rCellStore.push_back_empty();
+            }
 
-                sc::CellTextAttrStoreType& rAttrStore = aSortedCols.at(j).maCellTextAttrs;
-                if (rCell.mpAttr)
-                    rAttrStore.push_back(*rCell.mpAttr);
-                else
-                    rAttrStore.push_back_empty();
-
-                // At this point each broadcaster instance is managed by 2
-                // containers. We will release those in the original storage
-                // below before transferring them to the document.
-                sc::BroadcasterStoreType& rBCStore = aSortedCols.at(j).maBroadcasters;
-                if (rCell.mpBroadcaster)
-                    // A const pointer would be implicitly converted to a bool type.
-                    rBCStore.push_back(const_cast<SvtBroadcaster*>(rCell.mpBroadcaster));
-                else
-                    rBCStore.push_back_empty();
-
-                // The same with cell note instances ...
-                sc::CellNoteStoreType& rNoteStore = aSortedCols.at(j).maCellNotes;
-                if (rCell.mpNote)
-                    rNoteStore.push_back(const_cast<ScPostIt*>(rCell.mpNote));
-                else
-                    rNoteStore.push_back_empty();
+            sc::CellTextAttrStoreType& rAttrStore = aSortedCols.at(j).maCellTextAttrs;
+            if (rCell.mpAttr)
+                rAttrStore.push_back(*rCell.mpAttr);
+            else
+                rAttrStore.push_back_empty();
+
+            // At this point each broadcaster instance is managed by 2
+            // containers. We will release those in the original storage
+            // below before transferring them to the document.
+            sc::BroadcasterStoreType& rBCStore = aSortedCols.at(j).maBroadcasters;
+            if (rCell.mpBroadcaster)
+                // A const pointer would be implicitly converted to a bool type.
+                rBCStore.push_back(const_cast<SvtBroadcaster*>(rCell.mpBroadcaster));
+            else
+                rBCStore.push_back_empty();
 
-                if (rCell.mpPattern)
-                    aSortedCols.at(j).setPattern(aCellPos.Row(), rCell.mpPattern);
-            }
+            // The same with cell note instances ...
+            sc::CellNoteStoreType& rNoteStore = aSortedCols.at(j).maCellNotes;
+            if (rCell.mpNote)
+                rNoteStore.push_back(const_cast<ScPostIt*>(rCell.mpNote));
+            else
+                rNoteStore.push_back_empty();
 
-            if (pArray->IsKeepQuery())
-            {
-                // Hidden and filtered flags are first converted to segments.
-                SCROW nRow = nRow1 + i;
-                aRowFlags.setRowHidden(nRow, pRow->mbHidden);
-                aRowFlags.setRowFiltered(nRow, pRow->mbFiltered);
-            }
+            if (rCell.mpPattern)
+                aSortedCols.at(j).setPattern(aCellPos.Row(), rCell.mpPattern);
+        }
 
-            if (pProgress)
-                pProgress->SetStateOnPercent(i);
+        if (pArray->IsKeepQuery())
+        {
+            // Hidden and filtered flags are first converted to segments.
+            SCROW nRow = nRow1 + i;
+            aRowFlags.setRowHidden(nRow, pRow->mbHidden);
+            aRowFlags.setRowFiltered(nRow, pRow->mbFiltered);
         }
 
-        for (size_t i = 0, n = aSortedCols.size(); i < n; ++i)
+        if (pProgress)
+            pProgress->SetStateOnPercent(i);
+    }
+
+    for (size_t i = 0, n = aSortedCols.size(); i < n; ++i)
+    {
+        SCCOL nThisCol = i + aSortParam.nCol1;
+
         {
-            SCCOL nThisCol = i + aSortParam.nCol1;
+            sc::CellStoreType& rDest = aCol[nThisCol].maCells;
+            sc::CellStoreType& rSrc = aSortedCols[i].maCells;
+            rSrc.transfer(nRow1, nRow2, rDest, nRow1);
+        }
 
-            {
-                sc::CellStoreType& rDest = aCol[nThisCol].maCells;
-                sc::CellStoreType& rSrc = aSortedCols[i].maCells;
-                rSrc.transfer(nRow1, nRow2, rDest, nRow1);
-            }
+        {
+            sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs;
+            sc::CellTextAttrStoreType& rSrc = aSortedCols[i].maCellTextAttrs;
+            rSrc.transfer(nRow1, nRow2, rDest, nRow1);
+        }
 
-            {
-                sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs;
-                sc::CellTextAttrStoreType& rSrc = aSortedCols[i].maCellTextAttrs;
-                rSrc.transfer(nRow1, nRow2, rDest, nRow1);
-            }
+        {
+            sc::BroadcasterStoreType& rSrc = aSortedCols[i].maBroadcasters;
+            sc::BroadcasterStoreType& rDest = aCol[nThisCol].maBroadcasters;
 
-            {
-                sc::BroadcasterStoreType& rSrc = aSortedCols[i].maBroadcasters;
-                sc::BroadcasterStoreType& rDest = aCol[nThisCol].maBroadcasters;
+            // Release current broadcasters first, to prevent them from getting deleted.
+            rDest.release_range(nRow1, nRow2);
 
-                // Release current broadcasters first, to prevent them from getting deleted.
-                rDest.release_range(nRow1, nRow2);
+            // Transfer sorted broadcaster segment to the document.
+            rSrc.transfer(nRow1, nRow2, rDest, nRow1);
+        }
 
-                // Transfer sorted broadcaster segment to the document.
-                rSrc.transfer(nRow1, nRow2, rDest, nRow1);
-            }
+        {
+            sc::CellNoteStoreType& rSrc = aSortedCols[i].maCellNotes;
+            sc::CellNoteStoreType& rDest = aCol[nThisCol].maCellNotes;
 
-            {
-                sc::CellNoteStoreType& rSrc = aSortedCols[i].maCellNotes;
-                sc::CellNoteStoreType& rDest = aCol[nThisCol].maCellNotes;
+            // Do the same as broadcaster storage transfer (to prevent double deletion).
+            rDest.release_range(nRow1, nRow2);
+            rSrc.transfer(nRow1, nRow2, rDest, nRow1);
+            aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2);
+        }
 
-                // Do the same as broadcaster storage transfer (to prevent double deletion).
-                rDest.release_range(nRow1, nRow2);
-                rSrc.transfer(nRow1, nRow2, rDest, nRow1);
-                aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2);
-            }
+        {
+            // Get all row spans where the pattern is not NULL.
+            std::vector<PatternSpan> aSpans =
+                sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>(
+                    aSortedCols[i].maPatterns);
 
+            std::vector<PatternSpan>::iterator it = aSpans.begin(), itEnd = aSpans.end();
+            for (; it != itEnd; ++it)
             {
-                // Get all row spans where the pattern is not NULL.
-                std::vector<PatternSpan> aSpans =
-                    sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>(
-                        aSortedCols[i].maPatterns);
-
-                std::vector<PatternSpan>::iterator it = aSpans.begin(), itEnd = aSpans.end();
-                for (; it != itEnd; ++it)
-                {
-                    assert(it->mpPattern); // should never be NULL.
-                    aCol[nThisCol].SetPatternArea(it->mnRow1, it->mnRow2, *it->mpPattern, true);
-                }
+                assert(it->mpPattern); // should never be NULL.
+                aCol[nThisCol].SetPatternArea(it->mnRow1, it->mnRow2, *it->mpPattern, true);
             }
-
-            aCol[nThisCol].CellStorageModified();
         }
 
-        if (pArray->IsKeepQuery())
-        {
-            aRowFlags.maRowsHidden.build_tree();
-            aRowFlags.maRowsFiltered.build_tree();
+        aCol[nThisCol].CellStorageModified();
+    }
 
-            // Remove all flags in the range first.
-            SetRowHidden(nRow1, nRow2, false);
-            SetRowFiltered(nRow1, nRow2, false);
+    if (pArray->IsKeepQuery())
+    {
+        aRowFlags.maRowsHidden.build_tree();
+        aRowFlags.maRowsFiltered.build_tree();
 
-            std::vector<sc::RowSpan> aSpans =
-                sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsHidden, nRow1);
+        // Remove all flags in the range first.
+        SetRowHidden(nRow1, nRow2, false);
+        SetRowFiltered(nRow1, nRow2, false);
 
-            std::vector<sc::RowSpan>::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
-            for (; it != itEnd; ++it)
-                SetRowHidden(it->mnRow1, it->mnRow2, true);
+        std::vector<sc::RowSpan> aSpans =
+            sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsHidden, nRow1);
 
-            aSpans = sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsFiltered, nRow1);
+        std::vector<sc::RowSpan>::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
+        for (; it != itEnd; ++it)
+            SetRowHidden(it->mnRow1, it->mnRow2, true);
 
-            it = aSpans.begin(), itEnd = aSpans.end();
-            for (; it != itEnd; ++it)
-                SetRowFiltered(it->mnRow1, it->mnRow2, true);
-        }
+        aSpans = sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsFiltered, nRow1);
 
-        // Attach all formula cells within sorted range, to have them start listening again.
-        sc::StartListeningContext aStartListenCxt(*pDocument);
-        AttachFormulaCells(
-            aStartListenCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, nRow2);
+        it = aSpans.begin(), itEnd = aSpans.end();
+        for (; it != itEnd; ++it)
+            SetRowFiltered(it->mnRow1, it->mnRow2, true);
     }
-    else
-    {
-        std::vector<ScSortInfo*> aTable(nCount);
-        SCSIZE nPos;
-        for ( nPos = 0; nPos < nCount; nPos++ )
-            aTable[ppInfo[nPos]->nOrg - nStart] = ppInfo[nPos];
 
-        SCCOLROW nDest = nStart;
-        for ( nPos = 0; nPos < nCount; nPos++, nDest++ )
-        {
-            SCCOLROW nOrg = ppInfo[nPos]->nOrg;
-            if ( nDest != nOrg )
-            {
-                SwapCol( static_cast<SCCOL>(nDest), static_cast<SCCOL>(nOrg) );
-                // neue Position des weggeswapten eintragen
-                ScSortInfo* p = ppInfo[nPos];
-                p->nOrg = nDest;
-                ::std::swap(p, aTable[nDest-nStart]);
-                p->nOrg = nOrg;
-                ::std::swap(p, aTable[nOrg-nStart]);
-                OSL_ENSURE( p == ppInfo[nPos], "SortReorder: nOrg MisMatch" );
-            }
-            if(pProgress)
-                pProgress->SetStateOnPercent( nPos );
-        }
-    }
+    // Attach all formula cells within sorted range, to have them start listening again.
+    sc::StartListeningContext aStartListenCxt(*pDocument);
+    AttachFormulaCells(
+        aStartListenCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, nRow2);
 }
 
 short ScTable::CompareCell(
commit 91261a246bd1c69b4b5ee62669e8a854c62bf3da
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Apr 22 21:38:05 2014 -0400

    Apply sorted patterns as ranges instead of row-by-row.
    
    This scrapes off additional 2.2 seconds.
    
    Change-Id: I08ae67f45946721d722be7183270d7bcf01f96b0

diff --git a/sc/inc/fstalgorithm.hxx b/sc/inc/fstalgorithm.hxx
index 8a50ae0..08d68d4 100644
--- a/sc/inc/fstalgorithm.hxx
+++ b/sc/inc/fstalgorithm.hxx
@@ -44,6 +44,35 @@ void buildSpan(
     }
 }
 
+template<typename _Key, typename _Val, typename _Span>
+void buildSpanWithValue(
+    std::vector<_Span>& rSpans,
+    typename mdds::flat_segment_tree<_Key,_Val>::const_iterator it,
+    typename mdds::flat_segment_tree<_Key,_Val>::const_iterator itEnd, const _Key* pStart )
+{
+    _Key nLastPos = it->first;
+    _Val nLastVal = it->second;
+    for (++it; it != itEnd; ++it)
+    {
+        _Key nThisPos = it->first;
+        _Val nThisVal = it->second;
+
+        if (nLastVal)
+        {
+            _Key nIndex1 = nLastPos;
+            _Key nIndex2 = nThisPos-1;
+
+            if (!pStart || *pStart < nIndex1)
+                rSpans.push_back(_Span(nIndex1, nIndex2, nLastVal));
+            else if (*pStart <= nIndex2)
+                rSpans.push_back(_Span(*pStart, nIndex2, nLastVal));
+        }
+
+        nLastPos = nThisPos;
+        nLastVal = nThisVal;
+    }
+}
+
 /**
  * Convert a flat_segment_tree structure whose value type is boolean, into
  * an array of ranges that corresponds with the segments that have a 'true'
@@ -61,6 +90,25 @@ std::vector<_Span> toSpanArray( const mdds::flat_segment_tree<_Key,bool>& rTree
     return aSpans;
 }
 
+/**
+ * Convert a flat_segment_tree structure into an array of ranges with
+ * values.  Only those ranges whose value is evaluated to be true will be
+ * included.  The value type must be something that supports bool operator.
+ * The span type must support a constructor that takes a start key, an end
+ * key and a value in this order.
+ */
+template<typename _Key, typename _Val, typename _Span>
+std::vector<_Span> toSpanArrayWithValue( const mdds::flat_segment_tree<_Key,_Val>& rTree )
+{
+    typedef mdds::flat_segment_tree<_Key,_Val> FstType;
+
+    std::vector<_Span> aSpans;
+
+    typename FstType::const_iterator it = rTree.begin(), itEnd = rTree.end();
+    buildSpanWithValue<_Key,_Val,_Span>(aSpans, it, itEnd, NULL);
+    return aSpans;
+}
+
 template<typename _Key, typename _Span>
 std::vector<_Span> toSpanArray( const mdds::flat_segment_tree<_Key,bool>& rTree, _Key nStartPos )
 {
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 77ecb69..bedbb62 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -69,6 +69,7 @@
 #include <boost/unordered_set.hpp>
 #include <boost/noncopyable.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
+#include <mdds/flat_segment_tree.hpp>
 
 using namespace ::com::sun::star;
 
@@ -422,17 +423,28 @@ namespace {
 
 struct SortedColumn : boost::noncopyable
 {
+    typedef mdds::flat_segment_tree<SCROW, const ScPatternAttr*> PatRangeType;
 
     sc::CellStoreType maCells;
     sc::CellTextAttrStoreType maCellTextAttrs;
     sc::BroadcasterStoreType maBroadcasters;
     sc::CellNoteStoreType maCellNotes;
 
+    PatRangeType maPatterns;
+    PatRangeType::const_iterator miPatternPos;
+
     SortedColumn( size_t nTopEmptyRows ) :
         maCells(nTopEmptyRows),
         maCellTextAttrs(nTopEmptyRows),
         maBroadcasters(nTopEmptyRows),
-        maCellNotes(nTopEmptyRows) {}
+        maCellNotes(nTopEmptyRows),
+        maPatterns(0, MAXROWCOUNT, NULL),
+        miPatternPos(maPatterns.begin()) {}
+
+    void setPattern( SCROW nRow, const ScPatternAttr* pPat )
+    {
+        miPatternPos = maPatterns.insert(miPatternPos, nRow, nRow+1, pPat).first;
+    }
 };
 
 struct SortedRowFlags
@@ -461,6 +473,16 @@ struct SortedRowFlags
     }
 };
 
+struct PatternSpan
+{
+    SCROW mnRow1;
+    SCROW mnRow2;
+    const ScPatternAttr* mpPattern;
+
+    PatternSpan( SCROW nRow1, SCROW nRow2, const ScPatternAttr* pPat ) :
+        mnRow1(nRow1), mnRow2(nRow2), mpPattern(pPat) {}
+};
+
 }
 
 bool ScTable::IsSortCollatorGlobal() const
@@ -595,9 +617,8 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
                 else
                     rNoteStore.push_back_empty();
 
-                // Set formats to the document directly.
                 if (rCell.mpPattern)
-                    aCol[aCellPos.Col()].SetPattern(aCellPos.Row(), *rCell.mpPattern, true);
+                    aSortedCols.at(j).setPattern(aCellPos.Row(), rCell.mpPattern);
             }
 
             if (pArray->IsKeepQuery())
@@ -649,6 +670,20 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
                 aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2);
             }
 
+            {
+                // Get all row spans where the pattern is not NULL.
+                std::vector<PatternSpan> aSpans =
+                    sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>(
+                        aSortedCols[i].maPatterns);
+
+                std::vector<PatternSpan>::iterator it = aSpans.begin(), itEnd = aSpans.end();
+                for (; it != itEnd; ++it)
+                {
+                    assert(it->mpPattern); // should never be NULL.
+                    aCol[nThisCol].SetPatternArea(it->mnRow1, it->mnRow2, *it->mpPattern, true);
+                }
+            }
+
             aCol[nThisCol].CellStorageModified();
         }
 
commit 46b35f349ef795d89e4f03fe7f72623ee105e669
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Apr 22 20:59:13 2014 -0400

    Skip reordering of cell formats when whole range is over one pattern entry.
    
    Change-Id: I2ee377a865f361673912b796af1eb8517c1456f7

diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index a672303..77ecb69 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -370,6 +370,10 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2, b
         for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; ++nCol)
         {
             ScColumn& rCol = aCol[nCol];
+
+            // Skip reordering of cell formats if the whole span is on the same pattern entry.
+            bool bUniformPattern = rCol.GetPatternCount(nInd1, nInd2) < 2u;
+
             sc::ColumnBlockConstPosition aBlockPos;
             rCol.InitBlockPosition(aBlockPos);
             for (SCROW nRow = nInd1; nRow <= nInd2; ++nRow)
@@ -382,7 +386,7 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2, b
                 rCell.mpBroadcaster = rCol.GetBroadcaster(aBlockPos, nRow);
                 rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow);
 
-                if (aSortParam.bIncludePattern)
+                if (!bUniformPattern && aSortParam.bIncludePattern)
                     rCell.mpPattern = rCol.GetPattern(nRow);
             }
         }
commit d053d40e86381cc4e7c7249e66530f5f4323b514
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Apr 22 16:29:14 2014 -0400

    Skip adjustment of row height when all rows have the same height.
    
    Change-Id: I490ecade6b909bcf36b848c05e198d58adc90e0a

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index ac81e17..f16b292 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1572,6 +1572,8 @@ public:
 
     SC_DLLPUBLIC bool IsManualRowHeight(SCROW nRow, SCTAB nTab) const;
 
+    bool HasUniformRowHeight( SCTAB nTab, SCROW nRow1, SCROW nRow2 ) const;
+
     /**
      * Write all column row flags to table's flag data, because not all column
      * row attributes are stored in the flag data members.  This is necessary
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index ac44f30..f6e2583 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -815,6 +815,8 @@ public:
 
     bool IsManualRowHeight(SCROW nRow) const;
 
+    bool HasUniformRowHeight( SCROW nRow1, SCROW nRow2 ) const;
+
     void        SyncColRowFlags();
 
     void        StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 );
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index abf5297..9513dfb 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -279,4 +279,13 @@ void ScDocument::UpdateScriptTypes( const ScAddress& rPos, SCCOL nColSize, SCROW
     pTab->UpdateScriptTypes(rPos.Col(), rPos.Row(), rPos.Col()+nColSize-1, rPos.Row()+nRowSize-1);
 }
 
+bool ScDocument::HasUniformRowHeight( SCTAB nTab, SCROW nRow1, SCROW nRow2 ) const
+{
+    const ScTable* pTab = FetchTable(nTab);
+    if (!pTab)
+        return false;
+
+    return pTab->HasUniformRowHeight(nRow1, nRow2);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index eeb4643..385bea1 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -12,6 +12,7 @@
 #include <document.hxx>
 #include <clipparam.hxx>
 #include <bcaslot.hxx>
+#include <segmenttree.hxx>
 
 bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const
 {
@@ -110,4 +111,17 @@ void ScTable::UpdateScriptTypes( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nR
         aCol[nCol].UpdateScriptTypes(nRow1, nRow2);
 }
 
+bool ScTable::HasUniformRowHeight( SCROW nRow1, SCROW nRow2 ) const
+{
+    if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
+        return false;
+
+    ScFlatUInt16RowSegments::RangeData aData;
+    if (!mpRowHeights->getRangeData(nRow1, aData))
+        // Search failed.
+        return false;
+
+    return nRow2 <= aData.mnRow2;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx
index de45b1a..deaf244 100644
--- a/sc/source/ui/docshell/dbdocfun.cxx
+++ b/sc/source/ui/docshell/dbdocfun.cxx
@@ -490,13 +490,19 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
 
     WaitObject aWait( rDocShell.GetActiveDialogParent() );
 
+    SCROW nStartRow = aLocalParam.nRow1 + (aLocalParam.bHasHeader ? 1 : 0);
+
     // Calculate the script types for all cells in the sort range beforehand.
     // This will speed up the row height adjustment that takes place after the
     // sort.
     pDoc->UpdateScriptTypes(
-        ScAddress(rSortParam.nCol1,rSortParam.nRow1,nTab),
-        rSortParam.nCol2-rSortParam.nCol1+1,
-        rSortParam.nRow2-rSortParam.nRow1+1);
+        ScAddress(aLocalParam.nCol1,nStartRow,nTab),
+        aLocalParam.nCol2-aLocalParam.nCol1+1,
+        aLocalParam.nRow2-nStartRow+1);
+
+    // No point adjusting row heights after the sort when all rows have the same height.
+    bool bUniformRowHeight =
+        pDoc->HasUniformRowHeight(nTab, nStartRow, aLocalParam.nRow2);
 
     bool bRepeatQuery = false;                          // bestehenden Filter wiederholen?
     ScQueryParam aQueryParam;
@@ -632,8 +638,9 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
         }
     }
 
-    ScRange aDirtyRange( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
-        aLocalParam.nCol2, aLocalParam.nRow2, nTab );
+    ScRange aDirtyRange(
+        aLocalParam.nCol1, nStartRow, nTab,
+        aLocalParam.nCol2, aLocalParam.nRow2, nTab);
     pDoc->SetDirty( aDirtyRange );
 
     if (bPaint)
@@ -659,7 +666,8 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
         rDocShell.PostPaint(ScRange(nStartX, nStartY, nTab, nEndX, nEndY, nTab), nPaint);
     }
 
-    rDocShell.AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, nTab );
+    if (!bUniformRowHeight)
+        rDocShell.AdjustRowHeight(nStartRow, aLocalParam.nRow2, nTab);
 
     // #i59745# set collected drawing undo actions at sorting undo action
     if( pUndoAction && pDrawLayer )
commit 832bee9aae88c30d2eea4c8fd0765e4a193cbe7b
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Apr 22 15:28:49 2014 -0400

    Update script types of all cells in sort range ahead of time.
    
    To ensure that there is no SC_SCRIPTTYPE_UNKNOWN in the sort range,
    the presence of which would slow down during AdjustRowHeight().
    
    This only adds a tiny overhead (0.3 second) and cuts the duration of
    AdjustRowHeight() from 15 seconds to 5 seconds.
    
    Change-Id: I145e901225ef1136f53c6f682ffed3902099859c

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 25f1be6..51ddaf4 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -499,6 +499,7 @@ public:
             sc::CellStoreType::iterator itr);
 
     void SetScriptType( SCROW nRow, sal_uInt8 nType );
+    void UpdateScriptTypes( SCROW nRow1, SCROW nRow2 );
 
     size_t GetFormulaHash( SCROW nRow ) const;
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index b57ce70..ac81e17 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -2060,6 +2060,7 @@ public:
 
     sal_uInt8 GetScriptType( const ScAddress& rPos ) const;
     void SetScriptType( const ScAddress& rPos, sal_uInt8 nType );
+    void UpdateScriptTypes( const ScAddress& rPos, SCCOL nColSize, SCROW nRowSize );
 
     size_t GetFormulaHash( const ScAddress& rPos ) const;
 
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index b29bb8d..ac44f30 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -864,6 +864,7 @@ public:
 
     sal_uInt8 GetScriptType( SCCOL nCol, SCROW nRow ) const;
     void SetScriptType( SCCOL nCol, SCROW nRow, sal_uInt8 nType );
+    void UpdateScriptTypes( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
 
     sal_uInt8 GetRangeScriptType( sc::ColumnBlockPosition& rBlockPos, SCCOL nCol, SCROW nRow1, SCROW nRow2 );
 
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 2698f0b..cad94e5 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -25,6 +25,9 @@
 #include <conditio.hxx>
 #include <formulagroup.hxx>
 #include <tokenarray.hxx>
+#include <globalnames.hxx>
+#include <scitems.hxx>
+#include <cellform.hxx>
 
 #include <svl/sharedstringpool.hxx>
 
@@ -721,4 +724,105 @@ void ScColumn::PostprocessRangeNameUpdate( sc::CompileFormulaContext& rCompileCx
     std::for_each(aGroups.begin(), aGroups.end(), aFunc);
 }
 
+namespace {
+
+class ScriptTypeUpdater
+{
+    ScColumn& mrCol;
+    sc::CellTextAttrStoreType& mrTextAttrs;
+    sc::CellTextAttrStoreType::iterator miPosAttr;
+    ScConditionalFormatList* mpCFList;
+    SvNumberFormatter* mpFormatter;
+    ScAddress maPos;
+    bool mbUpdated;
+
+private:
+    void updateScriptType( size_t nRow, ScRefCellValue& rCell )
+    {
+        sc::CellTextAttrStoreType::position_type aAttrPos = mrTextAttrs.position(miPosAttr, nRow);
+        miPosAttr = aAttrPos.first;
+
+        if (aAttrPos.first->type != sc::element_type_celltextattr)
+            return;
+
+        sc::CellTextAttr& rAttr = sc::celltextattr_block::at(*aAttrPos.first->data, aAttrPos.second);
+        if (rAttr.mnScriptType != SC_SCRIPTTYPE_UNKNOWN)
+            // Script type already deteremined.  Skip it.
+            return;
+
+        const ScPatternAttr* pPat = mrCol.GetPattern(nRow);
+        if (!pPat)
+            // In theory this should never return NULL. But let's be safe.
+            return;
+
+        const SfxItemSet* pCondSet = NULL;
+        if (mpCFList)
+        {
+            maPos.SetRow(nRow);
+            const ScCondFormatItem& rItem =
+                static_cast<const ScCondFormatItem&>(pPat->GetItem(ATTR_CONDITIONAL));
+            const std::vector<sal_uInt32>& rData = rItem.GetCondFormatData();
+            pCondSet = mrCol.GetDoc().GetCondResult(rCell, maPos, *mpCFList, rData);
+        }
+
+        OUString aStr;
+        Color* pColor;
+        sal_uLong nFormat = pPat->GetNumberFormat(mpFormatter, pCondSet);
+        ScCellFormat::GetString(rCell, nFormat, aStr, &pColor, *mpFormatter, &mrCol.GetDoc());
+
+        rAttr.mnScriptType = mrCol.GetDoc().GetStringScriptType(aStr);
+        mbUpdated = true;
+    }
+
+public:
+    ScriptTypeUpdater( ScColumn& rCol ) :
+        mrCol(rCol),
+        mrTextAttrs(rCol.GetCellAttrStore()),
+        miPosAttr(mrTextAttrs.begin()),
+        mpCFList(rCol.GetDoc().GetCondFormList(rCol.GetTab())),
+        mpFormatter(rCol.GetDoc().GetFormatTable()),
+        maPos(rCol.GetCol(), 0, rCol.GetTab()),
+        mbUpdated(false)
+    {}
+
+    void operator() ( size_t nRow, double fVal )
+    {
+        ScRefCellValue aCell(fVal);
+        updateScriptType(nRow, aCell);
+    }
+
+    void operator() ( size_t nRow, const svl::SharedString& rStr )
+    {
+        ScRefCellValue aCell(&rStr);
+        updateScriptType(nRow, aCell);
+    }
+
+    void operator() ( size_t nRow, const EditTextObject* pText )
+    {
+        ScRefCellValue aCell(pText);
+        updateScriptType(nRow, aCell);
+    }
+
+    void operator() ( size_t nRow, const ScFormulaCell* pCell )
+    {
+        ScRefCellValue aCell(const_cast<ScFormulaCell*>(pCell));
+        updateScriptType(nRow, aCell);
+    }
+
+    bool isUpdated() const { return mbUpdated; }
+};
+
+}
+
+void ScColumn::UpdateScriptTypes( SCROW nRow1, SCROW nRow2 )
+{
+    if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
+        return;
+
+    ScriptTypeUpdater aFunc(*this);
+    sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+    if (aFunc.isUpdated())
+        CellStorageModified();
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index a04e8f9..abf5297 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -270,4 +270,13 @@ void ScDocument::SharePooledResources( ScDocument* pSrcDoc )
     mpCellStringPool = pSrcDoc->mpCellStringPool;
 }
 
+void ScDocument::UpdateScriptTypes( const ScAddress& rPos, SCCOL nColSize, SCROW nRowSize )
+{
+    ScTable* pTab = FetchTable(rPos.Tab());
+    if (!pTab)
+        return;
+
+    pTab->UpdateScriptTypes(rPos.Col(), rPos.Row(), rPos.Col()+nColSize-1, rPos.Row()+nRowSize-1);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index 928c109..eeb4643 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -101,4 +101,13 @@ void ScTable::PostprocessRangeNameUpdate( sc::CompileFormulaContext& rCompileCxt
         aCol[i].PostprocessRangeNameUpdate(rCompileCxt);
 }
 
+void ScTable::UpdateScriptTypes( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+    if (!ValidCol(nCol1) || !ValidCol(nCol2) || nCol1 > nCol2)
+        return;
+
+    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+        aCol[nCol].UpdateScriptTypes(nRow1, nRow2);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx
index 605ba47..de45b1a 100644
--- a/sc/source/ui/docshell/dbdocfun.cxx
+++ b/sc/source/ui/docshell/dbdocfun.cxx
@@ -490,6 +490,14 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
 
     WaitObject aWait( rDocShell.GetActiveDialogParent() );
 
+    // Calculate the script types for all cells in the sort range beforehand.
+    // This will speed up the row height adjustment that takes place after the
+    // sort.
+    pDoc->UpdateScriptTypes(
+        ScAddress(rSortParam.nCol1,rSortParam.nRow1,nTab),
+        rSortParam.nCol2-rSortParam.nCol1+1,
+        rSortParam.nRow2-rSortParam.nRow1+1);
+
     bool bRepeatQuery = false;                          // bestehenden Filter wiederholen?
     ScQueryParam aQueryParam;
     pDBData->GetQueryParam( aQueryParam );
@@ -651,7 +659,6 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
         rDocShell.PostPaint(ScRange(nStartX, nStartY, nTab, nEndX, nEndY, nTab), nPaint);
     }
 
-    //  AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, bPaint );
     rDocShell.AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, nTab );
 
     // #i59745# set collected drawing undo actions at sorting undo action
commit 94cf534a89634290201141a08e19d156bb3b9a19
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Apr 22 00:36:40 2014 -0400

    Handle reordering of row hidden and filtered flags during sort.
    
    Only when the "keep query" flag is set.
    
    Change-Id: Ia799f62ec53a08cfd92e93c546965002c030b324

diff --git a/sc/inc/fstalgorithm.hxx b/sc/inc/fstalgorithm.hxx
index 20972ef..8a50ae0 100644
--- a/sc/inc/fstalgorithm.hxx
+++ b/sc/inc/fstalgorithm.hxx
@@ -15,6 +15,35 @@
 
 namespace sc {
 
+template<typename _Key, typename _Span>
+void buildSpan(
+    std::vector<_Span>& rSpans,
+    typename mdds::flat_segment_tree<_Key,bool>::const_iterator it,
+    typename mdds::flat_segment_tree<_Key,bool>::const_iterator itEnd, const _Key* pStart )
+{
+    _Key nLastPos = it->first;
+    bool bLastVal = it->second;
+    for (++it; it != itEnd; ++it)
+    {
+        _Key nThisPos = it->first;
+        bool bThisVal = it->second;
+
+        if (bLastVal)
+        {
+            _Key nIndex1 = nLastPos;
+            _Key nIndex2 = nThisPos-1;
+
+            if (!pStart || *pStart < nIndex1)
+                rSpans.push_back(_Span(nIndex1, nIndex2));
+            else if (*pStart <= nIndex2)
+                rSpans.push_back(_Span(*pStart, nIndex2));
+        }
+
+        nLastPos = nThisPos;
+        bLastVal = bThisVal;
+    }
+}
+
 /**
  * Convert a flat_segment_tree structure whose value type is boolean, into
  * an array of ranges that corresponds with the segments that have a 'true'
@@ -28,20 +57,29 @@ std::vector<_Span> toSpanArray( const mdds::flat_segment_tree<_Key,bool>& rTree
     std::vector<_Span> aSpans;
 
     typename FstType::const_iterator it = rTree.begin(), itEnd = rTree.end();
-    _Key nLastPos = it->first;
-    bool bLastVal = it->second;
-    for (++it; it != itEnd; ++it)
-    {
-        _Key nThisPos = it->first;
-        bool bThisVal = it->second;
+    buildSpan<_Key,_Span>(aSpans, it, itEnd, NULL);
+    return aSpans;
+}
 
-        if (bLastVal)
-            aSpans.push_back(_Span(nLastPos, nThisPos-1));
+template<typename _Key, typename _Span>
+std::vector<_Span> toSpanArray( const mdds::flat_segment_tree<_Key,bool>& rTree, _Key nStartPos )
+{
+    typedef mdds::flat_segment_tree<_Key,bool> FstType;
 
-        nLastPos = nThisPos;
-        bLastVal = bThisVal;
-    }
+    std::vector<_Span> aSpans;
+    if (!rTree.is_tree_valid())
+        return aSpans;
+
+    bool bThisVal = false;
+    std::pair<typename FstType::const_iterator, bool> r =
+        rTree.search_tree(nStartPos, bThisVal);
+
+    if (!r.second)
+        // Tree search failed.
+        return aSpans;
 
+    typename FstType::const_iterator it = r.first, itEnd = rTree.end();
+    buildSpan<_Key,_Span>(aSpans, it, itEnd, &nStartPos);
     return aSpans;
 }
 
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 413152e..b29bb8d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1011,7 +1011,7 @@ private:
         ScRefCellValue& rCell2, SCCOL nCell2Col, SCROW nCell2Row ) const;
     short       Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const;
     short       Compare( ScSortInfoArray*, SCCOLROW nIndex1, SCCOLROW nIndex2) const;
-    ScSortInfoArray*    CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 );
+    ScSortInfoArray* CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2, bool bKeepQuery );
     void        QuickSort( ScSortInfoArray*, SCsCOLROW nLo, SCsCOLROW nHi);
     void        SortReorder( ScSortInfoArray*, ScProgress* );
 
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index b1a40d0..a672303 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -57,6 +57,7 @@
 #include "mtvcellfunc.hxx"
 #include "columnspanset.hxx"
 #include <stlalgorithm.hxx>
+#include <fstalgorithm.hxx>
 #include <listenercontext.hxx>
 #include <sharedformula.hxx>
 
@@ -234,8 +235,17 @@ public:
         Cell() : mpAttr(NULL), mpBroadcaster(NULL), mpNote(NULL), mpPattern(NULL) {}
     };
 
-    typedef std::vector<Cell> RowType;
-    typedef std::vector<RowType*> RowsType;
+    struct Row
+    {
+        std::vector<Cell> maCells;
+
+        bool mbHidden:1;
+        bool mbFiltered:1;
+
+        Row( size_t nColSize ) : maCells(nColSize, Cell()), mbHidden(false), mbFiltered(false) {}
+    };
+
+    typedef std::vector<Row*> RowsType;
 
 private:
     boost::scoped_ptr<RowsType> mpRows; /// row-wise data table for sort by row operation.
@@ -246,21 +256,24 @@ private:
     SCCOLROW        mnLastIndex; /// index of last non-empty cell position.
     sal_uInt16      nUsedSorts;
 
+    bool mbKeepQuery;
+
 public:
     ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
-            pppInfo( new ScSortInfo**[nSorts]),
-            nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
-            mnLastIndex(nInd2),
-            nUsedSorts( nSorts )
+        pppInfo( new ScSortInfo**[nSorts]),
+        nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
+        mnLastIndex(nInd2),
+        nUsedSorts(nSorts),
+        mbKeepQuery(false)
+    {
+        for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
         {
-            for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
-            {
-                ScSortInfo** ppInfo = new ScSortInfo* [nCount];
-                for ( SCSIZE j = 0; j < nCount; j++ )
-                    ppInfo[j] = new ScSortInfo;
-                pppInfo[nSort] = ppInfo;
-            }
+            ScSortInfo** ppInfo = new ScSortInfo* [nCount];
+            for ( SCSIZE j = 0; j < nCount; j++ )
+                ppInfo[j] = new ScSortInfo;
+            pppInfo[nSort] = ppInfo;
         }
+    }
 
     ~ScSortInfoArray()
     {
@@ -274,9 +287,13 @@ public:
         delete[] pppInfo;
 
         if (mpRows)
-            std::for_each(mpRows->begin(), mpRows->end(), ScDeleteObjectByPtr<RowType>());
+            std::for_each(mpRows->begin(), mpRows->end(), ScDeleteObjectByPtr<Row>());
     }
 
+    void SetKeepQuery( bool b ) { mbKeepQuery = b; }
+
+    bool IsKeepQuery() const { return mbKeepQuery; }
+
     ScSortInfo* Get( sal_uInt16 nSort, SCCOLROW nInd )
                     { return (pppInfo[nSort])[ nInd - nStart ]; }
 
@@ -311,7 +328,7 @@ public:
         mpRows.reset(new RowsType);
         mpRows->reserve(nRowSize);
         for (size_t i = 0; i < nRowSize; ++i)
-            mpRows->push_back(new RowType(nColSize, Cell()));
+            mpRows->push_back(new Row(nColSize));
 
         return *mpRows;
     }
@@ -322,12 +339,14 @@ public:
     }
 };
 
-ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
+ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2, bool bKeepQuery )
 {
     sal_uInt16 nUsedSorts = 1;
     while ( nUsedSorts < aSortParam.GetSortKeyCount() && aSortParam.maKeyState[nUsedSorts].bDoSort )
         nUsedSorts++;
     ScSortInfoArray* pArray = new ScSortInfoArray( nUsedSorts, nInd1, nInd2 );
+    pArray->SetKeepQuery(bKeepQuery);
+
     if ( aSortParam.bByRow )
     {
         for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
@@ -355,8 +374,8 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
             rCol.InitBlockPosition(aBlockPos);
             for (SCROW nRow = nInd1; nRow <= nInd2; ++nRow)
             {
-                ScSortInfoArray::RowType& rRow = *rRows[nRow-nInd1];
-                ScSortInfoArray::Cell& rCell = rRow[nCol-aSortParam.nCol1];
+                ScSortInfoArray::Row& rRow = *rRows[nRow-nInd1];
+                ScSortInfoArray::Cell& rCell = rRow.maCells[nCol-aSortParam.nCol1];
 
                 rCell.maCell = rCol.GetCellValue(aBlockPos, nRow);
                 rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow);
@@ -367,6 +386,16 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
                     rCell.mpPattern = rCol.GetPattern(nRow);
             }
         }
+
+        if (bKeepQuery)
+        {
+            for (SCROW nRow = nInd1; nRow <= nInd2; ++nRow)
+            {
+                ScSortInfoArray::Row& rRow = *rRows[nRow-nInd1];
+                rRow.mbHidden = RowHidden(nRow);
+                rRow.mbFiltered = RowFiltered(nRow);
+            }
+        }
     }
     else
     {
@@ -389,6 +418,7 @@ namespace {
 
 struct SortedColumn : boost::noncopyable
 {
+
     sc::CellStoreType maCells;
     sc::CellTextAttrStoreType maCellTextAttrs;
     sc::BroadcasterStoreType maBroadcasters;
@@ -401,6 +431,32 @@ struct SortedColumn : boost::noncopyable
         maCellNotes(nTopEmptyRows) {}
 };
 
+struct SortedRowFlags
+{
+    typedef mdds::flat_segment_tree<SCROW,bool> FlagsType;
+
+    FlagsType maRowsHidden;
+    FlagsType maRowsFiltered;
+    FlagsType::const_iterator miPosHidden;
+    FlagsType::const_iterator miPosFiltered;
+
+    SortedRowFlags() :
+        maRowsHidden(0, MAXROWCOUNT, false),
+        maRowsFiltered(0, MAXROWCOUNT, false),
+        miPosHidden(maRowsHidden.begin()),
+        miPosFiltered(maRowsFiltered.begin()) {}
+
+    void setRowHidden( SCROW nRow, bool b )
+    {
+        miPosHidden = maRowsHidden.insert(miPosHidden, nRow, nRow+1, b).first;
+    }
+
+    void setRowFiltered( SCROW nRow, bool b )
+    {
+        miPosFiltered = maRowsFiltered.insert(miPosFiltered, nRow, nRow+1, b).first;
+    }
+};
+
 }
 
 bool ScTable::IsSortCollatorGlobal() const
@@ -461,6 +517,7 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
 
         size_t nColCount = aSortParam.nCol2 - aSortParam.nCol1 + 1;
         boost::ptr_vector<SortedColumn> aSortedCols; // storage for copied cells.
+        SortedRowFlags aRowFlags;
         aSortedCols.reserve(nColCount);
         for (size_t i = 0; i < nColCount; ++i)
         {
@@ -472,12 +529,12 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
 
         for (size_t i = 0; i < pRows->size(); ++i)
         {
-            ScSortInfoArray::RowType* pRow = (*pRows)[i];
-            for (size_t j = 0; j < pRow->size(); ++j)
+            ScSortInfoArray::Row* pRow = (*pRows)[i];
+            for (size_t j = 0; j < pRow->maCells.size(); ++j)
             {
                 ScAddress aCellPos(aSortParam.nCol1 + j, nRow1 + i, nTab);
 
-                ScSortInfoArray::Cell& rCell = (*pRow)[j];
+                ScSortInfoArray::Cell& rCell = pRow->maCells[j];
 
                 sc::CellStoreType& rCellStore = aSortedCols.at(j).maCells;
                 switch (rCell.maCell.meType)
@@ -539,6 +596,14 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
                     aCol[aCellPos.Col()].SetPattern(aCellPos.Row(), *rCell.mpPattern, true);
             }
 
+            if (pArray->IsKeepQuery())
+            {
+                // Hidden and filtered flags are first converted to segments.
+                SCROW nRow = nRow1 + i;
+                aRowFlags.setRowHidden(nRow, pRow->mbHidden);
+                aRowFlags.setRowFiltered(nRow, pRow->mbFiltered);
+            }
+
             if (pProgress)
                 pProgress->SetStateOnPercent(i);
         }
@@ -583,6 +648,29 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
             aCol[nThisCol].CellStorageModified();
         }
 
+        if (pArray->IsKeepQuery())
+        {
+            aRowFlags.maRowsHidden.build_tree();
+            aRowFlags.maRowsFiltered.build_tree();
+
+            // Remove all flags in the range first.
+            SetRowHidden(nRow1, nRow2, false);
+            SetRowFiltered(nRow1, nRow2, false);
+
+            std::vector<sc::RowSpan> aSpans =
+                sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsHidden, nRow1);
+
+            std::vector<sc::RowSpan>::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
+            for (; it != itEnd; ++it)
+                SetRowHidden(it->mnRow1, it->mnRow2, true);
+
+            aSpans = sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsFiltered, nRow1);
+
+            it = aSpans.begin(), itEnd = aSpans.end();
+            for (; it != itEnd; ++it)
+                SetRowFiltered(it->mnRow1, it->mnRow2, true);
+        }
+
         // Attach all formula cells within sorted range, to have them start listening again.
         sc::StartListeningContext aStartListenCxt(*pDocument);
         AttachFormulaCells(
@@ -906,7 +994,7 @@ void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* p
             if(pProgress)
                 pProgress->SetState( 0, nLastRow-nRow1 );
 
-            boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(nRow1, nLastRow));
+            boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(nRow1, nLastRow, bKeepQuery));
 
             if ( nLastRow - nRow1 > 255 )
                 DecoladeRow(pArray.get(), nRow1, nLastRow);
@@ -931,7 +1019,7 @@ void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* p
             if(pProgress)
                 pProgress->SetState( 0, nLastCol-nCol1 );
 
-            boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(nCol1, nLastCol));
+            boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(nCol1, nLastCol, bKeepQuery));
 
             QuickSort(pArray.get(), nCol1, nLastCol);
             SortReorder(pArray.get(), pProgress);
@@ -1932,7 +2020,7 @@ void ScTable::TopTenQuery( ScQueryParam& rParam )
                     bSortCollatorInitialized = true;
                     InitSortCollator( aLocalSortParam );
                 }
-                ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, rParam.nRow2 );
+                ScSortInfoArray* pArray = CreateSortInfoArray(nRow1, rParam.nRow2, bGlobalKeepQuery);
                 DecoladeRow( pArray, nRow1, rParam.nRow2 );
                 QuickSort( pArray, nRow1, rParam.nRow2 );
                 ScSortInfo** ppInfo = pArray->GetFirstArray();
commit aa3e2b7ae90c0fdad28dfd097a230e8ab4cb2565
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Apr 21 21:50:44 2014 -0400

    Handle cell formats correctly during sort.
    
    Unfortunately sorting becomes noticeably slower when cell format is
    enabled.  Perhaps a future project.
    
    Change-Id: Ieb02b207b62df343d1f667a8075874b7688ee9a7

diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 88e693e..b1a40d0 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -229,8 +229,9 @@ public:
         const sc::CellTextAttr* mpAttr;
         const SvtBroadcaster* mpBroadcaster;
         const ScPostIt* mpNote;
+        const ScPatternAttr* mpPattern;
 
-        Cell() : mpAttr(NULL), mpBroadcaster(NULL), mpNote(NULL) {}
+        Cell() : mpAttr(NULL), mpBroadcaster(NULL), mpNote(NULL), mpPattern(NULL) {}
     };
 
     typedef std::vector<Cell> RowType;
@@ -361,6 +362,9 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
                 rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow);
                 rCell.mpBroadcaster = rCol.GetBroadcaster(aBlockPos, nRow);
                 rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow);
+
+                if (aSortParam.bIncludePattern)
+                    rCell.mpPattern = rCol.GetPattern(nRow);
             }
         }
     }
@@ -471,6 +475,8 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
             ScSortInfoArray::RowType* pRow = (*pRows)[i];
             for (size_t j = 0; j < pRow->size(); ++j)
             {
+                ScAddress aCellPos(aSortParam.nCol1 + j, nRow1 + i, nTab);
+
                 ScSortInfoArray::Cell& rCell = (*pRow)[j];
 
                 sc::CellStoreType& rCellStore = aSortedCols.at(j).maCells;
@@ -492,9 +498,9 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
                     {
                         assert(rCell.mpAttr);
                         size_t n = rCellStore.size();
-                        ScAddress aCellPos(aSortParam.nCol1 + j, nRow1 + i, nTab);
                         sc::CellStoreType::iterator itBlk = rCellStore.push_back(rCell.maCell.mpFormula->Clone(aCellPos));
 
+                        // Join the formula cells as we fill the container.
                         size_t nOffset = n - itBlk->position;
                         sc::CellStoreType::position_type aPos(itBlk, nOffset);
                         sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
@@ -527,6 +533,10 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
                     rNoteStore.push_back(const_cast<ScPostIt*>(rCell.mpNote));
                 else
                     rNoteStore.push_back_empty();
+
+                // Set formats to the document directly.
+                if (rCell.mpPattern)
+                    aCol[aCellPos.Col()].SetPattern(aCellPos.Row(), *rCell.mpPattern, true);
             }
 
             if (pProgress)
commit f1047b5e3bd819f76b54900b52d9ca1d2ed305a7
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Apr 21 19:10:47 2014 -0400

    Make sure to ignore trailing empty rows in all places.
    
    Otherwise it'd throw an exception.
    
    All unit tests pass now.
    
    Change-Id: I1dc49afcdf3e6604de4c0bc2440106c5ce0da090

diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 9caae2b..88e693e 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -242,22 +242,24 @@ private:
     ScSortInfo***   pppInfo;
     SCSIZE          nCount;
     SCCOLROW        nStart;
+    SCCOLROW        mnLastIndex; /// index of last non-empty cell position.
     sal_uInt16      nUsedSorts;
 
 public:
-                ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
-                        pppInfo( new ScSortInfo**[nSorts]),
-                        nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
-                        nUsedSorts( nSorts )
-                    {
-                        for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
-                        {
-                            ScSortInfo** ppInfo = new ScSortInfo* [nCount];
-                            for ( SCSIZE j = 0; j < nCount; j++ )
-                                ppInfo[j] = new ScSortInfo;
-                            pppInfo[nSort] = ppInfo;
-                        }
-                    }
+    ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
+            pppInfo( new ScSortInfo**[nSorts]),
+            nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
+            mnLastIndex(nInd2),
+            nUsedSorts( nSorts )
+        {
+            for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
+            {
+                ScSortInfo** ppInfo = new ScSortInfo* [nCount];
+                for ( SCSIZE j = 0; j < nCount; j++ )
+                    ppInfo[j] = new ScSortInfo;
+                pppInfo[nSort] = ppInfo;
+            }
+        }
 
     ~ScSortInfoArray()
     {
@@ -300,6 +302,7 @@ public:
     sal_uInt16      GetUsedSorts() const { return nUsedSorts; }
     ScSortInfo**    GetFirstArray() const { return pppInfo[0]; }
     SCCOLROW    GetStart() const { return nStart; }
+    SCCOLROW GetLast() const { return mnLastIndex; }
     SCSIZE      GetCount() const { return nCount; }
 
     RowsType& InitDataRows( size_t nRowSize, size_t nColSize )
@@ -340,7 +343,7 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
             }
         }
 
-        // Filll row-wise data table.
+        // Fill row-wise data table.
         ScSortInfoArray::RowsType& rRows = pArray->InitDataRows(
             nInd2 - nInd1 + 1, aSortParam.nCol2 - aSortParam.nCol1 + 1);
 
@@ -440,13 +443,14 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
 
     if (aSortParam.bByRow)
     {
-        SCROW nRow1 = aSortParam.nRow1 + (aSortParam.bHasHeader ? 1 : 0);
+        SCROW nRow1 = pArray->GetStart();
+        SCROW nRow2 = pArray->GetLast();
         ScSortInfoArray::RowsType* pRows = pArray->GetDataRows();
         assert(pRows); // In sort-by-row mode we must have data rows already populated.
 
         // Detach all formula cells within the sorted range first.
         sc::EndListeningContext aCxt(*pDocument);
-        DetachFormulaCells(aCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, aSortParam.nRow2);
+        DetachFormulaCells(aCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, nRow2);
 
         // Cells in the data rows only reference values in the document. Make
         // a copy before updating the document.
@@ -536,13 +540,13 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
             {
                 sc::CellStoreType& rDest = aCol[nThisCol].maCells;
                 sc::CellStoreType& rSrc = aSortedCols[i].maCells;
-                rSrc.transfer(nRow1, aSortParam.nRow2, rDest, nRow1);
+                rSrc.transfer(nRow1, nRow2, rDest, nRow1);
             }
 
             {
                 sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs;
                 sc::CellTextAttrStoreType& rSrc = aSortedCols[i].maCellTextAttrs;
-                rSrc.transfer(nRow1, aSortParam.nRow2, rDest, nRow1);
+                rSrc.transfer(nRow1, nRow2, rDest, nRow1);
             }
 
             {
@@ -550,10 +554,10 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
                 sc::BroadcasterStoreType& rDest = aCol[nThisCol].maBroadcasters;
 
                 // Release current broadcasters first, to prevent them from getting deleted.
-                rDest.release_range(nRow1, aSortParam.nRow2);
+                rDest.release_range(nRow1, nRow2);
 
                 // Transfer sorted broadcaster segment to the document.
-                rSrc.transfer(nRow1, aSortParam.nRow2, rDest, nRow1);
+                rSrc.transfer(nRow1, nRow2, rDest, nRow1);
             }
 
             {
@@ -561,9 +565,9 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
                 sc::CellNoteStoreType& rDest = aCol[nThisCol].maCellNotes;
 
                 // Do the same as broadcaster storage transfer (to prevent double deletion).
-                rDest.release_range(nRow1, aSortParam.nRow2);
-                rSrc.transfer(nRow1, aSortParam.nRow2, rDest, nRow1);
-                aCol[nThisCol].UpdateNoteCaptions(nRow1, aSortParam.nRow2);
+                rDest.release_range(nRow1, nRow2);
+                rSrc.transfer(nRow1, nRow2, rDest, nRow1);
+                aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2);
             }
 
             aCol[nThisCol].CellStorageModified();
@@ -572,7 +576,7 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
         // Attach all formula cells within sorted range, to have them start listening again.
         sc::StartListeningContext aStartListenCxt(*pDocument);
         AttachFormulaCells(
-            aStartListenCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, aSortParam.nRow2);
+            aStartListenCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, nRow2);
     }
     else
     {
commit 2e8c0c7076023573728489170e3d9d364aa6130c
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Apr 21 17:14:47 2014 -0400

    Annotate the test code a bit to make it easier to follow.
    
    Also, during unit test, the function separator is set to ';', not ','.
    
    Change-Id: I3ba948c54bee3c05715928f6f2f2945621fbacad

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 824f84a..beb1bf1 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -4599,12 +4599,12 @@ void Test::testSortWithFormulaRefs()
     m_pDoc->InsertTab(1, "List2");
 
     const char* aFormulaData[6] = {

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list