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