diff --git a/sc/CppunitTest_sc_pivottable_filters_test.mk b/sc/CppunitTest_sc_pivottable_filters_test.mk index 45ceded3698e..a2134039cdb0 100644 --- a/sc/CppunitTest_sc_pivottable_filters_test.mk +++ b/sc/CppunitTest_sc_pivottable_filters_test.mk @@ -13,6 +13,7 @@ $(eval $(call gb_CppunitTest_use_common_precompiled_header,sc_pivottable_filters $(eval $(call gb_CppunitTest_add_exception_objects,sc_pivottable_filters_test, \ sc/qa/unit/pivottable_filters_test \ + sc/qa/unit/PivotTable_FieldsAndItemsExport \ )) $(eval $(call gb_CppunitTest_use_externals,sc_pivottable_filters_test, \ diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 2567f7f21735..5960a50e1fa4 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -213,6 +213,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/data/types \ sc/source/core/data/userdat \ sc/source/core/data/validat \ + sc/source/core/data/pivot/PivotTableResultTraverser \ sc/source/core/tool/addincfg \ sc/source/core/tool/addincol \ sc/source/core/tool/addinhelpid \ diff --git a/sc/inc/miscuno.hxx b/sc/inc/miscuno.hxx index 71cd9390de49..075bf0046185 100644 --- a/sc/inc/miscuno.hxx +++ b/sc/inc/miscuno.hxx @@ -107,7 +107,7 @@ public: }; // new (uno 3) variant -class ScNameToIndexAccess final : public cppu::WeakImplHelper< +class SC_DLLPUBLIC ScNameToIndexAccess final : public cppu::WeakImplHelper< css::container::XIndexAccess, css::lang::XServiceInfo > { @@ -134,7 +134,7 @@ public: virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; }; -class ScUnoHelpFunctions +class SC_DLLPUBLIC ScUnoHelpFunctions { public: static bool GetBoolProperty( const css::uno::Reference< css::beans::XPropertySet>& xProp, @@ -152,8 +152,8 @@ public: const css::uno::Reference& xProp, const OUString& rName, const OUString& rDefault ); - SC_DLLPUBLIC static bool GetBoolFromAny( const css::uno::Any& aAny ); - SC_DLLPUBLIC static sal_Int16 GetInt16FromAny( const css::uno::Any& aAny ); + static bool GetBoolFromAny( const css::uno::Any& aAny ); + static sal_Int16 GetInt16FromAny( const css::uno::Any& aAny ); static sal_Int32 GetInt32FromAny( const css::uno::Any& aAny ); static sal_Int32 GetEnumFromAny( const css::uno::Any& aAny ); diff --git a/sc/inc/pivot/PivotTableResultTraverser.hxx b/sc/inc/pivot/PivotTableResultTraverser.hxx new file mode 100644 index 000000000000..3ecd7c0c8c4a --- /dev/null +++ b/sc/inc/pivot/PivotTableResultTraverser.hxx @@ -0,0 +1,73 @@ +/* -*- 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/. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +namespace sc +{ +namespace pivot +{ +SC_DLLPUBLIC css::uno::Any +getMemberForLevel(css::uno::Reference const& xLevel, OUString const& rName); +} + +class SC_DLLPUBLIC PivotTableResultVisitor +{ +public: + virtual bool filterOrientation(css::sheet::DataPilotFieldOrientation eOrientation) + { + return eOrientation == css::sheet::DataPilotFieldOrientation_HIDDEN; + } + + virtual void startDimension(sal_Int32 /*nDimensionIndex*/, + css::uno::Reference const& /*xDimension*/, + css::sheet::DataPilotFieldOrientation /*eOrientation*/) + { + } + + virtual void endDimension() {} + + virtual void startLevel(sal_Int32 /*nLevelIndex*/, + css::uno::Reference const& /*xLevel*/, + OUString const& /*rLevelName*/) + { + } + + virtual void endLevel() {} + + virtual void memberResult(css::sheet::MemberResult const& rResult, sal_Int32 nIndex, + sal_Int32 nSize) + = 0; +}; + +class SC_DLLPUBLIC PivotTableResultTraverser +{ +private: + ScDPObject& mrDPObject; + PivotTableResultVisitor& mrVisitor; + +public: + PivotTableResultTraverser(ScDPObject& rDPObject, PivotTableResultVisitor& rVisitor) + : mrDPObject(rDPObject) + , mrVisitor(rVisitor) + { + } + + void traverse(); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/unit/PivotTable_FieldsAndItemsExport.cxx b/sc/qa/unit/PivotTable_FieldsAndItemsExport.cxx new file mode 100644 index 000000000000..dbbaf3c8f3ff --- /dev/null +++ b/sc/qa/unit/PivotTable_FieldsAndItemsExport.cxx @@ -0,0 +1,840 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include "helper/qahelper.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +class PivotTableFieldsAndItemsExport : public ScModelTestBase +{ +public: + PivotTableFieldsAndItemsExport() + : ScModelTestBase(u"sc/qa/unit/data"_ustr) + { + } +}; + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testTdf123225PivotTableRowColItems) +{ + createScDoc("ods/tdf123225_pivotTable_row_col_items.ods"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + /* Make sure that we have and element under after export of the .ods to .xlsx */ + /* otherwise: + - Excel will fail to open the xlsx document, you will get an error message. + - Excel will open the file without any errors but: + * context menu -by right clicking on the pivot table- will have less or more items than it should have after "refresh". + * if e.g. trying to sort the items you will get "Cannot determine which PivotTable field to sort by" warning. + */ + + // Row items + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + // check if + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"8"); + // check if has enough depending on count attribute value + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 8); + // check if first has single element + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 1); + // check if of the first element, exists (note the v=0 is default) + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 1); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", "v"); + + // Column items + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + // check if + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"5"); + // check if has enough depending on count attribute value + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 5); + // check if first has single element + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 1); + // check if of the first element, exists (note the v=0 is default) + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 1); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", "v"); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testTdf123225_CheckGrandTotalIsSet) +{ + createScDoc("ods/tdf123225_pivotTable_no_col_items.ods"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + /* If there is a grand (Total result) there needs to be a row/column item with t="grand"*/ + + // Row items + + // check if + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"3"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 3); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[1]", "v", u"2"); + + // check if last element, has t="grand" + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]", "t", u"grand"); + // check element + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 1); + + // Column items + + // check if + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + // check if has only a single element + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + // check there is no attribute "t" + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", "t"); + // check that it doesn't contain any elements + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testTdf123225PivotTableEmptyRowColItems) +{ + // this doc contains blank row/col items + // (xl/pivotCache/pivotCacheDefinition1.xml) + createScDoc("ods/tdf123225_pivotTable_empty_row_col_items.ods"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + // Row items + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + // check if + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"4"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 4); + + // Column items + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + // check if + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"5"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 5); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testPivotTable_RowColumnItems_Row1) +{ + /* Input document rowItems: + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot1_Row.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"5"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 5); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 2); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[2]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[1]", "v", u"2"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[1]", "v", u"3"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[1]", "v", u"4"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[2]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testPivotTable_RowColumnItems_Row1_Grand) +{ + /* Input document rowItems: + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot1_Row_Grand.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"6"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 6); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 2); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[2]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[1]", "v", u"2"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[1]", "v", u"3"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[1]", "v", u"4"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[2]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]", "t", u"grand"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, + testPivotTable_RowColumnItems_Row1_Grand_Subtotals) +{ + /* Input document rowItems: + + + + + + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot1_Row_Grand_Subtotals.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"11"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 11); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[9]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[10]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[11]/x:x", 1); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[2]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[1]", "v", u"2"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x[1]", "v", u"3"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[9]/x:x[1]", "v", u"4"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[9]/x:x[2]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[10]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[10]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[10]/x:x", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[11]", "t", u"grand"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[11]/x:x", 1); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[11]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testPivotTable_RowColumnItems_Row2) +{ + /* Input document rowItems: + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot2_Row.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"5"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 5); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 2); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[1]", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[1]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[1]", "v", u"2"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[2]", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testPivotTable_RowColumnItems_Row2_Grand) +{ + /* Input document rowItems: + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot2_Row_Grand.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"6"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 6); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[1]", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[1]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[1]", "v", u"2"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[2]", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]", "t", u"grand"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testPivotTable_RowColumnItems_Row2_Subtotals) +{ + /* Input document rowItems: + + + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot2_Row_Subtotals.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"8"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 8); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", 1); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[1]", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]", "t", u"default"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[1]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x[1]", "v", u"2"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x[2]", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, + testPivotTable_RowColumnItems_Row2_Grand_Subtotals) +{ + /* Input document rowItems: + + + + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot2_Row_Grand_Subtotals.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"9"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 9); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[9]/x:x", 1); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[1]", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 1); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[1]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x[1]", "v", u"2"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x[2]", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[9]", "t", u"grand"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[9]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, testPivotTable_RowColumnItems_Row2_Compact) +{ + /* Input document rowItems: + + + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot2_Row_Compact.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"8"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 8); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 1); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]", "r", u"1"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x[1]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[1]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x[1]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x[1]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x[1]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x[1]", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, + testPivotTable_RowColumnItems_Row2_Subtotals_SortDescendingAll) +{ + /* Input document rowItems: + + + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot2_Row_Subtotals_SortDescendingAll.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"8"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 8); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", 1); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[1]", "v"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]", "t", u"default"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[2]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x[2]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[4]/x:x[1]", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[5]/x:x", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x[1]", "v", u"2"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[6]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[7]/x:x[1]", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[8]/x:x", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 0); +} + +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, + testPivotTable_RowColumnItems_Column3_Grand_Subtotals) +{ + /* Input colItems should be the same as output + + + + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot3_Column_Grand_Subtotals.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 0); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"9"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 9); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[3]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[4]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[5]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[6]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[7]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[8]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[9]/x:x", 1); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x[1]", "v"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[2]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[2]/x:x[1]", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[3]", "t", u"default"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[3]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[4]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[4]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[5]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[5]/x:x[1]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[6]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[6]/x:x", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[7]/x:x[1]", "v", u"2"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[7]/x:x[2]", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[8]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[8]/x:x", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[9]", "t", u"grand"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[9]/x:x", "v"); +} +CPPUNIT_TEST_FIXTURE(PivotTableFieldsAndItemsExport, + testPivotTable_RowColumnItems_Column4_Grand_Subtotals_SortDescending) +{ + /* Input colItems should be the same as output + + + + + + + + + + + + */ + createScDoc("xlsx/pivot/Pivot4_Column_Grand_Subtotals_SortDescending.xlsx"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 0); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"9"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 9); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[2]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[3]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[4]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[5]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[6]/x:x", 2); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[7]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[8]/x:x", 1); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[9]/x:x", 1); + + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x[1]", "v"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x[2]", "v", u"3"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[2]", "t", u"default"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[2]/x:x", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[3]/x:x[1]", "v", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[3]/x:x[2]", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[4]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[4]/x:x[1]", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[5]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[5]/x:x", "v", u"1"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[6]/x:x[1]", "v", u"2"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[6]/x:x[2]", "v"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[7]", "r", u"1"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[7]/x:x[1]", "v", u"4"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[8]", "t", u"default"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[8]/x:x", "v", u"2"); + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[9]", "t", u"grand"); + assertXPathNoAttribute(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[9]/x:x", "v"); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot1_Row.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot1_Row.xlsx new file mode 100644 index 000000000000..77df731a5602 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot1_Row.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot1_Row_Grand.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot1_Row_Grand.xlsx new file mode 100644 index 000000000000..c36c6202f7a4 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot1_Row_Grand.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot1_Row_Grand_Subtotals.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot1_Row_Grand_Subtotals.xlsx new file mode 100644 index 000000000000..cae68e5c6904 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot1_Row_Grand_Subtotals.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot2_Row.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row.xlsx new file mode 100644 index 000000000000..de44fa7c6420 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Compact.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Compact.xlsx new file mode 100644 index 000000000000..c48ab5b4b917 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Compact.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Grand.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Grand.xlsx new file mode 100644 index 000000000000..6e81ddc7d486 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Grand.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Grand_Subtotals.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Grand_Subtotals.xlsx new file mode 100644 index 000000000000..848c30e02a54 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Grand_Subtotals.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Subtotals.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Subtotals.xlsx new file mode 100644 index 000000000000..043e31185f03 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Subtotals.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Subtotals_SortDescendingAll.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Subtotals_SortDescendingAll.xlsx new file mode 100644 index 000000000000..ade6310b8c03 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Subtotals_SortDescendingAll.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot3_Column_Grand_Subtotals.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot3_Column_Grand_Subtotals.xlsx new file mode 100644 index 000000000000..3d3065b7db49 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot3_Column_Grand_Subtotals.xlsx differ diff --git a/sc/qa/unit/data/xlsx/pivot/Pivot4_Column_Grand_Subtotals_SortDescending.xlsx b/sc/qa/unit/data/xlsx/pivot/Pivot4_Column_Grand_Subtotals_SortDescending.xlsx new file mode 100644 index 000000000000..bca42a014dbc Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot/Pivot4_Column_Grand_Subtotals_SortDescending.xlsx differ diff --git a/sc/qa/unit/pivottable_filters_test.cxx b/sc/qa/unit/pivottable_filters_test.cxx index b874bdd398b8..12a360790d13 100644 --- a/sc/qa/unit/pivottable_filters_test.cxx +++ b/sc/qa/unit/pivottable_filters_test.cxx @@ -122,137 +122,6 @@ CPPUNIT_TEST_FIXTURE(ScPivotTableFiltersTest, testPivotTableBasicODS) sal_uInt16(pDim->GetFunction())); } -CPPUNIT_TEST_FIXTURE(ScPivotTableFiltersTest, testTdf123225PivotTableRowColItems) -{ - createScDoc("ods/tdf123225_pivotTable_row_col_items.ods"); - save(TestFilter::XLSX); - - xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); - CPPUNIT_ASSERT(pSheet); - - /* - - be sure that we have and element - under after export of the .ods to .xlsx - - otherwise: - 1) Excel will fail to open the xlsx document, you will get an error message. - 2) Excel will open the file without any errors but: - 2.1) context menu -by right clicking on the pivot table- will have - less or more items than it should have after "refresh". - 2.2) if e.g. trying to sort the items you will get "Cannot determine - which PivotTable field to sort by" warning. - - - after exporting the .ods as .xlsx and opening the .xlsx document in Excel: - the count attribute of rowItems(or colItems) should have the expected value. - otherwise, context menu on the pivot table will have less/more items - than it should have after "refresh". we shouldn't need "refresh" to use all - functions/items in the context menu. - */ - - // Row items - - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); - // check if - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"8"); - // check if has enough depending on count attribute value - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 8); - // check if first has single element - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 1); - // check if of the first element, has v="0" attribute value - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", "v", u"0"); - - // Column items - - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); - // check if - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"5"); - // check if has enough depending on count attribute value - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 5); - // check if first has single element - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 1); - // check if of the first element, has v="0" attribute value - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", "v", u"0"); -} - -CPPUNIT_TEST_FIXTURE(ScPivotTableFiltersTest, testTdf123225PivotTableNoColItems) -{ - createScDoc("ods/tdf123225_pivotTable_no_col_items.ods"); - save(TestFilter::XLSX); - - xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); - CPPUNIT_ASSERT(pSheet); - - /* - - after exporting the .ods to .xlsx, we should have t="grand" in the - last element of the and . Otherwise, Excel will not - have all functions in the context menu of the pivot table. Especially for the - "Grand Total" column/row cells. - - - additionally, we should always export a single and regardless of - whether the document has row/col items. Otherwise, in Excel, context menu on some - cells of the pivot table, will not have the expected context menu items. - - - this tdf123225_pivotTable_no_col_items.ods document does not have - axisCol (DataPilotFieldOrientation_COLUMN) and that means should not exist - during export. But in Excel, if pivot table refreshed, there will be - - - - - - in the xl/pivotTables/pivotTable1.xml. So, that means we should export - without checking the existence of it. - For the sake of completeness, exported as: - - - - - - - */ - - // Row items - - // check if - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"3"); - // check if last element, has t="grand" - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[last()]", "t", u"grand"); - - // Column items - - // check if - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); - // check if has only a single element - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); - // check if element has t="grand" - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", "t", u"grand"); - // check if has - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i/x:x", "v", u"0"); -} - -CPPUNIT_TEST_FIXTURE(ScPivotTableFiltersTest, testTdf123225PivotTableEmptyRowColItems) -{ - // this doc contains blank row/col items - // (xl/pivotCache/pivotCacheDefinition1.xml) - createScDoc("ods/tdf123225_pivotTable_empty_row_col_items.ods"); - save(TestFilter::XLSX); - - xmlDocUniquePtr pSheet = parseExport(u"xl/pivotTables/pivotTable1.xml"_ustr); - CPPUNIT_ASSERT(pSheet); - - // Row items - - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); - // check if - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"4"); - - // Column items - - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); - // check if - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"5"); -} - CPPUNIT_TEST_FIXTURE(ScPivotTableFiltersTest, testPivotTableNamedRangeSourceODS) { createScDoc("ods/pivot-table-named-range-source.ods"); diff --git a/sc/source/core/data/pivot/PivotTableResultTraverser.cxx b/sc/source/core/data/pivot/PivotTableResultTraverser.cxx new file mode 100644 index 000000000000..90037e6684e3 --- /dev/null +++ b/sc/source/core/data/pivot/PivotTableResultTraverser.cxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace css; + +namespace sc +{ +namespace pivot +{ +uno::Any getMemberForLevel(uno::Reference const& xLevel, OUString const& rName) +{ + uno::Reference xMembersSupplier(xLevel, uno::UNO_QUERY); + if (xMembersSupplier.is()) + { + uno::Reference xMembers = xMembersSupplier->getMembers(); + if (xMembers.is()) + { + if (xMembers->hasByName(rName)) + return xMembers->getByName(rName); + } + } + return uno::Any(); +} +} + +// PivotTableResultTraverser + +void PivotTableResultTraverser::traverse() +{ + uno::Reference xDimensionsSupplier(mrDPObject.GetSource()); + uno::Reference xDimensions + = new ScNameToIndexAccess(xDimensionsSupplier->getDimensions()); + + for (sal_Int32 nDimension = 0; nDimension < xDimensions->getCount(); nDimension++) + { + uno::Reference xDimension(xDimensions->getByIndex(nDimension), + uno::UNO_QUERY); + uno::Reference xDimensionPropertySet(xDimension, uno::UNO_QUERY); + uno::Reference xDimensionSupplier(xDimension, uno::UNO_QUERY); + + if (xDimensionPropertySet.is() && xDimensionSupplier.is()) + { + sheet::DataPilotFieldOrientation eDimensionOrientation + = ScUnoHelpFunctions::GetEnumProperty(xDimensionPropertySet, SC_UNO_DP_ORIENTATION, + sheet::DataPilotFieldOrientation_HIDDEN); + mrVisitor.startDimension(nDimension, xDimension, eDimensionOrientation); + + if (!mrVisitor.filterOrientation(eDimensionOrientation)) + { + uno::Reference xHierarchies + = new ScNameToIndexAccess(xDimensionSupplier->getHierarchies()); + sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty(xDimensionPropertySet, + SC_UNO_DP_USEDHIERARCHY); + if (nHierarchy >= xHierarchies->getCount()) + nHierarchy = 0; + + uno::Reference xLevelsSupplier( + xHierarchies->getByIndex(nHierarchy), uno::UNO_QUERY); + if (xLevelsSupplier.is()) + { + uno::Reference xLevels + = new ScNameToIndexAccess(xLevelsSupplier->getLevels()); + if (xLevels.is()) + { + for (sal_Int32 nLevel = 0; nLevel < xLevels->getCount(); nLevel++) + { + uno::Reference xLevel(xLevels->getByIndex(nLevel), + uno::UNO_QUERY); + uno::Reference xLevelName(xLevel, uno::UNO_QUERY); + uno::Reference xLevelResult( + xLevel, uno::UNO_QUERY); + + if (xLevelName.is() && xLevelResult.is()) + { + mrVisitor.startLevel(nLevel, xLevel, xLevelName->getName()); + + const uno::Sequence aSequence + = xLevelResult->getResults(); + sal_Int32 nCurrent = 0; + sal_Int32 nSize = aSequence.getLength(); + for (sheet::MemberResult const& rMemberResult : aSequence) + { + mrVisitor.memberResult(rMemberResult, nCurrent, nSize); + nCurrent++; + } + mrVisitor.endLevel(); + } + } + } + } + } + mrVisitor.endDimension(); + } + } +} + +} // end sc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx index 0667ef11347c..5b2596289de0 100644 --- a/sc/source/filter/excel/xepivotxml.cxx +++ b/sc/source/filter/excel/xepivotxml.cxx @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include #include @@ -37,8 +39,15 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include +#include using namespace oox; using namespace com::sun::star; @@ -711,12 +720,233 @@ sal_Int32 GetSubtotalAttrToken(ScGeneralFunction eFunc) return XML_defaultSubtotal; } +struct RowOrColumnItemsData +{ + bool mbSet = false; + bool mbContinue = false; + bool mbSubtotal = false; + bool mbGrandTotal = false; + OUString msName; + OUString maLevelName; +}; + +struct RowOrColumnMemberResultData +{ + std::vector maFieldOrder; + std::vector> maItemsData; + std::unordered_map> maLookUpIndexForMemberName; + + void ensureItemData(sal_Int32 nSize) + { + if (maItemsData.size() < o3tl::make_unsigned(nSize)) + maItemsData.resize(nSize); + } + + RowOrColumnItemsData& addItemsData(OUString const& sName, sal_Int32 nIndex) + { + auto& rItemsMap = maItemsData[nIndex]; + + if (!rItemsMap.contains(sName)) + rItemsMap.emplace(sName, RowOrColumnItemsData()); + + return rItemsMap[sName]; + } + + void initLookupFor(OUString const& sDimensionName) + { + maLookUpIndexForMemberName.emplace(sDimensionName, std::unordered_map{}); + } + + void addLookupEntryFor(OUString const& sDimensionName, OUString const& sMemberName, sal_Int32 nIndex) + { + maLookUpIndexForMemberName[sDimensionName].emplace(sMemberName, nIndex); + } + + sal_Int32 lookup(OUString const& sDimensionName, OUString const& sMemberName) + { + return maLookUpIndexForMemberName[sDimensionName][sMemberName]; + } +}; + +class RowColumnItemsDataVisitor : public sc::PivotTableResultVisitor +{ + RowOrColumnMemberResultData& mrRowMemberResultData; + RowOrColumnMemberResultData& mrColumnMemberResultData; + +public: + RowColumnItemsDataVisitor(RowOrColumnMemberResultData& rRowMemberResultData, RowOrColumnMemberResultData& rColumnMemberResultData) + : mrRowMemberResultData(rRowMemberResultData) + , mrColumnMemberResultData(rColumnMemberResultData) + {} + + sheet::DataPilotFieldOrientation meCurrentOrientation = sheet::DataPilotFieldOrientation_HIDDEN; + OUString maLevelName; + + bool filterOrientation(sheet::DataPilotFieldOrientation eOrientation) override + { + return eOrientation == sheet::DataPilotFieldOrientation_HIDDEN; + } + + void startDimension(sal_Int32 /*nDimensionIndex*/, uno::Reference const& /*xDimension*/, sheet::DataPilotFieldOrientation eOrientation) override + { + meCurrentOrientation = eOrientation; + } + + void endDimension() override + { + meCurrentOrientation = sheet::DataPilotFieldOrientation_HIDDEN; + } + + void startLevel(sal_Int32 /*nLevelIndex*/, uno::Reference const& /*xLevel*/, OUString const& rLevelName) override + { + maLevelName = rLevelName; + } + + void endLevel() override + { + maLevelName = OUString(); + } + + void memberResult(sheet::MemberResult const& rResult, sal_Int32 nIndex, sal_Int32 nSize) override + { + if (meCurrentOrientation == sheet::DataPilotFieldOrientation_ROW) + { + mrRowMemberResultData.ensureItemData(nSize); + gatherFieldsData(mrRowMemberResultData, rResult, nIndex); + } + else if (meCurrentOrientation == sheet::DataPilotFieldOrientation_COLUMN) + { + mrColumnMemberResultData.ensureItemData(nSize); + gatherFieldsData(mrColumnMemberResultData, rResult, nIndex); + } + } + + void gatherFieldsData(RowOrColumnMemberResultData& rMemberResultData, sheet::MemberResult const& rResult, sal_Int32 nIndex) + { + auto& rItemsData = rMemberResultData.addItemsData(maLevelName, nIndex); + assert(!rItemsData.mbSet); + + rItemsData.mbSet = true; + rItemsData.maLevelName = maLevelName; + + bool bHasContinueFlag = rResult.Flags & sheet::MemberResultFlags::CONTINUE; + bool bIsGrandTotal = rResult.Flags & sheet::MemberResultFlags::GRANDTOTAL; + bool bIsSubtotal = rResult.Flags & sheet::MemberResultFlags::SUBTOTAL; + + if (bIsGrandTotal) + { + rItemsData.mbGrandTotal = true; + } + else if (bIsSubtotal) + { + rItemsData.mbSubtotal = true; + rItemsData.msName = rResult.Name; + } + else if (bHasContinueFlag) + { + rItemsData.mbContinue = true; + } + else + { + rItemsData.msName = rResult.Name; + } + } +}; + +void writeRowColumnItems(sal_Int32 nItemElement, RowOrColumnMemberResultData& rMemberResultData, sax_fastparser::FSHelperPtr& pStream) +{ + if (rMemberResultData.maItemsData.empty() || rMemberResultData.maFieldOrder.empty()) + { + pStream->startElement(nItemElement, XML_count, "1"); + pStream->singleElement(XML_i); + pStream->endElement(nItemElement); + return; + } + + pStream->startElement(nItemElement, XML_count, OString::number(rMemberResultData.maItemsData.size())); + for (auto& rItemMap : rMemberResultData.maItemsData) + { + bool bIsGrandTotal = false; + bool bIsSubtotal = false; + + for (OUString const& rFieldName : rMemberResultData.maFieldOrder) + { + RowOrColumnItemsData const& rData = rItemMap[rFieldName]; + if (rData.mbSubtotal) + bIsSubtotal = true; + if (rData.mbGrandTotal) + bIsGrandTotal = true; + } + + { + OUString const& rFieldName = rMemberResultData.maFieldOrder[0]; + RowOrColumnItemsData const& rData = rItemMap[rFieldName]; + sal_Int32 nIndex = -1; + if (!rData.msName.isEmpty()) + nIndex = rMemberResultData.lookup(rFieldName, rData.msName); + if (bIsGrandTotal) + { + pStream->startElement(XML_i, XML_t, "grand"); + pStream->singleElement(XML_x); + } + else if (bIsSubtotal) + { + pStream->startElement(XML_i, XML_t, "default"); + + if (nIndex == 0) // 0 is the default + pStream->singleElement(XML_x); + else + pStream->singleElement(XML_x, XML_v, OString::number(nIndex)); + } + else if (rData.mbContinue) + { + pStream->startElement(XML_i, XML_r, "1"); + } + else if (nIndex >= 0) + { + pStream->startElement(XML_i); + if (nIndex == 0) // 0 is the default + pStream->singleElement(XML_x); + else + pStream->singleElement(XML_x, XML_v, OString::number(nIndex)); + } + else + { + pStream->startElement(XML_i); + } + } + + for (size_t i = 1; i < rMemberResultData.maFieldOrder.size(); i++) + { + OUString const& rItemName = rMemberResultData.maFieldOrder[i]; + RowOrColumnItemsData const& rData = rItemMap[rItemName]; + + sal_Int32 nIndex = -1; + if (!rData.msName.isEmpty()) + nIndex = rMemberResultData.lookup(rItemName, rData.msName); + + if (nIndex >= 0) + { + if (nIndex == 0) // 0 is the default + pStream->singleElement(XML_x); + else + pStream->singleElement(XML_x, XML_v, OString::number(nIndex)); + } + } + + pStream->endElement(XML_i); + } + pStream->endElement(nItemElement); } +} // end anonymous namespace + void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rDPObj, sal_Int32 nCacheId ) { typedef std::unordered_map NameToIdMapType; + auto& rDPObjectModifiable = const_cast(rDPObj); + const XclExpXmlPivotCaches::Entry* pCacheEntry = mrCaches.GetCache(nCacheId); if (!pCacheEntry) // Something is horribly wrong. Check your logic. @@ -744,11 +974,9 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP std::vector aPageFields; std::vector aDataFields; - // we should always export and , even if the pivot table - // does not contain col/row items. otherwise, in Excel, pivot table will not - // have all context menu items. - tools::Long nRowItemsCount = 1; // for of pivotTable*.xml - tools::Long nColItemsCount = 1; // for of pivotTable*.xml + RowOrColumnMemberResultData aRowMemberResultData; + RowOrColumnMemberResultData aColumnMemberResultData; + tools::Long nDataDimCount = rSaveData.GetDataDimensionCount(); // Use dimensions in the save data to get their correct ordering. // Dimension order here is significant as they specify the order of @@ -785,9 +1013,11 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP if (nPos == -2 && nDataDimCount <= 1) break; aColFields.push_back(nPos); + aColumnMemberResultData.maFieldOrder.push_back(rDim.GetName()); break; case sheet::DataPilotFieldOrientation_ROW: aRowFields.push_back(nPos); + aRowMemberResultData.maFieldOrder.push_back(rDim.GetName()); break; case sheet::DataPilotFieldOrientation_PAGE: aPageFields.push_back(nPos); @@ -833,9 +1063,6 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP // normalize the order to prevent negative row/col counts - just in case. aOutRange.PutInOrder(); - // both start and end cells are included. subtraction excludes the start cells, therefore add +1. - SCROW pivotTableRowCount = aOutRange.aEnd.Row() - aOutRange.aStart.Row() + 1; - SCCOL pivotTableColCount = aOutRange.aEnd.Col() - aOutRange.aStart.Col() + 1; sal_Int32 nFirstHeaderRow = rDPObj.GetHideHeader() ? 0 : (rDPObj.GetHeaderLayout() ? 2 : 1); sal_Int32 nFirstDataRow = rDPObj.GetHideHeader() ? 1 : 2; @@ -901,8 +1128,8 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP { pPivotStrm->singleElement(XML_pivotField, XML_compact, ToPsz10(false), - XML_showAll, ToPsz10(false), - XML_outline, ToPsz10(false)); + XML_outline, ToPsz10(false), + XML_showAll, ToPsz10(false)); } else { @@ -924,8 +1151,8 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP pPivotStrm->singleElement(XML_pivotField, XML_dataField, ToPsz10(true), XML_compact, ToPsz10(false), - XML_showAll, ToPsz10(false), - XML_outline, ToPsz10(false)); + XML_outline, ToPsz10(false), + XML_showAll, ToPsz10(false)); } else { @@ -946,8 +1173,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP std::vector aMembers; { // We need to get the members in actual order, getting which requires non-const reference here - auto& dpo = const_cast(rDPObj); - dpo.GetMembers(i, dpo.GetUsedHierarchy(i), aMembers); + rDPObjectModifiable.GetMembers(i, rDPObjectModifiable.GetUsedHierarchy(i), aMembers); } std::vector aCacheFieldItems; @@ -968,9 +1194,16 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP { aCacheFieldItems = SortGroupItems(rCache, i); } + + if (eOrient == sheet::DataPilotFieldOrientation_ROW) + aRowMemberResultData.initLookupFor(pDim->GetName()); + else if (eOrient == sheet::DataPilotFieldOrientation_COLUMN) + aColumnMemberResultData.initLookupFor(pDim->GetName()); + // The pair contains the member index in cache and if it is hidden std::vector< std::pair > aMemberSequence; std::set aUsedCachePositions; + sal_Int32 nIndex = 0; for (const auto & rMember : aMembers) { auto it = std::find(aCacheFieldItems.begin(), aCacheFieldItems.end(), rMember.maName); @@ -979,7 +1212,14 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP size_t nCachePos = static_cast(std::distance(aCacheFieldItems.begin(), it)); auto aInserted = aUsedCachePositions.insert(nCachePos); if (aInserted.second) + { aMemberSequence.emplace_back(std::make_pair(nCachePos, !rMember.mbVisible)); + if (eOrient == sheet::DataPilotFieldOrientation_ROW) + aRowMemberResultData.addLookupEntryFor(pDim->GetName(), rMember.maName, nIndex); + else if (eOrient == sheet::DataPilotFieldOrientation_COLUMN) + aColumnMemberResultData.addLookupEntryFor(pDim->GetName(), rMember.maName, nIndex); + nIndex++; + } } } // Now add all remaining cache items as hidden @@ -1011,6 +1251,9 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP if (!bDimInCompactMode) pAttList->add(XML_compact, ToPsz10(false)); + if(bDimInTabularMode) + pAttList->add(XML_outline, ToPsz10(false)); + pAttList->add(XML_showAll, ToPsz10(false)); tools::Long nSubTotalCount = pDim->GetSubTotalsCount(); @@ -1030,8 +1273,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP if (!bHasDefaultSubtotal) pAttList->add(XML_defaultSubtotal, ToPsz10(false)); - if(bDimInTabularMode) - pAttList->add( XML_outline, ToPsz10(false)); + pPivotStrm->startElement(XML_pivotField, pAttList); sal_uInt32 nItems = aMemberSequence.size() + aSubtotalSequence.size(); @@ -1049,11 +1291,6 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP pPivotStrm->singleElement(XML_item, pItemAttList); } - if (strcmp(toOOXMLAxisType(eOrient), "axisCol") == 0) - nColItemsCount = pivotTableColCount - nFirstDataCol; - else if (strcmp(toOOXMLAxisType(eOrient), "axisRow") == 0) - nRowItemsCount = pivotTableRowCount - nFirstDataRow; - for (const OString& sSubtotal : aSubtotalSequence) { pPivotStrm->singleElement(XML_item, XML_t, sSubtotal); @@ -1081,32 +1318,13 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP pPivotStrm->endElement(XML_rowFields); } + RowColumnItemsDataVisitor aVisitor(aRowMemberResultData, aColumnMemberResultData); + sc::PivotTableResultTraverser aTraverser(rDPObjectModifiable, aVisitor); + aTraverser.traverse(); + // - if (nRowItemsCount > 0) - { - pPivotStrm->startElement(XML_rowItems, XML_count, OString::number(nRowItemsCount)); - // export nRowItemsCount times and elements - for (tools::Long nCount = 0; nCount < nRowItemsCount; ++nCount) - { - /* we should add t="grand" to the last element. Otherwise, Excel will not - have all functions in the context menu of the pivot table. Especially for the - "Grand Total" column/row cells. - - note: it is not completely clear that the last element always gets t="grand". - however, testing on the same docs indicate that t="grand" should be - in the last element, so let's try this here. */ - if (nCount == nRowItemsCount - 1) - pPivotStrm->startElement(XML_i, XML_t, "grand"); - else - pPivotStrm->startElement(XML_i); - - pPivotStrm->singleElement(XML_x, XML_v, OString::number(nCount)); - pPivotStrm->endElement(XML_i); - } - - pPivotStrm->endElement(XML_rowItems); - } + writeRowColumnItems(XML_rowItems, aRowMemberResultData, pPivotStrm); // @@ -1124,31 +1342,8 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP } // - if (nColItemsCount > 0) - { - pPivotStrm->startElement(XML_colItems, XML_count, OString::number(nColItemsCount)); - // export nColItemsCount times and elements - for (tools::Long nCount = 0; nCount < nColItemsCount; ++nCount) - { - /* we should add t="grand" to the last element. Otherwise, Excel will not - have all functions in the context menu of the pivot table. Especially for the - "Grand Total" column/row cells. - - note: it is not completely clear that the last element always gets t="grand". - however, testing on the some docs indicate that t="grand" should be - in the last element, so let's try this here. */ - if (nCount == nColItemsCount - 1) - pPivotStrm->startElement(XML_i, XML_t, "grand"); - else - pPivotStrm->startElement(XML_i); - - pPivotStrm->singleElement(XML_x, XML_v, OString::number(nCount)); - pPivotStrm->endElement(XML_i); - } - - pPivotStrm->endElement(XML_colItems); - } + writeRowColumnItems(XML_colItems, aColumnMemberResultData, pPivotStrm); //