1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/debug.hxx>
21 #include <xmloff/nmspmap.hxx>
22 #include "xmloff/xmlnmspe.hxx"
23 #include <xmloff/xmltoken.hxx>
24 #include <xmloff/xmluconv.hxx>
25 #include <xmloff/attrlist.hxx>
26 #include <xmloff/xmlprmap.hxx>
27 #include <xmloff/xmlexppr.hxx>
28 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
31 #include <com/sun/star/style/XStyle.hpp>
32 #include <com/sun/star/container/XNameContainer.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/XPropertyState.hpp>
35 #include <com/sun/star/document/XEventsSupplier.hpp>
36 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
37 #include <xmloff/xmlaustp.hxx>
38 #include <xmloff/styleexp.hxx>
39 #include <xmloff/xmlexp.hxx>
40 #include <xmloff/XMLEventExport.hxx>
42 #include <boost/scoped_ptr.hpp>
44 using namespace ::com::sun::star
;
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::style
;
47 using namespace ::com::sun::star::container
;
48 using namespace ::com::sun::star::beans
;
49 using namespace ::com::sun::star::text
;
50 using namespace ::xmloff::token
;
52 using ::com::sun::star::document::XEventsSupplier
;
54 XMLStyleExport::XMLStyleExport(
56 const OUString
& rPoolStyleName
,
57 SvXMLAutoStylePoolP
*pAutoStyleP
) :
59 sIsPhysical( "IsPhysical" ),
60 sIsAutoUpdate( "IsAutoUpdate" ),
61 sFollowStyle( "FollowStyle" ),
62 sNumberingStyleName( "NumberingStyleName" ),
63 sOutlineLevel( "OutlineLevel" ),
64 sPoolStyleName( rPoolStyleName
),
65 pAutoStylePool( pAutoStyleP
)
69 XMLStyleExport::~XMLStyleExport()
73 void XMLStyleExport::exportStyleAttributes( const Reference
< XStyle
>& )
77 void XMLStyleExport::exportStyleContent( const Reference
< XStyle
>& )
81 sal_Bool
XMLStyleExport::exportStyle(
82 const Reference
< XStyle
>& rStyle
,
83 const OUString
& rXMLFamily
,
84 const UniReference
< SvXMLExportPropertyMapper
>& rPropMapper
,
85 const Reference
< XNameAccess
>& xStyles
,
86 const OUString
* pPrefix
)
88 Reference
< XPropertySet
> xPropSet( rStyle
, UNO_QUERY
);
89 Reference
< XPropertySetInfo
> xPropSetInfo
=
90 xPropSet
->getPropertySetInfo();
93 // Don't export styles that aren't existing really. This may be the
94 // case for StarOffice Writer's pool styles.
95 if( xPropSetInfo
->hasPropertyByName( sIsPhysical
) )
97 aAny
= xPropSet
->getPropertyValue( sIsPhysical
);
98 if( !*(sal_Bool
*)aAny
.getValue() )
103 GetExport().CheckAttrList();
110 sName
+= rStyle
->getName();
112 sal_Bool bEncoded
= sal_False
;
113 const OUString
sEncodedStyleName(GetExport().EncodeStyleName( sName
, &bEncoded
));
114 GetExport().AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
, sEncodedStyleName
);
117 GetExport().AddAttribute( XML_NAMESPACE_STYLE
, XML_DISPLAY_NAME
,
120 // style:family="..."
121 if( !rXMLFamily
.isEmpty() )
122 GetExport().AddAttribute( XML_NAMESPACE_STYLE
, XML_FAMILY
, rXMLFamily
);
124 if ( xPropSetInfo
->hasPropertyByName( "Hidden" ) )
126 aAny
= xPropSet
->getPropertyValue( "Hidden" );
127 sal_Bool bHidden
= sal_False
;
128 if ( ( aAny
>>= bHidden
) && bHidden
&& GetExport( ).getDefaultVersion( ) == SvtSaveOptions::ODFVER_LATEST
)
129 GetExport( ).AddAttribute( XML_NAMESPACE_STYLE
, XML_HIDDEN
, "true" );
132 // style:parent-style-name="..."
133 OUString
sParentString(rStyle
->getParentStyle());
136 if(!sParentString
.isEmpty())
140 sParent
+= sParentString
;
143 sParent
= sPoolStyleName
;
145 if( !sParent
.isEmpty() )
146 GetExport().AddAttribute( XML_NAMESPACE_STYLE
, XML_PARENT_STYLE_NAME
,
147 GetExport().EncodeStyleName( sParent
) );
149 // style:next-style-name="..." (paragraph styles only)
150 if( xPropSetInfo
->hasPropertyByName( sFollowStyle
) )
152 aAny
= xPropSet
->getPropertyValue( sFollowStyle
);
155 if( sName
!= sNextName
)
157 GetExport().AddAttribute( XML_NAMESPACE_STYLE
, XML_NEXT_STYLE_NAME
,
158 GetExport().EncodeStyleName( sNextName
) );
162 // style:auto-update="..." (SW only)
163 if( xPropSetInfo
->hasPropertyByName( sIsAutoUpdate
) )
165 aAny
= xPropSet
->getPropertyValue( sIsAutoUpdate
);
166 if( *(sal_Bool
*)aAny
.getValue() )
167 GetExport().AddAttribute( XML_NAMESPACE_STYLE
, XML_AUTO_UPDATE
,
171 // style:default-outline-level"..."
172 sal_Int32 nOutlineLevel
= 0;
173 if( xPropSetInfo
->hasPropertyByName( sOutlineLevel
) )
175 Reference
< XPropertyState
> xPropState( xPropSet
, uno::UNO_QUERY
);
176 if( PropertyState_DIRECT_VALUE
== xPropState
->getPropertyState( sOutlineLevel
) )
178 aAny
= xPropSet
->getPropertyValue( sOutlineLevel
);
179 aAny
>>= nOutlineLevel
;
180 if( nOutlineLevel
> 0 )
183 sTmp
.append( static_cast<sal_Int32
>(nOutlineLevel
));
184 GetExport().AddAttribute( XML_NAMESPACE_STYLE
,
185 XML_DEFAULT_OUTLINE_LEVEL
,
186 sTmp
.makeStringAndClear() );
190 /* Empty value for style:default-outline-level does exist
191 since ODF 1.2. Thus, suppress its export for former versions. (#i104889#)
193 if ( ( GetExport().getExportFlags() & EXPORT_OASIS
) != 0 &&
194 GetExport().getDefaultVersion() >= SvtSaveOptions::ODFVER_012
)
196 GetExport().AddAttribute( XML_NAMESPACE_STYLE
,
197 XML_DEFAULT_OUTLINE_LEVEL
,
204 // style:list-style-name="..." (SW paragarph styles only)
205 if( xPropSetInfo
->hasPropertyByName( sNumberingStyleName
) )
207 Reference
< XPropertyState
> xPropState( xPropSet
, uno::UNO_QUERY
);
208 if( PropertyState_DIRECT_VALUE
==
209 xPropState
->getPropertyState( sNumberingStyleName
) )
211 aAny
= xPropSet
->getPropertyValue( sNumberingStyleName
);
212 if( aAny
.hasValue() )
217 /* An direct set empty list style has to be written. Otherwise,
218 this information is lost and causes an error, if the parent
219 style has a list style set. (#i69523#)
221 if ( sListName
.isEmpty() )
223 GetExport().AddAttribute( XML_NAMESPACE_STYLE
,
225 sListName
/* empty string */);
229 // Written OpenDocument file format doesn't fit to the created text document (#i69627#)
230 bool bSuppressListStyle( false );
232 if ( !GetExport().writeOutlineStyleAsNormalListStyle() )
234 Reference
< XChapterNumberingSupplier
> xCNSupplier
235 (GetExport().GetModel(), UNO_QUERY
);
237 OUString sOutlineName
;
238 if (xCNSupplier
.is())
240 Reference
< XIndexReplace
> xNumRule
241 ( xCNSupplier
->getChapterNumberingRules() );
242 DBG_ASSERT( xNumRule
.is(), "no chapter numbering rules" );
246 Reference
< XPropertySet
> xNumRulePropSet
247 (xNumRule
, UNO_QUERY
);
248 xNumRulePropSet
->getPropertyValue(
251 bSuppressListStyle
= ( sListName
== sOutlineName
);
257 if ( !sListName
.isEmpty() && !bSuppressListStyle
)
259 GetExport().AddAttribute( XML_NAMESPACE_STYLE
,
261 GetExport().EncodeStyleName( sListName
) );
266 else if( nOutlineLevel
> 0 )
269 bool bNoInheritedListStyle( true );
271 /////////////////////////////////////////////////
272 Reference
<XStyle
> xStyle( xPropState
, UNO_QUERY
);
273 while ( xStyle
.is() )
275 OUString
aParentStyle( xStyle
->getParentStyle() );
276 if ( aParentStyle
.isEmpty() || !xStyles
->hasByName( aParentStyle
) )
282 xPropState
= Reference
< XPropertyState
>( xStyles
->getByName( aParentStyle
), UNO_QUERY
);
283 if ( !xPropState
.is() )
287 if ( xPropState
->getPropertyState( sNumberingStyleName
) == PropertyState_DIRECT_VALUE
)
289 bNoInheritedListStyle
= false;
294 xStyle
= Reference
<XStyle
>( xPropState
, UNO_QUERY
);
298 /////////////////////////////////////////////////
299 if ( bNoInheritedListStyle
)
300 GetExport().AddAttribute( XML_NAMESPACE_STYLE
,
306 // style:pool-id="..." is not required any longer since we use
307 // english style names only
308 exportStyleAttributes( rStyle
);
310 // TODO: style:help-file-name="..." and style:help-id="..." can neither
311 // be modified by UI nor by API and that for, have not to be exported
316 SvXMLElementExport
aElem( GetExport(), XML_NAMESPACE_STYLE
, XML_STYLE
,
317 sal_True
, sal_True
);
319 rPropMapper
->SetStyleName( sName
);
321 // <style:properties>
322 ::std::vector
< XMLPropertyState
> xPropStates
=
323 rPropMapper
->Filter( xPropSet
, true );
324 rPropMapper
->exportXML( GetExport(), xPropStates
,
325 XML_EXPORT_FLAG_IGN_WS
);
327 rPropMapper
->SetStyleName( OUString() );
329 exportStyleContent( rStyle
);
331 // <script:events>, if they are supported by this style
332 Reference
<XEventsSupplier
> xEventsSupp(rStyle
, UNO_QUERY
);
333 GetExport().GetEventExport().Export(xEventsSupp
);
338 sal_Bool
XMLStyleExport::exportDefaultStyle(
339 const Reference
< XPropertySet
>& xPropSet
,
340 const OUString
& rXMLFamily
,
341 const UniReference
< SvXMLExportPropertyMapper
>& rPropMapper
)
343 Reference
< XPropertySetInfo
> xPropSetInfo
=
344 xPropSet
->getPropertySetInfo();
348 // <style:default-style ...>
349 GetExport().CheckAttrList();
352 // style:family="..."
353 if( !rXMLFamily
.isEmpty() )
354 GetExport().AddAttribute( XML_NAMESPACE_STYLE
, XML_FAMILY
,
357 SvXMLElementExport
aElem( GetExport(), XML_NAMESPACE_STYLE
,
359 sal_True
, sal_True
);
360 // <style:properties>
361 ::std::vector
< XMLPropertyState
> xPropStates
=
362 rPropMapper
->FilterDefaults( xPropSet
);
363 rPropMapper
->exportXML( GetExport(), xPropStates
,
364 XML_EXPORT_FLAG_IGN_WS
);
369 void XMLStyleExport::exportStyleFamily(
370 const sal_Char
*pFamily
,
371 const OUString
& rXMLFamily
,
372 const UniReference
< SvXMLExportPropertyMapper
>& rPropMapper
,
373 sal_Bool bUsed
, sal_uInt16 nFamily
, const OUString
* pPrefix
)
375 const OUString
sFamily(OUString::createFromAscii(pFamily
));
376 exportStyleFamily( sFamily
, rXMLFamily
, rPropMapper
, bUsed
, nFamily
,
380 void XMLStyleExport::exportStyleFamily(
381 const OUString
& rFamily
, const OUString
& rXMLFamily
,
382 const UniReference
< SvXMLExportPropertyMapper
>& rPropMapper
,
383 sal_Bool bUsed
, sal_uInt16 nFamily
, const OUString
* pPrefix
)
385 DBG_ASSERT( GetExport().GetModel().is(), "There is the model?" );
386 Reference
< XStyleFamiliesSupplier
> xFamiliesSupp( GetExport().GetModel(), UNO_QUERY
);
387 if( !xFamiliesSupp
.is() )
388 return; // family not available in current model
390 Reference
< XNameAccess
> xStyleCont
;
392 Reference
< XNameAccess
> xFamilies( xFamiliesSupp
->getStyleFamilies() );
393 if( xFamilies
->hasByName( rFamily
) )
394 xFamilies
->getByName( rFamily
) >>= xStyleCont
;
396 if( !xStyleCont
.is() )
399 Reference
< XNameAccess
> xStyles( xStyleCont
, UNO_QUERY
);
400 // If next styles are supported and used styles should be exported only,
401 // the next style may be unused but has to be exported, too. In this case
402 // the names of all exported styles are remembered.
403 boost::scoped_ptr
<std::set
<OUString
> > pExportedStyles(0);
404 sal_Bool bFirstStyle
= sal_True
;
406 const uno::Sequence
< OUString
> aSeq
= xStyles
->getElementNames();
407 const OUString
* pIter
= aSeq
.getConstArray();
408 const OUString
* pEnd
= pIter
+ aSeq
.getLength();
409 for(;pIter
!= pEnd
;++pIter
)
411 Reference
< XStyle
> xStyle
;
414 xStyles
->getByName( *pIter
) >>= xStyle
;
416 catch(const lang::IndexOutOfBoundsException
&)
418 // due to bugs in prior versions it is possible that
419 // a binary file is missing some critical styles.
420 // The only possible way to deal with this is to
421 // not export them here and remain silent.
425 DBG_ASSERT( xStyle
.is(), "Style not found for export!" );
428 if( !bUsed
|| xStyle
->isInUse() )
430 sal_Bool bExported
= exportStyle( xStyle
, rXMLFamily
, rPropMapper
,
432 if( bUsed
&& bFirstStyle
&& bExported
)
434 // If this is the first style, find out whether next styles
436 Reference
< XPropertySet
> xPropSet( xStyle
, UNO_QUERY
);
437 Reference
< XPropertySetInfo
> xPropSetInfo
=
438 xPropSet
->getPropertySetInfo();
440 if( xPropSetInfo
->hasPropertyByName( sFollowStyle
) )
441 pExportedStyles
.reset(new std::set
<OUString
>());
442 bFirstStyle
= sal_False
;
445 if( pExportedStyles
&& bExported
)
447 // If next styles are supported, remember this style's name.
448 pExportedStyles
->insert( xStyle
->getName() );
452 // if an auto style pool is given, remember this style's name as a
453 // style name that must not be used by automatic styles.
455 pAutoStylePool
->RegisterName( nFamily
, xStyle
->getName() );
459 if( pExportedStyles
)
461 // if next styles are supported, export all next styles that are
462 // unused and that for, haven't been exported in the first loop.
463 pIter
= aSeq
.getConstArray();
464 for(;pIter
!= pEnd
;++pIter
)
466 Reference
< XStyle
> xStyle
;
467 xStyles
->getByName( *pIter
) >>= xStyle
;
469 DBG_ASSERT( xStyle
.is(), "Style not found for export!" );
472 Reference
< XPropertySet
> xPropSet( xStyle
, UNO_QUERY
);
473 Reference
< XPropertySetInfo
> xPropSetInfo( xPropSet
->getPropertySetInfo() );
475 // styles that aren't existing realy are ignored.
476 if( xPropSetInfo
->hasPropertyByName( sIsPhysical
) )
478 Any
aAny( xPropSet
->getPropertyValue( sIsPhysical
) );
479 if( !*(sal_Bool
*)aAny
.getValue() )
483 if( !xStyle
->isInUse() )
486 if( !xPropSetInfo
->hasPropertyByName( sFollowStyle
) )
488 DBG_ASSERT( sFollowStyle
.isEmpty(), "no follow style???" );
493 xPropSet
->getPropertyValue( sFollowStyle
) >>= sNextName
;
494 OUString
sTmp( sNextName
);
495 // if the next style hasn't been exported by now, export it now
496 // and remember its name.
497 if( xStyle
->getName() != sNextName
&&
498 0 == pExportedStyles
->count( sTmp
) )
500 xStyleCont
->getByName( sNextName
) >>= xStyle
;
501 DBG_ASSERT( xStyle
.is(), "Style not found for export!" );
503 if( xStyle
.is() && exportStyle( xStyle
, rXMLFamily
, rPropMapper
, xStyles
,pPrefix
) )
504 pExportedStyles
->insert( sTmp
);
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */