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