diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2022-03-25 14:53:48 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2022-04-12 08:23:02 +0200 |
commit | 8299b6fa263305e4e9dc1d94b2118f398aec7104 (patch) | |
tree | 6b844f76a372e9b3cad8b15bb020b441a03b9c3e /sc | |
parent | 10cfe5955d8d2e7d5adfdd16c1c0404f363fb116 (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.mk | 6 | ||||
-rw-r--r-- | sc/Library_sc.mk | 2 | ||||
-rw-r--r-- | sc/inc/SparklineGroup.hxx | 1 | ||||
-rw-r--r-- | sc/qa/unit/SparklineImportExportTest.cxx | 84 | ||||
-rw-r--r-- | sc/source/filter/xml/SparklineGroupsExport.cxx | 222 | ||||
-rw-r--r-- | sc/source/filter/xml/SparklineGroupsExport.hxx | 48 | ||||
-rw-r--r-- | sc/source/filter/xml/SparklineGroupsImportContext.cxx | 332 | ||||
-rw-r--r-- | sc/source/filter/xml/SparklineGroupsImportContext.hxx | 61 | ||||
-rw-r--r-- | sc/source/filter/xml/xmlexprt.cxx | 15 | ||||
-rw-r--r-- | sc/source/filter/xml/xmlexprt.hxx | 1 | ||||
-rw-r--r-- | sc/source/filter/xml/xmltabi.cxx | 5 |
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; |