sc/inc/dputil.hxx | 2 sc/qa/unit/pivottable_filters_test.cxx | 167 +++++++++++++++++---------------- sc/source/core/data/dpobject.cxx | 5 sc/source/filter/excel/xepivotxml.cxx | 120 ++++++++++++++++++++++- 4 files changed, 208 insertions(+), 86 deletions(-)
New commits: commit b4f61d5bb36130198a83a8cdcf060ebddea07b23 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Fri Mar 22 14:06:19 2019 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Jun 19 07:09:02 2019 +0200 tdf#113908: Implement exporting pivot tables' groups fields to XSLX Two tests in sc/qa/unit/pivottable_filters_test.cxx were extended to also test round-trip of group fields in XLSX. Change-Id: I70b7c15b09040c64fa1da2f88001af7ba16f2c6f Reviewed-on: https://gerrit.libreoffice.org/69653 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/70687 Tested-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/74328 diff --git a/sc/inc/dputil.hxx b/sc/inc/dputil.hxx index b2539a159bce..735843b84578 100644 --- a/sc/inc/dputil.hxx +++ b/sc/inc/dputil.hxx @@ -33,7 +33,7 @@ public: SC_DLLPUBLIC static OUString createDuplicateDimensionName(const OUString& rOriginal, size_t nDupCount); - static OUString getDateGroupName( + SC_DLLPUBLIC static OUString getDateGroupName( sal_Int32 nDatePart, sal_Int32 nValue, SvNumberFormatter* pFormatter, double fStart, double fEnd); diff --git a/sc/qa/unit/pivottable_filters_test.cxx b/sc/qa/unit/pivottable_filters_test.cxx index 2c3448b78cfc..84ad5eade972 100644 --- a/sc/qa/unit/pivottable_filters_test.cxx +++ b/sc/qa/unit/pivottable_filters_test.cxx @@ -53,8 +53,8 @@ public: void testPivotTableSharedCacheGroupODS(); void testGetPivotDataXLS(); void testPivotTableSharedGroupXLSX(); - void testPivotTableSharedDateGroupXLSX(); - void testPivotTableSharedNestedDateGroupXLSX(); + void testPivotTableSharedDateGroupXLSX(); // + export + void testPivotTableSharedNestedDateGroupXLSX(); // + export void testPivotTableSharedNumGroupXLSX(); void testPivotTableNoColumnsLayout(); void testTdf112501(); @@ -532,86 +532,99 @@ void ScPivotTableFiltersTest::testPivotTableSharedGroupXLSX() void ScPivotTableFiltersTest::testPivotTableSharedDateGroupXLSX() { - ScDocShellRef xDocSh = loadDoc("pivot-table/shared-dategroup.", FORMAT_XLSX); - CPPUNIT_ASSERT_MESSAGE("Failed to load file", xDocSh.is()); - ScDocument& rDoc = xDocSh->GetDocument(); - - // Check whether right date labels are imported for both tables - // First table - CPPUNIT_ASSERT_EQUAL(OUString("a"), rDoc.GetString(ScAddress(0, 3, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("1965"), rDoc.GetString(ScAddress(0, 4, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("1989"), rDoc.GetString(ScAddress(0, 5, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("2000"), rDoc.GetString(ScAddress(0, 6, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("2004"), rDoc.GetString(ScAddress(0, 7, 1))); - // TODO: check why this fails with 2005 - // CPPUNIT_ASSERT_EQUAL(OUString("2007"), rDoc.GetString(ScAddress(0,8,1))); - - // Second table - CPPUNIT_ASSERT_EQUAL(OUString("a"), rDoc.GetString(ScAddress(5, 3, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("1965"), rDoc.GetString(ScAddress(5, 4, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("1989"), rDoc.GetString(ScAddress(5, 5, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("2000"), rDoc.GetString(ScAddress(5, 6, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("2004"), rDoc.GetString(ScAddress(5, 7, 1))); - // TODO: check why this fails with 2005 - // CPPUNIT_ASSERT_EQUAL(OUString("2007"), rDoc.GetString(ScAddress(5,8,1))); - - // There should be exactly 2 pivot tables and 1 cache. - ScDPCollection* pDPs = rDoc.GetDPCollection(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pDPs->GetCount()); - - ScDPCollection::SheetCaches& rSheetCaches = pDPs->GetSheetCaches(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rSheetCaches.size()); - - const ScDPCache* pCache = rSheetCaches.getExistingCache(ScRange(0, 0, 0, 9, 24, 0)); - CPPUNIT_ASSERT_MESSAGE("Pivot cache is expected for A1:J25 on the first sheet.", pCache); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(10), pCache->GetFieldCount()); - - xDocSh->DoClose(); + auto testThis = [](ScDocShellRef& xDocSh) { + CPPUNIT_ASSERT_MESSAGE("Failed to load file", xDocSh.is()); + ScDocument& rDoc = xDocSh->GetDocument(); + + // Check whether right date labels are imported for both tables + // First table + CPPUNIT_ASSERT_EQUAL(OUString("a"), rDoc.GetString(ScAddress(0, 3, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("1965"), rDoc.GetString(ScAddress(0, 4, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("1989"), rDoc.GetString(ScAddress(0, 5, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("2000"), rDoc.GetString(ScAddress(0, 6, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("2004"), rDoc.GetString(ScAddress(0, 7, 1))); + // TODO: check why this fails with 2005 + // CPPUNIT_ASSERT_EQUAL(OUString("2007"), rDoc.GetString(ScAddress(0,8,1))); + + // Second table + CPPUNIT_ASSERT_EQUAL(OUString("a"), rDoc.GetString(ScAddress(5, 3, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("1965"), rDoc.GetString(ScAddress(5, 4, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("1989"), rDoc.GetString(ScAddress(5, 5, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("2000"), rDoc.GetString(ScAddress(5, 6, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("2004"), rDoc.GetString(ScAddress(5, 7, 1))); + // TODO: check why this fails with 2005 + // CPPUNIT_ASSERT_EQUAL(OUString("2007"), rDoc.GetString(ScAddress(5,8,1))); + + // There should be exactly 2 pivot tables and 1 cache. + ScDPCollection* pDPs = rDoc.GetDPCollection(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pDPs->GetCount()); + + ScDPCollection::SheetCaches& rSheetCaches = pDPs->GetSheetCaches(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rSheetCaches.size()); + + const ScDPCache* pCache = rSheetCaches.getExistingCache(ScRange(0, 0, 0, 9, 24, 0)); + CPPUNIT_ASSERT_MESSAGE("Pivot cache is expected for A1:J25 on the first sheet.", pCache); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(10), pCache->GetFieldCount()); + }; + ScDocShellRef xDocSh1 = loadDoc("pivot-table/shared-dategroup.", FORMAT_XLSX); + testThis(xDocSh1); + // Now test round-trip of group fields + ScDocShellRef xDocSh2 = saveAndReload(xDocSh1.get(), FORMAT_XLSX); + testThis(xDocSh2); + xDocSh2->DoClose(); + xDocSh1->DoClose(); } void ScPivotTableFiltersTest::testPivotTableSharedNestedDateGroupXLSX() { - ScDocShellRef xDocSh = loadDoc("pivot-table/shared-nested-dategroup.", FORMAT_XLSX); - CPPUNIT_ASSERT_MESSAGE("Failed to load file", xDocSh.is()); - ScDocument& rDoc = xDocSh->GetDocument(); - - // Check whether right date groups are imported for both tables - // First table - CPPUNIT_ASSERT_EQUAL(OUString("Years"), rDoc.GetString(ScAddress(0, 3, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("1965"), rDoc.GetString(ScAddress(0, 4, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("1989"), rDoc.GetString(ScAddress(0, 11, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("2000"), rDoc.GetString(ScAddress(0, 18, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("2004"), rDoc.GetString(ScAddress(0, 21, 1))); - // TODO: check why this fails with the empty string - //CPPUNIT_ASSERT_EQUAL(OUString("2007"), rDoc.GetString(ScAddress(0,32,1))); - CPPUNIT_ASSERT_EQUAL(OUString("Quarters"), rDoc.GetString(ScAddress(1, 3, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("a"), rDoc.GetString(ScAddress(2, 3, 1))); - - // Second table - CPPUNIT_ASSERT_EQUAL(OUString("Years"), rDoc.GetString(ScAddress(6, 3, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("1965"), rDoc.GetString(ScAddress(6, 4, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("1989"), rDoc.GetString(ScAddress(6, 11, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("2000"), rDoc.GetString(ScAddress(6, 18, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("2004"), rDoc.GetString(ScAddress(6, 21, 1))); - // TODO: check why this fails with the empty string - //CPPUNIT_ASSERT_EQUAL(OUString("2007"), rDoc.GetString(ScAddress(6,31,1))); - CPPUNIT_ASSERT_EQUAL(OUString("Quarters"), rDoc.GetString(ScAddress(7, 3, 1))); - CPPUNIT_ASSERT_EQUAL(OUString("a"), rDoc.GetString(ScAddress(8, 3, 1))); - - // There should be exactly 2 pivot tables and 1 cache. - ScDPCollection* pDPs = rDoc.GetDPCollection(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pDPs->GetCount()); - - ScDPCollection::SheetCaches& rSheetCaches = pDPs->GetSheetCaches(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rSheetCaches.size()); - - const ScDPCache* pCache = rSheetCaches.getExistingCache(ScRange(0, 0, 0, 9, 24, 0)); - CPPUNIT_ASSERT_MESSAGE("Pivot cache is expected for A1:J25 on the first sheet.", pCache); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(10), pCache->GetFieldCount()); - // Two new group field is created - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pCache->GetGroupFieldCount()); + auto testThis = [](ScDocShellRef& xDocSh) { + CPPUNIT_ASSERT_MESSAGE("Failed to load file", xDocSh.is()); + ScDocument& rDoc = xDocSh->GetDocument(); + + // Check whether right date groups are imported for both tables + // First table + CPPUNIT_ASSERT_EQUAL(OUString("Years"), rDoc.GetString(ScAddress(0, 3, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("1965"), rDoc.GetString(ScAddress(0, 4, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("1989"), rDoc.GetString(ScAddress(0, 11, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("2000"), rDoc.GetString(ScAddress(0, 18, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("2004"), rDoc.GetString(ScAddress(0, 21, 1))); + // TODO: check why this fails with the empty string + //CPPUNIT_ASSERT_EQUAL(OUString("2007"), rDoc.GetString(ScAddress(0,32,1))); + CPPUNIT_ASSERT_EQUAL(OUString("Quarters"), rDoc.GetString(ScAddress(1, 3, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("a"), rDoc.GetString(ScAddress(2, 3, 1))); + + // Second table + CPPUNIT_ASSERT_EQUAL(OUString("Years"), rDoc.GetString(ScAddress(6, 3, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("1965"), rDoc.GetString(ScAddress(6, 4, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("1989"), rDoc.GetString(ScAddress(6, 11, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("2000"), rDoc.GetString(ScAddress(6, 18, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("2004"), rDoc.GetString(ScAddress(6, 21, 1))); + // TODO: check why this fails with the empty string + //CPPUNIT_ASSERT_EQUAL(OUString("2007"), rDoc.GetString(ScAddress(6,31,1))); + CPPUNIT_ASSERT_EQUAL(OUString("Quarters"), rDoc.GetString(ScAddress(7, 3, 1))); + CPPUNIT_ASSERT_EQUAL(OUString("a"), rDoc.GetString(ScAddress(8, 3, 1))); + + // There should be exactly 2 pivot tables and 1 cache. + ScDPCollection* pDPs = rDoc.GetDPCollection(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pDPs->GetCount()); + + ScDPCollection::SheetCaches& rSheetCaches = pDPs->GetSheetCaches(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rSheetCaches.size()); + + const ScDPCache* pCache = rSheetCaches.getExistingCache(ScRange(0, 0, 0, 9, 24, 0)); + CPPUNIT_ASSERT_MESSAGE("Pivot cache is expected for A1:J25 on the first sheet.", pCache); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(10), pCache->GetFieldCount()); + // Two new group field is created + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pCache->GetGroupFieldCount()); + }; - xDocSh->DoClose(); + ScDocShellRef xDocSh1 = loadDoc("pivot-table/shared-nested-dategroup.", FORMAT_XLSX); + testThis(xDocSh1); + // Now test round-trip of group fields + ScDocShellRef xDocSh2 = saveAndReload(xDocSh1.get(), FORMAT_XLSX); + testThis(xDocSh2); + xDocSh2->DoClose(); + xDocSh1->DoClose(); } void ScPivotTableFiltersTest::testPivotTableSharedNumGroupXLSX() diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx index f1d5d8644f62..bc6bf4a0d1d6 100644 --- a/sc/source/core/data/dpobject.cxx +++ b/sc/source/core/data/dpobject.cxx @@ -1233,6 +1233,11 @@ OUString ScDPObject::GetDimName( long nDim, bool& rIsDataLayout, sal_Int32* pFla } } } + else if (ScDPTableData* pData = GetTableData()) + { + aRet = pData->getDimensionName(nDim); + rIsDataLayout = pData->getIsDataLayoutDimension(nDim); + } return aRet; } diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx index 5538bd8770b1..e6af90295288 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 <dpitemdata.hxx> +#include <dpdimsave.hxx> #include <dpobject.hxx> #include <dpsave.hxx> #include <dputil.hxx> @@ -22,6 +23,7 @@ #include <sax/tools/converter.hxx> #include <sax/fastattribs.hxx> +#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> #include <com/sun/star/sheet/DataPilotFieldLayoutMode.hpp> #include <com/sun/star/sheet/DataPilotOutputRangeType.hpp> @@ -242,10 +244,74 @@ void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream& rStrm, const Entr pDefStrm->endElement(XML_cacheSource); size_t nCount = rCache.GetFieldCount(); + const size_t nGroupFieldCount = rCache.GetGroupFieldCount(); pDefStrm->startElement(XML_cacheFields, - XML_count, OString::number(static_cast<long>(nCount)).getStr(), + XML_count, OString::number(static_cast<long>(nCount + nGroupFieldCount)).getStr(), FSEND); + auto WriteFieldGroup = [this, &rCache, pDefStrm](size_t i, size_t base) { + const sal_Int32 nDatePart = rCache.GetGroupType(i); + if (!nDatePart) + return; + OString sGroupBy; + switch (nDatePart) + { + case sheet::DataPilotFieldGroupBy::SECONDS: + sGroupBy = "seconds"; + break; + case sheet::DataPilotFieldGroupBy::MINUTES: + sGroupBy = "minutes"; + break; + case sheet::DataPilotFieldGroupBy::HOURS: + sGroupBy = "hours"; + break; + case sheet::DataPilotFieldGroupBy::DAYS: + sGroupBy = "days"; + break; + case sheet::DataPilotFieldGroupBy::MONTHS: + sGroupBy = "months"; + break; + case sheet::DataPilotFieldGroupBy::QUARTERS: + sGroupBy = "quarters"; + break; + case sheet::DataPilotFieldGroupBy::YEARS: + sGroupBy = "years"; + break; + } + + // fieldGroup element + pDefStrm->startElement(XML_fieldGroup, XML_base, OString::number(base), FSEND); + + SvNumberFormatter& rFormatter = GetFormatter(); + + // rangePr element + const ScDPNumGroupInfo* pGI = rCache.GetNumGroupInfo(i); + auto pGroupAttList = sax_fastparser::FastSerializerHelper::createAttrList(); + pGroupAttList->add(XML_groupBy, sGroupBy); + // Possible TODO: find out when to write autoStart attribute for years grouping + pGroupAttList->add(XML_startDate, GetExcelFormattedDate(pGI->mfStart, rFormatter).toUtf8()); + pGroupAttList->add(XML_endDate, GetExcelFormattedDate(pGI->mfEnd, rFormatter).toUtf8()); + if (pGI->mfStep) + pGroupAttList->add(XML_groupInterval, OString::number(pGI->mfStep)); + pDefStrm->singleElement(XML_rangePr, pGroupAttList); + + // groupItems element + ScfInt32Vec aGIIds; + rCache.GetGroupDimMemberIds(i, aGIIds); + pDefStrm->startElement(XML_groupItems, XML_count, OString::number(aGIIds.size()), FSEND); + for (auto nGIId : aGIIds) + { + const ScDPItemData* pGIData = rCache.GetItemDataById(i, nGIId); + if (pGIData->GetType() == ScDPItemData::GroupValue) + { + OUString sVal = rCache.GetFormattedString(i, *pGIData, false); + pDefStrm->singleElement(XML_s, XML_v, sVal.toUtf8(), FSEND); + } + } + pDefStrm->endElement(XML_groupItems); + pDefStrm->endElement(XML_fieldGroup); + }; + for (size_t i = 0; i < nCount; ++i) { OUString aName = rCache.GetDimensionName(i); @@ -396,7 +462,7 @@ void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream& rStrm, const Entr XML_v, XclXmlUtils::ToOString(rItem.GetString()), FSEND); break; - case ScDPItemData::GroupValue: + case ScDPItemData::GroupValue: // Should not happen here! case ScDPItemData::RangeStart: // TODO : What do we do with these types? pDefStrm->singleElement(XML_m, FSEND); @@ -408,6 +474,29 @@ void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream& rStrm, const Entr } pDefStrm->endElement(XML_sharedItems); + + WriteFieldGroup(i, i); + + pDefStrm->endElement(XML_cacheField); + } + + ScDPObject* pDPObject + = rCache.GetAllReferences().empty() ? nullptr : *rCache.GetAllReferences().begin(); + + for (size_t i = nCount; pDPObject && i < nCount + nGroupFieldCount; ++i) + { + bool bDummy = false; + const OUString aName = pDPObject->GetDimName(i, bDummy); + ScDPSaveData* pSaveData = pDPObject->GetSaveData(); + assert(pSaveData); + const ScDPSaveGroupDimension* pDim = pSaveData->GetDimensionData()->GetNamedGroupDim(aName); + assert(pDim); + const size_t nBase = rCache.GetDimensionIndex(pDim->GetSourceDimName()); + + pDefStrm->startElement(XML_cacheField, XML_name, aName.toUtf8(), XML_numFmtId, + OString::number(0).getStr(), XML_databaseField, ToPsz10(false), + FSEND); + WriteFieldGroup(i, nBase); pDefStrm->endElement(XML_cacheField); } @@ -601,14 +690,15 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP const ScDPSaveData& rSaveData = *rDPObj.GetSaveData(); - size_t nFieldCount = rCache.GetFieldCount(); + size_t nFieldCount = rCache.GetFieldCount() + rCache.GetGroupFieldCount(); std::vector<const ScDPSaveDimension*> aCachedDims; NameToIdMapType aNameToIdMap; aCachedDims.reserve(nFieldCount); for (size_t i = 0; i < nFieldCount; ++i) { - OUString aName = rCache.GetDimensionName(i); + bool bDummy = false; + OUString aName = const_cast<ScDPObject&>(rDPObj).GetDimName(i, bDummy); aNameToIdMap.emplace(aName, aCachedDims.size()); const ScDPSaveDimension* pDim = rSaveData.GetExistingDimensionByName(aName); aCachedDims.push_back(pDim); @@ -802,7 +892,17 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP dpo.GetMembers(i, dpo.GetUsedHierarchy(i), aMembers); } - const ScDPCache::ScDPItemDataVec& rCacheFieldItems = rCache.GetDimMemberValues(i); + std::vector<const ScDPItemData*> rCacheFieldItems; + if (i < rCache.GetFieldCount() && !rCache.GetGroupType(i)) + for (const auto& it : rCache.GetDimMemberValues(i)) + rCacheFieldItems.push_back(&it); + else + { + ScfInt32Vec aGIIds; + rCache.GetGroupDimMemberIds(i, aGIIds); + for (const sal_Int32 id : aGIIds) + rCacheFieldItems.push_back(rCache.GetItemDataById(i, id)); + } const auto iCacheFieldItems_begin = rCacheFieldItems.begin(), iCacheFieldItems_end = rCacheFieldItems.end(); // The pair contains the member index in cache and if it is hidden std::vector< std::pair<size_t, bool> > aMemberSequence; @@ -812,13 +912,17 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP for (auto it = iCacheFieldItems_begin; it != iCacheFieldItems_end; ++it) { OUString sFormattedName; - if (it->HasStringData() || it->IsEmpty()) + if ((*it)->GetType() == ScDPItemData::GroupValue) + { + sFormattedName = rCache.GetFormattedString(i, **it, false); + } + else if ((*it)->HasStringData() || (*it)->IsEmpty()) { - sFormattedName = it->GetString(); + sFormattedName = (*it)->GetString(); } else { - sFormattedName = const_cast<ScDPObject&>(rDPObj).GetFormattedString(pDim->GetName(), it->GetValue()); + sFormattedName = const_cast<ScDPObject&>(rDPObj).GetFormattedString(pDim->GetName(), (*it)->GetValue()); } if (sFormattedName == rMember.maName) { _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits