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  rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_LIST_LEVEL, OUString::number(nNumberingLevel));
151 }
152 }
153 
155  const Reference< XStyle >& rStyle,
156  const OUString& rXMLFamily,
158  const Reference< XNameAccess >& xStyles,
159  const OUString* pPrefix )
160 {
161  Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY );
162  if (!xPropSet)
163  return false;
164 
165  Reference< XPropertySetInfo > xPropSetInfo =
166  xPropSet->getPropertySetInfo();
167  Any aAny;
168 
169  // Don't export styles that aren't existing really. This may be the
170  // case for StarOffice Writer's pool styles.
171  if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) )
172  {
173  aAny = xPropSet->getPropertyValue( gsIsPhysical );
174  if( !*o3tl::doAccess<bool>(aAny) )
175  return false;
176  }
177 
178  // <style:style ...>
180 
181  // style:name="..."
182  OUString sName;
183 
184  if(pPrefix)
185  sName = *pPrefix;
186  sName += rStyle->getName();
187 
188  bool bEncoded = false;
189  const OUString sEncodedStyleName(GetExport().EncodeStyleName( sName, &bEncoded ));
190  GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, sEncodedStyleName );
191 
192  if( bEncoded )
194  sName);
195 
196  // style:family="..."
197  if( !rXMLFamily.isEmpty() )
199 
200  if ( xPropSetInfo->hasPropertyByName( "Hidden" ) )
201  {
202  aAny = xPropSet->getPropertyValue( "Hidden" );
203  bool bHidden = false;
204  if ((aAny >>= bHidden) && bHidden
205  && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
206  {
208  GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility
209  }
210  }
211 
212  // style:parent-style-name="..."
213  OUString sParentString(rStyle->getParentStyle());
214  OUString sParent;
215 
216  if(!sParentString.isEmpty())
217  {
218  if(pPrefix)
219  sParent = *pPrefix;
220  sParent += sParentString;
221  }
222 
223  if( !sParent.isEmpty() )
225  GetExport().EncodeStyleName( sParent ) );
226 
227  // style:next-style-name="..." (paragraph styles only)
228  if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) )
229  {
230  aAny = xPropSet->getPropertyValue( gsFollowStyle );
231  OUString sNextName;
232  aAny >>= sNextName;
233  if( sName != sNextName )
234  {
236  GetExport().EncodeStyleName( sNextName ) );
237  }
238  }
239 
240  // style:auto-update="..." (SW only)
241  if( xPropSetInfo->hasPropertyByName( gsIsAutoUpdate ) )
242  {
243  aAny = xPropSet->getPropertyValue( gsIsAutoUpdate );
244  if( *o3tl::doAccess<bool>(aAny) )
246  XML_TRUE );
247  }
248 
249  // style:default-outline-level"..."
250  sal_Int32 nOutlineLevel = 0;
251  if( xPropSetInfo->hasPropertyByName( gsOutlineLevel ) )
252  {
253  Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
254  if( PropertyState_DIRECT_VALUE == xPropState->getPropertyState( gsOutlineLevel ) )
255  {
256  aAny = xPropSet->getPropertyValue( gsOutlineLevel );
257  aAny >>= nOutlineLevel;
258  if( nOutlineLevel > 0 )
259  {
262  OUString::number(nOutlineLevel) );
263  }
264  else
265  {
266  /* Empty value for style:default-outline-level does exist
267  since ODF 1.2. Thus, suppress its export for former versions. (#i104889#)
268  */
269  if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
270  GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
271  {
274  OUString( "" ));
275  }
276  }
277  }
278  }
279 
280  // style:list-style-name="..." (SW paragraph styles only)
281  if( xPropSetInfo->hasPropertyByName( gsNumberingStyleName ) )
282  {
283  Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
284  if( PropertyState_DIRECT_VALUE ==
285  xPropState->getPropertyState( gsNumberingStyleName ) )
286  {
287  aAny = xPropSet->getPropertyValue( gsNumberingStyleName );
288  if( aAny.hasValue() )
289  {
290  OUString sListName;
291  aAny >>= sListName;
292 
293  /* A direct set empty list style has to be written. Otherwise,
294  this information is lost and causes an error, if the parent
295  style has a list style set. (#i69523#)
296  */
297  if ( sListName.isEmpty() )
298  {
301  sListName /* empty string */);
302  }
303  else
304  {
305  // Written OpenDocument file format doesn't fit to the created text document (#i69627#)
306  bool bSuppressListStyle( false );
307  {
308  if ( !GetExport().writeOutlineStyleAsNormalListStyle() )
309  {
310  Reference< XChapterNumberingSupplier > xCNSupplier
311  (GetExport().GetModel(), UNO_QUERY);
312 
313  if (xCNSupplier.is())
314  {
315  Reference< XIndexReplace > xNumRule
316  ( xCNSupplier->getChapterNumberingRules() );
317  assert(xNumRule.is());
318 
319  Reference< XPropertySet > xNumRulePropSet
320  (xNumRule, UNO_QUERY);
321  OUString sOutlineName;
322  xNumRulePropSet->getPropertyValue("Name")
323  >>= sOutlineName;
324  bSuppressListStyle = sListName == sOutlineName;
325  }
326  }
327  }
328 
329  if ( !sListName.isEmpty() && !bSuppressListStyle )
330  {
333  GetExport().EncodeStyleName( sListName ) );
334 
335  ExportStyleListlevel(xPropSetInfo, xPropState, xPropSet, GetExport());
336  }
337  }
338  }
339  }
340  else if( nOutlineLevel > 0 )
341  {
342 
343  bool bNoInheritedListStyle( true );
344 
345  Reference<XStyle> xStyle( xPropState, UNO_QUERY );
346  while ( xStyle.is() )
347  {
348  OUString aParentStyle( xStyle->getParentStyle() );
349  if ( aParentStyle.isEmpty() || !xStyles->hasByName( aParentStyle ) )
350  {
351  break;
352  }
353  else
354  {
355  xPropState.set( xStyles->getByName( aParentStyle ), UNO_QUERY );
356  if ( !xPropState.is() )
357  {
358  break;
359  }
360  if ( xPropState->getPropertyState( gsNumberingStyleName ) == PropertyState_DIRECT_VALUE )
361  {
362  bNoInheritedListStyle = false;
363  break;
364  }
365  else
366  {
367  xStyle.set( xPropState, UNO_QUERY );
368  }
369  }
370  }
371  if ( bNoInheritedListStyle )
374  OUString( "" ));
375  }
376  }
377 
378  // style:pool-id="..." is not required any longer since we use
379  // english style names only
380  exportStyleAttributes( rStyle );
381 
382  // TODO: style:help-file-name="..." and style:help-id="..." can neither
383  // be modified by UI nor by API and that for, have not to be exported
384  // currently.
385 
386  {
387  // <style:style>
389  true, true );
390 
391  rPropMapper->SetStyleName( sName );
392 
393  // <style:properties>
394  ::std::vector< XMLPropertyState > aPropStates =
395  rPropMapper->Filter(GetExport(), xPropSet, true);
396  bool const bUseExtensionNamespaceForGraphicProperties(
397  rXMLFamily != "drawing-page" &&
398  rXMLFamily != "graphic" &&
399  rXMLFamily != "presentation" &&
400  rXMLFamily != "chart");
401  rPropMapper->exportXML( GetExport(), aPropStates,
403  bUseExtensionNamespaceForGraphicProperties );
404 
405  rPropMapper->SetStyleName( OUString() );
406 
407  exportStyleContent( rStyle );
408 
409  // <script:events>, if they are supported by this style
410  Reference<XEventsSupplier> xEventsSupp(rStyle, UNO_QUERY);
411  GetExport().GetEventExport().Export(xEventsSupp);
412  }
413  return true;
414 }
415 
417  const Reference< XPropertySet >& xPropSet,
418  const OUString& rXMLFamily,
420 {
421  // <style:default-style ...>
423 
424  {
425  // style:family="..."
426  if( !rXMLFamily.isEmpty() )
428  rXMLFamily );
429  // <style:style>
432  true, true );
433  // <style:properties>
434  ::std::vector< XMLPropertyState > aPropStates =
435  rPropMapper->FilterDefaults(GetExport(), xPropSet);
436  rPropMapper->exportXML( GetExport(), aPropStates,
438  }
439 }
440 
442  const char *pFamily,
443  const OUString& rXMLFamily,
445  bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix)
446 {
447  const OUString sFamily(OUString::createFromAscii(pFamily ));
448  exportStyleFamily( sFamily, rXMLFamily, rPropMapper, bUsed, nFamily,
449  pPrefix);
450 }
451 
453  const OUString& rFamily, const OUString& rXMLFamily,
455  bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix)
456 {
457  assert(GetExport().GetModel().is());
458  Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), UNO_QUERY );
459  if( !xFamiliesSupp.is() )
460  return; // family not available in current model
461 
462  Reference< XNameAccess > xStyleCont;
463 
464  Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() );
465  if( xFamilies->hasByName( rFamily ) )
466  xFamilies->getByName( rFamily ) >>= xStyleCont;
467 
468  if( !xStyleCont.is() )
469  return;
470 
471  // If next styles are supported and used styles should be exported only,
472  // the next style may be unused but has to be exported, too. In this case
473  // the names of all exported styles are remembered.
474  std::optional<std::set<OUString> > xExportedStyles;
475  bool bFirstStyle = true;
476 
477  const uno::Sequence< OUString> aSeq = xStyleCont->getElementNames();
478  for(const auto& rName : aSeq)
479  {
480  Reference< XStyle > xStyle;
481  try
482  {
483  xStyleCont->getByName( rName ) >>= xStyle;
484  }
485  catch(const lang::IndexOutOfBoundsException&)
486  {
487  // due to bugs in prior versions it is possible that
488  // a binary file is missing some critical styles.
489  // The only possible way to deal with this is to
490  // not export them here and remain silent.
491  continue;
492  }
493  catch(css::container::NoSuchElementException&)
494  {
495  continue;
496  }
497 
498  assert(xStyle.is());
499  if (!bUsed || xStyle->isInUse())
500  {
501  bool bExported = exportStyle( xStyle, rXMLFamily, rPropMapper,
502  xStyleCont,pPrefix );
503  if (bUsed && bFirstStyle && bExported)
504  {
505  // If this is the first style, find out whether next styles
506  // are supported.
507  Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY );
508  Reference< XPropertySetInfo > xPropSetInfo =
509  xPropSet->getPropertySetInfo();
510 
511  if (xPropSetInfo->hasPropertyByName( gsFollowStyle ))
512  xExportedStyles.emplace();
513  bFirstStyle = false;
514  }
515 
516  if (xExportedStyles && bExported)
517  {
518  // If next styles are supported, remember this style's name.
519  xExportedStyles->insert( xStyle->getName() );
520  }
521  }
522 
523  // if an auto style pool is given, remember this style's name as a
524  // style name that must not be used by automatic styles.
525  if (pAutoStylePool)
526  pAutoStylePool->RegisterName( nFamily, xStyle->getName() );
527  }
528 
529  if( !xExportedStyles )
530  return;
531 
532  // if next styles are supported, export all next styles that are
533  // unused and that for, haven't been exported in the first loop.
534  for(const auto& rName : aSeq)
535  {
536  Reference< XStyle > xStyle;
537  xStyleCont->getByName( rName ) >>= xStyle;
538 
539  assert(xStyle.is());
540 
541  Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY );
542  Reference< XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
543 
544  // styles that aren't existing really are ignored.
545  if (xPropSetInfo->hasPropertyByName( gsIsPhysical ))
546  {
547  Any aAny( xPropSet->getPropertyValue( gsIsPhysical ) );
548  if (!*o3tl::doAccess<bool>(aAny))
549  continue;
550  }
551 
552  if (!xStyle->isInUse())
553  continue;
554 
555  if (!xPropSetInfo->hasPropertyByName( gsFollowStyle ))
556  {
557  continue;
558  }
559 
560  OUString sNextName;
561  xPropSet->getPropertyValue( gsFollowStyle ) >>= sNextName;
562  OUString sTmp( sNextName );
563  // if the next style hasn't been exported by now, export it now
564  // and remember its name.
565  if (xStyle->getName() != sNextName &&
566  0 == xExportedStyles->count( sTmp ))
567  {
568  xStyleCont->getByName( sNextName ) >>= xStyle;
569  assert(xStyle.is());
570 
571  if (exportStyle(xStyle, rXMLFamily, rPropMapper, xStyleCont, pPrefix))
572  xExportedStyles->insert( sTmp );
573  }
574  }
575 }
576 
577 /* 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:416
constexpr OUStringLiteral gsIsPhysical(u"IsPhysical")
void CheckAttrList()
Definition: xmlexp.cxx:1059
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:47
void exportStyleFamily(const OUString &rFamily, const OUString &rXMLFamily, const rtl::Reference< SvXMLExportPropertyMapper > &rPropMapper, bool bUsed, XmlStyleFamily nFamily, const OUString *pPrefix=nullptr)
Definition: styleexp.cxx:452
constexpr OUStringLiteral gsIsAutoUpdate(u"IsAutoUpdate")
void AddAttribute(sal_uInt16 nPrefix, const char *pName, const OUString &rValue)
Definition: xmlexp.cxx:938
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:154
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:2036
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) )