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