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