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