From b36f7769dd07a6b6f55cdf4ce76e2f39ed186e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Vajngerl?= Date: Thu, 31 Aug 2023 22:29:46 +0200 Subject: [PATCH] sc: add ODF import/export of the Theme + tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One missing thing is the support in calc to save the Theme into the ODS document and read that back. The theme element is added as a child element to the office:styles - the same as it already is added in Writer. Also adds "Theme" property as a top level document property so it is possible to get and set the theme in xmloff. Also tests have been added to cover this usecases. Change-Id: Ic214ff5e945b77d50e6c881def9d49509560a0e0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156363 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl --- sc/inc/unonames.hxx | 1 + sc/qa/extras/scspreadsheetsettingsobj.cxx | 19 ++--- sc/qa/unit/ThemeImportExportTest.cxx | 85 ++++++++++++++++++++++- sc/source/filter/xml/xmlexprt.cxx | 21 ++++++ sc/source/filter/xml/xmlexprt.hxx | 2 + sc/source/ui/unoobj/docuno.cxx | 23 ++++++ xmloff/inc/XMLThemeContext.hxx | 6 +- xmloff/source/style/XMLThemeContext.cxx | 6 +- xmloff/source/style/xmlstyle.cxx | 24 ++++--- 9 files changed, 155 insertions(+), 32 deletions(-) diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx index 522582a36fb5..f88d89fdd2f0 100644 --- a/sc/inc/unonames.hxx +++ b/sc/inc/unonames.hxx @@ -47,6 +47,7 @@ inline constexpr OUStringLiteral SC_UNO_ROWLABELRNG = u"RowLabelRanges" inline constexpr OUStringLiteral SC_UNO_SHEETLINKS = u"SheetLinks"; inline constexpr OUStringLiteral SC_UNO_FORBIDDEN = u"ForbiddenCharacters"; inline constexpr OUStringLiteral SC_UNO_HASDRAWPAGES = u"HasDrawPages"; +inline constexpr OUStringLiteral SC_UNO_THEME = u"Theme"; // CharacterProperties inline constexpr OUStringLiteral SC_UNONAME_CCOLOR = u"CharColor"; diff --git a/sc/qa/extras/scspreadsheetsettingsobj.cxx b/sc/qa/extras/scspreadsheetsettingsobj.cxx index 117fc4d4a097..9173a80ba178 100644 --- a/sc/qa/extras/scspreadsheetsettingsobj.cxx +++ b/sc/qa/extras/scspreadsheetsettingsobj.cxx @@ -48,21 +48,10 @@ public: ScSpreadsheetSettingsObj::ScSpreadsheetSettingsObj() : UnoApiTest("/sc/qa/extras/testdocuments") - , XPropertySet({ - "AreaLinks", - "CharLocale", - "CharLocaleAsian", - "CharLocaleComplex", - "ColumnLabelRanges", - "DDELinks", - "DatabaseRanges", - "ExternalDocLinks", - "InteropGrabBag", - "NamedRanges", - "NullDate", - "RowLabelRanges", - "SheetLinks", - }) + , XPropertySet({ "AreaLinks", "CharLocale", "CharLocaleAsian", "CharLocaleComplex", + "ColumnLabelRanges", "DDELinks", "DatabaseRanges", "ExternalDocLinks", + "InteropGrabBag", "NamedRanges", "NullDate", "RowLabelRanges", "SheetLinks", + "Theme" }) { } diff --git a/sc/qa/unit/ThemeImportExportTest.cxx b/sc/qa/unit/ThemeImportExportTest.cxx index 9eac3762d6af..e8e1a31dbbff 100644 --- a/sc/qa/unit/ThemeImportExportTest.cxx +++ b/sc/qa/unit/ThemeImportExportTest.cxx @@ -15,6 +15,11 @@ #include #include +#include +#include +#include +#include + using namespace css; namespace @@ -28,7 +33,85 @@ public: } }; -CPPUNIT_TEST_FIXTURE(ThemeImportExportTest, testThemeExport) +CPPUNIT_TEST_FIXTURE(ThemeImportExportTest, testThemeExportAndImport) +{ + mxComponent = loadFromDesktop("private:factory/scalc"); + { + uno::Reference xPropertySet(mxComponent, uno::UNO_QUERY_THROW); + + auto pTheme = std::make_shared("MyTheme"); + auto pColorSet = std::make_shared("MyColorSet"); + pColorSet->add(model::ThemeColorType::Dark1, 0x111111); + pColorSet->add(model::ThemeColorType::Light1, 0x222222); + pColorSet->add(model::ThemeColorType::Dark2, 0x333333); + pColorSet->add(model::ThemeColorType::Light2, 0x444444); + pColorSet->add(model::ThemeColorType::Accent1, 0x555555); + pColorSet->add(model::ThemeColorType::Accent2, 0x666666); + pColorSet->add(model::ThemeColorType::Accent3, 0x777777); + pColorSet->add(model::ThemeColorType::Accent4, 0x888888); + pColorSet->add(model::ThemeColorType::Accent5, 0x999999); + pColorSet->add(model::ThemeColorType::Accent6, 0xaaaaaa); + pColorSet->add(model::ThemeColorType::Hyperlink, 0xbbbbbb); + pColorSet->add(model::ThemeColorType::FollowedHyperlink, 0xcccccc); + pTheme->setColorSet(pColorSet); + + xPropertySet->setPropertyValue("Theme", uno::Any(model::theme::createXTheme(pTheme))); + } + + // Check the "Theme" property + { + uno::Reference xPropertySet(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference xTheme(xPropertySet->getPropertyValue("Theme"), + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT(xTheme.is()); + auto* pUnoTheme = dynamic_cast(xTheme.get()); + CPPUNIT_ASSERT(pUnoTheme); + auto pTheme = pUnoTheme->getTheme(); + + CPPUNIT_ASSERT_EQUAL(OUString("MyTheme"), pTheme->GetName()); + CPPUNIT_ASSERT_EQUAL(OUString("MyColorSet"), pTheme->getColorSet()->getName()); + CPPUNIT_ASSERT_EQUAL(OUString("Office"), pTheme->getFontScheme().getName()); + CPPUNIT_ASSERT_EQUAL(OUString(""), pTheme->getFormatScheme().getName()); + } + + saveAndReload("calc8"); + + { + xmlDocUniquePtr pXmlDoc = parseExport("styles.xml"); + static constexpr OStringLiteral sThemePath = "//office:styles/loext:theme"; + assertXPath(pXmlDoc, sThemePath, 1); + assertXPath(pXmlDoc, sThemePath + "[@loext:name='MyTheme']"); + const OString sThemeColorsPath = sThemePath + "/loext:theme-colors"; + assertXPath(pXmlDoc, sThemeColorsPath, 1); + assertXPath(pXmlDoc, sThemeColorsPath + "[@loext:name='MyColorSet']"); + const OString sThemeColorPath = sThemeColorsPath + "/loext:color"; + assertXPath(pXmlDoc, sThemeColorPath, 12); + assertXPath(pXmlDoc, sThemeColorPath + "[3]", "name", "dark2"); + assertXPath(pXmlDoc, sThemeColorPath + "[3]", "color", "#333333"); + assertXPath(pXmlDoc, sThemeColorPath + "[9]", "name", "accent5"); + assertXPath(pXmlDoc, sThemeColorPath + "[9]", "color", "#999999"); + assertXPath(pXmlDoc, sThemeColorPath + "[12]", "name", "followed-hyperlink"); + assertXPath(pXmlDoc, sThemeColorPath + "[12]", "color", "#cccccc"); + } + + // Check the theme after import/export cycle + { + uno::Reference xPropertySet(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference xTheme(xPropertySet->getPropertyValue("Theme"), + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT(xTheme.is()); + auto* pUnoTheme = dynamic_cast(xTheme.get()); + CPPUNIT_ASSERT(pUnoTheme); + auto pTheme = pUnoTheme->getTheme(); + + CPPUNIT_ASSERT_EQUAL(OUString("MyTheme"), pTheme->GetName()); + CPPUNIT_ASSERT_EQUAL(OUString("MyColorSet"), pTheme->getColorSet()->getName()); + CPPUNIT_ASSERT_EQUAL(OUString("Office"), pTheme->getFontScheme().getName()); + CPPUNIT_ASSERT_EQUAL(OUString(""), pTheme->getFormatScheme().getName()); + } +} + +CPPUNIT_TEST_FIXTURE(ThemeImportExportTest, testThemeExportOOXML) { loadFromURL(u"xlsx/CalcThemeTest.xlsx"); diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx index e38ed5dcacda..65a94257cbc9 100644 --- a/sc/source/filter/xml/xmlexprt.cxx +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -121,7 +121,9 @@ #include #include #include +#include #include +#include #include #include @@ -1991,6 +1993,25 @@ void ScXMLExport::ExportStyles_( bool bUsed ) XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, xCellStylesExportPropertySetMapper, false, XmlStyleFamily::TABLE_CELL); SvXMLExport::ExportStyles_(bUsed); + + exportTheme(); +} + +void ScXMLExport::exportTheme() +{ + if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + return; + + SdrModel* pModel = GetDocument()->GetDrawLayer(); + + if (!pModel) + return; + + auto const& pTheme = pModel->getTheme(); + if (!pTheme) + return; + + ExportThemeElement(pTheme); } void ScXMLExport::AddStyleFromCells(const uno::Reference& xProperties, diff --git a/sc/source/filter/xml/xmlexprt.hxx b/sc/source/filter/xml/xmlexprt.hxx index 2fcdd0244f16..aaf490736a45 100644 --- a/sc/source/filter/xml/xmlexprt.hxx +++ b/sc/source/filter/xml/xmlexprt.hxx @@ -222,6 +222,8 @@ class ScXMLExport : public SvXMLExport const ScXMLEditAttributeMap& GetEditAttributeMap() const; + void exportTheme(); + protected: virtual SvXMLAutoStylePoolP* CreateAutoStylePool() override; virtual XMLPageExport* CreatePageExport() override; diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx index d98731951d17..86333bbd4b43 100644 --- a/sc/source/ui/unoobj/docuno.cxx +++ b/sc/source/ui/unoobj/docuno.cxx @@ -57,6 +57,7 @@ #include #include +#include #include #include #include @@ -82,6 +83,8 @@ #include #include #include +#include +#include #include #include @@ -165,6 +168,7 @@ static o3tl::span lcl_GetDocOptPropertyMap() { SC_UNO_LOOKUPLABELS, PROP_UNO_LOOKUPLABELS, cppu::UnoType::get(), 0, 0}, { SC_UNO_MATCHWHOLE, PROP_UNO_MATCHWHOLE, cppu::UnoType::get(), 0, 0}, { SC_UNO_NAMEDRANGES, 0, cppu::UnoType::get(), 0, 0}, + { SC_UNO_THEME, 0, cppu::UnoType::get(), 0, 0}, { SC_UNO_DATABASERNG, 0, cppu::UnoType::get(), 0, 0}, { SC_UNO_NULLDATE, PROP_UNO_NULLDATE, cppu::UnoType::get(), 0, 0}, { SC_UNO_ROWLABELRNG, 0, cppu::UnoType::get(), 0, 0}, @@ -2837,6 +2841,16 @@ void SAL_CALL ScModelObj::setPropertyValue( { setGrabBagItem(aValue); } + else if (aPropertyName == SC_UNO_THEME) + { + SdrModel& rSdrModel = getSdrModelFromUnoModel(); + uno::Reference xTheme; + if (aValue >>= xTheme) + { + auto& rUnoTheme = dynamic_cast(*xTheme); + rSdrModel.setTheme(rUnoTheme.getTheme()); + } + } if ( aNewOpt != rOldOpt ) { @@ -3023,6 +3037,15 @@ uno::Any SAL_CALL ScModelObj::getPropertyValue( const OUString& aPropertyName ) { getGrabBagItem(aRet); } + else if (aPropertyName == SC_UNO_THEME) + { + SdrModel& rSdrModel = getSdrModelFromUnoModel(); + css::uno::Reference xTheme; + auto pTheme = rSdrModel.getTheme(); + if (pTheme) + xTheme = model::theme::createXTheme(pTheme); + aRet <<= xTheme; + } } return aRet; diff --git a/xmloff/inc/XMLThemeContext.hxx b/xmloff/inc/XMLThemeContext.hxx index ce6f5ec9bbb6..f8ee08d5d4e8 100644 --- a/xmloff/inc/XMLThemeContext.hxx +++ b/xmloff/inc/XMLThemeContext.hxx @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include @@ -24,13 +24,13 @@ class Theme; /// Imports the theme class XMLThemeContext : public SvXMLImportContext { - css::uno::Reference m_xPage; + css::uno::Reference m_xObject; std::shared_ptr mpTheme; public: XMLThemeContext(SvXMLImport& rImport, css::uno::Reference const& xAttrList, - css::uno::Reference const& xPage); + css::uno::Reference const& xObject); ~XMLThemeContext(); css::uno::Reference SAL_CALL createFastChildContext( diff --git a/xmloff/source/style/XMLThemeContext.cxx b/xmloff/source/style/XMLThemeContext.cxx index 1579af468003..5c210c7a48dc 100644 --- a/xmloff/source/style/XMLThemeContext.cxx +++ b/xmloff/source/style/XMLThemeContext.cxx @@ -33,9 +33,9 @@ using namespace xmloff::token; XMLThemeContext::XMLThemeContext(SvXMLImport& rImport, const uno::Reference& xAttrList, - css::uno::Reference const& xPage) + css::uno::Reference const& xObject) : SvXMLImportContext(rImport) - , m_xPage(xPage) + , m_xObject(xObject) , mpTheme(new model::Theme) { for (const auto& rAttribute : sax_fastparser::castToFastAttributeList(xAttrList)) @@ -56,7 +56,7 @@ XMLThemeContext::~XMLThemeContext() { if (mpTheme && mpTheme->getColorSet()) { - uno::Reference xPropertySet(m_xPage, uno::UNO_QUERY); + uno::Reference xPropertySet(m_xObject, uno::UNO_QUERY); auto xTheme = model::theme::createXTheme(mpTheme); xPropertySet->setPropertyValue("Theme", uno::Any(xTheme)); } diff --git a/xmloff/source/style/xmlstyle.cxx b/xmloff/source/style/xmlstyle.cxx index d0dc368870a2..5158b43592cd 100644 --- a/xmloff/source/style/xmlstyle.cxx +++ b/xmloff/source/style/xmlstyle.cxx @@ -683,6 +683,20 @@ SvXMLStylesContext::~SvXMLStylesContext() css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLStylesContext::createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) { + if (nElement == XML_ELEMENT(LO_EXT, XML_THEME)) + { + uno::Reference xObject(GetImport().GetModel(), uno::UNO_QUERY); + uno::Reference const xDrawPageSupplier(GetImport().GetModel(), uno::UNO_QUERY); + if (xDrawPageSupplier.is()) + { + uno::Reference xPage = xDrawPageSupplier->getDrawPage(); + if (xPage.is()) + xObject = xPage; + } + + return new XMLThemeContext(GetImport(), xAttrList, xObject); + } + SvXMLStyleContext* pStyle = CreateStyleChildContext( nElement, xAttrList ); if (pStyle) { @@ -690,16 +704,6 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLStylesContext::cr mpImpl->AddStyle(pStyle); return pStyle; } - else if (nElement == XML_ELEMENT(LO_EXT, XML_THEME)) - { - uno::Reference const xDrawPageSupplier(GetImport().GetModel(), uno::UNO_QUERY); - if (xDrawPageSupplier.is()) - { - uno::Reference xPage = xDrawPageSupplier->getDrawPage(); - if (xPage.is()) - return new XMLThemeContext(GetImport(), xAttrList, xPage); - } - } return nullptr; }