LibreOffice Module xmloff (master)  1
styleexp.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <o3tl/any.hxx>
23 #include <xmloff/xmlnamespace.hxx>
24 #include <xmloff/xmltoken.hxx>
25 #include <xmloff/xmluconv.hxx>
26 #include <xmloff/xmlexppr.hxx>
27 #include <com/sun/star/frame/XModel.hpp>
28 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
29 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
30 #include <com/sun/star/style/XStyle.hpp>
31 #include <com/sun/star/beans/NamedValue.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/beans/XPropertyState.hpp>
34 #include <com/sun/star/document/XEventsSupplier.hpp>
35 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
36 #include <xmloff/xmlaustp.hxx>
37 #include <xmloff/styleexp.hxx>
38 #include <xmloff/xmlexp.hxx>
40 #include <xmloff/maptype.hxx>
41 #include <memory>
42 #include <set>
43 #include <prstylecond.hxx>
44 #include <sal/log.hxx>
45 
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::style;
49 using namespace ::com::sun::star::container;
50 using namespace ::com::sun::star::beans;
51 using namespace ::com::sun::star::text;
52 using namespace ::xmloff::token;
53 
54 using ::com::sun::star::document::XEventsSupplier;
55 
56 constexpr OUStringLiteral gsIsPhysical( u"IsPhysical" );
57 constexpr OUStringLiteral gsIsAutoUpdate( u"IsAutoUpdate" );
58 constexpr OUStringLiteral gsFollowStyle( u"FollowStyle" );
59 constexpr OUStringLiteral gsNumberingStyleName( u"NumberingStyleName" );
60 constexpr OUStringLiteral gsOutlineLevel( u"OutlineLevel" );
61 
63  SvXMLExport& rExp,
64  SvXMLAutoStylePoolP *pAutoStyleP ) :
65  rExport( rExp ),
66  pAutoStylePool( pAutoStyleP )
67 {
68 }
69 
71 {
72 }
73 
74 void XMLStyleExport::exportStyleAttributes( const Reference< XStyle >& )
75 {
76 }
77 
78 void XMLStyleExport::exportStyleContent( const Reference< XStyle >& rStyle )
79 {
80  Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY );
81  assert(xPropSet.is());
82 
83  try
84  {
85  uno::Any aProperty = xPropSet->getPropertyValue( "ParaStyleConditions" );
86  uno::Sequence< beans::NamedValue > aSeq;
87 
88  aProperty >>= aSeq;
89 
90  for (beans::NamedValue const& rNamedCond : std::as_const(aSeq))
91  {
92  OUString aStyleName;
93 
94  if (rNamedCond.Value >>= aStyleName)
95  {
96  if (!aStyleName.isEmpty())
97  {
98  OUString aExternal = GetParaStyleCondExternal(rNamedCond.Name);
99 
100  if (!aExternal.isEmpty())
101  {
102  bool bEncoded;
103 
106  aExternal);
109  GetExport().EncodeStyleName( aStyleName,
110  &bEncoded ) );
111  SvXMLElementExport aElem( GetExport(),
113  XML_MAP,
114  true,
115  true );
116  }
117  }
118  }
119  }
120  }
121  catch( const beans::UnknownPropertyException& )
122  {
123  }
124 }
125 
126 namespace
127 {
129 void ExportStyleListlevel(const uno::Reference<beans::XPropertySetInfo>& xPropSetInfo,
130  const uno::Reference<beans::XPropertyState>& xPropState,
131  const uno::Reference<beans::XPropertySet>& xPropSet, SvXMLExport& rExport)
132 {
133  if (!xPropSetInfo->hasPropertyByName("NumberingLevel"))
134  {
135  SAL_WARN("xmloff", "ExportStyleListlevel: no NumberingLevel for a Writer paragraph style");
136  return;
137  }
138 
139  if (xPropState->getPropertyState("NumberingLevel") != beans::PropertyState_DIRECT_VALUE)
140  {
141  return;
142  }
143 
144  sal_Int16 nNumberingLevel{};
145  if (!(xPropSet->getPropertyValue("NumberingLevel") >>= nNumberingLevel))
146  {
147  return;
148  }
149 
150  // The spec is positiveInteger (1-based), but the implementation is 0-based.
151  rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_LIST_LEVEL, OUString::number(++nNumberingLevel));
152 }
153 }
154 
156  const Reference< XStyle >& rStyle,
157  const OUString& rXMLFamily,
159  const Reference< XNameAccess >& xStyles,
160  const OUString* pPrefix )
161 {
162  Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY );
163  if (!xPropSet)
164  return false;
165 
166  Reference< XPropertySetInfo > xPropSetInfo =
167  xPropSet->getPropertySetInfo();
168  Any aAny;
169 
170  // Don't export styles that aren't existing really. This may be the
171  // case for StarOffice Writer's pool styles.
172  if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) )
173  {
174  aAny = xPropSet->getPropertyValue( gsIsPhysical );
175  if( !*o3tl::doAccess<bool>(aAny) )
176  return false;
177  }
178 
179  // <style:style ...>
181 
182  // style:name="..."
183  OUString sName;
184 
185  if(pPrefix)
186  sName = *pPrefix;
187  sName += rStyle->getName();
188 
189  bool bEncoded = false;
190  const OUString sEncodedStyleName(GetExport().EncodeStyleName( sName, &bEncoded ));
191  GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, sEncodedStyleName );
192 
193  if( bEncoded )
195  sName);
196 
197  // style:family="..."
198  if( !rXMLFamily.isEmpty() )
200 
201  if ( xPropSetInfo->hasPropertyByName( "Hidden" ) )
202  {
203  aAny = xPropSet->getPropertyValue( "Hidden" );
204  bool bHidden = false;
205  if ((aAny >>= bHidden) && bHidden
206  && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
207  {
209  GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility
210  }
211  }
212 
213  // style:parent-style-name="..."
214  OUString sParentString(rStyle->getParentStyle());
215  OUString sParent;
216 
217  if(!sParentString.isEmpty())
218  {
219  if(pPrefix)
220  sParent = *pPrefix;
221  sParent += sParentString;
222  }
223 
224  if( !sParent.isEmpty() )
226  GetExport().EncodeStyleName( sParent ) );
227 
228  // style:next-style-name="..." (paragraph styles only)
229  if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) )
230  {
231  aAny = xPropSet->getPropertyValue( gsFollowStyle );
232  OUString sNextName;
233  aAny >>= sNextName;
234  if( sName != sNextName )
235  {
237  GetExport().EncodeStyleName( sNextName ) );
238  }
239  }
240 
241  // style:linked-style-name="..." (SW paragraph and character styles only)
242  if (xPropSetInfo->hasPropertyByName("LinkStyle"))
243  {
244  aAny = xPropSet->getPropertyValue("LinkStyle");
245  OUString sLinkName;
246  aAny >>= sLinkName;
247  if (!sLinkName.isEmpty())
248  {
250  GetExport().EncodeStyleName(sLinkName));
251  }
252  }
253 
254  // style:auto-update="..." (SW only)
255  if( xPropSetInfo->hasPropertyByName( gsIsAutoUpdate ) )
256  {
257  aAny = xPropSet->getPropertyValue( gsIsAutoUpdate );
258  if( *o3tl::doAccess<bool>(aAny) )
260  XML_TRUE );
261  }
262 
263  // style:default-outline-level"..."
264  sal_Int32 nOutlineLevel = 0;
265  if( xPropSetInfo->hasPropertyByName( gsOutlineLevel ) )
266  {
267  Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
268  if( PropertyState_DIRECT_VALUE == xPropState->getPropertyState( gsOutlineLevel ) )
269  {
270  aAny = xPropSet->getPropertyValue( gsOutlineLevel );
271  aAny >>= nOutlineLevel;
272  if( nOutlineLevel > 0 )
273  {
276  OUString::number(nOutlineLevel) );
277  }
278  else
279  {
280  /* Empty value for style:default-outline-level does exist
281  since ODF 1.2. Thus, suppress its export for former versions. (#i104889#)
282  */
283  if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
284  GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
285  {
288  OUString( "" ));
289  }
290  }
291  }
292  }
293 
294  // style:list-style-name="..." (SW paragraph styles only)
295  if( xPropSetInfo->hasPropertyByName( gsNumberingStyleName ) )
296  {
297  Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
298  if( PropertyState_DIRECT_VALUE ==
299  xPropState->getPropertyState( gsNumberingStyleName ) )
300  {
301  aAny = xPropSet->getPropertyValue( gsNumberingStyleName );
302  if( aAny.hasValue() )
303  {
304  OUString sListName;
305  aAny >>= sListName;
306 
307  /* A direct set empty list style has to be written. Otherwise,
308  this information is lost and causes an error, if the parent
309  style has a list style set. (#i69523#)
310  */
311  if ( sListName.isEmpty() )
312  {
315  sListName /* empty string */);
316  }
317  else
318  {
319  // Written OpenDocument file format doesn't fit to the created text document (#i69627#)
320  bool bSuppressListStyle( false );
321  {
322  if ( !GetExport().writeOutlineStyleAsNormalListStyle() )
323  {
324  Reference< XChapterNumberingSupplier > xCNSupplier
325  (GetExport().GetModel(), UNO_QUERY);
326 
327  if (xCNSupplier.is())
328  {
329  Reference< XIndexReplace > xNumRule
330  ( xCNSupplier->getChapterNumberingRules() );
331  assert(xNumRule.is());
332 
333  Reference< XPropertySet > xNumRulePropSet
334  (xNumRule, UNO_QUERY);
335  OUString sOutlineName;
336  xNumRulePropSet->getPropertyValue("Name")
337  >>= sOutlineName;
338  bSuppressListStyle = sListName == sOutlineName;
339  }
340  }
341  }
342 
343  if ( !sListName.isEmpty() && !bSuppressListStyle )
344  {
347  GetExport().EncodeStyleName( sListName ) );
348 
349  ExportStyleListlevel(xPropSetInfo, xPropState, xPropSet, GetExport());
350  }
351  }
352  }
353  }
354  else if( nOutlineLevel > 0 )
355  {
356 
357  bool bNoInheritedListStyle( true );
358 
359  Reference<XStyle> xStyle( xPropState, UNO_QUERY );
360  while ( xStyle.is() )
361  {
362  OUString aParentStyle( xStyle->getParentStyle() );
363  if ( aParentStyle.isEmpty() || !xStyles->hasByName( aParentStyle ) )
364  {
365  break;
366  }
367  else
368  {
369  xPropState.set( xStyles->getByName( aParentStyle ), UNO_QUERY );
370  if ( !xPropState.is() )
371  {
372  break;
373  }
374  if ( xPropState->getPropertyState( gsNumberingStyleName ) == PropertyState_DIRECT_VALUE )
375  {
376  bNoInheritedListStyle = false;
377  break;
378  }
379  else
380  {
381  xStyle.set( xPropState, UNO_QUERY );
382  }
383  }
384  }
385  if ( bNoInheritedListStyle )
388  OUString( "" ));
389  }
390  }
391 
392  // style:pool-id="..." is not required any longer since we use
393  // english style names only
394  exportStyleAttributes( rStyle );
395 
396  // TODO: style:help-file-name="..." and style:help-id="..." can neither
397  // be modified by UI nor by API and that for, have not to be exported
398  // currently.
399 
400  {
401  // <style:style>
403  true, true );
404 
405  rPropMapper->SetStyleName( sName );
406 
407  // <style:properties>
408  ::std::vector< XMLPropertyState > aPropStates =
409  rPropMapper->Filter(GetExport(), xPropSet, true);
410  bool const bUseExtensionNamespaceForGraphicProperties(
411  rXMLFamily != "drawing-page" &&
412  rXMLFamily != "graphic" &&
413  rXMLFamily != "presentation" &&
414  rXMLFamily != "chart");
415  rPropMapper->exportXML( GetExport(), aPropStates,
417  bUseExtensionNamespaceForGraphicProperties );
418 
419  rPropMapper->SetStyleName( OUString() );
420 
421  exportStyleContent( rStyle );
422 
423  // <script:events>, if they are supported by this style
424  Reference<XEventsSupplier> xEventsSupp(rStyle, UNO_QUERY);
425  GetExport().GetEventExport().Export(xEventsSupp);
426  }
427  return true;
428 }
429 
431  const Reference< XPropertySet >& xPropSet,
432  const OUString& rXMLFamily,
434 {
435  // <style:default-style ...>
437 
438  {
439  // style:family="..."
440  if( !rXMLFamily.isEmpty() )
442  rXMLFamily );
443  // <style:style>
446  true, true );
447  // <style:properties>
448  ::std::vector< XMLPropertyState > aPropStates =
449  rPropMapper->FilterDefaults(GetExport(), xPropSet);
450  rPropMapper->exportXML( GetExport(), aPropStates,
452  }
453 }
454 
456  const char *pFamily,
457  const OUString& rXMLFamily,
459  bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix)
460 {
461  const OUString sFamily(OUString::createFromAscii(pFamily ));
462  exportStyleFamily( sFamily, rXMLFamily, rPropMapper, bUsed, nFamily,
463  pPrefix);
464 }
465 
467  const OUString& rFamily, const OUString& rXMLFamily,
469  bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix)
470 {
471  assert(GetExport().GetModel().is());
472  Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), UNO_QUERY );
473  if( !xFamiliesSupp.is() )
474  return; // family not available in current model
475 
476  Reference< XNameAccess > xStyleCont;
477 
478  Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() );
479  if( xFamilies->hasByName( rFamily ) )
480  xFamilies->getByName( rFamily ) >>= xStyleCont;
481 
482  if( !xStyleCont.is() )
483  return;
484 
485  // If next styles are supported and used styles should be exported only,
486  // the next style may be unused but has to be exported, too. In this case
487  // the names of all exported styles are remembered.
488  std::optional<std::set<OUString> > xExportedStyles;
489  bool bFirstStyle = true;
490 
491  const uno::Sequence< OUString> aSeq = xStyleCont->getElementNames();
492  for(const auto& rName : aSeq)
493  {
494  Reference< XStyle > xStyle;
495  try
496  {
497  xStyleCont->getByName( rName ) >>= xStyle;
498  }
499  catch(const lang::IndexOutOfBoundsException&)
500  {
501  // due to bugs in prior versions it is possible that
502  // a binary file is missing some critical styles.
503  // The only possible way to deal with this is to
504  // not export them here and remain silent.
505  continue;
506  }
507  catch(css::container::NoSuchElementException&)
508  {
509  continue;
510  }
511 
512  assert(xStyle.is());
513  if (!bUsed || xStyle->isInUse())
514  {
515  bool bExported = exportStyle( xStyle, rXMLFamily, rPropMapper,
516  xStyleCont,pPrefix );
517  if (bUsed && bFirstStyle && bExported)
518  {
519  // If this is the first style, find out whether next styles
520  // are supported.
521  Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY );
522  Reference< XPropertySetInfo > xPropSetInfo =
523  xPropSet->getPropertySetInfo();
524 
525  if (xPropSetInfo->hasPropertyByName( gsFollowStyle ))
526  xExportedStyles.emplace();
527  bFirstStyle = false;
528  }
529 
530  if (xExportedStyles && bExported)
531  {
532  // If next styles are supported, remember this style's name.
533  xExportedStyles->insert( xStyle->getName() );
534  }
535  }
536 
537  // if an auto style pool is given, remember this style's name as a
538  // style name that must not be used by automatic styles.
539  if (pAutoStylePool)
540  pAutoStylePool->RegisterName( nFamily, xStyle->getName() );
541  }
542 
543  if( !xExportedStyles )
544  return;
545 
546  // if next styles are supported, export all next styles that are
547  // unused and that for, haven't been exported in the first loop.
548  for(const auto& rName : aSeq)
549  {
550  Reference< XStyle > xStyle;
551  xStyleCont->getByName( rName ) >>= xStyle;
552 
553  assert(xStyle.is());
554 
555  Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY );
556  Reference< XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
557 
558  // styles that aren't existing really are ignored.
559  if (xPropSetInfo->hasPropertyByName( gsIsPhysical ))
560  {
561  Any aAny( xPropSet->getPropertyValue( gsIsPhysical ) );
562  if (!*o3tl::doAccess<bool>(aAny))
563  continue;
564  }
565 
566  if (!xStyle->isInUse())
567  continue;
568 
569  if (!xPropSetInfo->hasPropertyByName( gsFollowStyle ))
570  {
571  continue;
572  }
573 
574  OUString sNextName;
575  xPropSet->getPropertyValue( gsFollowStyle ) >>= sNextName;
576  OUString sTmp( sNextName );
577  // if the next style hasn't been exported by now, export it now
578  // and remember its name.
579  if (xStyle->getName() != sNextName &&
580  0 == xExportedStyles->count( sTmp ))
581  {
582  xStyleCont->getByName( sNextName ) >>= xStyle;
583  assert(xStyle.is());
584 
585  if (exportStyle(xStyle, rXMLFamily, rPropMapper, xStyleCont, pPrefix))
586  xExportedStyles->insert( sTmp );
587  }
588  }
589 }
590 
591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr OUStringLiteral gsOutlineLevel(u"OutlineLevel")
constexpr OUStringLiteral gsNumberingStyleName(u"NumberingStyleName")
void exportDefaultStyle(const css::uno::Reference< css::beans::XPropertySet > &xPropSet, const OUString &rXMLFamily, const rtl::Reference< SvXMLExportPropertyMapper > &rPropMapper)
Definition: styleexp.cxx:430
constexpr OUStringLiteral gsIsPhysical(u"IsPhysical")
void CheckAttrList()
Definition: xmlexp.cxx:1016
void RegisterName(XmlStyleFamily nFamily, const OUString &rName)
Register a name that must not be used as a generated name.
Definition: xmlaustp.cxx:300
OUString GetParaStyleCondExternal(OUString const &internal)
Definition: prstylecond.cxx:71
constexpr sal_uInt16 XML_NAMESPACE_LO_EXT
constexpr OUStringLiteral gsFollowStyle(u"FollowStyle")
SvXMLAutoStylePoolP * pAutoStylePool
Definition: styleexp.hxx:56
SvXMLExport & GetExport()
Definition: styleexp.hxx:59
XmlStyleFamily
Definition: families.hxx:49
void exportStyleFamily(const OUString &rFamily, const OUString &rXMLFamily, const rtl::Reference< SvXMLExportPropertyMapper > &rPropMapper, bool bUsed, XmlStyleFamily nFamily, const OUString *pPrefix=nullptr)
Definition: styleexp.cxx:466
constexpr OUStringLiteral gsIsAutoUpdate(u"IsAutoUpdate")
void AddAttribute(sal_uInt16 nPrefix, const OUString &rName, const OUString &rValue)
Definition: xmlexp.cxx:911
const char * sName
bool exportStyle(const css::uno::Reference< css::style::XStyle > &rStyle, const OUString &rXMLFamily, const rtl::Reference< SvXMLExportPropertyMapper > &rPropMapper, const css::uno::Reference< css::container::XNameAccess > &xStyles, const OUString *pPrefix)
Definition: styleexp.cxx:155
virtual void exportStyleAttributes(const css::uno::Reference< css::style::XStyle > &rStyle)
Definition: styleexp.cxx:74
XMLEventExport & GetEventExport()
get Event export, with handlers for script types "None" and "StarBasic" already registered; other han...
Definition: xmlexp.cxx:1994
virtual void exportStyleContent(const css::uno::Reference< css::style::XStyle > &rStyle)
Definition: styleexp.cxx:78
XMLStyleExport(SvXMLExport &rExp, SvXMLAutoStylePoolP *pAutoStyleP=nullptr)
Definition: styleexp.cxx:62
Handling of tokens in XML:
Sequence< sal_Int8 > aSeq
virtual ~XMLStyleExport() override
Definition: styleexp.cxx:70
#define SAL_WARN(area, stream)
constexpr sal_uInt16 XML_NAMESPACE_STYLE
void Export(css::uno::Reference< css::document::XEventsSupplier > const &xAccess, bool bUseWhitespace=true)
export the events (calls EventExport::Export(Reference) )