Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / oox / source / drawingml / chart / seriesconverter.cxx
bloba1f2cb737c7f748d3ac2b98465308d9643bca0c3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "drawingml/chart/seriesconverter.hxx"
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 <osl/diagnose.h>
31 #include <basegfx/numeric/ftools.hxx>
32 #include "drawingml/chart/datasourceconverter.hxx"
33 #include "drawingml/chart/seriesmodel.hxx"
34 #include "drawingml/chart/titleconverter.hxx"
35 #include "drawingml/chart/typegroupconverter.hxx"
36 #include "drawingml/chart/typegroupmodel.hxx"
37 #include <oox/core/xmlfilterbase.hxx>
38 #include "oox/helper/containerhelper.hxx"
39 #include <oox/helper/attributelist.hxx>
40 #include <oox/token/namespaces.hxx>
41 #include <oox/token/properties.hxx>
42 #include <oox/token/tokens.hxx>
43 #include "drawingml/lineproperties.hxx"
45 namespace oox {
46 namespace drawingml {
47 namespace chart {
49 using namespace com::sun::star;
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;
55 namespace {
57 /** nested-up sgn function - employs some gratuity around 0 - values
58 smaller than 0.33 are clamped to 0
60 int lclSgn( double nVal )
62 const int intVal=nVal*3;
63 return intVal == 0 ? 0 : (intVal < 0 ? -1 : 1);
66 Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
67 const ConverterRoot& rParent,
68 DataSourceModel* pValues, const OUString& rRole,
69 TextModel* pTitle = nullptr )
71 // create data sequence for values
72 Reference< XDataSequence > xValueSeq;
73 if( pValues )
75 DataSourceConverter aSourceConv( rParent, *pValues );
76 xValueSeq = aSourceConv.createDataSequence( rRole );
79 // create data sequence for title
80 Reference< XDataSequence > xTitleSeq;
81 if( pTitle )
83 TextConverter aTextConv( rParent, *pTitle );
84 xTitleSeq = aTextConv.createDataSequence( "label" );
87 // create the labeled data sequence, if values or title are present
88 Reference< XLabeledDataSequence > xLabeledSeq;
89 if( xValueSeq.is() || xTitleSeq.is() )
91 xLabeledSeq.set( LabeledDataSequence::create(rParent.getComponentContext()), UNO_QUERY );
92 if( xLabeledSeq.is() )
94 xLabeledSeq->setValues( xValueSeq );
95 xLabeledSeq->setLabel( xTitleSeq );
98 return xLabeledSeq;
101 void lclConvertLabelFormatting( PropertySet& rPropSet, ObjectFormatter& rFormatter,
102 const DataLabelModelBase& rDataLabel, const TypeGroupConverter& rTypeGroup,
103 bool bDataSeriesLabel, bool bMSO2007Doc, const PropertySet* pSeriesPropSet )
105 const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
107 /* Excel 2007 does not change the series setting for a single data point,
108 if none of some specific elements occur. But only one existing element
109 in a data point will reset most other of these elements from the series
110 (e.g.: series has <c:showVal>, data point has <c:showCatName>, this
111 will reset <c:showVal> for this point, unless <c:showVal> is repeated
112 in the data point). The elements <c:layout>, <c:numberFormat>,
113 <c:spPr>, <c:tx>, and <c:txPr> are not affected at all. */
114 bool bHasAnyElement = true;
115 if (bMSO2007Doc)
117 bHasAnyElement = rDataLabel.moaSeparator.has() || rDataLabel.monLabelPos.has() ||
118 rDataLabel.mobShowCatName.has() || rDataLabel.mobShowLegendKey.has() ||
119 rDataLabel.mobShowPercent.has() || rDataLabel.mobShowSerName.has() ||
120 rDataLabel.mobShowVal.has();
123 bool bShowValue = !rDataLabel.mbDeleted && rDataLabel.mobShowVal.get( !bMSO2007Doc );
124 bool bShowPercent = !rDataLabel.mbDeleted && rDataLabel.mobShowPercent.get( !bMSO2007Doc ) && (rTypeInfo.meTypeCategory == TYPECATEGORY_PIE);
125 if( bShowValue &&
126 !bShowPercent && rTypeInfo.meTypeCategory == TYPECATEGORY_PIE &&
127 rDataLabel.maNumberFormat.maFormatCode.indexOf('%') >= 0 )
129 bShowValue = false;
130 bShowPercent = true;
132 bool bShowCateg = !rDataLabel.mbDeleted && rDataLabel.mobShowCatName.get( !bMSO2007Doc );
133 bool bShowSymbol = !rDataLabel.mbDeleted && rDataLabel.mobShowLegendKey.get( !bMSO2007Doc );
135 // type of attached label
136 if( bHasAnyElement || rDataLabel.mbDeleted )
138 DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol );
139 rPropSet.setProperty( PROP_Label, aPointLabel );
142 if( !rDataLabel.mbDeleted )
144 // data label number format (percentage format wins over value format)
145 rFormatter.convertNumberFormat( rPropSet, rDataLabel.maNumberFormat, false, bShowPercent );
147 // data label text formatting (frame formatting not supported by Chart2)
148 rFormatter.convertTextFormatting( rPropSet, rDataLabel.mxTextProp, OBJECTTYPE_DATALABEL );
149 ObjectFormatter::convertTextRotation( rPropSet, rDataLabel.mxTextProp, false );
150 ObjectFormatter::convertTextWrap( rPropSet, rDataLabel.mxTextProp );
153 // data label separator (do not overwrite series separator, if no explicit point separator is present)
154 if( bDataSeriesLabel || rDataLabel.moaSeparator.has() )
155 rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( "; " ) );
157 // data label placement (do not overwrite series placement, if no explicit point placement is present)
158 if( bDataSeriesLabel || rDataLabel.monLabelPos.has() )
160 namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
161 sal_Int32 nPlacement = rTypeInfo.mnDefLabelPos;
162 switch( rDataLabel.monLabelPos.get( XML_TOKEN_INVALID ) )
164 case XML_outEnd: nPlacement = csscd::OUTSIDE; break;
165 case XML_inEnd: nPlacement = csscd::INSIDE; break;
166 case XML_ctr: nPlacement = csscd::CENTER; break;
167 case XML_inBase: nPlacement = csscd::NEAR_ORIGIN; break;
168 case XML_t: nPlacement = csscd::TOP; break;
169 case XML_b: nPlacement = csscd::BOTTOM; break;
170 case XML_l: nPlacement = csscd::LEFT; break;
171 case XML_r: nPlacement = csscd::RIGHT; break;
172 case XML_bestFit: nPlacement = csscd::AVOID_OVERLAP; break;
175 sal_Int32 nGlobalPlacement = 0;
176 if ( !bDataSeriesLabel && nPlacement == rTypeInfo.mnDefLabelPos && pSeriesPropSet &&
177 pSeriesPropSet->getProperty( nGlobalPlacement, PROP_LabelPlacement ) )
178 nPlacement = nGlobalPlacement;
180 rPropSet.setProperty( PROP_LabelPlacement, nPlacement );
185 void importBorderProperties( PropertySet& rPropSet, Shape& rShape, const GraphicHelper& rGraphicHelper )
187 LineProperties& rLP = rShape.getLineProperties();
188 // no fill has the same effect as no border so skip it
189 if (rLP.maLineFill.moFillType.get() == XML_noFill)
190 return;
192 if (rLP.moLineWidth.has())
194 sal_Int32 nWidth = convertEmuToHmm(rLP.moLineWidth.get());
195 rPropSet.setProperty(PROP_LabelBorderWidth, uno::makeAny(nWidth));
196 rPropSet.setProperty(PROP_LabelBorderStyle, uno::makeAny(drawing::LineStyle_SOLID));
198 const Color& aColor = rLP.maLineFill.maFillColor;
199 sal_Int32 nColor = aColor.getColor(rGraphicHelper);
200 rPropSet.setProperty(PROP_LabelBorderColor, uno::makeAny(nColor));
203 } // namespace
205 DataLabelConverter::DataLabelConverter( const ConverterRoot& rParent, DataLabelModel& rModel ) :
206 ConverterBase< DataLabelModel >( rParent, rModel )
210 DataLabelConverter::~DataLabelConverter()
214 void DataLabelConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, const TypeGroupConverter& rTypeGroup,
215 const PropertySet& rSeriesPropSet )
217 if (!rxDataSeries.is())
218 return;
222 bool bMSO2007Doc = getFilter().isMSO2007Document();
223 PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
224 lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, false, bMSO2007Doc, &rSeriesPropSet );
225 const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
226 bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
227 if( mrModel.mxLayout && !mrModel.mxLayout->mbAutoLayout && !bIsPie )
229 // bnc#694340 - nasty hack - chart2 cannot individually
230 // place data labels, let's try to find a useful
231 // compromise instead
232 namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
233 const sal_Int32 aPositionsLookupTable[] =
235 csscd::TOP_LEFT, csscd::TOP, csscd::TOP_RIGHT,
236 csscd::LEFT, csscd::CENTER, csscd::RIGHT,
237 csscd::BOTTOM_LEFT, csscd::BOTTOM, csscd::BOTTOM_RIGHT
239 const double nMax=std::max(
240 fabs(mrModel.mxLayout->mfX),
241 fabs(mrModel.mxLayout->mfY));
242 const int simplifiedX=lclSgn(mrModel.mxLayout->mfX/nMax);
243 const int simplifiedY=lclSgn(mrModel.mxLayout->mfY/nMax);
244 aPropSet.setProperty( PROP_LabelPlacement,
245 aPositionsLookupTable[ simplifiedX+1 + 3*(simplifiedY+1) ] );
248 if (mrModel.mxShapeProp)
249 importBorderProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper());
251 catch( Exception& )
256 DataLabelsConverter::DataLabelsConverter( const ConverterRoot& rParent, DataLabelsModel& rModel ) :
257 ConverterBase< DataLabelsModel >( rParent, rModel )
261 DataLabelsConverter::~DataLabelsConverter()
265 void DataLabelsConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, const TypeGroupConverter& rTypeGroup )
267 PropertySet aPropSet( rxDataSeries );
268 if( !mrModel.mbDeleted )
270 bool bMSO2007Doc = getFilter().isMSO2007Document();
271 lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, true, bMSO2007Doc, nullptr );
273 if (mrModel.mxShapeProp)
274 // Import baseline border properties for these data labels.
275 importBorderProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper());
278 // data point label settings
279 for( DataLabelsModel::DataLabelVector::iterator aIt = mrModel.maPointLabels.begin(), aEnd = mrModel.maPointLabels.end(); aIt != aEnd; ++aIt )
281 if ((*aIt)->maNumberFormat.maFormatCode.isEmpty())
282 (*aIt)->maNumberFormat = mrModel.maNumberFormat;
284 DataLabelConverter aLabelConv( *this, **aIt );
285 aLabelConv.convertFromModel( rxDataSeries, rTypeGroup, aPropSet );
289 ErrorBarConverter::ErrorBarConverter( const ConverterRoot& rParent, ErrorBarModel& rModel ) :
290 ConverterBase< ErrorBarModel >( rParent, rModel )
294 ErrorBarConverter::~ErrorBarConverter()
298 void ErrorBarConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries )
300 bool bShowPos = (mrModel.mnTypeId == XML_plus) || (mrModel.mnTypeId == XML_both);
301 bool bShowNeg = (mrModel.mnTypeId == XML_minus) || (mrModel.mnTypeId == XML_both);
302 if( bShowPos || bShowNeg ) try
304 Reference< XPropertySet > xErrorBar( createInstance( "com.sun.star.chart2.ErrorBar" ), UNO_QUERY_THROW );
305 PropertySet aBarProp( xErrorBar );
307 // plus/minus bars
308 aBarProp.setProperty( PROP_ShowPositiveError, bShowPos );
309 aBarProp.setProperty( PROP_ShowNegativeError, bShowNeg );
311 // type of displayed error
312 namespace cssc = ::com::sun::star::chart;
313 switch( mrModel.mnValueType )
315 case XML_cust:
317 // #i87806# manual error bars
318 aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::FROM_DATA );
319 // attach data sequences to erorr bar
320 Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY );
321 if( xDataSink.is() )
323 // create vector of all value sequences
324 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
325 // add positive values
326 if( bShowPos )
328 Reference< XLabeledDataSequence > xValueSeq = createLabeledDataSequence( ErrorBarModel::PLUS );
329 if( xValueSeq.is() )
330 aLabeledSeqVec.push_back( xValueSeq );
332 // add negative values
333 if( bShowNeg )
335 Reference< XLabeledDataSequence > xValueSeq = createLabeledDataSequence( ErrorBarModel::MINUS );
336 if( xValueSeq.is() )
337 aLabeledSeqVec.push_back( xValueSeq );
339 // attach labeled data sequences to series
340 if( aLabeledSeqVec.empty() )
341 xErrorBar.clear();
342 else
343 xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) );
346 break;
347 case XML_fixedVal:
348 aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::ABSOLUTE );
349 aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
350 aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
351 break;
352 case XML_percentage:
353 aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::RELATIVE );
354 aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
355 aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
356 break;
357 case XML_stdDev:
358 aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_DEVIATION );
359 aBarProp.setProperty( PROP_Weight, mrModel.mfValue );
360 break;
361 case XML_stdErr:
362 aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_ERROR );
363 break;
364 default:
365 OSL_FAIL( "ErrorBarConverter::convertFromModel - unknown error bar type" );
366 xErrorBar.clear();
369 // error bar formatting
370 getFormatter().convertFrameFormatting( aBarProp, mrModel.mxShapeProp, OBJECTTYPE_ERRORBAR );
372 if( xErrorBar.is() )
374 PropertySet aSeriesProp( rxDataSeries );
375 switch( mrModel.mnDirection )
377 case XML_x: aSeriesProp.setProperty( PROP_ErrorBarX, xErrorBar ); break;
378 case XML_y: aSeriesProp.setProperty( PROP_ErrorBarY, xErrorBar ); break;
379 default: OSL_FAIL( "ErrorBarConverter::convertFromModel - invalid error bar direction" );
383 catch( Exception& )
385 OSL_FAIL( "ErrorBarConverter::convertFromModel - error while creating error bars" );
389 Reference< XLabeledDataSequence > ErrorBarConverter::createLabeledDataSequence( ErrorBarModel::SourceType eSourceType )
391 OUString aRole;
392 switch( eSourceType )
394 case ErrorBarModel::PLUS:
395 switch( mrModel.mnDirection )
397 case XML_x: aRole = "error-bars-x-positive"; break;
398 case XML_y: aRole = "error-bars-y-positive"; break;
400 break;
401 case ErrorBarModel::MINUS:
402 switch( mrModel.mnDirection )
404 case XML_x: aRole = "error-bars-x-negative"; break;
405 case XML_y: aRole = "error-bars-y-negative"; break;
407 break;
409 OSL_ENSURE( !aRole.isEmpty(), "ErrorBarConverter::createLabeledDataSequence - invalid error bar direction" );
410 return lclCreateLabeledDataSequence( *this, mrModel.maSources.get( eSourceType ).get(), aRole );
413 TrendlineLabelConverter::TrendlineLabelConverter( const ConverterRoot& rParent, TrendlineLabelModel& rModel ) :
414 ConverterBase< TrendlineLabelModel >( rParent, rModel )
418 TrendlineLabelConverter::~TrendlineLabelConverter()
422 void TrendlineLabelConverter::convertFromModel( PropertySet& rPropSet )
424 // formatting
425 getFormatter().convertFormatting( rPropSet, mrModel.mxShapeProp, mrModel.mxTextProp, OBJECTTYPE_TRENDLINELABEL );
428 TrendlineConverter::TrendlineConverter( const ConverterRoot& rParent, TrendlineModel& rModel ) :
429 ConverterBase< TrendlineModel >( rParent, rModel )
433 TrendlineConverter::~TrendlineConverter()
437 void TrendlineConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries )
441 // trend line type
442 OUString aServiceName;
443 switch( mrModel.mnTypeId )
445 case XML_exp:
446 aServiceName = "com.sun.star.chart2.ExponentialRegressionCurve";
447 break;
448 case XML_linear:
449 aServiceName = "com.sun.star.chart2.LinearRegressionCurve";
450 break;
451 case XML_log:
452 aServiceName = "com.sun.star.chart2.LogarithmicRegressionCurve";
453 break;
454 case XML_movingAvg:
455 aServiceName = "com.sun.star.chart2.MovingAverageRegressionCurve";
456 break;
457 case XML_poly:
458 aServiceName = "com.sun.star.chart2.PolynomialRegressionCurve";
459 break;
460 case XML_power:
461 aServiceName = "com.sun.star.chart2.PotentialRegressionCurve";
462 break;
463 default:
464 OSL_FAIL( "TrendlineConverter::convertFromModel - unknown trendline type" );
466 if( !aServiceName.isEmpty() )
468 Reference< XRegressionCurve > xRegCurve( createInstance( aServiceName ), UNO_QUERY_THROW );
469 PropertySet aPropSet( xRegCurve );
471 // Name
472 aPropSet.setProperty( PROP_CurveName, mrModel.maName );
473 aPropSet.setProperty( PROP_PolynomialDegree, mrModel.mnOrder );
474 aPropSet.setProperty( PROP_MovingAveragePeriod, mrModel.mnPeriod );
476 // Intercept
477 bool hasIntercept = mrModel.mfIntercept.has();
478 aPropSet.setProperty( PROP_ForceIntercept, hasIntercept);
479 if (hasIntercept)
480 aPropSet.setProperty( PROP_InterceptValue, mrModel.mfIntercept.get());
482 // Extrapolation
483 if (mrModel.mfForward.has())
484 aPropSet.setProperty( PROP_ExtrapolateForward, mrModel.mfForward.get() );
485 if (mrModel.mfBackward.has())
486 aPropSet.setProperty( PROP_ExtrapolateBackward, mrModel.mfBackward.get() );
488 // trendline formatting
489 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, OBJECTTYPE_TRENDLINE );
491 // #i83100# show equation and correlation coefficient
492 PropertySet aLabelProp( xRegCurve->getEquationProperties() );
493 aLabelProp.setProperty( PROP_ShowEquation, mrModel.mbDispEquation );
494 aLabelProp.setProperty( PROP_ShowCorrelationCoefficient, mrModel.mbDispRSquared );
496 // #i83100# formatting of the equation text box
497 if( mrModel.mbDispEquation || mrModel.mbDispRSquared )
499 TrendlineLabelConverter aLabelConv( *this, mrModel.mxLabel.getOrCreate() );
500 aLabelConv.convertFromModel( aLabelProp );
503 // unsupported: #i5085# manual trendline size
504 // unsupported: #i34093# manual crossing point
506 Reference< XRegressionCurveContainer > xRegCurveCont( rxDataSeries, UNO_QUERY_THROW );
507 xRegCurveCont->addRegressionCurve( xRegCurve );
510 catch( Exception& )
512 OSL_FAIL( "TrendlineConverter::convertFromModel - error while creating trendline" );
516 DataPointConverter::DataPointConverter( const ConverterRoot& rParent, DataPointModel& rModel ) :
517 ConverterBase< DataPointModel >( rParent, rModel )
521 DataPointConverter::~DataPointConverter()
525 void DataPointConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries,
526 const TypeGroupConverter& rTypeGroup, const SeriesModel& rSeries )
528 bool bMSO2007Doc = getFilter().isMSO2007Document();
531 PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
533 // data point marker
534 if( mrModel.monMarkerSymbol.differsFrom( rSeries.mnMarkerSymbol ) || mrModel.monMarkerSize.differsFrom( rSeries.mnMarkerSize ) )
535 rTypeGroup.convertMarker( aPropSet, mrModel.monMarkerSymbol.get( rSeries.mnMarkerSymbol ),
536 mrModel.monMarkerSize.get( rSeries.mnMarkerSize ), mrModel.mxMarkerProp );
538 // data point pie explosion
539 if( mrModel.monExplosion.differsFrom( rSeries.mnExplosion ) )
540 rTypeGroup.convertPieExplosion( aPropSet, mrModel.monExplosion.get() );
542 // point formatting
543 if( mrModel.mxShapeProp.is() )
545 if( rTypeGroup.getTypeInfo().mbPictureOptions )
546 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(bMSO2007Doc), rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
547 else
548 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
551 catch( Exception& )
556 SeriesConverter::SeriesConverter( const ConverterRoot& rParent, SeriesModel& rModel ) :
557 ConverterBase< SeriesModel >( rParent, rModel )
561 SeriesConverter::~SeriesConverter()
565 Reference< XLabeledDataSequence > SeriesConverter::createCategorySequence( const OUString& rRole )
567 return createLabeledDataSequence(SeriesModel::CATEGORIES, rRole, false);
570 Reference< XLabeledDataSequence > SeriesConverter::createValueSequence( const OUString& rRole )
572 return createLabeledDataSequence( SeriesModel::VALUES, rRole, true );
575 Reference< XDataSeries > SeriesConverter::createDataSeries( const TypeGroupConverter& rTypeGroup, bool bVaryColorsByPoint )
577 const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
579 // create the data series object
580 Reference< XDataSeries > xDataSeries( createInstance( "com.sun.star.chart2.DataSeries" ), UNO_QUERY );
581 PropertySet aSeriesProp( xDataSeries );
583 // attach data and title sequences to series
584 sal_Int32 nDataPointCount = 0;
585 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
586 if( xDataSink.is() )
588 // create vector of all value sequences
589 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
590 // add Y values
591 Reference< XLabeledDataSequence > xYValueSeq = createValueSequence( "values-y" );
592 if( xYValueSeq.is() )
594 aLabeledSeqVec.push_back( xYValueSeq );
595 Reference< XDataSequence > xValues = xYValueSeq->getValues();
596 if( xValues.is() )
597 nDataPointCount = xValues->getData().getLength();
599 if (!nDataPointCount)
600 // No values present. Don't create a data series.
601 return Reference<XDataSeries>();
603 // add X values of scatter and bubble charts
604 if( !rTypeInfo.mbCategoryAxis )
606 Reference< XLabeledDataSequence > xXValueSeq = createCategorySequence( "values-x" );
607 if( xXValueSeq.is() )
608 aLabeledSeqVec.push_back( xXValueSeq );
609 // add size values of bubble charts
610 if( rTypeInfo.meTypeId == TYPEID_BUBBLE )
612 Reference< XLabeledDataSequence > xSizeValueSeq = createLabeledDataSequence( SeriesModel::POINTS, "values-size", true );
613 if( xSizeValueSeq.is() )
614 aLabeledSeqVec.push_back( xSizeValueSeq );
617 // attach labeled data sequences to series
618 if( !aLabeledSeqVec.empty() )
619 xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) );
622 // error bars
623 for( SeriesModel::ErrorBarVector::iterator aIt = mrModel.maErrorBars.begin(), aEnd = mrModel.maErrorBars.end(); aIt != aEnd; ++aIt )
625 ErrorBarConverter aErrorBarConv( *this, **aIt );
626 aErrorBarConv.convertFromModel( xDataSeries );
629 // trendlines
630 for( SeriesModel::TrendlineVector::iterator aIt = mrModel.maTrendlines.begin(), aEnd = mrModel.maTrendlines.end(); aIt != aEnd; ++aIt )
632 TrendlineConverter aTrendlineConv( *this, **aIt );
633 aTrendlineConv.convertFromModel( xDataSeries );
636 // data point markers
637 rTypeGroup.convertMarker( aSeriesProp, mrModel.mnMarkerSymbol, mrModel.mnMarkerSize, mrModel.mxMarkerProp );
638 #if OOX_CHART_SMOOTHED_PER_SERIES
639 // #i66858# smoothed series lines
640 rTypeGroup.convertLineSmooth( aSeriesProp, mrModel.mbSmooth );
641 #endif
642 // 3D bar style (not possible to set at chart type -> set at all series)
643 rTypeGroup.convertBarGeometry( aSeriesProp, mrModel.monShape.get( rTypeGroup.getModel().mnShape ) );
644 // pie explosion (restricted to [0%,100%] in Chart2)
645 rTypeGroup.convertPieExplosion( aSeriesProp, mrModel.mnExplosion );
647 // series formatting
648 ObjectFormatter& rFormatter = getFormatter();
649 ObjectType eObjType = rTypeGroup.getSeriesObjectType();
650 bool bMSO2007Doc = getFilter().isMSO2007Document();
651 if( rTypeInfo.mbPictureOptions )
652 rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(bMSO2007Doc), eObjType, mrModel.mnIndex );
653 else
654 rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, eObjType, mrModel.mnIndex );
656 // set the (unused) property default value used by the Chart2 templates (true for pie/doughnut charts)
657 bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
658 aSeriesProp.setProperty( PROP_VaryColorsByPoint, bVaryColorsByPoint );
660 // own area formatting for every data point (TODO: varying line color not supported)
661 // #i91271# always set area formatting for every point in pie/doughnut charts to override their automatic point formatting
662 if( bIsPie || (bVaryColorsByPoint && rTypeGroup.isSeriesFrameFormat() && ObjectFormatter::isAutomaticFill( mrModel.mxShapeProp )) )
664 /* Set the series point number as color cycle size at the object
665 formatter to get correct start-shade/end-tint. TODO: in doughnut
666 charts, the sizes of the series may vary, need to use the maximum
667 point count of all series. */
668 sal_Int32 nOldMax = rFormatter.getMaxSeriesIndex();
669 if( bVaryColorsByPoint )
670 rFormatter.setMaxSeriesIndex( nDataPointCount - 1 );
671 for( sal_Int32 nIndex = 0; nIndex < nDataPointCount; ++nIndex )
675 PropertySet aPointProp( xDataSeries->getDataPointByIndex( nIndex ) );
676 rFormatter.convertAutomaticFill( aPointProp, eObjType, bVaryColorsByPoint ? nIndex : mrModel.mnIndex );
678 catch( Exception& )
682 rFormatter.setMaxSeriesIndex( nOldMax );
685 // data point settings
686 for( SeriesModel::DataPointVector::iterator aIt = mrModel.maPoints.begin(), aEnd = mrModel.maPoints.end(); aIt != aEnd; ++aIt )
688 DataPointConverter aPointConv( *this, **aIt );
689 aPointConv.convertFromModel( xDataSeries, rTypeGroup, mrModel );
692 /* Series data label settings. If and only if the series does not contain
693 a c:dLbls element, then the c:dLbls element of the parent chart type is
694 used (data label settings of the parent chart type are *not* merged
695 into own existing data label settings). */
696 ModelRef< DataLabelsModel > xLabels = mrModel.mxLabels.is() ? mrModel.mxLabels : rTypeGroup.getModel().mxLabels;
697 if( xLabels.is() )
699 if( xLabels->maNumberFormat.maFormatCode.isEmpty() )
701 // Use number format code from Value series
702 DataSourceModel* pValues = mrModel.maSources.get( SeriesModel::VALUES ).get();
703 if( pValues )
704 xLabels->maNumberFormat.maFormatCode = pValues->mxDataSeq->maFormatCode;
706 DataLabelsConverter aLabelsConv( *this, *xLabels );
707 aLabelsConv.convertFromModel( xDataSeries, rTypeGroup );
710 return xDataSeries;
713 // private --------------------------------------------------------------------
715 Reference< XLabeledDataSequence > SeriesConverter::createLabeledDataSequence(
716 SeriesModel::SourceType eSourceType, const OUString& rRole, bool bUseTextLabel )
718 DataSourceModel* pValues = mrModel.maSources.get( eSourceType ).get();
719 TextModel* pTitle = bUseTextLabel ? mrModel.mxText.get() : nullptr;
720 return lclCreateLabeledDataSequence( *this, pValues, rRole, pTitle );
723 } // namespace chart
724 } // namespace drawingml
725 } // namespace oox
727 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */