diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2022-03-04 20:40:14 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2022-04-11 01:59:20 +0200 |
commit | 44d599ca1c4bfdf1b803b707cadc7eb5158af979 (patch) | |
tree | 967fa964264fd97ac944805274649e4f0bb0ce62 | |
parent | d076da9d3d9a66ad3f1c28ee2688b9040e8a6ade (diff) |
sc: Sparkline export for OOXML documents + roundtrip test
Change-Id: I4ab93d7ad33867ae817aa98d13ea9bc724b7d710
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132248
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
(cherry picked from commit 0d9aa7388541d10a463c2d0a8d752d234aecfddd)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132776
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r-- | sc/CppunitTest_sc_sparkline_test.mk | 1 | ||||
-rw-r--r-- | sc/Library_scfilt.mk | 1 | ||||
-rw-r--r-- | sc/qa/unit/SparklineImportExportTest.cxx | 21 | ||||
-rw-r--r-- | sc/source/filter/excel/excdoc.cxx | 3 | ||||
-rw-r--r-- | sc/source/filter/excel/export/SparklineExt.cxx | 246 | ||||
-rw-r--r-- | sc/source/filter/inc/export/SparklineExt.hxx | 54 | ||||
-rw-r--r-- | sc/source/filter/inc/xeextlst.hxx | 3 |
7 files changed, 323 insertions, 6 deletions
diff --git a/sc/CppunitTest_sc_sparkline_test.mk b/sc/CppunitTest_sc_sparkline_test.mk index 5dcd9a9921b5..30513b273791 100644 --- a/sc/CppunitTest_sc_sparkline_test.mk +++ b/sc/CppunitTest_sc_sparkline_test.mk @@ -32,6 +32,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_sparkline_test, \ test \ tl \ unotest \ + utl \ vcl \ )) diff --git a/sc/Library_scfilt.mk b/sc/Library_scfilt.mk index da73e3c43f15..eff7cca485e4 100644 --- a/sc/Library_scfilt.mk +++ b/sc/Library_scfilt.mk @@ -130,6 +130,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\ sc/source/filter/excel/xltools \ sc/source/filter/excel/xltracer \ sc/source/filter/excel/xlview \ + sc/source/filter/excel/export/SparklineExt \ sc/source/filter/ftools/fapihelper \ sc/source/filter/ftools/fprogressbar \ sc/source/filter/ftools/ftools \ diff --git a/sc/qa/unit/SparklineImportExportTest.cxx b/sc/qa/unit/SparklineImportExportTest.cxx index cf970ae8995c..f1af8f9d5eb1 100644 --- a/sc/qa/unit/SparklineImportExportTest.cxx +++ b/sc/qa/unit/SparklineImportExportTest.cxx @@ -50,12 +50,10 @@ public: CPPUNIT_TEST_SUITE_END(); }; -void SparklineImportExportTest::testSparklines() +namespace +{ +void checkSparklines(ScDocument& rDocument) { - ScDocShellRef xDocSh = loadDoc(u"Sparklines.", FORMAT_XLSX); - CPPUNIT_ASSERT(xDocSh); - - ScDocument& rDocument = xDocSh->GetDocument(); // Sparkline at Sheet1:A2 { sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 1, 0)); // A2 @@ -148,6 +146,19 @@ void SparklineImportExportTest::testSparklines() sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 3, 0)); //A4 CPPUNIT_ASSERT(!pSparkline); } +} +} // end anonymous namespace + +void SparklineImportExportTest::testSparklines() +{ + ScDocShellRef xDocSh = loadDoc(u"Sparklines.", FORMAT_XLSX); + CPPUNIT_ASSERT(xDocSh); + + checkSparklines(xDocSh->GetDocument()); + + xDocSh = saveAndReload(*xDocSh, FORMAT_XLSX); + + checkSparklines(xDocSh->GetDocument()); xDocSh->DoClose(); } diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx index 6b02457f70f6..529e76971cbc 100644 --- a/sc/source/filter/excel/excdoc.cxx +++ b/sc/source/filter/excel/excdoc.cxx @@ -39,6 +39,7 @@ #include <xecontent.hxx> #include <xeescher.hxx> #include <xepivot.hxx> +#include <export/SparklineExt.hxx> #include <XclExpChangeTrack.hxx> #include <xepivotxml.hxx> #include <xedbdata.hxx> @@ -611,6 +612,8 @@ void ExcTable::FillAsTableXml() // conditional formats Add( new XclExpCondFormatBuffer( GetRoot(), xExtLst ) ); + Add(new xcl::exp::SparklineBuffer(GetRoot(), xExtLst)); + // data validation (DVAL and list of DV records), generated by the cell table aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_DVAL ) ); diff --git a/sc/source/filter/excel/export/SparklineExt.cxx b/sc/source/filter/excel/export/SparklineExt.cxx new file mode 100644 index 000000000000..f0f3cd9e1d98 --- /dev/null +++ b/sc/source/filter/excel/export/SparklineExt.cxx @@ -0,0 +1,246 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <export/SparklineExt.hxx> + +#include <oox/export/utils.hxx> +#include <oox/token/namespaces.hxx> +#include <oox/token/tokens.hxx> + +using namespace oox; + +namespace xcl::exp +{ +SparklineExt::SparklineExt(const XclExpRoot& rRoot, + std::vector<std::shared_ptr<sc::Sparkline>> const& pSparklines) + : XclExpExt(rRoot) +{ + maURI = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"; + + for (auto const& pSparkline : pSparklines) + { + auto* pGroupPointer = pSparkline->getSparklineGroup().get(); + + auto aIterator = m_aSparklineGroupMap.find(pGroupPointer); + if (aIterator == m_aSparklineGroupMap.end()) + { + std::vector<std::shared_ptr<sc::Sparkline>> aSparklineVector; + aSparklineVector.push_back(pSparkline); + m_aSparklineGroupMap.emplace(pGroupPointer, aSparklineVector); + } + else + { + aIterator->second.push_back(pSparkline); + } + } +} + +void SparklineExt::SaveXml(XclExpXmlStream& rStream) +{ + sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream(); + rWorksheet->startElement(XML_ext, FSNS(XML_xmlns, XML_x14), + rStream.getNamespaceURL(OOX_NS(xls14Lst)), XML_uri, maURI); + + rWorksheet->startElementNS(XML_x14, XML_sparklineGroups, FSNS(XML_xmlns, XML_xm), + rStream.getNamespaceURL(OOX_NS(xm))); + + for (auto const & [ pSparklineGroup, rSparklineVector ] : m_aSparklineGroupMap) + { + addSparklineGroup(rStream, *pSparklineGroup, rSparklineVector); + } + + rWorksheet->endElementNS(XML_x14, XML_sparklineGroups); + rWorksheet->endElement(XML_ext); +} + +void SparklineExt::addSparklineGroupAttributes( + rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, + sc::SparklineGroup& rSparklineGroup) +{ + if (rSparklineGroup.m_fLineWeight != 0.75) + pAttrList->add(XML_lineWeight, OString::number(rSparklineGroup.m_fLineWeight)); + + if (rSparklineGroup.m_eType != sc::SparklineType::Line) + { + if (rSparklineGroup.m_eType == sc::SparklineType::Column) + pAttrList->add(XML_type, "column"); + else if (rSparklineGroup.m_eType == sc::SparklineType::Stacked) + pAttrList->add(XML_type, "stacked"); + } + + if (rSparklineGroup.m_bDateAxis) + pAttrList->add(XML_dateAxis, "1"); + + if (rSparklineGroup.m_eDisplayEmptyCellsAs != sc::DisplayEmptyCellAs::Zero) + { + if (rSparklineGroup.m_eDisplayEmptyCellsAs == sc::DisplayEmptyCellAs::Gap) + pAttrList->add(XML_displayEmptyCellsAs, "gap"); + else if (rSparklineGroup.m_eDisplayEmptyCellsAs == sc::DisplayEmptyCellAs::Span) + pAttrList->add(XML_displayEmptyCellsAs, "span"); + } + + if (rSparklineGroup.m_bMarkers) + pAttrList->add(XML_markers, "1"); + if (rSparklineGroup.m_bHigh) + pAttrList->add(XML_high, "1"); + if (rSparklineGroup.m_bLow) + pAttrList->add(XML_low, "1"); + if (rSparklineGroup.m_bFirst) + pAttrList->add(XML_first, "1"); + if (rSparklineGroup.m_bLast) + pAttrList->add(XML_last, "1"); + if (rSparklineGroup.m_bNegative) + pAttrList->add(XML_negative, "1"); + if (rSparklineGroup.m_bDisplayXAxis) + pAttrList->add(XML_displayXAxis, "1"); + if (rSparklineGroup.m_bDisplayHidden) + pAttrList->add(XML_displayHidden, "1"); + + if (rSparklineGroup.m_eMinAxisType != sc::AxisType::Individual) + { + if (rSparklineGroup.m_eMinAxisType == sc::AxisType::Group) + pAttrList->add(XML_minAxisType, "group"); + else if (rSparklineGroup.m_eMinAxisType == sc::AxisType::Custom) + pAttrList->add(XML_minAxisType, "custom"); + } + + if (rSparklineGroup.m_eMaxAxisType != sc::AxisType::Individual) + { + if (rSparklineGroup.m_eMaxAxisType == sc::AxisType::Group) + pAttrList->add(XML_maxAxisType, "group"); + else if (rSparklineGroup.m_eMaxAxisType == sc::AxisType::Custom) + pAttrList->add(XML_maxAxisType, "custom"); + } + + if (rSparklineGroup.m_bRightToLeft) + pAttrList->add(XML_rightToLeft, "1"); + + if (rSparklineGroup.m_aManualMax && rSparklineGroup.m_eMaxAxisType == sc::AxisType::Custom) + pAttrList->add(XML_manualMax, OString::number(*rSparklineGroup.m_aManualMax)); + + if (rSparklineGroup.m_aManualMin && rSparklineGroup.m_eMinAxisType == sc::AxisType::Custom) + pAttrList->add(XML_manualMin, OString::number(*rSparklineGroup.m_aManualMin)); +} + +void SparklineExt::addSparklineGroupColors(XclExpXmlStream& rStream, + sc::SparklineGroup& rSparklineGroup) +{ + sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream(); + + rWorksheet->singleElementNS(XML_x14, XML_colorSeries, XML_rgb, + XclXmlUtils::ToOString(rSparklineGroup.m_aColorSeries)); + + if (rSparklineGroup.m_aColorSeries != COL_TRANSPARENT) + { + rWorksheet->singleElementNS(XML_x14, XML_colorNegative, XML_rgb, + XclXmlUtils::ToOString(rSparklineGroup.m_aColorNegative)); + } + + if (rSparklineGroup.m_aColorAxis != COL_TRANSPARENT) + { + rWorksheet->singleElementNS(XML_x14, XML_colorAxis, XML_rgb, + XclXmlUtils::ToOString(rSparklineGroup.m_aColorAxis)); + } + + if (rSparklineGroup.m_aColorMarkers != COL_TRANSPARENT) + { + rWorksheet->singleElementNS(XML_x14, XML_colorMarkers, XML_rgb, + XclXmlUtils::ToOString(rSparklineGroup.m_aColorMarkers)); + } + + if (rSparklineGroup.m_aColorFirst != COL_TRANSPARENT) + { + rWorksheet->singleElementNS(XML_x14, XML_colorFirst, XML_rgb, + XclXmlUtils::ToOString(rSparklineGroup.m_aColorFirst)); + } + + if (rSparklineGroup.m_aColorLast != COL_TRANSPARENT) + { + rWorksheet->singleElementNS(XML_x14, XML_colorLast, XML_rgb, + XclXmlUtils::ToOString(rSparklineGroup.m_aColorLast)); + } + + if (rSparklineGroup.m_aColorHigh != COL_TRANSPARENT) + { + rWorksheet->singleElementNS(XML_x14, XML_colorHigh, XML_rgb, + XclXmlUtils::ToOString(rSparklineGroup.m_aColorHigh)); + } + + if (rSparklineGroup.m_aColorLow != COL_TRANSPARENT) + { + rWorksheet->singleElementNS(XML_x14, XML_colorLow, XML_rgb, + XclXmlUtils::ToOString(rSparklineGroup.m_aColorLow)); + } +} + +void SparklineExt::addSparklineGroup(XclExpXmlStream& rStream, sc::SparklineGroup& rSparklineGroup, + std::vector<std::shared_ptr<sc::Sparkline>> const& rSparklines) +{ + sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream(); + + // Sparkline Group Attributes + auto pAttrList = sax_fastparser::FastSerializerHelper::createAttrList(); + addSparklineGroupAttributes(pAttrList, rSparklineGroup); + + rWorksheet->startElementNS(XML_x14, XML_sparklineGroup, pAttrList); + + addSparklineGroupColors(rStream, rSparklineGroup); + + // Sparklines + + rWorksheet->startElementNS(XML_x14, XML_sparklines); + for (auto const& rSparkline : rSparklines) + { + rWorksheet->startElementNS(XML_x14, XML_sparkline); + + { + rWorksheet->startElementNS(XML_xm, XML_f); + + OUString sRangeFormula; + ScRefFlags eFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D; + rSparkline->getInputRange().Format(sRangeFormula, eFlags, GetDoc(), + formula::FormulaGrammar::CONV_XL_OOX, ' ', true); + + rWorksheet->writeEscaped(sRangeFormula); + rWorksheet->endElementNS(XML_xm, XML_f); + } + + { + rWorksheet->startElementNS(XML_xm, XML_sqref); + + ScAddress::Details detailsXL(formula::FormulaGrammar::CONV_XL_OOX); + ScAddress aAddress(rSparkline->getColumn(), rSparkline->getRow(), GetCurrScTab()); + OUString sLocation = aAddress.Format(ScRefFlags::VALID, &GetDoc(), detailsXL); + + rWorksheet->writeEscaped(sLocation); + rWorksheet->endElementNS(XML_xm, XML_sqref); + } + + rWorksheet->endElementNS(XML_x14, XML_sparkline); + } + rWorksheet->endElementNS(XML_x14, XML_sparklines); + rWorksheet->endElementNS(XML_x14, XML_sparklineGroup); +} + +SparklineBuffer::SparklineBuffer(const XclExpRoot& rRoot, XclExtLstRef const& xExtLst) + : XclExpRoot(rRoot) +{ + if (sc::SparklineList* pSparklineList = GetDoc().GetSparklineList(GetCurrScTab())) + { + auto pSparklines = pSparklineList->getSparklines(); + if (!pSparklines.empty()) + { + xExtLst->AddRecord(new xcl::exp::SparklineExt(GetRoot(), pSparklines)); + } + } +} + +} // end namespace xcl::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/export/SparklineExt.hxx b/sc/source/filter/inc/export/SparklineExt.hxx new file mode 100644 index 000000000000..aa649d89e772 --- /dev/null +++ b/sc/source/filter/inc/export/SparklineExt.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <memory> +#include <vector> +#include <map> +#include <rangelst.hxx> +#include <Sparkline.hxx> + +#include <sax/fastattribs.hxx> + +#include <xerecord.hxx> +#include <xeroot.hxx> +#include <xeextlst.hxx> + +namespace xcl::exp +{ +class SparklineExt : public XclExpExt +{ + std::map<sc::SparklineGroup*, std::vector<std::shared_ptr<sc::Sparkline>>> m_aSparklineGroupMap; + +public: + SparklineExt(const XclExpRoot& rRoot, + std::vector<std::shared_ptr<sc::Sparkline>> const& pSparklines); + + void SaveXml(XclExpXmlStream& rStream) override; + void addSparklineGroup(XclExpXmlStream& rStream, sc::SparklineGroup& rSparklineGroup, + std::vector<std::shared_ptr<sc::Sparkline>> const& rSparklines); + static void + addSparklineGroupAttributes(rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, + sc::SparklineGroup& rSparklineGroup); + static void addSparklineGroupColors(XclExpXmlStream& rStream, + sc::SparklineGroup& rSparklineGroup); + + XclExpExtType GetType() override { return XclExpExtSparklineType; } +}; + +class SparklineBuffer : public XclExpRecordBase, protected XclExpRoot +{ +public: + explicit SparklineBuffer(const XclExpRoot& rRoot, const XclExtLstRef& xExtLst); +}; + +} // end namespace xcl::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/xeextlst.hxx b/sc/source/filter/inc/xeextlst.hxx index c5db5fcaff99..1770f9af191d 100644 --- a/sc/source/filter/inc/xeextlst.hxx +++ b/sc/source/filter/inc/xeextlst.hxx @@ -19,7 +19,8 @@ enum XclExpExtType { XclExpExtDataBarType, - XclExpExtDataFooType + XclExpExtDataFooType, + XclExpExtSparklineType, }; struct XclExpExtCondFormatData |