Line data Source code
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 "oox/drawingml/chart/seriesconverter.hxx"
21 :
22 : #include <com/sun/star/chart/DataLabelPlacement.hpp>
23 : #include <com/sun/star/chart/ErrorBarStyle.hpp>
24 : #include <com/sun/star/chart2/DataPointLabel.hpp>
25 : #include <com/sun/star/chart2/XDataSeries.hpp>
26 : #include <com/sun/star/chart2/XRegressionCurve.hpp>
27 : #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
28 : #include <com/sun/star/chart2/data/XDataSink.hpp>
29 : #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
30 : #include <basegfx/numeric/ftools.hxx>
31 : #include "oox/drawingml/chart/datasourceconverter.hxx"
32 : #include "oox/drawingml/chart/seriesmodel.hxx"
33 : #include "oox/drawingml/chart/titleconverter.hxx"
34 : #include "oox/drawingml/chart/typegroupconverter.hxx"
35 : #include "oox/drawingml/chart/typegroupmodel.hxx"
36 : #include "oox/helper/containerhelper.hxx"
37 :
38 : namespace oox {
39 : namespace drawingml {
40 : namespace chart {
41 :
42 : // ============================================================================
43 :
44 : using namespace ::com::sun::star::beans;
45 : using namespace ::com::sun::star::chart2;
46 : using namespace ::com::sun::star::chart2::data;
47 : using namespace ::com::sun::star::uno;
48 :
49 : // ============================================================================
50 :
51 : namespace {
52 :
53 : /** nastied-up sgn function - employs some gratuity around 0 - values
54 : smaller than 0.33 are clamped to 0
55 : */
56 0 : int lclSgn( double nVal )
57 : {
58 0 : const int intVal=nVal*3;
59 0 : return intVal == 0 ? 0 : (intVal < 0 ? -1 : 1);
60 : }
61 :
62 4 : Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
63 : const ConverterRoot& rParent,
64 : DataSourceModel* pValues, const OUString& rRole,
65 : TextModel* pTitle = 0 )
66 : {
67 : // create data sequence for values
68 4 : Reference< XDataSequence > xValueSeq;
69 4 : if( pValues )
70 : {
71 4 : DataSourceConverter aSourceConv( rParent, *pValues );
72 4 : xValueSeq = aSourceConv.createDataSequence( rRole );
73 : }
74 :
75 : // create data sequence for title
76 8 : Reference< XDataSequence > xTitleSeq;
77 4 : if( pTitle )
78 : {
79 2 : TextConverter aTextConv( rParent, *pTitle );
80 2 : xTitleSeq = aTextConv.createDataSequence( "label" );
81 : }
82 :
83 : // create the labeled data sequence, if values or title are present
84 4 : Reference< XLabeledDataSequence > xLabeledSeq;
85 4 : if( xValueSeq.is() || xTitleSeq.is() )
86 : {
87 4 : xLabeledSeq.set( LabeledDataSequence::create(rParent.getComponentContext()), UNO_QUERY );
88 4 : if( xLabeledSeq.is() )
89 : {
90 4 : xLabeledSeq->setValues( xValueSeq );
91 4 : xLabeledSeq->setLabel( xTitleSeq );
92 : }
93 : }
94 8 : return xLabeledSeq;
95 : }
96 :
97 0 : void lclConvertLabelFormatting( PropertySet& rPropSet, ObjectFormatter& rFormatter,
98 : const DataLabelModelBase& rDataLabel, const TypeGroupConverter& rTypeGroup, bool bDataSeriesLabel )
99 : {
100 0 : const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
101 :
102 : /* Excel 2007 does not change the series setting for a single data point,
103 : if none of some specific elements occur. But only one existing element
104 : in a data point will reset most other of these elements from the series
105 : (e.g.: series has <c:showVal>, data point has <c:showCatName>, this
106 : will reset <c:showVal> for this point, unless <c:showVal> is repeated
107 : in the data point). The elements <c:layout>, <c:numberFormat>,
108 : <c:spPr>, <c:tx>, and <c:txPr> are not affected at all. */
109 : bool bHasAnyElement =
110 0 : rDataLabel.moaSeparator.has() || rDataLabel.monLabelPos.has() ||
111 0 : rDataLabel.mobShowCatName.has() || rDataLabel.mobShowLegendKey.has() ||
112 0 : rDataLabel.mobShowPercent.has() || rDataLabel.mobShowSerName.has() ||
113 0 : rDataLabel.mobShowVal.has();
114 :
115 0 : bool bShowValue = !rDataLabel.mbDeleted && rDataLabel.mobShowVal.get( false );
116 0 : bool bShowPercent = !rDataLabel.mbDeleted && rDataLabel.mobShowPercent.get( false ) && (rTypeInfo.meTypeCategory == TYPECATEGORY_PIE);
117 0 : if( bShowValue &&
118 0 : !bShowPercent && rTypeInfo.meTypeCategory == TYPECATEGORY_PIE &&
119 0 : rDataLabel.maNumberFormat.maFormatCode.indexOf('%') >= 0 )
120 : {
121 0 : bShowValue = false;
122 0 : bShowPercent = true;
123 : }
124 0 : bool bShowCateg = !rDataLabel.mbDeleted && rDataLabel.mobShowCatName.get( false );
125 0 : bool bShowSymbol = !rDataLabel.mbDeleted && rDataLabel.mobShowLegendKey.get( false );
126 :
127 : // type of attached label
128 0 : if( bHasAnyElement || rDataLabel.mbDeleted )
129 : {
130 0 : DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol );
131 0 : rPropSet.setProperty( PROP_Label, aPointLabel );
132 : }
133 :
134 0 : if( !rDataLabel.mbDeleted )
135 : {
136 : // data label number format (percentage format wins over value format)
137 0 : rFormatter.convertNumberFormat( rPropSet, rDataLabel.maNumberFormat, bShowPercent );
138 :
139 : // data label text formatting (frame formatting not supported by Chart2)
140 0 : rFormatter.convertTextFormatting( rPropSet, rDataLabel.mxTextProp, OBJECTTYPE_DATALABEL );
141 0 : rFormatter.convertTextRotation( rPropSet, rDataLabel.mxTextProp, false );
142 :
143 : // data label separator (do not overwrite series separator, if no explicit point separator is present)
144 0 : if( bDataSeriesLabel || rDataLabel.moaSeparator.has() )
145 0 : rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( "; " ) );
146 :
147 : // data label placement (do not overwrite series placement, if no explicit point placement is present)
148 0 : if( bDataSeriesLabel || rDataLabel.monLabelPos.has() )
149 : {
150 : namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
151 0 : sal_Int32 nPlacement = rTypeInfo.mnDefLabelPos;
152 0 : switch( rDataLabel.monLabelPos.get( XML_TOKEN_INVALID ) )
153 : {
154 0 : case XML_outEnd: nPlacement = csscd::OUTSIDE; break;
155 0 : case XML_inEnd: nPlacement = csscd::INSIDE; break;
156 0 : case XML_ctr: nPlacement = csscd::CENTER; break;
157 0 : case XML_inBase: nPlacement = csscd::NEAR_ORIGIN; break;
158 0 : case XML_t: nPlacement = csscd::TOP; break;
159 0 : case XML_b: nPlacement = csscd::BOTTOM; break;
160 0 : case XML_l: nPlacement = csscd::LEFT; break;
161 0 : case XML_r: nPlacement = csscd::RIGHT; break;
162 0 : case XML_bestFit: nPlacement = csscd::AVOID_OVERLAP; break;
163 : }
164 0 : rPropSet.setProperty( PROP_LabelPlacement, nPlacement );
165 : }
166 : }
167 0 : }
168 :
169 : } // namespace
170 :
171 : // ============================================================================
172 :
173 0 : DataLabelConverter::DataLabelConverter( const ConverterRoot& rParent, DataLabelModel& rModel ) :
174 0 : ConverterBase< DataLabelModel >( rParent, rModel )
175 : {
176 0 : }
177 :
178 0 : DataLabelConverter::~DataLabelConverter()
179 : {
180 0 : }
181 :
182 0 : void DataLabelConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, const TypeGroupConverter& rTypeGroup )
183 : {
184 0 : if( rxDataSeries.is() ) try
185 : {
186 0 : PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
187 0 : lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, false );
188 :
189 0 : if( mrModel.mxLayout && !mrModel.mxLayout->mbAutoLayout )
190 : {
191 : // bnc#694340 - nasty hack - chart2 cannot individually
192 : // place data labels, let's try to find a useful
193 : // compromise instead
194 : namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
195 : const sal_Int32 aPositionsLookupTable[] =
196 : {
197 : csscd::TOP_LEFT, csscd::TOP, csscd::TOP_RIGHT,
198 : csscd::LEFT, csscd::CENTER, csscd::RIGHT,
199 : csscd::BOTTOM_LEFT, csscd::BOTTOM, csscd::BOTTOM_RIGHT
200 0 : };
201 : const double nMax=std::max(
202 0 : fabs(mrModel.mxLayout->mfX),
203 0 : fabs(mrModel.mxLayout->mfY));
204 0 : const int simplifiedX=lclSgn(mrModel.mxLayout->mfX/nMax);
205 0 : const int simplifiedY=lclSgn(mrModel.mxLayout->mfY/nMax);
206 : aPropSet.setProperty( PROP_LabelPlacement,
207 0 : aPositionsLookupTable[ simplifiedX+1 + 3*(simplifiedY+1) ] );
208 0 : }
209 : }
210 0 : catch( Exception& )
211 : {
212 : }
213 0 : }
214 :
215 : // ============================================================================
216 :
217 0 : DataLabelsConverter::DataLabelsConverter( const ConverterRoot& rParent, DataLabelsModel& rModel ) :
218 0 : ConverterBase< DataLabelsModel >( rParent, rModel )
219 : {
220 0 : }
221 :
222 0 : DataLabelsConverter::~DataLabelsConverter()
223 : {
224 0 : }
225 :
226 0 : void DataLabelsConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, const TypeGroupConverter& rTypeGroup )
227 : {
228 0 : if( !mrModel.mbDeleted )
229 : {
230 0 : PropertySet aPropSet( rxDataSeries );
231 0 : lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, true );
232 : }
233 :
234 : // data point label settings
235 0 : for( DataLabelsModel::DataLabelVector::iterator aIt = mrModel.maPointLabels.begin(), aEnd = mrModel.maPointLabels.end(); aIt != aEnd; ++aIt )
236 : {
237 0 : (*aIt)->maNumberFormat.maFormatCode = mrModel.maNumberFormat.maFormatCode;
238 0 : if( !mrModel.maNumberFormat.maFormatCode.isEmpty() )
239 0 : (*aIt)->maNumberFormat.mbSourceLinked = false;
240 :
241 0 : DataLabelConverter aLabelConv( *this, **aIt );
242 0 : aLabelConv.convertFromModel( rxDataSeries, rTypeGroup );
243 0 : }
244 0 : }
245 :
246 : // ============================================================================
247 :
248 1 : ErrorBarConverter::ErrorBarConverter( const ConverterRoot& rParent, ErrorBarModel& rModel ) :
249 1 : ConverterBase< ErrorBarModel >( rParent, rModel )
250 : {
251 1 : }
252 :
253 1 : ErrorBarConverter::~ErrorBarConverter()
254 : {
255 1 : }
256 :
257 1 : void ErrorBarConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries )
258 : {
259 1 : bool bShowPos = (mrModel.mnTypeId == XML_plus) || (mrModel.mnTypeId == XML_both);
260 1 : bool bShowNeg = (mrModel.mnTypeId == XML_minus) || (mrModel.mnTypeId == XML_both);
261 1 : if( bShowPos || bShowNeg ) try
262 : {
263 1 : Reference< XPropertySet > xErrorBar( createInstance( "com.sun.star.chart2.ErrorBar" ), UNO_QUERY_THROW );
264 2 : PropertySet aBarProp( xErrorBar );
265 :
266 : // plus/minus bars
267 1 : aBarProp.setProperty( PROP_ShowPositiveError, bShowPos );
268 1 : aBarProp.setProperty( PROP_ShowNegativeError, bShowNeg );
269 :
270 : // type of displayed error
271 : namespace cssc = ::com::sun::star::chart;
272 1 : switch( mrModel.mnValueType )
273 : {
274 : case XML_cust:
275 : {
276 : // #i87806# manual error bars
277 0 : aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::FROM_DATA );
278 : // attach data sequences to erorr bar
279 0 : Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY );
280 0 : if( xDataSink.is() )
281 : {
282 : // create vector of all value sequences
283 0 : ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
284 : // add positive values
285 0 : if( bShowPos )
286 : {
287 0 : Reference< XLabeledDataSequence > xValueSeq = createLabeledDataSequence( ErrorBarModel::PLUS );
288 0 : if( xValueSeq.is() )
289 0 : aLabeledSeqVec.push_back( xValueSeq );
290 : }
291 : // add negative values
292 0 : if( bShowNeg )
293 : {
294 0 : Reference< XLabeledDataSequence > xValueSeq = createLabeledDataSequence( ErrorBarModel::MINUS );
295 0 : if( xValueSeq.is() )
296 0 : aLabeledSeqVec.push_back( xValueSeq );
297 : }
298 : // attach labeled data sequences to series
299 0 : if( aLabeledSeqVec.empty() )
300 0 : xErrorBar.clear();
301 : else
302 0 : xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) );
303 0 : }
304 : }
305 0 : break;
306 : case XML_fixedVal:
307 0 : aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::ABSOLUTE );
308 0 : aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
309 0 : aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
310 0 : break;
311 : case XML_percentage:
312 1 : aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::RELATIVE );
313 1 : aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
314 1 : aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
315 1 : break;
316 : case XML_stdDev:
317 0 : aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_DEVIATION );
318 0 : aBarProp.setProperty( PROP_Weight, mrModel.mfValue );
319 0 : break;
320 : case XML_stdErr:
321 0 : aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_ERROR );
322 0 : break;
323 : default:
324 : OSL_FAIL( "ErrorBarConverter::convertFromModel - unknown error bar type" );
325 0 : xErrorBar.clear();
326 : }
327 :
328 : // error bar formatting
329 1 : getFormatter().convertFrameFormatting( aBarProp, mrModel.mxShapeProp, OBJECTTYPE_ERRORBAR );
330 :
331 1 : if( xErrorBar.is() )
332 : {
333 1 : PropertySet aSeriesProp( rxDataSeries );
334 1 : switch( mrModel.mnDirection )
335 : {
336 0 : case XML_x: aSeriesProp.setProperty( PROP_ErrorBarX, xErrorBar ); break;
337 1 : case XML_y: aSeriesProp.setProperty( PROP_ErrorBarY, xErrorBar ); break;
338 : default: OSL_FAIL( "ErrorBarConverter::convertFromModel - invalid error bar direction" );
339 1 : }
340 1 : }
341 : }
342 0 : catch( Exception& )
343 : {
344 : OSL_FAIL( "ErrorBarConverter::convertFromModel - error while creating error bars" );
345 : }
346 1 : }
347 :
348 : // private --------------------------------------------------------------------
349 :
350 0 : Reference< XLabeledDataSequence > ErrorBarConverter::createLabeledDataSequence( ErrorBarModel::SourceType eSourceType )
351 : {
352 0 : OUString aRole;
353 0 : switch( eSourceType )
354 : {
355 : case ErrorBarModel::PLUS:
356 0 : switch( mrModel.mnDirection )
357 : {
358 0 : case XML_x: aRole = "error-bars-x-positive"; break;
359 0 : case XML_y: aRole = "error-bars-y-positive"; break;
360 : }
361 0 : break;
362 : case ErrorBarModel::MINUS:
363 0 : switch( mrModel.mnDirection )
364 : {
365 0 : case XML_x: aRole = "error-bars-x-negative"; break;
366 0 : case XML_y: aRole = "error-bars-y-negative"; break;
367 : }
368 0 : break;
369 : }
370 : OSL_ENSURE( !aRole.isEmpty(), "ErrorBarConverter::createLabeledDataSequence - invalid error bar direction" );
371 0 : return lclCreateLabeledDataSequence( *this, mrModel.maSources.get( eSourceType ).get(), aRole );
372 : }
373 :
374 : // ============================================================================
375 :
376 0 : TrendlineLabelConverter::TrendlineLabelConverter( const ConverterRoot& rParent, TrendlineLabelModel& rModel ) :
377 0 : ConverterBase< TrendlineLabelModel >( rParent, rModel )
378 : {
379 0 : }
380 :
381 0 : TrendlineLabelConverter::~TrendlineLabelConverter()
382 : {
383 0 : }
384 :
385 0 : void TrendlineLabelConverter::convertFromModel( PropertySet& rPropSet )
386 : {
387 : // formatting
388 0 : getFormatter().convertFormatting( rPropSet, mrModel.mxShapeProp, mrModel.mxTextProp, OBJECTTYPE_TRENDLINELABEL );
389 0 : }
390 :
391 : // ============================================================================
392 :
393 0 : TrendlineConverter::TrendlineConverter( const ConverterRoot& rParent, TrendlineModel& rModel ) :
394 0 : ConverterBase< TrendlineModel >( rParent, rModel )
395 : {
396 0 : }
397 :
398 0 : TrendlineConverter::~TrendlineConverter()
399 : {
400 0 : }
401 :
402 0 : void TrendlineConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries )
403 : {
404 : try
405 : {
406 : // trend line type
407 0 : OUString aServiceName;
408 0 : switch( mrModel.mnTypeId )
409 : {
410 : case XML_exp:
411 0 : aServiceName = "com.sun.star.chart2.ExponentialRegressionCurve";
412 0 : break;
413 : case XML_linear:
414 0 : aServiceName = "com.sun.star.chart2.LinearRegressionCurve";
415 0 : break;
416 : case XML_log:
417 0 : aServiceName = "com.sun.star.chart2.LogarithmicRegressionCurve";
418 0 : break;
419 : case XML_movingAvg:
420 0 : aServiceName = "com.sun.star.chart2.MovingAverageRegressionCurve";
421 0 : break;
422 : case XML_poly:
423 0 : aServiceName = "com.sun.star.chart2.PolynomialRegressionCurve";
424 0 : break;
425 : case XML_power:
426 0 : aServiceName = "com.sun.star.chart2.PotentialRegressionCurve";
427 0 : break;
428 : default:
429 : OSL_FAIL( "TrendlineConverter::convertFromModel - unknown trendline type" );
430 : }
431 0 : if( !aServiceName.isEmpty() )
432 : {
433 0 : Reference< XRegressionCurve > xRegCurve( createInstance( aServiceName ), UNO_QUERY_THROW );
434 0 : PropertySet aPropSet( xRegCurve );
435 :
436 0 : aPropSet.setProperty( PROP_PolynomialDegree, mrModel.mnOrder );
437 0 : aPropSet.setProperty( PROP_MovingAveragePeriod, mrModel.mnPeriod );
438 :
439 : // Intercept
440 0 : sal_Bool hasIntercept = mrModel.mfIntercept.has();
441 0 : aPropSet.setProperty( PROP_ForceIntercept, hasIntercept);
442 0 : if (hasIntercept)
443 0 : aPropSet.setProperty( PROP_InterceptValue, mrModel.mfIntercept.get());
444 :
445 : // Extrapolation
446 0 : if (mrModel.mfForward.has())
447 0 : aPropSet.setProperty( PROP_ExtrapolateForward, mrModel.mfForward.get() );
448 0 : if (mrModel.mfBackward.has())
449 0 : aPropSet.setProperty( PROP_ExtrapolateBackward, mrModel.mfBackward.get() );
450 :
451 : // trendline formatting
452 0 : getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, OBJECTTYPE_TRENDLINE );
453 :
454 : // #i83100# show equation and correlation coefficient
455 0 : PropertySet aLabelProp( xRegCurve->getEquationProperties() );
456 0 : aLabelProp.setProperty( PROP_ShowEquation, mrModel.mbDispEquation );
457 0 : aLabelProp.setProperty( PROP_ShowCorrelationCoefficient, mrModel.mbDispRSquared );
458 :
459 : // #i83100# formatting of the equation text box
460 0 : if( mrModel.mbDispEquation || mrModel.mbDispRSquared )
461 : {
462 0 : TrendlineLabelConverter aLabelConv( *this, mrModel.mxLabel.getOrCreate() );
463 0 : aLabelConv.convertFromModel( aLabelProp );
464 : }
465 :
466 : // unsupported: #i5085# manual trendline size
467 : // unsupported: #i34093# manual crossing point
468 :
469 0 : Reference< XRegressionCurveContainer > xRegCurveCont( rxDataSeries, UNO_QUERY_THROW );
470 0 : xRegCurveCont->addRegressionCurve( xRegCurve );
471 0 : }
472 : }
473 0 : catch( Exception& )
474 : {
475 : OSL_FAIL( "TrendlineConverter::convertFromModel - error while creating trendline" );
476 : }
477 0 : }
478 :
479 : // ============================================================================
480 :
481 0 : DataPointConverter::DataPointConverter( const ConverterRoot& rParent, DataPointModel& rModel ) :
482 0 : ConverterBase< DataPointModel >( rParent, rModel )
483 : {
484 0 : }
485 :
486 0 : DataPointConverter::~DataPointConverter()
487 : {
488 0 : }
489 :
490 0 : void DataPointConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries,
491 : const TypeGroupConverter& rTypeGroup, const SeriesModel& rSeries )
492 : {
493 : try
494 : {
495 0 : PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
496 :
497 : // data point marker
498 0 : if( mrModel.monMarkerSymbol.differsFrom( rSeries.mnMarkerSymbol ) || mrModel.monMarkerSize.differsFrom( rSeries.mnMarkerSize ) )
499 0 : rTypeGroup.convertMarker( aPropSet, mrModel.monMarkerSymbol.get( rSeries.mnMarkerSymbol ), mrModel.monMarkerSize.get( rSeries.mnMarkerSize ) );
500 :
501 : // data point pie explosion
502 0 : if( mrModel.monExplosion.differsFrom( rSeries.mnExplosion ) )
503 0 : rTypeGroup.convertPieExplosion( aPropSet, mrModel.monExplosion.get() );
504 :
505 : // point formatting
506 0 : if( mrModel.mxShapeProp.is() )
507 : {
508 0 : if( rTypeGroup.getTypeInfo().mbPictureOptions )
509 0 : getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(), rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
510 : else
511 0 : getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
512 0 : }
513 : }
514 0 : catch( Exception& )
515 : {
516 : }
517 0 : }
518 :
519 : // ============================================================================
520 :
521 2 : SeriesConverter::SeriesConverter( const ConverterRoot& rParent, SeriesModel& rModel ) :
522 2 : ConverterBase< SeriesModel >( rParent, rModel )
523 : {
524 2 : }
525 :
526 4 : SeriesConverter::~SeriesConverter()
527 : {
528 4 : }
529 :
530 2 : Reference< XLabeledDataSequence > SeriesConverter::createCategorySequence( const OUString& rRole )
531 : {
532 2 : return createLabeledDataSequence( SeriesModel::CATEGORIES, rRole, false );
533 : }
534 :
535 2 : Reference< XLabeledDataSequence > SeriesConverter::createValueSequence( const OUString& rRole )
536 : {
537 2 : return createLabeledDataSequence( SeriesModel::VALUES, rRole, true );
538 : }
539 :
540 2 : Reference< XDataSeries > SeriesConverter::createDataSeries( const TypeGroupConverter& rTypeGroup, bool bVaryColorsByPoint )
541 : {
542 2 : const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
543 :
544 : // create the data series object
545 2 : Reference< XDataSeries > xDataSeries( createInstance( "com.sun.star.chart2.DataSeries" ), UNO_QUERY );
546 4 : PropertySet aSeriesProp( xDataSeries );
547 :
548 : // attach data and title sequences to series
549 2 : sal_Int32 nDataPointCount = 0;
550 4 : Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
551 2 : if( xDataSink.is() )
552 : {
553 : // create vector of all value sequences
554 2 : ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
555 : // add Y values
556 4 : Reference< XLabeledDataSequence > xYValueSeq = createValueSequence( "values-y" );
557 2 : if( xYValueSeq.is() )
558 : {
559 2 : aLabeledSeqVec.push_back( xYValueSeq );
560 2 : Reference< XDataSequence > xValues = xYValueSeq->getValues();
561 2 : if( xValues.is() )
562 2 : nDataPointCount = xValues->getData().getLength();
563 : }
564 : // add X values of scatter and bubble charts
565 2 : if( !rTypeInfo.mbCategoryAxis )
566 : {
567 2 : Reference< XLabeledDataSequence > xXValueSeq = createCategorySequence( "values-x" );
568 2 : if( xXValueSeq.is() )
569 2 : aLabeledSeqVec.push_back( xXValueSeq );
570 : // add size values of bubble charts
571 2 : if( rTypeInfo.meTypeId == TYPEID_BUBBLE )
572 : {
573 0 : Reference< XLabeledDataSequence > xSizeValueSeq = createLabeledDataSequence( SeriesModel::POINTS, "values-size", true );
574 0 : if( xSizeValueSeq.is() )
575 0 : aLabeledSeqVec.push_back( xSizeValueSeq );
576 2 : }
577 : }
578 : // attach labeled data sequences to series
579 2 : if( !aLabeledSeqVec.empty() )
580 4 : xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) );
581 : }
582 :
583 : // error bars
584 3 : for( SeriesModel::ErrorBarVector::iterator aIt = mrModel.maErrorBars.begin(), aEnd = mrModel.maErrorBars.end(); aIt != aEnd; ++aIt )
585 : {
586 1 : ErrorBarConverter aErrorBarConv( *this, **aIt );
587 1 : aErrorBarConv.convertFromModel( xDataSeries );
588 1 : }
589 :
590 : // trendlines
591 2 : for( SeriesModel::TrendlineVector::iterator aIt = mrModel.maTrendlines.begin(), aEnd = mrModel.maTrendlines.end(); aIt != aEnd; ++aIt )
592 : {
593 0 : TrendlineConverter aTrendlineConv( *this, **aIt );
594 0 : aTrendlineConv.convertFromModel( xDataSeries );
595 0 : }
596 :
597 : // data point markers
598 2 : rTypeGroup.convertMarker( aSeriesProp, mrModel.mnMarkerSymbol, mrModel.mnMarkerSize );
599 : #if OOX_CHART_SMOOTHED_PER_SERIES
600 : // #i66858# smoothed series lines
601 : rTypeGroup.convertLineSmooth( aSeriesProp, mrModel.mbSmooth );
602 : #endif
603 : // 3D bar style (not possible to set at chart type -> set at all series)
604 2 : rTypeGroup.convertBarGeometry( aSeriesProp, mrModel.monShape.get( rTypeGroup.getModel().mnShape ) );
605 : // pie explosion (restricted to [0%,100%] in Chart2)
606 2 : rTypeGroup.convertPieExplosion( aSeriesProp, mrModel.mnExplosion );
607 :
608 : // series formatting
609 2 : ObjectFormatter& rFormatter = getFormatter();
610 2 : ObjectType eObjType = rTypeGroup.getSeriesObjectType();
611 2 : if( rTypeInfo.mbPictureOptions )
612 0 : rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(), eObjType, mrModel.mnIndex );
613 : else
614 2 : rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, eObjType, mrModel.mnIndex );
615 :
616 : // set the (unused) property default value used by the Chart2 templates (true for pie/doughnut charts)
617 2 : bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
618 2 : aSeriesProp.setProperty( PROP_VaryColorsByPoint, bIsPie );
619 :
620 : // own area formatting for every data point (TODO: varying line color not supported)
621 : // #i91271# always set area formatting for every point in pie/doughnut charts to override their automatic point formatting
622 2 : if( bIsPie || (bVaryColorsByPoint && rTypeGroup.isSeriesFrameFormat() && ObjectFormatter::isAutomaticFill( mrModel.mxShapeProp )) )
623 : {
624 : /* Set the series point number as color cycle size at the object
625 : formatter to get correct start-shade/end-tint. TODO: in doughnut
626 : charts, the sizes of the series may vary, need to use the maximum
627 : point count of all series. */
628 0 : sal_Int32 nOldMax = rFormatter.getMaxSeriesIndex();
629 0 : if( bVaryColorsByPoint )
630 0 : rFormatter.setMaxSeriesIndex( nDataPointCount - 1 );
631 0 : for( sal_Int32 nIndex = 0; nIndex < nDataPointCount; ++nIndex )
632 : {
633 : try
634 : {
635 0 : PropertySet aPointProp( xDataSeries->getDataPointByIndex( nIndex ) );
636 0 : rFormatter.convertAutomaticFill( aPointProp, eObjType, bVaryColorsByPoint ? nIndex : mrModel.mnIndex );
637 : }
638 0 : catch( Exception& )
639 : {
640 : }
641 : }
642 0 : rFormatter.setMaxSeriesIndex( nOldMax );
643 : }
644 :
645 : // data point settings
646 2 : for( SeriesModel::DataPointVector::iterator aIt = mrModel.maPoints.begin(), aEnd = mrModel.maPoints.end(); aIt != aEnd; ++aIt )
647 : {
648 0 : DataPointConverter aPointConv( *this, **aIt );
649 0 : aPointConv.convertFromModel( xDataSeries, rTypeGroup, mrModel );
650 0 : }
651 :
652 : /* Series data label settings. If and only if the series does not contain
653 : a c:dLbls element, then the c:dLbls element of the parent chart type is
654 : used (data label settings of the parent chart type are *not* merged
655 : into own existing data label settings). */
656 4 : ModelRef< DataLabelsModel > xLabels = mrModel.mxLabels.is() ? mrModel.mxLabels : rTypeGroup.getModel().mxLabels;
657 2 : if( xLabels.is() )
658 : {
659 0 : if( xLabels->maNumberFormat.maFormatCode.isEmpty() )
660 : {
661 : // Use number format code from Value series
662 0 : DataSourceModel* pValues = mrModel.maSources.get( SeriesModel::VALUES ).get();
663 0 : xLabels->maNumberFormat.maFormatCode = pValues->mxDataSeq->maFormatCode;
664 : }
665 0 : DataLabelsConverter aLabelsConv( *this, *xLabels );
666 0 : aLabelsConv.convertFromModel( xDataSeries, rTypeGroup );
667 : }
668 :
669 4 : return xDataSeries;
670 : }
671 :
672 : // private --------------------------------------------------------------------
673 :
674 4 : Reference< XLabeledDataSequence > SeriesConverter::createLabeledDataSequence(
675 : SeriesModel::SourceType eSourceType, const OUString& rRole, bool bUseTextLabel )
676 : {
677 4 : DataSourceModel* pValues = mrModel.maSources.get( eSourceType ).get();
678 4 : TextModel* pTitle = bUseTextLabel ? mrModel.mxText.get() : 0;
679 4 : return lclCreateLabeledDataSequence( *this, pValues, rRole, pTitle );
680 : }
681 :
682 : // ============================================================================
683 :
684 : } // namespace chart
685 : } // namespace drawingml
686 141 : } // namespace oox
687 :
688 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|