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

Reply via email to