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