1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "VDataSeries.hxx"
21 #include "ObjectIdentifier.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 #include <unonames.hxx>
31 #include <com/sun/star/chart/MissingValueTreatment.hpp>
32 #include <com/sun/star/chart2/Symbol.hpp>
34 #include <rtl/math.hxx>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/beans/XPropertyState.hpp>
37 #include <com/sun/star/drawing/LineStyle.hpp>
38 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
39 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
40 #include <com/sun/star/text/WritingMode.hpp>
41 #include <com/sun/star/chart2/data/XDataSource.hpp>
45 using namespace ::com::sun::star
;
46 using namespace ::com::sun::star::chart2
;
47 using ::com::sun::star::uno::Reference
;
49 void VDataSequence::init( const uno::Reference
< data::XDataSequence
>& xModel
)
52 Doubles
= DataSequenceToDoubleSequence( xModel
);
55 bool VDataSequence::is() const
59 void VDataSequence::clear()
65 double VDataSequence::getValue( sal_Int32 index
) const
67 if( 0<=index
&& index
<Doubles
.getLength() )
68 return Doubles
[index
];
72 ::rtl::math::setNan( & fNan
);
77 sal_Int32
VDataSequence::detectNumberFormatKey( sal_Int32 index
) const
79 sal_Int32 nNumberFormatKey
= -1;
81 // -1 is allowed and means a key for the whole sequence
82 if( -1<=index
&& index
<Doubles
.getLength() &&
85 nNumberFormatKey
= Model
->getNumberFormatKeyByIndex( index
);
88 return nNumberFormatKey
;
91 sal_Int32
VDataSequence::getLength() const
93 return Doubles
.getLength();
98 struct lcl_LessXOfPoint
100 inline bool operator() ( const std::vector
< double >& first
,
101 const std::vector
< double >& second
)
103 if( !first
.empty() && !second
.empty() )
105 return first
[0]<second
[0];
111 void lcl_clearIfNoValuesButTextIsContained( VDataSequence
& rData
, const uno::Reference
<data::XDataSequence
>& xDataSequence
)
113 //#i71686#, #i101968#, #i102428#
114 sal_Int32 nCount
= rData
.Doubles
.getLength();
115 for( sal_Int32 i
= 0; i
< nCount
; ++i
)
117 if( !::rtl::math::isNan( rData
.Doubles
[i
] ) )
120 //no double value is countained
122 uno::Sequence
< OUString
> aStrings( DataSequenceToStringSequence( xDataSequence
) );
123 sal_Int32 nTextCount
= aStrings
.getLength();
124 for( sal_Int32 j
= 0; j
< nTextCount
; ++j
)
126 if( !aStrings
[j
].isEmpty() )
135 void lcl_maybeReplaceNanWithZero( double& rfValue
, sal_Int32 nMissingValueTreatment
)
137 if( nMissingValueTreatment
== ::com::sun::star::chart::MissingValueTreatment::USE_ZERO
138 && (::rtl::math::isNan(rfValue
) || ::rtl::math::isInf(rfValue
)) )
144 VDataSeries::VDataSeries( const uno::Reference
< XDataSeries
>& xDataSeries
)
149 , m_xGroupShape(NULL
)
150 , m_xLabelsGroupShape(NULL
)
151 , m_xErrorXBarsGroupShape(NULL
)
152 , m_xErrorYBarsGroupShape(NULL
)
153 , m_xFrontSubGroupShape(NULL
)
154 , m_xBackSubGroupShape(NULL
)
155 , m_xDataSeries(xDataSeries
)
158 , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y
)
163 , m_aAttributedDataPointIndexList()
165 , m_eStackingDirection(StackingDirection_NO_STACKING
)
167 , m_bConnectBars(false)
168 , m_bGroupBarsPerAxis(true)
169 , m_nStartingAngle(90)
171 , m_nGlobalSeriesIndex(0)
173 , m_apLabel_Series(NULL
)
174 , m_apLabelPropNames_Series(NULL
)
175 , m_apLabelPropValues_Series(NULL
)
176 , m_apSymbolProperties_Series(NULL
)
178 , m_apLabel_AttributedPoint(NULL
)
179 , m_apLabelPropNames_AttributedPoint(NULL
)
180 , m_apLabelPropValues_AttributedPoint(NULL
)
181 , m_apSymbolProperties_AttributedPoint(NULL
)
182 , m_apSymbolProperties_InvisibleSymbolForSelection(NULL
)
183 , m_nCurrentAttributedPoint(-1)
184 , m_nMissingValueTreatment(::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP
)
185 , m_bAllowPercentValueInDataLabel(false)
189 ::rtl::math::setNan( & m_fXMeanValue
);
190 ::rtl::math::setNan( & m_fYMeanValue
);
192 uno::Reference
<data::XDataSource
> xDataSource
=
193 uno::Reference
<data::XDataSource
>( xDataSeries
, uno::UNO_QUERY
);
195 uno::Sequence
< uno::Reference
<
196 chart2::data::XLabeledDataSequence
> > aDataSequences
=
197 xDataSource
->getDataSequences();
199 for(sal_Int32 nN
= aDataSequences
.getLength();nN
--;)
201 if(!aDataSequences
[nN
].is())
203 uno::Reference
<data::XDataSequence
> xDataSequence( aDataSequences
[nN
]->getValues());
204 uno::Reference
<beans::XPropertySet
> xProp(xDataSequence
, uno::UNO_QUERY
);
209 uno::Any aARole
= xProp
->getPropertyValue("Role");
213 if (aRole
== "values-x")
215 m_aValues_X
.init( xDataSequence
);
216 lcl_clearIfNoValuesButTextIsContained( m_aValues_X
, xDataSequence
);
218 else if (aRole
=="values-y")
219 m_aValues_Y
.init( xDataSequence
);
220 else if (aRole
== "values-min")
221 m_aValues_Y_Min
.init( xDataSequence
);
222 else if (aRole
== "values-max")
223 m_aValues_Y_Max
.init( xDataSequence
);
224 else if (aRole
== "values-first")
225 m_aValues_Y_First
.init( xDataSequence
);
226 else if (aRole
== "values-last")
227 m_aValues_Y_Last
.init( xDataSequence
);
228 else if (aRole
== "values-size")
229 m_aValues_Bubble_Size
.init( xDataSequence
);
232 VDataSequence
* pSequence
= new VDataSequence();
233 pSequence
->init( xDataSequence
);
234 maPropertyMap
.insert(aRole
, pSequence
);
237 catch( const uno::Exception
& e
)
239 ASSERT_EXCEPTION( e
);
244 //determine the point count
245 m_nPointCount
= m_aValues_Y
.getLength();
247 if( m_nPointCount
< m_aValues_Bubble_Size
.getLength() )
248 m_nPointCount
= m_aValues_Bubble_Size
.getLength();
249 if( m_nPointCount
< m_aValues_Y_Min
.getLength() )
250 m_nPointCount
= m_aValues_Y_Min
.getLength();
251 if( m_nPointCount
< m_aValues_Y_Max
.getLength() )
252 m_nPointCount
= m_aValues_Y_Max
.getLength();
253 if( m_nPointCount
< m_aValues_Y_First
.getLength() )
254 m_nPointCount
= m_aValues_Y_First
.getLength();
255 if( m_nPointCount
< m_aValues_Y_Last
.getLength() )
256 m_nPointCount
= m_aValues_Y_Last
.getLength();
259 uno::Reference
<beans::XPropertySet
> xProp(xDataSeries
, uno::UNO_QUERY
);
264 //get AttributedDataPoints
265 xProp
->getPropertyValue("AttributedDataPoints") >>= m_aAttributedDataPointIndexList
;
267 xProp
->getPropertyValue("StackingDirection") >>= m_eStackingDirection
;
269 xProp
->getPropertyValue("AttachedAxisIndex") >>= m_nAxisIndex
;
273 catch( const uno::Exception
& e
)
275 ASSERT_EXCEPTION( e
);
280 VDataSeries::~VDataSeries()
284 void VDataSeries::doSortByXValues()
286 if( m_aValues_X
.is() && m_aValues_X
.Doubles
.getLength() )
288 //prepare a vector for sorting
289 std::vector
< ::std::vector
< double > > aTmp
;//outer vector are points, inner vector are the different values of athe point
291 ::rtl::math::setNan( & fNan
);
292 sal_Int32 nPointIndex
= 0;
293 for( nPointIndex
=0; nPointIndex
< m_nPointCount
; nPointIndex
++ )
295 std::vector
< double > aSinglePoint
;
296 aSinglePoint
.push_back( (nPointIndex
< m_aValues_X
.Doubles
.getLength()) ? m_aValues_X
.Doubles
[nPointIndex
] : fNan
);
297 aSinglePoint
.push_back( (nPointIndex
< m_aValues_Y
.Doubles
.getLength()) ? m_aValues_Y
.Doubles
[nPointIndex
] : fNan
);
298 aTmp
.push_back( aSinglePoint
);
302 std::stable_sort( aTmp
.begin(), aTmp
.end(), lcl_LessXOfPoint() );
304 //fill the sorted points back to the members
305 m_aValues_X
.Doubles
.realloc( m_nPointCount
);
306 m_aValues_Y
.Doubles
.realloc( m_nPointCount
);
308 for( nPointIndex
=0; nPointIndex
< m_nPointCount
; nPointIndex
++ )
310 m_aValues_X
.Doubles
[nPointIndex
]=aTmp
[nPointIndex
][0];
311 m_aValues_Y
.Doubles
[nPointIndex
]=aTmp
[nPointIndex
][1];
316 void VDataSeries::releaseShapes()
318 m_xGroupShape
.set(0);
319 m_xLabelsGroupShape
.set(0);
320 m_xErrorXBarsGroupShape
.set(0);
321 m_xErrorYBarsGroupShape
.set(0);
322 m_xFrontSubGroupShape
.set(0);
323 m_xBackSubGroupShape
.set(0);
325 m_aPolyPolygonShape3D
.SequenceX
.realloc(0);
326 m_aPolyPolygonShape3D
.SequenceY
.realloc(0);
327 m_aPolyPolygonShape3D
.SequenceZ
.realloc(0);
331 uno::Reference
<css::chart2::XDataSeries
> VDataSeries::getModel() const
333 return m_xDataSeries
;
336 void VDataSeries::setCategoryXAxis()
339 m_bAllowPercentValueInDataLabel
= true;
342 void VDataSeries::setXValues( const Reference
< chart2::data::XDataSequence
>& xValues
)
345 m_aValues_X
.init( xValues
);
346 m_bAllowPercentValueInDataLabel
= true;
349 void VDataSeries::setXValuesIfNone( const Reference
< chart2::data::XDataSequence
>& xValues
)
351 if( m_aValues_X
.is() )
354 m_aValues_X
.init( xValues
);
355 lcl_clearIfNoValuesButTextIsContained( m_aValues_X
, xValues
);
358 void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex
)
360 m_nGlobalSeriesIndex
= nGlobalSeriesIndex
;
363 void VDataSeries::setParticle( const OUString
& rSeriesParticle
)
365 m_aSeriesParticle
= rSeriesParticle
;
368 m_aCID
= ObjectIdentifier::createClassifiedIdentifierForParticle( m_aSeriesParticle
);
369 m_aPointCID_Stub
= ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
, m_aSeriesParticle
);
371 m_aLabelCID_Stub
= ObjectIdentifier::createClassifiedIdentifierWithParent(
372 OBJECTTYPE_DATA_LABEL
, OUString(), getLabelsCID() );
374 OUString
VDataSeries::getErrorBarsCID(bool bYError
) const
376 OUString
aChildParticle( ObjectIdentifier::getStringForType(
377 bYError
? OBJECTTYPE_DATA_ERRORS_Y
: OBJECTTYPE_DATA_ERRORS_X
) );
378 aChildParticle
+= "=";
380 return ObjectIdentifier::createClassifiedIdentifierForParticles(
381 m_aSeriesParticle
, aChildParticle
);
383 OUString
VDataSeries::getLabelsCID() const
385 OUString
aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS
) );
386 aChildParticle
+= "=";
388 return ObjectIdentifier::createClassifiedIdentifierForParticles(
389 m_aSeriesParticle
, aChildParticle
);
391 OUString
VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex
, bool bAverageLine
) const
394 aRet
= ObjectIdentifier::createDataCurveCID( m_aSeriesParticle
, nCurveIndex
, bAverageLine
);
398 OUString
VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex
) const
401 aRet
= ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle
, nCurveIndex
);
404 void VDataSeries::setPageReferenceSize( const awt::Size
& rPageRefSize
)
406 m_aReferenceSize
= rPageRefSize
;
409 void VDataSeries::setConnectBars( bool bConnectBars
)
411 m_bConnectBars
= bConnectBars
;
414 bool VDataSeries::getConnectBars() const
416 return m_bConnectBars
;
419 void VDataSeries::setGroupBarsPerAxis( bool bGroupBarsPerAxis
)
421 m_bGroupBarsPerAxis
= bGroupBarsPerAxis
;
424 bool VDataSeries::getGroupBarsPerAxis() const
426 return m_bGroupBarsPerAxis
;
429 void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle
)
431 m_nStartingAngle
= nStartingAngle
;
434 sal_Int32
VDataSeries::getStartingAngle() const
436 return m_nStartingAngle
;
439 chart2::StackingDirection
VDataSeries::getStackingDirection() const
441 return m_eStackingDirection
;
444 sal_Int32
VDataSeries::getAttachedAxisIndex() const
449 void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex
)
451 if( nAttachedAxisIndex
< 0 )
452 nAttachedAxisIndex
= 0;
453 m_nAxisIndex
= nAttachedAxisIndex
;
456 double VDataSeries::getXValue( sal_Int32 index
) const
461 if( 0<=index
&& index
<m_aValues_X
.getLength() )
463 fRet
= m_aValues_X
.Doubles
[index
];
464 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_X
.getLength())
466 double nOldVal
= mpOldSeries
->m_aValues_X
.Doubles
[index
];
467 fRet
= nOldVal
+ (fRet
- nOldVal
) * mnPercent
;
471 ::rtl::math::setNan( &fRet
);
475 // #i70133# always return correct X position - needed for short data series
476 if( 0<=index
/*&& index < m_nPointCount*/ )
477 fRet
= index
+1;//first category (index 0) matches with real number 1.0
479 ::rtl::math::setNan( &fRet
);
481 lcl_maybeReplaceNanWithZero( fRet
, getMissingValueTreatment() );
485 double VDataSeries::getYValue( sal_Int32 index
) const
490 if( 0<=index
&& index
<m_aValues_Y
.getLength() )
492 fRet
= m_aValues_Y
.Doubles
[index
];
493 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_Y
.getLength())
495 double nOldVal
= mpOldSeries
->m_aValues_Y
.Doubles
[index
];
496 fRet
= nOldVal
+ (fRet
- nOldVal
) * mnPercent
;
500 ::rtl::math::setNan( &fRet
);
504 // #i70133# always return correct X position - needed for short data series
505 if( 0<=index
/*&& index < m_nPointCount*/ )
506 fRet
= index
+1;//first category (index 0) matches with real number 1.0
508 ::rtl::math::setNan( &fRet
);
510 lcl_maybeReplaceNanWithZero( fRet
, getMissingValueTreatment() );
514 void VDataSeries::getMinMaxXValue(double& fMin
, double& fMax
) const
516 rtl::math::setNan( &fMax
);
517 rtl::math::setNan( &fMin
);
519 uno::Sequence
< double > aValuesX
= getAllX();
521 if(aValuesX
.getLength() > 0)
524 while ( i
< aValuesX
.getLength() && ::rtl::math::isNan( aValuesX
[i
] ) )
526 if ( i
< aValuesX
.getLength() )
527 fMax
= fMin
= aValuesX
[i
++];
529 for ( ; i
< aValuesX
.getLength(); i
++)
531 const double aValue
= aValuesX
[i
];
536 else if ( aValue
< fMin
)
543 double VDataSeries::getY_Min( sal_Int32 index
) const
545 return m_aValues_Y_Min
.getValue( index
);
547 double VDataSeries::getY_Max( sal_Int32 index
) const
549 return m_aValues_Y_Max
.getValue( index
);
551 double VDataSeries::getY_First( sal_Int32 index
) const
553 return m_aValues_Y_First
.getValue( index
);
555 double VDataSeries::getY_Last( sal_Int32 index
) const
557 return m_aValues_Y_Last
.getValue( index
);
559 double VDataSeries::getBubble_Size( sal_Int32 index
) const
561 double nNewVal
= m_aValues_Bubble_Size
.getValue( index
);
562 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_Bubble_Size
.getLength())
564 double nOldVal
= mpOldSeries
->m_aValues_Bubble_Size
.getValue( index
);
565 nNewVal
= nOldVal
+ (nNewVal
- nOldVal
) * mnPercent
;
571 bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex
, bool bForPercentage
) const
573 OUString aPropName
= bForPercentage
? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT
);
574 bool bHasNumberFormat
= false;
575 uno::Reference
< beans::XPropertySet
> xPointProp( this->getPropertiesOfPoint( nPointIndex
));
576 sal_Int32 nNumberFormat
= -1;
577 if( xPointProp
.is() && (xPointProp
->getPropertyValue(aPropName
) >>= nNumberFormat
) )
578 bHasNumberFormat
= true;
579 return bHasNumberFormat
;
581 sal_Int32
VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex
, bool bForPercentage
) const
583 OUString aPropName
= bForPercentage
? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT
);
584 sal_Int32 nNumberFormat
= -1;
585 uno::Reference
< beans::XPropertySet
> xPointProp( this->getPropertiesOfPoint( nPointIndex
));
586 if( xPointProp
.is() )
587 xPointProp
->getPropertyValue(aPropName
) >>= nNumberFormat
;
588 return nNumberFormat
;
590 void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( const OUString
& rRole
)
592 if (rRole
== "values-y")
593 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y
;
594 else if (rRole
== "values-size")
595 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Bubble_Size
;
596 else if (rRole
== "values-min")
597 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Min
;
598 else if (rRole
== "values-max")
599 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Max
;
600 else if (rRole
== "values-first")
601 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_First
;
602 else if (rRole
== "values-last")
603 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Last
;
604 else if (rRole
== "values-x")
605 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_X
;
607 bool VDataSeries::shouldLabelNumberFormatKeyBeDetectedFromYAxis() const
609 if( m_pValueSequenceForDataLabelNumberFormatDetection
== &m_aValues_Bubble_Size
)
611 else if( m_pValueSequenceForDataLabelNumberFormatDetection
== &m_aValues_X
)
615 sal_Int32
VDataSeries::detectNumberFormatKey( sal_Int32 index
) const
618 if( m_pValueSequenceForDataLabelNumberFormatDetection
)
619 nRet
= m_pValueSequenceForDataLabelNumberFormatDetection
->detectNumberFormatKey( index
);
623 sal_Int32
VDataSeries::getLabelPlacement( sal_Int32 nPointIndex
, const uno::Reference
< chart2::XChartType
>& xChartType
, sal_Int32 nDimensionCount
, bool bSwapXAndY
) const
625 sal_Int32 nLabelPlacement
=0;
628 uno::Reference
< beans::XPropertySet
> xPointProps( this->getPropertiesOfPoint( nPointIndex
) );
629 if( xPointProps
.is() )
630 xPointProps
->getPropertyValue("LabelPlacement") >>= nLabelPlacement
;
632 //ensure that the set label placement is supported by this charttype
634 uno::Sequence
< sal_Int32
> aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
635 xChartType
, nDimensionCount
, bSwapXAndY
, m_xDataSeries
) );
637 for( sal_Int32 nN
= 0; nN
< aAvailablePlacements
.getLength(); nN
++ )
638 if( aAvailablePlacements
[nN
] == nLabelPlacement
)
639 return nLabelPlacement
; //ok
641 //otherwise use the first supported one
642 if( aAvailablePlacements
.getLength() )
644 nLabelPlacement
= aAvailablePlacements
[0];
645 return nLabelPlacement
;
648 OSL_FAIL("no label placement supported");
650 catch( const uno::Exception
& e
)
652 ASSERT_EXCEPTION( e
);
654 return nLabelPlacement
;
657 double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index
) const
660 ::rtl::math::setInf(&fMin
, false);
662 if( !m_aValues_Y
.is() &&
663 (m_aValues_Y_Min
.is() || m_aValues_Y_Max
.is()
664 || m_aValues_Y_First
.is() || m_aValues_Y_Last
.is() ) )
666 double fY_Min
= getY_Min( index
);
667 double fY_Max
= getY_Max( index
);
668 double fY_First
= getY_First( index
);
669 double fY_Last
= getY_Last( index
);
682 double fY
= getYValue( index
);
687 if( ::rtl::math::isInf(fMin
) )
688 ::rtl::math::setNan(&fMin
);
693 double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index
) const
696 ::rtl::math::setInf(&fMax
, true);
698 if( !m_aValues_Y
.is() &&
699 (m_aValues_Y_Min
.is() || m_aValues_Y_Max
.is()
700 || m_aValues_Y_First
.is() || m_aValues_Y_Last
.is() ) )
702 double fY_Min
= getY_Min( index
);
703 double fY_Max
= getY_Max( index
);
704 double fY_First
= getY_First( index
);
705 double fY_Last
= getY_Last( index
);
718 double fY
= getYValue( index
);
723 if( ::rtl::math::isInf(fMax
) )
724 ::rtl::math::setNan(&fMax
);
729 uno::Sequence
< double > VDataSeries::getAllX() const
731 if(!m_aValues_X
.is() && !m_aValues_X
.getLength() && m_nPointCount
)
733 //init x values from category indexes
734 //first category (index 0) matches with real number 1.0
735 m_aValues_X
.Doubles
.realloc( m_nPointCount
);
736 for(sal_Int32 nN
=m_aValues_X
.getLength();nN
--;)
737 m_aValues_X
.Doubles
[nN
] = nN
+1;
739 return m_aValues_X
.Doubles
;
742 uno::Sequence
< double > VDataSeries::getAllY() const
744 if(!m_aValues_Y
.is() && !m_aValues_Y
.getLength() && m_nPointCount
)
746 //init y values from indexes
747 //first y-value (index 0) matches with real number 1.0
748 m_aValues_Y
.Doubles
.realloc( m_nPointCount
);
749 for(sal_Int32 nN
=m_aValues_Y
.getLength();nN
--;)
750 m_aValues_Y
.Doubles
[nN
] = nN
+1;
752 return m_aValues_Y
.Doubles
;
755 double VDataSeries::getXMeanValue() const
757 if( ::rtl::math::isNan( m_fXMeanValue
) )
759 uno::Reference
< XRegressionCurveCalculator
> xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( "com.sun.star.chart2.MeanValueRegressionCurve" ) );
760 uno::Sequence
< double > aXValuesDummy
;
761 xCalculator
->recalculateRegression( aXValuesDummy
, getAllX() );
762 double fXDummy
= 1.0;
763 m_fXMeanValue
= xCalculator
->getCurveValue( fXDummy
);
765 return m_fXMeanValue
;
768 double VDataSeries::getYMeanValue() const
770 if( ::rtl::math::isNan( m_fYMeanValue
) )
772 uno::Reference
< XRegressionCurveCalculator
> xCalculator(
773 RegressionCurveHelper::createRegressionCurveCalculatorByServiceName("com.sun.star.chart2.MeanValueRegressionCurve"));
774 uno::Sequence
< double > aXValuesDummy
;
775 xCalculator
->recalculateRegression( aXValuesDummy
, getAllY() );
776 double fXDummy
= 1.0;
777 m_fYMeanValue
= xCalculator
->getCurveValue( fXDummy
);
779 return m_fYMeanValue
;
782 Symbol
* getSymbolPropertiesFromPropertySet( const uno::Reference
< beans::XPropertySet
>& xProp
)
784 ::std::unique_ptr
< Symbol
> apSymbolProps( new Symbol() );
787 if( xProp
->getPropertyValue("Symbol") >>= *apSymbolProps
)
789 //use main color to fill symbols
790 xProp
->getPropertyValue("Color") >>= apSymbolProps
->FillColor
;
791 // border of symbols always same as fill color
792 apSymbolProps
->BorderColor
= apSymbolProps
->FillColor
;
795 apSymbolProps
.reset();
797 catch(const uno::Exception
&e
)
799 ASSERT_EXCEPTION( e
);
801 return apSymbolProps
.release();
804 Symbol
* VDataSeries::getSymbolProperties( sal_Int32 index
) const
807 if( isAttributedDataPoint( index
) )
809 adaptPointCache( index
);
810 if (!m_apSymbolProperties_AttributedPoint
)
811 m_apSymbolProperties_AttributedPoint
.reset(
812 getSymbolPropertiesFromPropertySet(this->getPropertiesOfPoint(index
)));
813 pRet
= m_apSymbolProperties_AttributedPoint
.get();
814 //if a single data point does not have symbols but the dataseries itself has symbols
815 //we create an invisible symbol shape to enable selection of that point
816 if( !pRet
|| pRet
->Style
== SymbolStyle_NONE
)
818 if (!m_apSymbolProperties_Series
)
819 m_apSymbolProperties_Series
.reset(
820 getSymbolPropertiesFromPropertySet(this->getPropertiesOfSeries()));
821 if( m_apSymbolProperties_Series
.get() && m_apSymbolProperties_Series
->Style
!= SymbolStyle_NONE
)
823 if (!m_apSymbolProperties_InvisibleSymbolForSelection
)
825 m_apSymbolProperties_InvisibleSymbolForSelection
.reset(new Symbol
);
826 m_apSymbolProperties_InvisibleSymbolForSelection
->Style
= SymbolStyle_STANDARD
;
827 m_apSymbolProperties_InvisibleSymbolForSelection
->StandardSymbol
= 0;//square
828 m_apSymbolProperties_InvisibleSymbolForSelection
->Size
= m_apSymbolProperties_Series
->Size
;
829 m_apSymbolProperties_InvisibleSymbolForSelection
->BorderColor
= 0xff000000;//invisible
830 m_apSymbolProperties_InvisibleSymbolForSelection
->FillColor
= 0xff000000;//invisible
832 pRet
= m_apSymbolProperties_InvisibleSymbolForSelection
.get();
838 if (!m_apSymbolProperties_Series
)
839 m_apSymbolProperties_Series
.reset(
840 getSymbolPropertiesFromPropertySet(this->getPropertiesOfSeries()));
841 pRet
= m_apSymbolProperties_Series
.get();
844 if( pRet
&& pRet
->Style
== SymbolStyle_AUTO
)
846 pRet
->Style
= SymbolStyle_STANDARD
;
848 sal_Int32 nIndex
= m_nGlobalSeriesIndex
;
851 pRet
->StandardSymbol
= nIndex
;
857 uno::Reference
< beans::XPropertySet
> VDataSeries::getXErrorBarProperties( sal_Int32 index
) const
859 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
861 uno::Reference
< beans::XPropertySet
> xPointProp( this->getPropertiesOfPoint( index
));
862 if( xPointProp
.is() )
863 xPointProp
->getPropertyValue(CHART_UNONAME_ERRORBAR_X
) >>= xErrorBarProp
;
864 return xErrorBarProp
;
867 uno::Reference
< beans::XPropertySet
> VDataSeries::getYErrorBarProperties( sal_Int32 index
) const
869 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
871 uno::Reference
< beans::XPropertySet
> xPointProp( this->getPropertiesOfPoint( index
));
872 if( xPointProp
.is() )
873 xPointProp
->getPropertyValue(CHART_UNONAME_ERRORBAR_Y
) >>= xErrorBarProp
;
874 return xErrorBarProp
;
877 bool VDataSeries::hasPointOwnColor( sal_Int32 index
) const
879 if( !isAttributedDataPoint(index
) )
884 uno::Reference
< beans::XPropertyState
> xPointState( this->getPropertiesOfPoint(index
), uno::UNO_QUERY_THROW
);
885 return (xPointState
->getPropertyState("Color") != beans::PropertyState_DEFAULT_VALUE
);
887 catch(const uno::Exception
& e
)
889 ASSERT_EXCEPTION( e
);
894 bool VDataSeries::isAttributedDataPoint( sal_Int32 index
) const
896 //returns true if the data point assigned by the given index has set it's own properties
897 if( index
>=m_nPointCount
|| m_nPointCount
==0)
899 for(sal_Int32 nN
=m_aAttributedDataPointIndexList
.getLength();nN
--;)
901 if(index
==m_aAttributedDataPointIndexList
[nN
])
907 bool VDataSeries::isVaryColorsByPoint() const
909 bool bVaryColorsByPoint
= false;
910 Reference
< beans::XPropertySet
> xSeriesProp( this->getPropertiesOfSeries() );
911 if( xSeriesProp
.is() )
912 xSeriesProp
->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint
;
913 return bVaryColorsByPoint
;
916 uno::Reference
< beans::XPropertySet
> VDataSeries::getPropertiesOfPoint( sal_Int32 index
) const
918 if( isAttributedDataPoint( index
) )
919 return m_xDataSeries
->getDataPointByIndex(index
);
920 return this->getPropertiesOfSeries();
923 uno::Reference
<beans::XPropertySet
> VDataSeries::getPropertiesOfSeries() const
925 return uno::Reference
<css::beans::XPropertySet
>(m_xDataSeries
, css::uno::UNO_QUERY
);
928 DataPointLabel
* getDataPointLabelFromPropertySet( const uno::Reference
< beans::XPropertySet
>& xProp
)
930 ::std::unique_ptr
< DataPointLabel
> apLabel( new DataPointLabel() );
933 if( !(xProp
->getPropertyValue(CHART_UNONAME_LABEL
) >>= *apLabel
) )
936 catch(const uno::Exception
&e
)
938 ASSERT_EXCEPTION( e
);
940 return apLabel
.release();
943 void VDataSeries::adaptPointCache( sal_Int32 nNewPointIndex
) const
945 if( m_nCurrentAttributedPoint
!= nNewPointIndex
)
947 m_apLabel_AttributedPoint
.reset();
948 m_apLabelPropNames_AttributedPoint
.reset();
949 m_apLabelPropValues_AttributedPoint
.reset();
950 m_apSymbolProperties_AttributedPoint
.reset();
951 m_nCurrentAttributedPoint
= nNewPointIndex
;
955 DataPointLabel
* VDataSeries::getDataPointLabel( sal_Int32 index
) const
957 DataPointLabel
* pRet
= NULL
;
958 if( isAttributedDataPoint( index
) )
960 adaptPointCache( index
);
961 if( !m_apLabel_AttributedPoint
.get() )
962 m_apLabel_AttributedPoint
.reset(
963 getDataPointLabelFromPropertySet(this->getPropertiesOfPoint(index
)));
964 pRet
= m_apLabel_AttributedPoint
.get();
968 if (!m_apLabel_Series
)
969 m_apLabel_Series
.reset(
970 getDataPointLabelFromPropertySet(this->getPropertiesOfPoint(index
)));
971 pRet
= m_apLabel_Series
.get();
973 if( !m_bAllowPercentValueInDataLabel
)
976 pRet
->ShowNumberInPercent
= false;
981 DataPointLabel
* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index
) const
983 DataPointLabel
* pLabel
= this->getDataPointLabel( index
);
984 if( !pLabel
|| (!pLabel
->ShowNumber
&& !pLabel
->ShowNumberInPercent
985 && !pLabel
->ShowCategoryName
) )
990 bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index
991 , tNameSequence
*& pPropNames
992 , tAnySequence
*& pPropValues
) const
994 pPropNames
= NULL
; pPropValues
= NULL
;
995 uno::Reference
< beans::XPropertySet
> xTextProp
;
996 bool bDoDynamicFontResize
= false;
997 if( isAttributedDataPoint( index
) )
999 adaptPointCache( index
);
1000 if (!m_apLabelPropValues_AttributedPoint
)
1002 // Cache these properties for this point.
1003 m_apLabelPropNames_AttributedPoint
.reset(new tNameSequence
);
1004 m_apLabelPropValues_AttributedPoint
.reset(new tAnySequence
);
1005 xTextProp
.set( this->getPropertiesOfPoint( index
));
1006 PropertyMapper::getTextLabelMultiPropertyLists(
1007 xTextProp
, *m_apLabelPropNames_AttributedPoint
, *m_apLabelPropValues_AttributedPoint
);
1008 bDoDynamicFontResize
= true;
1010 pPropNames
= m_apLabelPropNames_AttributedPoint
.get();
1011 pPropValues
= m_apLabelPropValues_AttributedPoint
.get();
1015 if (!m_apLabelPropValues_Series
)
1017 // Cache these properties for the whole series.
1018 m_apLabelPropNames_Series
.reset(new tNameSequence
);
1019 m_apLabelPropValues_Series
.reset(new tAnySequence
);
1020 xTextProp
.set( this->getPropertiesOfPoint( index
));
1021 PropertyMapper::getTextLabelMultiPropertyLists(
1022 xTextProp
, *m_apLabelPropNames_Series
, *m_apLabelPropValues_Series
);
1023 bDoDynamicFontResize
= true;
1025 pPropNames
= m_apLabelPropNames_Series
.get();
1026 pPropValues
= m_apLabelPropValues_Series
.get();
1029 if( bDoDynamicFontResize
&&
1030 pPropNames
&& pPropValues
&&
1033 LabelPositionHelper::doDynamicFontResize( *pPropValues
, *pPropNames
, xTextProp
, m_aReferenceSize
);
1036 return (pPropNames
&& pPropValues
);
1039 void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment
)
1041 m_nMissingValueTreatment
= nMissingValueTreatment
;
1044 sal_Int32
VDataSeries::getMissingValueTreatment() const
1046 return m_nMissingValueTreatment
;
1049 VDataSeries::VDataSeries()
1050 : m_nPolygonIndex(0)
1055 , m_pValueSequenceForDataLabelNumberFormatDetection(NULL
)
1058 , m_eStackingDirection(chart2::StackingDirection_NO_STACKING
)
1060 , m_bConnectBars(false)
1061 , m_bGroupBarsPerAxis(false)
1062 , m_nStartingAngle(0)
1063 , m_nGlobalSeriesIndex(0)
1064 , m_nCurrentAttributedPoint(0)
1065 , m_nMissingValueTreatment(0)
1066 , m_bAllowPercentValueInDataLabel(false)
1072 void VDataSeries::setOldTimeBased( VDataSeries
* pOldSeries
, double nPercent
)
1074 mnPercent
= nPercent
;
1075 mpOldSeries
= pOldSeries
;
1076 mpOldSeries
->mpOldSeries
= NULL
;
1079 VDataSeries
* VDataSeries::createCopyForTimeBased() const
1081 VDataSeries
* pNew
= new VDataSeries();
1082 pNew
->m_aValues_X
= m_aValues_X
;
1083 pNew
->m_aValues_Y
= m_aValues_Y
;
1084 pNew
->m_aValues_Z
= m_aValues_Z
;
1085 pNew
->m_aValues_Y_Min
= m_aValues_Y_Min
;
1086 pNew
->m_aValues_Y_Max
= m_aValues_Y_Max
;
1087 pNew
->m_aValues_Y_First
= m_aValues_Y_First
;
1088 pNew
->m_aValues_Y_Last
= m_aValues_Y_Last
;
1089 pNew
->m_aValues_Bubble_Size
= m_aValues_Bubble_Size
;
1090 pNew
->maPropertyMap
= maPropertyMap
;
1092 pNew
->m_nPointCount
= m_nPointCount
;
1097 double VDataSeries::getValueByProperty( sal_Int32 nIndex
, const OUString
& rPropName
) const
1099 boost::ptr_map
<OUString
, VDataSequence
>::const_iterator itr
=
1100 maPropertyMap
.find(rPropName
);
1101 if(itr
== maPropertyMap
.end())
1104 ::rtl::math::setNan( &fNan
);
1108 const VDataSequence
* pData
= itr
->second
;
1109 double fValue
= pData
->getValue(nIndex
);
1110 if(mpOldSeries
&& mpOldSeries
->hasPropertyMapping(rPropName
))
1112 double fOldValue
= mpOldSeries
->getValueByProperty( nIndex
, rPropName
);
1113 if(rPropName
.endsWith("Color"))
1115 //optimized interpolation for color values
1116 Color
aColor(static_cast<sal_uInt32
>(fValue
));
1117 Color
aOldColor(static_cast<sal_uInt32
>(fOldValue
));
1118 sal_uInt8 r
= aOldColor
.GetRed() + (aColor
.GetRed() - aOldColor
.GetRed()) * mnPercent
;
1119 sal_uInt8 g
= aOldColor
.GetGreen() + (aColor
.GetGreen() - aOldColor
.GetGreen()) * mnPercent
;
1120 sal_uInt8 b
= aOldColor
.GetBlue() + (aColor
.GetBlue() - aOldColor
.GetBlue()) * mnPercent
;
1121 sal_uInt8 t
= aOldColor
.GetTransparency() + (aColor
.GetTransparency() - aOldColor
.GetTransparency()) * mnPercent
;
1122 Color
aRet(t
, r
, g
, b
);
1123 return aRet
.GetColor();
1125 return fOldValue
+ (fValue
- fOldValue
) * mnPercent
;
1130 bool VDataSeries::hasPropertyMapping(const OUString
& rPropName
) const
1132 return maPropertyMap
.find(rPropName
) != maPropertyMap
.end();
1137 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */