sc/CppunitTest_sc_pivottable_filters_test.mk | 1 sc/Library_sc.mk | 1 sc/inc/miscuno.hxx | 8 sc/inc/pivot/PivotTableResultTraverser.hxx | 73 sc/qa/unit/PivotTable_FieldsAndItemsExport.cxx | 840 ++++++++++ sc/qa/unit/data/xlsx/pivot/Pivot1_Row.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot1_Row_Grand.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot1_Row_Grand_Subtotals.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot2_Row.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Compact.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Grand.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Grand_Subtotals.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Subtotals.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot2_Row_Subtotals_SortDescendingAll.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot3_Column_Grand_Subtotals.xlsx |binary sc/qa/unit/data/xlsx/pivot/Pivot4_Column_Grand_Subtotals_SortDescending.xlsx |binary sc/qa/unit/pivottable_filters_test.cxx | 131 - sc/source/core/data/pivot/PivotTableResultTraverser.cxx | 125 + sc/source/filter/excel/xepivotxml.cxx | 333 +++ 19 files changed, 1308 insertions(+), 204 deletions(-)
New commits: commit ca071ce7fd7143ad0404fd78c7d079695efa0761 Author: Tomaž Vajngerl <[email protected]> AuthorDate: Tue Dec 2 14:31:11 2025 +0900 Commit: Tomaž Vajngerl <[email protected]> CommitDate: Thu Dec 4 08:20:48 2025 +0100 sc: fix exporting of row / column items of a pivot table The current row and column items export implementation was quite naive, where it added jsut one level of items and not understood why t="grand" needs to be added. This fixes the implementation so it now gathers the row / column items correctly. There are many scenarios we need to take into account, like grant totals, subtotals, filters and sorts. Those are covered by tests using different pivot tables. If the row / column items are not correctly set, the pivot table in MSOffice is not shown correctly in the sheet until you actually refresh the pivot table, so the data refreshes. In recent MSOffice version it also marks the pivot table as corrupt and removes the pivot table from the document. With this fix it now accepts the pivot table and show it correctly. Change-Id: I1fbe05b4b5a2051ec9d527f5243c84c2e8818b72 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194940 Reviewed-by: Tomaž Vajngerl <[email protected]> Tested-by: Jenkins 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<css::beans::XPropertySet>& 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 <dpobject.hxx> +#include <scdllapi.h> +#include <rtl/ustring.hxx> + +#include <com/sun/star/sheet/MemberResult.hpp> +#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> + +namespace sc +{ +namespace pivot +{ +SC_DLLPUBLIC css::uno::Any +getMemberForLevel(css::uno::Reference<css::uno::XInterface> 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<css::uno::XInterface> const& /*xDimension*/, + css::sheet::DataPilotFieldOrientation /*eOrientation*/) + { + } + + virtual void endDimension() {} + + virtual void startLevel(sal_Int32 /*nLevelIndex*/, + css::uno::Reference<css::uno::XInterface> 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 <sal/config.h> + +#include "helper/qahelper.hxx" + +#include <patattr.hxx> +#include <scitems.hxx> +#include <document.hxx> +#include <generalfunction.hxx> +#include <dpcache.hxx> +#include <dpobject.hxx> +#include <dpsave.hxx> +#include <dputil.hxx> +#include <attrib.hxx> +#include <dpshttab.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <queryentry.hxx> +#include <queryparam.hxx> +#include <rtl/string.hxx> + +#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> +#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> + +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 <rowItems> and <colItems> element under <pivotTableDefinition> 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 <rowItems> + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + // check if <rowItems count="8"> + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"8"); + // check if <rowItems> has enough <i> depending on count attribute value + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 8); + // check if first <i> has single <x/> element + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 1); + // check if <x/> of the first <i> 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 <colItems> + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + // check if <colItems count="5"> + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"5"); + // check if <colItems> has enough <i> depending on count attribute value + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 5); + // check if first <i> has single <x/> element + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 1); + // check if <x/> of the first <i> 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 <rowItems> + + // check if <rowItems count="3"> + 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 <i> element, has t="grand" + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]", "t", u"grand"); + // check <x> element + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[3]/x:x", 1); + + // Column items <colItems> + + // check if <colItems count="1"> + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); + // check if <colItems> has only a single <i> 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 <x> 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 + // <sharedItems containsBlank="1" count="..."> (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 <rowItems> + + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); + // check if <rowItems count="4"> + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"4"); + assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 4); + + // Column items <colItems> + + assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); + // check if <colItems count="5"> + 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: + <rowItems count="5"> + <i> <x /> <x v="2" /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i> <x v="2" /> <x v="1" /> </i> + <i> <x v="3" /> <x /> </i> + <i> <x v="4" /> <x v="2" /> </i> + </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: + <rowItems count="6"> + <i> <x /> <x v="2" /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i> <x v="2" /> <x v="1" /> </i> + <i> <x v="3" /> <x /> </i> + <i> <x v="4" /> <x v="2" /> </i> + <i t="grand"> <x /> </i> + </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: + <rowItems count="11"> + <i> <x /> <x v="2" /> </i> + <i t="default"> <x /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i t="default"> <x v="1" /> </i> + <i> <x v="2" /> <x v="1" /> </i> + <i t="default"><x v="2" /> </i> + <i> <x v="3" /> <x /> </i> + <i t="default"> <x v="3" /> </i> + <i> <x v="4" /> <x v="2" /> </i> + <i t="default"> <x v="4" /> </i> + <i t="grand"> <x /> </i> + </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: + <rowItems count="5"> + <i> <x /> <x /> </i> + <i r="1"> <x v="4" /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i r="1"> <x v="2" /> </i> + <i> <x v="2" /> <x v="3" /> </i> + </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: + <rowItems count="6"> + <i> <x /> <x /> </i> + <i r="1"> <x v="4" /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i r="1"> <x v="2" /> </i> + <i> <x v="2" /> <x v="3" /> </i> + <i t="grand"> <x /> </i> + </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: + <rowItems count="8"> + <i> <x /> <x /> </i> + <i r="1"> <x v="4" /> </i> + <i t="default"> <x /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i r="1"> <x v="2" /> </i> + <i t="default"> <x v="1" /> </i> + <i> <x v="2" /> <x v="3" /> </i> + <i t="default"> <x v="2" /> </i> + </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: + <rowItems count="9"> + <i> <x /> <x /> </i> + <i r="1"> <x v="4" /> </i> + <i t="default"> <x /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i r="1"> <x v="2" /> </i> + <i t="default"> <x v="1" /> </i> + <i> <x v="2" /> <x v="3" /> </i> + <i t="default"> <x v="2" /> </i> + <i t="grand"> <x /> </i> + </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: + <rowItems count="8"> + <i> <x /> </i> + <i r="1"> <x /> </i> + <i r="1"> <x v="4" /> </i> + <i> <x v="1" /> </i> + <i r="1"> <x v="1" /> </i> + <i r="1"> <x v="2" /> </i> + <i> <x v="2" /> </i> + <i r="1"> <x v="3" /> </i> + </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: + <rowItems count="8"> + <i> <x /> <x v="1" /> </i> + <i t="default"> <x /> </i> + <i> <x v="1" /> <x v="2" /> </i> + <i r="1"> <x v="3" /> </i> + <i t="default"> <x v="1" /> </i> + <i> <x v="2" /> <x /> </i> + <i r="1"> <x v="4" /> </i> + <i t="default"> <x v="2" /> </i> + </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 + <colItems count="9"> + <i> <x /> <x /> </i> + <i r="1"> <x v="4" /> </i> + <i t="default"> <x /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i r="1"> <x v="2" /> </i> + <i t="default"> <x v="1" /> </i> + <i> <x v="2" /> <x v="3" /> </i> + <i t="default"> <x v="2" /> </i> + <i t="grand"> <x /> </i> + </colItems> + */ + 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 + <colItems count="9"> + <i> <x /> <x v="3" /> </i> + <i t="default"> <x /> </i> + <i> <x v="1" /> <x v="1" /> </i> + <i r="1"> <x v="2" /> </i> + <i t="default"> <x v="1" /> </i> + <i> <x v="2" /> <x /> </i> + <i r="1"> <x v="4" /> </i> + <i t="default"> <x v="2" /> </i> + <i t="grand"> <x /> </i> + </colItems> + */ + 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 <rowItems> and <colItems> element - under <pivotTableDefinition> 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 <rowItems> - - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); - // check if <rowItems count="8"> - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"8"); - // check if <rowItems> has enough <i> depending on count attribute value - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i", 8); - // check if first <i> has single <x/> element - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", 1); - // check if <x/> of the first <i> element, has v="0" attribute value - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[1]/x:x", "v", u"0"); - - // Column items <colItems> - - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); - // check if <colItems count="5"> - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"5"); - // check if <colItems> has enough <i> depending on count attribute value - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 5); - // check if first <i> has single <x/> element - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i[1]/x:x", 1); - // check if <x/> of the first <i> 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 <i> element of the <rowItems> and <colItems>. 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 <rowItems> and <colItems> 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 <colItems> should not exist - during export. But in Excel, if pivot table refreshed, there will be - - <colItems count="1"> - <i/> - </colItems> - - in the xl/pivotTables/pivotTable1.xml. So, that means we should export <colItems> - without checking the existence of it. - For the sake of completeness, <colItems> exported as: - - <colItems count="1"> - <i t="grand"> - <x v="0"/> - </i> - </colItems> - */ - - // Row items <rowItems> - - // check if <rowItems count="3"> - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"3"); - // check if last <i> element, has t="grand" - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems/x:i[last()]", "t", u"grand"); - - // Column items <colItems> - - // check if <colItems count="1"> - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", "count", u"1"); - // check if <colItems> has only a single <i> element - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", 1); - // check if <i> element has t="grand" - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems/x:i", "t", u"grand"); - // check if <i> has <x v="0"/> - 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 - // <sharedItems containsBlank="1" count="..."> (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 <rowItems> - - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", 1); - // check if <rowItems count="4"> - assertXPath(pSheet, "/x:pivotTableDefinition/x:rowItems", "count", u"4"); - - // Column items <colItems> - - assertXPath(pSheet, "/x:pivotTableDefinition/x:colItems", 1); - // check if <colItems count="5"> - 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 <pivot/PivotTableResultTraverser.hxx> + +#include <miscuno.hxx> +#include <unonames.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNamed.hpp> + +#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> +#include <com/sun/star/sheet/DataPilotFieldLayoutMode.hpp> +#include <com/sun/star/sheet/DataPilotOutputRangeType.hpp> +#include <com/sun/star/sheet/XDimensionsSupplier.hpp> +#include <com/sun/star/sheet/XHierarchiesSupplier.hpp> +#include <com/sun/star/sheet/XLevelsSupplier.hpp> +#include <com/sun/star/sheet/XDataPilotResults.hpp> +#include <com/sun/star/sheet/XDataPilotMemberResults.hpp> +#include <com/sun/star/sheet/MemberResultFlags.hpp> +#include <com/sun/star/sheet/XMembersSupplier.hpp> + +using namespace css; + +namespace sc +{ +namespace pivot +{ +uno::Any getMemberForLevel(uno::Reference<uno::XInterface> const& xLevel, OUString const& rName) +{ + uno::Reference<sheet::XMembersSupplier> xMembersSupplier(xLevel, uno::UNO_QUERY); + if (xMembersSupplier.is()) + { + uno::Reference<sheet::XMembersAccess> xMembers = xMembersSupplier->getMembers(); + if (xMembers.is()) + { + if (xMembers->hasByName(rName)) + return xMembers->getByName(rName); + } + } + return uno::Any(); +} +} + +// PivotTableResultTraverser + +void PivotTableResultTraverser::traverse() +{ + uno::Reference<sheet::XDimensionsSupplier> xDimensionsSupplier(mrDPObject.GetSource()); + uno::Reference<container::XIndexAccess> xDimensions + = new ScNameToIndexAccess(xDimensionsSupplier->getDimensions()); + + for (sal_Int32 nDimension = 0; nDimension < xDimensions->getCount(); nDimension++) + { + uno::Reference<uno::XInterface> xDimension(xDimensions->getByIndex(nDimension), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xDimensionPropertySet(xDimension, uno::UNO_QUERY); + uno::Reference<sheet::XHierarchiesSupplier> 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<container::XIndexAccess> xHierarchies + = new ScNameToIndexAccess(xDimensionSupplier->getHierarchies()); + sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty(xDimensionPropertySet, + SC_UNO_DP_USEDHIERARCHY); + if (nHierarchy >= xHierarchies->getCount()) + nHierarchy = 0; + + uno::Reference<sheet::XLevelsSupplier> xLevelsSupplier( + xHierarchies->getByIndex(nHierarchy), uno::UNO_QUERY); + if (xLevelsSupplier.is()) + { + uno::Reference<container::XIndexAccess> xLevels + = new ScNameToIndexAccess(xLevelsSupplier->getLevels()); + if (xLevels.is()) + { + for (sal_Int32 nLevel = 0; nLevel < xLevels->getCount(); nLevel++) + { + uno::Reference<uno::XInterface> xLevel(xLevels->getByIndex(nLevel), + uno::UNO_QUERY); + uno::Reference<container::XNamed> xLevelName(xLevel, uno::UNO_QUERY); + uno::Reference<sheet::XDataPilotMemberResults> xLevelResult( + xLevel, uno::UNO_QUERY); + + if (xLevelName.is() && xLevelResult.is()) + { + mrVisitor.startLevel(nLevel, xLevel, xLevelName->getName()); + + const uno::Sequence<sheet::MemberResult> 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 <xepivotxml.hxx> #include <dpcache.hxx> #include <pivot/PivotTableFormats.hxx> +#include <pivot/PivotTableResultTraverser.hxx> #include <dpdimsave.hxx> #include <dpitemdata.hxx> #include <dpobject.hxx> @@ -30,6 +31,7 @@ #include <sax/fastattribs.hxx> #include <sax/fshelper.hxx> #include <svl/numformat.hxx> +#include <miscuno.hxx> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> @@ -37,8 +39,15 @@ #include <com/sun/star/sheet/DataPilotFieldLayoutMode.hpp> #include <com/sun/star/sheet/DataPilotOutputRangeType.hpp> #include <com/sun/star/sheet/XDimensionsSupplier.hpp> +#include <com/sun/star/sheet/XHierarchiesSupplier.hpp> +#include <com/sun/star/sheet/XLevelsSupplier.hpp> +#include <com/sun/star/sheet/XDataPilotResults.hpp> +#include <com/sun/star/sheet/XDataPilotMemberResults.hpp> +#include <com/sun/star/sheet/MemberResultFlags.hpp> +#include <com/sun/star/sheet/XMembersSupplier.hpp> #include <vector> +#include <unordered_map> 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<OUString> maFieldOrder; + std::vector<std::unordered_map<OUString, RowOrColumnItemsData>> maItemsData; + std::unordered_map<OUString, std::unordered_map<OUString, sal_Int32>> 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<OUString, sal_Int32>{}); + } + + 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<uno::XInterface> const& /*xDimension*/, sheet::DataPilotFieldOrientation eOrientation) override + { + meCurrentOrientation = eOrientation; + } + + void endDimension() override + { + meCurrentOrientation = sheet::DataPilotFieldOrientation_HIDDEN; + } + + void startLevel(sal_Int32 /*nLevelIndex*/, uno::Reference<uno::XInterface> 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<OUString, long> NameToIdMapType; + auto& rDPObjectModifiable = const_cast<ScDPObject&>(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<tools::Long> aPageFields; std::vector<DataField> aDataFields; - // we should always export <rowItems> and <colItems>, 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 <rowItems count="..."> of pivotTable*.xml - tools::Long nColItemsCount = 1; // for <colItems count="..."> 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<ScDPLabelData::Member> aMembers; { // We need to get the members in actual order, getting which requires non-const reference here - auto& dpo = const_cast<ScDPObject&>(rDPObj); - dpo.GetMembers(i, dpo.GetUsedHierarchy(i), aMembers); + rDPObjectModifiable.GetMembers(i, rDPObjectModifiable.GetUsedHierarchy(i), aMembers); } std::vector<OUString> 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<size_t, bool> > aMemberSequence; std::set<size_t> 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<size_t>(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); } - // <rowItems> - if (nRowItemsCount > 0) - { - pPivotStrm->startElement(XML_rowItems, XML_count, OString::number(nRowItemsCount)); - - // export nRowItemsCount times <i> and <x> elements - for (tools::Long nCount = 0; nCount < nRowItemsCount; ++nCount) - { - /* we should add t="grand" to the last <i> 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 <i> 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); + RowColumnItemsDataVisitor aVisitor(aRowMemberResultData, aColumnMemberResultData); + sc::PivotTableResultTraverser aTraverser(rDPObjectModifiable, aVisitor); + aTraverser.traverse(); - pPivotStrm->singleElement(XML_x, XML_v, OString::number(nCount)); - pPivotStrm->endElement(XML_i); - } + // <rowItems> - pPivotStrm->endElement(XML_rowItems); - } + writeRowColumnItems(XML_rowItems, aRowMemberResultData, pPivotStrm); // <colFields> @@ -1124,31 +1342,8 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP } // <colItems> - if (nColItemsCount > 0) - { - pPivotStrm->startElement(XML_colItems, XML_count, OString::number(nColItemsCount)); - - // export nColItemsCount times <i> and <x> elements - for (tools::Long nCount = 0; nCount < nColItemsCount; ++nCount) - { - /* we should add t="grand" to the last <i> 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 <i> 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); // <pageFields>
