Rebased ref, commits from common ancestor:
commit daeb48ef12d81253752aa3e933647b0ee7786630
Author: Tomaž Vajngerl <[email protected]>
AuthorDate: Fri Mar 4 20:40:14 2022 +0900
Commit: Tomaž Vajngerl <[email protected]>
CommitDate: Sat Mar 5 20:25:40 2022 +0900
sc: Sparkline export for OOXML documents + roundtrip test
Change-Id: I4ab93d7ad33867ae817aa98d13ea9bc724b7d710
diff --git a/sc/CppunitTest_sc_sparkline_test.mk
b/sc/CppunitTest_sc_sparkline_test.mk
index 5dcd9a9921b5..30513b273791 100644
--- a/sc/CppunitTest_sc_sparkline_test.mk
+++ b/sc/CppunitTest_sc_sparkline_test.mk
@@ -32,6 +32,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_sparkline_test,
\
test \
tl \
unotest \
+ utl \
vcl \
))
diff --git a/sc/Library_scfilt.mk b/sc/Library_scfilt.mk
index 8e23db6662fa..84b6e5fd5edd 100644
--- a/sc/Library_scfilt.mk
+++ b/sc/Library_scfilt.mk
@@ -130,6 +130,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\
sc/source/filter/excel/xltools \
sc/source/filter/excel/xltracer \
sc/source/filter/excel/xlview \
+ sc/source/filter/excel/export/SparklineExt \
sc/source/filter/ftools/fapihelper \
sc/source/filter/ftools/fprogressbar \
sc/source/filter/ftools/ftools \
diff --git a/sc/qa/unit/SparklineImportExportTest.cxx
b/sc/qa/unit/SparklineImportExportTest.cxx
index cf970ae8995c..2b8de3e34c29 100644
--- a/sc/qa/unit/SparklineImportExportTest.cxx
+++ b/sc/qa/unit/SparklineImportExportTest.cxx
@@ -50,12 +50,11 @@ public:
CPPUNIT_TEST_SUITE_END();
};
-void SparklineImportExportTest::testSparklines()
+namespace
{
- ScDocShellRef xDocSh = loadDoc(u"Sparklines.", FORMAT_XLSX);
- CPPUNIT_ASSERT(xDocSh);
- ScDocument& rDocument = xDocSh->GetDocument();
+void checkSparklines(ScDocument& rDocument)
+{
// Sparkline at Sheet1:A2
{
sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 1,
0)); // A2
@@ -148,6 +147,20 @@ void SparklineImportExportTest::testSparklines()
sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 3,
0)); //A4
CPPUNIT_ASSERT(!pSparkline);
}
+}
+
+} // end anonymous namespace
+
+void SparklineImportExportTest::testSparklines()
+{
+ ScDocShellRef xDocSh = loadDoc(u"Sparklines.", FORMAT_XLSX);
+ CPPUNIT_ASSERT(xDocSh);
+
+ checkSparklines(xDocSh->GetDocument());
+
+ xDocSh = saveAndReload(*xDocSh, FORMAT_XLSX);
+
+ checkSparklines(xDocSh->GetDocument());
xDocSh->DoClose();
}
diff --git a/sc/source/filter/excel/excdoc.cxx
b/sc/source/filter/excel/excdoc.cxx
index 6b02457f70f6..529e76971cbc 100644
--- a/sc/source/filter/excel/excdoc.cxx
+++ b/sc/source/filter/excel/excdoc.cxx
@@ -39,6 +39,7 @@
#include <xecontent.hxx>
#include <xeescher.hxx>
#include <xepivot.hxx>
+#include <export/SparklineExt.hxx>
#include <XclExpChangeTrack.hxx>
#include <xepivotxml.hxx>
#include <xedbdata.hxx>
@@ -611,6 +612,8 @@ void ExcTable::FillAsTableXml()
// conditional formats
Add( new XclExpCondFormatBuffer( GetRoot(), xExtLst ) );
+ Add(new xcl::exp::SparklineBuffer(GetRoot(), xExtLst));
+
// data validation (DVAL and list of DV records), generated by the cell
table
aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_DVAL ) );
diff --git a/sc/source/filter/excel/export/SparklineExt.cxx
b/sc/source/filter/excel/export/SparklineExt.cxx
new file mode 100644
index 000000000000..f1e97b2c62ed
--- /dev/null
+++ b/sc/source/filter/excel/export/SparklineExt.cxx
@@ -0,0 +1,246 @@
+/* -*- 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 "export/SparklineExt.hxx"
+
+#include <oox/export/utils.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/token/tokens.hxx>
+
+using namespace oox;
+
+namespace xcl::exp
+{
+SparklineExt::SparklineExt(const XclExpRoot& rRoot,
+ std::vector<std::shared_ptr<sc::Sparkline>> const&
pSparklines)
+ : 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)
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream();
+ rWorksheet->startElement(XML_ext, FSNS(XML_xmlns, XML_x14),
+ rStream.getNamespaceURL(OOX_NS(xls14Lst)),
XML_uri, maURI);
+
+ rWorksheet->startElementNS(XML_x14, XML_sparklineGroups, FSNS(XML_xmlns,
XML_xm),
+ rStream.getNamespaceURL(OOX_NS(xm)));
+
+ for (auto const & [ pSparklineGroup, rSparklineVector ] :
m_aSparklineGroupMap)
+ {
+ addSparklineGroup(rStream, *pSparklineGroup, rSparklineVector);
+ }
+
+ rWorksheet->endElementNS(XML_x14, XML_sparklineGroups);
+ rWorksheet->endElement(XML_ext);
+}
+
+void SparklineExt::addSparklineGroupAttributes(
+ rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList,
+ sc::SparklineGroup& rSparklineGroup)
+{
+ if (rSparklineGroup.m_fLineWeight != 0.75)
+ pAttrList->add(XML_lineWeight,
OString::number(rSparklineGroup.m_fLineWeight));
+
+ if (rSparklineGroup.m_eType != sc::SparklineType::Line)
+ {
+ if (rSparklineGroup.m_eType == sc::SparklineType::Column)
+ pAttrList->add(XML_type, "column");
+ else if (rSparklineGroup.m_eType == sc::SparklineType::Stacked)
+ pAttrList->add(XML_type, "stacked");
+ }
+
+ if (rSparklineGroup.m_bDateAxis)
+ pAttrList->add(XML_dateAxis, "1");
+
+ if (rSparklineGroup.m_eDisplayEmptyCellsAs != sc::DisplayEmptyCellAs::Zero)
+ {
+ if (rSparklineGroup.m_eDisplayEmptyCellsAs ==
sc::DisplayEmptyCellAs::Gap)
+ pAttrList->add(XML_displayEmptyCellsAs, "gap");
+ else if (rSparklineGroup.m_eDisplayEmptyCellsAs ==
sc::DisplayEmptyCellAs::Span)
+ pAttrList->add(XML_displayEmptyCellsAs, "span");
+ }
+
+ if (rSparklineGroup.m_bMarkers)
+ pAttrList->add(XML_markers, "1");
+ if (rSparklineGroup.m_bHigh)
+ pAttrList->add(XML_high, "1");
+ if (rSparklineGroup.m_bLow)
+ pAttrList->add(XML_low, "1");
+ if (rSparklineGroup.m_bFirst)
+ pAttrList->add(XML_first, "1");
+ if (rSparklineGroup.m_bLast)
+ pAttrList->add(XML_last, "1");
+ if (rSparklineGroup.m_bNegative)
+ pAttrList->add(XML_negative, "1");
+ if (rSparklineGroup.m_bDisplayXAxis)
+ pAttrList->add(XML_displayXAxis, "1");
+ if (rSparklineGroup.m_bDisplayHidden)
+ pAttrList->add(XML_displayHidden, "1");
+
+ if (rSparklineGroup.m_eMinAxisType != sc::AxisType::Individual)
+ {
+ if (rSparklineGroup.m_eMinAxisType == sc::AxisType::Group)
+ pAttrList->add(XML_minAxisType, "group");
+ else if (rSparklineGroup.m_eMinAxisType == sc::AxisType::Custom)
+ pAttrList->add(XML_minAxisType, "custom");
+ }
+
+ if (rSparklineGroup.m_eMaxAxisType != sc::AxisType::Individual)
+ {
+ if (rSparklineGroup.m_eMaxAxisType == sc::AxisType::Group)
+ pAttrList->add(XML_maxAxisType, "group");
+ else if (rSparklineGroup.m_eMaxAxisType == sc::AxisType::Custom)
+ pAttrList->add(XML_maxAxisType, "custom");
+ }
+
+ if (rSparklineGroup.m_bRightToLeft)
+ pAttrList->add(XML_rightToLeft, "1");
+
+ if (rSparklineGroup.m_aManualMax && rSparklineGroup.m_eMaxAxisType ==
sc::AxisType::Custom)
+ pAttrList->add(XML_manualMax,
OString::number(*rSparklineGroup.m_aManualMax));
+
+ if (rSparklineGroup.m_aManualMin && rSparklineGroup.m_eMinAxisType ==
sc::AxisType::Custom)
+ pAttrList->add(XML_manualMin,
OString::number(*rSparklineGroup.m_aManualMin));
+}
+
+void SparklineExt::addSparklineGroupColors(XclExpXmlStream& rStream,
+ sc::SparklineGroup& rSparklineGroup)
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream();
+
+ rWorksheet->singleElementNS(XML_x14, XML_colorSeries, XML_rgb,
+
XclXmlUtils::ToOString(rSparklineGroup.m_aColorSeries));
+
+ if (rSparklineGroup.m_aColorSeries != COL_TRANSPARENT)
+ {
+ rWorksheet->singleElementNS(XML_x14, XML_colorNegative, XML_rgb,
+
XclXmlUtils::ToOString(rSparklineGroup.m_aColorNegative));
+ }
+
+ if (rSparklineGroup.m_aColorAxis != COL_TRANSPARENT)
+ {
+ rWorksheet->singleElementNS(XML_x14, XML_colorAxis, XML_rgb,
+
XclXmlUtils::ToOString(rSparklineGroup.m_aColorAxis));
+ }
+
+ if (rSparklineGroup.m_aColorMarkers != COL_TRANSPARENT)
+ {
+ rWorksheet->singleElementNS(XML_x14, XML_colorMarkers, XML_rgb,
+
XclXmlUtils::ToOString(rSparklineGroup.m_aColorMarkers));
+ }
+
+ if (rSparklineGroup.m_aColorFirst != COL_TRANSPARENT)
+ {
+ rWorksheet->singleElementNS(XML_x14, XML_colorFirst, XML_rgb,
+
XclXmlUtils::ToOString(rSparklineGroup.m_aColorFirst));
+ }
+
+ if (rSparklineGroup.m_aColorLast != COL_TRANSPARENT)
+ {
+ rWorksheet->singleElementNS(XML_x14, XML_colorLast, XML_rgb,
+
XclXmlUtils::ToOString(rSparklineGroup.m_aColorLast));
+ }
+
+ if (rSparklineGroup.m_aColorHigh != COL_TRANSPARENT)
+ {
+ rWorksheet->singleElementNS(XML_x14, XML_colorHigh, XML_rgb,
+
XclXmlUtils::ToOString(rSparklineGroup.m_aColorHigh));
+ }
+
+ if (rSparklineGroup.m_aColorLow != COL_TRANSPARENT)
+ {
+ rWorksheet->singleElementNS(XML_x14, XML_colorLow, XML_rgb,
+
XclXmlUtils::ToOString(rSparklineGroup.m_aColorLow));
+ }
+}
+
+void SparklineExt::addSparklineGroup(XclExpXmlStream& rStream,
sc::SparklineGroup& rSparklineGroup,
+
std::vector<std::shared_ptr<sc::Sparkline>> const& rSparklines)
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream();
+
+ // Sparkline Group Attributes
+ auto pAttrList = sax_fastparser::FastSerializerHelper::createAttrList();
+ addSparklineGroupAttributes(pAttrList, rSparklineGroup);
+
+ rWorksheet->startElementNS(XML_x14, XML_sparklineGroup, pAttrList);
+
+ addSparklineGroupColors(rStream, rSparklineGroup);
+
+ // Sparklines
+
+ rWorksheet->startElementNS(XML_x14, XML_sparklines);
+ for (auto const& rSparkline : rSparklines)
+ {
+ rWorksheet->startElementNS(XML_x14, XML_sparkline);
+
+ {
+ rWorksheet->startElementNS(XML_xm, XML_f);
+
+ OUString sRangeFormula;
+ ScRefFlags eFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D;
+ rSparkline->getInputRange().Format(sRangeFormula, eFlags, GetDoc(),
+
formula::FormulaGrammar::CONV_XL_OOX, ' ', true);
+
+ rWorksheet->writeEscaped(sRangeFormula);
+ rWorksheet->endElementNS(XML_xm, XML_f);
+ }
+
+ {
+ rWorksheet->startElementNS(XML_xm, XML_sqref);
+
+ ScAddress::Details detailsXL(formula::FormulaGrammar::CONV_XL_OOX);
+ ScAddress aAddress(rSparkline->getColumn(), rSparkline->getRow(),
GetCurrScTab());
+ OUString sLocation = aAddress.Format(ScRefFlags::VALID, &GetDoc(),
detailsXL);
+
+ rWorksheet->writeEscaped(sLocation);
+ rWorksheet->endElementNS(XML_xm, XML_sqref);
+ }
+
+ rWorksheet->endElementNS(XML_x14, XML_sparkline);
+ }
+ rWorksheet->endElementNS(XML_x14, XML_sparklines);
+ rWorksheet->endElementNS(XML_x14, XML_sparklineGroup);
+}
+
+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));
+ }
+ }
+}
+
+} // end namespace xcl::exp
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/export/SparklineExt.hxx
b/sc/source/filter/inc/export/SparklineExt.hxx
new file mode 100644
index 000000000000..116462c5f3c4
--- /dev/null
+++ b/sc/source/filter/inc/export/SparklineExt.hxx
@@ -0,0 +1,52 @@
+/* -*- 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 <vector>
+#include <map>
+#include <rangelst.hxx>
+#include <Sparkline.hxx>
+
+#include <sax/fastattribs.hxx>
+
+#include "xerecord.hxx"
+#include "xeroot.hxx"
+#include "xeextlst.hxx"
+
+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);
+
+ void SaveXml(XclExpXmlStream& rStream) override;
+ void addSparklineGroup(XclExpXmlStream& rStream, sc::SparklineGroup&
rSparklineGroup,
+ std::vector<std::shared_ptr<sc::Sparkline>> const&
rSparklines);
+ void
addSparklineGroupAttributes(rtl::Reference<sax_fastparser::FastAttributeList>&
pAttrList,
+ sc::SparklineGroup& rSparklineGroup);
+ void addSparklineGroupColors(XclExpXmlStream& rStream, sc::SparklineGroup&
rSparklineGroup);
+
+ XclExpExtType GetType() override { return XclExpExtSparklineType; }
+};
+
+class SparklineBuffer : public XclExpRecordBase, protected XclExpRoot
+{
+public:
+ explicit SparklineBuffer(const XclExpRoot& rRoot, const XclExtLstRef&
xExtLst);
+};
+
+} // end namespace xcl::exp
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/xeextlst.hxx
b/sc/source/filter/inc/xeextlst.hxx
index c5db5fcaff99..1770f9af191d 100644
--- a/sc/source/filter/inc/xeextlst.hxx
+++ b/sc/source/filter/inc/xeextlst.hxx
@@ -19,7 +19,8 @@
enum XclExpExtType
{
XclExpExtDataBarType,
- XclExpExtDataFooType
+ XclExpExtDataFooType,
+ XclExpExtSparklineType,
};
struct XclExpExtCondFormatData
commit f16f8f15f12fd5437337de89400f90cc22d8d945
Author: Tomaž Vajngerl <[email protected]>
AuthorDate: Fri Mar 4 17:26:34 2022 +0900
Commit: Tomaž Vajngerl <[email protected]>
CommitDate: Sat Mar 5 20:23:54 2022 +0900
sc: set colors in SparklineGroup construction to COL_TRANSPARENT
Change-Id: I67ceab2ffd723511fbf0616cca661992f0a8cf69
diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx
index 32e4b757378f..170ccee51539 100644
--- a/sc/inc/SparklineGroup.hxx
+++ b/sc/inc/SparklineGroup.hxx
@@ -74,7 +74,17 @@ public:
std::optional<double> m_aManualMin;
OUString m_sUID;
- SparklineGroup() {}
+ SparklineGroup()
+ : m_aColorSeries(COL_TRANSPARENT)
+ , m_aColorNegative(COL_TRANSPARENT)
+ , m_aColorAxis(COL_TRANSPARENT)
+ , m_aColorMarkers(COL_TRANSPARENT)
+ , m_aColorFirst(COL_TRANSPARENT)
+ , m_aColorLast(COL_TRANSPARENT)
+ , m_aColorHigh(COL_TRANSPARENT)
+ , m_aColorLow(COL_TRANSPARENT)
+ {
+ }
SparklineGroup(const SparklineGroup&) = delete;
SparklineGroup& operator=(const SparklineGroup&) = delete;
commit f161de9ed627be3da08ff0cffe250137156d2f37
Author: Tomaž Vajngerl <[email protected]>
AuthorDate: Wed Mar 2 17:44:08 2022 +0900
Commit: Tomaž Vajngerl <[email protected]>
CommitDate: Sat Mar 5 20:23:54 2022 +0900
sc: refactor sparkline struture to store a list of sparklines
We need to access a list of sparklines and sparkline groups for
a sheet. To preven going through all the columns of a sheet, we
need to store all the created sparklines in a list. For this it
is necessary to change the model structrue a bit. A cell now has
a container that stores a shared_ptr to the sparkline instead of
storing the sparkline directly. With this we can store a list
of weak_ptr to the sparklines in a list (vector), which can be
accessed at any time and is quite fast.
This is needed by the OOXML export.
Change-Id: Iaca0a41e20912775f072ea6e8cab9c44367d6f30
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 11449217edd9..62ab22a797c4 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -185,7 +185,6 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
sc/source/core/data/sheetevents \
sc/source/core/data/simpleformulacalc \
sc/source/core/data/sortparam \
- sc/source/core/data/Sparkline \
sc/source/core/data/stlpool \
sc/source/core/data/stlsheet \
sc/source/core/data/subtotalparam \
diff --git a/sc/inc/Sparkline.hxx b/sc/inc/Sparkline.hxx
index 8969fa3bfd3e..ad4688f33a5e 100644
--- a/sc/inc/Sparkline.hxx
+++ b/sc/inc/Sparkline.hxx
@@ -19,20 +19,67 @@ namespace sc
{
class SC_DLLPUBLIC Sparkline
{
-private:
+ SCCOL m_nColumn;
+ SCROW m_nRow;
+
ScRangeList m_aInputRange;
std::shared_ptr<SparklineGroup> m_pSparklineGroup;
public:
- Sparkline(std::shared_ptr<SparklineGroup>& pSparklineGroup);
+ Sparkline(SCCOL nColumn, SCROW nRow, std::shared_ptr<SparklineGroup>
const& pSparklineGroup)
+ : m_nColumn(nColumn)
+ , m_nRow(nRow)
+ , m_pSparklineGroup(pSparklineGroup)
+ {
+ }
Sparkline(const Sparkline&) = delete;
Sparkline& operator=(const Sparkline&) = delete;
void setInputRange(ScRangeList const& rInputRange) { m_aInputRange =
rInputRange; }
+
ScRangeList const& getInputRange() { return m_aInputRange; }
std::shared_ptr<SparklineGroup> const& getSparklineGroup() { return
m_pSparklineGroup; }
+
+ SCCOL getColumn() { return m_nColumn; }
+
+ SCROW getRow() { 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
diff --git a/sc/inc/SparklineCell.hxx b/sc/inc/SparklineCell.hxx
new file mode 100644
index 000000000000..0aca857170c9
--- /dev/null
+++ b/sc/inc/SparklineCell.hxx
@@ -0,0 +1,47 @@
+/* -*- 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 "Sparkline.hxx"
+#include <memory>
+
+namespace sc
+{
+class SC_DLLPUBLIC SparklineCell
+{
+private:
+ std::shared_ptr<Sparkline> m_pSparkline;
+
+public:
+ SparklineCell(std::shared_ptr<Sparkline> const& pSparkline)
+ : m_pSparkline(pSparkline)
+ {
+ }
+
+ SparklineCell(const SparklineCell&) = delete;
+ SparklineCell& operator=(const SparklineCell&) = delete;
+
+ void setInputRange(ScRangeList const& rInputRange) {
m_pSparkline->setInputRange(rInputRange); }
+
+ ScRangeList const& getInputRange() { return m_pSparkline->getInputRange();
}
+
+ std::shared_ptr<SparklineGroup> const& getSparklineGroup()
+ {
+ return m_pSparkline->getSparklineGroup();
+ }
+
+ std::shared_ptr<Sparkline> const& getSparkline() { return m_pSparkline; }
+};
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index f4b603c5c721..5472419e2297 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -617,8 +617,8 @@ public:
void BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint );
// Spaklines
- sc::Sparkline* GetSparkline(SCROW nRow);
- void SetSparkline(SCROW nRow, std::unique_ptr<sc::Sparkline> pSparkline);
+ sc::SparklineCell* GetSparklineCell(SCROW nRow);
+ void CreateSparklineCell(SCROW nRow, std::shared_ptr<sc::Sparkline> const&
pSparkline);
// cell notes
ScPostIt* GetCellNote( SCROW nRow );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 86bd4ebd02bf..1b86695ba94b 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -103,6 +103,7 @@ class ColumnIterator;
class ExternalDataMapper;
class Sparkline;
class SparklineGroup;
+class SparklineList;
}
@@ -1244,6 +1245,7 @@ public:
/** Spaklines */
SC_DLLPUBLIC sc::Sparkline* GetSparkline(ScAddress const & rPosition);
SC_DLLPUBLIC sc::Sparkline* CreateSparkline(ScAddress const & rPosition,
std::shared_ptr<sc::SparklineGroup> & pSparklineGroup);
+ SC_DLLPUBLIC sc::SparklineList* GetSparklineList(SCTAB nTab);
/** Notes **/
SC_DLLPUBLIC ScPostIt* GetNote(const ScAddress& rPos);
diff --git a/sc/inc/mtvelements.hxx b/sc/inc/mtvelements.hxx
index 6de0f3e7ec23..ee669c0a6e6b 100644
--- a/sc/inc/mtvelements.hxx
+++ b/sc/inc/mtvelements.hxx
@@ -15,7 +15,7 @@
#include <editeng/editobj.hxx>
#include "calcmacros.hxx"
#include "postit.hxx"
-#include "Sparkline.hxx"
+#include "SparklineCell.hxx"
#include "celltextattr.hxx"
#if DEBUG_COLUMN_STORAGE
@@ -59,7 +59,7 @@ const mdds::mtv::element_t element_type_uint16 =
mdds::mtv::element_type_uint16;
/// Custom element blocks.
-typedef mdds::mtv::noncopyable_managed_element_block<element_type_sparkline,
sc::Sparkline> sparkline_block;
+typedef mdds::mtv::noncopyable_managed_element_block<element_type_sparkline,
sc::SparklineCell> sparkline_block;
typedef mdds::mtv::noncopyable_managed_element_block<element_type_cellnote,
ScPostIt> cellnote_block;
typedef mdds::mtv::noncopyable_managed_element_block<element_type_broadcaster,
SvtBroadcaster> broadcaster_block;
typedef mdds::mtv::default_element_block<element_type_celltextattr,
CellTextAttr> celltextattr_block;
@@ -77,7 +77,7 @@ typedef mdds::mtv::uint16_element_block uint16_block;
/// For example sc types like sc::CellTextAttr, ScFormulaCell in global
namespace.
namespace sc {
MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(CellTextAttr, element_type_celltextattr,
CellTextAttr(), celltextattr_block)
-MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(Sparkline, sc::element_type_sparkline,
nullptr, sc::sparkline_block)
+MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(SparklineCell,
sc::element_type_sparkline, nullptr, sc::sparkline_block)
}
/// These need to be in global namespace just like their respective types are.
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 4a8654a67344..39cc4736d12d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -227,6 +227,7 @@ private:
mutable std::unique_ptr<ScRangeName> mpRangeName;
std::unique_ptr<ScConditionalFormatList> mpCondFormatList;
+ sc::SparklineList maSparklineList;
ScAddress maLOKFreezeCell;
@@ -472,6 +473,14 @@ public:
void GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const;
void GetLastDataPos(SCCOL& rCol, SCROW& rRow) const;
+ // Sparklines
+
+ sc::Sparkline* GetSparkline(SCCOL nCol, SCROW nRow);
+ sc::Sparkline* CreateSparkline(SCCOL nCol, SCROW nRow,
std::shared_ptr<sc::SparklineGroup> & pSparklineGroup);
+
+ sc::SparklineList& GetSparklineList();
+
+ // Notes / Comments
std::unique_ptr<ScPostIt> ReleaseNote( SCCOL nCol, SCROW nRow );
ScPostIt* GetNote( SCCOL nCol, SCROW nRow );
void SetNote( SCCOL nCol, SCROW nRow,
std::unique_ptr<ScPostIt> pNote );
diff --git a/sc/source/core/data/Sparkline.cxx
b/sc/source/core/data/Sparkline.cxx
deleted file mode 100644
index 301fda820ff2..000000000000
--- a/sc/source/core/data/Sparkline.cxx
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- 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 <memory>
-#include <Sparkline.hxx>
-
-namespace sc
-{
-Sparkline::Sparkline(std::shared_ptr<SparklineGroup>& pSparklineGroup)
- : m_pSparklineGroup(pSparklineGroup)
-{
-}
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index c2755f8f3cbb..cccd2af0fb34 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1979,14 +1979,14 @@ void ScColumn::PrepareBroadcastersForDestruction()
}
}
-sc::Sparkline* ScColumn::GetSparkline(SCROW nRow)
+sc::SparklineCell* ScColumn::GetSparklineCell(SCROW nRow)
{
- return maSparklines.get<sc::Sparkline*>(nRow);
+ return maSparklines.get<sc::SparklineCell*>(nRow);
}
-void ScColumn::SetSparkline(SCROW nRow, std::unique_ptr<sc::Sparkline>
pSparkline)
+void ScColumn::CreateSparklineCell(SCROW nRow, std::shared_ptr<sc::Sparkline>
const& pSparkline)
{
- maSparklines.set(nRow, pSparkline.release());
+ maSparklines.set(nRow, new sc::SparklineCell(pSparkline));
}
ScPostIt* ScColumn::GetCellNote(SCROW nRow)
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 92bf74e40c30..e0b1037c8d3e 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6505,33 +6505,41 @@ bool ScDocument::IsInVBAMode() const
return false;
}
+// Sparklines
sc::Sparkline* ScDocument::GetSparkline(ScAddress const& rPosition)
{
SCTAB nTab = rPosition.Tab();
- SCCOL nCol = rPosition.Col();
- if (ValidTab(nTab) && nTab < SCTAB(maTabs.size()) &&
- nCol < maTabs[nTab]->GetAllocatedColumnsCount())
+ if (ValidTab(nTab) && nTab < SCTAB(maTabs.size()))
{
- SCROW nRow = rPosition.Row();
- return maTabs[nTab]->aCol[nCol].GetSparkline(nRow);
+ return maTabs[nTab]->GetSparkline(rPosition.Col(), rPosition.Row());
}
return nullptr;
}
sc::Sparkline* ScDocument::CreateSparkline(ScAddress const & rPosition,
std::shared_ptr<sc::SparklineGroup> & pSparklineGroup)
{
- std::unique_ptr<sc::Sparkline> pSparkline(new
sc::Sparkline(pSparklineGroup));
- sc::Sparkline* pCreated = pSparkline.get();
-
SCTAB nTab = rPosition.Tab();
- SCCOL nCol = rPosition.Col();
- SCROW nRow = rPosition.Row();
- maTabs[nTab]->CreateColumnIfNotExists(nCol).SetSparkline(nRow,
std::move(pSparkline));
- return pCreated;
+ if (ValidTab(nTab) && nTab < SCTAB(maTabs.size()))
+ {
+ return maTabs[nTab]->CreateSparkline(rPosition.Col(), rPosition.Row(),
pSparklineGroup);
+ }
+
+ return nullptr;
+}
+
+sc::SparklineList* ScDocument::GetSparklineList(SCTAB nTab)
+{
+ if (ValidTab(nTab) && nTab < SCTAB(maTabs.size()))
+ {
+ return &maTabs[nTab]->GetSparklineList();
+ }
+ return nullptr;
}
+// Notes
+
ScPostIt* ScDocument::GetNote(const ScAddress& rPos)
{
return GetNote(rPos.Col(), rPos.Row(), rPos.Tab());
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index b65d1651e56d..aa218ee44cec 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1809,6 +1809,43 @@ ScFormulaCell* ScTable::GetFormulaCell( SCCOL nCol,
SCROW nRow )
return aCol[nCol].GetFormulaCell(nRow);
}
+// Sparklines
+
+sc::Sparkline* ScTable::GetSparkline(SCCOL nCol, SCROW nRow)
+{
+ if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
+ return nullptr;
+
+ sc::SparklineCell* pSparklineCell = aCol[nCol].GetSparklineCell(nRow);
+ if (!pSparklineCell)
+ return nullptr;
+
+ std::shared_ptr<sc::Sparkline> pSparkline(pSparklineCell->getSparkline());
+ assert(pSparkline);
+
+ return pSparkline.get();
+}
+
+sc::Sparkline* ScTable::CreateSparkline(SCCOL nCol, SCROW nRow,
std::shared_ptr<sc::SparklineGroup>& pSparklineGroup)
+{
+ if (!ValidCol(nCol))
+ return nullptr;
+
+ ScColumn& rColumn = CreateColumnIfNotExists(nCol);
+
+ std::shared_ptr<sc::Sparkline> pSparkline(new sc::Sparkline(nCol, nRow,
pSparklineGroup));
+ maSparklineList.addSparkline(pSparkline);
+ rColumn.CreateSparklineCell(nRow, pSparkline);
+ return pSparkline.get();
+}
+
+sc::SparklineList& ScTable::GetSparklineList()
+{
+ return maSparklineList;
+}
+
+// Notes
+
std::unique_ptr<ScPostIt> ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
{
if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
commit 6c91adf37b251825df974ffb4c3eecb7526c8a48
Author: Tomaž Vajngerl <[email protected]>
AuthorDate: Mon Feb 28 15:35:48 2022 +0900
Commit: Tomaž Vajngerl <[email protected]>
CommitDate: Sat Mar 5 20:23:54 2022 +0900
sc: support sparkline bar colors, add markers to sparkline lines
Change-Id: I705a7f57cc4d6544ecb35a5f93c18a27056b9944
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index ce7ac14d5a1d..6f0de245290d 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -2316,33 +2316,121 @@ void ScOutputData::DrawChangeTrack()
namespace
{
+struct SparklineMarker
+{
+ basegfx::B2DPolygon maPolygon;
+ Color maColor;
+};
+
+void createMarker(std::vector<SparklineMarker> & rMarkers, double x, double y,
Color const & rColor)
+{
+ auto & rMarker = rMarkers.emplace_back();
+ basegfx::B2DRectangle aRectangle(x - 2, y - 2, x + 2, y + 2);
+ rMarker.maPolygon = basegfx::utils::createPolygonFromRect(aRectangle);
+ rMarker.maColor = rColor;
+}
+
void drawLine(vcl::RenderContext& rRenderContext, tools::Rectangle const &
rRectangle,
- std::vector<double> const & rValues, double nMin, double nMax)
+ std::vector<double> const & rValues, double nMin, double nMax,
+ std::shared_ptr<sc::SparklineGroup> const & pSparklineGroup)
{
basegfx::B2DPolygon aPolygon;
double numebrOfSteps = rValues.size() - 1;
double xStep = 0;
double nDelta = nMax - nMin;
- for (double aValue : rValues)
+ std::vector<SparklineMarker> aMarkers;
+ sal_Int64 nValueIndex = 0;
+ sal_Int64 nValuesSize = rValues.size();
+
+ for (double nValue : rValues)
{
- double nP = (aValue - nMin) / nDelta;
+ double nP = (nValue - nMin) / nDelta;
double x = rRectangle.GetWidth() * (xStep / numebrOfSteps);
double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nP;
aPolygon.append({ x, y } );
+
+ if (pSparklineGroup->m_bFirst && nValueIndex == 0)
+ {
+ createMarker(aMarkers, x, y, pSparklineGroup->m_aColorFirst);
+ }
+ else if (pSparklineGroup->m_bLast && nValueIndex == (nValuesSize - 1))
+ {
+ createMarker(aMarkers, x, y, pSparklineGroup->m_aColorLast);
+ }
+ else if (pSparklineGroup->m_bHigh && nValue == nMax)
+ {
+ createMarker(aMarkers, x, y, pSparklineGroup->m_aColorHigh);
+ }
+ else if (pSparklineGroup->m_bLow && nValue == nMin)
+ {
+ createMarker(aMarkers, x, y, pSparklineGroup->m_aColorLow);
+ }
+ else if (pSparklineGroup->m_bNegative && nValue < 0.0)
+ {
+ createMarker(aMarkers, x, y, pSparklineGroup->m_aColorNegative);
+ }
+
xStep++;
+ nValueIndex++;
}
basegfx::B2DHomMatrix aMatrix;
aMatrix.translate(rRectangle.Left(), rRectangle.Top());
aPolygon.transform(aMatrix);
+ rRenderContext.SetLineColor(pSparklineGroup->m_aColorSeries);
rRenderContext.DrawPolyLine(aPolygon);
+
+ for (auto const & rMarker : aMarkers)
+ {
+ rRenderContext.SetLineColor(rMarker.maColor);
+ rRenderContext.SetFillColor(rMarker.maColor);
+ aPolygon = rMarker.maPolygon;
+ aPolygon.transform(aMatrix);
+ rRenderContext.DrawPolygon(aPolygon);
+ }
+}
+
+void setFillAndLineColor(vcl::RenderContext& rRenderContext,
std::shared_ptr<sc::SparklineGroup> const & pSparklineGroup,
+ double nValue, sal_Int64 nValueIndex, sal_Int64
nValuesSize, double nMin, double nMax)
+{
+ if (pSparklineGroup->m_bFirst && nValueIndex == 0)
+ {
+ rRenderContext.SetLineColor(pSparklineGroup->m_aColorFirst);
+ rRenderContext.SetFillColor(pSparklineGroup->m_aColorFirst);
+ }
+ else if (pSparklineGroup->m_bLast && nValueIndex == (nValuesSize - 1))
+ {
+ rRenderContext.SetLineColor(pSparklineGroup->m_aColorLast);
+ rRenderContext.SetFillColor(pSparklineGroup->m_aColorLast);
+ }
+ else if (pSparklineGroup->m_bHigh && nValue == nMax)
+ {
+ rRenderContext.SetLineColor(pSparklineGroup->m_aColorHigh);
+ rRenderContext.SetFillColor(pSparklineGroup->m_aColorHigh);
+ }
+ else if (pSparklineGroup->m_bLow && nValue == nMin)
+ {
+ rRenderContext.SetLineColor(pSparklineGroup->m_aColorLow);
+ rRenderContext.SetFillColor(pSparklineGroup->m_aColorLow);
+ }
+ else if (pSparklineGroup->m_bNegative && nValue < 0.0)
+ {
+ rRenderContext.SetLineColor(pSparklineGroup->m_aColorNegative);
+ rRenderContext.SetFillColor(pSparklineGroup->m_aColorNegative);
+ }
+ else
+ {
+ rRenderContext.SetLineColor(pSparklineGroup->m_aColorSeries);
+ rRenderContext.SetFillColor(pSparklineGroup->m_aColorSeries);
+ }
}
void drawColumn(vcl::RenderContext& rRenderContext, tools::Rectangle const &
rRectangle,
- std::vector<double> const & rValues, double nMin, double nMax)
+ std::vector<double> const & rValues, double nMin, double nMax,
+ std::shared_ptr<sc::SparklineGroup> const & pSparklineGroup)
{
basegfx::B2DPolygon aPolygon;
@@ -2359,11 +2447,15 @@ void drawColumn(vcl::RenderContext& rRenderContext,
tools::Rectangle const & rRe
else
nZeroPosition = rRectangle.GetHeight();
- for (double aValue : rValues)
+ sal_Int64 nValueIndex = 0;
+
+ for (double nValue : rValues)
{
- if (aValue != 0.0)
+ if (nValue != 0.0)
{
- double nP = (aValue - nMin) / nDelta;
+ setFillAndLineColor(rRenderContext, pSparklineGroup, nValue,
nValueIndex, sal_Int64(rValues.size()), nMax, nMin);
+
+ double nP = (nValue - nMin) / nDelta;
double x = rRectangle.GetWidth() * (xStep / numberOfSteps);
double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nP;
@@ -2376,6 +2468,7 @@ void drawColumn(vcl::RenderContext& rRenderContext,
tools::Rectangle const & rRe
rRenderContext.DrawPolygon(aPolygon);
}
xStep++;
+ nValueIndex++;
}
}
@@ -2391,9 +2484,6 @@ void drawSparkline(sc::Sparkline* pSparkline,
vcl::RenderContext& rRenderContext
rRenderContext.SetAntialiasing(AntialiasingFlags::Enable);
- rRenderContext.SetLineColor(pSparklineGroup->m_aColorSeries);
- rRenderContext.SetFillColor(pSparklineGroup->m_aColorSeries);
-
ScRange aRange = rRangeList[0];
std::vector<double> aValues;
@@ -2434,7 +2524,7 @@ void drawSparkline(sc::Sparkline* pSparkline,
vcl::RenderContext& rRenderContext
if (pSparklineGroup->m_eType == sc::SparklineType::Column)
{
- drawColumn(rRenderContext, rRectangle, aValues, nMin, nMax);
+ drawColumn(rRenderContext, rRectangle, aValues, nMin, nMax,
pSparklineGroup);
}
else if (pSparklineGroup->m_eType == sc::SparklineType::Stacked)
{
@@ -2444,11 +2534,11 @@ void drawSparkline(sc::Sparkline* pSparkline,
vcl::RenderContext& rRenderContext
if (rValue != 0.0)
rValue = rValue > 0.0 ? 1.0 : -1.0;
}
- drawColumn(rRenderContext, rRectangle, aValues, -1, 1);
+ drawColumn(rRenderContext, rRectangle, aValues, -1, 1,
pSparklineGroup);
}
else if (pSparklineGroup->m_eType == sc::SparklineType::Line)
{
- drawLine(rRenderContext, rRectangle, aValues, nMin, nMax);
+ drawLine(rRenderContext, rRectangle, aValues, nMin, nMax,
pSparklineGroup);
}
}
} // end anonymous namespace
commit de13b4a9bf102dc7655920b1b767b42181314ec5
Author: Tomaž Vajngerl <[email protected]>
AuthorDate: Thu Feb 24 18:04:37 2022 +0900
Commit: Tomaž Vajngerl <[email protected]>
CommitDate: Sat Mar 5 20:23:46 2022 +0900
sc: test Sparkline OOXML Import into Calc Sparkline doc. model
Change-Id: I513571de398be419074d54c5861374effae07709
diff --git a/sc/CppunitTest_sc_sparkline_test.mk
b/sc/CppunitTest_sc_sparkline_test.mk
new file mode 100644
index 000000000000..5dcd9a9921b5
--- /dev/null
+++ b/sc/CppunitTest_sc_sparkline_test.mk
@@ -0,0 +1,60 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# 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/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sc_sparkline_test, \
+ sc/qa/unit/SparklineImportExportTest \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sc_sparkline_test, \
+ basegfx \
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+ sax \
+ sc \
+ scqahelper \
+ sfx \
+ subsequenttest \
+ test \
+ tl \
+ unotest \
+ vcl \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sc_sparkline_test,\
+ -I$(SRCDIR)/sc/source/ui/inc \
+ -I$(SRCDIR)/sc/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sc_sparkline_test,\
+ offapi \
+ udkapi \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_use_ure,sc_sparkline_test))
+$(eval $(call gb_CppunitTest_use_vcl,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_use_rdb,sc_sparkline_test,services))
+
+$(eval $(call gb_CppunitTest_use_components,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_use_configuration,sc_sparkline_test))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk
index 5179c5fdb292..4dcefc694ea7 100644
--- a/sc/Module_sc.mk
+++ b/sc/Module_sc.mk
@@ -209,6 +209,7 @@ $(eval $(call gb_Module_add_subsequentcheck_targets,sc,\
CppunitTest_sc_sheetlinkobj \
CppunitTest_sc_sheetlinksobj \
CppunitTest_sc_sortdescriptorbaseobj \
+ CppunitTest_sc_sparkline_test \
CppunitTest_sc_spreadsheetsettings \
CppunitTest_sc_spreadsheetsettingsobj \
CppunitTest_sc_styleobj \
diff --git a/sc/qa/unit/SparklineImportExportTest.cxx
b/sc/qa/unit/SparklineImportExportTest.cxx
new file mode 100644
index 000000000000..cf970ae8995c
--- /dev/null
+++ b/sc/qa/unit/SparklineImportExportTest.cxx
@@ -0,0 +1,159 @@
+/* -*- 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 "helper/qahelper.hxx"
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <docsh.hxx>
+#include <Sparkline.hxx>
+
+using namespace css;
+
+class SparklineImportExportTest : public ScBootstrapFixture
+{
+private:
+ uno::Reference<uno::XInterface> m_xCalcComponent;
+
+public:
+ SparklineImportExportTest()
+ : ScBootstrapFixture("sc/qa/unit/data")
+ {
+ }
+
+ virtual void setUp() override
+ {
+ test::BootstrapFixture::setUp();
+
+ // This is a bit of a fudge, we do this to ensure that
ScGlobals::ensure,
+ // which is a private symbol to us, gets called
+ m_xCalcComponent = getMultiServiceFactory()->createInstance(
+ "com.sun.star.comp.Calc.SpreadsheetDocument");
+ CPPUNIT_ASSERT_MESSAGE("no calc component!", m_xCalcComponent.is());
+ }
+
+ virtual void tearDown() override
+ {
+ uno::Reference<lang::XComponent>(m_xCalcComponent,
uno::UNO_QUERY_THROW)->dispose();
+ test::BootstrapFixture::tearDown();
+ }
+
+ void testSparklines();
+
+ CPPUNIT_TEST_SUITE(SparklineImportExportTest);
+ CPPUNIT_TEST(testSparklines);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void SparklineImportExportTest::testSparklines()
+{
+ ScDocShellRef xDocSh = loadDoc(u"Sparklines.", FORMAT_XLSX);
+ CPPUNIT_ASSERT(xDocSh);
+
+ ScDocument& rDocument = xDocSh->GetDocument();
+ // Sparkline at Sheet1:A2
+ {
+ sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 1,
0)); // A2
+ CPPUNIT_ASSERT(pSparkline);
+ auto pSparklineGroup = pSparkline->getSparklineGroup();
+ CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line,
pSparklineGroup->m_eType);
+
+ CPPUNIT_ASSERT_EQUAL(Color(0x376092), pSparklineGroup->m_aColorSeries);
+ CPPUNIT_ASSERT_EQUAL(Color(0x00b050),
pSparklineGroup->m_aColorNegative);
+ CPPUNIT_ASSERT_EQUAL(Color(0x000000), pSparklineGroup->m_aColorAxis);
+ CPPUNIT_ASSERT_EQUAL(Color(0x000000),
pSparklineGroup->m_aColorMarkers);
+ CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), pSparklineGroup->m_aColorFirst);
+ CPPUNIT_ASSERT_EQUAL(Color(0xff0000), pSparklineGroup->m_aColorLast);
+ CPPUNIT_ASSERT_EQUAL(Color(0x92d050), pSparklineGroup->m_aColorHigh);
+ CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), pSparklineGroup->m_aColorLow);
+
+ CPPUNIT_ASSERT_EQUAL(1.0, pSparklineGroup->m_fLineWeight);
+ CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
+ CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap,
pSparklineGroup->m_eDisplayEmptyCellsAs);
+
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bMarkers);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bDisplayXAxis);
+ CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
+ CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
+
+ CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
+ CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
+ }
+ // Sparkline at Sheet1:A3
+ {
+ sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 2,
0)); // A3
+ CPPUNIT_ASSERT(pSparkline);
+ auto pSparklineGroup = pSparkline->getSparklineGroup();
+ CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column,
pSparklineGroup->m_eType);
+
+ CPPUNIT_ASSERT_EQUAL(Color(0x376092), pSparklineGroup->m_aColorSeries);
+ CPPUNIT_ASSERT_EQUAL(Color(0xff0000),
pSparklineGroup->m_aColorNegative);
+ CPPUNIT_ASSERT_EQUAL(Color(0x000000), pSparklineGroup->m_aColorAxis);
+ CPPUNIT_ASSERT_EQUAL(Color(0xd00000),
pSparklineGroup->m_aColorMarkers);
+ CPPUNIT_ASSERT_EQUAL(Color(0x92d050), pSparklineGroup->m_aColorFirst);
+ CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), pSparklineGroup->m_aColorLast);
+ CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), pSparklineGroup->m_aColorHigh);
+ CPPUNIT_ASSERT_EQUAL(Color(0xffc000), pSparklineGroup->m_aColorLow);
+
+ CPPUNIT_ASSERT_EQUAL(0.75, pSparklineGroup->m_fLineWeight);
+ CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
+ CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap,
pSparklineGroup->m_eDisplayEmptyCellsAs);
+
+ CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bMarkers);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
+ CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
+ CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayXAxis);
+ CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
+ CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
+
+ CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
+ CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
+ }
+ // Sparkline at Sheet2:B1
+ {
+ sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 0,
1)); //B1
+ CPPUNIT_ASSERT(pSparkline);
+ auto pSparklineGroup = pSparkline->getSparklineGroup();
+ CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column,
pSparklineGroup->m_eType);
+ }
+ // Sparkline at Sheet2:B2
+ {
+ sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1,
1)); //B2
+ CPPUNIT_ASSERT(pSparkline);
+ auto pSparklineGroup = pSparkline->getSparklineGroup();
+ CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line,
pSparklineGroup->m_eType);
+ }
+ // Sparkline at Sheet2:B2
+ {
+ sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1,
1)); //B2
+ CPPUNIT_ASSERT(pSparkline);
+ auto pSparklineGroup = pSparkline->getSparklineGroup();
+ CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line,
pSparklineGroup->m_eType);
+ }
+ // Sparkline doesn't exists at A4
+ {
+ sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 3,
0)); //A4
+ CPPUNIT_ASSERT(!pSparkline);
+ }
+
+ xDocSh->DoClose();
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SparklineImportExportTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/data/xlsx/Sparklines.xlsx
b/sc/qa/unit/data/xlsx/Sparklines.xlsx
new file mode 100644
index 000000000000..3725841603be
Binary files /dev/null and b/sc/qa/unit/data/xlsx/Sparklines.xlsx differ