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/xmlnmspe.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 
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::style;
48 using namespace ::com::sun::star::container;
49 using namespace ::com::sun::star::beans;
50 using namespace ::com::sun::star::text;
51 using namespace ::xmloff::token;
52 
53 using ::com::sun::star::document::XEventsSupplier;
54 
55 static const OUStringLiteral gsIsPhysical( "IsPhysical" );
56 static const OUStringLiteral gsIsAutoUpdate( "IsAutoUpdate" );
57 static const OUStringLiteral gsFollowStyle( "FollowStyle" );
58 static const OUStringLiteral gsNumberingStyleName( "NumberingStyleName" );
59 static const OUStringLiteral gsOutlineLevel( "OutlineLevel" );
60 
62  SvXMLExport& rExp,
63  SvXMLAutoStylePoolP *pAutoStyleP ) :
64  rExport( rExp ),
65  pAutoStylePool( pAutoStyleP )
66 {
67 }
68 
70 {
71 }
72 
73 void XMLStyleExport::exportStyleAttributes( const Reference< XStyle >& )
74 {
75 }
76 
77 void XMLStyleExport::exportStyleContent( const Reference< XStyle >& rStyle )
78 {
79  Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY );
80  assert(xPropSet.is());
81 
82  try
83  {
84  uno::Any aProperty = xPropSet->getPropertyValue( "ParaStyleConditions" );
85  uno::Sequence< beans::NamedValue > aSeq;
86 
87  aProperty >>= aSeq;
88 
89  for (beans::NamedValue const& rNamedCond : std::as_const(aSeq))
90  {
91  OUString aStyleName;
92 
93  if (rNamedCond.Value >>= aStyleName)
94  {
95  if (!aStyleName.isEmpty())
96  {
97  OUString aExternal = GetParaStyleCondExternal(rNamedCond.Name);
98 
99  if (!aExternal.isEmpty())
100  {
101  bool bEncoded;
102 
105  aExternal);
108  GetExport().EncodeStyleName( aStyleName,
109  &bEncoded ) );
110  SvXMLElementExport aElem( GetExport(),
112  XML_MAP,
113  true,
114  true );
115  }
116  }
117  }
118  }
119  }
120  catch( const beans::UnknownPropertyException& )
121  {
122  }
123 }
124 
126  const Reference< XStyle >& rStyle,
127  const OUString& rXMLFamily,
129  const Reference< XNameAccess >& xStyles,
130  const OUString* pPrefix )
131 {
132  Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY );
133  Reference< XPropertySetInfo > xPropSetInfo =
134  xPropSet->getPropertySetInfo();
135  Any aAny;
136 
137  // Don't export styles that aren't existing really. This may be the
138  // case for StarOffice Writer's pool styles.
139  if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) )
140  {
141  aAny = xPropSet->getPropertyValue( gsIsPhysical );
142  if( !*o3tl::doAccess<bool>(aAny) )
143  return false;
144  }
145 
146  // <style:style ...>
148 
149  // style:name="..."
150  OUString sName;
151 
152  if(pPrefix)
153  sName = *pPrefix;
154  sName += rStyle->getName();
155 
156  bool bEncoded = false;
157  const OUString sEncodedStyleName(GetExport().EncodeStyleName( sName, &bEncoded ));
158  GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, sEncodedStyleName );
159 
160  if( bEncoded )
162  sName);
163 
164  // style:family="..."
165  if( !rXMLFamily.isEmpty() )
167 
168  if ( xPropSetInfo->hasPropertyByName( "Hidden" ) )
169  {
170  aAny = xPropSet->getPropertyValue( "Hidden" );
171  bool bHidden = false;
172  if ( ( aAny >>= bHidden ) && bHidden && GetExport( ).getDefaultVersion( ) == SvtSaveOptions::ODFVER_LATEST )
174  }
175 
176  // style:parent-style-name="..."
177  OUString sParentString(rStyle->getParentStyle());
178  OUString sParent;
179 
180  if(!sParentString.isEmpty())
181  {
182  if(pPrefix)
183  sParent = *pPrefix;
184  sParent += sParentString;
185  }
186 
187  if( !sParent.isEmpty() )
189  GetExport().EncodeStyleName( sParent ) );
190 
191  // style:next-style-name="..." (paragraph styles only)
192  if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) )
193  {
194  aAny = xPropSet->getPropertyValue( gsFollowStyle );
195  OUString sNextName;
196  aAny >>= sNextName;
197  if( sName != sNextName )
198  {
200  GetExport().EncodeStyleName( sNextName ) );
201  }
202  }
203 
204  // style:auto-update="..." (SW only)
205  if( xPropSetInfo->hasPropertyByName( gsIsAutoUpdate ) )
206  {
207  aAny = xPropSet->getPropertyValue( gsIsAutoUpdate );
208  if( *o3tl::doAccess<bool>(aAny) )
210  XML_TRUE );
211  }
212 
213  // style:default-outline-level"..."
214  sal_Int32 nOutlineLevel = 0;
215  if( xPropSetInfo->hasPropertyByName( gsOutlineLevel ) )
216  {
217  Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
218  if( PropertyState_DIRECT_VALUE == xPropState->getPropertyState( gsOutlineLevel ) )
219  {
220  aAny = xPropSet->getPropertyValue( gsOutlineLevel );
221  aAny >>= nOutlineLevel;
222  if( nOutlineLevel > 0 )
223  {
226  OUString::number(nOutlineLevel) );
227  }
228  else
229  {
230  /* Empty value for style:default-outline-level does exist
231  since ODF 1.2. Thus, suppress its export for former versions. (#i104889#)
232  */
233  if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
234  GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
235  {
238  OUString( "" ));
239  }
240  }
241  }
242  }
243 
244  // style:list-style-name="..." (SW paragraph styles only)
245  if( xPropSetInfo->hasPropertyByName( gsNumberingStyleName ) )
246  {
247  Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
248  if( PropertyState_DIRECT_VALUE ==
249  xPropState->getPropertyState( gsNumberingStyleName ) )
250  {
251  aAny = xPropSet->getPropertyValue( gsNumberingStyleName );
252  if( aAny.hasValue() )
253  {
254  OUString sListName;
255  aAny >>= sListName;
256 
257  /* A direct set empty list style has to be written. Otherwise,
258  this information is lost and causes an error, if the parent
259  style has a list style set. (#i69523#)
260  */
261  if ( sListName.isEmpty() )
262  {
265  sListName /* empty string */);
266  }
267  else
268  {
269  // Written OpenDocument file format doesn't fit to the created text document (#i69627#)
270  bool bSuppressListStyle( false );
271  {
272  if ( !GetExport().writeOutlineStyleAsNormalListStyle() )
273  {
274  Reference< XChapterNumberingSupplier > xCNSupplier
275  (GetExport().GetModel(), UNO_QUERY);
276 
277  OUString sOutlineName;
278  if (xCNSupplier.is())
279  {
280  Reference< XIndexReplace > xNumRule
281  ( xCNSupplier->getChapterNumberingRules() );
282  assert(xNumRule.is());
283 
284  Reference< XPropertySet > xNumRulePropSet
285  (xNumRule, UNO_QUERY);
286  xNumRulePropSet->getPropertyValue("Name")
287  >>= sOutlineName;
288  bSuppressListStyle = sListName == sOutlineName;
289  }
290  }
291  }
292 
293  if ( !sListName.isEmpty() && !bSuppressListStyle )
294  {
297  GetExport().EncodeStyleName( sListName ) );
298  }
299  }
300  }
301  }
302  else if( nOutlineLevel > 0 )
303  {
304 
305  bool bNoInheritedListStyle( true );
306 
307  Reference<XStyle> xStyle( xPropState, UNO_QUERY );
308  while ( xStyle.is() )
309  {
310  OUString aParentStyle( xStyle->getParentStyle() );
311  if ( aParentStyle.isEmpty() || !xStyles->hasByName( aParentStyle ) )
312  {
313  break;
314  }
315  else
316  {
317  xPropState.set( xStyles->getByName( aParentStyle ), UNO_QUERY );
318  if ( !xPropState.is() )
319  {
320  break;
321  }
322  if ( xPropState->getPropertyState( gsNumberingStyleName ) == PropertyState_DIRECT_VALUE )
323  {
324  bNoInheritedListStyle = false;
325  break;
326  }
327  else
328  {
329  xStyle.set( xPropState, UNO_QUERY );
330  }
331  }
332  }
333  if ( bNoInheritedListStyle )
336  OUString( "" ));
337  }
338  }
339 
340  // style:pool-id="..." is not required any longer since we use
341  // english style names only
342  exportStyleAttributes( rStyle );
343 
344  // TODO: style:help-file-name="..." and style:help-id="..." can neither
345  // be modified by UI nor by API and that for, have not to be exported
346  // currently.
347 
348  {
349  // <style:style>
351  true, true );
352 
353  rPropMapper->SetStyleName( sName );
354 
355  // <style:properties>
356  ::std::vector< XMLPropertyState > aPropStates =
357  rPropMapper->Filter( xPropSet, true );
358  bool const bUseExtensionNamespaceForGraphicProperties(
359  rXMLFamily != "drawing-page" &&
360  rXMLFamily != "graphic" &&
361  rXMLFamily != "presentation" &&
362  rXMLFamily != "chart");
363  rPropMapper->exportXML( GetExport(), aPropStates,
365  bUseExtensionNamespaceForGraphicProperties );
366 
367  rPropMapper->SetStyleName( OUString() );
368 
369  exportStyleContent( rStyle );
370 
371  // <script:events>, if they are supported by this style
372  Reference<XEventsSupplier> xEventsSupp(rStyle, UNO_QUERY);
373  GetExport().GetEventExport().Export(xEventsSupp);
374  }
375  return true;
376 }
377 
379  const Reference< XPropertySet >& xPropSet,
380  const OUString& rXMLFamily,
382 {
383  // <style:default-style ...>
385 
386  {
387  // style:family="..."
388  if( !rXMLFamily.isEmpty() )
390  rXMLFamily );
391  // <style:style>
394  true, true );
395  // <style:properties>
396  ::std::vector< XMLPropertyState > aPropStates =
397  rPropMapper->FilterDefaults( xPropSet );
398  rPropMapper->exportXML( GetExport(), aPropStates,
400  }
401 }
402 
404  const char *pFamily,
405  const OUString& rXMLFamily,
407  bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix)
408 {
409  const OUString sFamily(OUString::createFromAscii(pFamily ));
410  exportStyleFamily( sFamily, rXMLFamily, rPropMapper, bUsed, nFamily,
411  pPrefix);
412 }
413 
415  const OUString& rFamily, const OUString& rXMLFamily,
417  bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix)
418 {
419  assert(GetExport().GetModel().is());
420  Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), UNO_QUERY );
421  if( !xFamiliesSupp.is() )
422  return; // family not available in current model
423 
424  Reference< XNameAccess > xStyleCont;
425 
426  Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() );
427  if( xFamilies->hasByName( rFamily ) )
428  xFamilies->getByName( rFamily ) >>= xStyleCont;
429 
430  if( !xStyleCont.is() )
431  return;
432 
433  // If next styles are supported and used styles should be exported only,
434  // the next style may be unused but has to be exported, too. In this case
435  // the names of all exported styles are remembered.
436  std::unique_ptr<std::set<OUString> > pExportedStyles;
437  bool bFirstStyle = true;
438 
439  const uno::Sequence< OUString> aSeq = xStyleCont->getElementNames();
440  for(const auto& rName : aSeq)
441  {
442  Reference< XStyle > xStyle;
443  try
444  {
445  xStyleCont->getByName( rName ) >>= xStyle;
446  }
447  catch(const lang::IndexOutOfBoundsException&)
448  {
449  // due to bugs in prior versions it is possible that
450  // a binary file is missing some critical styles.
451  // The only possible way to deal with this is to
452  // not export them here and remain silent.
453  continue;
454  }
455  catch(css::container::NoSuchElementException&)
456  {
457  continue;
458  }
459 
460  assert(xStyle.is());
461  if (!bUsed || xStyle->isInUse())
462  {
463  bool bExported = exportStyle( xStyle, rXMLFamily, rPropMapper,
464  xStyleCont,pPrefix );
465  if (bUsed && bFirstStyle && bExported)
466  {
467  // If this is the first style, find out whether next styles
468  // are supported.
469  Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY );
470  Reference< XPropertySetInfo > xPropSetInfo =
471  xPropSet->getPropertySetInfo();
472 
473  if (xPropSetInfo->hasPropertyByName( gsFollowStyle ))
474  pExportedStyles.reset(new std::set<OUString>);
475  bFirstStyle = false;
476  }
477 
478  if (pExportedStyles && bExported)
479  {
480  // If next styles are supported, remember this style's name.
481  pExportedStyles->insert( xStyle->getName() );
482  }
483  }
484 
485  // if an auto style pool is given, remember this style's name as a
486  // style name that must not be used by automatic styles.
487  if (pAutoStylePool)
488  pAutoStylePool->RegisterName( nFamily, xStyle->getName() );
489  }
490 
491  if( pExportedStyles )
492  {
493  // if next styles are supported, export all next styles that are
494  // unused and that for, haven't been exported in the first loop.
495  for(const auto& rName : aSeq)
496  {
497  Reference< XStyle > xStyle;
498  xStyleCont->getByName( rName ) >>= xStyle;
499 
500  assert(xStyle.is());
501 
502  Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY );
503  Reference< XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
504 
505  // styles that aren't existing really are ignored.
506  if (xPropSetInfo->hasPropertyByName( gsIsPhysical ))
507  {
508  Any aAny( xPropSet->getPropertyValue( gsIsPhysical ) );
509  if (!*o3tl::doAccess<bool>(aAny))
510  continue;
511  }
512 
513  if (!xStyle->isInUse())
514  continue;
515 
516  if (!xPropSetInfo->hasPropertyByName( gsFollowStyle ))
517  {
518  continue;
519  }
520 
521  OUString sNextName;
522  xPropSet->getPropertyValue( gsFollowStyle ) >>= sNextName;
523  OUString sTmp( sNextName );
524  // if the next style hasn't been exported by now, export it now
525  // and remember its name.
526  if (xStyle->getName() != sNextName &&
527  0 == pExportedStyles->count( sTmp ))
528  {
529  xStyleCont->getByName( sNextName ) >>= xStyle;
530  assert(xStyle.is());
531 
532  if (exportStyle(xStyle, rXMLFamily, rPropMapper, xStyleCont, pPrefix))
533  pExportedStyles->insert( sTmp );
534  }
535  }
536  }
537 }
538 
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr sal_uInt16 XML_NAMESPACE_STYLE
Definition: xmlnmspe.hxx:30
void exportDefaultStyle(const css::uno::Reference< css::beans::XPropertySet > &xPropSet, const OUString &rXMLFamily, const rtl::Reference< SvXMLExportPropertyMapper > &rPropMapper)
Definition: styleexp.cxx:378
static const OUStringLiteral gsOutlineLevel("OutlineLevel")
void CheckAttrList()
Definition: xmlexp.cxx:1047
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
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:414
void AddAttribute(sal_uInt16 nPrefix, const char *pName, const OUString &rValue)
Definition: xmlexp.cxx:926
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:125
static const OUStringLiteral gsNumberingStyleName("NumberingStyleName")
virtual void exportStyleAttributes(const css::uno::Reference< css::style::XStyle > &rStyle)
Definition: styleexp.cxx:73
XMLEventExport & GetEventExport()
get Event export, with handlers for script types "None" and "StarBasic" already registered; other han...
Definition: xmlexp.cxx:2014
virtual void exportStyleContent(const css::uno::Reference< css::style::XStyle > &rStyle)
Definition: styleexp.cxx:77
static const OUStringLiteral gsIsAutoUpdate("IsAutoUpdate")
XMLStyleExport(SvXMLExport &rExp, SvXMLAutoStylePoolP *pAutoStyleP=nullptr)
Definition: styleexp.cxx:61
Handling of tokens in XML:
Sequence< sal_Int8 > aSeq
static const OUStringLiteral gsFollowStyle("FollowStyle")
virtual ~XMLStyleExport() override
Definition: styleexp.cxx:69
static const OUStringLiteral gsIsPhysical("IsPhysical")
css::uno::Any const SvXMLExport & rExport
Definition: ImageStyle.hxx:38
void Export(css::uno::Reference< css::document::XEventsSupplier > const &xAccess, bool bUseWhitespace=true)
export the events (calls EventExport::Export(Reference) )