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