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 <drawingml/textparagraphproperties.hxx>
22 #include <com/sun/star/text/XNumberingRulesSupplier.hpp>
23 #include <com/sun/star/container/XIndexReplace.hpp>
24 #include <com/sun/star/text/HoriOrientation.hpp>
25 #include <com/sun/star/awt/FontDescriptor.hpp>
26 #include <com/sun/star/awt/FontWeight.hpp>
27 #include <com/sun/star/awt/XBitmap.hpp>
28 #include <com/sun/star/graphic/XGraphic.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/style/NumberingType.hpp>
31 #include <com/sun/star/style/TabStop.hpp>
32 #include <com/sun/star/style/ParagraphAdjust.hpp>
33 #include <com/sun/star/drawing/XDrawPage.hpp>
35 #include <osl/diagnose.h>
37 #include <oox/helper/propertyset.hxx>
38 #include <oox/core/xmlfilterbase.hxx>
39 #include <oox/token/properties.hxx>
40 #include <oox/token/tokens.hxx>
42 #if OSL_DEBUG_LEVEL > 0
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <com/sun/star/text/XText.hpp>
45 #include <com/sun/star/drawing/XShape.hpp>
46 #include <oox/ppt/pptimport.hxx>
47 #include <oox/ppt/slidepersist.hxx>
50 using namespace ::oox::core
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star::beans
;
53 using namespace ::com::sun::star::style
;
54 using namespace ::com::sun::star::text
;
55 using namespace ::com::sun::star::container
;
56 using ::com::sun::star::awt::FontDescriptor
;
58 namespace oox::drawingml
{
60 BulletList::BulletList( )
61 : maBulletColorPtr( std::make_shared
<Color
>() ),
62 mbBulletColorFollowText ( false ),
63 mbBulletFontFollowText ( false ),
64 mbBulletSizeFollowText ( false )
68 bool BulletList::is() const
70 return mnNumberingType
.hasValue();
73 void BulletList::setBulletChar( const OUString
& sChar
)
75 mnNumberingType
<<= NumberingType::CHAR_SPECIAL
;
76 msBulletChar
<<= sChar
;
79 void BulletList::setGraphic( css::uno::Reference
< css::graphic::XGraphic
> const & rXGraphic
)
81 mnNumberingType
<<= NumberingType::BITMAP
;
82 maGraphic
<<= rXGraphic
;
85 void BulletList::setNone( )
87 mnNumberingType
<<= NumberingType::NUMBER_NONE
;
90 void BulletList::setSuffixParenBoth()
92 msNumberingSuffix
<<= OUString( ")" );
93 msNumberingPrefix
<<= OUString( "(" );
96 void BulletList::setSuffixParenRight()
98 msNumberingSuffix
<<= OUString( ")" );
99 msNumberingPrefix
<<= OUString();
102 void BulletList::setSuffixPeriod()
104 msNumberingSuffix
<<= OUString( "." );
105 msNumberingPrefix
<<= OUString();
108 void BulletList::setSuffixNone()
110 msNumberingSuffix
<<= OUString();
111 msNumberingPrefix
<<= OUString();
114 void BulletList::setSuffixMinusRight()
116 msNumberingSuffix
<<= OUString( "-" );
117 msNumberingPrefix
<<= OUString();
120 void BulletList::setType( sal_Int32 nType
)
122 OSL_ASSERT((nType
& sal_Int32(0xFFFF0000))==0);
125 case XML_alphaLcParenBoth
:
126 mnNumberingType
<<= NumberingType::CHARS_LOWER_LETTER
;
127 setSuffixParenBoth();
129 case XML_alphaLcParenR
:
130 mnNumberingType
<<= NumberingType::CHARS_LOWER_LETTER
;
131 setSuffixParenRight();
133 case XML_alphaLcPeriod
:
134 mnNumberingType
<<= NumberingType::CHARS_LOWER_LETTER
;
137 case XML_alphaUcParenBoth
:
138 mnNumberingType
<<= NumberingType::CHARS_UPPER_LETTER
;
139 setSuffixParenBoth();
141 case XML_alphaUcParenR
:
142 mnNumberingType
<<= NumberingType::CHARS_UPPER_LETTER
;
143 setSuffixParenRight();
145 case XML_alphaUcPeriod
:
146 mnNumberingType
<<= NumberingType::CHARS_UPPER_LETTER
;
149 case XML_arabic1Minus
:
150 case XML_arabic2Minus
:
151 case XML_arabicDbPeriod
:
152 case XML_arabicDbPlain
:
155 case XML_arabicParenBoth
:
156 mnNumberingType
<<= NumberingType::ARABIC
;
157 setSuffixParenBoth();
159 case XML_arabicParenR
:
160 mnNumberingType
<<= NumberingType::ARABIC
;
161 setSuffixParenRight();
163 case XML_arabicPeriod
:
164 mnNumberingType
<<= NumberingType::ARABIC
;
167 case XML_arabicPlain
:
168 mnNumberingType
<<= NumberingType::ARABIC
;
171 case XML_circleNumDbPlain
:
172 case XML_circleNumWdBlackPlain
:
173 case XML_circleNumWdWhitePlain
:
174 mnNumberingType
<<= NumberingType::CIRCLE_NUMBER
;
176 case XML_ea1ChsPeriod
:
177 mnNumberingType
<<= NumberingType::NUMBER_UPPER_ZH
;
180 case XML_ea1ChsPlain
:
181 mnNumberingType
<<= NumberingType::NUMBER_UPPER_ZH
;
184 case XML_ea1ChtPeriod
:
185 mnNumberingType
<<= NumberingType::NUMBER_UPPER_ZH_TW
;
188 case XML_ea1ChtPlain
:
189 mnNumberingType
<<= NumberingType::NUMBER_UPPER_ZH_TW
;
192 case XML_ea1JpnChsDbPeriod
:
193 case XML_ea1JpnKorPeriod
:
194 case XML_ea1JpnKorPlain
:
196 case XML_hebrew2Minus
:
197 mnNumberingType
<<= NumberingType::CHARS_HEBREW
;
198 setSuffixMinusRight();
200 case XML_hindiAlpha1Period
:
201 case XML_hindiAlphaPeriod
:
202 case XML_hindiNumParenR
:
203 case XML_hindiNumPeriod
:
206 case XML_romanLcParenBoth
:
207 mnNumberingType
<<= NumberingType::ROMAN_LOWER
;
208 setSuffixParenBoth();
210 case XML_romanLcParenR
:
211 mnNumberingType
<<= NumberingType::ROMAN_LOWER
;
212 setSuffixParenRight();
214 case XML_romanLcPeriod
:
215 mnNumberingType
<<= NumberingType::ROMAN_LOWER
;
218 case XML_romanUcParenBoth
:
219 mnNumberingType
<<= NumberingType::ROMAN_UPPER
;
220 setSuffixParenBoth();
222 case XML_romanUcParenR
:
223 mnNumberingType
<<= NumberingType::ROMAN_UPPER
;
224 setSuffixParenRight();
226 case XML_romanUcPeriod
:
227 mnNumberingType
<<= NumberingType::ROMAN_UPPER
;
230 case XML_thaiAlphaParenBoth
:
231 case XML_thaiNumParenBoth
:
232 mnNumberingType
<<= NumberingType::CHARS_THAI
;
233 setSuffixParenBoth();
235 case XML_thaiAlphaParenR
:
236 case XML_thaiNumParenR
:
237 mnNumberingType
<<= NumberingType::CHARS_THAI
;
238 setSuffixParenRight();
240 case XML_thaiAlphaPeriod
:
241 case XML_thaiNumPeriod
:
242 mnNumberingType
<<= NumberingType::CHARS_THAI
;
248 void BulletList::setBulletSize(sal_Int16 nSize
)
253 void BulletList::setBulletAspectRatio(double nAspectRatio
)
255 mnAspectRatio
<<= nAspectRatio
;
258 void BulletList::setFontSize(sal_Int16 nSize
)
260 mnFontSize
<<= nSize
;
263 void BulletList::apply( const BulletList
& rSource
)
265 if ( rSource
.maBulletColorPtr
->isUsed() )
266 maBulletColorPtr
= rSource
.maBulletColorPtr
;
267 if ( rSource
.mbBulletColorFollowText
.hasValue() )
268 mbBulletColorFollowText
= rSource
.mbBulletColorFollowText
;
269 if ( rSource
.mbBulletFontFollowText
.hasValue() )
270 mbBulletFontFollowText
= rSource
.mbBulletFontFollowText
;
271 if ( rSource
.mbBulletSizeFollowText
.hasValue() )
272 mbBulletSizeFollowText
= rSource
.mbBulletSizeFollowText
;
273 maBulletFont
.assignIfUsed( rSource
.maBulletFont
);
274 if ( rSource
.msBulletChar
.hasValue() )
275 msBulletChar
= rSource
.msBulletChar
;
276 if ( rSource
.mnStartAt
.hasValue() )
277 mnStartAt
= rSource
.mnStartAt
;
278 if ( rSource
.mnNumberingType
.hasValue() )
279 mnNumberingType
= rSource
.mnNumberingType
;
280 if ( rSource
.msNumberingPrefix
.hasValue() )
281 msNumberingPrefix
= rSource
.msNumberingPrefix
;
282 if ( rSource
.msNumberingSuffix
.hasValue() )
283 msNumberingSuffix
= rSource
.msNumberingSuffix
;
284 if ( rSource
.mnSize
.hasValue() )
285 mnSize
= rSource
.mnSize
;
286 if ( rSource
.mnAspectRatio
.hasValue() )
287 mnAspectRatio
= rSource
.mnAspectRatio
;
288 if ( rSource
.mnFontSize
.hasValue() )
289 mnFontSize
= rSource
.mnFontSize
;
290 if ( rSource
.maStyleName
.hasValue() )
291 maStyleName
= rSource
.maStyleName
;
292 if ( rSource
.maGraphic
.hasValue() )
293 maGraphic
= rSource
.maGraphic
;
296 void BulletList::pushToPropMap( const ::oox::core::XmlFilterBase
* pFilterBase
, PropertyMap
& rPropMap
) const
298 if( msNumberingPrefix
.hasValue() )
299 rPropMap
.setAnyProperty( PROP_Prefix
, msNumberingPrefix
);
300 if( msNumberingSuffix
.hasValue() )
301 rPropMap
.setAnyProperty( PROP_Suffix
, msNumberingSuffix
);
302 if( mnStartAt
.hasValue() )
303 rPropMap
.setAnyProperty( PROP_StartWith
, mnStartAt
);
304 rPropMap
.setProperty( PROP_Adjust
, HoriOrientation::LEFT
);
306 if( mnNumberingType
.hasValue() )
307 rPropMap
.setAnyProperty( PROP_NumberingType
, mnNumberingType
);
309 OUString aBulletFontName
;
310 sal_Int16 nBulletFontPitch
= 0;
311 sal_Int16 nBulletFontFamily
= 0;
312 float nBulletFontWeight
= css::awt::FontWeight::NORMAL
;
313 bool bSymbolFont
= false;
315 bool bFollowTextFont
= false;
316 mbBulletFontFollowText
>>= bFollowTextFont
;
317 if (!bFollowTextFont
&& maBulletFont
.getFontData( aBulletFontName
, nBulletFontPitch
, nBulletFontFamily
, *pFilterBase
) )
319 FontDescriptor aFontDesc
;
320 sal_Int16 nFontSize
= 0;
321 if( mnFontSize
>>= nFontSize
)
322 aFontDesc
.Height
= nFontSize
;
324 // TODO move the to the TextFont struct.
325 aFontDesc
.Name
= aBulletFontName
;
326 aFontDesc
.Pitch
= nBulletFontPitch
;
327 aFontDesc
.Family
= nBulletFontFamily
;
328 aFontDesc
.Weight
= nBulletFontWeight
;
329 if ( aBulletFontName
.equalsIgnoreAsciiCase("Wingdings") ||
330 aBulletFontName
.equalsIgnoreAsciiCase("Wingdings 2") ||
331 aBulletFontName
.equalsIgnoreAsciiCase("Wingdings 3") ||
332 aBulletFontName
.equalsIgnoreAsciiCase("Monotype Sorts") ||
333 aBulletFontName
.equalsIgnoreAsciiCase("Monotype Sorts 2") ||
334 aBulletFontName
.equalsIgnoreAsciiCase("Webdings") ||
335 aBulletFontName
.equalsIgnoreAsciiCase("StarBats") ||
336 aBulletFontName
.equalsIgnoreAsciiCase("StarMath") ||
337 aBulletFontName
.equalsIgnoreAsciiCase("ZapfDingbats") ) {
338 aFontDesc
.CharSet
= RTL_TEXTENCODING_SYMBOL
;
341 rPropMap
.setProperty( PROP_BulletFont
, aFontDesc
);
342 rPropMap
.setProperty( PROP_BulletFontName
, aBulletFontName
);
345 if ( msBulletChar
.hasValue() ) {
348 msBulletChar
>>= sBuChar
;
350 if( pFilterBase
&& sBuChar
.getLength() == 1 && maBulletFont
.getFontData( aBulletFontName
, nBulletFontPitch
, nBulletFontFamily
, *pFilterBase
) && bSymbolFont
)
352 sal_Unicode nBuChar
= sBuChar
.toChar();
355 sBuChar
= OUString( &nBuChar
, 1 );
358 rPropMap
.setProperty( PROP_BulletChar
, sBuChar
);
360 if ( maGraphic
.hasValue() )
362 Reference
<css::awt::XBitmap
> xBitmap(maGraphic
, UNO_QUERY
);
364 rPropMap
.setProperty(PROP_GraphicBitmap
, xBitmap
);
366 bool bFollowTextSize
= false;
367 mbBulletSizeFollowText
>>= bFollowTextSize
;
368 if( !bFollowTextSize
&& mnSize
.hasValue() )
369 rPropMap
.setAnyProperty( PROP_BulletRelSize
, mnSize
);
370 if ( maStyleName
.hasValue() )
371 rPropMap
.setAnyProperty( PROP_CharStyleName
, maStyleName
);
373 bool bFollowTextColor
= false;
374 mbBulletColorFollowText
>>= bFollowTextColor
;
375 if ( maBulletColorPtr
->isUsed() && !bFollowTextColor
)
376 rPropMap
.setProperty( PROP_BulletColor
, maBulletColorPtr
->getColor( pFilterBase
->getGraphicHelper() ));
380 TextParagraphProperties::TextParagraphProperties()
385 void TextParagraphProperties::apply( const TextParagraphProperties
& rSourceProps
)
387 maTextParagraphPropertyMap
.assignAll( rSourceProps
.maTextParagraphPropertyMap
);
388 maBulletList
.apply( rSourceProps
.maBulletList
);
389 maTextCharacterProperties
.assignUsed( rSourceProps
.maTextCharacterProperties
);
390 if ( rSourceProps
.maParaTopMargin
.bHasValue
)
391 maParaTopMargin
= rSourceProps
.maParaTopMargin
;
392 if ( rSourceProps
.maParaBottomMargin
.bHasValue
)
393 maParaBottomMargin
= rSourceProps
.maParaBottomMargin
;
394 if ( rSourceProps
.moParaLeftMargin
)
395 moParaLeftMargin
= rSourceProps
.moParaLeftMargin
;
396 if ( rSourceProps
.moFirstLineIndentation
)
397 moFirstLineIndentation
= rSourceProps
.moFirstLineIndentation
;
398 if ( rSourceProps
.moDefaultTabSize
)
399 moDefaultTabSize
= rSourceProps
.moDefaultTabSize
;
400 if( rSourceProps
.mnLevel
)
401 mnLevel
= rSourceProps
.mnLevel
;
402 if( rSourceProps
.moParaAdjust
)
403 moParaAdjust
= rSourceProps
.moParaAdjust
;
404 if( rSourceProps
.maLineSpacing
.bHasValue
)
405 maLineSpacing
= rSourceProps
.maLineSpacing
;
408 void TextParagraphProperties::pushToPropSet( const ::oox::core::XmlFilterBase
* pFilterBase
,
409 const Reference
< XPropertySet
>& xPropSet
, PropertyMap
& rioBulletMap
, const BulletList
* pMasterBuList
, bool bApplyBulletMap
, float fCharacterSize
,
410 bool bPushDefaultValues
) const
412 PropertySet
aPropSet( xPropSet
);
413 aPropSet
.setProperties( maTextParagraphPropertyMap
);
415 sal_Int32 nNumberingType
= NumberingType::NUMBER_NONE
;
416 if ( maBulletList
.mnNumberingType
.hasValue() )
418 maBulletList
.mnNumberingType
>>= nNumberingType
;
419 aPropSet
.setProperty
< sal_Int16
>( PROP_NumberingLevel
, getLevel() );
421 else if ( pMasterBuList
&& pMasterBuList
->mnNumberingType
.hasValue() )
422 pMasterBuList
->mnNumberingType
>>= nNumberingType
;
423 if ( nNumberingType
== NumberingType::NUMBER_NONE
)
424 aPropSet
.setProperty
< sal_Int16
>( PROP_NumberingLevel
, -1 );
426 maBulletList
.pushToPropMap( pFilterBase
, rioBulletMap
);
428 if ( maParaTopMargin
.bHasValue
|| bPushDefaultValues
)
429 aPropSet
.setProperty( PROP_ParaTopMargin
, maParaTopMargin
.toMargin( fCharacterSize
!= 0.0 ? fCharacterSize
: getCharHeightPoints ( 12.0 ) ) );
430 if ( maParaBottomMargin
.bHasValue
|| bPushDefaultValues
)
431 aPropSet
.setProperty( PROP_ParaBottomMargin
, maParaBottomMargin
.toMargin( fCharacterSize
!= 0.0 ? fCharacterSize
: getCharHeightPoints ( 12.0 ) ) );
433 std::optional
< sal_Int32
> noParaLeftMargin( moParaLeftMargin
);
434 std::optional
< sal_Int32
> noFirstLineIndentation( moFirstLineIndentation
);
436 if ( nNumberingType
!= NumberingType::NUMBER_NONE
)
438 if ( noParaLeftMargin
)
440 aPropSet
.setProperty
<sal_Int32
>( PROP_ParaLeftMargin
, 0);
441 rioBulletMap
.setProperty( PROP_LeftMargin
, *noParaLeftMargin
);
442 noParaLeftMargin
.reset();
444 if ( noFirstLineIndentation
)
446 // Force Paragraph property as zero - impress seems to use the value from previous
447 // (non) bullet line if not set to zero explicitly :(
448 aPropSet
.setProperty
<sal_Int32
>( PROP_ParaFirstLineIndent
, 0);
449 rioBulletMap
.setProperty( PROP_FirstLineOffset
, *noFirstLineIndentation
);
450 noFirstLineIndentation
.reset();
452 if ( nNumberingType
!= NumberingType::BITMAP
&& !rioBulletMap
.hasProperty( PROP_BulletColor
) && pFilterBase
)
453 rioBulletMap
.setProperty( PROP_BulletColor
, maTextCharacterProperties
.maFillProperties
.getBestSolidColor().getColor( pFilterBase
->getGraphicHelper()));
456 if ( bApplyBulletMap
)
458 Reference
< XIndexReplace
> xNumRule
;
459 aPropSet
.getProperty( xNumRule
, PROP_NumberingRules
);
460 OSL_ENSURE( xNumRule
.is(), "can't get Numbering rules");
466 if( !rioBulletMap
.empty() )
468 // fix default bullet size to be 100%
469 if( !rioBulletMap
.hasProperty( PROP_BulletRelSize
) )
470 rioBulletMap
.setProperty
<sal_Int16
>( PROP_BulletRelSize
, 100);
471 Sequence
< PropertyValue
> aBulletPropSeq
= rioBulletMap
.makePropertyValueSequence();
472 xNumRule
->replaceByIndex( getLevel(), Any( aBulletPropSeq
) );
475 aPropSet
.setProperty( PROP_NumberingRules
, xNumRule
);
478 catch (const Exception
&)
480 // Don't warn for now, expected to fail for Writer.
483 if ( noParaLeftMargin
)
484 aPropSet
.setProperty( PROP_ParaLeftMargin
, *noParaLeftMargin
);
485 if ( noFirstLineIndentation
)
487 aPropSet
.setProperty( PROP_ParaFirstLineIndent
, *noFirstLineIndentation
);
488 if( bPushDefaultValues
)
490 // Reset TabStops - these would be auto calculated by Impress
492 aTabStop
.Position
= 0;
493 Sequence
< TabStop
> aSeq
{ aTabStop
};
494 aPropSet
.setProperty( PROP_ParaTabStops
, aSeq
);
498 aPropSet
.setProperty
<sal_Int32
>( PROP_ParaFirstLineIndent
, 0);
500 if ( moDefaultTabSize
)
502 aPropSet
.setProperty( PROP_ParaTabStopDefaultDistance
, *moDefaultTabSize
);
507 aPropSet
.setProperty( PROP_ParaAdjust
, *moParaAdjust
);
511 aPropSet
.setProperty( PROP_ParaAdjust
, css::style::ParagraphAdjust_LEFT
);
514 if ( maLineSpacing
.bHasValue
)
516 aPropSet
.setProperty( PROP_ParaLineSpacing
, maLineSpacing
.toLineSpacing());
520 aPropSet
.setProperty( PROP_ParaLineSpacing
, css::style::LineSpacing( css::style::LineSpacingMode::PROP
, 100 ));
524 float TextParagraphProperties::getCharHeightPoints( float fDefault
) const
526 return maTextCharacterProperties
.getCharHeightPoints( fDefault
);
530 // Note: Please don't remove this function. This is required for
531 // debugging pptx import problems.
532 void TextParagraphProperties::dump() const
534 Reference
< css::drawing::XShape
> xShape( oox::ppt::PowerPointImport::mpDebugFilterBase
->getModelFactory()->createInstance( "com.sun.star.presentation.TitleTextShape" ), UNO_QUERY
);
535 Reference
< css::text::XText
> xText( xShape
, UNO_QUERY
);
537 Reference
< css::drawing::XDrawPage
> xDebugPage(ppt::SlidePersist::mxDebugPage
.get(), UNO_QUERY
);
539 xDebugPage
->add( xShape
);
541 PropertyMap emptyMap
;
543 xText
->setString( "debug" );
544 Reference
< css::text::XTextCursor
> xStart
= xText
->createTextCursor();
545 xStart
->gotoEnd( true );
546 Reference
< XPropertySet
> xPropSet( xStart
, UNO_QUERY
);
547 pushToPropSet( nullptr, xPropSet
, emptyMap
, nullptr, false, 0 );
548 PropertySet
aPropSet( xPropSet
);
554 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */