sc/qa/unit/data/ods/tdf123225_pivotTable_no_col_items.ods |binary sc/qa/unit/pivottable_filters_test.cxx | 76 +++++++++++++- sc/source/filter/excel/xepivotxml.cxx | 35 +++++- 3 files changed, 104 insertions(+), 7 deletions(-)
New commits: commit 3b3ba9c329b691ef600ad9ecc419e818b385ce0e Author: Bayram Çiçek <bayram.ci...@collabora.com> AuthorDate: Wed Feb 26 18:33:06 2025 +0300 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Thu Feb 27 09:53:36 2025 +0100 tdf#123225 - export <i t="grand"> of row/colItems in xl/pivotTables/pivotTable*.xml. - we should always export (.ods to .xlsx) <rowItems> and <colItems>, even if the pivot table does not contain col/row items. 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. - 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. we shouldn't need "refresh" to use all functions/items in the context menu. - 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 <i> element. - added testTdf123225PivotTableNoColItems unit test to check if <i t="grand"> exported. also, added some useful information in the comment section for future tests/issues. Signed-off-by: Bayram Çiçek <bayram.ci...@collabora.com> Change-Id: I22b42ddb4a27c4b7b88ad8a71376c2c82d5a735a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182242 Tested-by: Jenkins Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/sc/qa/unit/data/ods/tdf123225_pivotTable_no_col_items.ods b/sc/qa/unit/data/ods/tdf123225_pivotTable_no_col_items.ods new file mode 100644 index 000000000000..0e2b601efa44 Binary files /dev/null and b/sc/qa/unit/data/ods/tdf123225_pivotTable_no_col_items.ods differ diff --git a/sc/qa/unit/pivottable_filters_test.cxx b/sc/qa/unit/pivottable_filters_test.cxx index 276dcd324248..fe33c66d447c 100644 --- a/sc/qa/unit/pivottable_filters_test.cxx +++ b/sc/qa/unit/pivottable_filters_test.cxx @@ -133,8 +133,24 @@ CPPUNIT_TEST_FIXTURE(ScPivotTableFiltersTest, testTdf123225PivotTableRowColItems 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 + /* + - 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> @@ -161,6 +177,62 @@ CPPUNIT_TEST_FIXTURE(ScPivotTableFiltersTest, testTdf123225PivotTableRowColItems 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(u"Calc Office Open XML"_ustr); + + 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, testPivotTableNamedRangeSourceODS) { createScDoc("ods/pivot-table-named-range-source.ods"); diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx index c0c9946fa8b5..65e5d9c61839 100644 --- a/sc/source/filter/excel/xepivotxml.cxx +++ b/sc/source/filter/excel/xepivotxml.cxx @@ -776,8 +776,11 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP std::vector<tools::Long> aPageFields; std::vector<DataField> aDataFields; - tools::Long nRowItemsCount = 0; // for <rowItems count="..."> of pivotTable*.xml - tools::Long nColItemsCount = 0; // for <colItems count="..."> of pivotTable*.xml + // 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 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 @@ -1064,7 +1067,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP if (strcmp(toOOXMLAxisType(eOrient), "axisCol") == 0) nColItemsCount = nItemsCount; - else + else if (strcmp(toOOXMLAxisType(eOrient), "axisRow") == 0) nRowItemsCount = nItemsCount; for (const auto & nMember : aMemberSequence) @@ -1110,7 +1113,18 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP // export nRowItemsCount times <i> and <x> elements for (tools::Long nCount = 0; nCount < nRowItemsCount; ++nCount) { - pPivotStrm->startElement(XML_i); + /* 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 == 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); } @@ -1141,7 +1155,18 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP // export nColItemsCount times <i> and <x> elements for (tools::Long nCount = 0; nCount < nColItemsCount; ++nCount) { - pPivotStrm->startElement(XML_i); + /* 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); }