Rebased ref, commits from common ancestor:
commit 1c5d5eb6c25ec32166a8d38cfa3812bced00d5b3
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Fri Apr 1 17:06:18 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Apr 1 17:17:57 2022 +0900

    sc: improve SparklineList to track added SparklineGroups
    
    SparklineList used to only track added Sparklines for a sheet, but
    usually (in an export) we want to start with SparklineGroups and
    then search for all sparklines belonging to a group. This changes
    to use that. Now there is a method getSparklineGroups() and then
    another method getSparklineFor(), which returns all sparklines for
    the input group.
    
    Also added SparklineListTest, and refactored the export code for
    OOXML and ODF.
    
    Change-Id: I975e30f649788d41aab92a9a3220e38998e39670

diff --git a/sc/inc/Sparkline.hxx b/sc/inc/Sparkline.hxx
index 5cc079f8530e..0cdf7be9b55c 100644
--- a/sc/inc/Sparkline.hxx
+++ b/sc/inc/Sparkline.hxx
@@ -48,41 +48,6 @@ public:
     SCROW getRow() const { return m_nRow; }
 };
 
-class SC_DLLPUBLIC SparklineList
-{
-private:
-    std::vector<std::weak_ptr<Sparkline>> m_pSparklines;
-
-public:
-    SparklineList() {}
-
-    void addSparkline(std::shared_ptr<Sparkline> const& pSparkline)
-    {
-        m_pSparklines.push_back(pSparkline);
-    }
-
-    std::vector<std::shared_ptr<Sparkline>> getSparklines()
-    {
-        std::vector<std::shared_ptr<Sparkline>> toReturn;
-
-        std::vector<std::weak_ptr<Sparkline>>::iterator aIter;
-        for (aIter = m_pSparklines.begin(); aIter != m_pSparklines.end();)
-        {
-            if (auto aSparkline = aIter->lock())
-            {
-                toReturn.push_back(aSparkline);
-                aIter++;
-            }
-            else
-            {
-                aIter = m_pSparklines.erase(aIter);
-            }
-        }
-
-        return toReturn;
-    }
-};
-
 } // end sc
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/SparklineList.hxx b/sc/inc/SparklineList.hxx
new file mode 100644
index 000000000000..2c51ab296a84
--- /dev/null
+++ b/sc/inc/SparklineList.hxx
@@ -0,0 +1,101 @@
+/* -*- 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 "scdllapi.h"
+#include <memory>
+#include <map>
+
+#include "rangelst.hxx"
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+/** Tracks and gathers all created sparklines and sparkline groups.
+ *
+ * All the collections of sparkline groups and sparklines don't take
+ * the ownership of the pointers.
+ */
+class SC_DLLPUBLIC SparklineList
+{
+private:
+    std::vector<std::weak_ptr<SparklineGroup>> m_aSparklineGroups;
+    std::map<std::weak_ptr<SparklineGroup>, 
std::vector<std::weak_ptr<Sparkline>>,
+             std::owner_less<>>
+        m_aSparklineGroupMap;
+
+public:
+    SparklineList() {}
+
+    void addSparkline(std::shared_ptr<Sparkline> const& pSparkline)
+    {
+        auto pWeakGroup = 
std::weak_ptr<SparklineGroup>(pSparkline->getSparklineGroup());
+
+        auto[iterator, bInserted]
+            = m_aSparklineGroupMap.try_emplace(pWeakGroup, 
std::vector<std::weak_ptr<Sparkline>>());
+        iterator->second.push_back(std::weak_ptr<Sparkline>(pSparkline));
+        if (bInserted)
+            m_aSparklineGroups.push_back(pWeakGroup);
+    }
+
+    std::vector<std::shared_ptr<SparklineGroup>> getSparklineGroups()
+    {
+        std::vector<std::shared_ptr<SparklineGroup>> toReturn;
+
+        for (auto iterator = m_aSparklineGroups.begin(); iterator != 
m_aSparklineGroups.end();)
+        {
+            if (auto pSparklineGroup = iterator->lock())
+            {
+                toReturn.push_back(pSparklineGroup);
+                iterator++;
+            }
+            else
+            {
+                iterator = m_aSparklineGroups.erase(iterator);
+            }
+        }
+        return toReturn;
+    }
+
+    std::vector<std::shared_ptr<Sparkline>>
+    getSparklinesFor(std::shared_ptr<SparklineGroup> const& pSparklineGroup)
+    {
+        std::vector<std::shared_ptr<Sparkline>> toReturn;
+
+        std::weak_ptr<SparklineGroup> pWeakGroup(pSparklineGroup);
+        auto iteratorGroup = m_aSparklineGroupMap.find(pWeakGroup);
+
+        if (iteratorGroup == m_aSparklineGroupMap.end())
+            return toReturn;
+
+        auto& rWeakSparklines = iteratorGroup->second;
+
+        for (auto iterator = rWeakSparklines.begin(); iterator != 
rWeakSparklines.end();)
+        {
+            if (auto aSparkline = iterator->lock())
+            {
+                toReturn.push_back(aSparkline);
+                iterator++;
+            }
+            else
+            {
+                iterator = rWeakSparklines.erase(iterator);
+            }
+        }
+
+        return toReturn;
+    }
+};
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index ca099be7a0a0..7b3c01e67989 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -32,6 +32,7 @@
 #include <formula/errorcodes.hxx>
 #include "document.hxx"
 #include "drwlayer.hxx"
+#include "SparklineList.hxx"
 
 #include <algorithm>
 #include <atomic>
diff --git a/sc/qa/unit/SparklineTest.cxx b/sc/qa/unit/SparklineTest.cxx
index 16381527adda..ff09564a972b 100644
--- a/sc/qa/unit/SparklineTest.cxx
+++ b/sc/qa/unit/SparklineTest.cxx
@@ -15,6 +15,7 @@
 
 #include <Sparkline.hxx>
 #include <SparklineGroup.hxx>
+#include <SparklineList.hxx>
 
 using namespace css;
 
@@ -54,6 +55,7 @@ public:
     void testUndoRedoDeleteSparkline();
     void testUndoRedoClearContentForSparkline();
     void testUndoRedoEditSparklineGroup();
+    void testSparklineList();
 
     CPPUNIT_TEST_SUITE(SparklineTest);
     CPPUNIT_TEST(testAddSparkline);
@@ -64,6 +66,7 @@ public:
     CPPUNIT_TEST(testUndoRedoDeleteSparkline);
     CPPUNIT_TEST(testUndoRedoClearContentForSparkline);
     CPPUNIT_TEST(testUndoRedoEditSparklineGroup);
+    CPPUNIT_TEST(testSparklineList);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -113,10 +116,12 @@ void SparklineTest::testAddSparkline()
 
     CPPUNIT_ASSERT_EQUAL(pGetSparkline.get(), pSparkline);
 
-    sc::SparklineList* pList = rDocument.GetSparklineList(0);
+    sc::SparklineList* pList = rDocument.GetSparklineList(SCTAB(0));
     CPPUNIT_ASSERT(pList);
 
-    std::vector<std::shared_ptr<sc::Sparkline>> aSparklineVector = 
pList->getSparklines();
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pList->getSparklineGroups().size());
+
+    auto const& aSparklineVector = 
pList->getSparklinesFor(pGetSparkline->getSparklineGroup());
     CPPUNIT_ASSERT_EQUAL(size_t(1), aSparklineVector.size());
     CPPUNIT_ASSERT_EQUAL(aSparklineVector[0].get(), pSparkline);
 
@@ -496,6 +501,65 @@ void SparklineTest::testUndoRedoEditSparklineGroup()
     xDocSh->DoClose();
 }
 
+void SparklineTest::testSparklineList()
+{
+    ScDocShellRef xDocSh = loadEmptyDocument();
+    CPPUNIT_ASSERT(xDocSh);
+
+    ScDocument& rDocument = xDocSh->GetDocument();
+
+    auto pSparklineGroup = std::make_shared<sc::SparklineGroup>();
+
+    rDocument.CreateSparkline(ScAddress(0, 6, 0), pSparklineGroup);
+
+    {
+        auto* pSparklineList = rDocument.GetSparklineList(SCTAB(0));
+        auto pSparklineGroups = pSparklineList->getSparklineGroups();
+        CPPUNIT_ASSERT_EQUAL(size_t(1), pSparklineGroups.size());
+
+        auto pSparklines = 
pSparklineList->getSparklinesFor(pSparklineGroups[0]);
+        CPPUNIT_ASSERT_EQUAL(size_t(1), pSparklines.size());
+    }
+    rDocument.CreateSparkline(ScAddress(1, 6, 0), pSparklineGroup);
+    rDocument.CreateSparkline(ScAddress(2, 6, 0), pSparklineGroup);
+
+    {
+        auto* pSparklineList = rDocument.GetSparklineList(SCTAB(0));
+        auto pSparklineGroups = pSparklineList->getSparklineGroups();
+        CPPUNIT_ASSERT_EQUAL(size_t(1), pSparklineGroups.size());
+
+        auto pSparklines = 
pSparklineList->getSparklinesFor(pSparklineGroups[0]);
+        CPPUNIT_ASSERT_EQUAL(size_t(3), pSparklines.size());
+    }
+
+    {
+        auto pSparklineGroup2 = std::make_shared<sc::SparklineGroup>();
+        rDocument.CreateSparkline(ScAddress(3, 6, 0), pSparklineGroup2);
+
+        auto* pSparklineList = rDocument.GetSparklineList(SCTAB(0));
+
+        auto pSparklineGroups = pSparklineList->getSparklineGroups();
+        CPPUNIT_ASSERT_EQUAL(size_t(2), pSparklineGroups.size());
+
+        auto pSparklines2 = pSparklineList->getSparklinesFor(pSparklineGroup2);
+        CPPUNIT_ASSERT_EQUAL(size_t(1), pSparklines2.size());
+    }
+
+    rDocument.DeleteSparkline(ScAddress(3, 6, 0));
+
+    {
+        auto* pSparklineList = rDocument.GetSparklineList(SCTAB(0));
+
+        auto pSparklineGroups = pSparklineList->getSparklineGroups();
+        CPPUNIT_ASSERT_EQUAL(size_t(1), pSparklineGroups.size());
+
+        auto pSparklines = 
pSparklineList->getSparklinesFor(pSparklineGroups[0]);
+        CPPUNIT_ASSERT_EQUAL(size_t(3), pSparklines.size());
+    }
+
+    xDocSh->DoClose();
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SparklineTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 351e795ac5da..3a93964024b8 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -87,6 +87,7 @@
 #include <compressedarray.hxx>
 #include <recursionhelper.hxx>
 #include <SparklineGroup.hxx>
+#include <SparklineList.hxx>
 
 #include <formula/vectortoken.hxx>
 
@@ -6588,13 +6589,12 @@ std::shared_ptr<sc::SparklineGroup> 
ScDocument::SearchSparklineGroup(tools::Guid
 {
     for (auto const& rTable : maTabs)
     {
-        std::vector<std::shared_ptr<sc::SparklineGroup>> aSparklineGroupMap;
+        auto& rSparklineList = rTable->GetSparklineList();
 
-        for (auto const& pSparkline : 
rTable->GetSparklineList().getSparklines())
+        for (auto const& pSparklineGroup : rSparklineList.getSparklineGroups())
         {
-            auto const& pGroup = pSparkline->getSparklineGroup();
-            if (pGroup->getID() == rGuid)
-                return pGroup;
+            if (pSparklineGroup->getID() == rGuid)
+                return pSparklineGroup;
         }
     }
 
diff --git a/sc/source/filter/excel/export/SparklineExt.cxx 
b/sc/source/filter/excel/export/SparklineExt.cxx
index 47e469a31ef0..986852f2e9c2 100644
--- a/sc/source/filter/excel/export/SparklineExt.cxx
+++ b/sc/source/filter/excel/export/SparklineExt.cxx
@@ -13,37 +13,28 @@
 #include <oox/token/namespaces.hxx>
 #include <oox/token/tokens.hxx>
 #include <SparklineGroup.hxx>
+#include <SparklineList.hxx>
 
 using namespace oox;
 
 namespace xcl::exp
 {
-SparklineExt::SparklineExt(const XclExpRoot& rRoot,
-                           std::vector<std::shared_ptr<sc::Sparkline>> const& 
pSparklines)
+SparklineExt::SparklineExt(const XclExpRoot& rRoot)
     : XclExpExt(rRoot)
 {
     maURI = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}";
-
-    for (auto const& pSparkline : pSparklines)
-    {
-        auto* pGroupPointer = pSparkline->getSparklineGroup().get();
-
-        auto aIterator = m_aSparklineGroupMap.find(pGroupPointer);
-        if (aIterator == m_aSparklineGroupMap.end())
-        {
-            std::vector<std::shared_ptr<sc::Sparkline>> aSparklineVector;
-            aSparklineVector.push_back(pSparkline);
-            m_aSparklineGroupMap.emplace(pGroupPointer, aSparklineVector);
-        }
-        else
-        {
-            aIterator->second.push_back(pSparkline);
-        }
-    }
 }
 
 void SparklineExt::SaveXml(XclExpXmlStream& rStream)
 {
+    auto& rDocument = GetDoc();
+
+    auto* pSparklineList = rDocument.GetSparklineList(GetCurrScTab());
+    if (!pSparklineList)
+        return;
+
+    auto const& rSparklineGroups = pSparklineList->getSparklineGroups();
+
     sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream();
     rWorksheet->startElement(XML_ext, FSNS(XML_xmlns, XML_x14),
                              rStream.getNamespaceURL(OOX_NS(xls14Lst)), 
XML_uri, maURI);
@@ -51,8 +42,9 @@ void SparklineExt::SaveXml(XclExpXmlStream& rStream)
     rWorksheet->startElementNS(XML_x14, XML_sparklineGroups, FSNS(XML_xmlns, 
XML_xm),
                                rStream.getNamespaceURL(OOX_NS(xm)));
 
-    for (auto const & [ pSparklineGroup, rSparklineVector ] : 
m_aSparklineGroupMap)
+    for (auto const& pSparklineGroup : rSparklineGroups)
     {
+        auto const& rSparklineVector = 
pSparklineList->getSparklinesFor(pSparklineGroup);
         addSparklineGroup(rStream, *pSparklineGroup, rSparklineVector);
     }
 
@@ -238,14 +230,7 @@ void SparklineExt::addSparklineGroup(XclExpXmlStream& 
rStream, sc::SparklineGrou
 SparklineBuffer::SparklineBuffer(const XclExpRoot& rRoot, XclExtLstRef const& 
xExtLst)
     : XclExpRoot(rRoot)
 {
-    if (sc::SparklineList* pSparklineList = 
GetDoc().GetSparklineList(GetCurrScTab()))
-    {
-        auto pSparklines = pSparklineList->getSparklines();
-        if (!pSparklines.empty())
-        {
-            xExtLst->AddRecord(new xcl::exp::SparklineExt(GetRoot(), 
pSparklines));
-        }
-    }
+    xExtLst->AddRecord(new xcl::exp::SparklineExt(GetRoot()));
 }
 
 } // end namespace xcl::exp
diff --git a/sc/source/filter/inc/export/SparklineExt.hxx 
b/sc/source/filter/inc/export/SparklineExt.hxx
index 7d26922f15db..e6a155360545 100644
--- a/sc/source/filter/inc/export/SparklineExt.hxx
+++ b/sc/source/filter/inc/export/SparklineExt.hxx
@@ -26,11 +26,8 @@ namespace xcl::exp
 {
 class SparklineExt : public XclExpExt
 {
-    std::map<sc::SparklineGroup*, std::vector<std::shared_ptr<sc::Sparkline>>> 
m_aSparklineGroupMap;
-
 public:
-    SparklineExt(const XclExpRoot& rRoot,
-                 std::vector<std::shared_ptr<sc::Sparkline>> const& 
pSparklines);
+    SparklineExt(const XclExpRoot& rRoot);
 
     void SaveXml(XclExpXmlStream& rStream) override;
     void addSparklineGroup(XclExpXmlStream& rStream, sc::SparklineGroup& 
rSparklineGroup,
diff --git a/sc/source/filter/xml/SparklineGroupsExport.cxx 
b/sc/source/filter/xml/SparklineGroupsExport.cxx
index 4de56fcfaf58..077d43beab60 100644
--- a/sc/source/filter/xml/SparklineGroupsExport.cxx
+++ b/sc/source/filter/xml/SparklineGroupsExport.cxx
@@ -11,6 +11,8 @@
 #include "SparklineGroupsExport.hxx"
 #include "xmlexprt.hxx"
 #include <rangeutl.hxx>
+#include <SparklineList.hxx>
+#include <document.hxx>
 
 #include <xmloff/xmluconv.hxx>
 #include <xmloff/xmltoken.hxx>
@@ -25,27 +27,10 @@ using namespace xmloff::token;
 
 namespace sc
 {
-SparklineGroupsExport::SparklineGroupsExport(
-    ScXMLExport& rExport, SCTAB nTable, 
std::vector<std::shared_ptr<Sparkline>> const& rSparklines)
+SparklineGroupsExport::SparklineGroupsExport(ScXMLExport& rExport, SCTAB 
nTable)
     : 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)
@@ -183,7 +168,9 @@ void 
SparklineGroupsExport::addSparklineGroupAttributes(SparklineAttributes cons
     insertColor(rAttributes.getColorLow(), XML_COLOR_LOW);
 }
 
-void SparklineGroupsExport::addSparklineGroup(SparklineGroup* pSparklineGroup)
+void SparklineGroupsExport::addSparklineGroup(
+    std::shared_ptr<SparklineGroup> const& pSparklineGroup,
+    std::vector<std::shared_ptr<Sparkline>> const& rSparklines)
 {
     auto const& rAttributes = pSparklineGroup->getAttributes();
 
@@ -197,7 +184,8 @@ void 
SparklineGroupsExport::addSparklineGroup(SparklineGroup* pSparklineGroup)
 
     SvXMLElementExport aElementSparklines(m_rExport, XML_NAMESPACE_CALC_EXT, 
XML_SPARKLINES, true,
                                           true);
-    for (auto const& rSparkline : m_aSparklineGroupMap[pSparklineGroup])
+
+    for (auto const& rSparkline : rSparklines)
     {
         addSparklineAttributes(*rSparkline);
         SvXMLElementExport aElementSparkline(m_rExport, 
XML_NAMESPACE_CALC_EXT, XML_SPARKLINE, true,
@@ -207,13 +195,24 @@ void 
SparklineGroupsExport::addSparklineGroup(SparklineGroup* pSparklineGroup)
 
 void SparklineGroupsExport::write()
 {
-    SvXMLElementExport aElement(m_rExport, XML_NAMESPACE_CALC_EXT, 
XML_SPARKLINE_GROUPS, true,
-                                true);
-    for (auto* pSparklineGroup : m_aSparklineGroups)
+    auto* pDocument = m_rExport.GetDocument();
+    if (sc::SparklineList* pSparklineList = 
pDocument->GetSparklineList(m_nTable))
     {
-        addSparklineGroup(pSparklineGroup);
+        auto const& aSparklineGroups = pSparklineList->getSparklineGroups();
+        if (!aSparklineGroups.empty())
+        {
+            SvXMLElementExport aElement(m_rExport, XML_NAMESPACE_CALC_EXT, 
XML_SPARKLINE_GROUPS,
+                                        true, true);
+
+            for (auto const& pSparklineGroup : aSparklineGroups)
+            {
+                auto const& aSparklines = 
pSparklineList->getSparklinesFor(pSparklineGroup);
+                addSparklineGroup(pSparklineGroup, aSparklines);
+            }
+        }
     }
 }
-}
+
+} // end sc
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/SparklineGroupsExport.hxx 
b/sc/source/filter/xml/SparklineGroupsExport.hxx
index 4e49f585dbc7..b20fd8529574 100644
--- a/sc/source/filter/xml/SparklineGroupsExport.hxx
+++ b/sc/source/filter/xml/SparklineGroupsExport.hxx
@@ -25,21 +25,18 @@ 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 addSparklineGroup(std::shared_ptr<SparklineGroup> const& 
pSparklineGroup,
+                           std::vector<std::shared_ptr<Sparkline>> const& 
rSparklines);
     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);
+    SparklineGroupsExport(ScXMLExport& rExport, SCTAB nTable);
 
     void write();
 };
diff --git a/sc/source/filter/xml/xmlexprt.cxx 
b/sc/source/filter/xml/xmlexprt.cxx
index 1b273a7b53d5..8644108589b4 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -68,6 +68,7 @@
 #include <datamapper.hxx>
 #include <datatransformation.hxx>
 #include "SparklineGroupsExport.hxx"
+#include "SparklineList.hxx"
 
 #include <xmloff/xmltoken.hxx>
 #include <xmloff/xmlnamespace.hxx>
@@ -4516,15 +4517,8 @@ 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();
-        }
-    }
+    sc::SparklineGroupsExport aSparklineGroupExport(*this, nTable);
+    aSparklineGroupExport.write();
 }
 
 namespace {
commit 24ef83390d53d95f9c3becdd3e23e0f534abad4d
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Mar 31 23:07:44 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Apr 1 14:12:46 2022 +0900

    sc: add SparklineGroup Undo/Redo
    
    As SparklineAttributes are COW, we can just exchange them around
    in the SparklineGroup when undoing and redoing.
    
    This also changes SparklineDialog to work with a local copy of
    SparklineAttributes when editing, or an empty initial copy when
    inserting a new Sparkline into the sheet.
    
    Change-Id: I36e9c887ca640f40266f381e98e57f027a5ca07f

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index e97f6e04b4c2..294c36b4578c 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -555,6 +555,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/ui/undo/undotab \
     sc/source/ui/undo/undoutil \
     sc/source/ui/undo/UndoInsertSparkline \
+    sc/source/ui/undo/UndoEditSparklineGroup \
     sc/source/ui/undo/UndoDeleteSparkline \
     sc/source/ui/unoobj/ChartRangeSelectionListener \
     sc/source/ui/unoobj/addruno \
diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx
index d6cb8cf4402d..f9e0f7784feb 100644
--- a/sc/inc/SparklineGroup.hxx
+++ b/sc/inc/SparklineGroup.hxx
@@ -28,11 +28,14 @@ public:
     SparklineAttributes& getAttributes() { return m_aAttributes; }
     SparklineAttributes const& getAttributes() const { return m_aAttributes; }
 
+    void setAttributes(SparklineAttributes const& rAttributes) { m_aAttributes 
= rAttributes; };
+
     tools::Guid& getID() { return m_aGUID; }
 
     void setID(tools::Guid const& rGuid) { m_aGUID = rGuid; }
 
     SparklineGroup();
+    SparklineGroup(SparklineAttributes const& rSparklineAttributes);
 
     SparklineGroup(SparklineGroup const& pOtherSparkline);
 
diff --git a/sc/inc/globstr.hrc b/sc/inc/globstr.hrc
index bed2e10f9b51..adb02782122b 100644
--- a/sc/inc/globstr.hrc
+++ b/sc/inc/globstr.hrc
@@ -541,6 +541,7 @@
 #define STR_INDENTCELL                          NC_("STR_INDENTCELL", "Indent: 
")
 #define STR_UNDO_INSERT_SPARKLINE_GROUP         
NC_("STR_UNDO_INSERT_SPARKLINE", "Insert Sparkline Group")
 #define STR_UNDO_DELETE_SPARKLINE               
NC_("STR_UNDO_DELETE_SPARKLINE", "Delete Sparkline")
+#define STR_UNDO_EDIT_SPARKLINE_GROUP           
NC_("STR_UNDO_EDIT_SPARKLINE_GROUP", "Edit Sparkline Group")
 
 #endif
 
diff --git a/sc/qa/unit/SparklineTest.cxx b/sc/qa/unit/SparklineTest.cxx
index 64f05a703590..16381527adda 100644
--- a/sc/qa/unit/SparklineTest.cxx
+++ b/sc/qa/unit/SparklineTest.cxx
@@ -53,6 +53,7 @@ public:
     void testUndoRedoInsertSparkline();
     void testUndoRedoDeleteSparkline();
     void testUndoRedoClearContentForSparkline();
+    void testUndoRedoEditSparklineGroup();
 
     CPPUNIT_TEST_SUITE(SparklineTest);
     CPPUNIT_TEST(testAddSparkline);
@@ -62,6 +63,7 @@ public:
     CPPUNIT_TEST(testUndoRedoInsertSparkline);
     CPPUNIT_TEST(testUndoRedoDeleteSparkline);
     CPPUNIT_TEST(testUndoRedoClearContentForSparkline);
+    CPPUNIT_TEST(testUndoRedoEditSparklineGroup);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -427,6 +429,73 @@ void SparklineTest::testUndoRedoClearContentForSparkline()
     xDocSh->DoClose();
 }
 
+void SparklineTest::testUndoRedoEditSparklineGroup()
+{
+    ScDocShellRef xDocSh = loadEmptyDocument();
+    CPPUNIT_ASSERT(xDocSh);
+
+    ScDocument& rDocument = xDocSh->GetDocument();
+    ScTabViewShell* pViewShell = xDocSh->GetBestViewShell(false);
+    CPPUNIT_ASSERT(pViewShell);
+
+    auto& rDocFunc = xDocSh->GetDocFunc();
+
+    auto pSparklineGroup = std::make_shared<sc::SparklineGroup>();
+    {
+        sc::SparklineAttributes& rAttibutes = pSparklineGroup->getAttributes();
+        rAttibutes.setType(sc::SparklineType::Column);
+        rAttibutes.setColorSeries(COL_YELLOW);
+        rAttibutes.setColorAxis(COL_GREEN);
+    }
+
+    rDocument.CreateSparkline(ScAddress(0, 6, 0), pSparklineGroup);
+
+    sc::SparklineAttributes aNewAttributes;
+    aNewAttributes.setType(sc::SparklineType::Stacked);
+    aNewAttributes.setColorSeries(COL_BLACK);
+    aNewAttributes.setColorAxis(COL_BLUE);
+
+    sc::SparklineAttributes 
aInitialAttibutes(pSparklineGroup->getAttributes());
+
+    CPPUNIT_ASSERT(aNewAttributes != aInitialAttibutes);
+
+    CPPUNIT_ASSERT_EQUAL(true, aInitialAttibutes == 
pSparklineGroup->getAttributes());
+    CPPUNIT_ASSERT_EQUAL(false, aNewAttributes == 
pSparklineGroup->getAttributes());
+
+    CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->getAttributes().getType());
+    CPPUNIT_ASSERT_EQUAL(COL_YELLOW, 
pSparklineGroup->getAttributes().getColorSeries());
+    CPPUNIT_ASSERT_EQUAL(COL_GREEN, 
pSparklineGroup->getAttributes().getColorAxis());
+
+    rDocFunc.ChangeSparklineGroupAttributes(pSparklineGroup, aNewAttributes);
+
+    CPPUNIT_ASSERT_EQUAL(false, aInitialAttibutes == 
pSparklineGroup->getAttributes());
+    CPPUNIT_ASSERT_EQUAL(true, aNewAttributes == 
pSparklineGroup->getAttributes());
+
+    CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Stacked, 
pSparklineGroup->getAttributes().getType());
+    CPPUNIT_ASSERT_EQUAL(COL_BLACK, 
pSparklineGroup->getAttributes().getColorSeries());
+    CPPUNIT_ASSERT_EQUAL(COL_BLUE, 
pSparklineGroup->getAttributes().getColorAxis());
+
+    rDocument.GetUndoManager()->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(true, aInitialAttibutes == 
pSparklineGroup->getAttributes());
+    CPPUNIT_ASSERT_EQUAL(false, aNewAttributes == 
pSparklineGroup->getAttributes());
+
+    CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->getAttributes().getType());
+    CPPUNIT_ASSERT_EQUAL(COL_YELLOW, 
pSparklineGroup->getAttributes().getColorSeries());
+    CPPUNIT_ASSERT_EQUAL(COL_GREEN, 
pSparklineGroup->getAttributes().getColorAxis());
+
+    rDocument.GetUndoManager()->Redo();
+
+    CPPUNIT_ASSERT_EQUAL(false, aInitialAttibutes == 
pSparklineGroup->getAttributes());
+    CPPUNIT_ASSERT_EQUAL(true, aNewAttributes == 
pSparklineGroup->getAttributes());
+
+    CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Stacked, 
pSparklineGroup->getAttributes().getType());
+    CPPUNIT_ASSERT_EQUAL(COL_BLACK, 
pSparklineGroup->getAttributes().getColorSeries());
+    CPPUNIT_ASSERT_EQUAL(COL_BLUE, 
pSparklineGroup->getAttributes().getColorAxis());
+
+    xDocSh->DoClose();
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SparklineTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dialogs/SparklineDialog.cxx 
b/sc/source/ui/dialogs/SparklineDialog.cxx
index 59068077b969..4a7fa320a38e 100644
--- a/sc/source/ui/dialogs/SparklineDialog.cxx
+++ b/sc/source/ui/dialogs/SparklineDialog.cxx
@@ -163,7 +163,8 @@ void SparklineDialog::setupValues()
     {
         if (auto pSparkline = mrDocument.GetSparkline(aSelectionRange.aStart))
         {
-            mpLocalSparklineGroup = pSparkline->getSparklineGroup();
+            mpSparklineGroup = pSparkline->getSparklineGroup();
+            maAttributes = mpSparklineGroup->getAttributes();
             mxFrameData->set_visible(false);
             mbEditMode = true;
         }
@@ -173,16 +174,9 @@ void SparklineDialog::setupValues()
         maInputRange = aSelectionRange;
     }
 
-    if (!mpLocalSparklineGroup)
-    {
-        mpLocalSparklineGroup = std::make_shared<sc::SparklineGroup>();
-    }
-
     setInputSelection();
 
-    auto const& rAttribute = mpLocalSparklineGroup->getAttributes();
-
-    switch (rAttribute.getType())
+    switch (maAttributes.getType())
     {
         case sc::SparklineType::Line:
             mxRadioLine->set_active(true);
@@ -195,7 +189,7 @@ void SparklineDialog::setupValues()
             break;
     }
 
-    switch (rAttribute.getDisplayEmptyCellsAs())
+    switch (maAttributes.getDisplayEmptyCellsAs())
     {
         case sc::DisplayEmptyCellsAs::Gap:
             mxRadioDisplayEmptyGap->set_active(true);
@@ -208,28 +202,28 @@ void SparklineDialog::setupValues()
             break;
     }
 
-    mxColorSeries->SelectEntry(rAttribute.getColorSeries());
-    mxColorNegative->SelectEntry(rAttribute.getColorNegative());
-    mxColorMarker->SelectEntry(rAttribute.getColorMarkers());
-    mxColorHigh->SelectEntry(rAttribute.getColorHigh());
-    mxColorLow->SelectEntry(rAttribute.getColorLow());
-    mxColorFirst->SelectEntry(rAttribute.getColorFirst());
-    mxColorLast->SelectEntry(rAttribute.getColorLast());
+    mxColorSeries->SelectEntry(maAttributes.getColorSeries());
+    mxColorNegative->SelectEntry(maAttributes.getColorNegative());
+    mxColorMarker->SelectEntry(maAttributes.getColorMarkers());
+    mxColorHigh->SelectEntry(maAttributes.getColorHigh());
+    mxColorLow->SelectEntry(maAttributes.getColorLow());
+    mxColorFirst->SelectEntry(maAttributes.getColorFirst());
+    mxColorLast->SelectEntry(maAttributes.getColorLast());
 
-    mxCheckButtonNegative->set_active(rAttribute.isNegative());
-    mxCheckButtonMarker->set_active(rAttribute.isMarkers());
-    mxCheckButtonHigh->set_active(rAttribute.isHigh());
-    mxCheckButtonLow->set_active(rAttribute.isLow());
-    mxCheckButtonFirst->set_active(rAttribute.isFirst());
-    mxCheckButtonLast->set_active(rAttribute.isLast());
+    mxCheckButtonNegative->set_active(maAttributes.isNegative());
+    mxCheckButtonMarker->set_active(maAttributes.isMarkers());
+    mxCheckButtonHigh->set_active(maAttributes.isHigh());
+    mxCheckButtonLow->set_active(maAttributes.isLow());
+    mxCheckButtonFirst->set_active(maAttributes.isFirst());
+    mxCheckButtonLast->set_active(maAttributes.isLast());
 
-    mxSpinLineWidth->set_value(sal_Int64(rAttribute.getLineWeight() * 100.0));
+    mxSpinLineWidth->set_value(sal_Int64(maAttributes.getLineWeight() * 
100.0));
 
-    mxCheckDisplayXAxis->set_active(rAttribute.shouldDisplayXAxis());
-    mxCheckDisplayHidden->set_active(rAttribute.shouldDisplayHidden());
-    mxCheckRightToLeft->set_active(rAttribute.isRightToLeft());
+    mxCheckDisplayXAxis->set_active(maAttributes.shouldDisplayXAxis());
+    mxCheckDisplayHidden->set_active(maAttributes.shouldDisplayHidden());
+    mxCheckRightToLeft->set_active(maAttributes.isRightToLeft());
 
-    switch (rAttribute.getMinAxisType())
+    switch (maAttributes.getMinAxisType())
     {
         case sc::AxisType::Individual:
             mxComboMinAxisType->set_active(0);
@@ -241,13 +235,13 @@ void SparklineDialog::setupValues()
             break;
         case sc::AxisType::Custom:
             mxComboMinAxisType->set_active(2);
-            if (rAttribute.getManualMin())
-                
mxSpinCustomMin->GetFormatter().SetValue(*rAttribute.getManualMin());
+            if (maAttributes.getManualMin())
+                
mxSpinCustomMin->GetFormatter().SetValue(*maAttributes.getManualMin());
             break;
     }
     ComboValueChanged(*mxComboMinAxisType);
 
-    switch (rAttribute.getMaxAxisType())
+    switch (maAttributes.getMaxAxisType())
     {
         case sc::AxisType::Individual:
             mxComboMaxAxisType->set_active(0);
@@ -259,8 +253,8 @@ void SparklineDialog::setupValues()
             break;
         case sc::AxisType::Custom:
             mxComboMaxAxisType->set_active(2);
-            if (rAttribute.getManualMin())
-                
mxSpinCustomMax->GetFormatter().SetValue(*rAttribute.getManualMax());
+            if (maAttributes.getManualMin())
+                
mxSpinCustomMax->GetFormatter().SetValue(*maAttributes.getManualMax());
             break;
     }
     ComboValueChanged(*mxComboMaxAxisType);
@@ -405,72 +399,63 @@ IMPL_LINK(SparklineDialog, ButtonClicked, weld::Button&, 
rButton, void)
 
 IMPL_LINK(SparklineDialog, ToggleHandler, weld::Toggleable&, rToggle, void)
 {
-    auto& rAttribute = mpLocalSparklineGroup->getAttributes();
-
     if (mxCheckButtonNegative.get() == &rToggle)
-        rAttribute.setNegative(mxCheckButtonNegative->get_active());
+        maAttributes.setNegative(mxCheckButtonNegative->get_active());
     if (mxCheckButtonMarker.get() == &rToggle)
-        rAttribute.setMarkers(mxCheckButtonMarker->get_active());
+        maAttributes.setMarkers(mxCheckButtonMarker->get_active());
     if (mxCheckButtonHigh.get() == &rToggle)
-        rAttribute.setHigh(mxCheckButtonHigh->get_active());
+        maAttributes.setHigh(mxCheckButtonHigh->get_active());
     if (mxCheckButtonLow.get() == &rToggle)
-        rAttribute.setLow(mxCheckButtonLow->get_active());
+        maAttributes.setLow(mxCheckButtonLow->get_active());
     if (mxCheckButtonFirst.get() == &rToggle)
-        rAttribute.setFirst(mxCheckButtonFirst->get_active());
+        maAttributes.setFirst(mxCheckButtonFirst->get_active());
     if (mxCheckButtonLast.get() == &rToggle)
-        rAttribute.setLast(mxCheckButtonLast->get_active());
+        maAttributes.setLast(mxCheckButtonLast->get_active());
     if (mxCheckDisplayXAxis.get() == &rToggle)
-        rAttribute.setDisplayXAxis(mxCheckDisplayXAxis->get_active());
+        maAttributes.setDisplayXAxis(mxCheckDisplayXAxis->get_active());
     if (mxCheckDisplayHidden.get() == &rToggle)
-        rAttribute.setDisplayHidden(mxCheckDisplayHidden->get_active());
+        maAttributes.setDisplayHidden(mxCheckDisplayHidden->get_active());
     if (mxCheckRightToLeft.get() == &rToggle)
-        rAttribute.setRightToLeft(mxCheckRightToLeft->get_active());
+        maAttributes.setRightToLeft(mxCheckRightToLeft->get_active());
 }
 
 IMPL_LINK_NOARG(SparklineDialog, SelectSparklineType, weld::Toggleable&, void)
 {
-    auto& rAttribute = mpLocalSparklineGroup->getAttributes();
-
     if (mxRadioLine->get_active())
-        rAttribute.setType(sc::SparklineType::Line);
+        maAttributes.setType(sc::SparklineType::Line);
     else if (mxRadioColumn->get_active())
-        rAttribute.setType(sc::SparklineType::Column);
+        maAttributes.setType(sc::SparklineType::Column);
     else if (mxRadioStacked->get_active())
-        rAttribute.setType(sc::SparklineType::Stacked);
+        maAttributes.setType(sc::SparklineType::Stacked);
 
     if (mxRadioDisplayEmptyGap->get_active())
-        rAttribute.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Gap);
+        maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Gap);
     else if (mxRadioDisplayEmptyZero->get_active())
-        rAttribute.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Zero);
+        maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Zero);
     else if (mxRadioDisplayEmptySpan->get_active())
-        rAttribute.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Span);
+        maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Span);
 }
 
 IMPL_LINK_NOARG(SparklineDialog, SpinLineWidthChanged, weld::SpinButton&, void)
 {
-    auto& rAttribute = mpLocalSparklineGroup->getAttributes();
-
     double value = mxSpinLineWidth->get_value() / 100.0;
-    rAttribute.setLineWeight(value);
+    maAttributes.setLineWeight(value);
 }
 
 IMPL_LINK(SparklineDialog, SpinCustomChanged, weld::FormattedSpinButton&, 
rFormatted, void)
 {
-    auto& rAttribute = mpLocalSparklineGroup->getAttributes();
-
     if (mxSpinCustomMin.get() == &rFormatted)
     {
-        rAttribute.setManualMin(rFormatted.GetFormatter().GetValue());
+        maAttributes.setManualMin(rFormatted.GetFormatter().GetValue());
     }
     else if (mxSpinCustomMax.get() == &rFormatted)
     {
-        rAttribute.setManualMax(rFormatted.GetFormatter().GetValue());
+        maAttributes.setManualMax(rFormatted.GetFormatter().GetValue());
     }
 }
 
 IMPL_LINK(SparklineDialog, ComboValueChanged, weld::ComboBox&, rComboBox, void)
 {
-    auto& rAttribute = mpLocalSparklineGroup->getAttributes();
     int nActive = rComboBox.get_active();
 
     if (mxComboMinAxisType.get() == &rComboBox)
@@ -478,15 +463,15 @@ IMPL_LINK(SparklineDialog, ComboValueChanged, 
weld::ComboBox&, rComboBox, void)
         switch (nActive)
         {
             case 0:
-                rAttribute.setMinAxisType(sc::AxisType::Individual);
+                maAttributes.setMinAxisType(sc::AxisType::Individual);
                 mxSpinCustomMin->set_sensitive(false);
                 break;
             case 1:
-                rAttribute.setMinAxisType(sc::AxisType::Group);
+                maAttributes.setMinAxisType(sc::AxisType::Group);
                 mxSpinCustomMin->set_sensitive(false);
                 break;
             case 2:
-                rAttribute.setMinAxisType(sc::AxisType::Custom);
+                maAttributes.setMinAxisType(sc::AxisType::Custom);
                 mxSpinCustomMin->set_sensitive(true);
                 break;
             default:
@@ -498,15 +483,15 @@ IMPL_LINK(SparklineDialog, ComboValueChanged, 
weld::ComboBox&, rComboBox, void)
         switch (nActive)
         {
             case 0:
-                rAttribute.setMaxAxisType(sc::AxisType::Individual);
+                maAttributes.setMaxAxisType(sc::AxisType::Individual);
                 mxSpinCustomMax->set_sensitive(false);
                 break;
             case 1:
-                rAttribute.setMaxAxisType(sc::AxisType::Group);
+                maAttributes.setMaxAxisType(sc::AxisType::Group);
                 mxSpinCustomMax->set_sensitive(false);
                 break;
             case 2:
-                rAttribute.setMaxAxisType(sc::AxisType::Custom);
+                maAttributes.setMaxAxisType(sc::AxisType::Custom);
                 mxSpinCustomMax->set_sensitive(true);
                 break;
             default:
@@ -540,20 +525,27 @@ bool SparklineDialog::checkValidInputOutput()
 
 void SparklineDialog::perform()
 {
-    auto& rAttribute = mpLocalSparklineGroup->getAttributes();
-
-    rAttribute.setColorSeries(mxColorSeries->GetSelectEntryColor());
-    rAttribute.setColorNegative(mxColorNegative->GetSelectEntryColor());
-    rAttribute.setColorMarkers(mxColorMarker->GetSelectEntryColor());
-    rAttribute.setColorHigh(mxColorHigh->GetSelectEntryColor());
-    rAttribute.setColorLow(mxColorLow->GetSelectEntryColor());
-    rAttribute.setColorFirst(mxColorFirst->GetSelectEntryColor());
-    rAttribute.setColorLast(mxColorLast->GetSelectEntryColor());
+    maAttributes.setColorSeries(mxColorSeries->GetSelectEntryColor());
+    maAttributes.setColorNegative(mxColorNegative->GetSelectEntryColor());
+    maAttributes.setColorMarkers(mxColorMarker->GetSelectEntryColor());
+    maAttributes.setColorHigh(mxColorHigh->GetSelectEntryColor());
+    maAttributes.setColorLow(mxColorLow->GetSelectEntryColor());
+    maAttributes.setColorFirst(mxColorFirst->GetSelectEntryColor());
+    maAttributes.setColorLast(mxColorLast->GetSelectEntryColor());
 
     auto& rDocFunc = mrViewData.GetDocShell()->GetDocFunc();
 
-    rDocFunc.InsertSparklines(maInputRange, maOutputRange, 
mpLocalSparklineGroup);
-}
+    if (mpSparklineGroup)
+    {
+        rDocFunc.ChangeSparklineGroupAttributes(mpSparklineGroup, 
maAttributes);
+    }
+    else
+    {
+        auto pNewSparklineGroup = 
std::make_shared<sc::SparklineGroup>(maAttributes);
+        rDocFunc.InsertSparklines(maInputRange, maOutputRange, 
pNewSparklineGroup);
+    }
 }
 
+} // end sc
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docfunc.cxx 
b/sc/source/ui/docshell/docfunc.cxx
index e5972d54b7af..265d65f79e28 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -95,9 +95,11 @@
 #include <columnspanset.hxx>
 #include <validat.hxx>
 #include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
 #include <SparklineData.hxx>
 #include <undo/UndoInsertSparkline.hxx>
 #include <undo/UndoDeleteSparkline.hxx>
+#include <undo/UndoEditSparklineGroup.hxx>
 #include <config_features.h>
 
 #include <memory>
@@ -5857,4 +5859,14 @@ bool ScDocFunc::DeleteSparkline(ScAddress const& 
rAddress)
     return true;
 }
 
+bool 
ScDocFunc::ChangeSparklineGroupAttributes(std::shared_ptr<sc::SparklineGroup> 
const& pExistingSparklineGroup,
+                                               sc::SparklineAttributes const& 
rNewAttributes)
+{
+    auto pUndo = std::make_unique<sc::UndoEditSparklneGroup>(rDocShell, 
pExistingSparklineGroup, rNewAttributes);
+    // change sparkline group attributes by "redoing"
+    pUndo->Redo();
+    rDocShell.GetUndoManager()->AddUndoAction(std::move(pUndo));
+    return true;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/SparklineDialog.hxx 
b/sc/source/ui/inc/SparklineDialog.hxx
index 776480b05fce..1be81e80f7d6 100644
--- a/sc/source/ui/inc/SparklineDialog.hxx
+++ b/sc/source/ui/inc/SparklineDialog.hxx
@@ -13,6 +13,9 @@
 #include "anyrefdg.hxx"
 #include <viewdata.hxx>
 
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
 class ColorListBox;
 
 namespace sc
@@ -88,7 +91,8 @@ private:
     DECL_LINK(SpinLineWidthChanged, weld::SpinButton&, void);
     DECL_LINK(SpinCustomChanged, weld::FormattedSpinButton&, void);
 
-    std::shared_ptr<sc::SparklineGroup> mpLocalSparklineGroup;
+    std::shared_ptr<sc::SparklineGroup> mpSparklineGroup;
+    sc::SparklineAttributes maAttributes;
 
     bool mbEditMode;
 
diff --git a/sc/source/ui/inc/docfunc.hxx b/sc/source/ui/inc/docfunc.hxx
index 9ac438639585..72ac0fbcb9f0 100644
--- a/sc/source/ui/inc/docfunc.hxx
+++ b/sc/source/ui/inc/docfunc.hxx
@@ -54,6 +54,7 @@ enum class CreateNameFlags;
 namespace sc
 {
     struct ColRowSpan;
+    class SparklineAttributes;
     class SparklineGroup;
 }
 
@@ -241,6 +242,9 @@ public:
 
     SC_DLLPUBLIC bool DeleteSparkline(ScAddress const& rAddress);
 
+    SC_DLLPUBLIC bool 
ChangeSparklineGroupAttributes(std::shared_ptr<sc::SparklineGroup> const& 
pExistingSparklineGroup,
+                                                     sc::SparklineAttributes 
const& rNewAttributes);
+
 private:
     void ProtectDocument(const ScDocProtection& rProtect);
 };
diff --git a/sc/source/ui/inc/undo/UndoEditSparklineGroup.hxx 
b/sc/source/ui/inc/undo/UndoEditSparklineGroup.hxx
new file mode 100644
index 000000000000..373ebd35eb69
--- /dev/null
+++ b/sc/source/ui/inc/undo/UndoEditSparklineGroup.hxx
@@ -0,0 +1,44 @@
+/* -*- 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 "undobase.hxx"
+#include <memory>
+
+#include <SparklineAttributes.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+/** Undo action for editing a Sparkline */
+class UndoEditSparklneGroup : public ScSimpleUndo
+{
+private:
+    std::shared_ptr<sc::SparklineGroup> m_pSparklineGroup;
+    sc::SparklineAttributes m_aNewAttributes;
+    sc::SparklineAttributes m_aOriginalAttributes;
+
+public:
+    UndoEditSparklneGroup(ScDocShell& rDocShell,
+                          std::shared_ptr<sc::SparklineGroup> const& 
rSparklineGroup,
+                          sc::SparklineAttributes const& rAttributes);
+    virtual ~UndoEditSparklneGroup() override;
+
+    void Undo() override;
+    void Redo() override;
+    bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+    void Repeat(SfxRepeatTarget& rTarget) override;
+    OUString GetComment() const override;
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sparklines/SparklineGroup.cxx 
b/sc/source/ui/sparklines/SparklineGroup.cxx
index 9ef2c7044ab0..1ba235e75014 100644
--- a/sc/source/ui/sparklines/SparklineGroup.cxx
+++ b/sc/source/ui/sparklines/SparklineGroup.cxx
@@ -12,6 +12,12 @@
 
 namespace sc
 {
+SparklineGroup::SparklineGroup(SparklineAttributes const& rSparklineAttributes)
+    : m_aAttributes(rSparklineAttributes)
+    , m_aGUID(tools::Guid::Generate)
+{
+}
+
 SparklineGroup::SparklineGroup()
     : m_aGUID(tools::Guid::Generate)
 {
diff --git a/sc/source/ui/undo/UndoEditSparklineGroup.cxx 
b/sc/source/ui/undo/UndoEditSparklineGroup.cxx
new file mode 100644
index 000000000000..8136003d6b20
--- /dev/null
+++ b/sc/source/ui/undo/UndoEditSparklineGroup.cxx
@@ -0,0 +1,65 @@
+/* -*- 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 <undo/UndoEditSparklineGroup.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+UndoEditSparklneGroup::UndoEditSparklneGroup(
+    ScDocShell& rDocShell, std::shared_ptr<sc::SparklineGroup> const& 
pSparklineGroup,
+    sc::SparklineAttributes const& rAttributes)
+    : ScSimpleUndo(&rDocShell)
+    , m_pSparklineGroup(pSparklineGroup)
+    , m_aNewAttributes(rAttributes)
+    , m_aOriginalAttributes(pSparklineGroup->getAttributes())
+{
+}
+
+UndoEditSparklneGroup::~UndoEditSparklneGroup() = default;
+
+void UndoEditSparklneGroup::Undo()
+{
+    BeginUndo();
+
+    m_pSparklineGroup->setAttributes(m_aOriginalAttributes);
+    pDocShell->PostPaintGridAll();
+
+    EndUndo();
+}
+
+void UndoEditSparklneGroup::Redo()
+{
+    BeginRedo();
+
+    m_pSparklineGroup->setAttributes(m_aNewAttributes);
+    pDocShell->PostPaintGridAll();
+
+    EndRedo();
+}
+
+void UndoEditSparklneGroup::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoEditSparklneGroup::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { 
return false; }
+
+OUString UndoEditSparklneGroup::GetComment() const
+{
+    return ScResId(STR_UNDO_EDIT_SPARKLINE_GROUP);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to