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