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 <drawingml/textparagraphpropertiescontext.hxx>
21
22 #include <com/sun/star/text/WritingMode2.hpp>
23 #include <com/sun/star/style/ParagraphAdjust.hpp>
24 #include <com/sun/star/xml/sax/SAXException.hpp>
25
26 #include <svx/unopage.hxx>
27 #include <sal/log.hxx>
28
29 #include <drawingml/colorchoicecontext.hxx>
30 #include <drawingml/textcharacterpropertiescontext.hxx>
31 #include <drawingml/fillproperties.hxx>
32 #include <oox/helper/attributelist.hxx>
33 #include "textspacingcontext.hxx"
34 #include "texttabstoplistcontext.hxx"
35 #include <oox/token/namespaces.hxx>
36 #include <oox/token/properties.hxx>
37 #include <oox/token/tokens.hxx>
38
39 using namespace ::oox::core;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::xml::sax;
42 using namespace ::com::sun::star::style;
43 using namespace ::com::sun::star::text;
44
45 namespace oox { namespace drawingml {
46
47 // CT_TextParagraphProperties
TextParagraphPropertiesContext(ContextHandler2Helper const & rParent,const AttributeList & rAttribs,TextParagraphProperties & rTextParagraphProperties)48 TextParagraphPropertiesContext::TextParagraphPropertiesContext( ContextHandler2Helper const & rParent,
49 const AttributeList& rAttribs,
50 TextParagraphProperties& rTextParagraphProperties )
51 : ContextHandler2( rParent )
52 , mrTextParagraphProperties( rTextParagraphProperties )
53 , mrBulletList( rTextParagraphProperties.getBulletList() )
54 {
55 OUString sValue;
56
57 PropertyMap& rPropertyMap( mrTextParagraphProperties.getTextParagraphPropertyMap() );
58
59 // ST_TextAlignType
60 if ( rAttribs.hasAttribute( XML_algn ) )
61 {
62 mrTextParagraphProperties.getParaAdjust() = GetParaAdjust( rAttribs.getToken( XML_algn, XML_l ) );
63 }
64 // TODO see to do the same with RubyAdjust
65
66 // ST_Coordinate32
67 // sValue = rAttribs.getString( XML_defTabSz ).get(); SJ: we need to be able to set the default tab size for each text object,
68 // this is possible at the moment only for the whole document.
69 // sal_Int32 nDefTabSize = ( sValue.getLength() == 0 ? 0 : GetCoordinate( sValue ) );
70 // TODO
71
72 // bool bEaLineBrk = rAttribs.getBool( XML_eaLnBrk, true );
73 if ( rAttribs.hasAttribute( XML_latinLnBrk ) )
74 {
75 bool bLatinLineBrk = rAttribs.getBool( XML_latinLnBrk, true );
76 rPropertyMap.setProperty( PROP_ParaIsHyphenation, bLatinLineBrk);
77 }
78 // TODO see what to do with Asian hyphenation
79
80 // ST_TextFontAlignType
81 // TODO
82 // sal_Int32 nFontAlign = rAttribs.getToken( XML_fontAlgn, XML_base );
83
84 if ( rAttribs.hasAttribute( XML_hangingPunct ) )
85 {
86 bool bHangingPunct = rAttribs.getBool( XML_hangingPunct, false );
87 rPropertyMap.setProperty( PROP_ParaIsHangingPunctuation, bHangingPunct);
88 }
89
90 // ST_Coordinate
91 if ( rAttribs.hasAttribute( XML_indent ) )
92 {
93 sValue = rAttribs.getString( XML_indent ).get();
94 mrTextParagraphProperties.getFirstLineIndentation() = boost::optional< sal_Int32 >( sValue.isEmpty() ? 0 : GetCoordinate( sValue ) );
95 }
96
97 // ST_TextIndentLevelType
98 // -1 is an invalid value and denote the lack of level
99 sal_Int32 nLevel = rAttribs.getInteger( XML_lvl, 0 );
100 if( nLevel > 8 || nLevel < 0 )
101 {
102 nLevel = 0;
103 }
104
105 mrTextParagraphProperties.setLevel( static_cast< sal_Int16 >( nLevel ) );
106
107 char name[] = "Outline X";
108 name[8] = static_cast<char>( '1' + nLevel );
109 const OUString sStyleNameValue( OUString::createFromAscii( name ) );
110 mrBulletList.setStyleName( sStyleNameValue );
111
112 // ST_TextMargin
113 // ParaLeftMargin
114 if ( rAttribs.hasAttribute( XML_marL ) )
115 {
116 sValue = rAttribs.getString( XML_marL ).get();
117 mrTextParagraphProperties.getParaLeftMargin() = boost::optional< sal_Int32 >( sValue.isEmpty() ? 0 : GetCoordinate( sValue ) );
118 }
119
120 // ParaRightMargin
121 if ( rAttribs.hasAttribute( XML_marR ) )
122 {
123 sValue = rAttribs.getString( XML_marR ).get();
124 sal_Int32 nMarR = sValue.isEmpty() ? 0 : GetCoordinate( sValue ) ;
125 rPropertyMap.setProperty( PROP_ParaRightMargin, nMarR);
126 }
127
128 if ( rAttribs.hasAttribute( XML_rtl ) )
129 {
130 bool bRtl = rAttribs.getBool( XML_rtl, false );
131 rPropertyMap.setProperty( PROP_WritingMode, ( bRtl ? WritingMode2::RL_TB : WritingMode2::LR_TB ));
132 }
133 }
134
~TextParagraphPropertiesContext()135 TextParagraphPropertiesContext::~TextParagraphPropertiesContext()
136 {
137 PropertyMap& rPropertyMap( mrTextParagraphProperties.getTextParagraphPropertyMap() );
138 if ( mrTextParagraphProperties.getLineSpacing().bHasValue )
139 rPropertyMap.setProperty( PROP_ParaLineSpacing, mrTextParagraphProperties.getLineSpacing().toLineSpacing());
140 else
141 rPropertyMap.setProperty( PROP_ParaLineSpacing, css::style::LineSpacing( css::style::LineSpacingMode::PROP, 100 ));
142
143 ::std::vector< TabStop >::size_type nTabCount = maTabList.size();
144 if( nTabCount != 0 )
145 {
146 Sequence< TabStop > aSeq( nTabCount );
147 TabStop * aArray = aSeq.getArray();
148 OSL_ENSURE( aArray != nullptr, "sequence array is NULL" );
149 ::std::copy( maTabList.begin(), maTabList.end(), aArray );
150 rPropertyMap.setProperty( PROP_ParaTabStops, aSeq);
151 }
152
153 if (mxBlipProps.get() && mxBlipProps->mxFillGraphic.is())
154 mrBulletList.setGraphic(mxBlipProps->mxFillGraphic);
155
156 if( mrBulletList.is() )
157 rPropertyMap.setProperty( PROP_IsNumbering, true);
158 sal_Int16 nLevel = mrTextParagraphProperties.getLevel();
159 rPropertyMap.setProperty( PROP_NumberingLevel, nLevel);
160 rPropertyMap.setProperty( PROP_NumberingIsNumber, true);
161
162 if( mrTextParagraphProperties.getParaAdjust() )
163 rPropertyMap.setProperty( PROP_ParaAdjust, mrTextParagraphProperties.getParaAdjust().get());
164 }
165
onCreateContext(sal_Int32 aElementToken,const AttributeList & rAttribs)166 ContextHandlerRef TextParagraphPropertiesContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
167 {
168 switch( aElementToken )
169 {
170 case A_TOKEN( lnSpc ): // CT_TextSpacing
171 return new TextSpacingContext( *this, mrTextParagraphProperties.getLineSpacing() );
172 case A_TOKEN( spcBef ): // CT_TextSpacing
173 return new TextSpacingContext( *this, mrTextParagraphProperties.getParaTopMargin() );
174 case A_TOKEN( spcAft ): // CT_TextSpacing
175 return new TextSpacingContext( *this, mrTextParagraphProperties.getParaBottomMargin() );
176 // EG_TextBulletColor
177 case A_TOKEN( buClrTx ): // CT_TextBulletColorFollowText ???
178 mrBulletList.mbBulletColorFollowText <<= true;
179 break;
180 case A_TOKEN( buClr ): // CT_Color
181 return new ColorContext( *this, *mrBulletList.maBulletColorPtr );
182 // EG_TextBulletSize
183 case A_TOKEN( buSzTx ): // CT_TextBulletSizeFollowText
184 mrBulletList.setBulletSize(100);
185 break;
186 case A_TOKEN( buSzPct ): // CT_TextBulletSizePercent
187 mrBulletList.setBulletSize( std::lround( GetPercent( rAttribs.getString( XML_val ).get() ) / 1000.f ) );
188 break;
189 case A_TOKEN( buSzPts ): // CT_TextBulletSizePoint
190 mrBulletList.setBulletSize(0);
191 mrBulletList.setFontSize( static_cast<sal_Int16>(GetTextSize( rAttribs.getString( XML_val ).get() ) ) );
192 break;
193
194 // EG_TextBulletTypeface
195 case A_TOKEN( buFontTx ): // CT_TextBulletTypefaceFollowText
196 mrBulletList.mbBulletFontFollowText <<= true;
197 break;
198 case A_TOKEN( buFont ): // CT_TextFont
199 mrBulletList.maBulletFont.setAttributes( rAttribs );
200 break;
201
202 // EG_TextBullet
203 case A_TOKEN( buNone ): // CT_TextNoBullet
204 mrBulletList.setNone();
205 break;
206 case A_TOKEN( buAutoNum ): // CT_TextAutonumberBullet
207 {
208 try {
209 sal_Int32 nType = rAttribs.getToken( XML_type, 0 );
210 sal_Int32 nStartAt = rAttribs.getInteger( XML_startAt, 1 );
211 if( nStartAt > 32767 )
212 {
213 nStartAt = 32767;
214 }
215 else if( nStartAt < 1 )
216 {
217 nStartAt = 1;
218 }
219 mrBulletList.setStartAt( nStartAt );
220 mrBulletList.setType( nType );
221 }
222 catch(SAXException& /* e */ )
223 {
224 SAL_WARN("oox", "OOX: SAXException in XML_buAutoNum");
225 }
226 break;
227 }
228 case A_TOKEN( buChar ): // CT_TextCharBullet
229 try {
230
231 mrBulletList.setBulletChar( rAttribs.getString( XML_char ).get() );
232 mrBulletList.setSuffixNone();
233 }
234 catch(SAXException& /* e */)
235 {
236 SAL_WARN("oox", "OOX: SAXException in XML_buChar");
237 }
238 break;
239 case A_TOKEN( buBlip ): // CT_TextBlipBullet
240 {
241 mxBlipProps.reset( new BlipFillProperties );
242 return new BlipFillContext( *this, rAttribs, *mxBlipProps );
243 }
244 case A_TOKEN( tabLst ): // CT_TextTabStopList
245 return new TextTabStopListContext( *this, maTabList );
246 case A_TOKEN( defRPr ): // CT_TextCharacterProperties
247 return new TextCharacterPropertiesContext( *this, rAttribs, mrTextParagraphProperties.getTextCharacterProperties() );
248 case W_TOKEN( jc ):
249 {
250 OptValue< OUString > oParaAdjust = rAttribs.getString( W_TOKEN(val) );
251 if( oParaAdjust.has() && !oParaAdjust.get().isEmpty() )
252 {
253 const OUString& sParaAdjust = oParaAdjust.get();
254 if( sParaAdjust == "left" )
255 mrTextParagraphProperties.setParaAdjust(ParagraphAdjust_LEFT);
256 else if ( sParaAdjust == "right" )
257 mrTextParagraphProperties.setParaAdjust(ParagraphAdjust_RIGHT);
258 else if ( sParaAdjust == "center" )
259 mrTextParagraphProperties.setParaAdjust(ParagraphAdjust_CENTER);
260 else if ( sParaAdjust == "both" )
261 mrTextParagraphProperties.setParaAdjust(ParagraphAdjust_BLOCK);
262 }
263 }
264 break;
265 case W_TOKEN( spacing ):
266 {
267 // Spacing before
268 if( !rAttribs.getBool(W_TOKEN(beforeAutospacing), false) )
269 {
270 OptValue<sal_Int32> oBefore = rAttribs.getInteger(W_TOKEN(before));
271 if (oBefore.has())
272 {
273 TextSpacing& rSpacing = mrTextParagraphProperties.getParaTopMargin();
274 rSpacing.nUnit = TextSpacing::Unit::Points;
275 rSpacing.nValue = TWIPS_TO_MM(oBefore.get());
276 rSpacing.bHasValue = true;
277 }
278 else
279 {
280 OptValue<sal_Int32> oBeforeLines = rAttribs.getInteger(W_TOKEN(beforeLines));
281 if (oBeforeLines.has())
282 {
283 TextSpacing& rSpacing = mrTextParagraphProperties.getParaTopMargin();
284 rSpacing.nUnit = TextSpacing::Unit::Percent;
285 rSpacing.nValue = oBeforeLines.get() * MAX_PERCENT / 100;
286 rSpacing.bHasValue = true;
287 }
288 }
289 }
290
291 // Spacing after
292 if( !rAttribs.getBool(W_TOKEN(afterAutospacing), false) )
293 {
294 OptValue<sal_Int32> oAfter = rAttribs.getInteger(W_TOKEN(after));
295 if (oAfter.has())
296 {
297 TextSpacing& rSpacing = mrTextParagraphProperties.getParaBottomMargin();
298 rSpacing.nUnit = TextSpacing::Unit::Points;
299 rSpacing.nValue = TWIPS_TO_MM(oAfter.get());
300 rSpacing.bHasValue = true;
301 }
302 else
303 {
304 OptValue<sal_Int32> oAfterLines = rAttribs.getInteger(W_TOKEN(afterLines));
305 if (oAfterLines.has())
306 {
307 TextSpacing& rSpacing = mrTextParagraphProperties.getParaBottomMargin();
308 rSpacing.nUnit = TextSpacing::Unit::Percent;
309 rSpacing.nValue = oAfterLines.get() * MAX_PERCENT / 100;
310 rSpacing.bHasValue = true;
311 }
312 }
313 }
314
315 // Line spacing
316 OptValue<OUString> oLineRule = rAttribs.getString(W_TOKEN(lineRule));
317 OptValue<sal_Int32> oLineSpacing = rAttribs.getInteger(W_TOKEN(line));
318 if (oLineSpacing.has())
319 {
320 TextSpacing& rLineSpacing = mrTextParagraphProperties.getLineSpacing();
321 if( !oLineRule.has() || oLineRule.get() == "auto" )
322 {
323 rLineSpacing.nUnit = TextSpacing::Unit::Percent;
324 rLineSpacing.nValue = oLineSpacing.get() * MAX_PERCENT / 240;
325 }
326 else
327 {
328 rLineSpacing.nUnit = TextSpacing::Unit::Points;
329 rLineSpacing.nValue = TWIPS_TO_MM(oLineSpacing.get());
330 }
331 rLineSpacing.bHasValue = true;
332 }
333 }
334 break;
335 default:
336 SAL_WARN("oox", "TextParagraphPropertiesContext::onCreateContext: unhandled element: " << getBaseToken(aElementToken));
337 }
338 return this;
339 }
340
341 } }
342
343 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
344