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 <quikee@gmail.com>
Tested-by: Jenkins
This commit is contained in:
Tomaž Vajngerl
2025-12-04 08:20:48 +01:00
committed by Tomaž Vajngerl
parent 8f07dac2d8
commit ca071ce7fd
19 changed files with 1308 additions and 204 deletions
@@ -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, \
+1
View File
@@ -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 \
+4 -4
View File
@@ -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 );
@@ -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: */
@@ -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: */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-131
View File
@@ -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");
@@ -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: */
+264 -69
View File
@@ -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);
}
RowColumnItemsDataVisitor aVisitor(aRowMemberResultData, aColumnMemberResultData);
sc::PivotTableResultTraverser aTraverser(rDPObjectModifiable, aVisitor);
aTraverser.traverse();
// <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);
pPivotStrm->singleElement(XML_x, XML_v, OString::number(nCount));
pPivotStrm->endElement(XML_i);
}
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>