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 "VDataSeries.hxx"
21 : #include "ObjectIdentifier.hxx"
22 : #include "macros.hxx"
23 : #include "CommonConverters.hxx"
24 : #include "LabelPositionHelper.hxx"
25 : #include "ChartTypeHelper.hxx"
26 : #include "ContainerHelper.hxx"
27 : #include "DataSeriesHelper.hxx"
28 : #include "RegressionCurveHelper.hxx"
29 :
30 : #include <com/sun/star/chart/MissingValueTreatment.hpp>
31 : #include <com/sun/star/chart2/Symbol.hpp>
32 :
33 : #include <rtl/math.hxx>
34 : #include <com/sun/star/beans/XPropertySet.hpp>
35 : #include <com/sun/star/beans/XPropertyState.hpp>
36 : #include <com/sun/star/drawing/LineStyle.hpp>
37 : #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
38 : #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
39 : #include <com/sun/star/text/WritingMode.hpp>
40 : #include <com/sun/star/chart2/data/XDataSource.hpp>
41 :
42 : namespace chart {
43 :
44 : using namespace ::com::sun::star;
45 : using namespace ::com::sun::star::chart2;
46 : using ::com::sun::star::uno::Reference;
47 :
48 1798 : void VDataSequence::init( const uno::Reference< data::XDataSequence >& xModel )
49 : {
50 1798 : Model = xModel;
51 1798 : Doubles = DataSequenceToDoubleSequence( xModel );
52 1798 : }
53 :
54 73904 : bool VDataSequence::is() const
55 : {
56 73904 : return Model.is();
57 : }
58 1748 : void VDataSequence::clear()
59 : {
60 1748 : Model = NULL;
61 1748 : Doubles.realloc(0);
62 1748 : }
63 :
64 360 : double VDataSequence::getValue( sal_Int32 index ) const
65 : {
66 360 : if( 0<=index && index<Doubles.getLength() )
67 234 : return Doubles[index];
68 : else
69 : {
70 : double fNan;
71 126 : ::rtl::math::setNan( & fNan );
72 126 : return fNan;
73 : }
74 : }
75 :
76 858 : sal_Int32 VDataSequence::detectNumberFormatKey( sal_Int32 index ) const
77 : {
78 858 : sal_Int32 nNumberFormatKey = -1;
79 :
80 : // -1 is allowed and means a key for the whole sequence
81 1716 : if( -1<=index && index<Doubles.getLength() &&
82 858 : Model.is())
83 : {
84 858 : nNumberFormatKey = Model->getNumberFormatKeyByIndex( index );
85 : }
86 :
87 858 : return nNumberFormatKey;
88 : }
89 :
90 33806 : sal_Int32 VDataSequence::getLength() const
91 : {
92 33806 : return Doubles.getLength();
93 : }
94 :
95 : namespace
96 : {
97 : struct lcl_LessXOfPoint
98 : {
99 0 : inline bool operator() ( const std::vector< double >& first,
100 : const std::vector< double >& second )
101 : {
102 0 : if( !first.empty() && !second.empty() )
103 : {
104 0 : return first[0]<second[0];
105 : }
106 0 : return false;
107 : }
108 : };
109 :
110 25 : void lcl_clearIfNoValuesButTextIsContained( VDataSequence& rData, const uno::Reference<data::XDataSequence>& xDataSequence )
111 : {
112 : //#i71686#, #i101968#, #i102428#
113 25 : sal_Int32 nCount = rData.Doubles.getLength();
114 76 : for( sal_Int32 i = 0; i < nCount; ++i )
115 : {
116 60 : if( !::rtl::math::isNan( rData.Doubles[i] ) )
117 34 : return;
118 : }
119 : //no double value is countained
120 : //is there any text?
121 16 : uno::Sequence< OUString > aStrings( DataSequenceToStringSequence( xDataSequence ) );
122 16 : sal_Int32 nTextCount = aStrings.getLength();
123 16 : for( sal_Int32 j = 0; j < nTextCount; ++j )
124 : {
125 16 : if( !aStrings[j].isEmpty() )
126 : {
127 16 : rData.clear();
128 16 : return;
129 : }
130 0 : }
131 : //no content at all
132 : }
133 :
134 59453 : void lcl_maybeReplaceNanWithZero( double& rfValue, sal_Int32 nMissingValueTreatment )
135 : {
136 59453 : if( nMissingValueTreatment == ::com::sun::star::chart::MissingValueTreatment::USE_ZERO
137 59453 : && (::rtl::math::isNan(rfValue) || ::rtl::math::isInf(rfValue)) )
138 0 : rfValue = 0.0;
139 59453 : }
140 :
141 : }
142 :
143 1757 : VDataSeries::VDataSeries( const uno::Reference< XDataSeries >& xDataSeries )
144 : : m_nPolygonIndex(0)
145 : , m_fLogicMinX(0.0)
146 : , m_fLogicMaxX(0.0)
147 : , m_fLogicZPos(0.0)
148 : , m_xGroupShape(NULL)
149 : , m_xLabelsGroupShape(NULL)
150 : , m_xErrorXBarsGroupShape(NULL)
151 : , m_xErrorYBarsGroupShape(NULL)
152 : , m_xFrontSubGroupShape(NULL)
153 : , m_xBackSubGroupShape(NULL)
154 : , m_xDataSeries(xDataSeries)
155 : , m_aDataSequences()
156 : , m_nPointCount(0)
157 :
158 : , m_aValues_X()
159 : , m_aValues_Y()
160 : , m_aValues_Z()
161 : , m_aValues_Y_Min()
162 : , m_aValues_Y_Max()
163 : , m_aValues_Y_First()
164 : , m_aValues_Y_Last()
165 : , m_aValues_Bubble_Size()
166 : , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y)
167 :
168 : , m_fXMeanValue(1.0)
169 : , m_fYMeanValue(1.0)
170 :
171 : , m_aAttributedDataPointIndexList()
172 :
173 : , m_eStackingDirection(StackingDirection_NO_STACKING)
174 : , m_nAxisIndex(0)
175 : , m_bConnectBars(sal_False)
176 : , m_bGroupBarsPerAxis(sal_True)
177 : , m_nStartingAngle(90)
178 :
179 : , m_aSeriesParticle()
180 : , m_aCID()
181 : , m_aPointCID_Stub()
182 : , m_aLabelCID_Stub()
183 :
184 : , m_nGlobalSeriesIndex(0)
185 :
186 : , m_apLabel_Series(NULL)
187 : , m_apLabelPropNames_Series(NULL)
188 : , m_apLabelPropValues_Series(NULL)
189 : , m_apSymbolProperties_Series(NULL)
190 :
191 : , m_apLabel_AttributedPoint(NULL)
192 : , m_apLabelPropNames_AttributedPoint(NULL)
193 : , m_apLabelPropValues_AttributedPoint(NULL)
194 : , m_apSymbolProperties_AttributedPoint(NULL)
195 : , m_apSymbolProperties_InvisibleSymbolForSelection(NULL)
196 : , m_nCurrentAttributedPoint(-1)
197 : , m_nMissingValueTreatment(::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP)
198 1757 : , m_bAllowPercentValueInDataLabel(false)
199 : {
200 1757 : ::rtl::math::setNan( & m_fXMeanValue );
201 1757 : ::rtl::math::setNan( & m_fYMeanValue );
202 :
203 : uno::Reference<data::XDataSource> xDataSource =
204 1757 : uno::Reference<data::XDataSource>( xDataSeries, uno::UNO_QUERY );
205 :
206 1757 : m_aDataSequences = xDataSource->getDataSequences();
207 :
208 5296 : for(sal_Int32 nN = m_aDataSequences.getLength();nN--;)
209 : {
210 1782 : if(!m_aDataSequences[nN].is())
211 0 : continue;
212 1782 : uno::Reference<data::XDataSequence> xDataSequence( m_aDataSequences[nN]->getValues());
213 3564 : uno::Reference<beans::XPropertySet> xProp(xDataSequence, uno::UNO_QUERY );
214 1782 : if( xProp.is())
215 : {
216 : try
217 : {
218 1782 : uno::Any aARole = xProp->getPropertyValue("Role");
219 3564 : OUString aRole;
220 1782 : aARole >>= aRole;
221 :
222 1782 : if (aRole == "values-x")
223 : {
224 9 : m_aValues_X.init( xDataSequence );
225 9 : lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xDataSequence );
226 : }
227 1773 : else if (aRole =="values-y")
228 1747 : m_aValues_Y.init( xDataSequence );
229 26 : else if (aRole == "values-min")
230 10 : m_aValues_Y_Min.init( xDataSequence );
231 16 : else if (aRole == "values-max")
232 8 : m_aValues_Y_Max.init( xDataSequence );
233 8 : else if (aRole == "values-first")
234 0 : m_aValues_Y_First.init( xDataSequence );
235 8 : else if (aRole == "values-last")
236 8 : m_aValues_Y_Last.init( xDataSequence );
237 0 : else if (aRole == "values-size")
238 1782 : m_aValues_Bubble_Size.init( xDataSequence );
239 : }
240 0 : catch( const uno::Exception& e )
241 : {
242 : ASSERT_EXCEPTION( e );
243 : }
244 : }
245 1782 : }
246 :
247 : //determine the point count
248 1757 : m_nPointCount = m_aValues_Y.getLength();
249 : {
250 1757 : if( m_nPointCount < m_aValues_Bubble_Size.getLength() )
251 0 : m_nPointCount = m_aValues_Bubble_Size.getLength();
252 1757 : if( m_nPointCount < m_aValues_Y_Min.getLength() )
253 10 : m_nPointCount = m_aValues_Y_Min.getLength();
254 1757 : if( m_nPointCount < m_aValues_Y_Max.getLength() )
255 0 : m_nPointCount = m_aValues_Y_Max.getLength();
256 1757 : if( m_nPointCount < m_aValues_Y_First.getLength() )
257 0 : m_nPointCount = m_aValues_Y_First.getLength();
258 1757 : if( m_nPointCount < m_aValues_Y_Last.getLength() )
259 0 : m_nPointCount = m_aValues_Y_Last.getLength();
260 : }
261 :
262 3514 : uno::Reference<beans::XPropertySet> xProp(xDataSeries, uno::UNO_QUERY );
263 1757 : if( xProp.is())
264 : {
265 : try
266 : {
267 : //get AttributedDataPoints
268 1757 : xProp->getPropertyValue("AttributedDataPoints") >>= m_aAttributedDataPointIndexList;
269 :
270 1757 : xProp->getPropertyValue("StackingDirection") >>= m_eStackingDirection;
271 :
272 1757 : xProp->getPropertyValue("AttachedAxisIndex") >>= m_nAxisIndex;
273 1757 : if(m_nAxisIndex<0)
274 0 : m_nAxisIndex=0;
275 : }
276 0 : catch( const uno::Exception& e )
277 : {
278 : ASSERT_EXCEPTION( e );
279 : }
280 1757 : }
281 1757 : }
282 :
283 3514 : VDataSeries::~VDataSeries()
284 : {
285 3514 : }
286 :
287 0 : void VDataSeries::doSortByXValues()
288 : {
289 0 : if( m_aValues_X.is() && m_aValues_X.Doubles.getLength() )
290 : {
291 : //prepare a vector for sorting
292 0 : std::vector< ::std::vector< double > > aTmp;//outer vector are points, inner vector are the different values of athe point
293 : double fNan;
294 0 : ::rtl::math::setNan( & fNan );
295 0 : sal_Int32 nPointIndex = 0;
296 0 : for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ )
297 : {
298 0 : std::vector< double > aSinglePoint;
299 0 : aSinglePoint.push_back( (nPointIndex < m_aValues_X.Doubles.getLength()) ? m_aValues_X.Doubles[nPointIndex] : fNan );
300 0 : aSinglePoint.push_back( (nPointIndex < m_aValues_Y.Doubles.getLength()) ? m_aValues_Y.Doubles[nPointIndex] : fNan );
301 0 : aTmp.push_back( aSinglePoint );
302 0 : }
303 :
304 : //do sort
305 0 : std::stable_sort( aTmp.begin(), aTmp.end(), lcl_LessXOfPoint() );
306 :
307 : //fill the sorted points back to the members
308 0 : m_aValues_X.Doubles.realloc( m_nPointCount );
309 0 : m_aValues_Y.Doubles.realloc( m_nPointCount );
310 :
311 0 : for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ )
312 : {
313 0 : m_aValues_X.Doubles[nPointIndex]=aTmp[nPointIndex][0];
314 0 : m_aValues_Y.Doubles[nPointIndex]=aTmp[nPointIndex][1];
315 0 : }
316 : }
317 0 : }
318 :
319 6696 : uno::Reference< XDataSeries > VDataSeries::getModel() const
320 : {
321 6696 : return m_xDataSeries;
322 : }
323 :
324 39 : void VDataSeries::releaseShapes()
325 : {
326 39 : m_xGroupShape.set(0);
327 39 : m_xLabelsGroupShape.set(0);
328 39 : m_xErrorXBarsGroupShape.set(0);
329 39 : m_xErrorYBarsGroupShape.set(0);
330 39 : m_xFrontSubGroupShape.set(0);
331 39 : m_xBackSubGroupShape.set(0);
332 :
333 39 : m_aPolyPolygonShape3D.SequenceX.realloc(0);
334 39 : m_aPolyPolygonShape3D.SequenceY.realloc(0);
335 39 : m_aPolyPolygonShape3D.SequenceZ.realloc(0);
336 39 : m_nPolygonIndex = 0;
337 39 : }
338 :
339 1732 : void VDataSeries::setCategoryXAxis()
340 : {
341 1732 : m_aValues_X.clear();
342 1732 : m_bAllowPercentValueInDataLabel = true;
343 1732 : }
344 :
345 0 : void VDataSeries::setXValues( const Reference< chart2::data::XDataSequence >& xValues )
346 : {
347 0 : m_aValues_X.clear();
348 0 : m_aValues_X.init( xValues );
349 0 : m_bAllowPercentValueInDataLabel = true;
350 0 : }
351 :
352 25 : void VDataSeries::setXValuesIfNone( const Reference< chart2::data::XDataSequence >& xValues )
353 : {
354 25 : if( m_aValues_X.is() )
355 34 : return;
356 :
357 16 : m_aValues_X.init( xValues );
358 16 : lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xValues );
359 : }
360 :
361 1757 : void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex )
362 : {
363 1757 : m_nGlobalSeriesIndex = nGlobalSeriesIndex;
364 1757 : }
365 :
366 1757 : void VDataSeries::setParticle( const OUString& rSeriesParticle )
367 : {
368 1757 : m_aSeriesParticle = rSeriesParticle;
369 :
370 : //get CID
371 1757 : m_aCID = ObjectIdentifier::createClassifiedIdentifierForParticle( m_aSeriesParticle );
372 1757 : m_aPointCID_Stub = ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT, m_aSeriesParticle );
373 :
374 3514 : m_aLabelCID_Stub = ObjectIdentifier::createClassifiedIdentifierWithParent(
375 1757 : OBJECTTYPE_DATA_LABEL, OUString(), getLabelsCID() );
376 1757 : }
377 1830 : OUString VDataSeries::getSeriesParticle() const
378 : {
379 1830 : return m_aSeriesParticle;
380 : }
381 1744 : OUString VDataSeries::getCID() const
382 : {
383 1744 : return m_aCID;
384 : }
385 6893 : OUString VDataSeries::getPointCID_Stub() const
386 : {
387 6893 : return m_aPointCID_Stub;
388 : }
389 524 : OUString VDataSeries::getErrorBarsCID(bool bYError) const
390 : {
391 : OUString aChildParticle( ObjectIdentifier::getStringForType(
392 524 : bYError ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X ) );
393 524 : aChildParticle += "=";
394 :
395 : return ObjectIdentifier::createClassifiedIdentifierForParticles(
396 524 : m_aSeriesParticle, aChildParticle );
397 : }
398 1942 : OUString VDataSeries::getLabelsCID() const
399 : {
400 1942 : OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) );
401 1942 : aChildParticle += "=";
402 :
403 : return ObjectIdentifier::createClassifiedIdentifierForParticles(
404 1942 : m_aSeriesParticle, aChildParticle );
405 : }
406 905 : OUString VDataSeries::getLabelCID_Stub() const
407 : {
408 905 : return m_aLabelCID_Stub;
409 : }
410 15 : OUString VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex, bool bAverageLine ) const
411 : {
412 15 : OUString aRet;
413 15 : aRet = ObjectIdentifier::createDataCurveCID( m_aSeriesParticle, nCurveIndex, bAverageLine );
414 15 : return aRet;
415 : }
416 :
417 21 : OUString VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex ) const
418 : {
419 21 : OUString aRet;
420 21 : aRet = ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle, nCurveIndex );
421 21 : return aRet;
422 : }
423 1757 : void VDataSeries::setPageReferenceSize( const awt::Size & rPageRefSize )
424 : {
425 1757 : m_aReferenceSize = rPageRefSize;
426 1757 : }
427 :
428 3441 : StackingDirection VDataSeries::getStackingDirection() const
429 : {
430 3441 : return m_eStackingDirection;
431 : }
432 26094 : sal_Int32 VDataSeries::getAttachedAxisIndex() const
433 : {
434 26094 : return m_nAxisIndex;
435 : }
436 1757 : void VDataSeries::setConnectBars( sal_Bool bConnectBars )
437 : {
438 1757 : m_bConnectBars = bConnectBars;
439 1757 : }
440 475 : sal_Bool VDataSeries::getConnectBars() const
441 : {
442 475 : return m_bConnectBars;
443 : }
444 1757 : void VDataSeries::setGroupBarsPerAxis( sal_Bool bGroupBarsPerAxis )
445 : {
446 1757 : m_bGroupBarsPerAxis = bGroupBarsPerAxis;
447 1757 : }
448 2035 : sal_Bool VDataSeries::getGroupBarsPerAxis() const
449 : {
450 2035 : return m_bGroupBarsPerAxis;
451 : }
452 :
453 1757 : void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle )
454 : {
455 1757 : m_nStartingAngle = nStartingAngle;
456 1757 : }
457 26 : sal_Int32 VDataSeries::getStartingAngle() const
458 : {
459 26 : return m_nStartingAngle;
460 : }
461 :
462 0 : void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex )
463 : {
464 0 : if( nAttachedAxisIndex < 0 )
465 0 : nAttachedAxisIndex = 0;
466 0 : m_nAxisIndex = nAttachedAxisIndex;
467 0 : }
468 :
469 8740 : sal_Int32 VDataSeries::getTotalPointCount() const
470 : {
471 8740 : return m_nPointCount;
472 : }
473 :
474 36547 : double VDataSeries::getXValue( sal_Int32 index ) const
475 : {
476 36547 : double fRet = 0.0;
477 36547 : if(m_aValues_X.is())
478 : {
479 306 : if( 0<=index && index<m_aValues_X.getLength() )
480 306 : fRet = m_aValues_X.Doubles[index];
481 : else
482 0 : ::rtl::math::setNan( &fRet );
483 : }
484 : else
485 : {
486 : // #i70133# always return correct X position - needed for short data series
487 36241 : if( 0<=index /*&& index < m_nPointCount*/ )
488 36241 : fRet = index+1;//first category (index 0) matches with real number 1.0
489 : else
490 0 : ::rtl::math::setNan( &fRet );
491 : }
492 36547 : lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() );
493 36547 : return fRet;
494 : }
495 :
496 22906 : double VDataSeries::getYValue( sal_Int32 index ) const
497 : {
498 22906 : double fRet = 0.0;
499 22906 : if(m_aValues_Y.is())
500 : {
501 22906 : if( 0<=index && index<m_aValues_Y.getLength() )
502 22906 : fRet = m_aValues_Y.Doubles[index];
503 : else
504 0 : ::rtl::math::setNan( &fRet );
505 : }
506 : else
507 : {
508 : // #i70133# always return correct X position - needed for short data series
509 0 : if( 0<=index /*&& index < m_nPointCount*/ )
510 0 : fRet = index+1;//first category (index 0) matches with real number 1.0
511 : else
512 0 : ::rtl::math::setNan( &fRet );
513 : }
514 22906 : lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() );
515 22906 : return fRet;
516 : }
517 :
518 0 : void VDataSeries::getMinMaxXValue(double& fMin, double& fMax) const
519 : {
520 0 : rtl::math::setNan( &fMax );
521 0 : rtl::math::setNan( &fMin );
522 :
523 0 : uno::Sequence< double > aValuesX = getAllX();
524 :
525 0 : if(aValuesX.getLength() > 0)
526 : {
527 : double aValue;
528 :
529 0 : fMax = fMin = aValuesX[0];
530 :
531 0 : for (sal_Int32 i = 1; i < aValuesX.getLength(); i++)
532 : {
533 0 : aValue = aValuesX[i];
534 0 : if ( aValue > fMax)
535 : {
536 0 : fMax = aValue;
537 : }
538 0 : else if ( aValue < fMin)
539 : {
540 0 : fMin = aValue;
541 : }
542 : }
543 0 : }
544 0 : }
545 90 : double VDataSeries::getY_Min( sal_Int32 index ) const
546 : {
547 90 : return m_aValues_Y_Min.getValue( index );
548 : }
549 90 : double VDataSeries::getY_Max( sal_Int32 index ) const
550 : {
551 90 : return m_aValues_Y_Max.getValue( index );
552 : }
553 90 : double VDataSeries::getY_First( sal_Int32 index ) const
554 : {
555 90 : return m_aValues_Y_First.getValue( index );
556 : }
557 90 : double VDataSeries::getY_Last( sal_Int32 index ) const
558 : {
559 90 : return m_aValues_Y_Last.getValue( index );
560 : }
561 0 : double VDataSeries::getBubble_Size( sal_Int32 index ) const
562 : {
563 0 : return m_aValues_Bubble_Size.getValue( index );
564 : }
565 :
566 908 : bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const
567 : {
568 908 : OUString aPropName = bForPercentage ? OUString("PercentageNumberFormat") : OUString("NumberFormat");
569 908 : bool bHasNumberFormat = false;
570 1816 : uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( nPointIndex ));
571 908 : sal_Int32 nNumberFormat = -1;
572 908 : if( xPointProp.is() && (xPointProp->getPropertyValue(aPropName) >>= nNumberFormat) )
573 0 : bHasNumberFormat = true;
574 1816 : return bHasNumberFormat;
575 : }
576 0 : sal_Int32 VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const
577 : {
578 0 : OUString aPropName = bForPercentage ? OUString("PercentageNumberFormat") : OUString("NumberFormat");
579 0 : sal_Int32 nNumberFormat = -1;
580 0 : uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( nPointIndex ));
581 0 : if( xPointProp.is() )
582 0 : xPointProp->getPropertyValue(aPropName) >>= nNumberFormat;
583 0 : return nNumberFormat;
584 : }
585 1757 : void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( const OUString& rRole )
586 : {
587 1757 : if (rRole == "values-y")
588 1747 : m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y;
589 10 : else if (rRole == "values-size")
590 0 : m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Bubble_Size;
591 10 : else if (rRole == "values-min")
592 0 : m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Min;
593 10 : else if (rRole == "values-max")
594 0 : m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Max;
595 10 : else if (rRole == "values-first")
596 0 : m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_First;
597 10 : else if (rRole == "values-last")
598 10 : m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Last;
599 0 : else if (rRole == "values-x")
600 0 : m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_X;
601 1757 : }
602 858 : bool VDataSeries::shouldLabelNumberFormatKeyBeDetectedFromYAxis() const
603 : {
604 858 : if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_Bubble_Size )
605 0 : return false;
606 858 : else if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_X )
607 0 : return false;
608 858 : return true;
609 : }
610 858 : sal_Int32 VDataSeries::detectNumberFormatKey( sal_Int32 index ) const
611 : {
612 858 : sal_Int32 nRet = 0;
613 858 : if( m_pValueSequenceForDataLabelNumberFormatDetection )
614 858 : nRet = m_pValueSequenceForDataLabelNumberFormatDetection->detectNumberFormatKey( index );
615 858 : return nRet;
616 : }
617 :
618 905 : sal_Int32 VDataSeries::getLabelPlacement( sal_Int32 nPointIndex, const uno::Reference< chart2::XChartType >& xChartType, sal_Int32 nDimensionCount, sal_Bool bSwapXAndY ) const
619 : {
620 905 : sal_Int32 nLabelPlacement=0;
621 : try
622 : {
623 905 : uno::Reference< beans::XPropertySet > xPointProps( this->getPropertiesOfPoint( nPointIndex ) );
624 905 : if( xPointProps.is() )
625 905 : xPointProps->getPropertyValue("LabelPlacement") >>= nLabelPlacement;
626 :
627 : //ensure that the set label placement is supported by this charttype
628 :
629 : uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
630 905 : xChartType, nDimensionCount, bSwapXAndY, m_xDataSeries ) );
631 :
632 5555 : for( sal_Int32 nN = 0; nN < aAvailablePlacements.getLength(); nN++ )
633 4650 : if( aAvailablePlacements[nN] == nLabelPlacement )
634 0 : return nLabelPlacement; //ok
635 :
636 : //otherwise use the first supported one
637 905 : if( aAvailablePlacements.getLength() )
638 : {
639 905 : nLabelPlacement = aAvailablePlacements[0];
640 905 : return nLabelPlacement;
641 : }
642 :
643 0 : OSL_FAIL("no label placement supported");
644 : }
645 0 : catch( const uno::Exception& e )
646 : {
647 : ASSERT_EXCEPTION( e );
648 : }
649 0 : return nLabelPlacement;
650 : }
651 :
652 7094 : double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index ) const
653 : {
654 7094 : double fMin=0.0;
655 7094 : ::rtl::math::setInf(&fMin, false);
656 :
657 7154 : if( !m_aValues_Y.is() &&
658 30 : (m_aValues_Y_Min.is() || m_aValues_Y_Max.is()
659 0 : || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) )
660 : {
661 30 : double fY_Min = getY_Min( index );
662 30 : double fY_Max = getY_Max( index );
663 30 : double fY_First = getY_First( index );
664 30 : double fY_Last = getY_Last( index );
665 :
666 30 : if(fMin>fY_First)
667 0 : fMin=fY_First;
668 30 : if(fMin>fY_Last)
669 24 : fMin=fY_Last;
670 30 : if(fMin>fY_Min)
671 20 : fMin=fY_Min;
672 30 : if(fMin>fY_Max)
673 8 : fMin=fY_Max;
674 : }
675 : else
676 : {
677 7064 : double fY = getYValue( index );
678 7064 : if(fMin>fY)
679 7048 : fMin=fY;
680 : }
681 :
682 7094 : if( ::rtl::math::isInf(fMin) )
683 16 : ::rtl::math::setNan(&fMin);
684 :
685 7094 : return fMin;
686 : }
687 :
688 7094 : double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index ) const
689 : {
690 7094 : double fMax=0.0;
691 7094 : ::rtl::math::setInf(&fMax, true);
692 :
693 7154 : if( !m_aValues_Y.is() &&
694 30 : (m_aValues_Y_Min.is() || m_aValues_Y_Max.is()
695 0 : || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) )
696 : {
697 30 : double fY_Min = getY_Min( index );
698 30 : double fY_Max = getY_Max( index );
699 30 : double fY_First = getY_First( index );
700 30 : double fY_Last = getY_Last( index );
701 :
702 30 : if(fMax<fY_First)
703 0 : fMax=fY_First;
704 30 : if(fMax<fY_Last)
705 24 : fMax=fY_Last;
706 30 : if(fMax<fY_Min)
707 16 : fMax=fY_Min;
708 30 : if(fMax<fY_Max)
709 8 : fMax=fY_Max;
710 : }
711 : else
712 : {
713 7064 : double fY = getYValue( index );
714 7064 : if(fMax<fY)
715 7048 : fMax=fY;
716 : }
717 :
718 7094 : if( ::rtl::math::isInf(fMax) )
719 16 : ::rtl::math::setNan(&fMax);
720 :
721 7094 : return fMax;
722 : }
723 :
724 21 : uno::Sequence< double > VDataSeries::getAllX() const
725 : {
726 21 : if(!m_aValues_X.is() && !m_aValues_X.getLength() && m_nPointCount)
727 : {
728 : //init x values from category indexes
729 : //first category (index 0) matches with real number 1.0
730 21 : m_aValues_X.Doubles.realloc( m_nPointCount );
731 270 : for(sal_Int32 nN=m_aValues_X.getLength();nN--;)
732 228 : m_aValues_X.Doubles[nN] = nN+1;
733 : }
734 21 : return m_aValues_X.Doubles;
735 : }
736 :
737 155 : uno::Sequence< double > VDataSeries::getAllY() const
738 : {
739 155 : if(!m_aValues_Y.is() && !m_aValues_Y.getLength() && m_nPointCount)
740 : {
741 : //init y values from indexes
742 : //first y-value (index 0) matches with real number 1.0
743 0 : m_aValues_Y.Doubles.realloc( m_nPointCount );
744 0 : for(sal_Int32 nN=m_aValues_Y.getLength();nN--;)
745 0 : m_aValues_Y.Doubles[nN] = nN+1;
746 : }
747 155 : return m_aValues_Y.Doubles;
748 : }
749 :
750 0 : double VDataSeries::getXMeanValue() const
751 : {
752 0 : if( ::rtl::math::isNan( m_fXMeanValue ) )
753 : {
754 0 : uno::Reference< XRegressionCurveCalculator > xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( "com.sun.star.chart2.MeanValueRegressionCurve" ) );
755 0 : uno::Sequence< double > aXValuesDummy;
756 0 : xCalculator->recalculateRegression( aXValuesDummy, getAllX() );
757 0 : double fXDummy = 1.0;
758 0 : m_fXMeanValue = xCalculator->getCurveValue( fXDummy );
759 : }
760 0 : return m_fXMeanValue;
761 : }
762 :
763 0 : double VDataSeries::getYMeanValue() const
764 : {
765 0 : if( ::rtl::math::isNan( m_fYMeanValue ) )
766 : {
767 : uno::Reference< XRegressionCurveCalculator > xCalculator(
768 0 : RegressionCurveHelper::createRegressionCurveCalculatorByServiceName("com.sun.star.chart2.MeanValueRegressionCurve"));
769 0 : uno::Sequence< double > aXValuesDummy;
770 0 : xCalculator->recalculateRegression( aXValuesDummy, getAllY() );
771 0 : double fXDummy = 1.0;
772 0 : m_fYMeanValue = xCalculator->getCurveValue( fXDummy );
773 : }
774 0 : return m_fYMeanValue;
775 : }
776 :
777 142 : Symbol* getSymbolPropertiesFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp )
778 : {
779 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
780 142 : ::std::auto_ptr< Symbol > apSymbolProps( new Symbol() );
781 : SAL_WNODEPRECATED_DECLARATIONS_POP
782 : try
783 : {
784 142 : if( xProp->getPropertyValue("Symbol") >>= *apSymbolProps )
785 : {
786 : //use main color to fill symbols
787 142 : xProp->getPropertyValue("Color") >>= apSymbolProps->FillColor;
788 : // border of symbols always same as fill color
789 142 : apSymbolProps->BorderColor = apSymbolProps->FillColor;
790 : }
791 : else
792 0 : apSymbolProps.reset();
793 : }
794 0 : catch(const uno::Exception &e)
795 : {
796 : ASSERT_EXCEPTION( e );
797 : }
798 142 : return apSymbolProps.release();
799 : }
800 :
801 988 : Symbol* VDataSeries::getSymbolProperties( sal_Int32 index ) const
802 : {
803 988 : Symbol* pRet=NULL;
804 988 : if( isAttributedDataPoint( index ) )
805 : {
806 0 : adaptPointCache( index );
807 0 : if (!m_apSymbolProperties_AttributedPoint)
808 : m_apSymbolProperties_AttributedPoint.reset(
809 0 : getSymbolPropertiesFromPropertySet(this->getPropertiesOfPoint(index)));
810 0 : pRet = m_apSymbolProperties_AttributedPoint.get();
811 : //if a single data point does not have symbols but the dataseries itself has symbols
812 : //we create an invisible symbol shape to enable selection of that point
813 0 : if( !pRet || pRet->Style == SymbolStyle_NONE )
814 : {
815 0 : if (!m_apSymbolProperties_Series)
816 : m_apSymbolProperties_Series.reset(
817 0 : getSymbolPropertiesFromPropertySet(this->getPropertiesOfSeries()));
818 0 : if( m_apSymbolProperties_Series.get() && m_apSymbolProperties_Series->Style != SymbolStyle_NONE )
819 : {
820 0 : if (!m_apSymbolProperties_InvisibleSymbolForSelection)
821 : {
822 0 : m_apSymbolProperties_InvisibleSymbolForSelection.reset(new Symbol);
823 0 : m_apSymbolProperties_InvisibleSymbolForSelection->Style = SymbolStyle_STANDARD;
824 0 : m_apSymbolProperties_InvisibleSymbolForSelection->StandardSymbol = 0;//square
825 0 : m_apSymbolProperties_InvisibleSymbolForSelection->Size = m_apSymbolProperties_Series->Size;
826 0 : m_apSymbolProperties_InvisibleSymbolForSelection->BorderColor = 0xff000000;//invisible
827 0 : m_apSymbolProperties_InvisibleSymbolForSelection->FillColor = 0xff000000;//invisible
828 : }
829 0 : pRet = m_apSymbolProperties_InvisibleSymbolForSelection.get();
830 : }
831 : }
832 : }
833 : else
834 : {
835 988 : if (!m_apSymbolProperties_Series)
836 : m_apSymbolProperties_Series.reset(
837 142 : getSymbolPropertiesFromPropertySet(this->getPropertiesOfSeries()));
838 988 : pRet = m_apSymbolProperties_Series.get();
839 : }
840 :
841 988 : if( pRet && pRet->Style == SymbolStyle_AUTO )
842 : {
843 2 : pRet->Style = SymbolStyle_STANDARD;
844 :
845 2 : sal_Int32 nIndex = m_nGlobalSeriesIndex;
846 2 : if(m_aValues_X.is())
847 2 : nIndex++;
848 2 : pRet->StandardSymbol = nIndex;
849 : }
850 :
851 988 : return pRet;
852 : }
853 :
854 1081 : uno::Reference< beans::XPropertySet > VDataSeries::getXErrorBarProperties( sal_Int32 index ) const
855 : {
856 1081 : uno::Reference< beans::XPropertySet > xErrorBarProp;
857 :
858 2162 : uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( index ));
859 1081 : if( xPointProp.is() )
860 1081 : xPointProp->getPropertyValue("ErrorBarX") >>= xErrorBarProp;
861 2162 : return xErrorBarProp;
862 : }
863 :
864 7195 : uno::Reference< beans::XPropertySet > VDataSeries::getYErrorBarProperties( sal_Int32 index ) const
865 : {
866 7195 : uno::Reference< beans::XPropertySet > xErrorBarProp;
867 :
868 14390 : uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( index ));
869 7195 : if( xPointProp.is() )
870 7195 : xPointProp->getPropertyValue("ErrorBarY") >>= xErrorBarProp;
871 14390 : return xErrorBarProp;
872 : }
873 :
874 134 : bool VDataSeries::hasPointOwnColor( sal_Int32 index ) const
875 : {
876 134 : if( !isAttributedDataPoint(index) )
877 134 : return false;
878 :
879 : try
880 : {
881 0 : uno::Reference< beans::XPropertyState > xPointState( this->getPropertiesOfPoint(index), uno::UNO_QUERY_THROW );
882 0 : return (xPointState->getPropertyState("Color") != beans::PropertyState_DEFAULT_VALUE );
883 : }
884 0 : catch(const uno::Exception& e)
885 : {
886 : ASSERT_EXCEPTION( e );
887 : }
888 0 : return false;
889 : }
890 :
891 38042 : bool VDataSeries::isAttributedDataPoint( sal_Int32 index ) const
892 : {
893 : //returns true if the data point assigned by the given index has set it's own properties
894 38042 : if( index>=m_nPointCount || m_nPointCount==0)
895 0 : return false;
896 77709 : for(sal_Int32 nN=m_aAttributedDataPointIndexList.getLength();nN--;)
897 : {
898 3128 : if(index==m_aAttributedDataPointIndexList[nN])
899 1503 : return true;
900 : }
901 36539 : return false;
902 : }
903 :
904 2195 : bool VDataSeries::isVaryColorsByPoint() const
905 : {
906 2195 : bool bVaryColorsByPoint = false;
907 2195 : Reference< beans::XPropertySet > xSeriesProp( this->getPropertiesOfSeries() );
908 2195 : if( xSeriesProp.is() )
909 2195 : xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint;
910 2195 : return bVaryColorsByPoint;
911 : }
912 :
913 20113 : uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfPoint( sal_Int32 index ) const
914 : {
915 20113 : if( isAttributedDataPoint( index ) )
916 1003 : return m_xDataSeries->getDataPointByIndex(index);
917 19110 : return this->getPropertiesOfSeries();
918 : }
919 :
920 23664 : uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfSeries() const
921 : {
922 23664 : return uno::Reference<beans::XPropertySet>(m_xDataSeries, uno::UNO_QUERY );
923 : }
924 :
925 1843 : DataPointLabel* getDataPointLabelFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp )
926 : {
927 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
928 1843 : ::std::auto_ptr< DataPointLabel > apLabel( new DataPointLabel() );
929 : SAL_WNODEPRECATED_DECLARATIONS_POP
930 : try
931 : {
932 1843 : if( !(xProp->getPropertyValue("Label") >>= *apLabel) )
933 0 : apLabel.reset();
934 : }
935 0 : catch(const uno::Exception &e)
936 : {
937 : ASSERT_EXCEPTION( e );
938 : }
939 1843 : return apLabel.release();
940 : }
941 :
942 375 : void VDataSeries::adaptPointCache( sal_Int32 nNewPointIndex ) const
943 : {
944 375 : if( m_nCurrentAttributedPoint != nNewPointIndex )
945 : {
946 125 : m_apLabel_AttributedPoint.reset();
947 125 : m_apLabelPropNames_AttributedPoint.reset();
948 125 : m_apLabelPropValues_AttributedPoint.reset();
949 125 : m_apSymbolProperties_AttributedPoint.reset();
950 125 : m_nCurrentAttributedPoint = nNewPointIndex;
951 : }
952 375 : }
953 :
954 8787 : DataPointLabel* VDataSeries::getDataPointLabel( sal_Int32 index ) const
955 : {
956 8787 : DataPointLabel* pRet = NULL;
957 8787 : if( isAttributedDataPoint( index ) )
958 : {
959 250 : adaptPointCache( index );
960 250 : if( !m_apLabel_AttributedPoint.get() )
961 : m_apLabel_AttributedPoint.reset(
962 125 : getDataPointLabelFromPropertySet(this->getPropertiesOfPoint(index)));
963 250 : pRet = m_apLabel_AttributedPoint.get();
964 : }
965 : else
966 : {
967 8537 : if (!m_apLabel_Series)
968 : m_apLabel_Series.reset(
969 1718 : getDataPointLabelFromPropertySet(this->getPropertiesOfPoint(index)));
970 8537 : pRet = m_apLabel_Series.get();
971 : }
972 8787 : if( !m_bAllowPercentValueInDataLabel )
973 : {
974 85 : if( pRet )
975 85 : pRet->ShowNumberInPercent = false;
976 : }
977 8787 : return pRet;
978 : }
979 :
980 8787 : DataPointLabel* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index ) const
981 : {
982 8787 : DataPointLabel* pLabel = this->getDataPointLabel( index );
983 8787 : if( !pLabel || (!pLabel->ShowNumber && !pLabel->ShowNumberInPercent
984 6360 : && !pLabel->ShowCategoryName ) )
985 6314 : return 0;
986 2473 : return pLabel;
987 : }
988 :
989 905 : bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index
990 : , tNameSequence*& pPropNames
991 : , tAnySequence*& pPropValues ) const
992 : {
993 905 : pPropNames = NULL; pPropValues = NULL;
994 905 : uno::Reference< beans::XPropertySet > xTextProp;
995 905 : bool bDoDynamicFontResize = false;
996 905 : if( isAttributedDataPoint( index ) )
997 : {
998 125 : adaptPointCache( index );
999 125 : if (!m_apLabelPropValues_AttributedPoint)
1000 : {
1001 125 : m_apLabelPropNames_AttributedPoint.reset(new tNameSequence);
1002 125 : m_apLabelPropValues_AttributedPoint.reset(new tAnySequence);
1003 125 : xTextProp.set( this->getPropertiesOfPoint( index ));
1004 : PropertyMapper::getTextLabelMultiPropertyLists(
1005 125 : xTextProp, *m_apLabelPropNames_AttributedPoint, *m_apLabelPropValues_AttributedPoint);
1006 125 : bDoDynamicFontResize = true;
1007 : }
1008 125 : pPropNames = m_apLabelPropNames_AttributedPoint.get();
1009 125 : pPropValues = m_apLabelPropValues_AttributedPoint.get();
1010 : }
1011 : else
1012 : {
1013 780 : if (!m_apLabelPropValues_Series)
1014 : {
1015 60 : m_apLabelPropNames_Series.reset(new tNameSequence);
1016 60 : m_apLabelPropValues_Series.reset(new tAnySequence);
1017 60 : xTextProp.set( this->getPropertiesOfPoint( index ));
1018 : PropertyMapper::getTextLabelMultiPropertyLists(
1019 60 : xTextProp, *m_apLabelPropNames_Series, *m_apLabelPropValues_Series);
1020 60 : bDoDynamicFontResize = true;
1021 : }
1022 780 : pPropNames = m_apLabelPropNames_Series.get();
1023 780 : pPropValues = m_apLabelPropValues_Series.get();
1024 : }
1025 :
1026 1090 : if( bDoDynamicFontResize &&
1027 1275 : pPropNames && pPropValues &&
1028 185 : xTextProp.is())
1029 : {
1030 185 : LabelPositionHelper::doDynamicFontResize( *pPropValues, *pPropNames, xTextProp, m_aReferenceSize );
1031 : }
1032 905 : if(pPropNames&&pPropValues)
1033 905 : return true;
1034 0 : return false;
1035 : }
1036 :
1037 1757 : void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment )
1038 : {
1039 1757 : m_nMissingValueTreatment = nMissingValueTreatment;
1040 1757 : }
1041 :
1042 59453 : sal_Int32 VDataSeries::getMissingValueTreatment() const
1043 : {
1044 59453 : return m_nMissingValueTreatment;
1045 : }
1046 :
1047 : } //namespace chart
1048 :
1049 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|