diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index aecf9a5bd4ae..6c1eff448930 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -507,6 +507,7 @@ namespace xmloff::token { XML_CONSOLIDATION, XML_CONSTANT, XML_CONTAINS_ERROR, + XML_CONTAINS_FOOTER, XML_CONTAINS_HEADER, XML_CONTENT, XML_CONTENT_VALIDATION, diff --git a/sc/CppunitTest_sc_subsequent_filters_test5.mk b/sc/CppunitTest_sc_subsequent_filters_test5.mk new file mode 100644 index 000000000000..2bf8e2e5f998 --- /dev/null +++ b/sc/CppunitTest_sc_subsequent_filters_test5.mk @@ -0,0 +1,12 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call sc_subsequent_test,filters_test5)) + +# vim: set noet sw=4 ts=4: diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk index ab9dada68aa7..ee4f23eeab0a 100644 --- a/sc/Module_sc.mk +++ b/sc/Module_sc.mk @@ -92,6 +92,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sc, \ CppunitTest_sc_subsequent_filters_test2 \ CppunitTest_sc_subsequent_filters_test3 \ CppunitTest_sc_subsequent_filters_test4 \ + CppunitTest_sc_subsequent_filters_test5 \ CppunitTest_sc_subsequent_export_test \ CppunitTest_sc_subsequent_export_test2 \ CppunitTest_sc_subsequent_export_test3 \ diff --git a/sc/inc/queryparam.hxx b/sc/inc/queryparam.hxx index dc38638075af..5b27bce3bf77 100644 --- a/sc/inc/queryparam.hxx +++ b/sc/inc/queryparam.hxx @@ -42,6 +42,7 @@ struct SAL_DLLPUBLIC_RTTI ScQueryParamBase { utl::SearchParam::SearchType eSearchType; bool bHasHeader; + bool bHasTotals; bool bByRow; bool bInplace; bool bCaseSens; @@ -88,6 +89,7 @@ inline std::basic_ostream & operator <<(std::basic_ostream + + + + LODev_daily_installed/25.2.0.0.alpha0$Windows_X86_64 LibreOffice_project/976567aee323afd09629b6adf13537908f43d2a8 + + 5mm Grid + Regina Henschel + 2024-07-29T22:39:46 + Regina Henschel + 2024-09-18T20:23:43 + 16.0300 + + + + + 0 + 0 + 4198 + 8731 + + + view1 + + + 3 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 100 + 60 + true + false + false + false + false + + + Vertical + 1666 + 0 + 100 + 60 + false + true + true + true + false + true + -1 + 1 + true + true + true + false + false + false + 500 + 500 + 4 + 4 + true + false + false + false + false + + + + + true + true + true + true + false + true + -1 + false + true + 3 + true + true + true + true + false + false + 500 + 500 + 4 + 4 + true + true + true + 0 + false + true + 0 + false + true + true + false + false + false + false + true + 2 + + + Sheet1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + . + + + + + + + . + + + + + + + + + + : + + + + + + + : + + : + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + + + + - + + + + + + + + - € + + + + + + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + : + + + + + : + + : + + + + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ??? + + + + + Page 1 + + + + + + + + ???(???) + + + 00.00.0000, 00:00:00 + + + + + + Page 1/ 99 + + + + + + + ??? + + + + + Page 1 + + + + + + + + + + + + + + + + + + + + Name + + + Sales + + + + + + Alice + + + 21 + + + + + + Bärbel + + + 23 + + + + + + Barbie + + + 9 + + + + + + Inés + + + 34 + + + + + + Inge + + + 23 + + + + + + John + + + 12 + + + + + + Judy + + + 15 + + + + + + Mary + + + 17 + + + + + + Tom + + + 31 + + + + + + + 185 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sc/qa/unit/data/xlsx/tdf162963_TableWithTotalsEnabled.xlsx b/sc/qa/unit/data/xlsx/tdf162963_TableWithTotalsEnabled.xlsx new file mode 100644 index 000000000000..7411f05e8dea Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf162963_TableWithTotalsEnabled.xlsx differ diff --git a/sc/qa/unit/subsequent_filters_test5.cxx b/sc/qa/unit/subsequent_filters_test5.cxx new file mode 100644 index 000000000000..f22b2ff82c83 --- /dev/null +++ b/sc/qa/unit/subsequent_filters_test5.cxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +// core, please keep it alphabetically ordered +#include +#include "helper/qahelper.hxx" +#include +#include +#include + +// API, please keep it alphabetically ordered +#include +#include +#include +#include + +using namespace css; +using namespace css::uno; + +/* Implementation of Filters test, volume 5*/ + +class ScFiltersTest5 : public ScModelTestBase +{ +public: + ScFiltersTest5() + : ScModelTestBase(u"sc/qa/unit/data"_ustr) + { + } +}; + +CPPUNIT_TEST_FIXTURE(ScFiltersTest5, testTdf162963) +{ + //tests xlsx -> ods -> ods of property "TotalsRow" + createScDoc("xlsx/tdf162963_TableWithTotalsEnabled.xlsx"); + + constexpr OUString sDBName(u"myData"_ustr); + constexpr OUString sPropName(u"TotalsRow"_ustr); + + // Make sure the database range "myData" has TotalsRow TRUE after import from xlsx. + { + uno::Reference xDoc(mxComponent, UNO_QUERY_THROW); + uno::Reference xDocPropSet(xDoc, UNO_QUERY_THROW); + uno::Reference xNameAccess( + xDocPropSet->getPropertyValue(u"DatabaseRanges"_ustr), UNO_QUERY_THROW); + uno::Reference xDBRangePropSet(xNameAccess->getByName(sDBName), + UNO_QUERY_THROW); + bool bTotalsRow = false; + xDBRangePropSet->getPropertyValue(sPropName) >>= bTotalsRow; + CPPUNIT_ASSERT_MESSAGE("xlsx-import", bTotalsRow); + } + // Make sure TotalsRow is still TRUE after save to ods and reload. + // The error was, that the property "TotalsRow" was not written to ods at all. + // With fix it is written as calcext:contains-footer. + { + saveAndReload(u"calc8"_ustr); + uno::Reference xDoc(mxComponent, UNO_QUERY_THROW); + uno::Reference xDocPropSet(xDoc, UNO_QUERY_THROW); + uno::Reference xNameAccess( + xDocPropSet->getPropertyValue(u"DatabaseRanges"_ustr), UNO_QUERY_THROW); + uno::Reference xDBRangePropSet(xNameAccess->getByName(sDBName), + UNO_QUERY_THROW); + bool bTotalsRow = true; + xDBRangePropSet->getPropertyValue(sPropName) >>= bTotalsRow; + CPPUNIT_ASSERT_MESSAGE("save ods, reload", bTotalsRow); + } +} + +CPPUNIT_TEST_FIXTURE(ScFiltersTest5, testTdf162963_ODF) +{ + // Verify, that calcext:contains-footer is only written in extended file format versions. + // The parameter in DefaultVersion::set need to be adapted, when attribute contains-footer + // is included in ODF strict, see issue OFFICE-4169 at OASIS. + createScDoc("fods/tdf162963_DatabaseRange.fods"); + + // enable TotalsRow + uno::Reference xDoc(mxComponent, UNO_QUERY_THROW); + uno::Reference xDocPropSet(xDoc, UNO_QUERY_THROW); + uno::Reference xNameAccess( + xDocPropSet->getPropertyValue(u"DatabaseRanges"_ustr), UNO_QUERY_THROW); + uno::Reference xDBRangePropSet(xNameAccess->getByName(u"myData"_ustr), + UNO_QUERY_THROW); + xDBRangePropSet->setPropertyValue(u"TotalsRow"_ustr, uno::Any(true)); + + // Backup original ODF default version + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion(GetODFDefaultVersion()); + + // Save to ODF 1.3 strict. Make sure attribute is not written. + // Adapt to ODF 1.4 strict, when it is available. + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_013); + save(u"calc8"_ustr); // this saves to .ods not to .fods + xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr); + assertXPath(pXmlDoc, + "/office:document-content/office:body/office:spreadsheet/" + "table:database-ranges/table:database-range/contains-footer"_ostr, + 0); + + // Save to ODF_LATEST which is currently (Sep 2024) ODF 1.3 extended. + // Adapt to a concrete version when attribute contains-footer is availabe in ODF strict. + // Make sure attribute is written in calcext namespace + SetODFDefaultVersion(SvtSaveOptions::ODFDefaultVersion::ODFVER_LATEST); + save(u"calc8"_ustr); + pXmlDoc = parseExport(u"content.xml"_ustr); + assertXPath(pXmlDoc, + "/office:document-content/office:body/office:spreadsheet/" + "table:database-ranges/table:database-range[@calcext:contains-footer='true']"_ostr); + + // Set back to original ODF default version. + SetODFDefaultVersion(nCurrentODFVersion); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/dbdata.cxx b/sc/source/core/tool/dbdata.cxx index 823849554693..24009dfbe4e2 100644 --- a/sc/source/core/tool/dbdata.cxx +++ b/sc/source/core/tool/dbdata.cxx @@ -423,7 +423,7 @@ void ScDBData::GetQueryParam( ScQueryParam& rQueryParam ) const rQueryParam.nTab = nTable; rQueryParam.bByRow = bByRow; rQueryParam.bHasHeader = bHasHeader; - /* TODO: add Totals to ScQueryParam? */ + rQueryParam.bHasTotals = bHasTotals; } void ScDBData::SetQueryParam(const ScQueryParam& rQueryParam) diff --git a/sc/source/core/tool/queryparam.cxx b/sc/source/core/tool/queryparam.cxx index f270488c7e72..aafe0d891951 100644 --- a/sc/source/core/tool/queryparam.cxx +++ b/sc/source/core/tool/queryparam.cxx @@ -68,6 +68,7 @@ ScQueryParamBase::const_iterator ScQueryParamBase::end() const ScQueryParamBase::ScQueryParamBase() : eSearchType(utl::SearchParam::SearchType::Normal), bHasHeader(true), + bHasTotals(false), bByRow(true), bInplace(true), bCaseSens(false), @@ -78,9 +79,9 @@ ScQueryParamBase::ScQueryParamBase() : } ScQueryParamBase::ScQueryParamBase(const ScQueryParamBase& r) : - eSearchType(r.eSearchType), bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace), - bCaseSens(r.bCaseSens), bDuplicate(r.bDuplicate), mbRangeLookup(r.mbRangeLookup), - m_Entries(r.m_Entries) + eSearchType(r.eSearchType), bHasHeader(r.bHasHeader), bHasTotals(r.bHasTotals), bByRow(r.bByRow), + bInplace(r.bInplace), bCaseSens(r.bCaseSens), bDuplicate(r.bDuplicate), + mbRangeLookup(r.mbRangeLookup), m_Entries(r.m_Entries) { } @@ -90,6 +91,7 @@ ScQueryParamBase& ScQueryParamBase::operator=(const ScQueryParamBase& r) { eSearchType = r.eSearchType; bHasHeader = r.bHasHeader; + bHasTotals = r.bHasTotals; bByRow = r.bByRow; bInplace = r.bInplace; bCaseSens = r.bCaseSens; @@ -337,7 +339,7 @@ void ScQueryParam::Clear() nRow1=nRow2 = 0; nTab = SCTAB_MAX; eSearchType = utl::SearchParam::SearchType::Normal; - bHasHeader = bCaseSens = false; + bHasHeader = bHasTotals = bCaseSens = false; bInplace = bByRow = bDuplicate = true; for (auto & itr : m_Entries) @@ -379,6 +381,7 @@ bool ScQueryParam::operator==( const ScQueryParam& rOther ) const && (nRow2 == rOther.nRow2) && (nTab == rOther.nTab) && (bHasHeader == rOther.bHasHeader) + && (bHasTotals == rOther.bHasTotals) && (bByRow == rOther.bByRow) && (bInplace == rOther.bInplace) && (bCaseSens == rOther.bCaseSens) diff --git a/sc/source/filter/xml/XMLExportDatabaseRanges.cxx b/sc/source/filter/xml/XMLExportDatabaseRanges.cxx index 89ebcc27373c..9328b796a81b 100644 --- a/sc/source/filter/xml/XMLExportDatabaseRanges.cxx +++ b/sc/source/filter/xml/XMLExportDatabaseRanges.cxx @@ -246,6 +246,9 @@ private: rData.GetQueryParam(aQueryParam); if (!aQueryParam.bHasHeader) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CONTAINS_HEADER, XML_FALSE); + if (mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + if (aQueryParam.bHasTotals) + mrExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CONTAINS_FOOTER, XML_TRUE); ScSortParam aSortParam; rData.GetSortParam(aSortParam); diff --git a/sc/source/filter/xml/xmldrani.cxx b/sc/source/filter/xml/xmldrani.cxx index cf6cd7d3e651..0e6c400c30bb 100644 --- a/sc/source/filter/xml/xmldrani.cxx +++ b/sc/source/filter/xml/xmldrani.cxx @@ -104,6 +104,7 @@ ScXMLDatabaseRangeContext::ScXMLDatabaseRangeContext( ScXMLImport& rImport, bSubTotalsAscending(true), bFilterConditionSourceRange(false), bHasHeader(true), + bHasFooter(false), bByRow(true), meRangeType(ScDBCollection::GlobalNamed) { @@ -150,6 +151,13 @@ ScXMLDatabaseRangeContext::ScXMLDatabaseRangeContext( ScXMLImport& rImport, mpQueryParam->bHasHeader = bHasHeader; } break; + case XML_ELEMENT( TABLE, XML_CONTAINS_FOOTER ): + case XML_ELEMENT( CALC_EXT, XML_CONTAINS_FOOTER ): + { + bHasFooter = IsXMLToken( aIter, XML_TRUE ); + mpQueryParam->bHasTotals = bHasFooter; + } + break; case XML_ELEMENT( TABLE, XML_DISPLAY_FILTER_BUTTONS ): { bAutoFilter = IsXMLToken( aIter, XML_TRUE ); @@ -247,7 +255,7 @@ std::unique_ptr ScXMLDatabaseRangeContext::ConvertToDBData(const OUStr ScDocument* pDoc = GetScImport().GetDocument(); ::std::unique_ptr pData( - new ScDBData(rName, maRange.aStart.Tab(), maRange.aStart.Col(), maRange.aStart.Row(), maRange.aEnd.Col(), maRange.aEnd.Row(), bByRow, bHasHeader)); + new ScDBData(rName, maRange.aStart.Tab(), maRange.aStart.Col(), maRange.aStart.Row(), maRange.aEnd.Col(), maRange.aEnd.Row(), bByRow, bHasHeader, bHasFooter)); pData->SetAutoFilter(bAutoFilter); pData->SetKeepFmt(bKeepFormats); diff --git a/sc/source/filter/xml/xmldrani.hxx b/sc/source/filter/xml/xmldrani.hxx index a35074117c28..037d5710d52c 100644 --- a/sc/source/filter/xml/xmldrani.hxx +++ b/sc/source/filter/xml/xmldrani.hxx @@ -81,6 +81,7 @@ class ScXMLDatabaseRangeContext : public ScXMLImportContext bool bSubTotalsAscending; bool bFilterConditionSourceRange; bool bHasHeader; + bool bHasFooter; // UNO TotalsRow, ODF contains-footer bool bByRow; ScDBCollection::RangeType meRangeType; diff --git a/sc/source/ui/unoobj/datauno.cxx b/sc/source/ui/unoobj/datauno.cxx index bb31d5f9e7fc..170f1a58993d 100644 --- a/sc/source/ui/unoobj/datauno.cxx +++ b/sc/source/ui/unoobj/datauno.cxx @@ -1750,6 +1750,7 @@ void ScDatabaseRangeObj::SetQueryParam(const ScQueryParam& rQueryParam) ScDBData aNewData( *pData ); aNewData.SetQueryParam(aParam); aNewData.SetHeader(aParam.bHasHeader); // not in ScDBData::SetQueryParam + aNewData.SetTotals(aParam.bHasTotals); // not in ScDBData::SetQueryParam ScDBDocFunc aFunc(*pDocShell); aFunc.ModifyDBData(aNewData); } diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index 0af6bb20301e..ac0882c0ad4f 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -3970,4 +3970,13 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. + + + + + + + + + diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 6f458260a69d..92440718d77e 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -519,6 +519,7 @@ namespace xmloff::token { TOKEN( "consolidation", XML_CONSOLIDATION ), TOKEN( "constant", XML_CONSTANT ), TOKEN( "contains-error", XML_CONTAINS_ERROR ), + TOKEN( "contains-footer", XML_CONTAINS_FOOTER ), TOKEN( "contains-header", XML_CONTAINS_HEADER ), TOKEN( "content", XML_CONTENT ), TOKEN( "content-validation", XML_CONTENT_VALIDATION ), diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 9ade81537b5f..6eb3f7612766 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -424,6 +424,7 @@ consecutive-numbering consolidation constant contains-error +contains-footer contains-header content content-validation