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