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 "DataSeriesHelper.hxx"
27 #include "DiagramHelper.hxx"
28 #include "DataSource.hxx"
29 #include "macros.hxx"
30 #include "ContainerHelper.hxx"
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/chart2/DataPointLabel.hpp>
33 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
34 #include <com/sun/star/chart2/StackingDirection.hpp>
35 #include <com/sun/star/chart2/data/LabelOrigin.hpp>
36 #include <com/sun/star/chart2/AxisType.hpp>
37 #include <com/sun/star/chart2/SymbolStyle.hpp>
38 #include <com/sun/star/chart2/Symbol.hpp>
39 #include <com/sun/star/drawing/LineStyle.hpp>
40
41
42 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
43 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
44 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
45 #include <rtl/ustrbuf.hxx>
46
47 #include <functional>
48 #include <algorithm>
49 #include <iterator>
50 #include <vector>
51 #include <set>
52
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::chart2;
55
56 using ::com::sun::star::uno::Reference;
57 using ::com::sun::star::uno::Sequence;
58 using ::rtl::OUString;
59 using ::rtl::OUStringBuffer;
60
61 // ----------------------------------------
62 namespace
63 {
64
65 class lcl_MatchesRole : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool >
66 {
67 public:
lcl_MatchesRole(const OUString & aRole,bool bMatchPrefix)68 explicit lcl_MatchesRole( const OUString & aRole, bool bMatchPrefix ) :
69 m_aRole( aRole ),
70 m_bMatchPrefix( bMatchPrefix )
71 {}
72
operator ()(const Reference<chart2::data::XLabeledDataSequence> & xSeq) const73 bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const
74 {
75 if(!xSeq.is())
76 return false;
77 Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY );
78 OUString aRole;
79
80 if( m_bMatchPrefix )
81 return ( xProp.is() &&
82 (xProp->getPropertyValue(
83 OUString( RTL_CONSTASCII_USTRINGPARAM( "Role" )) ) >>= aRole ) &&
84 aRole.match( m_aRole ));
85
86 return ( xProp.is() &&
87 (xProp->getPropertyValue(
88 OUString( RTL_CONSTASCII_USTRINGPARAM( "Role" )) ) >>= aRole ) &&
89 m_aRole.equals( aRole ));
90 }
91
92 private:
93 OUString m_aRole;
94 bool m_bMatchPrefix;
95 };
96
lcl_findLSequenceWithOnlyLabel(const Reference<chart2::data::XDataSource> & xDataSource)97 Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel(
98 const Reference< chart2::data::XDataSource > & xDataSource )
99 {
100 Reference< chart2::data::XLabeledDataSequence > xResult;
101 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
102
103 for( sal_Int32 i=0; i<aSequences.getLength(); ++i )
104 {
105 OSL_ENSURE( aSequences[i].is(), "empty LabeledDataSequence" );
106 // no values are set but a label exists
107 if( aSequences[i].is() &&
108 ( ! aSequences[i]->getValues().is() &&
109 aSequences[i]->getLabel().is()))
110 {
111 xResult.set( aSequences[i] );
112 break;
113 }
114 }
115
116 return xResult;
117 }
118
lcl_getCooSysAndChartTypeOfSeries(const Reference<chart2::XDataSeries> & xSeries,const Reference<chart2::XDiagram> & xDiagram,Reference<chart2::XCoordinateSystem> & xOutCooSys,Reference<chart2::XChartType> & xOutChartType)119 void lcl_getCooSysAndChartTypeOfSeries(
120 const Reference< chart2::XDataSeries > & xSeries,
121 const Reference< chart2::XDiagram > & xDiagram,
122 Reference< chart2::XCoordinateSystem > & xOutCooSys,
123 Reference< chart2::XChartType > & xOutChartType )
124 {
125 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY );
126 if( xCooSysCnt.is())
127 {
128 Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
129 for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
130 {
131 Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
132 Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes());
133 for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx )
134 {
135 Reference< chart2::XDataSeriesContainer > xSeriesCnt( aChartTypes[nCTIdx], uno::UNO_QUERY );
136 if( xSeriesCnt.is())
137 {
138 Sequence< Reference< chart2::XDataSeries > > aSeries( xSeriesCnt->getDataSeries());
139 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeries.getLength(); ++nSeriesIdx )
140 {
141 if( aSeries[nSeriesIdx] == xSeries )
142 {
143 xOutCooSys.set( aCooSysSeq[nCooSysIdx] );
144 xOutChartType.set( aChartTypes[nCTIdx] );
145 }
146 }
147 }
148 }
149 }
150 }
151 }
152
lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints(const Reference<chart2::XDataSeries> & xSeries,bool bInsert)153 void lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries, bool bInsert )
154 {
155 try
156 {
157 Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY );
158 if( xSeriesProperties.is() )
159 {
160 DataPointLabel aLabelAtSeries;
161 xSeriesProperties->getPropertyValue( C2U( "Label" ) ) >>= aLabelAtSeries;
162 aLabelAtSeries.ShowNumber = bInsert;
163 if( !bInsert )
164 {
165 aLabelAtSeries.ShowNumberInPercent = false;
166 aLabelAtSeries.ShowCategoryName = false;
167 }
168 xSeriesProperties->setPropertyValue( C2U( "Label" ), uno::makeAny( aLabelAtSeries ) );
169 uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
170 if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
171 {
172 for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
173 {
174 Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) );
175 if( xPointProp.is() )
176 {
177 DataPointLabel aLabel;
178 xPointProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel;
179 aLabel.ShowNumber = bInsert;
180 if( !bInsert )
181 {
182 aLabel.ShowNumberInPercent = false;
183 aLabel.ShowCategoryName = false;
184 }
185 xPointProp->setPropertyValue( C2U( "Label" ), uno::makeAny( aLabel ) );
186 }
187 }
188 }
189 }
190 }
191 catch( uno::Exception &e)
192 {
193 ASSERT_EXCEPTION( e );
194 }
195 }
196
197 } // anonymous namespace
198 // ----------------------------------------
199
200 namespace chart
201 {
202
203 namespace DataSeriesHelper
204 {
205
GetRole(const uno::Reference<chart2::data::XLabeledDataSequence> & xLabeledDataSequence)206 OUString GetRole( const uno::Reference< chart2::data::XLabeledDataSequence >& xLabeledDataSequence )
207 {
208 OUString aRet;
209 if( xLabeledDataSequence.is() )
210 {
211 Reference< beans::XPropertySet > xProp( xLabeledDataSequence->getValues(), uno::UNO_QUERY );
212 if( xProp.is() )
213 xProp->getPropertyValue( C2U("Role") ) >>= aRet;
214 }
215 return aRet;
216 }
217
218 Reference< chart2::data::XLabeledDataSequence >
getDataSequenceByRole(const Reference<chart2::data::XDataSource> & xSource,OUString aRole,bool bMatchPrefix)219 getDataSequenceByRole(
220 const Reference< chart2::data::XDataSource > & xSource, OUString aRole,
221 bool bMatchPrefix /* = false */ )
222 {
223 Reference< chart2::data::XLabeledDataSequence > aNoResult;
224 if( ! xSource.is())
225 return aNoResult;
226 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq( xSource->getDataSequences());
227
228 const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray();
229 const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength();
230 const Reference< chart2::data::XLabeledDataSequence > * pMatch =
231 ::std::find_if( pBegin, pEnd, lcl_MatchesRole( aRole, bMatchPrefix ));
232
233 if( pMatch != pEnd )
234 return *pMatch;
235
236 return aNoResult;
237 }
238
239 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >
getAllDataSequencesByRole(const Sequence<Reference<chart2::data::XLabeledDataSequence>> & aDataSequences,OUString aRole,bool bMatchPrefix)240 getAllDataSequencesByRole( const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aDataSequences,
241 OUString aRole, bool bMatchPrefix /* = false */ )
242 {
243 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aResultVec;
244 ::std::remove_copy_if( aDataSequences.getConstArray(), aDataSequences.getConstArray() + aDataSequences.getLength(),
245 ::std::back_inserter( aResultVec ),
246 ::std::not1( lcl_MatchesRole( aRole, bMatchPrefix )));
247 return aResultVec;
248 }
249
250 Reference< chart2::data::XDataSource >
getDataSource(const Sequence<Reference<chart2::XDataSeries>> & aSeries)251 getDataSource( const Sequence< Reference< chart2::XDataSeries > > & aSeries )
252 {
253 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSeqVec;
254
255 for( sal_Int32 i = 0; i < aSeries.getLength(); ++i )
256 {
257 Reference< chart2::data::XDataSource > xSource( aSeries[ i ], uno::UNO_QUERY );
258 if( xSource.is())
259 {
260 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences());
261 ::std::copy( aSeq.getConstArray(), aSeq.getConstArray() + aSeq.getLength(),
262 ::std::back_inserter( aSeqVec ));
263 }
264 }
265
266 return Reference< chart2::data::XDataSource >(
267 new DataSource( ContainerHelper::ContainerToSequence( aSeqVec )));
268 }
269
270 namespace
271 {
lcl_getDataSequenceLabel(const Reference<chart2::data::XDataSequence> & xSequence)272 OUString lcl_getDataSequenceLabel( const Reference< chart2::data::XDataSequence > & xSequence )
273 {
274 OUString aResult;
275
276 Reference< chart2::data::XTextualDataSequence > xTextSeq( xSequence, uno::UNO_QUERY );
277 if( xTextSeq.is())
278 {
279 Sequence< OUString > aSeq( xTextSeq->getTextualData());
280
281 const sal_Int32 nMax = aSeq.getLength() - 1;
282 OUString aVal;
283 OUStringBuffer aBuf;
284
285 for( sal_Int32 i = 0; i <= nMax; ++i )
286 {
287 aBuf.append( aSeq[i] );
288 if( i < nMax )
289 aBuf.append( sal_Unicode( ' ' ));
290 }
291 aResult = aBuf.makeStringAndClear();
292 }
293 else if( xSequence.is())
294 {
295 Sequence< uno::Any > aSeq( xSequence->getData());
296
297 const sal_Int32 nMax = aSeq.getLength() - 1;
298 OUString aVal;
299 OUStringBuffer aBuf;
300 double fNum = 0;
301
302 for( sal_Int32 i = 0; i <= nMax; ++i )
303 {
304 if( aSeq[i] >>= aVal )
305 {
306 aBuf.append( aVal );
307 if( i < nMax )
308 aBuf.append( sal_Unicode( ' ' ));
309 }
310 else if( aSeq[ i ] >>= fNum )
311 {
312 aBuf.append( fNum );
313 if( i < nMax )
314 aBuf.append( sal_Unicode( ' ' ));
315 }
316 }
317 aResult = aBuf.makeStringAndClear();
318 }
319
320 return aResult;
321 }
322 }
323
getLabelForLabeledDataSequence(const Reference<chart2::data::XLabeledDataSequence> & xLabeledSeq)324 OUString getLabelForLabeledDataSequence(
325 const Reference< chart2::data::XLabeledDataSequence > & xLabeledSeq )
326 {
327 OUString aResult;
328 if( xLabeledSeq.is())
329 {
330 Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getLabel());
331 if( xSeq.is() )
332 aResult = lcl_getDataSequenceLabel( xSeq );
333 if( !xSeq.is() || aResult.isEmpty() )
334 {
335 // no label set or label content is empty -> use auto-generated one
336 Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() );
337 if( xValueSeq.is() )
338 {
339 Sequence< OUString > aLabels( xValueSeq->generateLabel(
340 chart2::data::LabelOrigin_SHORT_SIDE ) );
341 // no labels returned is interpreted as: auto-generation not
342 // supported by sequence
343 if( aLabels.getLength() )
344 aResult=aLabels[0];
345 else
346 {
347 //todo?: maybe use the index of the series as name
348 //but as the index may change it would be better to have such a name persistent
349 //what is not possible at the moment
350 //--> maybe use the identifier as part of the name ...
351 aResult = lcl_getDataSequenceLabel( xValueSeq );
352 }
353 }
354 }
355 }
356 return aResult;
357 }
358
getDataSeriesLabel(const Reference<chart2::XDataSeries> & xSeries,const OUString & rLabelSequenceRole)359 OUString getDataSeriesLabel(
360 const Reference< chart2::XDataSeries > & xSeries,
361 const OUString & rLabelSequenceRole )
362 {
363 OUString aResult;
364
365 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
366 if( xSource.is())
367 {
368 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
369 ::chart::DataSeriesHelper::getDataSequenceByRole( xSource, rLabelSequenceRole ));
370 if( xLabeledSeq.is())
371 aResult = getLabelForLabeledDataSequence( xLabeledSeq );
372 else
373 {
374 // special case: labeled data series with only a label and no values may
375 // serve as label
376 xLabeledSeq.set( lcl_findLSequenceWithOnlyLabel( xSource ));
377 if( xLabeledSeq.is())
378 {
379 Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getLabel());
380 if( xSeq.is())
381 aResult = lcl_getDataSequenceLabel( xSeq );
382 }
383 }
384
385 }
386
387 return aResult;
388 }
389
setStackModeAtSeries(const Sequence<Reference<chart2::XDataSeries>> & aSeries,const Reference<chart2::XCoordinateSystem> & xCorrespondingCoordinateSystem,StackMode eStackMode)390 void setStackModeAtSeries(
391 const Sequence< Reference< chart2::XDataSeries > > & aSeries,
392 const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem,
393 StackMode eStackMode )
394 {
395 if( eStackMode == StackMode_AMBIGUOUS )
396 return;
397
398 const OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( "StackingDirection" ));
399 const uno::Any aPropValue = uno::makeAny(
400 ( (eStackMode == StackMode_Y_STACKED) ||
401 (eStackMode == StackMode_Y_STACKED_PERCENT) )
402 ? chart2::StackingDirection_Y_STACKING
403 : (eStackMode == StackMode_Z_STACKED )
404 ? chart2::StackingDirection_Z_STACKING
405 : chart2::StackingDirection_NO_STACKING );
406
407 std::set< sal_Int32 > aAxisIndexSet;
408 for( sal_Int32 i=0; i<aSeries.getLength(); ++i )
409 {
410 try
411 {
412 Reference< beans::XPropertySet > xProp( aSeries[i], uno::UNO_QUERY );
413 if( xProp.is() )
414 {
415 xProp->setPropertyValue( aPropName, aPropValue );
416
417 sal_Int32 nAxisIndex;
418 xProp->getPropertyValue( C2U("AttachedAxisIndex") ) >>= nAxisIndex;
419 aAxisIndexSet.insert(nAxisIndex);
420 }
421 }
422 catch( uno::Exception & ex )
423 {
424 ASSERT_EXCEPTION( ex );
425 }
426 }
427
428 if( xCorrespondingCoordinateSystem.is() &&
429 1 < xCorrespondingCoordinateSystem->getDimension() )
430 {
431 sal_Int32 nAxisIndexCount = aAxisIndexSet.size();
432 if( !nAxisIndexCount )
433 {
434 aAxisIndexSet.insert(0);
435 nAxisIndexCount = aAxisIndexSet.size();
436 }
437
438 for( ::std::set< sal_Int32 >::const_iterator aIt = aAxisIndexSet.begin();
439 aIt != aAxisIndexSet.end(); ++aIt )
440 {
441 sal_Int32 nAxisIndex = *aIt;
442 Reference< chart2::XAxis > xAxis(
443 xCorrespondingCoordinateSystem->getAxisByDimension( 1, nAxisIndex ));
444 if( xAxis.is())
445 {
446 sal_Bool bPercent = (eStackMode == StackMode_Y_STACKED_PERCENT);
447 chart2::ScaleData aScaleData = xAxis->getScaleData();
448
449 if( bPercent != (aScaleData.AxisType==chart2::AxisType::PERCENT) )
450 {
451 if( bPercent )
452 aScaleData.AxisType = chart2::AxisType::PERCENT;
453 else
454 aScaleData.AxisType = chart2::AxisType::REALNUMBER;
455 xAxis->setScaleData( aScaleData );
456 }
457 }
458 }
459 }
460 }
461
getAttachedAxisIndex(const Reference<chart2::XDataSeries> & xSeries)462 sal_Int32 getAttachedAxisIndex( const Reference< chart2::XDataSeries > & xSeries )
463 {
464 sal_Int32 nRet = 0;
465 try
466 {
467 Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY );
468 if( xProp.is() )
469 {
470 xProp->getPropertyValue( C2U("AttachedAxisIndex") ) >>= nRet;
471 }
472 }
473 catch( uno::Exception & ex )
474 {
475 ASSERT_EXCEPTION( ex );
476 }
477 return nRet;
478 }
479
getNumberFormatKeyFromAxis(const Reference<chart2::XDataSeries> & xSeries,const Reference<chart2::XCoordinateSystem> & xCorrespondingCoordinateSystem,sal_Int32 nDimensionIndex,sal_Int32 nAxisIndex)480 sal_Int32 getNumberFormatKeyFromAxis(
481 const Reference< chart2::XDataSeries > & xSeries,
482 const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem,
483 sal_Int32 nDimensionIndex,
484 sal_Int32 nAxisIndex /* = -1 */ )
485 {
486 sal_Int32 nResult = 0;
487 if( nAxisIndex == -1 )
488 nAxisIndex = getAttachedAxisIndex( xSeries );
489 try
490 {
491 Reference< beans::XPropertySet > xAxisProp(
492 xCorrespondingCoordinateSystem->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY );
493 if( xAxisProp.is())
494 xAxisProp->getPropertyValue( C2U("NumberFormat")) >>= nResult;
495 }
496 catch( const uno::Exception & ex )
497 {
498 ASSERT_EXCEPTION( ex );
499 }
500
501 return nResult;
502 }
503
getCoordinateSystemOfSeries(const Reference<chart2::XDataSeries> & xSeries,const Reference<chart2::XDiagram> & xDiagram)504 Reference< chart2::XCoordinateSystem > getCoordinateSystemOfSeries(
505 const Reference< chart2::XDataSeries > & xSeries,
506 const Reference< chart2::XDiagram > & xDiagram )
507 {
508 Reference< chart2::XCoordinateSystem > xResult;
509 Reference< chart2::XChartType > xDummy;
510 lcl_getCooSysAndChartTypeOfSeries( xSeries, xDiagram, xResult, xDummy );
511
512 return xResult;
513 }
514
getChartTypeOfSeries(const Reference<chart2::XDataSeries> & xSeries,const Reference<chart2::XDiagram> & xDiagram)515 Reference< chart2::XChartType > getChartTypeOfSeries(
516 const Reference< chart2::XDataSeries > & xSeries,
517 const Reference< chart2::XDiagram > & xDiagram )
518 {
519 Reference< chart2::XChartType > xResult;
520 Reference< chart2::XCoordinateSystem > xDummy;
521 lcl_getCooSysAndChartTypeOfSeries( xSeries, xDiagram, xDummy, xResult );
522
523 return xResult;
524 }
525
deleteSeries(const Reference<chart2::XDataSeries> & xSeries,const Reference<chart2::XChartType> & xChartType)526 void deleteSeries(
527 const Reference< chart2::XDataSeries > & xSeries,
528 const Reference< chart2::XChartType > & xChartType )
529 {
530 try
531 {
532 Reference< chart2::XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY_THROW );
533 ::std::vector< Reference< chart2::XDataSeries > > aSeries(
534 ContainerHelper::SequenceToVector( xSeriesCnt->getDataSeries()));
535 ::std::vector< Reference< chart2::XDataSeries > >::iterator aIt =
536 ::std::find( aSeries.begin(), aSeries.end(), xSeries );
537 if( aIt != aSeries.end())
538 {
539 aSeries.erase( aIt );
540 xSeriesCnt->setDataSeries( ContainerHelper::ContainerToSequence( aSeries ));
541 }
542 }
543 catch( uno::Exception & ex )
544 {
545 ASSERT_EXCEPTION( ex );
546 }
547 }
548
switchSymbolsOnOrOff(const Reference<beans::XPropertySet> & xSeriesProperties,bool bSymbolsOn,sal_Int32 nSeriesIndex)549 void switchSymbolsOnOrOff( const Reference< beans::XPropertySet > & xSeriesProperties,
550 bool bSymbolsOn, sal_Int32 nSeriesIndex )
551 {
552 if( !xSeriesProperties.is() )
553 return;
554
555 chart2::Symbol aSymbProp;
556 if( (xSeriesProperties->getPropertyValue( C2U( "Symbol" )) >>= aSymbProp ) )
557 {
558 if( !bSymbolsOn )
559 aSymbProp.Style = chart2::SymbolStyle_NONE;
560 else if( aSymbProp.Style == chart2::SymbolStyle_NONE )
561 {
562 aSymbProp.Style = chart2::SymbolStyle_STANDARD;
563 aSymbProp.StandardSymbol = nSeriesIndex;
564 }
565 xSeriesProperties->setPropertyValue( C2U( "Symbol" ), uno::makeAny( aSymbProp ));
566 }
567 //todo: check attributed data points
568 }
569
switchLinesOnOrOff(const Reference<beans::XPropertySet> & xSeriesProperties,bool bLinesOn)570 void switchLinesOnOrOff( const Reference< beans::XPropertySet > & xSeriesProperties, bool bLinesOn )
571 {
572 if( !xSeriesProperties.is() )
573 return;
574
575 if( bLinesOn )
576 {
577 // keep line-styles that are not NONE
578 drawing::LineStyle eLineStyle;
579 if( (xSeriesProperties->getPropertyValue( C2U( "LineStyle" )) >>= eLineStyle ) &&
580 eLineStyle == drawing::LineStyle_NONE )
581 {
582 xSeriesProperties->setPropertyValue( C2U( "LineStyle" ), uno::makeAny( drawing::LineStyle_SOLID ) );
583 }
584 }
585 else
586 xSeriesProperties->setPropertyValue( C2U( "LineStyle" ), uno::makeAny( drawing::LineStyle_NONE ) );
587 }
588
makeLinesThickOrThin(const Reference<beans::XPropertySet> & xSeriesProperties,bool bThick)589 void makeLinesThickOrThin( const Reference< beans::XPropertySet > & xSeriesProperties, bool bThick )
590 {
591 if( !xSeriesProperties.is() )
592 return;
593
594 sal_Int32 nNewValue = bThick ? 80 : 0;
595 sal_Int32 nOldValue = 0;
596 if( (xSeriesProperties->getPropertyValue( C2U( "LineWidth" )) >>= nOldValue ) &&
597 nOldValue != nNewValue )
598 {
599 if( !(bThick && nOldValue>0))
600 xSeriesProperties->setPropertyValue( C2U( "LineWidth" ), uno::makeAny( nNewValue ) );
601 }
602 }
603
setPropertyAlsoToAllAttributedDataPoints(const Reference<chart2::XDataSeries> & xSeries,const OUString & rPropertyName,const uno::Any & rPropertyValue)604 void setPropertyAlsoToAllAttributedDataPoints( const Reference< chart2::XDataSeries >& xSeries,
605 const OUString& rPropertyName, const uno::Any& rPropertyValue )
606 {
607 Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY );
608 if( !xSeriesProperties.is() )
609 return;
610
611 xSeriesProperties->setPropertyValue( rPropertyName, rPropertyValue );
612 uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
613 if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
614 {
615 for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
616 {
617 Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) );
618 if(!xPointProp.is())
619 continue;
620 xPointProp->setPropertyValue( rPropertyName, rPropertyValue );
621 }
622 }
623 }
624
hasAttributedDataPointDifferentValue(const Reference<chart2::XDataSeries> & xSeries,const OUString & rPropertyName,const uno::Any & rPropertyValue)625 bool hasAttributedDataPointDifferentValue( const Reference< chart2::XDataSeries >& xSeries,
626 const OUString& rPropertyName, const uno::Any& rPropertyValue )
627 {
628 Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY );
629 if( !xSeriesProperties.is() )
630 return false;
631
632 uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
633 if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
634 {
635 for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
636 {
637 Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) );
638 if(!xPointProp.is())
639 continue;
640 uno::Any aPointValue( xPointProp->getPropertyValue( rPropertyName ) );
641 if( !( rPropertyValue==aPointValue ) )
642 return true;
643 }
644 }
645 return false;
646 }
647
areAllSeriesAttachedToSameAxis(const uno::Reference<chart2::XChartType> & xChartType,sal_Int32 & rOutAxisIndex)648 bool areAllSeriesAttachedToSameAxis( const uno::Reference< chart2::XChartType >& xChartType, sal_Int32 & rOutAxisIndex )
649 {
650 try
651 {
652 uno::Reference< chart2::XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY_THROW );
653 uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDataSeriesContainer->getDataSeries());
654
655 const sal_Int32 nSeriesCount( aSeriesSeq.getLength());
656 // AxisIndex can only be 0 or 1
657 sal_Int32 nSeriesAtFirstAxis = 0;
658 sal_Int32 nSeriesAtSecondAxis = 0;
659
660 for( sal_Int32 nI = 0; nI < nSeriesCount; ++nI )
661 {
662 uno::Reference< chart2::XDataSeries > xSeries( aSeriesSeq[nI], uno::UNO_QUERY );
663 sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex( xSeries );
664 if( nAxisIndex == 0 )
665 ++nSeriesAtFirstAxis;
666 else if( nAxisIndex == 1 )
667 ++nSeriesAtSecondAxis;
668 }
669 OSL_ENSURE( nSeriesAtFirstAxis + nSeriesAtSecondAxis == nSeriesCount, "Invalid axis index found" );
670
671 if( nSeriesAtFirstAxis == nSeriesCount )
672 rOutAxisIndex = 0;
673 else if( nSeriesAtSecondAxis == nSeriesCount )
674 rOutAxisIndex = 1;
675
676 return ( nSeriesAtFirstAxis == nSeriesCount ||
677 nSeriesAtSecondAxis == nSeriesCount );
678 }
679 catch( const uno::Exception & ex )
680 {
681 ASSERT_EXCEPTION( ex );
682 return false;
683 }
684 }
685
686 namespace
687 {
688
lcl_SequenceHasUnhiddenData(const uno::Reference<chart2::data::XDataSequence> & xDataSequence)689 bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
690 {
691 if( !xDataSequence.is() )
692 return false;
693 uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY );
694 if( xProp.is() )
695 {
696 uno::Sequence< sal_Int32 > aHiddenValues;
697 try
698 {
699 xProp->getPropertyValue( C2U( "HiddenValues" ) ) >>= aHiddenValues;
700 if( !aHiddenValues.getLength() )
701 return true;
702 }
703 catch( uno::Exception& e )
704 {
705 (void)e; // avoid warning
706 return true;
707 }
708 }
709 if( xDataSequence->getData().getLength() )
710 return true;
711 return false;
712 }
713
714 }
715
hasUnhiddenData(const uno::Reference<chart2::XDataSeries> & xSeries)716 bool hasUnhiddenData( const uno::Reference< chart2::XDataSeries >& xSeries )
717 {
718 uno::Reference< chart2::data::XDataSource > xDataSource =
719 uno::Reference< chart2::data::XDataSource >( xSeries, uno::UNO_QUERY );
720
721 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aDataSequences = xDataSource->getDataSequences();
722
723 for(sal_Int32 nN = aDataSequences.getLength();nN--;)
724 {
725 if( !aDataSequences[nN].is() )
726 continue;
727 if( lcl_SequenceHasUnhiddenData( aDataSequences[nN]->getValues() ) )
728 return true;
729 if( lcl_SequenceHasUnhiddenData( aDataSequences[nN]->getLabel() ) )
730 return true;
731 }
732 return false;
733 }
734
735 struct lcl_LessIndex
736 {
operator ()chart::DataSeriesHelper::lcl_LessIndex737 inline bool operator() ( const sal_Int32& first, const sal_Int32& second )
738 {
739 return ( first < second );
740 }
741 };
742
translateIndexFromHiddenToFullSequence(sal_Int32 nIndex,const Reference<chart2::data::XDataSequence> & xDataSequence,bool bTranslate)743 sal_Int32 translateIndexFromHiddenToFullSequence( sal_Int32 nIndex, const Reference< chart2::data::XDataSequence >& xDataSequence, bool bTranslate )
744 {
745 if( !bTranslate )
746 return nIndex;
747
748 try
749 {
750 uno::Reference<beans::XPropertySet> xProp( xDataSequence, uno::UNO_QUERY );
751 if( xProp.is())
752 {
753 Sequence<sal_Int32> aHiddenIndicesSeq;
754 xProp->getPropertyValue( C2U("HiddenValues") ) >>= aHiddenIndicesSeq;
755 if( aHiddenIndicesSeq.getLength() )
756 {
757 ::std::vector< sal_Int32 > aHiddenIndices( ContainerHelper::SequenceToVector( aHiddenIndicesSeq ) );
758 ::std::sort( aHiddenIndices.begin(), aHiddenIndices.end(), lcl_LessIndex() );
759
760 sal_Int32 nHiddenCount = static_cast<sal_Int32>(aHiddenIndices.size());
761 for( sal_Int32 nN = 0; nN < nHiddenCount; ++nN)
762 {
763 if( aHiddenIndices[nN] <= nIndex )
764 nIndex += 1;
765 else
766 break;
767 }
768 }
769 }
770 }
771 catch (const beans::UnknownPropertyException&)
772 {
773 }
774 return nIndex;
775 }
776
hasDataLabelsAtSeries(const Reference<chart2::XDataSeries> & xSeries)777 bool hasDataLabelsAtSeries( const Reference< chart2::XDataSeries >& xSeries )
778 {
779 bool bRet = false;
780 try
781 {
782 Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY );
783 if( xProp.is() )
784 {
785 DataPointLabel aLabel;
786 if( (xProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel) )
787 bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent || aLabel.ShowCategoryName;
788 }
789 }
790 catch( uno::Exception &e)
791 {
792 ASSERT_EXCEPTION( e );
793 }
794 return bRet;
795 }
796
hasDataLabelsAtPoints(const Reference<chart2::XDataSeries> & xSeries)797 bool hasDataLabelsAtPoints( const Reference< chart2::XDataSeries >& xSeries )
798 {
799 bool bRet = false;
800 try
801 {
802 Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY );
803 if( xSeriesProperties.is() )
804 {
805 uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
806 if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
807 {
808 for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
809 {
810 Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) );
811 if( xPointProp.is() )
812 {
813 DataPointLabel aLabel;
814 if( (xPointProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel) )
815 bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent || aLabel.ShowCategoryName;
816 if( bRet )
817 break;
818 }
819 }
820 }
821 }
822 }
823 catch( uno::Exception &e)
824 {
825 ASSERT_EXCEPTION( e );
826 }
827 return bRet;
828 }
829
hasDataLabelAtPoint(const Reference<chart2::XDataSeries> & xSeries,sal_Int32 nPointIndex)830 bool hasDataLabelAtPoint( const Reference< chart2::XDataSeries >& xSeries, sal_Int32 nPointIndex )
831 {
832 bool bRet = false;
833 try
834 {
835 Reference< beans::XPropertySet > xProp;
836 Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY );
837 if( xSeriesProperties.is() )
838 {
839 uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
840 if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
841 {
842 ::std::vector< sal_Int32 > aIndices( ContainerHelper::SequenceToVector( aAttributedDataPointIndexList ) );
843 ::std::vector< sal_Int32 >::iterator aIt = ::std::find( aIndices.begin(), aIndices.end(), nPointIndex );
844 if( aIt != aIndices.end())
845 xProp = xSeries->getDataPointByIndex(nPointIndex);
846 else
847 xProp = xSeriesProperties;
848 }
849 if( xProp.is() )
850 {
851 DataPointLabel aLabel;
852 if( (xProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel) )
853 bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent || aLabel.ShowCategoryName;
854 }
855 }
856 }
857 catch( uno::Exception &e)
858 {
859 ASSERT_EXCEPTION( e );
860 }
861 return bRet;
862 }
863
insertDataLabelsToSeriesAndAllPoints(const Reference<chart2::XDataSeries> & xSeries)864 void insertDataLabelsToSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries )
865 {
866 lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( xSeries, true /*bInsert*/ );
867 }
868
deleteDataLabelsFromSeriesAndAllPoints(const Reference<chart2::XDataSeries> & xSeries)869 void deleteDataLabelsFromSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries )
870 {
871 lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( xSeries, false /*bInsert*/ );
872 }
873
874
insertDataLabelToPoint(const Reference<beans::XPropertySet> & xPointProp)875 void insertDataLabelToPoint( const Reference< beans::XPropertySet >& xPointProp )
876 {
877 try
878 {
879 if( xPointProp.is() )
880 {
881 DataPointLabel aLabel;
882 xPointProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel;
883 aLabel.ShowNumber = true;
884 xPointProp->setPropertyValue( C2U( "Label" ), uno::makeAny( aLabel ) );
885 }
886 }
887 catch( uno::Exception &e)
888 {
889 ASSERT_EXCEPTION( e );
890 }
891 }
892
deleteDataLabelsFromPoint(const Reference<beans::XPropertySet> & xPointProp)893 void deleteDataLabelsFromPoint( const Reference< beans::XPropertySet >& xPointProp )
894 {
895 try
896 {
897 if( xPointProp.is() )
898 {
899 DataPointLabel aLabel;
900 xPointProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel;
901 aLabel.ShowNumber = false;
902 aLabel.ShowNumberInPercent = false;
903 aLabel.ShowCategoryName = false;
904 xPointProp->setPropertyValue( C2U( "Label" ), uno::makeAny( aLabel ) );
905 }
906 }
907 catch( uno::Exception &e)
908 {
909 ASSERT_EXCEPTION( e );
910 }
911 }
912
913 } // namespace DataSeriesHelper
914 } // namespace chart
915