oox/source/token/tokens.txt                |   24 +++
 sc/Library_scfilt.mk                       |    1 
 sc/source/filter/inc/SparklineFragment.hxx |   94 ++++++++++++++
 sc/source/filter/oox/SparklineFragment.cxx |  189 +++++++++++++++++++++++++++++
 sc/source/filter/oox/extlstcontext.cxx     |    2 
 5 files changed, 310 insertions(+)

New commits:
commit 343a5786f946f45818c6d7d7aebf3b1972f4187d
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Wed Feb 2 15:25:28 2022 +0900
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Sun Apr 10 15:31:15 2022 +0200

    sc: support reading sparklines from OOXML document
    
    Read sparklines and sparkline groups from the OOXML document and
    add store it into a (temporary local) doc. model.
    
    Change-Id: Id2d34db70300957735571875d6defb3d560fbb26
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131161
    Tested-by: Tomaž Vajngerl <qui...@gmail.com>
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    (cherry picked from commit 04b3a9baf5731696418bc1a6db8c8b1bf65dc7c4)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132546

diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt
index 9a10000c1fc8..593ef0b23a5d 100644
--- a/oox/source/token/tokens.txt
+++ b/oox/source/token/tokens.txt
@@ -1291,9 +1291,17 @@ collapsedLevelsAreSubtotals
 colon
 color
 color2
+colorAxis
 colorFilter
+colorFirst
+colorHigh
 colorId
+colorLast
+colorLow
+colorMarkers
+colorNegative
 colorScale
+colorSeries
 colorTemp
 colorTemperature
 colormenu
@@ -1662,6 +1670,7 @@ datastoreItem
 date
 date1904
 dateAx
+dateAxis
 dateBetween
 dateCompatibility
 dateEqual
@@ -1825,12 +1834,15 @@ dispUnitsLbl
 displacedByCustomXml
 display
 displayBackgroundShape
+displayEmptyCellsAs
 displayFolder
 displayHangulFixedWidth
+displayHidden
 displayHorizontalDrawingGridEvery
 displayName
 displayText
 displayVerticalDrawingGridEvery
+displayXAxis
 displayed
 dissolve
 dist
@@ -3136,6 +3148,7 @@ lineMarker
 linePitch
 lineRule
 lineTo
+lineWeight
 lineWrapLikeWord6
 linear
 linen
@@ -3283,6 +3296,8 @@ manifestLocation
 manual
 manualBreakCount
 manualLayout
+manualMax
+manualMin
 map
 mapId
 mapPins
@@ -3303,6 +3318,7 @@ marTop
 marW
 margin
 marker
+markers
 markup
 maroon
 marquee
@@ -3325,6 +3341,7 @@ mathPr
 matrix
 matte
 max
+maxAxisType
 maxAng
 maxDate
 maxDepth
@@ -3402,6 +3419,7 @@ middleDot
 midnightBlue
 millions
 min
+minAxisType
 minAng
 minDate
 minLength
@@ -3505,6 +3523,7 @@ nc
 nd
 ndxf
 neCell
+negative
 negativeBarColorSameAsPositive
 negativeFillColor
 negativeInteger
@@ -4868,6 +4887,10 @@ span
 spanAng
 spans
 sparkle
+sparklineGroups
+sparklineGroup
+sparklines
+sparkline
 spc
 spcAft
 spcBef
@@ -5488,6 +5511,7 @@ ui8
 uiCompat97To2003
 uiExpand
 uiPriority
+uid
 uint
 ulTrailSpace
 un
diff --git a/sc/Library_scfilt.mk b/sc/Library_scfilt.mk
index d7da0cd95f44..da73e3c43f15 100644
--- a/sc/Library_scfilt.mk
+++ b/sc/Library_scfilt.mk
@@ -202,6 +202,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\
        sc/source/filter/oox/sharedstringsfragment \
        sc/source/filter/oox/sheetdatabuffer \
        sc/source/filter/oox/sheetdatacontext \
+       sc/source/filter/oox/SparklineFragment \
        sc/source/filter/oox/stylesbuffer \
        sc/source/filter/oox/stylesfragment \
        sc/source/filter/oox/tablebuffer \
diff --git a/sc/source/filter/inc/SparklineFragment.hxx 
b/sc/source/filter/inc/SparklineFragment.hxx
new file mode 100644
index 000000000000..36a7b5ca9f05
--- /dev/null
+++ b/sc/source/filter/inc/SparklineFragment.hxx
@@ -0,0 +1,94 @@
+/* -*- 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 "excelhandlers.hxx"
+#include <oox/core/contexthandler.hxx>
+
+#include <vector>
+#include <memory>
+#include <optional>
+
+namespace oox
+{
+class AttributeList;
+}
+
+namespace oox::xls
+{
+class Sparkline
+{
+public:
+    ScRangeList m_aInputRange;
+    ScRangeList m_aTargetRange;
+    Sparkline() {}
+};
+
+class SparklineGroup
+{
+private:
+    std::vector<Sparkline> m_aSparklines;
+
+public:
+    Color m_aColorSeries;
+    Color m_aColorNegative;
+    Color m_aColorAxis;
+    Color m_aColorMarkers;
+    Color m_aColorFirst;
+    Color m_aColorLast;
+    Color m_aColorHigh;
+    Color m_aColorLow;
+
+    OUString m_sMinAxisType; // individual, group, custom
+    OUString m_sMaxAxisType;
+
+    double m_fLineWeight; // In pt
+
+    OUString m_sType; // line, column, stacked
+
+    bool m_bDateAxis;
+
+    OUString m_sDisplayEmptyCellsAs; // span, gap, zero
+
+    bool m_bMarkers;
+    bool m_bHigh;
+    bool m_bLow;
+    bool m_bFirst;
+    bool m_bLast;
+    bool m_bNegative;
+    bool m_bDisplayXAxis;
+    bool m_bDisplayHidden;
+    bool m_bRightToLeft;
+
+    std::optional<double> m_aManualMax;
+    std::optional<double> m_aManualMin;
+    OUString m_sUID;
+
+    std::vector<Sparkline>& getSparklines() { return m_aSparklines; }
+};
+
+class SparklineGroupsContext : public WorksheetContextBase
+{
+private:
+    std::vector<SparklineGroup> m_aSparklineGroups;
+
+public:
+    explicit SparklineGroupsContext(WorksheetContextBase& rFragment);
+
+    oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement,
+                                                 const AttributeList& 
rAttribs) override;
+    void onStartElement(const AttributeList& rAttribs) override;
+    void onCharacters(const OUString& rCharacters) override;
+    void onEndElement() override;
+};
+
+} //namespace oox::xls
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/SparklineFragment.cxx 
b/sc/source/filter/oox/SparklineFragment.cxx
new file mode 100644
index 000000000000..a743b886b7db
--- /dev/null
+++ b/sc/source/filter/oox/SparklineFragment.cxx
@@ -0,0 +1,189 @@
+/* -*- 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 <SparklineFragment.hxx>
+#include <oox/core/contexthandler.hxx>
+#include <oox/token/tokens.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/helper/helper.hxx>
+#include <oox/helper/attributelist.hxx>
+#include <document.hxx>
+#include <rangeutl.hxx>
+
+using ::oox::core::ContextHandlerRef;
+
+namespace oox::xls
+{
+namespace
+{
+Color getColor(const AttributeList& rAttribs)
+{
+    if (rAttribs.hasAttribute(XML_rgb))
+    {
+        return Color(ColorTransparency,
+                     rAttribs.getIntegerHex(XML_rgb, 
sal_Int32(API_RGB_TRANSPARENT)));
+    }
+    return Color();
+}
+
+void addColorsToSparklineGroup(SparklineGroup& rSparklineGroup, sal_Int32 
nElement,
+                               const AttributeList& rAttribs)
+{
+    switch (nElement)
+    {
+        case XLS14_TOKEN(colorSeries):
+            rSparklineGroup.m_aColorSeries = getColor(rAttribs);
+            break;
+        case XLS14_TOKEN(colorNegative):
+            rSparklineGroup.m_aColorNegative = getColor(rAttribs);
+            break;
+        case XLS14_TOKEN(colorAxis):
+            rSparklineGroup.m_aColorAxis = getColor(rAttribs);
+            break;
+        case XLS14_TOKEN(colorMarkers):
+            rSparklineGroup.m_aColorMarkers = getColor(rAttribs);
+            break;
+        case XLS14_TOKEN(colorFirst):
+            rSparklineGroup.m_aColorFirst = getColor(rAttribs);
+            break;
+        case XLS14_TOKEN(colorLast):
+            rSparklineGroup.m_aColorLast = getColor(rAttribs);
+            break;
+        case XLS14_TOKEN(colorHigh):
+            rSparklineGroup.m_aColorHigh = getColor(rAttribs);
+            break;
+        case XLS14_TOKEN(colorLow):
+            rSparklineGroup.m_aColorLow = getColor(rAttribs);
+            break;
+        default:
+            break;
+    }
+}
+
+void addAttributesToSparklineGroup(SparklineGroup& rSparklineGroup, const 
AttributeList& rAttribs)
+{
+    auto oManualMax = rAttribs.getDouble(XML_manualMax);
+    auto oManualMin = rAttribs.getDouble(XML_manualMin);
+
+    rSparklineGroup.m_fLineWeight = rAttribs.getDouble(XML_lineWeight, 0.75);
+
+    rSparklineGroup.m_sType = rAttribs.getString(XML_type, "line");
+
+    rSparklineGroup.m_bDateAxis = rAttribs.getBool(XML_dateAxis, false);
+
+    rSparklineGroup.m_sDisplayEmptyCellsAs = 
rAttribs.getString(XML_displayEmptyCellsAs, "zero");
+
+    rSparklineGroup.m_bMarkers = rAttribs.getBool(XML_markers, false);
+    rSparklineGroup.m_bHigh = rAttribs.getBool(XML_high, false);
+    rSparklineGroup.m_bLow = rAttribs.getBool(XML_low, false);
+    rSparklineGroup.m_bFirst = rAttribs.getBool(XML_first, false);
+    rSparklineGroup.m_bLast = rAttribs.getBool(XML_last, false);
+    rSparklineGroup.m_bNegative = rAttribs.getBool(XML_negative, false);
+    rSparklineGroup.m_bDisplayXAxis = rAttribs.getBool(XML_displayXAxis, 
false);
+    rSparklineGroup.m_bDisplayHidden = rAttribs.getBool(XML_displayHidden, 
false);
+
+    rSparklineGroup.m_sMinAxisType = rAttribs.getString(XML_minAxisType, 
"individual");
+    rSparklineGroup.m_sMaxAxisType = rAttribs.getString(XML_maxAxisType, 
"individual");
+
+    rSparklineGroup.m_bRightToLeft = rAttribs.getBool(XML_rightToLeft, false);
+
+    rSparklineGroup.m_sUID = rAttribs.getString(XML_uid, OUString());
+
+    if (rSparklineGroup.m_sMaxAxisType == "custom")
+        rSparklineGroup.m_aManualMax = oManualMax.get();
+    if (rSparklineGroup.m_sMinAxisType == "custom")
+        rSparklineGroup.m_aManualMin = oManualMin.get();
+}
+
+} // end anonymous namespace
+
+SparklineGroupsContext::SparklineGroupsContext(WorksheetContextBase& rFragment)
+    : WorksheetContextBase(rFragment)
+{
+}
+
+ContextHandlerRef SparklineGroupsContext::onCreateContext(sal_Int32 nElement,
+                                                          const AttributeList& 
rAttribs)
+{
+    switch (nElement)
+    {
+        case XLS14_TOKEN(sparklineGroup):
+        {
+            auto& rLastGroup = m_aSparklineGroups.emplace_back();
+            addAttributesToSparklineGroup(rLastGroup, rAttribs);
+            return this;
+        }
+        case XLS14_TOKEN(colorSeries):
+        case XLS14_TOKEN(colorNegative):
+        case XLS14_TOKEN(colorAxis):
+        case XLS14_TOKEN(colorMarkers):
+        case XLS14_TOKEN(colorFirst):
+        case XLS14_TOKEN(colorLast):
+        case XLS14_TOKEN(colorHigh):
+        case XLS14_TOKEN(colorLow):
+        {
+            auto& rLastGroup = m_aSparklineGroups.back();
+            addColorsToSparklineGroup(rLastGroup, nElement, rAttribs);
+            return this;
+        }
+        case XLS14_TOKEN(sparklines):
+        {
+            return this;
+        }
+        case XLS14_TOKEN(sparkline):
+        {
+            auto& rLastGroup = m_aSparklineGroups.back();
+            rLastGroup.getSparklines().emplace_back();
+            return this;
+        }
+    }
+    return this;
+}
+
+void SparklineGroupsContext::onStartElement(const AttributeList&) {}
+
+void SparklineGroupsContext::onCharacters(const OUString& rChars)
+{
+    if (getCurrentElement() == XM_TOKEN(sqref) || getCurrentElement() == 
XM_TOKEN(f))
+    {
+        ScDocument& rDocument = getScDocument();
+        auto& rLastGroup = m_aSparklineGroups.back();
+        auto& rLastSparkline = rLastGroup.getSparklines().back();
+
+        ScRangeList aRange;
+        if (ScRangeStringConverter::GetRangeListFromString(aRange, rChars, 
rDocument,
+                                                           
formula::FormulaGrammar::CONV_XL_OOX))
+        {
+            if (!aRange.empty())
+            {
+                if (getCurrentElement() == XM_TOKEN(sqref))
+                {
+                    rLastSparkline.m_aTargetRange = aRange;
+
+                    // Need to set the current sheet index to the range as
+                    // it is assumed that the address string referes to
+                    // the current sheet and is not defined in the string.
+                    for (auto& rRange : rLastSparkline.m_aTargetRange)
+                    {
+                        rRange.aStart.SetTab(getSheetIndex());
+                        rRange.aEnd.SetTab(getSheetIndex());
+                    }
+                }
+                else if (getCurrentElement() == XM_TOKEN(f))
+                    rLastSparkline.m_aInputRange = aRange;
+            }
+        }
+    }
+}
+
+void SparklineGroupsContext::onEndElement() {}
+
+} //namespace oox::xls
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/extlstcontext.cxx 
b/sc/source/filter/oox/extlstcontext.cxx
index eee453a7242c..67d52fc69da9 100644
--- a/sc/source/filter/oox/extlstcontext.cxx
+++ b/sc/source/filter/oox/extlstcontext.cxx
@@ -22,6 +22,7 @@
 #include <workbookfragment.hxx>
 #include <stylesbuffer.hxx>
 #include <stylesfragment.hxx>
+#include <SparklineFragment.hxx>
 
 #include <rangeutl.hxx>
 #include <sal/log.hxx>
@@ -350,6 +351,7 @@ ContextHandlerRef ExtGlobalContext::onCreateContext( 
sal_Int32 nElement, const A
     {
         case XLS14_TOKEN(conditionalFormatting): return new 
ExtConditionalFormattingContext(*this);
         case XLS14_TOKEN(dataValidations):       return new 
ExtDataValidationsContext(*this);
+        case XLS14_TOKEN(sparklineGroups): return new 
SparklineGroupsContext(*this);
     }
     return this;
 }

Reply via email to