[Libreoffice-commits] core.git: sc/source

Mike Kaganski mike.kaganski at collabora.com
Thu Jun 22 22:49:26 UTC 2017


 sc/source/filter/excel/xepivotxml.cxx |  103 ++++++++++++++++++++++++++++++++--
 1 file changed, 98 insertions(+), 5 deletions(-)

New commits:
commit 430774c4edcdba3e6a4e383d9ac9345a517e227f
Author: Mike Kaganski <mike.kaganski at collabora.com>
Date:   Tue Jun 13 22:00:51 2017 +0300

    tdf#89139: dump pivotField items
    
    This makes the pivot table exported to XLSX refreshable (does not
    crash Excel on pivot table refresh).
    
    Change-Id: Icc35795cd116e091b75bb1d4a603c52ccc71c44d
    Reviewed-on: https://gerrit.libreoffice.org/39018
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Kohei Yoshida <libreoffice at kohei.us>

diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx
index 04d85f0a9ff8..bf820838e0ee 100644
--- a/sc/source/filter/excel/xepivotxml.cxx
+++ b/sc/source/filter/excel/xepivotxml.cxx
@@ -13,6 +13,7 @@
 #include <dpsave.hxx>
 #include <dputil.hxx>
 #include <document.hxx>
+#include <generalfunction.hxx>
 
 #include <oox/export/utils.hxx>
 #include <oox/token/namespaces.hxx>
@@ -414,6 +415,47 @@ struct DataField
     DataField( long nPos, const ScDPSaveDimension* pDim ) : mnPos(nPos), mpDim(pDim) {}
 };
 
+/** Returns a OOXML subtotal function name string. See ECMA-376-1:2016 18.18.43 */
+OString GetSubtotalFuncName(ScGeneralFunction eFunc)
+{
+    switch (eFunc)
+    {
+        case ScGeneralFunction::SUM:       return "sum";
+        case ScGeneralFunction::COUNT:     return "count";
+        case ScGeneralFunction::AVERAGE:   return "avg";
+        case ScGeneralFunction::MAX:       return "max";
+        case ScGeneralFunction::MIN:       return "min";
+        case ScGeneralFunction::PRODUCT:   return "product";
+        case ScGeneralFunction::COUNTNUMS: return "countA";
+        case ScGeneralFunction::STDEV:     return "stdDev";
+        case ScGeneralFunction::STDEVP:    return "stdDevP";
+        case ScGeneralFunction::VAR:       return "var";
+        case ScGeneralFunction::VARP:      return "varP";
+        default:;
+    }
+    return "default";
+}
+
+sal_Int32 GetSubtotalAttrToken(ScGeneralFunction eFunc)
+{
+    switch (eFunc)
+    {
+        case ScGeneralFunction::SUM:       return XML_sumSubtotal;
+        case ScGeneralFunction::COUNT:     return XML_countSubtotal;
+        case ScGeneralFunction::AVERAGE:   return XML_avgSubtotal;
+        case ScGeneralFunction::MAX:       return XML_maxSubtotal;
+        case ScGeneralFunction::MIN:       return XML_minSubtotal;
+        case ScGeneralFunction::PRODUCT:   return XML_productSubtotal;
+        case ScGeneralFunction::COUNTNUMS: return XML_countASubtotal;
+        case ScGeneralFunction::STDEV:     return XML_stdDevSubtotal;
+        case ScGeneralFunction::STDEVP:    return XML_stdDevPSubtotal;
+        case ScGeneralFunction::VAR:       return XML_varSubtotal;
+        case ScGeneralFunction::VARP:      return XML_varPSubtotal;
+        default:;
+    }
+    return XML_defaultSubtotal;
+}
+
 }
 
 void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rDPObj, sal_Int32 nCacheId )
@@ -554,8 +596,9 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
         XML_count, OString::number(static_cast<long>(aCachedDims.size())).getStr(),
         FSEND);
 
-    for (const ScDPSaveDimension* pDim : aCachedDims)
+    for (size_t i = 0; i < nFieldCount; ++i)
     {
+        const ScDPSaveDimension* pDim = aCachedDims[i];
         if (!pDim)
         {
             pPivotStrm->singleElement(XML_pivotField,
@@ -584,13 +627,63 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP
             continue;
         }
 
-        pPivotStrm->startElement(XML_pivotField,
-            XML_axis, toOOXMLAxisType(eOrient),
-            XML_showAll, BS(false),
+        // Dump field items.
+        css::uno::Sequence<OUString> aMemberNames;
+        {
+            // We need to get the members in actual order, getting which requires non-const reference here
+            auto& dpo = const_cast<ScDPObject&>(rDPObj);
+            dpo.GetMemberNames(i, aMemberNames);
+        }
+
+        const ScDPCache::ScDPItemDataVec& rCacheFieldItems = rCache.GetDimMemberValues(i);
+        std::vector<size_t> aMemberSequence;
+        for (const OUString& sMemberName : aMemberNames)
+        {
+            auto it = std::find_if(rCacheFieldItems.begin(), rCacheFieldItems.end(),
+                [&sMemberName](const ScDPItemData& arg) -> bool { return arg.GetString() == sMemberName; });
+            if (it != rCacheFieldItems.end())
+            {
+                aMemberSequence.push_back(it - rCacheFieldItems.begin());
+            }
+        }
+
+        auto pAttList = sax_fastparser::FastSerializerHelper::createAttrList();
+        pAttList->add(XML_axis, toOOXMLAxisType(eOrient));
+        pAttList->add(XML_showAll, BS(false));
+
+        long nSubTotalCount = pDim->GetSubTotalsCount();
+        std::vector<OString> aSubtotalSequence;
+        for (long nSubTotal = 0; nSubTotal < nSubTotalCount; ++nSubTotal)
+        {
+            ScGeneralFunction eFunc = pDim->GetSubTotalFunc(nSubTotal);
+            aSubtotalSequence.push_back(GetSubtotalFuncName(eFunc));
+            sal_Int32 nAttToken = GetSubtotalAttrToken(eFunc);
+            if (!pAttList->hasAttribute(nAttToken))
+                pAttList->add(nAttToken, BS(true));
+        }
+
+        sax_fastparser::XFastAttributeListRef xAttributeList(pAttList);
+        pPivotStrm->startElement(XML_pivotField, xAttributeList);
+
+        pPivotStrm->startElement(XML_items,
+            XML_count, OString::number(static_cast<long>(aMemberSequence.size() + aSubtotalSequence.size())),
             FSEND);
 
-        // TODO : Dump field items.
+        for (size_t nMember : aMemberSequence)
+        {
+            pPivotStrm->singleElement(XML_item,
+                XML_x, OString::number(static_cast<long>(nMember)),
+                FSEND);
+        }
+
+        for (const OString& sSubtotal : aSubtotalSequence)
+        {
+            pPivotStrm->singleElement(XML_item,
+                XML_t, sSubtotal,
+                FSEND);
+        }
 
+        pPivotStrm->endElement(XML_items);
         pPivotStrm->endElement(XML_pivotField);
     }
 


More information about the Libreoffice-commits mailing list