From a86ddd7fc0413f65ee7851eb09b15a24e5d457ba Mon Sep 17 00:00:00 2001 From: Serge Krot Date: Mon, 29 Jun 2020 13:23:34 +0200 Subject: 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 Reviewed-by: Serge Krot Reviewed-by: Thorsten Behrens Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102254 Reviewed-by: Samuel Mehrbrodt --- sc/inc/dbdata.hxx | 4 +- sc/inc/document.hxx | 4 +- sc/qa/unit/data/ods/tdf95640.ods | Bin 0 -> 8406 bytes sc/qa/unit/data/ods/tdf95640_standard_list.ods | Bin 0 -> 9684 bytes sc/qa/unit/data/xlsx/tdf95640.xlsx | Bin 0 -> 8500 bytes 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(-) create mode 100644 sc/qa/unit/data/ods/tdf95640.ods create mode 100644 sc/qa/unit/data/ods/tdf95640_standard_list.ods create mode 100644 sc/qa/unit/data/xlsx/tdf95640.xlsx diff --git a/sc/inc/dbdata.hxx b/sc/inc/dbdata.hxx index a7dc35c3b61b..24eaa3be7d18 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 15fdc5074357..63009443b919 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -805,8 +805,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 e220803967cb..b7b41d40addb 100644 --- a/sc/qa/unit/subsequent_export-test.cxx +++ b/sc/qa/unit/subsequent_export-test.cxx @@ -195,6 +195,12 @@ public: void testPreserveTextWhitespace2XLSX(); void testTextDirectionXLSX(); + xmlDocPtr 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(); @@ -326,6 +332,9 @@ public: CPPUNIT_TEST(testMoveCellAnchoredShapesODS); CPPUNIT_TEST(testMatrixMultiplicationXLSX); CPPUNIT_TEST(testTextDirectionXLSX); + 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); @@ -3954,6 +3963,60 @@ void ScExportTest::testTextDirectionXLSX() assertXPath(pDoc, "/x:styleSheet/x:cellXfs/x:xf[3]/x:alignment", "readingOrder", "2");//RTL } +xmlDocPtr 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 + xmlDocPtr 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 + xmlDocPtr 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 + xmlDocPtr 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 4fbe955d8b52..d7ab5d7d95af 100644 --- a/sc/source/filter/excel/excrecds.cxx +++ b/sc/source/filter/excel/excrecds.cxx @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -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 c6387e5d37d4..ae8e8b4fa2a0 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 74a21cbfa563..a0abbf9410cd 100644 --- a/sc/source/filter/inc/excrecds.hxx +++ b/sc/source/filter/inc/excrecds.hxx @@ -417,6 +417,9 @@ private: std::unique_ptr m_pFilterInfo; ScRange maRef; bool mbAutoFilter; + + ScRange maSortRef; // sort area without headers + std::vector< std::tuple > 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 9e53200092ce..8209df526283 100644 --- a/sc/source/filter/oox/autofilterbuffer.cxx +++ b/sc/source/filter/oox/autofilterbuffer.cxx @@ -39,6 +39,10 @@ #include #include #include +#include +#include +#include +#include namespace oox { namespace xls { @@ -530,6 +534,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 ) { @@ -548,6 +571,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( new FilterColumn( *this ) ); @@ -555,12 +584,21 @@ FilterColumn& AutoFilter::createFilterColumn() return *xFilterColumn; } -void AutoFilter::finalizeImport( const Reference& rxFilterDesc ) +SortCondition& AutoFilter::createSortCondition() { - if( rxFilterDesc.is() ) + SortConditionVector::value_type xSortCondition = std::make_shared( *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 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 ); @@ -631,11 +669,71 @@ void AutoFilter::finalizeImport( const Reference& 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"); + } + } } } @@ -662,7 +760,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() ) { @@ -709,7 +807,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 @@ -717,9 +815,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 1ec7b7138b72..814569e0b45f 100644 --- a/sc/source/filter/oox/autofiltercontext.cxx +++ b/sc/source/filter/oox/autofiltercontext.cxx @@ -116,6 +116,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 ) @@ -124,8 +183,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 8c8526ce9a57..928870276276 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& ) { -- cgit