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