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