diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2017-06-13 22:00:51 +0300 |
---|---|---|
committer | Kohei Yoshida <libreoffice@kohei.us> | 2017-06-23 00:49:04 +0200 |
commit | 430774c4edcdba3e6a4e383d9ac9345a517e227f (patch) | |
tree | d3bc78c67831f2c67635148ad25069c087c1954e | |
parent | ba4831629e93bd6957ed8cfce9cec25f4f8ce5e4 (diff) |
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@libreoffice.org>
Reviewed-by: Kohei Yoshida <libreoffice@kohei.us>
-rw-r--r-- | sc/source/filter/excel/xepivotxml.cxx | 103 |
1 files changed, 98 insertions, 5 deletions
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); } |