ODP export: write the theme of a master page

Which requires describing the schema, which is really just a new
<loext:theme> element, the rest reuses the color-table markup, which
wasn't used in ODF so far (but was used in our .soc files).

Also make sure that we only do this in ODF extended mode (which is the
default).

Change-Id: I90eaad30f63946c441fe0c53caf6a47caf1714d5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126466
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Miklos Vajna
2021-12-07 08:32:30 +01:00
parent 68c15984ea
commit c95288aec4
7 changed files with 234 additions and 5 deletions

View File

@@ -3440,6 +3440,8 @@ namespace xmloff::token {
XML_LINKED_STYLE_NAME,
XML_THEME,
XML_TOKEN_END
};

View File

@@ -2743,4 +2743,100 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
</rng:optional>
</rng:define>
<rng:define name="loext-color-attlist">
<rng:interleave>
<rng:optional>
<rng:attribute name="loext:name">
<rng:ref name="string"/>
</rng:attribute>
</rng:optional>
<rng:optional>
<rng:attribute name="loext:color">
<rng:ref name="color"/>
</rng:attribute>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="loext-color">
<rng:element name="loext:color">
<rng:ref name="loext-color-attlist"/>
<rng:empty/>
</rng:element>
</rng:define>
<rng:define name="loext-color-table-attlist">
<rng:interleave>
<rng:optional>
<rng:attribute name="loext:name">
<rng:ref name="string"/>
</rng:attribute>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="loext-color-table">
<rng:element name="loext:color-table">
<rng:ref name="loext-color-table-attlist"/>
<rng:zeroOrMore>
<rng:ref name="loext-color"/>
</rng:zeroOrMore>
</rng:element>
</rng:define>
<rng:define name="loext-theme-attlist">
<rng:interleave>
<rng:optional>
<rng:attribute name="loext:name">
<rng:ref name="string"/>
</rng:attribute>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="loext-theme">
<rng:element name="loext:theme">
<rng:ref name="loext-theme-attlist"/>
<rng:optional>
<rng:ref name="loext-color-table"/>
</rng:optional>
</rng:element>
</rng:define>
<rng:define name="style-master-page" combine="choice">
<rng:element name="style:master-page">
<rng:ref name="style-master-page-attlist"/>
<rng:optional>
<rng:ref name="style-header"/>
<rng:optional>
<rng:ref name="style-header-left"/>
</rng:optional>
<rng:optional>
<rng:ref name="style-header-first"/>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:ref name="style-footer"/>
<rng:optional>
<rng:ref name="style-footer-left"/>
</rng:optional>
<rng:optional>
<rng:ref name="style-footer-first"/>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:ref name="draw-layer-set"/>
</rng:optional>
<rng:optional>
<rng:ref name="office-forms"/>
</rng:optional>
<rng:optional>
<!-- TODO no proposal -->
<rng:ref name="loext-theme"/>
</rng:optional>
<rng:zeroOrMore>
<rng:ref name="shape"/>
</rng:zeroOrMore>
<rng:optional>
<rng:ref name="animation-element"/>
</rng:optional>
<rng:optional>
<rng:ref name="presentation-notes"/>
</rng:optional>
</rng:element>
</rng:define>
</rng:grammar>

View File

@@ -16,6 +16,9 @@
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include <com/sun/star/drawing/XMasterPageTarget.hpp>
#include <com/sun/star/util/Color.hpp>
#include <unotools/mediadescriptor.hxx>
#include <unotools/tempfile.hxx>
@@ -38,6 +41,7 @@ public:
void tearDown() override;
void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
void save(const OUString& rFilterName, utl::TempFile& rTempFile);
};
void XmloffDrawTest::setUp()
@@ -60,6 +64,16 @@ void XmloffDrawTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
XmlTestTools::registerODFNamespaces(pXmlXpathCtx);
}
void XmloffDrawTest::save(const OUString& rFilterName, utl::TempFile& rTempFile)
{
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
utl::MediaDescriptor aMediaDescriptor;
aMediaDescriptor["FilterName"] <<= rFilterName;
rTempFile.EnableKillingFile();
xStorable->storeToURL(rTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
validate(rTempFile.GetFileName(), test::ODF);
}
CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTextBoxLoss)
{
// Load a document that has a shape with a textbox in it. Save it to ODF and reload.
@@ -93,12 +107,8 @@ CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf141301_Extrusion_Angle)
getComponent() = loadFromDesktop(aURL, "com.sun.star.comp.drawing.DrawingDocument");
// Prepare use of XPath
uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY);
utl::TempFile aTempFile;
aTempFile.EnableKillingFile();
utl::MediaDescriptor aMediaDescriptor;
aMediaDescriptor["FilterName"] <<= OUString("draw8");
xStorable->storeAsURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
save("draw8", aTempFile);
uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
= packages::zip::ZipFileAccess::createWithURL(mxComponentContext, aTempFile.GetURL());
uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName("content.xml"),
@@ -111,6 +121,38 @@ CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf141301_Extrusion_Angle)
assertXPath(pXmlDoc, "//draw:enhanced-geometry", "extrusion-skew", "50 -135");
}
CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testThemeExport)
{
// Create an Impress document which has a master page which has a theme associated with it.
getComponent() = loadFromDesktop("private:factory/simpress");
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
uno::Reference<drawing::XMasterPageTarget> xDrawPage(
xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xMasterPage(xDrawPage->getMasterPage(), uno::UNO_QUERY);
comphelper::SequenceAsHashMap aMap;
aMap["Name"] <<= OUString("mytheme");
aMap["ColorSchemeName"] <<= OUString("mycolorscheme");
uno::Sequence<util::Color> aColorScheme
= { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb };
aMap["ColorScheme"] <<= aColorScheme;
uno::Any aTheme = uno::makeAny(aMap.getAsConstPropertyValueList());
xMasterPage->setPropertyValue("Theme", aTheme);
// Export to ODP:
utl::TempFile aTempFile;
save("impress8", aTempFile);
// Check if the 12 colors are written in the XML:
std::unique_ptr<SvStream> pStream = parseExportStream(aTempFile, "styles.xml");
xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 12
// - Actual : 0
// - XPath '//style:master-page/loext:theme/loext:color-table/loext:color' number of nodes is incorrect
// i.e. the theme was lost on exporting to ODF.
assertXPath(pXmlDoc, "//style:master-page/loext:theme/loext:color-table/loext:color", 12);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -3443,6 +3443,8 @@ namespace xmloff::token {
TOKEN("linked-style-name", XML_LINKED_STYLE_NAME ),
TOKEN("theme", XML_THEME ),
#if OSL_DEBUG_LEVEL > 0
{ 0, nullptr, std::nullopt, XML_TOKEN_END }

View File

@@ -72,6 +72,9 @@
#include <com/sun/star/document/XDocumentProperties.hpp>
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/util/Color.hpp>
#include <comphelper/sequenceashashmap.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
@@ -2299,6 +2302,12 @@ void SdXMLExport::ExportMasterStyles_()
// write optional office:forms
exportFormsElement( xMasterPage );
// write optional loext:theme
if (IsImpress())
{
ExportThemeElement(xMasterPage);
}
// write graphic objects on this master page (if any)
if(xMasterPage.is() && xMasterPage->getCount())
GetShapeExport()->exportShapes( xMasterPage );
@@ -2354,6 +2363,82 @@ void SdXMLExport::exportFormsElement( const Reference< XDrawPage >& xDrawPage )
}
}
void SdXMLExport::ExportThemeElement(const uno::Reference<drawing::XDrawPage>& xDrawPage)
{
uno::Reference<beans::XPropertySet> xPropertySet(xDrawPage, uno::UNO_QUERY);
if (!xPropertySet.is())
return;
comphelper::SequenceAsHashMap aMap(xPropertySet->getPropertyValue("Theme"));
if (aMap.empty())
{
return;
}
if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
{
// Do not export in standard ODF 1.3 or older.
return;
}
auto it = aMap.find("Name");
if (it != aMap.end())
{
OUString aName;
it->second >>= aName;
AddAttribute(XML_NAMESPACE_LO_EXT, XML_NAME, aName);
}
SvXMLElementExport aTheme(*this, XML_NAMESPACE_LO_EXT, XML_THEME, true, true);
uno::Sequence<util::Color> aColors;
it = aMap.find("ColorScheme");
if (it != aMap.end())
{
it->second >>= aColors;
}
if (!aColors.hasElements())
{
return;
}
it = aMap.find("ColorSchemeName");
if (it != aMap.end())
{
OUString aName;
it->second >>= aName;
AddAttribute(XML_NAMESPACE_LO_EXT, XML_NAME, aName);
}
SvXMLElementExport aColorTable(*this, XML_NAMESPACE_LO_EXT, XML_COLOR_TABLE, true, true);
static const std::u16string_view aColorNames[] = {
u"dk1", // Background 1
u"lt1", // Text 1
u"dk2", // Background 2
u"lt2", // Text 2
u"accent1", // Accent 1
u"accent2", // Accent 2
u"accent3", // Accent 3
u"accent4", // Accent 4
u"accent5", // Accent 5
u"accent6", // Accent 6
u"hlink", // Hyperlink
u"folHlink", // Followed hyperlink
};
for (size_t nColor = 0; nColor < aColors.size(); ++nColor)
{
// Import goes via svx::Theme::FromAny(), which sanitizes user input.
assert(nColor < SAL_N_ELEMENTS(aColorNames));
AddAttribute(XML_NAMESPACE_LO_EXT, XML_NAME, OUString(aColorNames[nColor]));
OUStringBuffer sValue;
sax::Converter::convertColor(sValue, aColors[nColor]);
AddAttribute(XML_NAMESPACE_LO_EXT, XML_COLOR, sValue.makeStringAndClear());
SvXMLElementExport aColor(*this, XML_NAMESPACE_LO_EXT, XML_COLOR, true, true);
}
}
void SdXMLExport::GetViewSettings(uno::Sequence<beans::PropertyValue>& rProps)
{
Reference< beans::XPropertySet > xPropSet( GetModel(), UNO_QUERY );

View File

@@ -135,6 +135,7 @@ class SdXMLExport : public SvXMLExport
void ImplExportHeaderFooterDeclAttributes( const HeaderFooterPageSettingsImpl& aSettings );
void exportFormsElement( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage );
void ExportThemeElement(const css::uno::Reference<css::drawing::XDrawPage>& xDrawPage);
void exportPresentationSettings();
// #82003# helper function for recursive object count

View File

@@ -3187,4 +3187,5 @@ rspace
rtl
symmetric
linked-style-name
theme
TOKEN_END_DUMMY