bump product version to 5.0.4.1
[LibreOffice.git] / xmloff / source / text / txtstyli.cxx
blob9779fe61700ac31d620b3c51520a911d7ecf56c4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include "XMLTextPropertySetContext.hxx"
22 #include <xmloff/xmlnmspe.hxx>
23 #include <xmloff/XMLEventsImportContext.hxx>
24 #include <xmloff/attrlist.hxx>
25 #include <xmloff/families.hxx>
26 #include <xmloff/txtprmap.hxx>
27 #include <xmloff/txtstyli.hxx>
28 #include <xmloff/xmlimp.hxx>
29 #include <xmloff/xmltkmap.hxx>
30 #include <xmloff/xmltoken.hxx>
31 #include <xmloff/xmluconv.hxx>
32 #include <xmloff/maptype.hxx>
34 #include <com/sun/star/beans/XMultiPropertySet.hpp>
35 #include <com/sun/star/container/XNameContainer.hpp>
36 #include <com/sun/star/document/XEventsSupplier.hpp>
37 #include <com/sun/star/frame/XModel.hpp>
38 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
39 #include <com/sun/star/style/ParagraphStyleCategory.hpp>
40 #include <com/sun/star/style/XStyle.hpp>
42 #include <sax/tools/converter.hxx>
44 #include <tools/debug.hxx>
45 #include <tools/diagnose_ex.h>
47 #include <algorithm>
48 #include <functional>
49 #include <utility>
50 #include <vector>
52 //UUUU
53 #include <xmlsdtypes.hxx>
54 #include <xmloff/xmlerror.hxx>
57 using namespace ::std;
58 using namespace ::com::sun::star;
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::xml::sax;
61 using namespace ::com::sun::star::style;
62 using namespace ::com::sun::star::frame;
63 using namespace ::com::sun::star::beans;
64 using namespace ::com::sun::star::lang;
65 using namespace ::com::sun::star::container;
66 using namespace ::xmloff::token;
68 static const SvXMLEnumMapEntry aCategoryMap[] =
70 { XML_TEXT, ParagraphStyleCategory::TEXT },
71 { XML_CHAPTER, ParagraphStyleCategory::CHAPTER },
72 { XML_LIST, ParagraphStyleCategory::LIST },
73 { XML_INDEX, ParagraphStyleCategory::INDEX },
74 { XML_EXTRA, ParagraphStyleCategory::EXTRA },
75 { XML_HTML, ParagraphStyleCategory::HTML },
76 { XML_TOKEN_INVALID, 0 }
79 void XMLTextStyleContext::SetAttribute( sal_uInt16 nPrefixKey,
80 const OUString& rLocalName,
81 const OUString& rValue )
83 if( XML_NAMESPACE_STYLE == nPrefixKey )
85 // TODO: use a map here
86 if( IsXMLToken( rLocalName, XML_AUTO_UPDATE ) )
88 if( IsXMLToken( rValue, XML_TRUE ) )
89 bAutoUpdate = true;
91 else if( IsXMLToken( rLocalName, XML_LIST_STYLE_NAME ) )
93 sListStyleName = rValue;
94 // Inherited paragraph style lost information about unset numbering (#i69523#)
95 mbListStyleSet = true;
97 else if( IsXMLToken( rLocalName, XML_MASTER_PAGE_NAME ) )
99 sMasterPageName = rValue;
100 bHasMasterPageName = true;
102 else if( IsXMLToken( rLocalName, XML_DATA_STYLE_NAME ) )
104 sDataStyleName = rValue;
106 else if( IsXMLToken( rLocalName, XML_CLASS ) )
108 sCategoryVal = rValue;
110 else if( IsXMLToken( rLocalName, XML_DEFAULT_OUTLINE_LEVEL ) )
112 sal_Int32 nTmp;
113 if (::sax::Converter::convertNumber( nTmp, rValue ) &&
114 0 <= nTmp && nTmp <= 10 )
115 nOutlineLevel = static_cast< sal_Int8 >( nTmp );
117 else
119 XMLPropStyleContext::SetAttribute( nPrefixKey, rLocalName, rValue );
122 else
124 XMLPropStyleContext::SetAttribute( nPrefixKey, rLocalName, rValue );
128 TYPEINIT1( XMLTextStyleContext, XMLPropStyleContext );
130 XMLTextStyleContext::XMLTextStyleContext( SvXMLImport& rImport,
131 sal_uInt16 nPrfx, const OUString& rLName,
132 const Reference< XAttributeList > & xAttrList,
133 SvXMLStylesContext& rStyles, sal_uInt16 nFamily,
134 bool bDefaultStyle )
135 : XMLPropStyleContext( rImport, nPrfx, rLName, xAttrList, rStyles, nFamily, bDefaultStyle )
136 , sIsAutoUpdate( "IsAutoUpdate" )
137 , sCategory( "Category" )
138 , sNumberingStyleName( "NumberingStyleName" )
139 , sOutlineLevel("OutlineLevel" )
140 , sDropCapCharStyleName( "DropCapCharStyleName" )
141 , sPageDescName( "PageDescName" )
142 , nOutlineLevel( -1 )
143 , bAutoUpdate( false )
144 , bHasMasterPageName( false )
145 , bHasCombinedCharactersLetter( false )
146 // Inherited paragraph style lost information about unset numbering (#i69523#)
147 , mbListStyleSet( false )
148 , pEventContext( NULL )
152 XMLTextStyleContext::~XMLTextStyleContext()
156 SvXMLImportContext *XMLTextStyleContext::CreateChildContext(
157 sal_uInt16 nPrefix,
158 const OUString& rLocalName,
159 const Reference< XAttributeList > & xAttrList )
161 SvXMLImportContext *pContext = 0;
163 if( XML_NAMESPACE_STYLE == nPrefix )
165 sal_uInt32 nFamily = 0;
166 if( IsXMLToken( rLocalName, XML_TEXT_PROPERTIES ) )
167 nFamily = XML_TYPE_PROP_TEXT;
168 else if( IsXMLToken( rLocalName, XML_PARAGRAPH_PROPERTIES ) )
169 nFamily = XML_TYPE_PROP_PARAGRAPH;
170 else if( IsXMLToken( rLocalName, XML_SECTION_PROPERTIES ) )
171 nFamily = XML_TYPE_PROP_SECTION;
172 else if( IsDefaultStyle() && IsXMLToken( rLocalName, XML_TABLE_PROPERTIES ) )
173 nFamily = XML_TYPE_PROP_TABLE;
174 else if( IsDefaultStyle() && IsXMLToken( rLocalName, XML_TABLE_ROW_PROPERTIES ) )
175 nFamily = XML_TYPE_PROP_TABLE_ROW;
176 if( nFamily )
178 rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap =
179 GetStyles()->GetImportPropertyMapper( GetFamily() );
180 if( xImpPrMap.is() )
181 pContext = new XMLTextPropertySetContext( GetImport(), nPrefix,
182 rLocalName, xAttrList,
183 nFamily,
184 GetProperties(),
185 xImpPrMap,
186 sDropCapTextStyleName );
189 else if ( (XML_NAMESPACE_OFFICE == nPrefix) &&
190 IsXMLToken( rLocalName, XML_EVENT_LISTENERS ) )
192 // create and remember events import context
193 // (for delayed processing of events)
194 pEventContext = new XMLEventsImportContext( GetImport(), nPrefix,
195 rLocalName);
196 pEventContext->AddFirstRef();
197 pContext = pEventContext;
200 if( !pContext )
201 pContext = XMLPropStyleContext::CreateChildContext( nPrefix, rLocalName,
202 xAttrList );
204 return pContext;
207 void XMLTextStyleContext::CreateAndInsert( bool bOverwrite )
209 XMLPropStyleContext::CreateAndInsert( bOverwrite );
210 Reference < XStyle > xStyle = GetStyle();
211 if( !xStyle.is() || !(bOverwrite || IsNew()) )
212 return;
214 Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY );
215 Reference< XPropertySetInfo > xPropSetInfo =
216 xPropSet->getPropertySetInfo();
217 if( xPropSetInfo->hasPropertyByName( sIsAutoUpdate ) )
219 Any aAny;
220 sal_Bool bTmp = bAutoUpdate;
221 aAny.setValue( &bTmp, cppu::UnoType<bool>::get() );
222 xPropSet->setPropertyValue( sIsAutoUpdate, aAny );
225 sal_uInt16 nCategory = ParagraphStyleCategory::TEXT;
226 if( XML_STYLE_FAMILY_TEXT_PARAGRAPH == GetFamily() &&
227 !sCategoryVal.isEmpty() && xStyle->isUserDefined() &&
228 xPropSetInfo->hasPropertyByName( sCategory ) &&
229 SvXMLUnitConverter::convertEnum( nCategory, sCategoryVal, aCategoryMap ) )
231 Any aAny;
232 aAny <<= (sal_Int16)nCategory;
233 xPropSet->setPropertyValue( sCategory, aAny );
236 // tell the style about it's events (if applicable)
237 if (NULL != pEventContext)
239 // set event suppplier and release reference to context
240 Reference<document::XEventsSupplier> xEventsSupplier(xStyle,UNO_QUERY);
241 pEventContext->SetEvents(xEventsSupplier);
242 pEventContext->ReleaseRef();
245 // XML import: reconstrution of assignment of paragraph style to outline levels (#i69629#)
246 if ( nOutlineLevel > 0 )
248 GetImport().GetTextImport()->AddOutlineStyleCandidate( nOutlineLevel,
249 GetDisplayName() );
253 void XMLTextStyleContext::SetDefaults( )
255 if( ( GetFamily() == XML_STYLE_FAMILY_TEXT_PARAGRAPH ) ||
256 ( GetFamily() == XML_STYLE_FAMILY_TABLE_TABLE ) ||
257 ( GetFamily() == XML_STYLE_FAMILY_TABLE_ROW ) )
259 Reference < XMultiServiceFactory > xFactory ( GetImport().GetModel(), UNO_QUERY);
260 if (xFactory.is())
262 Reference < XInterface > xInt = xFactory->createInstance (
263 OUString ( "com.sun.star.text.Defaults" ) );
264 Reference < XPropertySet > xProperties ( xInt, UNO_QUERY );
265 if ( xProperties.is() )
266 FillPropertySet ( xProperties );
271 void XMLTextStyleContext::Finish( bool bOverwrite )
273 XMLPropStyleContext::Finish( bOverwrite );
275 Reference < XStyle > xStyle = GetStyle();
276 // Consider set empty list style (#i69523#)
277 if ( !( mbListStyleSet ||
278 nOutlineLevel >= 0 ||
279 !sDropCapTextStyleName.isEmpty() ||
280 bHasMasterPageName ) ||
281 !xStyle.is() ||
282 !( bOverwrite || IsNew() ) )
283 return;
285 Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY );
286 Reference< XPropertySetInfo > xPropSetInfo =
287 xPropSet->getPropertySetInfo();
289 if( xPropSetInfo->hasPropertyByName( sOutlineLevel ))
291 Any aAny;
292 if( nOutlineLevel >= 0 )
294 aAny <<= nOutlineLevel;
295 xPropSet->setPropertyValue( sOutlineLevel, aAny );
299 // Consider set empty list style (#i69523#)
300 if ( mbListStyleSet &&
301 xPropSetInfo->hasPropertyByName( sNumberingStyleName ) )
303 /* Only for text document from version prior OOo 2.1 resp. SO 8 PU5:
304 - Do not apply list style, if paragraph style has a default outline
305 level > 0 and thus, will be assigned to the corresponding list
306 level of the outline style. (#i70223#)
308 bool bApplyListStyle( true );
309 if ( nOutlineLevel > 0 )
311 if ( GetImport().IsTextDocInOOoFileFormat() )
313 bApplyListStyle = false;
315 else
317 sal_Int32 nUPD( 0 );
318 sal_Int32 nBuild( 0 );
319 // Check explicitly on certain versions (#i86058#)
320 if ( GetImport().getBuildIds( nUPD, nBuild ) &&
321 ( ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0
322 ( nUPD == 680 && nBuild <= 9073 ) ) ) // OOo 2.0 - OOo 2.0.4
324 bApplyListStyle = false;
329 if ( bApplyListStyle )
331 if ( sListStyleName.isEmpty() )
333 Any aAny;
334 aAny <<= sListStyleName /* empty string */;
335 xPropSet->setPropertyValue( sNumberingStyleName, aAny );
337 else
339 // change list style name to display name
340 OUString sDisplayListStyleName(
341 GetImport().GetStyleDisplayName( XML_STYLE_FAMILY_TEXT_LIST,
342 sListStyleName ) );
343 // The families container must exist
344 const Reference < XNameContainer >& rNumStyles =
345 GetImport().GetTextImport()->GetNumberingStyles();
346 // if( rNumStyles.is() && rNumStyles->hasByName( sDisplayListStyleName ) &&
347 // xPropSetInfo->hasPropertyByName( sNumberingStyleName ) )
348 if ( rNumStyles.is() &&
349 rNumStyles->hasByName( sDisplayListStyleName ) )
351 Any aAny;
352 aAny <<= sDisplayListStyleName;
353 xPropSet->setPropertyValue( sNumberingStyleName, aAny );
359 if( !sDropCapTextStyleName.isEmpty() )
361 // change list style name to display name
362 OUString sDisplayDropCapTextStyleName(
363 GetImport().GetStyleDisplayName( XML_STYLE_FAMILY_TEXT_TEXT,
364 sDropCapTextStyleName ) );
365 // The families cointaner must exist
366 const Reference < XNameContainer >& rTextStyles =
367 GetImport().GetTextImport()->GetTextStyles();
368 if( rTextStyles.is() &&
369 rTextStyles->hasByName( sDisplayDropCapTextStyleName ) &&
370 xPropSetInfo->hasPropertyByName( sDropCapCharStyleName ) )
372 Any aAny;
373 aAny <<= sDisplayDropCapTextStyleName;
374 xPropSet->setPropertyValue( sDropCapCharStyleName, aAny );
378 if( bHasMasterPageName )
380 OUString sDisplayName(
381 GetImport().GetStyleDisplayName(
382 XML_STYLE_FAMILY_MASTER_PAGE, sMasterPageName ) );
383 // The families cointaner must exist
384 const Reference < XNameContainer >& rPageStyles =
385 GetImport().GetTextImport()->GetPageStyles();
386 if( ( sDisplayName.isEmpty() ||
387 (rPageStyles.is() &&
388 rPageStyles->hasByName( sDisplayName )) ) &&
389 xPropSetInfo->hasPropertyByName( sPageDescName ) )
391 Any aAny;
392 aAny <<= sDisplayName;
393 xPropSet->setPropertyValue( sPageDescName, aAny );
398 void XMLTextStyleContext::FillPropertySet(
399 const Reference<XPropertySet > & rPropSet )
401 // imitate the FillPropertySet of the super class, so we get a chance to
402 // catch the combined characters attribute
404 // imitate XMLPropStyleContext::FillPropertySet(...)
405 SvXMLStylesContext* pSvXMLStylesContext = static_cast< SvXMLStylesContext* >(GetStyles());
406 rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = pSvXMLStylesContext->GetImportPropertyMapper(GetFamily());
407 DBG_ASSERT(xImpPrMap.is(),"Where is the import prop mapper?");
409 if(xImpPrMap.is())
411 // imitate SvXMLImportPropertyMapper::FillPropertySet(...)
412 // The reason for this is that we have no other way to
413 // efficiently intercept the value of combined characters. To
414 // get that value, we could iterate through the map once more,
415 // but instead we chose to insert the code into this
416 // iteration. I haven't been able to come up with a much more
417 // intelligent solution.
418 struct _ContextID_Index_Pair aContextIDs[] =
420 { CTF_COMBINED_CHARACTERS_FIELD, -1 },
421 { CTF_KEEP_TOGETHER, -1 },
422 { CTF_BORDER_MODEL, -1 },
423 { CTF_TEXT_DISPLAY, -1 },
424 { CTF_FONTFAMILYNAME, -1 },
425 { CTF_FONTFAMILYNAME_CJK, -1 },
426 { CTF_FONTFAMILYNAME_CTL, -1 },
428 //UUU need special handling for DrawingLayer FillStyle names
429 { CTF_FILLGRADIENTNAME, -1 },
430 { CTF_FILLTRANSNAME, -1 },
431 { CTF_FILLHATCHNAME, -1 },
432 { CTF_FILLBITMAPNAME, -1 },
434 { -1, -1 }
437 // the style families associated with the same index modulo 4
438 static sal_uInt16 aFamilies[] =
440 XML_STYLE_FAMILY_SD_GRADIENT_ID,
441 XML_STYLE_FAMILY_SD_GRADIENT_ID,
442 XML_STYLE_FAMILY_SD_HATCH_ID,
443 XML_STYLE_FAMILY_SD_FILL_IMAGE_ID
446 // get property set info
447 Reference< XPropertySetInfo > xInfo;
448 rtl::Reference< XMLPropertySetMapper > rPropMapper;
449 bool bAutomatic = false;
451 if(pSvXMLStylesContext->IsAutomaticStyle() &&
452 (XML_STYLE_FAMILY_TEXT_TEXT == GetFamily() || XML_STYLE_FAMILY_TEXT_PARAGRAPH == GetFamily()))
454 bAutomatic = true;
456 if( !GetAutoName().isEmpty() )
458 OUString sAutoProp = ( GetFamily() == XML_STYLE_FAMILY_TEXT_TEXT ) ?
459 OUString( "CharAutoStyleName" ):
460 OUString( "ParaAutoStyleName" );
464 if(!xInfo.is())
466 xInfo = rPropSet->getPropertySetInfo();
469 if ( xInfo->hasPropertyByName( sAutoProp ) )
471 rPropSet->setPropertyValue( sAutoProp, makeAny(GetAutoName()) );
473 else
475 bAutomatic = false;
478 catch( const RuntimeException& ) { throw; }
479 catch( const Exception& )
481 DBG_UNHANDLED_EXCEPTION();
482 bAutomatic = false;
487 if( bAutomatic )
489 xImpPrMap->CheckSpecialContext( GetProperties(), rPropSet, aContextIDs );
491 else
493 xImpPrMap->FillPropertySet( GetProperties(), rPropSet, aContextIDs );
496 sal_Int32 nIndex = aContextIDs[0].nIndex;
498 // have we found a combined characters
499 if ( nIndex != -1 )
501 Any& rAny = GetProperties()[nIndex].maValue;
502 bool bVal = *static_cast<sal_Bool const *>(rAny.getValue());
503 bHasCombinedCharactersLetter = bVal;
506 // keep-together: the application default is different from
507 // the file format default. Hence, if we always set this
508 // value; if we didn't find one, we'll set to false, the file
509 // format default.
510 // border-model: same
511 if(IsDefaultStyle() && XML_STYLE_FAMILY_TABLE_ROW == GetFamily())
513 OUString sIsSplitAllowed("IsSplitAllowed");
514 DBG_ASSERT( rPropSet->getPropertySetInfo()->hasPropertyByName( sIsSplitAllowed ), "property missing?" );
515 rPropSet->setPropertyValue(
516 sIsSplitAllowed,
517 (aContextIDs[1].nIndex == -1) ? makeAny( false ) : GetProperties()[aContextIDs[1].nIndex].maValue );
520 if(IsDefaultStyle() && XML_STYLE_FAMILY_TABLE_TABLE == GetFamily())
522 OUString sCollapsingBorders("CollapsingBorders");
523 DBG_ASSERT( rPropSet->getPropertySetInfo()->hasPropertyByName( sCollapsingBorders ), "property missing?" );
524 rPropSet->setPropertyValue(
525 sCollapsingBorders,
526 (aContextIDs[2].nIndex == -1)
527 ? makeAny( false )
528 : GetProperties()[aContextIDs[2].nIndex].maValue );
532 // iterate over aContextIDs entries, start with 3, prev ones are already used above
533 for(sal_uInt16 i(3); aContextIDs[i].nContextID != -1; i++)
535 nIndex = aContextIDs[i].nIndex;
537 if ( nIndex != -1 )
539 // Found!
540 struct XMLPropertyState& rState = GetProperties()[nIndex];
542 switch(aContextIDs[i].nContextID)
544 case CTF_FILLGRADIENTNAME:
545 case CTF_FILLTRANSNAME:
546 case CTF_FILLHATCHNAME:
547 case CTF_FILLBITMAPNAME:
549 // DrawingLayer FillStyle name needs to be mapped to DisplayName
550 rtl::OUString sStyleName;
551 rState.maValue >>= sStyleName;
553 //UUUU translate the used name from ODF intern to the name used in the Model
554 sStyleName = GetImport().GetStyleDisplayName(aFamilies[i - 7], sStyleName);
556 if(bAutomatic)
558 // in this case the rPropSet got not really filled since above the call to
559 // CheckSpecialContext was used and not FillPropertySet, thus the below call to
560 // setPropertyValue can fail/will not be useful (e.g. when the rPropSet
561 // is a SwXTextCursor).
562 // This happens for AutoStyles which are already filled in XMLPropStyleContext::CreateAndInsert,
563 // thus the whole mechanism based on _ContextID_Index_Pair will not work
564 // in that case. Thus the slots which need to be converted already get
565 // converted there (its called first) and not here (see
566 // translateNameBasedDrawingLayerFillStyleDefinitionsToStyleDisplayNames)
567 // For convenience, still Write back the corrected value to the XMLPropertyState entry
568 rState.maValue <<= sStyleName;
569 break;
572 // Still needed if it's not an AutomaticStyle (!)
575 if(!rPropMapper.is())
577 rPropMapper = xImpPrMap->getPropertySetMapper();
580 // set property
581 const rtl::OUString& rPropertyName = rPropMapper->GetEntryAPIName(rState.mnIndex);
583 if(!xInfo.is())
585 xInfo = rPropSet->getPropertySetInfo();
588 if(xInfo->hasPropertyByName(rPropertyName))
590 rPropSet->setPropertyValue(rPropertyName,Any(sStyleName));
593 catch(::com::sun::star::lang::IllegalArgumentException& e)
595 Sequence< rtl::OUString > aSeq(1);
596 aSeq[0] = sStyleName;
597 GetImport().SetError(XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, aSeq, e.Message, NULL);
599 break;
601 default:
603 // check for StarBats and StarMath fonts
604 Any rAny = rState.maValue;
605 sal_Int32 nMapperIndex = rState.mnIndex;
607 // Now check for font name in rState and set corrected value,
608 // if necessary.
609 OUString sFontName;
610 rAny >>= sFontName;
612 if ( !sFontName.isEmpty() )
614 if ( sFontName.equalsIgnoreAsciiCase( "StarBats" ) ||
615 sFontName.equalsIgnoreAsciiCase( "StarMath" ) )
617 // construct new value
618 sFontName = "StarSymbol";
619 Any aAny(rAny);
620 aAny <<= sFontName;
622 if(!rPropMapper.is())
624 rPropMapper = xImpPrMap->getPropertySetMapper();
627 // set property
628 OUString rPropertyName(rPropMapper->GetEntryAPIName(nMapperIndex));
630 if(!xInfo.is())
632 xInfo = rPropSet->getPropertySetInfo();
635 if(xInfo->hasPropertyByName(rPropertyName))
637 rPropSet->setPropertyValue(rPropertyName,aAny);
640 // else: "normal" style name -> no correction is necessary
642 // else: no style name found -> illegal value -> ignore
650 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */