include/xmloff/xmltoken.hxx | 26 oox/source/core/xmlfilterbase.cxx | 2 oox/source/token/namespaces-strict.txt | 1 oox/source/token/namespaces.hxx.tail | 1 oox/source/token/namespaces.txt | 1 oox/source/token/tokens.txt | 1 sc/CppunitTest_sc_sparkline_test.mk | 6 sc/Library_sc.mk | 2 sc/inc/SparklineGroup.hxx | 6 sc/qa/unit/SparklineImportExportTest.cxx | 87 ++- sc/source/filter/excel/excdoc.cxx | 1 sc/source/filter/excel/export/SparklineExt.cxx | 6 sc/source/filter/oox/SparklineFragment.cxx | 3 sc/source/filter/xml/SparklineGroupsExport.cxx | 222 ++++++++ sc/source/filter/xml/SparklineGroupsExport.hxx | 48 + sc/source/filter/xml/SparklineGroupsImportContext.cxx | 332 ++++++++++++ sc/source/filter/xml/SparklineGroupsImportContext.hxx | 61 ++ sc/source/filter/xml/xmlexprt.cxx | 15 sc/source/filter/xml/xmlexprt.hxx | 1 sc/source/filter/xml/xmltabi.cxx | 5 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 165 +++++ test/source/xmltesttools.cxx | 2 xmloff/source/core/xmltoken.cxx | 28 - xmloff/source/token/tokens.txt | 26 24 files changed, 1040 insertions(+), 8 deletions(-)
New commits: commit 8299b6fa263305e4e9dc1d94b2118f398aec7104 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Fri Mar 25 14:53:48 2022 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Tue Apr 12 08:23:02 2022 +0200 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 <qui...@gmail.com> (cherry picked from commit bd992ae1228b2f7e556f89f95949da0aeade5b91) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132844 Tested-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index 8e7583694f47..0cdd604e1ce7 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -449,8 +449,16 @@ namespace xmloff::token { XML_CODEBASE, XML_COLLAPSE, XML_COLOR, + XML_COLOR_AXIS, + XML_COLOR_FIRST, + XML_COLOR_HIGH, XML_COLOR_INVERSION, + XML_COLOR_LAST, + XML_COLOR_LOW, + XML_COLOR_MARKERS, XML_COLOR_MODE, + XML_COLOR_NEGATIVE, + XML_COLOR_SERIES, XML_COLOR_SCALE, XML_COLOR_SCALE_ENTRY, XML_COLOR_TABLE, @@ -593,6 +601,7 @@ namespace xmloff::token { XML_DATA_PILOT_TABLE, XML_DATA_PILOT_TABLES, XML_DATA_POINT, + XML_DATA_RANGE, XML_DATA_STREAM_SOURCE, XML_DATA_STYLE, XML_DATA_STYLE_NAME, @@ -609,6 +618,7 @@ namespace xmloff::token { XML_DATABASE_SOURCE_TABLE, XML_DATABASE_TABLE_NAME, XML_DATE, + XML_DATE_AXIS, XML_DATE_IS, XML_DATE_ADJUST, XML_DATE_STYLE, @@ -668,12 +678,15 @@ namespace xmloff::token { XML_DISPLAY_DETAILS, XML_DISPLAY_DUPLICATES, XML_DISPLAY_EMPTY, + XML_DISPLAY_EMPTY_CELLS_AS, XML_DISPLAY_FILTER_BUTTONS, XML_DISPLAY_FORMULA, + XML_DISPLAY_HIDDEN, XML_DISPLAY_LABEL, XML_DISPLAY_LEVELS, XML_DISPLAY_NAME, XML_DISPLAY_OUTLINE_LEVEL, + XML_DISPLAY_X_AXIS, XML_DISSOLVE, XML_DISTANCE, XML_DISTANCE_AFTER_SEP, @@ -1181,6 +1194,7 @@ namespace xmloff::token { XML_LINE_SKEW, XML_LINE_SPACING, XML_LINE_STYLE, + XML_LINE_WIDTH, XML_LINEAR, XML_LINEARGRADIENT, XML_LINENUMBERING_CONFIGURATION, @@ -1208,6 +1222,7 @@ namespace xmloff::token { XML_LOGARITHMIC, XML_LOGBASE, XML_LONG, + XML_LOW, XML_LOWLIMIT, XML_LR_TB, XML_LT, @@ -1221,6 +1236,8 @@ namespace xmloff::token { XML_MALIGNGROUP, XML_MALIGNMARK, XML_MANUAL, + XML_MANUAL_MIN, + XML_MANUAL_MAX, XML_MAP, XML_MARGIN_BOTTOM, XML_MARGIN_LEFT, @@ -1228,6 +1245,7 @@ namespace xmloff::token { XML_MARGIN_TOP, XML_MARGINS, XML_MARKER, + XML_MARKERS, XML_MARKER_END, XML_MARKER_END_CENTER, XML_MARKER_END_WIDTH, @@ -1246,6 +1264,7 @@ namespace xmloff::token { XML_MATRIX_COVERED, XML_MATRIXROW, XML_MAX, + XML_MAX_AXIS_TYPE, XML_MAX_EDGE, XML_MAX_HEIGHT, XML_MAX_LENGTH, @@ -1271,6 +1290,7 @@ namespace xmloff::token { XML_MIDDLE, XML_MIME_TYPE, XML_MIN, + XML_MIN_AXIS_TYPE, XML_MIN_DENOMINATOR_DIGITS, XML_MIN_EDGE, XML_MIN_EXPONENT_DIGITS, @@ -1345,6 +1365,7 @@ namespace xmloff::token { XML_NAMED_RANGE, XML_NAVIGATION_MODE, XML_NAVY, + XML_NEGATIVE, XML_NEGATIVE_COLOR, XML_NEQ, XML_NEW, @@ -1606,6 +1627,7 @@ namespace xmloff::token { XML_RIGHT, XML_RIGHT_OUTSIDE, XML_RIGHT_TEXT, + XML_RIGHT_TO_LEFT, XML_RIGHTARC, XML_RIGHTCIRCLE, XML_RING, @@ -1760,6 +1782,10 @@ namespace xmloff::token { XML_SOURCE_RANGE_ADDRESS, XML_SOURCE_SERVICE, XML_SPACE_BEFORE, + XML_SPARKLINE_GROUPS, + XML_SPARKLINE_GROUP, + XML_SPARKLINES, + XML_SPARKLINE, XML_SPAN, XML_SPECULAR, XML_SPECULAR_COLOR, 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; diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index 0d64385a7e67..5190957e93e7 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -1535,6 +1535,171 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:oneOrMore> </rng:element> </rng:optional> + <!-- Sparklines--> + <rng:optional> + <rng:element name="calcext:sparkline-groups"> + <rng:oneOrMore> + <rng:element name="calcext:sparkline-group"> + <rng:attribute name="calcext:id"> + <rng:ref name="string"/> + </rng:attribute> + <rng:optional> + <rng:attribute name="calcext:type"> + <rng:choice> + <rng:value>line</rng:value> + <rng:value>column</rng:value> + <rng:value>stacked</rng:value> + </rng:choice> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:line-width"> + <rng:ref name="length"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:date-axis"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:display-empty-cells-as"> + <rng:choice> + <rng:value>zero</rng:value> + <rng:value>gap</rng:value> + <rng:value>span</rng:value> + </rng:choice> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:markers"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:high"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:low"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:first"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:last"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:negative"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:display-x-axis"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:display-hidden"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:min-axis-type"> + <rng:choice> + <rng:value>individual</rng:value> + <rng:value>group</rng:value> + <rng:value>custom</rng:value> + </rng:choice> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:max-axis-type"> + <rng:choice> + <rng:value>individual</rng:value> + <rng:value>group</rng:value> + <rng:value>custom</rng:value> + </rng:choice> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:right-to-left"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:manual-max"> + <rng:ref name="double"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:manual-min"> + <rng:ref name="double"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:color-series"> + <rng:ref name="color"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:color-negative"> + <rng:ref name="color"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:color-axis"> + <rng:ref name="color"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:color-markers"> + <rng:ref name="color"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:color-first"> + <rng:ref name="color"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:color-last"> + <rng:ref name="color"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:color-high"> + <rng:ref name="color"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="calcext:color-low"> + <rng:ref name="color"/> + </rng:attribute> + </rng:optional> + <rng:element name="calcext:sparklines"> + <rng:oneOrMore> + <rng:element name="calcext:sparkline"> + <rng:attribute name="calcext:cell-address"> + <rng:ref name="cellAddress"/> + </rng:attribute> + <rng:attribute name="calcext:data-range"> + <rng:ref name="cellRangeAddressList"/> + </rng:attribute> + </rng:element> + </rng:oneOrMore> + </rng:element> + </rng:element> + </rng:oneOrMore> + </rng:element> + </rng:optional> </rng:element> </rng:define> diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 80cd4b6d6f3f..c1646dfb0701 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -461,8 +461,16 @@ namespace xmloff::token { TOKEN( "codebase", XML_CODEBASE ), TOKEN( "collapse", XML_COLLAPSE ), TOKEN( "color", XML_COLOR ), + TOKEN( "color-axis", XML_COLOR_AXIS ), + TOKEN( "color-first", XML_COLOR_FIRST ), + TOKEN( "color-high", XML_COLOR_HIGH ), TOKEN( "color-inversion", XML_COLOR_INVERSION ), + TOKEN( "color-last", XML_COLOR_LAST ), + TOKEN( "color-low", XML_COLOR_LOW ), + TOKEN( "color-markers", XML_COLOR_MARKERS ), TOKEN( "color-mode", XML_COLOR_MODE ), + TOKEN( "color-negative", XML_COLOR_NEGATIVE ), + TOKEN( "color-series", XML_COLOR_SERIES ), TOKEN( "color-scale", XML_COLOR_SCALE ), TOKEN( "color-scale-entry", XML_COLOR_SCALE_ENTRY ), TOKEN( "color-table", XML_COLOR_TABLE ), @@ -605,6 +613,7 @@ namespace xmloff::token { TOKEN( "data-pilot-table", XML_DATA_PILOT_TABLE ), TOKEN( "data-pilot-tables", XML_DATA_PILOT_TABLES ), TOKEN( "data-point", XML_DATA_POINT ), + TOKEN( "data-range", XML_DATA_RANGE ), TOKEN( "data-stream-source", XML_DATA_STREAM_SOURCE ), TOKEN( "data-style", XML_DATA_STYLE ), TOKEN( "data-style-name", XML_DATA_STYLE_NAME ), @@ -621,6 +630,7 @@ namespace xmloff::token { TOKEN( "database-source-table", XML_DATABASE_SOURCE_TABLE ), TOKEN( "database-table-name", XML_DATABASE_TABLE_NAME ), TOKEN( "date", XML_DATE ), + TOKEN( "date-axis", XML_DATE_AXIS ), TOKEN( "date-is", XML_DATE_IS ), TOKEN( "date-adjust", XML_DATE_ADJUST ), TOKEN( "date-style", XML_DATE_STYLE ), @@ -680,12 +690,15 @@ namespace xmloff::token { TOKEN( "display-details", XML_DISPLAY_DETAILS ), TOKEN( "display-duplicates", XML_DISPLAY_DUPLICATES ), TOKEN( "display-empty", XML_DISPLAY_EMPTY ), + TOKEN( "display-empty-cells-as", XML_DISPLAY_EMPTY_CELLS_AS ), TOKEN( "display-filter-buttons", XML_DISPLAY_FILTER_BUTTONS ), TOKEN( "display-formula", XML_DISPLAY_FORMULA ), + TOKEN( "display-hidden", XML_DISPLAY_HIDDEN ), TOKEN( "display-label", XML_DISPLAY_LABEL ), TOKEN( "display-levels", XML_DISPLAY_LEVELS ), TOKEN( "display-name", XML_DISPLAY_NAME ), TOKEN( "display-outline-level", XML_DISPLAY_OUTLINE_LEVEL ), + TOKEN( "display-x-axis", XML_DISPLAY_X_AXIS ), TOKEN( "dissolve", XML_DISSOLVE ), TOKEN( "distance", XML_DISTANCE ), TOKEN( "distance-after-sep", XML_DISTANCE_AFTER_SEP ), @@ -1194,6 +1207,7 @@ namespace xmloff::token { TOKEN( "line-skew", XML_LINE_SKEW ), TOKEN( "line-spacing", XML_LINE_SPACING ), TOKEN( "line-style", XML_LINE_STYLE ), + TOKEN( "line-width", XML_LINE_WIDTH ), TOKEN( "linear", XML_LINEAR ), TOKEN( "linearGradient", XML_LINEARGRADIENT ), TOKEN( "linenumbering-configuration", XML_LINENUMBERING_CONFIGURATION ), @@ -1221,6 +1235,7 @@ namespace xmloff::token { TOKEN( "logarithmic", XML_LOGARITHMIC ), TOKEN( "logbase", XML_LOGBASE ), TOKEN( "long", XML_LONG ), + TOKEN( "low", XML_LOW ), TOKEN( "lowlimit", XML_LOWLIMIT ), TOKEN( "lr-tb", XML_LR_TB ), TOKEN( "lt", XML_LT ), @@ -1234,6 +1249,8 @@ namespace xmloff::token { TOKEN( "maligngroup", XML_MALIGNGROUP ), TOKEN( "malignmark", XML_MALIGNMARK ), TOKEN( "manual", XML_MANUAL ), + TOKEN( "manual-min", XML_MANUAL_MIN ), + TOKEN( "manual-max", XML_MANUAL_MAX ), TOKEN( "map", XML_MAP ), TOKEN( "margin-bottom", XML_MARGIN_BOTTOM ), TOKEN( "margin-left", XML_MARGIN_LEFT ), @@ -1241,6 +1258,7 @@ namespace xmloff::token { TOKEN( "margin-top", XML_MARGIN_TOP ), TOKEN( "margins", XML_MARGINS ), TOKEN( "marker", XML_MARKER ), + TOKEN( "markers", XML_MARKERS ), TOKEN( "marker-end", XML_MARKER_END ), TOKEN( "marker-end-center", XML_MARKER_END_CENTER ), TOKEN( "marker-end-width", XML_MARKER_END_WIDTH ), @@ -1259,6 +1277,7 @@ namespace xmloff::token { TOKEN( "matrix-covered", XML_MATRIX_COVERED ), TOKEN( "matrixrow", XML_MATRIXROW ), TOKEN( "max", XML_MAX ), + TOKEN( "max-axis-type", XML_MAX_AXIS_TYPE ), TOKEN( "max-edge", XML_MAX_EDGE ), TOKEN( "max-height", XML_MAX_HEIGHT ), TOKEN( "max-length", XML_MAX_LENGTH ), @@ -1284,6 +1303,7 @@ namespace xmloff::token { TOKEN( "middle", XML_MIDDLE ), TOKEN( "mime-type", XML_MIME_TYPE ), TOKEN( "min", XML_MIN ), + TOKEN( "min-axis-type", XML_MIN_AXIS_TYPE ), TOKEN( "min-denominator-digits", XML_MIN_DENOMINATOR_DIGITS ), TOKEN( "min-edge", XML_MIN_EDGE ), TOKEN( "min-exponent-digits", XML_MIN_EXPONENT_DIGITS ), @@ -1358,7 +1378,8 @@ namespace xmloff::token { TOKEN( "named-range", XML_NAMED_RANGE ), TOKEN( "navigation-mode", XML_NAVIGATION_MODE ), TOKEN( "navy", XML_NAVY ), - TOKEN( "negative-color", XML_NEGATIVE_COLOR ), + TOKEN( "negative", XML_NEGATIVE ), + TOKEN( "negative-color", XML_NEGATIVE_COLOR ), TOKEN( "neq", XML_NEQ ), TOKEN( "new", XML_NEW ), TOKEN( "next", XML_NEXT ), @@ -1619,6 +1640,7 @@ namespace xmloff::token { TOKEN( "right", XML_RIGHT ), TOKEN( "right-outside", XML_RIGHT_OUTSIDE ), TOKEN( "right-text", XML_RIGHT_TEXT ), + TOKEN( "right-to-left", XML_RIGHT_TO_LEFT ), TOKEN( "right-arc", XML_RIGHTARC ), TOKEN( "right-circle", XML_RIGHTCIRCLE ), TOKEN( "ring", XML_RING ), @@ -1773,6 +1795,10 @@ namespace xmloff::token { TOKEN( "source-range-address", XML_SOURCE_RANGE_ADDRESS ), TOKEN( "source-service", XML_SOURCE_SERVICE ), TOKEN( "space-before", XML_SPACE_BEFORE ), + TOKEN( "sparkline-groups", XML_SPARKLINE_GROUPS ), + TOKEN( "sparkline-group", XML_SPARKLINE_GROUP ), + TOKEN( "sparklines", XML_SPARKLINES ), + TOKEN( "sparkline", XML_SPARKLINE ), TOKEN( "span", XML_SPAN ), TOKEN( "specular", XML_SPECULAR ), TOKEN( "specular-color", XML_SPECULAR_COLOR ), diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 072777981400..2547fbd58c66 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -366,8 +366,16 @@ code codebase collapse color +color-axis +color-first +color-high color-inversion +color-last +color-low +color-markers color-mode +color-negative +color-series color-scale color-scale-entry color-table @@ -510,6 +518,7 @@ data-pilot-subtotals data-pilot-table data-pilot-tables data-point +data-range data-stream-source data-style data-style-name @@ -526,6 +535,7 @@ database-source-sql database-source-table database-table-name date +date-axis date-is date-adjust date-style @@ -585,12 +595,15 @@ display-border display-details display-duplicates display-empty +display-empty-cells-as display-filter-buttons display-formula +display-hidden display-label display-levels display-name display-outline-level +display-x-axis dissolve distance distance-after-sep @@ -1094,6 +1107,7 @@ line-number line-skew line-spacing line-style +line-width linear linearGradient linenumbering-configuration @@ -1121,6 +1135,7 @@ log logarithmic logbase long +low lowlimit lr-tb lt @@ -1134,6 +1149,8 @@ major-origin maligngroup malignmark manual +manual-min +manual-max map margin-bottom margin-left @@ -1141,6 +1158,7 @@ margin-right margin-top margins marker +markers marker-end marker-end-center marker-end-width @@ -1159,6 +1177,7 @@ matrix matrix-covered matrixrow max +max-axis-type max-edge max-height max-length @@ -1184,6 +1203,7 @@ mi middle mime-type min +min-axis-type min-denominator-digits min-edge min-exponent-digits @@ -1258,6 +1278,7 @@ named-expressions named-range navigation-mode navy +negative negative-color neq new @@ -1519,6 +1540,7 @@ ridge right right-outside right-text +right-to-left right-arc right-circle ring @@ -1673,6 +1695,10 @@ source-name source-range-address source-service space-before +sparkline-groups +sparkline-group +sparklines +sparkline span specular specular-color commit 10cfe5955d8d2e7d5adfdd16c1c0404f363fb116 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Sat Mar 26 01:33:29 2022 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Tue Apr 12 08:22:47 2022 +0200 sc: add support for xr2 namespace and read uid of sparkline group Change-Id: I470819a89338f4fb1d9b2486ffb4d93f8eb42844 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132504 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit 1d25d32b4dcfbc750b8344cd79279aad0d621edf) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132843 Tested-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx index daea0ad49962..877e8d52eda3 100644 --- a/oox/source/core/xmlfilterbase.cxx +++ b/oox/source/core/xmlfilterbase.cxx @@ -146,6 +146,8 @@ const Sequence< beans::Pair< OUString, sal_Int32 > >& NamespaceIds() NMSP_x12ac}, {"http://schemas.microsoft.com/office/drawing/2012/chart", NMSP_c15}, + {"http://schemas.microsoft.com/office/spreadsheetml/2015/revision2", + NMSP_xr2}, }; return SINGLETON; }; diff --git a/oox/source/token/namespaces-strict.txt b/oox/source/token/namespaces-strict.txt index 5024249bfacc..7449dca99a33 100644 --- a/oox/source/token/namespaces-strict.txt +++ b/oox/source/token/namespaces-strict.txt @@ -88,6 +88,7 @@ w15 http://schemas.microsoft.com/office/word/2012/wordml p15 http://schemas.microsoft.com/office/powerpoint/2012/main x12ac http://schemas.microsoft.com/office/spreadsheetml/2011/1/ac c15 http://schemas.microsoft.com/office/drawing/2012/chart +xr2 http://schemas.microsoft.com/office/spreadsheetml/2015/revision2 # extlst namespaces diff --git a/oox/source/token/namespaces.hxx.tail b/oox/source/token/namespaces.hxx.tail index fdea5b96f1b4..382955683d7d 100644 --- a/oox/source/token/namespaces.hxx.tail +++ b/oox/source/token/namespaces.hxx.tail @@ -62,6 +62,7 @@ inline sal_Int32 getNamespace( sal_Int32 nToken ) { return nToken & NMSP_MASK; } #define W_TOKEN( token ) OOX_TOKEN( doc, token ) #define LOEXT_TOKEN( token ) OOX_TOKEN( loext, token ) #define M_TOKEN(token) OOX_TOKEN(officeMath, token) +#define XR2_TOKEN(token) OOX_TOKEN(xr2, token) diff --git a/oox/source/token/namespaces.txt b/oox/source/token/namespaces.txt index f18e0833f31d..849caa547695 100644 --- a/oox/source/token/namespaces.txt +++ b/oox/source/token/namespaces.txt @@ -88,6 +88,7 @@ w15 http://schemas.microsoft.com/office/word/2012/wordml p15 http://schemas.microsoft.com/office/powerpoint/2012/main x12ac http://schemas.microsoft.com/office/spreadsheetml/2011/1/ac c15 http://schemas.microsoft.com/office/drawing/2012/chart +xr2 http://schemas.microsoft.com/office/spreadsheetml/2015/revision2 # extlst namespaces diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index 593ef0b23a5d..d1a40140add9 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -5848,6 +5848,7 @@ xmlDataType xmlPr xmlns xpath +xr2 xrange xsc xscale diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx index 9e2fd89ff9cf..051e45d9e95a 100644 --- a/sc/inc/SparklineGroup.hxx +++ b/sc/inc/SparklineGroup.hxx @@ -22,11 +22,14 @@ class SC_DLLPUBLIC SparklineGroup { private: SparklineAttributes m_aAttributes; + OUString m_sUID; public: SparklineAttributes& getAttributes() { return m_aAttributes; } - OUString m_sUID; + OUString getID() { return m_sUID; } + + void setID(OUString const& rID) { m_sUID = rID; } SparklineGroup(); SparklineGroup(SparklineGroup const& pOtherSparkline); diff --git a/sc/qa/unit/SparklineImportExportTest.cxx b/sc/qa/unit/SparklineImportExportTest.cxx index 8f36cf2f9adf..2c324121a337 100644 --- a/sc/qa/unit/SparklineImportExportTest.cxx +++ b/sc/qa/unit/SparklineImportExportTest.cxx @@ -59,6 +59,9 @@ void checkSparklines(ScDocument& rDocument) { auto pSparkline = rDocument.GetSparkline(ScAddress(0, 1, 0)); // A2 CPPUNIT_ASSERT(pSparkline); + CPPUNIT_ASSERT_EQUAL(OUString("{1C5C5DE0-3C09-4CB3-A3EC-9E763301EC82}"), + pSparkline->getSparklineGroup()->getID()); + auto& rAttributes = pSparkline->getSparklineGroup()->getAttributes(); CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, rAttributes.getType()); diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx index 529e76971cbc..c01dde32981c 100644 --- a/sc/source/filter/excel/excdoc.cxx +++ b/sc/source/filter/excel/excdoc.cxx @@ -696,6 +696,7 @@ void ExcTable::WriteXml( XclExpXmlStream& rStrm ) FSNS(XML_xmlns, XML_r), rStrm.getNamespaceURL(OOX_NS(officeRel)).toUtf8(), FSNS(XML_xmlns, XML_xdr), "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing", // rStrm.getNamespaceURL(OOX_NS(xm)).toUtf8() -> "http://schemas.microsoft.com/office/excel/2006/main", FSNS(XML_xmlns, XML_x14), rStrm.getNamespaceURL(OOX_NS(xls14Lst)).toUtf8(), + FSNS(XML_xmlns, XML_xr2), rStrm.getNamespaceURL(OOX_NS(xr2)).toUtf8(), FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8()); SetCurrScTab( mnScTab ); diff --git a/sc/source/filter/excel/export/SparklineExt.cxx b/sc/source/filter/excel/export/SparklineExt.cxx index 1a82dbec46da..549365dcb003 100644 --- a/sc/source/filter/excel/export/SparklineExt.cxx +++ b/sc/source/filter/excel/export/SparklineExt.cxx @@ -187,6 +187,12 @@ void SparklineExt::addSparklineGroup(XclExpXmlStream& rStream, sc::SparklineGrou // Sparkline Group Attributes auto pAttrList = sax_fastparser::FastSerializerHelper::createAttrList(); + + // Write ID + OString sUID = OUStringToOString(rSparklineGroup.getID(), RTL_TEXTENCODING_UTF8); + pAttrList->addNS(XML_xr2, XML_uid, sUID); + + // Write attributes addSparklineGroupAttributes(pAttrList, rSparklineGroup.getAttributes()); rWorksheet->startElementNS(XML_x14, XML_sparklineGroup, pAttrList); diff --git a/sc/source/filter/oox/SparklineFragment.cxx b/sc/source/filter/oox/SparklineFragment.cxx index 451b7b2a70e1..94fefc37949f 100644 --- a/sc/source/filter/oox/SparklineFragment.cxx +++ b/sc/source/filter/oox/SparklineFragment.cxx @@ -173,7 +173,8 @@ ContextHandlerRef SparklineGroupsContext::onCreateContext(sal_Int32 nElement, auto& rLastGroup = m_aSparklineGroups.emplace_back(); auto& rSparklineAttributes = rLastGroup.getSparklineGroup()->getAttributes(); addAttributesToSparklineAttributes(rSparklineAttributes, rAttribs); - rLastGroup.getSparklineGroup()->m_sUID = rAttribs.getString(XML_uid, OUString()); + OUString sUID = rAttribs.getString(XR2_TOKEN(uid), OUString()); + rLastGroup.getSparklineGroup()->setID(sUID); return this; } case XLS14_TOKEN(colorSeries): diff --git a/test/source/xmltesttools.cxx b/test/source/xmltesttools.cxx index f92c380d9bf8..ab9e5dcff8b8 100644 --- a/test/source/xmltesttools.cxx +++ b/test/source/xmltesttools.cxx @@ -440,6 +440,8 @@ void XmlTestTools::registerOOXMLNamespaces(xmlXPathContextPtr& pXmlXpathCtx) BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/diagram")); xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("c15"), BAD_CAST("http://schemas.microsoft.com/office/drawing/2012/chart")); + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xr2"), + BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2015/revision2")); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */