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