diff options
author | Maxim Monastirsky <momonasmon@gmail.com> | 2022-11-13 11:05:28 +0200 |
---|---|---|
committer | Maxim Monastirsky <momonasmon@gmail.com> | 2022-11-21 14:38:59 +0100 |
commit | 5d683e8f6c9e677d7b6bc829a4ce9ee384f4fbd8 (patch) | |
tree | ab8bc64934e52293f3289461ae906f88de039fca | |
parent | 9e4b47190eb762f3aea80920846fe5135b7d76fc (diff) |
Export modified table styles
In addition to actually used styles, we want to
export user defined styles, as well as built in
styles that were modified.
Detecting the real modification state might be
challenging in some cases, e.g. when importing
the style from an existing document. So for
simplicity, we consider a style as "modified"
if at least one of its child cell styles is user
defined. The UI for modifying cell styles will be
implemented in such a way that built in styles
will never be modified themselves. Instead, a
user defined style will be created on the fly,
with the corresponding built in style set as its
parent, and only that new style will be modified.
It is still possible to modify built in cell
styles via the UNO API, but such styles won't be
exported unless actually used in the document.
Change-Id: Ic73eb460fd024f23016553e134397e07259f5c90
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143011
Tested-by: Jenkins
Reviewed-by: Maxim Monastirsky <momonasmon@gmail.com>
-rw-r--r-- | sd/qa/unit/data/odg/tablestyles.fodg | 22 | ||||
-rw-r--r-- | sd/qa/unit/export-tests.cxx | 35 | ||||
-rw-r--r-- | sd/source/core/drawdoc4.cxx | 5 | ||||
-rw-r--r-- | sd/source/core/stlsheet.cxx | 9 | ||||
-rw-r--r-- | svx/source/table/tabledesign.cxx | 87 | ||||
-rw-r--r-- | xmloff/source/table/XMLTableExport.cxx | 14 |
6 files changed, 167 insertions, 5 deletions
diff --git a/sd/qa/unit/data/odg/tablestyles.fodg b/sd/qa/unit/data/odg/tablestyles.fodg index 7b54e73955f9..3672ad8e4a70 100644 --- a/sd/qa/unit/data/odg/tablestyles.fodg +++ b/sd/qa/unit/data/odg/tablestyles.fodg @@ -2,6 +2,28 @@ <office:document xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.graphics"> <office:scripts/> <office:font-face-decls/> + <office:styles> + <style:style style:name="default" style:family="table-cell"/> + <style:style style:name="userdefined" style:family="table-cell"/> + <table:table-template table:name="default"> + <table:first-row table:style-name="userdefined"/> + <table:last-row table:style-name="userdefined"/> + <table:first-column table:style-name="userdefined"/> + <table:last-column table:style-name="userdefined"/> + <table:body table:style-name="userdefined"/> + <table:odd-rows table:style-name="userdefined"/> + <table:odd-columns table:style-name="userdefined"/> + </table:table-template> + <table:table-template table:name="userdefined"> + <table:first-row table:style-name="default"/> + <table:last-row table:style-name="default"/> + <table:first-column table:style-name="default"/> + <table:last-column table:style-name="default"/> + <table:body table:style-name="default"/> + <table:odd-rows table:style-name="default"/> + <table:odd-columns table:style-name="default"/> + </table:table-template> + </office:styles> <office:automatic-styles> <style:page-layout style:name="PM0"> <style:page-layout-properties fo:margin-top="1cm" fo:margin-bottom="1cm" fo:margin-left="1cm" fo:margin-right="1cm" fo:page-width="21.59cm" fo:page-height="27.94cm" style:print-orientation="portrait"/> diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx index 288e9acacf99..7d7f5c747cf9 100644 --- a/sd/qa/unit/export-tests.cxx +++ b/sd/qa/unit/export-tests.cxx @@ -102,6 +102,7 @@ public: void testColumnsODG(); void testTdf112126(); void testCellProperties(); + void testUserTableStyles(); CPPUNIT_TEST_SUITE(SdExportTest); @@ -151,6 +152,7 @@ public: CPPUNIT_TEST(testColumnsODG); CPPUNIT_TEST(testTdf112126); CPPUNIT_TEST(testCellProperties); + CPPUNIT_TEST(testUserTableStyles); CPPUNIT_TEST_SUITE_END(); virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override @@ -1767,6 +1769,11 @@ void SdExportTest::testTdf112126() void SdExportTest::testCellProperties() { + // Silence unrelated failure: + // Error: element "table:table-template" is missing "first-row-start-column" attribute + // Looks like an oversight in the schema, as the docs claim this attribute is deprecated. + skipValidation(); + loadFromURL(u"odg/tablestyles.fodg"); saveAndReload("draw8"); @@ -1792,6 +1799,34 @@ void SdExportTest::testCellProperties() CPPUNIT_ASSERT_EQUAL(drawing::TextVerticalAdjust::TextVerticalAdjust_CENTER, aTextAdjust); } +void SdExportTest::testUserTableStyles() +{ + // Silence unrelated failure: + // Error: element "table:table-template" is missing "first-row-start-column" attribute + // Looks like an oversight in the schema, as the docs claim this attribute is deprecated. + skipValidation(); + + loadFromURL(u"odg/tablestyles.fodg"); + saveAndReload("draw8"); + + uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent, + uno::UNO_QUERY); + uno::Reference<container::XNameAccess> xStyleFamily( + xStyleFamiliesSupplier->getStyleFamilies()->getByName("table"), uno::UNO_QUERY); + + uno::Reference<style::XStyle> xTableStyle(xStyleFamily->getByName("default"), uno::UNO_QUERY); + CPPUNIT_ASSERT(!xTableStyle->isUserDefined()); + + uno::Reference<container::XNameAccess> xNameAccess(xTableStyle, uno::UNO_QUERY); + uno::Reference<style::XStyle> xCellStyle(xNameAccess->getByName("first-row"), uno::UNO_QUERY); + CPPUNIT_ASSERT(xCellStyle); + CPPUNIT_ASSERT_EQUAL(OUString("userdefined"), xCellStyle->getName()); + + CPPUNIT_ASSERT(xStyleFamily->hasByName("userdefined")); + xTableStyle.set(xStyleFamily->getByName("userdefined"), uno::UNO_QUERY); + CPPUNIT_ASSERT(xTableStyle->isUserDefined()); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdExportTest); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sd/source/core/drawdoc4.cxx b/sd/source/core/drawdoc4.cxx index a4e1eb5a0c7c..0b8898e3095b 100644 --- a/sd/source/core/drawdoc4.cxx +++ b/sd/source/core/drawdoc4.cxx @@ -21,6 +21,7 @@ #include <com/sun/star/style/XStyle.hpp> #include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/form/XReset.hpp> #include <i18nlangtag/languagetag.hxx> #include <i18nlangtag/mslangid.hxx> #include <sfx2/dispatch.hxx> @@ -785,6 +786,10 @@ void SdDrawDocument::CreateDefaultCellStyles() Any aYellow3( implMakeSolidCellStyle( pSSPool, "yellow3" , aDefaultCellStyleName, Color(255,204,153))); implCreateTableTemplate( xTableFamily, "yellow" , aYellow1, aYellow3, aYellow2 ); + + Reference<form::XReset> xReset(xTableFamily, UNO_QUERY); + if (xReset) + xReset->reset(); } // Number of pages that reference a master page diff --git a/sd/source/core/stlsheet.cxx b/sd/source/core/stlsheet.cxx index 71cf76709ed1..14a0b13dd15c 100644 --- a/sd/source/core/stlsheet.cxx +++ b/sd/source/core/stlsheet.cxx @@ -309,6 +309,15 @@ bool SdStyleSheet::IsUsed() const bResult = std::any_of(aModifyListeners.begin(), aModifyListeners.end(), [](const Reference<XInterface>& rListener) { Reference< XStyle > xStyle( rListener, UNO_QUERY ); + try + { + Reference<XPropertySet> xPropertySet(xStyle, UNO_QUERY_THROW); + if (xPropertySet->getPropertyValue("IsPhysical").get<bool>()) + return true; + } + catch (const Exception&) + { + } return xStyle.is() && xStyle->isInUse(); }); } diff --git a/svx/source/table/tabledesign.cxx b/svx/source/table/tabledesign.cxx index ec316972232d..d4fe8cda4460 100644 --- a/svx/source/table/tabledesign.cxx +++ b/svx/source/table/tabledesign.cxx @@ -28,6 +28,7 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/util/XModifyBroadcaster.hpp> #include <com/sun/star/util/XModifyListener.hpp> +#include <com/sun/star/form/XReset.hpp> #include <vcl/svapp.hxx> @@ -47,6 +48,7 @@ #include <map> +using namespace css; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::style; using namespace ::com::sun::star::lang; @@ -58,7 +60,7 @@ namespace sdr::table { typedef std::map< OUString, sal_Int32 > CellStyleNameMap; -typedef ::comphelper::WeakComponentImplHelper< XStyle, XNameReplace, XServiceInfo, XIndexAccess, XModifyBroadcaster, XModifyListener > TableDesignStyleBase; +typedef ::comphelper::WeakComponentImplHelper< XStyle, XNameReplace, XServiceInfo, XIndexAccess, XModifyBroadcaster, XModifyListener, XPropertySet > TableDesignStyleBase; namespace { @@ -98,6 +100,15 @@ public: // XNameReplace virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) override; + // XPropertySet + virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) override; + virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference<XPropertyChangeListener>& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener>& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName,const Reference<XVetoableChangeListener>&aListener ) override; + // XModifyBroadcaster virtual void SAL_CALL addModifyListener( const Reference< XModifyListener >& aListener ) override; virtual void SAL_CALL removeModifyListener( const Reference< XModifyListener >& aListener ) override; @@ -107,12 +118,14 @@ public: virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; void notifyModifyListener(); + void resetUserDefined(); // this function is called upon disposing the component virtual void disposing(std::unique_lock<std::mutex>& aGuard) override; static const CellStyleNameMap& getCellStyleNameMap(); + bool mbUserDefined, mbModified; OUString msName; Reference< XStyle > maCellStyles[style_count]; comphelper::OInterfaceContainerHelper4<XModifyListener> maModifyListeners; @@ -124,7 +137,7 @@ typedef std::vector< Reference< XStyle > > TableDesignStyleVector; namespace { -class TableDesignFamily : public ::cppu::WeakImplHelper< XNameContainer, XNamed, XIndexAccess, XSingleServiceFactory, XServiceInfo, XComponent, XPropertySet > +class TableDesignFamily : public ::cppu::WeakImplHelper< XNameContainer, XNamed, XIndexAccess, XSingleServiceFactory, XServiceInfo, XComponent, XPropertySet, form::XReset > { public: // XServiceInfo @@ -174,12 +187,19 @@ public: virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener>& aListener ) override; virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName,const Reference<XVetoableChangeListener>&aListener ) override; + // XReset + virtual void SAL_CALL reset() override; + virtual void SAL_CALL addResetListener( const Reference<form::XResetListener>& aListener ) override; + virtual void SAL_CALL removeResetListener( const Reference<form::XResetListener>& aListener ) override; + TableDesignStyleVector maDesigns; }; } TableDesignStyle::TableDesignStyle() + : mbUserDefined(true) + , mbModified(false) { } @@ -221,7 +241,12 @@ Sequence< OUString > SAL_CALL TableDesignStyle::getSupportedServiceNames() // XStyle sal_Bool SAL_CALL TableDesignStyle::isUserDefined() { - return false; + return mbUserDefined; +} + +void TableDesignStyle::resetUserDefined() +{ + mbUserDefined = false; } sal_Bool SAL_CALL TableDesignStyle::isInUse() @@ -367,6 +392,9 @@ void SAL_CALL TableDesignStyle::replaceByName( const OUString& rName, const Any& if( xNewBroadcaster.is() ) xNewBroadcaster->addModifyListener( xListener ); + if (xNewStyle && xNewStyle->isUserDefined()) + mbModified = true; + maCellStyles[nIndex] = xNewStyle; } @@ -387,6 +415,41 @@ void TableDesignStyle::disposing(std::unique_lock<std::mutex>& aGuard) } } +// XPropertySet + +Reference<XPropertySetInfo> TableDesignStyle::getPropertySetInfo() +{ + return {}; +} + +void TableDesignStyle::setPropertyValue( const OUString&, const Any& ) +{ +} + +Any TableDesignStyle::getPropertyValue( const OUString& PropertyName ) +{ + if (PropertyName != "IsPhysical") + throw UnknownPropertyException("unknown property: " + PropertyName, static_cast<OWeakObject *>(this)); + + return Any(mbModified || mbUserDefined); +} + +void TableDesignStyle::addPropertyChangeListener( const OUString&, const Reference<XPropertyChangeListener>& ) +{ +} + +void TableDesignStyle::removePropertyChangeListener( const OUString&, const Reference<XPropertyChangeListener>& ) +{ +} + +void TableDesignStyle::addVetoableChangeListener( const OUString&, const Reference<XVetoableChangeListener>& ) +{ +} + +void TableDesignStyle::removeVetoableChangeListener( const OUString&,const Reference<XVetoableChangeListener>& ) +{ +} + // XModifyBroadcaster @@ -602,6 +665,9 @@ void SAL_CALL TableDesignFamily::replaceByName( const OUString& rName, const Any [&rName](const Reference<XStyle>& rpStyle) { return rpStyle->getName() == rName; }); if (iter != maDesigns.end()) { + if (!(*iter)->isUserDefined()) + static_cast<TableDesignStyle*>(xStyle.get())->resetUserDefined(); + Reference<XComponent> xComponent(*iter, UNO_QUERY); if (xComponent) xComponent->dispose(); @@ -707,6 +773,21 @@ void TableDesignFamily::removeVetoableChangeListener( const OUString& , const Re OSL_FAIL( "###unexpected!" ); } +// XReset + +void TableDesignFamily::reset() +{ + for (const auto& aDesign : maDesigns) + static_cast<TableDesignStyle*>(aDesign.get())->resetUserDefined(); +} + +void TableDesignFamily::addResetListener( const Reference<form::XResetListener>& ) +{ +} + +void TableDesignFamily::removeResetListener( const Reference<form::XResetListener>& ) +{ +} Reference< XNameAccess > CreateTableDesignFamily() { diff --git a/xmloff/source/table/XMLTableExport.cxx b/xmloff/source/table/XMLTableExport.cxx index 54bfb268d054..f415bb171af9 100644 --- a/xmloff/source/table/XMLTableExport.cxx +++ b/xmloff/source/table/XMLTableExport.cxx @@ -598,14 +598,24 @@ void XMLTableExport::exportTableTemplates() SvtSaveOptions::ODFSaneDefaultVersion eVersion = mrExport.getSaneDefaultVersion(); Reference< XStyle > xTableStyle( xTableFamily->getByIndex( nIndex ), UNO_QUERY_THROW ); - if( !xTableStyle->isInUse() ) + Reference<XPropertySet> xTableStylePropSet( xTableStyle, UNO_QUERY_THROW ); + bool bPhysical = false; + + try + { + xTableStylePropSet->getPropertyValue("IsPhysical") >>= bPhysical; + } + catch(const Exception&) + { + } + + if (!xTableStyle->isInUse() && !bPhysical) continue; const TableStyleElement* pElements; if (mbWriter) { mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, xTableStyle->getName()); - Reference<XPropertySet> xTableStylePropSet(xTableStyle, UNO_QUERY_THROW); pElements = getWriterSpecificTableStyleAttributes(); while(pElements->meElement != XML_TOKEN_END) { |