[Libreoffice-commits] core.git: Branch 'libreoffice-7-0' - sc/inc sc/qa sc/source

Serge Krot (via logerrit) logerrit at kemper.freedesktop.org
Wed Sep 9 06:49:53 UTC 2020


 sc/inc/dbdata.hxx                              |    4 
 sc/inc/document.hxx                            |    4 
 sc/qa/unit/data/ods/tdf95640.ods               |binary
 sc/qa/unit/data/ods/tdf95640_standard_list.ods |binary
 sc/qa/unit/data/xlsx/tdf95640.xlsx             |binary
 sc/qa/unit/subsequent_export-test.cxx          |   63 +++++++++++++
 sc/source/filter/excel/excrecds.cxx            |   64 +++++++++++++
 sc/source/filter/inc/autofilterbuffer.hxx      |   30 ++++++
 sc/source/filter/inc/autofiltercontext.hxx     |   39 ++++++++
 sc/source/filter/inc/excrecds.hxx              |    3 
 sc/source/filter/oox/autofilterbuffer.cxx      |  116 +++++++++++++++++++++++--
 sc/source/filter/oox/autofiltercontext.cxx     |   68 ++++++++++++++
 sc/source/filter/oox/tablebuffer.cxx           |    2 
 13 files changed, 375 insertions(+), 18 deletions(-)

New commits:
commit e6bdfaaf572b592f7e8b510cb38f82a4aca41593
Author:     Serge Krot <Serge.Krot at cib.de>
AuthorDate: Mon Jun 29 13:23:34 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Wed Sep 9 08:49:19 2020 +0200

    tdf#95640 XLSX: import/export of custom sort lists
    
    Conflicts:
            sc/source/filter/excel/excrecds.cxx
            sc/source/filter/oox/autofilterbuffer.cxx
            sc/source/filter/oox/tablebuffer.cxx
    
    Change-Id: If5ffef39770bf7abd6e75e8de998d4a2b4749a0d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97399
    Tested-by: Jenkins
    Tested-by: Serge Krot <Serge.Krot at cib.de>
    Reviewed-by: Serge Krot <Serge.Krot at cib.de>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102252
    Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>

diff --git a/sc/inc/dbdata.hxx b/sc/inc/dbdata.hxx
index 488063cd0a2b..0e31a0f02152 100644
--- a/sc/inc/dbdata.hxx
+++ b/sc/inc/dbdata.hxx
@@ -172,8 +172,8 @@ public:
     OUString GetSourceString() const;
     OUString GetOperations() const;
 
-    void        GetSortParam(ScSortParam& rSortParam) const;
-    void        SetSortParam(const ScSortParam& rSortParam);
+    SC_DLLPUBLIC void GetSortParam(ScSortParam& rSortParam) const;
+    SC_DLLPUBLIC void SetSortParam(const ScSortParam& rSortParam);
 
     /** Remember some more settings of ScSortParam, only to be called at
         anonymous DB ranges as it at least overwrites bHasHeader. */
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 15a7145b7abc..0c5ccc248faf 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -812,8 +812,8 @@ public:
                                                   bool bRemoveAutoFilter = false );
     const ScDBData*              GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const;
     ScDBData*                    GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion);
-    const ScDBData*              GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const;
-    ScDBData*                    GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
+    SC_DLLPUBLIC const ScDBData* GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const;
+    SC_DLLPUBLIC ScDBData*       GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
     void                         RefreshDirtyTableColumnNames();
     SC_DLLPUBLIC sc::ExternalDataMapper& GetExternalDataMapper();
 
diff --git a/sc/qa/unit/data/ods/tdf95640.ods b/sc/qa/unit/data/ods/tdf95640.ods
new file mode 100644
index 000000000000..5d435c61cc85
Binary files /dev/null and b/sc/qa/unit/data/ods/tdf95640.ods differ
diff --git a/sc/qa/unit/data/ods/tdf95640_standard_list.ods b/sc/qa/unit/data/ods/tdf95640_standard_list.ods
new file mode 100644
index 000000000000..37bea8a0c93e
Binary files /dev/null and b/sc/qa/unit/data/ods/tdf95640_standard_list.ods differ
diff --git a/sc/qa/unit/data/xlsx/tdf95640.xlsx b/sc/qa/unit/data/xlsx/tdf95640.xlsx
new file mode 100644
index 000000000000..78c2d32c2cf6
Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf95640.xlsx differ
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index d74d4d63d0ec..2f0a7c7fdd0e 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -205,6 +205,12 @@ public:
     void testTdf129985();
     void testTdf73063();
 
+    xmlDocUniquePtr testTdf95640(const OUString& rFileName, sal_Int32 nSourceFormat,
+                                 sal_Int32 nDestFormat);
+    void testTdf95640_ods_to_xlsx();
+    void testTdf95640_ods_to_xlsx_with_standard_list();
+    void testTdf95640_xlsx_to_xlsx();
+
     void testRefStringXLSX();
     void testRefStringConfigXLSX();
     void testRefStringUnspecified();
@@ -352,6 +358,9 @@ public:
     CPPUNIT_TEST(testTdf55417);
     CPPUNIT_TEST(testTdf129985);
     CPPUNIT_TEST(testTdf73063);
+    CPPUNIT_TEST(testTdf95640_ods_to_xlsx);
+    CPPUNIT_TEST(testTdf95640_ods_to_xlsx_with_standard_list);
+    CPPUNIT_TEST(testTdf95640_xlsx_to_xlsx);
 
     CPPUNIT_TEST(testRefStringXLSX);
     CPPUNIT_TEST(testRefStringConfigXLSX);
@@ -4269,6 +4278,60 @@ void ScExportTest::testTdf73063()
     xDocSh->DoClose();
 }
 
+xmlDocUniquePtr ScExportTest::testTdf95640(const OUString& rFileName, sal_Int32 nSourceFormat,
+                                           sal_Int32 nDestFormat)
+{
+    ScDocShellRef xShell = loadDoc(rFileName, nSourceFormat);
+    CPPUNIT_ASSERT(xShell);
+
+    auto pXPathFile = ScBootstrapFixture::exportTo(&(*xShell), nDestFormat);
+    xShell->DoClose();
+
+    return XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/worksheets/sheet1.xml");
+}
+
+void ScExportTest::testTdf95640_ods_to_xlsx()
+{
+    // Roundtripping sort options with user defined list to XLSX
+    xmlDocUniquePtr pDoc = testTdf95640("tdf95640.", FORMAT_ODS, FORMAT_XLSX);
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter", "ref", "A1:B4");
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter/x:sortState/x:sortCondition", "ref", "A2:A4");
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter/x:sortState/x:sortCondition", "customList",
+                "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec");
+}
+
+void ScExportTest::testTdf95640_ods_to_xlsx_with_standard_list()
+{
+    // Roundtripping sort options with user defined list to XLSX
+    xmlDocUniquePtr pDoc = testTdf95640("tdf95640_standard_list.", FORMAT_ODS, FORMAT_XLSX);
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter", "ref", "A1:B4");
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter/x:sortState/x:sortCondition", "ref", "A2:A4");
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter/x:sortState/x:sortCondition", "customList",
+                "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday");
+}
+
+void ScExportTest::testTdf95640_xlsx_to_xlsx()
+{
+    // XLSX Roundtripping sort options with custom sort list - note
+    // that compared to ODS source documents above, here we _actually_
+    // can use custom lists (beyond the global user defines), like
+    // low, medium, high
+    xmlDocUniquePtr pDoc = testTdf95640("tdf95640.", FORMAT_XLSX, FORMAT_XLSX);
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter", "ref", "A1:B4");
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter/x:sortState/x:sortCondition", "ref", "A2:A4");
+
+    assertXPath(pDoc, "//x:worksheet/x:autoFilter/x:sortState/x:sortCondition", "customList",
+                "Low,Medium,High");
+}
+
 void ScExportTest::testTdf88657ODS()
 {
     ScDocShellRef xDocSh = loadDoc("tdf88657.", FORMAT_ODS);
diff --git a/sc/source/filter/excel/excrecds.cxx b/sc/source/filter/excel/excrecds.cxx
index 494bedaf6b03..b82910908c7c 100644
--- a/sc/source/filter/excel/excrecds.cxx
+++ b/sc/source/filter/excel/excrecds.cxx
@@ -34,6 +34,8 @@
 #include <oox/token/tokens.hxx>
 #include <queryentry.hxx>
 #include <queryparam.hxx>
+#include <sortparam.hxx>
+#include <userlist.hxx>
 #include <root.hxx>
 
 #include <xeescher.hxx>
@@ -927,6 +929,45 @@ ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab, const
 
             if (maFilterList.IsEmpty () && !bConflict)
                 mbAutoFilter = true;
+
+            // get sort criteria
+            {
+                ScSortParam aSortParam;
+                pData->GetSortParam( aSortParam );
+
+                if (aSortParam.bUserDef)
+                {
+                    // get sorted area without headers
+                    maSortRef = ScRange(
+                        aParam.nCol1, aParam.nRow1 + (aSortParam.bHasHeader? 1 : 0), aParam.nTab,
+                        aParam.nCol2, aParam.nRow2, aParam.nTab );
+
+                    // get sorted columns with custom lists
+                    ScUserList* pList = ScGlobal::GetUserList();
+                    const ScUserListData& rData = (*pList)[aSortParam.nUserIndex];
+
+                    // get column index and sorting direction
+                    SCCOLROW nField = 0;
+                    bool bSortAscending=true;
+                    for (const auto & rKey : aSortParam.maKeyState)
+                    {
+                        if (rKey.bDoSort)
+                        {
+                            nField = rKey.nField;
+                            bSortAscending = rKey.bAscending;
+                            break;
+                        }
+                    }
+
+                    // remember sort criteria
+                    const ScRange aSortedColumn(
+                        nField, aParam.nRow1 + (aSortParam.bHasHeader? 1 : 0), aParam.nTab,
+                        nField, aParam.nRow2, aParam.nTab );
+                    const OUString aItemList = rData.GetString();
+
+                    maSortCustomList.emplace_back(aSortedColumn, aItemList, !bSortAscending);
+                }
+            }
         }
     }
 }
@@ -990,6 +1031,29 @@ void ExcAutoFilterRecs::SaveXml( XclExpXmlStream& rStrm )
     // OOXTODO: XML_extLst, XML_sortState
     if( !maFilterList.IsEmpty() )
         maFilterList.SaveXml( rStrm );
+
+    if (!maSortCustomList.empty())
+    {
+        rWorksheet->startElement(XML_sortState, XML_ref, XclXmlUtils::ToOString(rStrm.GetRoot().GetDoc(), maSortRef));
+
+        for (const auto & rSortCriteria : maSortCustomList)
+        {
+            if (std::get<2>(rSortCriteria))
+                rWorksheet->singleElement(XML_sortCondition,
+                                          XML_ref, XclXmlUtils::ToOString(rStrm.GetRoot().GetDoc(),
+                                                                          std::get<0>(rSortCriteria)),
+                                          XML_descending, "1",
+                                          XML_customList, std::get<1>(rSortCriteria).toUtf8().getStr());
+            else
+                rWorksheet->singleElement(XML_sortCondition,
+                                          XML_ref, XclXmlUtils::ToOString(rStrm.GetRoot().GetDoc(),
+                                                                          std::get<0>(rSortCriteria)),
+                                          XML_customList, std::get<1>(rSortCriteria).toUtf8().getStr());
+        }
+
+        rWorksheet->endElement(XML_sortState);
+    }
+
     rWorksheet->endElement( XML_autoFilter );
 }
 
diff --git a/sc/source/filter/inc/autofilterbuffer.hxx b/sc/source/filter/inc/autofilterbuffer.hxx
index cbf1efef2fed..469aacdce399 100644
--- a/sc/source/filter/inc/autofilterbuffer.hxx
+++ b/sc/source/filter/inc/autofilterbuffer.hxx
@@ -184,6 +184,22 @@ private:
     bool                mbShowButton;
 };
 
+// class SortCondition
+
+class SortCondition : public WorkbookHelper
+{
+public:
+    explicit SortCondition( const WorkbookHelper& rHelper );
+
+    void importSortCondition( const AttributeList& rAttribs, sal_Int16 nSheet );
+
+    ScRange maRange; // Column/Row that this sort condition applies to.
+    OUString maSortCustomList; // Sort by a custom list.
+    bool mbDescending;
+};
+
+// class AutoFilter
+
 class AutoFilter : public WorkbookHelper
 {
 public:
@@ -194,17 +210,26 @@ public:
     /** Imports auto filter settings from the AUTOFILTER record. */
     void                importAutoFilter( SequenceInputStream& rStrm, sal_Int16 nSheet );
 
+    void                importSortState( const AttributeList& rAttribs, sal_Int16 nSheet );
+
     /** Creates a new auto filter column and stores it internally. */
     FilterColumn&       createFilterColumn();
 
+    SortCondition&      createSortCondition();
+
     /** Applies the filter to the passed filter descriptor. */
-    void                finalizeImport( const css::uno::Reference< css::sheet::XSheetFilterDescriptor3>& rxFilterDesc );
+    void                finalizeImport( const css::uno::Reference< css::sheet::XDatabaseRange >& rxDatabaseRange,
+                                        sal_Int16 nSheet );
 
 private:
     typedef RefVector< FilterColumn > FilterColumnVector;
 
     FilterColumnVector  maFilterColumns;
     ScRange             maRange;
+
+    ScRange maSortRange; // The whole range of data to sort (not just the sort-by column).
+    typedef RefVector< SortCondition > SortConditionVector;
+    SortConditionVector maSortConditions;
 };
 
 class AutoFilterBuffer : public WorkbookHelper
@@ -221,7 +246,8 @@ public:
 
     /** Applies the filters to the passed database range object.
         @return  True = this buffer contains valid auto filter settings. */
-    bool                finalizeImport( const css::uno::Reference< css::sheet::XDatabaseRange >& rxDatabaseRange );
+    bool                finalizeImport( const css::uno::Reference< css::sheet::XDatabaseRange >& rxDatabaseRange,
+                                        sal_Int16 nSheet );
 
 private:
     /** Returns the auto filter object used to perform auto filtering. */
diff --git a/sc/source/filter/inc/autofiltercontext.hxx b/sc/source/filter/inc/autofiltercontext.hxx
index 9a58a8a998e0..ef7bb539c3e7 100644
--- a/sc/source/filter/inc/autofiltercontext.hxx
+++ b/sc/source/filter/inc/autofiltercontext.hxx
@@ -21,6 +21,7 @@
 #define INCLUDED_SC_SOURCE_FILTER_INC_AUTOFILTERCONTEXT_HXX
 
 #include "excelhandlers.hxx"
+#include "autofilterbuffer.hxx"
 
 namespace oox {
 namespace xls {
@@ -61,6 +62,44 @@ private:
     FilterColumn&       mrFilterColumn;
 };
 
+// class SortConditionContext
+
+class SortConditionContext : public WorksheetContextBase
+{
+public:
+    explicit            SortConditionContext( WorksheetContextBase& rFragment, SortCondition& rSortCondition );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) override;
+    virtual void        onStartElement( const AttributeList& rAttribs ) override;
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) override;
+    virtual void        onStartRecord( SequenceInputStream& rStrm ) override;
+
+private:
+    SortCondition&      mrSortCondition;
+};
+
+// class SortStateContext
+
+class SortStateContext : public WorksheetContextBase
+{
+public:
+    explicit            SortStateContext( WorksheetContextBase& rFragment, AutoFilter& rAutoFilter );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) override;
+    virtual void        onStartElement( const AttributeList& rAttribs ) override;
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) override;
+    virtual void        onStartRecord( SequenceInputStream& rStrm ) override;
+
+private:
+    AutoFilter&         mrAutoFilter;
+};
+
+// class AutoFilterContext
+
 class AutoFilterContext : public WorksheetContextBase
 {
 public:
diff --git a/sc/source/filter/inc/excrecds.hxx b/sc/source/filter/inc/excrecds.hxx
index 147808e4e758..20c9425822f1 100644
--- a/sc/source/filter/inc/excrecds.hxx
+++ b/sc/source/filter/inc/excrecds.hxx
@@ -417,6 +417,9 @@ private:
     rtl::Reference<XclExpAutofilterinfo> m_pFilterInfo;
     ScRange                 maRef;
     bool mbAutoFilter;
+
+    ScRange maSortRef; // sort area without headers
+    std::vector< std::tuple<ScRange, OUString, bool> > maSortCustomList; // sorted column with list of sorted items
 };
 
 /** Sheet filter manager. Contains auto filters or advanced filters from all sheets. */
diff --git a/sc/source/filter/oox/autofilterbuffer.cxx b/sc/source/filter/oox/autofilterbuffer.cxx
index 8e77d935d9a2..35f38e0a6974 100644
--- a/sc/source/filter/oox/autofilterbuffer.cxx
+++ b/sc/source/filter/oox/autofilterbuffer.cxx
@@ -39,6 +39,10 @@
 #include <addressconverter.hxx>
 #include <defnamesbuffer.hxx>
 #include <biffhelper.hxx>
+#include <document.hxx>
+#include <dbdata.hxx>
+#include <sortparam.hxx>
+#include <userlist.hxx>
 
 namespace oox::xls {
 
@@ -529,6 +533,25 @@ ApiFilterSettings FilterColumn::finalizeImport( sal_Int32 nMaxCount )
     return aSettings;
 }
 
+// SortCondition
+
+SortCondition::SortCondition( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper ),
+    mbDescending( false )
+{
+}
+
+void SortCondition::importSortCondition( const AttributeList& rAttribs, sal_Int16 nSheet )
+{
+    OUString aRangeStr = rAttribs.getString( XML_ref, OUString() );
+    AddressConverter::convertToCellRangeUnchecked( maRange, aRangeStr, nSheet );
+
+    maSortCustomList = rAttribs.getString( XML_customList, OUString() );
+    mbDescending = rAttribs.getBool( XML_descending, false );
+}
+
+// AutoFilter
+
 AutoFilter::AutoFilter( const WorkbookHelper& rHelper ) :
     WorkbookHelper( rHelper )
 {
@@ -547,6 +570,12 @@ void AutoFilter::importAutoFilter( SequenceInputStream& rStrm, sal_Int16 nSheet
     AddressConverter::convertToCellRangeUnchecked( maRange, aBinRange, nSheet );
 }
 
+void AutoFilter::importSortState( const AttributeList& rAttribs, sal_Int16 nSheet )
+{
+    OUString aRangeStr = rAttribs.getString( XML_ref, OUString() );
+    AddressConverter::convertToCellRangeUnchecked( maSortRange, aRangeStr, nSheet );
+}
+
 FilterColumn& AutoFilter::createFilterColumn()
 {
     FilterColumnVector::value_type xFilterColumn = std::make_shared<FilterColumn>( *this );
@@ -554,12 +583,21 @@ FilterColumn& AutoFilter::createFilterColumn()
     return *xFilterColumn;
 }
 
-void AutoFilter::finalizeImport( const Reference<XSheetFilterDescriptor3>& rxFilterDesc )
+SortCondition& AutoFilter::createSortCondition()
 {
-    if( rxFilterDesc.is() )
+    SortConditionVector::value_type xSortCondition = std::make_shared<SortCondition>( *this );
+    maSortConditions.push_back( xSortCondition );
+    return *xSortCondition;
+}
+
+void AutoFilter::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRange, sal_Int16 nSheet )
+{
+    // convert filter settings using the filter descriptor of the database range
+    const Reference<XSheetFilterDescriptor3> xFilterDesc( rxDatabaseRange->getFilterDescriptor(), UNO_QUERY_THROW );
+    if( xFilterDesc.is() )
     {
         // set some common properties for the auto filter range
-        PropertySet aDescProps( rxFilterDesc );
+        PropertySet aDescProps( xFilterDesc );
         aDescProps.setProperty( PROP_IsCaseSensitive, false );
         aDescProps.setProperty( PROP_SkipDuplicates, false );
         aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
@@ -630,11 +668,71 @@ void AutoFilter::finalizeImport( const Reference<XSheetFilterDescriptor3>& rxFil
 
         // insert all filter fields to the filter descriptor
         if( !aFilterFields.empty() )
-            rxFilterDesc->setFilterFields3( ContainerHelper::vectorToSequence( aFilterFields ) );
+            xFilterDesc->setFilterFields3( ContainerHelper::vectorToSequence( aFilterFields ) );
 
         // regular expressions
         bool bUseRegExp = obNeedsRegExp.get( false );
         aDescProps.setProperty( PROP_UseRegularExpressions, bUseRegExp );
+
+        // sort
+        if (!maSortConditions.empty())
+        {
+            const SortConditionVector::value_type& xSortConditionPointer = *maSortConditions.begin();
+            const SortCondition& rSorConditionLoaded = *xSortConditionPointer;
+
+            ScSortParam aParam;
+            aParam.bUserDef = false;
+            aParam.nUserIndex = 0;
+            aParam.bByRow = false;
+
+            ScUserList* pUserList = ScGlobal::GetUserList();
+            if (!rSorConditionLoaded.maSortCustomList.isEmpty())
+            {
+                for (size_t i=0; pUserList && i < pUserList->size(); i++)
+                {
+                    const OUString aEntry((*pUserList)[i].GetString());
+                    if (aEntry.equalsIgnoreAsciiCase(rSorConditionLoaded.maSortCustomList))
+                    {
+                        aParam.bUserDef = true;
+                        aParam.nUserIndex = i;
+                        break;
+                    }
+                }
+            }
+
+            if (!aParam.bUserDef)
+            {
+                pUserList->push_back(new ScUserListData(rSorConditionLoaded.maSortCustomList));
+                aParam.bUserDef = true;
+                aParam.nUserIndex = pUserList->size()-1;
+            }
+
+            // set sort parameter if we have detected it
+            if (aParam.bUserDef)
+            {
+                SCCOLROW nStartPos = aParam.bByRow ? maRange.aStart.Col() : maRange.aStart.Row();
+                if (rSorConditionLoaded.mbDescending)
+                {
+                    // descending sort - need to enable 1st SortParam slot
+                    assert(aParam.GetSortKeyCount() == DEFSORT);
+
+                    aParam.maKeyState[0].bDoSort = true;
+                    aParam.maKeyState[0].bAscending = false;
+                    aParam.maKeyState[0].nField += nStartPos;
+                }
+
+                ScDocument& rDoc = getScDocument();
+                ScDBData* pDBData = rDoc.GetDBAtArea(
+                    nSheet,
+                    maRange.aStart.Col(), maRange.aStart.Row(),
+                    maRange.aEnd.Col(), maRange.aEnd.Row());
+
+                if (pDBData)
+                    pDBData->SetSortParam(aParam);
+                else
+                    OSL_FAIL("AutoFilter::finalizeImport(): cannot find matching DBData");
+            }
+        }
     }
 }
 
@@ -661,7 +759,7 @@ void AutoFilterBuffer::finalizeImport( sal_Int16 nSheet )
             // use the same name for the database range as used for the defined name '_FilterDatabase'
             Reference< XDatabaseRange > xDatabaseRange = createUnnamedDatabaseRangeObject( aFilterRange );
             // first, try to create an auto filter
-            bool bHasAutoFilter = finalizeImport( xDatabaseRange );
+            bool bHasAutoFilter = finalizeImport( xDatabaseRange, nSheet );
             // no success: try to create an advanced filter
             if( !bHasAutoFilter && xDatabaseRange.is() )
             {
@@ -708,7 +806,7 @@ void AutoFilterBuffer::finalizeImport( sal_Int16 nSheet )
     }
 }
 
-bool AutoFilterBuffer::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRange )
+bool AutoFilterBuffer::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRange, sal_Int16 nSheet )
 {
     AutoFilter* pAutoFilter = getActiveAutoFilter();
     if( pAutoFilter && rxDatabaseRange.is() ) try
@@ -716,9 +814,9 @@ bool AutoFilterBuffer::finalizeImport( const Reference< XDatabaseRange >& rxData
         // the property 'AutoFilter' enables the drop-down buttons
         PropertySet aRangeProps( rxDatabaseRange );
         aRangeProps.setProperty( PROP_AutoFilter, true );
-        // convert filter settings using the filter descriptor of the database range
-        Reference< XSheetFilterDescriptor3 > xFilterDesc( rxDatabaseRange->getFilterDescriptor(), UNO_QUERY_THROW );
-        pAutoFilter->finalizeImport( xFilterDesc );
+
+        pAutoFilter->finalizeImport( rxDatabaseRange, nSheet );
+
         // return true to indicate enabled autofilter
         return true;
     }
diff --git a/sc/source/filter/oox/autofiltercontext.cxx b/sc/source/filter/oox/autofiltercontext.cxx
index 1e943e3c0206..3a1260198fcd 100644
--- a/sc/source/filter/oox/autofiltercontext.cxx
+++ b/sc/source/filter/oox/autofiltercontext.cxx
@@ -115,6 +115,65 @@ void FilterColumnContext::onStartRecord( SequenceInputStream& rStrm )
     mrFilterColumn.importFilterColumn( rStrm );
 }
 
+// class SortConditionContext
+
+SortConditionContext::SortConditionContext( WorksheetContextBase& rParent, SortCondition& rSortCondition ) :
+    WorksheetContextBase( rParent ),
+    mrSortCondition( rSortCondition )
+{
+}
+
+ContextHandlerRef SortConditionContext::onCreateContext( sal_Int32 , const AttributeList& )
+{
+    return nullptr;
+}
+
+void SortConditionContext::onStartElement( const AttributeList& rAttribs )
+{
+    mrSortCondition.importSortCondition( rAttribs, getSheetIndex() );
+}
+
+ContextHandlerRef SortConditionContext::onCreateRecordContext( sal_Int32 , SequenceInputStream& )
+{
+    return nullptr;
+}
+
+void SortConditionContext::onStartRecord( SequenceInputStream& )
+{
+}
+
+// class SortStateContext
+
+SortStateContext::SortStateContext( WorksheetContextBase& rParent, AutoFilter& rAutoFilter ) :
+    WorksheetContextBase( rParent ),
+    mrAutoFilter( rAutoFilter )
+{
+}
+
+ContextHandlerRef SortStateContext::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
+{
+    if( getCurrentElement() == XLS_TOKEN( sortState ) ) switch( nElement )
+    {
+        case XLS_TOKEN( sortCondition ):
+            return new SortConditionContext( *this, mrAutoFilter.createSortCondition() );
+    }
+    return nullptr;
+}
+
+void SortStateContext::onStartElement( const AttributeList& rAttribs )
+{
+    mrAutoFilter.importSortState( rAttribs, getSheetIndex() );
+}
+
+ContextHandlerRef SortStateContext::onCreateRecordContext( sal_Int32 , SequenceInputStream& )
+{
+    return nullptr;
+}
+
+void SortStateContext::onStartRecord( SequenceInputStream& )
+{
+}
+
 AutoFilterContext::AutoFilterContext( WorksheetFragmentBase& rFragment, AutoFilter& rAutoFilter ) :
     WorksheetContextBase( rFragment ),
     mrAutoFilter( rAutoFilter )
@@ -123,8 +182,13 @@ AutoFilterContext::AutoFilterContext( WorksheetFragmentBase& rFragment, AutoFilt
 
 ContextHandlerRef AutoFilterContext::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
 {
-    if( (getCurrentElement() == XLS_TOKEN( autoFilter )) && (nElement == XLS_TOKEN( filterColumn )) )
-        return new FilterColumnContext( *this, mrAutoFilter.createFilterColumn() );
+    if( getCurrentElement() == XLS_TOKEN( autoFilter ) ) switch( nElement )
+    {
+        case XLS_TOKEN( sortState ):
+            return new SortStateContext( *this, mrAutoFilter );
+        case XLS_TOKEN( filterColumn ):
+            return new FilterColumnContext( *this, mrAutoFilter.createFilterColumn() );
+    }
     return nullptr;
 }
 
diff --git a/sc/source/filter/oox/tablebuffer.cxx b/sc/source/filter/oox/tablebuffer.cxx
index b0cf1b879409..8dea2fa6ed1c 100644
--- a/sc/source/filter/oox/tablebuffer.cxx
+++ b/sc/source/filter/oox/tablebuffer.cxx
@@ -136,7 +136,7 @@ void Table::applyAutoFilters()
             PropertySet aDocProps( getDocument() );
             Reference< XDatabaseRanges > xDatabaseRanges( aDocProps.getAnyProperty( PROP_DatabaseRanges ), UNO_QUERY_THROW );
             Reference< XDatabaseRange > xDatabaseRange( xDatabaseRanges->getByName( maDBRangeName ), UNO_QUERY );
-            maAutoFilters.finalizeImport( xDatabaseRange );
+            maAutoFilters.finalizeImport( xDatabaseRange, maModel.maRange.aStart.Tab() );
         }
         catch( Exception& )
         {


More information about the Libreoffice-commits mailing list