summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2022-03-25 14:53:48 +0900
committerTomaž Vajngerl <quikee@gmail.com>2022-04-12 08:23:02 +0200
commit8299b6fa263305e4e9dc1d94b2118f398aec7104 (patch)
tree6b844f76a372e9b3cad8b15bb020b441a03b9c3e /sc
parent10cfe5955d8d2e7d5adfdd16c1c0404f363fb116 (diff)
sc: sparkline import/export for ODF
Change-Id: I0d8293cdd35cc8c7afab98efac0a28a3613d122b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132505 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com> (cherry picked from commit bd992ae1228b2f7e556f89f95949da0aeade5b91) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132844 Tested-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'sc')
-rw-r--r--sc/CppunitTest_sc_sparkline_test.mk6
-rw-r--r--sc/Library_sc.mk2
-rw-r--r--sc/inc/SparklineGroup.hxx1
-rw-r--r--sc/qa/unit/SparklineImportExportTest.cxx84
-rw-r--r--sc/source/filter/xml/SparklineGroupsExport.cxx222
-rw-r--r--sc/source/filter/xml/SparklineGroupsExport.hxx48
-rw-r--r--sc/source/filter/xml/SparklineGroupsImportContext.cxx332
-rw-r--r--sc/source/filter/xml/SparklineGroupsImportContext.hxx61
-rw-r--r--sc/source/filter/xml/xmlexprt.cxx15
-rw-r--r--sc/source/filter/xml/xmlexprt.hxx1
-rw-r--r--sc/source/filter/xml/xmltabi.cxx5
11 files changed, 772 insertions, 5 deletions
diff --git a/sc/CppunitTest_sc_sparkline_test.mk b/sc/CppunitTest_sc_sparkline_test.mk
index 499eaaf4ea38..a3e8078a9b83 100644
--- a/sc/CppunitTest_sc_sparkline_test.mk
+++ b/sc/CppunitTest_sc_sparkline_test.mk
@@ -18,6 +18,12 @@ $(eval $(call gb_CppunitTest_add_exception_objects,sc_sparkline_test, \
sc/qa/unit/SparklineTest \
))
+$(eval $(call gb_CppunitTest_use_externals,sc_sparkline_test, \
+ boost_headers \
+ mdds_headers \
+ libxml2 \
+))
+
$(eval $(call gb_CppunitTest_use_libraries,sc_sparkline_test, \
basegfx \
comphelper \
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index f523ee899254..2d65401e1c6d 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -291,6 +291,8 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
sc/source/core/tool/webservicelink \
sc/source/core/tool/zforauto \
sc/source/filter/xml/datastreamimport \
+ sc/source/filter/xml/SparklineGroupsExport \
+ sc/source/filter/xml/SparklineGroupsImportContext \
sc/source/filter/xml/XMLCalculationSettingsContext \
sc/source/filter/xml/XMLCellRangeSourceContext \
sc/source/filter/xml/XMLChangeTrackingExportHelper \
diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx
index 051e45d9e95a..5a3bda62b6ab 100644
--- a/sc/inc/SparklineGroup.hxx
+++ b/sc/inc/SparklineGroup.hxx
@@ -26,6 +26,7 @@ private:
public:
SparklineAttributes& getAttributes() { return m_aAttributes; }
+ SparklineAttributes const& getAttributes() const { return m_aAttributes; }
OUString getID() { return m_sUID; }
diff --git a/sc/qa/unit/SparklineImportExportTest.cxx b/sc/qa/unit/SparklineImportExportTest.cxx
index 2c324121a337..6da76fb2dcfb 100644
--- a/sc/qa/unit/SparklineImportExportTest.cxx
+++ b/sc/qa/unit/SparklineImportExportTest.cxx
@@ -8,6 +8,7 @@
*/
#include "helper/qahelper.hxx"
+#include "helper/xpath.hxx"
#include <com/sun/star/lang/XComponent.hpp>
#include <docsh.hxx>
@@ -16,7 +17,7 @@
using namespace css;
-class SparklineImportExportTest : public ScBootstrapFixture
+class SparklineImportExportTest : public ScBootstrapFixture, public XmlTestTools
{
private:
uno::Reference<uno::XInterface> m_xCalcComponent;
@@ -44,10 +45,19 @@ public:
test::BootstrapFixture::tearDown();
}
- void testSparklines();
+ virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathContextPtr) override
+ {
+ XmlTestTools::registerODFNamespaces(pXmlXPathContextPtr);
+ }
+
+ void testSparklinesRoundtripXLSX();
+ void testSparklinesExportODS();
+ void testSparklinesRoundtripODS();
CPPUNIT_TEST_SUITE(SparklineImportExportTest);
- CPPUNIT_TEST(testSparklines);
+ CPPUNIT_TEST(testSparklinesRoundtripXLSX);
+ CPPUNIT_TEST(testSparklinesExportODS);
+ CPPUNIT_TEST(testSparklinesRoundtripODS);
CPPUNIT_TEST_SUITE_END();
};
@@ -74,7 +84,7 @@ void checkSparklines(ScDocument& rDocument)
CPPUNIT_ASSERT_EQUAL(Color(0x92d050), rAttributes.getColorHigh());
CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), rAttributes.getColorLow());
- CPPUNIT_ASSERT_EQUAL(1.0, rAttributes.getLineWeight());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, rAttributes.getLineWeight(), 1E-2);
CPPUNIT_ASSERT_EQUAL(false, rAttributes.isDateAxis());
CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellsAs::Gap, rAttributes.getDisplayEmptyCellsAs());
@@ -153,7 +163,7 @@ void checkSparklines(ScDocument& rDocument)
}
} // end anonymous namespace
-void SparklineImportExportTest::testSparklines()
+void SparklineImportExportTest::testSparklinesRoundtripXLSX()
{
ScDocShellRef xDocSh = loadDoc(u"Sparklines.", FORMAT_XLSX);
CPPUNIT_ASSERT(xDocSh);
@@ -167,6 +177,70 @@ void SparklineImportExportTest::testSparklines()
xDocSh->DoClose();
}
+void SparklineImportExportTest::testSparklinesExportODS()
+{
+ // Load the document containing sparklines
+ ScDocShellRef xDocSh = loadDoc(u"Sparklines.", FORMAT_XLSX);
+ CPPUNIT_ASSERT(xDocSh);
+
+ // Save as ODS and check content.xml with XPath
+ std::shared_ptr<utl::TempFile> pXPathFile = ScBootstrapFixture::exportTo(*xDocSh, FORMAT_ODS);
+ xmlDocUniquePtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, "content.xml");
+
+ // We have 3 sparkline groups = 3 tables that contain spakrlines
+ assertXPath(pXmlDoc, "//table:table/calcext:sparkline-groups", 3);
+
+ // Check the number of sparkline groups in table[1]
+ assertXPath(pXmlDoc, "//table:table[1]/calcext:sparkline-groups/calcext:sparkline-group", 2);
+ // Check the number of sparkline groups in table[2]
+ assertXPath(pXmlDoc, "//table:table[2]/calcext:sparkline-groups/calcext:sparkline-group", 2);
+ // Check the number of sparkline groups in table[3]
+ assertXPath(pXmlDoc, "//table:table[3]/calcext:sparkline-groups/calcext:sparkline-group", 3);
+
+ // Check table[1] - sparkline-group[1]
+ OString aSparklineGroupPath
+ = "//table:table[1]/calcext:sparkline-groups/calcext:sparkline-group[1]";
+ assertXPath(pXmlDoc, aSparklineGroupPath, "type", "line");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "line-width", "1pt");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "display-empty-cells-as", "gap");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "markers", "true");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "high", "true");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "low", "true");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "first", "true");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "last", "true");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "negative", "true");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "display-x-axis", "true");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "min-axis-type", "individual");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "max-axis-type", "individual");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "color-series", "#376092");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "color-negative", "#00b050");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "color-axis", "#000000");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "color-markers", "#000000");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "color-first", "#7030a0");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "color-last", "#ff0000");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "color-high", "#92d050");
+ assertXPath(pXmlDoc, aSparklineGroupPath, "color-low", "#00b0f0");
+
+ assertXPath(pXmlDoc, aSparklineGroupPath + "/calcext:sparklines/calcext:sparkline", 1);
+ assertXPath(pXmlDoc, aSparklineGroupPath + "/calcext:sparklines/calcext:sparkline[1]",
+ "cell-address", "Sheet1.A2");
+}
+
+void SparklineImportExportTest::testSparklinesRoundtripODS()
+{
+ ScDocShellRef xDocSh = loadDoc(u"Sparklines.", FORMAT_XLSX);
+ CPPUNIT_ASSERT(xDocSh);
+
+ checkSparklines(xDocSh->GetDocument());
+
+ // Trigger export and import of sparklines
+ xDocSh = saveAndReload(*xDocSh, FORMAT_ODS);
+
+ checkSparklines(xDocSh->GetDocument());
+
+ xDocSh->DoClose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SparklineImportExportTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/filter/xml/SparklineGroupsExport.cxx b/sc/source/filter/xml/SparklineGroupsExport.cxx
new file mode 100644
index 000000000000..6be8a616a423
--- /dev/null
+++ b/sc/source/filter/xml/SparklineGroupsExport.cxx
@@ -0,0 +1,222 @@
+/* -*- 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 "SparklineGroupsExport.hxx"
+#include "xmlexprt.hxx"
+#include <rangeutl.hxx>
+
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sax/tools/converter.hxx>
+#include <o3tl/unit_conversion.hxx>
+
+using namespace css;
+using namespace xmloff::token;
+
+namespace sc
+{
+SparklineGroupsExport::SparklineGroupsExport(
+ ScXMLExport& rExport, SCTAB nTable, std::vector<std::shared_ptr<Sparkline>> const& rSparklines)
+ : m_rExport(rExport)
+ , m_nTable(nTable)
+{
+ for (auto const& pSparkline : rSparklines)
+ {
+ auto* pGroupPointer = pSparkline->getSparklineGroup().get();
+ auto aIterator = m_aSparklineGroupMap.find(pGroupPointer);
+ if (aIterator == m_aSparklineGroupMap.end())
+ {
+ m_aSparklineGroups.push_back(pGroupPointer);
+ std::vector<std::shared_ptr<sc::Sparkline>> aSparklineVector;
+ aSparklineVector.push_back(pSparkline);
+ m_aSparklineGroupMap.emplace(pGroupPointer, aSparklineVector);
+ }
+ else
+ {
+ aIterator->second.push_back(pSparkline);
+ }
+ }
+}
+
+void SparklineGroupsExport::insertColor(Color aColor, XMLTokenEnum eToken)
+{
+ OUStringBuffer aStringBuffer;
+ if (aColor != COL_TRANSPARENT)
+ {
+ sax::Converter::convertColor(aStringBuffer, aColor);
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, eToken, aStringBuffer.makeStringAndClear());
+ }
+}
+
+void SparklineGroupsExport::insertBool(bool bValue, XMLTokenEnum eToken)
+{
+ if (bValue)
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, eToken, "true");
+}
+
+void SparklineGroupsExport::addSparklineAttributes(Sparkline const& rSparkline)
+{
+ auto const* pDocument = m_rExport.GetDocument();
+
+ {
+ OUString sAddressString;
+ ScAddress aAddress(rSparkline.getColumn(), rSparkline.getRow(), m_nTable);
+ ScRangeStringConverter::GetStringFromAddress(sAddressString, aAddress, pDocument,
+ formula::FormulaGrammar::CONV_OOO);
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CELL_ADDRESS, sAddressString);
+ }
+
+ {
+ OUString sDataRangeString;
+ ScRangeList const& rRangeList = rSparkline.getInputRange();
+ ScRangeStringConverter::GetStringFromRangeList(sDataRangeString, &rRangeList, pDocument,
+ formula::FormulaGrammar::CONV_OOO);
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATA_RANGE, sDataRangeString);
+ }
+}
+
+namespace
+{
+OUString convertSparklineType(sc::SparklineType eType)
+{
+ switch (eType)
+ {
+ case sc::SparklineType::Line:
+ return u"line";
+ case sc::SparklineType::Column:
+ return u"column";
+ case sc::SparklineType::Stacked:
+ return u"stacked";
+ }
+ return u"";
+}
+
+OUString convertDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs eType)
+{
+ switch (eType)
+ {
+ case sc::DisplayEmptyCellsAs::Zero:
+ return u"zero";
+ case sc::DisplayEmptyCellsAs::Gap:
+ return u"gap";
+ case sc::DisplayEmptyCellsAs::Span:
+ return u"span";
+ }
+ return u"";
+}
+
+OUString convertAxisType(sc::AxisType eType)
+{
+ switch (eType)
+ {
+ case sc::AxisType::Individual:
+ return u"individual";
+ case sc::AxisType::Group:
+ return u"group";
+ case sc::AxisType::Custom:
+ return u"custom";
+ }
+ return u"";
+}
+
+} // end anonymous ns
+
+void SparklineGroupsExport::addSparklineGroupAttributes(SparklineAttributes const& rAttributes)
+{
+ OUString sType = convertSparklineType(rAttributes.getType());
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, sType);
+
+ // Line Weight = Line Width in ODF
+
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_LINE_WIDTH,
+ OUString::number(rAttributes.getLineWeight()) + "pt");
+
+ insertBool(rAttributes.isDateAxis(), XML_DATE_AXIS);
+
+ OUString sDisplayEmptyCellsAs
+ = convertDisplayEmptyCellsAs(rAttributes.getDisplayEmptyCellsAs());
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DISPLAY_EMPTY_CELLS_AS,
+ sDisplayEmptyCellsAs);
+
+ insertBool(rAttributes.isMarkers(), XML_MARKERS);
+ insertBool(rAttributes.isHigh(), XML_HIGH);
+ insertBool(rAttributes.isLow(), XML_LOW);
+ insertBool(rAttributes.isFirst(), XML_FIRST);
+ insertBool(rAttributes.isLast(), XML_LAST);
+ insertBool(rAttributes.isNegative(), XML_NEGATIVE);
+ insertBool(rAttributes.shouldDisplayXAxis(), XML_DISPLAY_X_AXIS);
+ insertBool(rAttributes.shouldDisplayHidden(), XML_DISPLAY_HIDDEN);
+
+ OUString sMinAxisType = convertAxisType(rAttributes.getMinAxisType());
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MIN_AXIS_TYPE, sMinAxisType);
+
+ OUString sMaxAxisType = convertAxisType(rAttributes.getMaxAxisType());
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MAX_AXIS_TYPE, sMaxAxisType);
+
+ insertBool(rAttributes.isRightToLeft(), XML_RIGHT_TO_LEFT);
+
+ if (rAttributes.getManualMax() && rAttributes.getMaxAxisType() == sc::AxisType::Custom)
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MANUAL_MAX,
+ OUString::number(*rAttributes.getManualMax()));
+
+ if (rAttributes.getManualMin() && rAttributes.getMinAxisType() == sc::AxisType::Custom)
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MANUAL_MIN,
+ OUString::number(*rAttributes.getManualMin()));
+
+ insertColor(rAttributes.getColorSeries(), XML_COLOR_SERIES);
+ insertColor(rAttributes.getColorNegative(), XML_COLOR_NEGATIVE);
+ insertColor(rAttributes.getColorAxis(), XML_COLOR_AXIS);
+ insertColor(rAttributes.getColorMarkers(), XML_COLOR_MARKERS);
+ insertColor(rAttributes.getColorFirst(), XML_COLOR_FIRST);
+ insertColor(rAttributes.getColorLast(), XML_COLOR_LAST);
+ insertColor(rAttributes.getColorHigh(), XML_COLOR_HIGH);
+ insertColor(rAttributes.getColorLow(), XML_COLOR_LOW);
+}
+
+void SparklineGroupsExport::addSparklineGroup(SparklineGroup* pSparklineGroup)
+{
+ auto const& rAttributes = pSparklineGroup->getAttributes();
+
+ OUString sID = pSparklineGroup->getID();
+ if (!sID.isEmpty())
+ {
+ m_rExport.AddAttribute(XML_NAMESPACE_CALC_EXT, XML_ID, sID);
+ }
+
+ addSparklineGroupAttributes(rAttributes);
+
+ SvXMLElementExport aElementSparklineGroup(m_rExport, XML_NAMESPACE_CALC_EXT,
+ XML_SPARKLINE_GROUP, true, true);
+
+ SvXMLElementExport aElementSparklines(m_rExport, XML_NAMESPACE_CALC_EXT, XML_SPARKLINES, true,
+ true);
+ for (auto const& rSparkline : m_aSparklineGroupMap[pSparklineGroup])
+ {
+ addSparklineAttributes(*rSparkline);
+ SvXMLElementExport aElementSparkline(m_rExport, XML_NAMESPACE_CALC_EXT, XML_SPARKLINE, true,
+ true);
+ }
+}
+
+void SparklineGroupsExport::write()
+{
+ SvXMLElementExport aElement(m_rExport, XML_NAMESPACE_CALC_EXT, XML_SPARKLINE_GROUPS, true,
+ true);
+ for (auto* pSparklineGroup : m_aSparklineGroups)
+ {
+ addSparklineGroup(pSparklineGroup);
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/SparklineGroupsExport.hxx b/sc/source/filter/xml/SparklineGroupsExport.hxx
new file mode 100644
index 000000000000..4e49f585dbc7
--- /dev/null
+++ b/sc/source/filter/xml/SparklineGroupsExport.hxx
@@ -0,0 +1,48 @@
+/* -*- 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 <unordered_map>
+#include <tools/color.hxx>
+#include <xmloff/xmltoken.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+
+class ScXMLExport;
+
+namespace sc
+{
+class SparklineGroupsExport
+{
+ ScXMLExport& m_rExport;
+ std::vector<SparklineGroup*> m_aSparklineGroups;
+ std::unordered_map<SparklineGroup*, std::vector<std::shared_ptr<Sparkline>>>
+ m_aSparklineGroupMap;
+ SCTAB m_nTable;
+
+ void addSparklineGroupAttributes(sc::SparklineAttributes const& rAttributes);
+ void addSparklineGroup(SparklineGroup* pSparklineGroup);
+ void addSparklineAttributes(Sparkline const& rSparkline);
+
+ void insertColor(Color aColor, xmloff::token::XMLTokenEnum eToken);
+ void insertBool(bool bValue, xmloff::token::XMLTokenEnum eToken);
+
+public:
+ SparklineGroupsExport(ScXMLExport& rExport, SCTAB nTable,
+ std::vector<std::shared_ptr<Sparkline>> const& rSparklines);
+
+ void write();
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/SparklineGroupsImportContext.cxx b/sc/source/filter/xml/SparklineGroupsImportContext.cxx
new file mode 100644
index 000000000000..87acbd047cf9
--- /dev/null
+++ b/sc/source/filter/xml/SparklineGroupsImportContext.cxx
@@ -0,0 +1,332 @@
+/* -*- 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 "SparklineGroupsImportContext.hxx"
+
+#include <sax/tools/converter.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmluconv.hxx>
+
+#include <document.hxx>
+#include <rangeutl.hxx>
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+using namespace xmloff::token;
+using namespace css;
+
+namespace sc
+{
+SparklineGroupsImportContext::SparklineGroupsImportContext(ScXMLImport& rImport)
+ : ScXMLImportContext(rImport)
+{
+}
+
+namespace
+{
+sc::SparklineType parseSparklineType(std::u16string_view aString)
+{
+ if (aString == u"column")
+ return sc::SparklineType::Column;
+ else if (aString == u"stacked")
+ return sc::SparklineType::Stacked;
+ return sc::SparklineType::Line;
+}
+
+sc::DisplayEmptyCellsAs parseDisplayEmptyCellsAs(std::u16string_view aString)
+{
+ if (aString == u"span")
+ return sc::DisplayEmptyCellsAs::Span;
+ else if (aString == u"gap")
+ return sc::DisplayEmptyCellsAs::Gap;
+ return sc::DisplayEmptyCellsAs::Zero;
+}
+
+sc::AxisType parseAxisType(std::u16string_view aString)
+{
+ if (aString == u"group")
+ return sc::AxisType::Group;
+ else if (aString == u"custom")
+ return sc::AxisType::Custom;
+ return sc::AxisType::Individual;
+}
+
+} // end anonymous namespace
+
+void SparklineGroupsImportContext::fillSparklineGroupID(
+ uno::Reference<xml::sax::XFastAttributeList> const& xAttrList)
+{
+ for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList))
+ {
+ switch (rIter.getToken())
+ {
+ case XML_ELEMENT(CALC_EXT, XML_ID):
+ {
+ m_pCurrentSparklineGroup->setID(rIter.toString());
+ break;
+ }
+ }
+ }
+}
+
+void SparklineGroupsImportContext::fillSparklineGroupAttributes(
+ uno::Reference<xml::sax::XFastAttributeList> const& xAttrList)
+{
+ sc::SparklineAttributes& rAttributes = m_pCurrentSparklineGroup->getAttributes();
+
+ for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList))
+ {
+ switch (rIter.getToken())
+ {
+ case XML_ELEMENT(CALC_EXT, XML_TYPE):
+ {
+ rAttributes.setType(parseSparklineType(rIter.toString()));
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_LINE_WIDTH):
+ {
+ OUString sLineWidth = rIter.toString();
+ double fLineWidth;
+ sal_Int16 const eSrcUnit
+ = ::sax::Converter::GetUnitFromString(sLineWidth, util::MeasureUnit::POINT);
+ ::sax::Converter::convertDouble(fLineWidth, sLineWidth, eSrcUnit,
+ util::MeasureUnit::POINT);
+ rAttributes.setLineWeight(fLineWidth);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_DATE_AXIS):
+ {
+ rAttributes.setDateAxis(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_DISPLAY_EMPTY_CELLS_AS):
+ {
+ auto eDisplayEmptyCellsAs = parseDisplayEmptyCellsAs(rIter.toString());
+ rAttributes.setDisplayEmptyCellsAs(eDisplayEmptyCellsAs);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_MARKERS):
+ {
+ rAttributes.setMarkers(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_HIGH):
+ {
+ rAttributes.setHigh(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_LOW):
+ {
+ rAttributes.setLow(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_FIRST):
+ {
+ rAttributes.setFirst(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_LAST):
+ {
+ rAttributes.setLast(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_NEGATIVE):
+ {
+ rAttributes.setNegative(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_DISPLAY_X_AXIS):
+ {
+ rAttributes.setDisplayXAxis(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_DISPLAY_HIDDEN):
+ {
+ rAttributes.setDisplayHidden(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_MIN_AXIS_TYPE):
+ {
+ rAttributes.setMinAxisType(parseAxisType(rIter.toString()));
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_MAX_AXIS_TYPE):
+ {
+ rAttributes.setMaxAxisType(parseAxisType(rIter.toString()));
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_RIGHT_TO_LEFT):
+ {
+ rAttributes.setRightToLeft(rIter.toBoolean());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_MANUAL_MAX):
+ {
+ rAttributes.setManualMax(rIter.toDouble());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_MANUAL_MIN):
+ {
+ rAttributes.setManualMin(rIter.toDouble());
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_COLOR_SERIES):
+ {
+ Color aColor;
+ sax::Converter::convertColor(aColor, rIter.toString());
+ rAttributes.setColorSeries(aColor);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_COLOR_NEGATIVE):
+ {
+ Color aColor;
+ sax::Converter::convertColor(aColor, rIter.toString());
+ rAttributes.setColorNegative(aColor);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_COLOR_AXIS):
+ {
+ Color aColor;
+ sax::Converter::convertColor(aColor, rIter.toString());
+ rAttributes.setColorAxis(aColor);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_COLOR_MARKERS):
+ {
+ Color aColor;
+ sax::Converter::convertColor(aColor, rIter.toString());
+ rAttributes.setColorMarkers(aColor);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_COLOR_FIRST):
+ {
+ Color aColor;
+ sax::Converter::convertColor(aColor, rIter.toString());
+ rAttributes.setColorFirst(aColor);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_COLOR_LAST):
+ {
+ Color aColor;
+ sax::Converter::convertColor(aColor, rIter.toString());
+ rAttributes.setColorLast(aColor);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_COLOR_HIGH):
+ {
+ Color aColor;
+ sax::Converter::convertColor(aColor, rIter.toString());
+ rAttributes.setColorHigh(aColor);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_COLOR_LOW):
+ {
+ Color aColor;
+ sax::Converter::convertColor(aColor, rIter.toString());
+ rAttributes.setColorLow(aColor);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void SparklineGroupsImportContext::fillSparklineAttributes(
+ SparklineImportData& rImportData, uno::Reference<xml::sax::XFastAttributeList> const& xAttrList)
+{
+ ScDocument* pDocument = GetScImport().GetDocument();
+
+ for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList))
+ {
+ switch (rIter.getToken())
+ {
+ case XML_ELEMENT(CALC_EXT, XML_CELL_ADDRESS):
+ {
+ sal_Int32 nOffset = 0;
+ ScRangeStringConverter::GetAddressFromString(
+ rImportData.m_aAddress, rIter.toString(), *pDocument,
+ formula::FormulaGrammar::CONV_OOO, nOffset);
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_DATA_RANGE):
+ {
+ ScRangeStringConverter::GetRangeListFromString(rImportData.m_aDataRangeList,
+ rIter.toString(), *pDocument,
+ formula::FormulaGrammar::CONV_OOO);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+uno::Reference<xml::sax::XFastContextHandler>
+ SAL_CALL SparklineGroupsImportContext::createFastChildContext(
+ sal_Int32 nElement, uno::Reference<xml::sax::XFastAttributeList> const& xAttrList)
+{
+ SvXMLImportContext* pContext = nullptr;
+ switch (nElement)
+ {
+ case XML_ELEMENT(CALC_EXT, XML_SPARKLINE_GROUP):
+ {
+ m_pCurrentSparklineGroup = std::make_shared<sc::SparklineGroup>();
+ fillSparklineGroupID(xAttrList);
+ fillSparklineGroupAttributes(xAttrList);
+ pContext = this;
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_SPARKLINES):
+ {
+ pContext = this;
+ break;
+ }
+ case XML_ELEMENT(CALC_EXT, XML_SPARKLINE):
+ {
+ SparklineImportData& rImportData = m_aCurrentSparklineDataList.emplace_back();
+ fillSparklineAttributes(rImportData, xAttrList);
+ pContext = this;
+ break;
+ }
+ }
+
+ return pContext;
+}
+
+void SparklineGroupsImportContext::insertSparklines()
+{
+ ScDocument* pDocument = GetScImport().GetDocument();
+ for (auto const& rSparklineImportData : m_aCurrentSparklineDataList)
+ {
+ auto* pSparkline
+ = pDocument->CreateSparkline(rSparklineImportData.m_aAddress, m_pCurrentSparklineGroup);
+ pSparkline->setInputRange(rSparklineImportData.m_aDataRangeList);
+ }
+}
+
+void SAL_CALL SparklineGroupsImportContext::endFastElement(sal_Int32 nElement)
+{
+ switch (nElement)
+ {
+ case XML_ELEMENT(CALC_EXT, XML_SPARKLINE_GROUP):
+ {
+ insertSparklines();
+ m_pCurrentSparklineGroup.reset();
+ m_aCurrentSparklineDataList.clear();
+ break;
+ }
+ }
+}
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/SparklineGroupsImportContext.hxx b/sc/source/filter/xml/SparklineGroupsImportContext.hxx
new file mode 100644
index 000000000000..f643c1c054f7
--- /dev/null
+++ b/sc/source/filter/xml/SparklineGroupsImportContext.hxx
@@ -0,0 +1,61 @@
+/* -*- 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 "importcontext.hxx"
+#include "xmlimprt.hxx"
+#include <address.hxx>
+#include <rangelst.hxx>
+
+namespace sax_fastparser
+{
+class FastAttributeList;
+}
+
+namespace sc
+{
+class SparklineGroup;
+
+struct SparklineImportData
+{
+ ScAddress m_aAddress;
+ ScRangeList m_aDataRangeList;
+};
+
+class SparklineGroupsImportContext : public ScXMLImportContext
+{
+private:
+ std::shared_ptr<sc::SparklineGroup> m_pCurrentSparklineGroup;
+ std::vector<SparklineImportData> m_aCurrentSparklineDataList;
+
+ void
+ fillSparklineGroupID(css::uno::Reference<css::xml::sax::XFastAttributeList> const& xAttrList);
+ void fillSparklineGroupAttributes(
+ css::uno::Reference<css::xml::sax::XFastAttributeList> const& xAttrList);
+ void fillSparklineAttributes(
+ SparklineImportData& rImportData,
+ css::uno::Reference<css::xml::sax::XFastAttributeList> const& xAttrList);
+
+ void insertSparklines();
+
+public:
+ SparklineGroupsImportContext(ScXMLImport& rImport);
+
+ css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ css::uno::Reference<css::xml::sax::XFastAttributeList> const& xAttrList) override;
+
+ void SAL_CALL endFastElement(sal_Int32 nElement) override;
+};
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx
index bdae3a1f94d0..b946535fc54b 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -67,6 +67,7 @@
#include <cellform.hxx>
#include <datamapper.hxx>
#include <datatransformation.hxx>
+#include "SparklineGroupsExport.hxx"
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlnamespace.hxx>
@@ -2988,6 +2989,7 @@ void ScXMLExport::WriteTable(sal_Int32 nTable, const uno::Reference<sheet::XSpre
{
//export new conditional format information
ExportConditionalFormat(nTable);
+ exportSparklineGroups(nTable);
}
}
@@ -4516,6 +4518,19 @@ void ScXMLExport::WriteNamedRange(ScRangeName* pRangeName)
}
}
+void ScXMLExport::exportSparklineGroups(SCTAB nTable)
+{
+ if (sc::SparklineList* pSparklineList = pDoc->GetSparklineList(nTable))
+ {
+ auto pSparklines = pSparklineList->getSparklines();
+ if (!pSparklines.empty())
+ {
+ sc::SparklineGroupsExport aSparklineGroupExport(*this, nTable, pSparklines);
+ aSparklineGroupExport.write();
+ }
+ }
+}
+
namespace {
OUString getCondFormatEntryType(const ScColorScaleEntry& rEntry, bool bFirst = true)
diff --git a/sc/source/filter/xml/xmlexprt.hxx b/sc/source/filter/xml/xmlexprt.hxx
index e4a165ab0511..8ab8901d4671 100644
--- a/sc/source/filter/xml/xmlexprt.hxx
+++ b/sc/source/filter/xml/xmlexprt.hxx
@@ -198,6 +198,7 @@ class ScXMLExport : public SvXMLExport
void WriteExternalDataTransformations(const std::vector<std::shared_ptr<sc::DataTransformation>>& aDataTransformations);
void WriteDataStream();
void WriteNamedRange(ScRangeName* pRangeName);
+ void exportSparklineGroups(SCTAB nTab);
void ExportConditionalFormat(SCTAB nTab);
void WriteExternalRefCaches();
void WriteConsolidation(); // core implementation
diff --git a/sc/source/filter/xml/xmltabi.cxx b/sc/source/filter/xml/xmltabi.cxx
index ddec732b01c0..5c235b1d35a6 100644
--- a/sc/source/filter/xml/xmltabi.cxx
+++ b/sc/source/filter/xml/xmltabi.cxx
@@ -34,6 +34,7 @@
#include <externalrefmgr.hxx>
#include <sheetdata.hxx>
#include "xmlcondformat.hxx"
+#include "SparklineGroupsImportContext.hxx"
#include <xmloff/xmltkmap.hxx>
#include <xmloff/xmltoken.hxx>
@@ -299,6 +300,9 @@ uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
case XML_ELEMENT( CALC_EXT, XML_CONDITIONAL_FORMATS ):
pContext = new ScXMLConditionalFormatsContext( GetScImport() );
break;
+ case XML_ELEMENT(CALC_EXT, XML_SPARKLINE_GROUPS):
+ pContext = new sc::SparklineGroupsImportContext(GetScImport());
+ break;
case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS):
case XML_ELEMENT(OFFICE_EXT, XML_EVENT_LISTENERS):
{
@@ -316,6 +320,7 @@ uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
break;
default:
XMLOFF_WARN_UNKNOWN_ELEMENT("sc", nElement);
+ break;
}
return pContext;