summaryrefslogtreecommitdiffstats
path: root/xmloff/source/style/styleexp.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'xmloff/source/style/styleexp.cxx')
-rw-r--r--xmloff/source/style/styleexp.cxx592
1 files changed, 592 insertions, 0 deletions
diff --git a/xmloff/source/style/styleexp.cxx b/xmloff/source/style/styleexp.cxx
new file mode 100644
index 000000000..b311dbdf6
--- /dev/null
+++ b/xmloff/source/style/styleexp.cxx
@@ -0,0 +1,592 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/xmlexppr.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+#include <com/sun/star/text/XChapterNumberingSupplier.hpp>
+#include <xmloff/xmlaustp.hxx>
+#include <xmloff/styleexp.hxx>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/XMLEventExport.hxx>
+#include <xmloff/maptype.hxx>
+#include <memory>
+#include <set>
+#include <prstylecond.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::text;
+using namespace ::xmloff::token;
+
+using ::com::sun::star::document::XEventsSupplier;
+
+constexpr OUStringLiteral gsIsPhysical( u"IsPhysical" );
+constexpr OUStringLiteral gsIsAutoUpdate( u"IsAutoUpdate" );
+constexpr OUStringLiteral gsFollowStyle( u"FollowStyle" );
+constexpr OUStringLiteral gsNumberingStyleName( u"NumberingStyleName" );
+constexpr OUStringLiteral gsOutlineLevel( u"OutlineLevel" );
+
+XMLStyleExport::XMLStyleExport(
+ SvXMLExport& rExp,
+ SvXMLAutoStylePoolP *pAutoStyleP ) :
+ rExport( rExp ),
+ pAutoStylePool( pAutoStyleP )
+{
+}
+
+XMLStyleExport::~XMLStyleExport()
+{
+}
+
+void XMLStyleExport::exportStyleAttributes( const Reference< XStyle >& )
+{
+}
+
+void XMLStyleExport::exportStyleContent( const Reference< XStyle >& rStyle )
+{
+ Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY );
+ assert(xPropSet.is());
+
+ try
+ {
+ uno::Any aProperty = xPropSet->getPropertyValue( "ParaStyleConditions" );
+ uno::Sequence< beans::NamedValue > aSeq;
+
+ aProperty >>= aSeq;
+
+ for (beans::NamedValue const& rNamedCond : std::as_const(aSeq))
+ {
+ OUString aStyleName;
+
+ if (rNamedCond.Value >>= aStyleName)
+ {
+ if (!aStyleName.isEmpty())
+ {
+ OUString aExternal = GetParaStyleCondExternal(rNamedCond.Name);
+
+ if (!aExternal.isEmpty())
+ {
+ bool bEncoded;
+
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ XML_CONDITION,
+ aExternal);
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ XML_APPLY_STYLE_NAME,
+ GetExport().EncodeStyleName( aStyleName,
+ &bEncoded ) );
+ SvXMLElementExport aElem( GetExport(),
+ XML_NAMESPACE_STYLE,
+ XML_MAP,
+ true,
+ true );
+ }
+ }
+ }
+ }
+ }
+ catch( const beans::UnknownPropertyException& )
+ {
+ }
+}
+
+namespace
+{
+/// Writes <style:style style:list-level="..."> for Writer paragraph styles.
+void ExportStyleListlevel(const uno::Reference<beans::XPropertySetInfo>& xPropSetInfo,
+ const uno::Reference<beans::XPropertyState>& xPropState,
+ const uno::Reference<beans::XPropertySet>& xPropSet, SvXMLExport& rExport)
+{
+ if (!xPropSetInfo->hasPropertyByName("NumberingLevel"))
+ {
+ SAL_WARN("xmloff", "ExportStyleListlevel: no NumberingLevel for a Writer paragraph style");
+ return;
+ }
+
+ if (xPropState->getPropertyState("NumberingLevel") != beans::PropertyState_DIRECT_VALUE)
+ {
+ return;
+ }
+
+ sal_Int16 nNumberingLevel{};
+ if (!(xPropSet->getPropertyValue("NumberingLevel") >>= nNumberingLevel))
+ {
+ return;
+ }
+
+ // The spec is positiveInteger (1-based), but the implementation is 0-based.
+ rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_LIST_LEVEL, OUString::number(++nNumberingLevel));
+}
+}
+
+bool XMLStyleExport::exportStyle(
+ const Reference< XStyle >& rStyle,
+ const OUString& rXMLFamily,
+ const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper,
+ const Reference< XNameAccess >& xStyles,
+ const OUString* pPrefix )
+{
+ Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY );
+ if (!xPropSet)
+ return false;
+
+ Reference< XPropertySetInfo > xPropSetInfo =
+ xPropSet->getPropertySetInfo();
+ Any aAny;
+
+ // Don't export styles that aren't existing really. This may be the
+ // case for StarOffice Writer's pool styles.
+ if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) )
+ {
+ aAny = xPropSet->getPropertyValue( gsIsPhysical );
+ if( !*o3tl::doAccess<bool>(aAny) )
+ return false;
+ }
+
+ // <style:style ...>
+ GetExport().CheckAttrList();
+
+ // style:name="..."
+ OUString sName;
+
+ if(pPrefix)
+ sName = *pPrefix;
+ sName += rStyle->getName();
+
+ bool bEncoded = false;
+ const OUString sEncodedStyleName(GetExport().EncodeStyleName( sName, &bEncoded ));
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, sEncodedStyleName );
+
+ if( bEncoded )
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME,
+ sName);
+
+ // style:family="..."
+ if( !rXMLFamily.isEmpty() )
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, rXMLFamily);
+
+ if ( xPropSetInfo->hasPropertyByName( "Hidden" ) )
+ {
+ aAny = xPropSet->getPropertyValue( "Hidden" );
+ bool bHidden = false;
+ if ((aAny >>= bHidden) && bHidden
+ && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
+ {
+ GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDDEN, "true");
+ GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility
+ }
+ }
+
+ // style:parent-style-name="..."
+ OUString sParentString(rStyle->getParentStyle());
+ OUString sParent;
+
+ if(!sParentString.isEmpty())
+ {
+ if(pPrefix)
+ sParent = *pPrefix;
+ sParent += sParentString;
+ }
+
+ if( !sParent.isEmpty() )
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_PARENT_STYLE_NAME,
+ GetExport().EncodeStyleName( sParent ) );
+
+ // style:next-style-name="..." (paragraph styles only)
+ if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) )
+ {
+ aAny = xPropSet->getPropertyValue( gsFollowStyle );
+ OUString sNextName;
+ aAny >>= sNextName;
+ if( sName != sNextName )
+ {
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NEXT_STYLE_NAME,
+ GetExport().EncodeStyleName( sNextName ) );
+ }
+ }
+
+ // style:linked-style-name="..." (SW paragraph and character styles only)
+ if (xPropSetInfo->hasPropertyByName("LinkStyle"))
+ {
+ aAny = xPropSet->getPropertyValue("LinkStyle");
+ OUString sLinkName;
+ aAny >>= sLinkName;
+ if (!sLinkName.isEmpty()
+ && (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
+ {
+ GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_LINKED_STYLE_NAME,
+ GetExport().EncodeStyleName(sLinkName));
+ }
+ }
+
+ // style:auto-update="..." (SW only)
+ if( xPropSetInfo->hasPropertyByName( gsIsAutoUpdate ) )
+ {
+ aAny = xPropSet->getPropertyValue( gsIsAutoUpdate );
+ if( *o3tl::doAccess<bool>(aAny) )
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_AUTO_UPDATE,
+ XML_TRUE );
+ }
+
+ // style:default-outline-level"..."
+ sal_Int32 nOutlineLevel = 0;
+ if( xPropSetInfo->hasPropertyByName( gsOutlineLevel ) )
+ {
+ Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
+ if( PropertyState_DIRECT_VALUE == xPropState->getPropertyState( gsOutlineLevel ) )
+ {
+ aAny = xPropSet->getPropertyValue( gsOutlineLevel );
+ aAny >>= nOutlineLevel;
+ if( nOutlineLevel > 0 )
+ {
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ XML_DEFAULT_OUTLINE_LEVEL,
+ OUString::number(nOutlineLevel) );
+ }
+ else
+ {
+ /* Empty value for style:default-outline-level does exist
+ since ODF 1.2. Thus, suppress its export for former versions. (#i104889#)
+ */
+ if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
+ GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
+ {
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ XML_DEFAULT_OUTLINE_LEVEL,
+ OUString( "" ));
+ }
+ }
+ }
+ }
+
+ // style:list-style-name="..." (SW paragraph styles only)
+ if( xPropSetInfo->hasPropertyByName( gsNumberingStyleName ) )
+ {
+ Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
+ if( PropertyState_DIRECT_VALUE ==
+ xPropState->getPropertyState( gsNumberingStyleName ) )
+ {
+ aAny = xPropSet->getPropertyValue( gsNumberingStyleName );
+ if( aAny.hasValue() )
+ {
+ OUString sListName;
+ aAny >>= sListName;
+
+ /* A direct set empty list style has to be written. Otherwise,
+ this information is lost and causes an error, if the parent
+ style has a list style set. (#i69523#)
+ */
+ if ( sListName.isEmpty() )
+ {
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ XML_LIST_STYLE_NAME,
+ sListName /* empty string */);
+ }
+ else
+ {
+ // Written OpenDocument file format doesn't fit to the created text document (#i69627#)
+ bool bSuppressListStyle( false );
+ {
+ if ( !GetExport().writeOutlineStyleAsNormalListStyle() )
+ {
+ Reference< XChapterNumberingSupplier > xCNSupplier
+ (GetExport().GetModel(), UNO_QUERY);
+
+ if (xCNSupplier.is())
+ {
+ Reference< XIndexReplace > xNumRule
+ ( xCNSupplier->getChapterNumberingRules() );
+ assert(xNumRule.is());
+
+ Reference< XPropertySet > xNumRulePropSet
+ (xNumRule, UNO_QUERY);
+ OUString sOutlineName;
+ xNumRulePropSet->getPropertyValue("Name")
+ >>= sOutlineName;
+ bSuppressListStyle = sListName == sOutlineName;
+ }
+ }
+ }
+
+ if ( !sListName.isEmpty() && !bSuppressListStyle )
+ {
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ XML_LIST_STYLE_NAME,
+ GetExport().EncodeStyleName( sListName ) );
+
+ ExportStyleListlevel(xPropSetInfo, xPropState, xPropSet, GetExport());
+ }
+ }
+ }
+ }
+ else if( nOutlineLevel > 0 )
+ {
+
+ bool bNoInheritedListStyle( true );
+
+ Reference<XStyle> xStyle( xPropState, UNO_QUERY );
+ while ( xStyle.is() )
+ {
+ OUString aParentStyle( xStyle->getParentStyle() );
+ if ( aParentStyle.isEmpty() || !xStyles->hasByName( aParentStyle ) )
+ {
+ break;
+ }
+ else
+ {
+ xPropState.set( xStyles->getByName( aParentStyle ), UNO_QUERY );
+ if ( !xPropState.is() )
+ {
+ break;
+ }
+ if ( xPropState->getPropertyState( gsNumberingStyleName ) == PropertyState_DIRECT_VALUE )
+ {
+ bNoInheritedListStyle = false;
+ break;
+ }
+ else
+ {
+ xStyle.set( xPropState, UNO_QUERY );
+ }
+ }
+ }
+ if ( bNoInheritedListStyle )
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ XML_LIST_STYLE_NAME,
+ OUString( "" ));
+ }
+ }
+
+ // style:pool-id="..." is not required any longer since we use
+ // english style names only
+ exportStyleAttributes( rStyle );
+
+ // TODO: style:help-file-name="..." and style:help-id="..." can neither
+ // be modified by UI nor by API and that for, have not to be exported
+ // currently.
+
+ {
+ // <style:style>
+ SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, XML_STYLE,
+ true, true );
+
+ rPropMapper->SetStyleName( sName );
+
+ // <style:properties>
+ ::std::vector< XMLPropertyState > aPropStates =
+ rPropMapper->Filter(GetExport(), xPropSet, true);
+ bool const bUseExtensionNamespaceForGraphicProperties(
+ rXMLFamily != "drawing-page" &&
+ rXMLFamily != "graphic" &&
+ rXMLFamily != "presentation" &&
+ rXMLFamily != "chart");
+ rPropMapper->exportXML( GetExport(), aPropStates,
+ SvXmlExportFlags::IGN_WS,
+ bUseExtensionNamespaceForGraphicProperties );
+
+ rPropMapper->SetStyleName( OUString() );
+
+ exportStyleContent( rStyle );
+
+ // <script:events>, if they are supported by this style
+ Reference<XEventsSupplier> xEventsSupp(rStyle, UNO_QUERY);
+ GetExport().GetEventExport().Export(xEventsSupp);
+ }
+ return true;
+}
+
+void XMLStyleExport::exportDefaultStyle(
+ const Reference< XPropertySet >& xPropSet,
+ const OUString& rXMLFamily,
+ const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper )
+{
+ // <style:default-style ...>
+ GetExport().CheckAttrList();
+
+ {
+ // style:family="..."
+ if( !rXMLFamily.isEmpty() )
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY,
+ rXMLFamily );
+ // <style:style>
+ SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE,
+ XML_DEFAULT_STYLE,
+ true, true );
+ // <style:properties>
+ ::std::vector< XMLPropertyState > aPropStates =
+ rPropMapper->FilterDefaults(GetExport(), xPropSet);
+ rPropMapper->exportXML( GetExport(), aPropStates,
+ SvXmlExportFlags::IGN_WS );
+ }
+}
+
+void XMLStyleExport::exportStyleFamily(
+ const char *pFamily,
+ const OUString& rXMLFamily,
+ const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper,
+ bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix)
+{
+ const OUString sFamily(OUString::createFromAscii(pFamily ));
+ exportStyleFamily( sFamily, rXMLFamily, rPropMapper, bUsed, nFamily,
+ pPrefix);
+}
+
+void XMLStyleExport::exportStyleFamily(
+ const OUString& rFamily, const OUString& rXMLFamily,
+ const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper,
+ bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix)
+{
+ assert(GetExport().GetModel().is());
+ Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), UNO_QUERY );
+ if( !xFamiliesSupp.is() )
+ return; // family not available in current model
+
+ Reference< XNameAccess > xStyleCont;
+
+ Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() );
+ if( xFamilies->hasByName( rFamily ) )
+ xFamilies->getByName( rFamily ) >>= xStyleCont;
+
+ if( !xStyleCont.is() )
+ return;
+
+ // If next styles are supported and used styles should be exported only,
+ // the next style may be unused but has to be exported, too. In this case
+ // the names of all exported styles are remembered.
+ std::optional<std::set<OUString> > xExportedStyles;
+ bool bFirstStyle = true;
+
+ const uno::Sequence< OUString> aSeq = xStyleCont->getElementNames();
+ for(const auto& rName : aSeq)
+ {
+ Reference< XStyle > xStyle;
+ try
+ {
+ xStyleCont->getByName( rName ) >>= xStyle;
+ }
+ catch(const lang::IndexOutOfBoundsException&)
+ {
+ // due to bugs in prior versions it is possible that
+ // a binary file is missing some critical styles.
+ // The only possible way to deal with this is to
+ // not export them here and remain silent.
+ continue;
+ }
+ catch(css::container::NoSuchElementException&)
+ {
+ continue;
+ }
+
+ assert(xStyle.is());
+ if (!bUsed || xStyle->isInUse())
+ {
+ bool bExported = exportStyle( xStyle, rXMLFamily, rPropMapper,
+ xStyleCont,pPrefix );
+ if (bUsed && bFirstStyle && bExported)
+ {
+ // If this is the first style, find out whether next styles
+ // are supported.
+ Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY );
+ Reference< XPropertySetInfo > xPropSetInfo =
+ xPropSet->getPropertySetInfo();
+
+ if (xPropSetInfo->hasPropertyByName( gsFollowStyle ))
+ xExportedStyles.emplace();
+ bFirstStyle = false;
+ }
+
+ if (xExportedStyles && bExported)
+ {
+ // If next styles are supported, remember this style's name.
+ xExportedStyles->insert( xStyle->getName() );
+ }
+ }
+
+ // if an auto style pool is given, remember this style's name as a
+ // style name that must not be used by automatic styles.
+ if (pAutoStylePool)
+ pAutoStylePool->RegisterName( nFamily, xStyle->getName() );
+ }
+
+ if( !xExportedStyles )
+ return;
+
+ // if next styles are supported, export all next styles that are
+ // unused and that for, haven't been exported in the first loop.
+ for(const auto& rName : aSeq)
+ {
+ Reference< XStyle > xStyle;
+ xStyleCont->getByName( rName ) >>= xStyle;
+
+ assert(xStyle.is());
+
+ Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY );
+ Reference< XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
+
+ // styles that aren't existing really are ignored.
+ if (xPropSetInfo->hasPropertyByName( gsIsPhysical ))
+ {
+ Any aAny( xPropSet->getPropertyValue( gsIsPhysical ) );
+ if (!*o3tl::doAccess<bool>(aAny))
+ continue;
+ }
+
+ if (!xStyle->isInUse())
+ continue;
+
+ if (!xPropSetInfo->hasPropertyByName( gsFollowStyle ))
+ {
+ continue;
+ }
+
+ OUString sNextName;
+ xPropSet->getPropertyValue( gsFollowStyle ) >>= sNextName;
+ OUString sTmp( sNextName );
+ // if the next style hasn't been exported by now, export it now
+ // and remember its name.
+ if (xStyle->getName() != sNextName &&
+ 0 == xExportedStyles->count( sTmp ))
+ {
+ xStyleCont->getByName( sNextName ) >>= xStyle;
+ assert(xStyle.is());
+
+ if (exportStyle(xStyle, rXMLFamily, rPropMapper, xStyleCont, pPrefix))
+ xExportedStyles->insert( sTmp );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */