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 27 #include "ObjectHierarchy.hxx" 28 #include "ObjectIdentifier.hxx" 29 #include "ChartModelHelper.hxx" 30 #include "DiagramHelper.hxx" 31 #include "RegressionCurveHelper.hxx" 32 #include "AxisHelper.hxx" 33 #include "chartview/ExplicitValueProvider.hxx" 34 #include "macros.hxx" 35 #include "LineProperties.hxx" 36 #include "ChartTypeHelper.hxx" 37 #include "DataSeriesHelper.hxx" 38 #include "LegendHelper.hxx" 39 #include "chartview/DrawModelWrapper.hxx" 40 41 #include <map> 42 #include <algorithm> 43 44 #include <com/sun/star/chart2/XTitled.hpp> 45 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> 46 #include <com/sun/star/chart2/XChartTypeContainer.hpp> 47 #include <com/sun/star/chart2/XDataSeriesContainer.hpp> 48 #include <com/sun/star/chart/ErrorBarStyle.hpp> 49 50 #include <com/sun/star/container/XIndexAccess.hpp> 51 #include <com/sun/star/awt/Key.hpp> 52 #include <com/sun/star/awt/KeyModifier.hpp> 53 54 using namespace ::com::sun::star; 55 using namespace ::com::sun::star::chart2; 56 57 using ::com::sun::star::uno::Reference; 58 using ::com::sun::star::uno::Sequence; 59 using ::rtl::OUString; 60 61 namespace 62 { 63 64 struct lcl_ObjectToOID : public ::std::unary_function< Reference< uno::XInterface >, ::chart::ObjectIdentifier > 65 { 66 explicit lcl_ObjectToOID( const Reference< chart2::XChartDocument > & xChartDoc ) : 67 m_xModel( xChartDoc, uno::UNO_QUERY ) 68 {} 69 70 ::chart::ObjectIdentifier operator() ( const Reference< uno::XInterface > & xObj ) 71 { 72 return ::chart::ObjectIdentifier( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xObj, m_xModel ) ); 73 } 74 75 private: 76 Reference< frame::XModel > m_xModel; 77 }; 78 79 void lcl_getChildOIDs( 80 ::chart::ObjectHierarchy::tChildContainer& rOutChildren, 81 const Reference< container::XIndexAccess >& xShapes ) 82 { 83 if( xShapes.is()) 84 { 85 sal_Int32 nCount = xShapes->getCount(); 86 for( sal_Int32 i=0; i<nCount; ++i) 87 { 88 Reference< beans::XPropertySet > xShapeProp( xShapes->getByIndex( i ), uno::UNO_QUERY ); 89 if( xShapeProp.is()) 90 { 91 Reference< beans::XPropertySetInfo > xInfo( xShapeProp->getPropertySetInfo()); 92 OUString aName; 93 if( xInfo.is() && 94 xInfo->hasPropertyByName( C2U("Name")) && 95 (xShapeProp->getPropertyValue( C2U("Name")) >>= aName ) && 96 aName.getLength() > 0 && 97 ::chart::ObjectIdentifier::isCID( aName )) 98 { 99 rOutChildren.push_back( ::chart::ObjectIdentifier( aName ) ); 100 } 101 Reference< container::XIndexAccess > xNewShapes( xShapeProp, uno::UNO_QUERY ); 102 if( xNewShapes.is()) 103 lcl_getChildOIDs( rOutChildren, xNewShapes ); 104 } 105 } 106 } 107 } 108 109 void lcl_addAxisTitle( const Reference< XAxis >& xAxis, ::chart::ObjectHierarchy::tChildContainer& rContainer, const Reference< frame::XModel >& xChartModel ) 110 { 111 Reference< XTitled > xAxisTitled( xAxis, uno::UNO_QUERY ); 112 if( xAxisTitled.is()) 113 { 114 Reference< XTitle > xAxisTitle( xAxisTitled->getTitleObject()); 115 if( xAxisTitle.is()) 116 rContainer.push_back( 117 ::chart::ObjectIdentifier( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xAxisTitle, xChartModel ) ) ); 118 } 119 } 120 121 } // anonymous namespace 122 123 namespace chart 124 { 125 126 namespace impl 127 { 128 129 class ImplObjectHierarchy 130 { 131 public: 132 explicit ImplObjectHierarchy( 133 const Reference< XChartDocument >& xChartDocument, 134 ExplicitValueProvider* pExplicitValueProvider, 135 bool bFlattenDiagram, bool bOrderingForElementSelector ); 136 137 bool hasChildren( const ObjectHierarchy::tOID& rParent ); 138 ObjectHierarchy::tChildContainer getChildren( const ObjectHierarchy::tOID& rParent ); 139 ObjectHierarchy::tChildContainer getSiblings( const ObjectHierarchy::tOID& rNode ); 140 141 ObjectHierarchy::tOID getParent( const ObjectHierarchy::tOID& rOID ); 142 143 private: 144 void createTree( const Reference< XChartDocument > & xChartDocument ); 145 void createAxesTree( 146 ObjectHierarchy::tChildContainer & rContainer, 147 const Reference< XChartDocument > & xChartDoc, 148 const Reference< XDiagram > & xDiagram ); 149 void createDiagramTree( 150 ObjectHierarchy::tChildContainer& rContainer, 151 const Reference< XChartDocument >& xChartDoc, 152 const Reference< XDiagram >& xDiagram ); 153 void createDataSeriesTree( 154 ObjectHierarchy::tChildContainer & rOutDiagramSubContainer, 155 const Reference< XDiagram > & xDiagram ); 156 void createWallAndFloor( 157 ObjectHierarchy::tChildContainer & rContainer, 158 const Reference< XDiagram > & xDiagram ); 159 void createLegendTree( 160 ObjectHierarchy::tChildContainer & rContainer, 161 const Reference< XChartDocument > & xChartDoc, 162 const Reference< XDiagram > & xDiagram ); 163 void createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer ); 164 165 ObjectHierarchy::tOID getParentImpl( 166 const ObjectHierarchy::tOID& rParentOID, 167 const ObjectHierarchy::tOID& rOID ); 168 169 typedef ::std::map< ObjectHierarchy::tOID, ObjectHierarchy::tChildContainer > 170 tChildMap; 171 tChildMap m_aChildMap; 172 ExplicitValueProvider* m_pExplicitValueProvider; 173 bool m_bFlattenDiagram; 174 bool m_bOrderingForElementSelector; 175 }; 176 177 ImplObjectHierarchy::ImplObjectHierarchy( 178 const Reference< XChartDocument >& xChartDocument, 179 ExplicitValueProvider* pExplicitValueProvider, 180 bool bFlattenDiagram, 181 bool bOrderingForElementSelector ) : 182 m_pExplicitValueProvider( pExplicitValueProvider ), 183 m_bFlattenDiagram( bFlattenDiagram ), 184 m_bOrderingForElementSelector( bOrderingForElementSelector ) 185 { 186 createTree( xChartDocument ); 187 // don't remember this helper to avoid access after lifetime 188 m_pExplicitValueProvider = 0; 189 } 190 191 void ImplObjectHierarchy::createTree( const Reference< XChartDocument >& xChartDocument ) 192 { 193 m_aChildMap = tChildMap();//clear tree 194 195 if( !xChartDocument.is() ) 196 return; 197 198 //@todo: change ObjectIdentifier to take an XChartDocument rather than XModel 199 Reference< frame::XModel > xModel( xChartDocument, uno::UNO_QUERY ); 200 Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartDocument ) ); 201 ObjectHierarchy::tOID aDiaOID; 202 if( xDiagram.is() ) 203 aDiaOID = ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram, xModel ) ); 204 ObjectHierarchy::tChildContainer aTopLevelContainer; 205 206 // First Level 207 208 // Chart Area 209 if( m_bOrderingForElementSelector ) 210 { 211 aTopLevelContainer.push_back( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) ); 212 if( xDiagram.is() ) 213 { 214 aTopLevelContainer.push_back( aDiaOID ); 215 createWallAndFloor( aTopLevelContainer, xDiagram ); 216 createLegendTree( aTopLevelContainer, xChartDocument, xDiagram ); 217 } 218 } 219 220 // Main Title 221 Reference< XTitled > xDocTitled( xChartDocument, uno::UNO_QUERY ); 222 if( xDocTitled.is()) 223 { 224 Reference< XTitle > xMainTitle( xDocTitled->getTitleObject()); 225 if( xMainTitle.is()) 226 aTopLevelContainer.push_back( 227 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xMainTitle, xModel ) ) ); 228 } 229 230 if( xDiagram.is()) 231 { 232 // Sub Title. Note: This is interpreted of being top level 233 Reference< XTitled > xDiaTitled( xDiagram, uno::UNO_QUERY ); 234 if( xDiaTitled.is()) 235 { 236 Reference< XTitle > xSubTitle( xDiaTitled->getTitleObject()); 237 if( xSubTitle.is()) 238 aTopLevelContainer.push_back( 239 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xSubTitle, xModel ) ) ); 240 } 241 242 if( !m_bOrderingForElementSelector ) 243 { 244 // Axis Titles. Note: These are interpreted of being top level 245 Sequence< Reference< XAxis > > aAxes( AxisHelper::getAllAxesOfDiagram( xDiagram ) ); 246 for( sal_Int32 i=0; i<aAxes.getLength(); ++i ) 247 lcl_addAxisTitle( aAxes[i], aTopLevelContainer, xModel ); 248 249 // Diagram 250 aTopLevelContainer.push_back( aDiaOID ); 251 } 252 253 if( m_bFlattenDiagram ) 254 createDiagramTree( aTopLevelContainer, xChartDocument, xDiagram ); 255 else 256 { 257 ObjectHierarchy::tChildContainer aSubContainer; 258 createDiagramTree( aSubContainer, xChartDocument, xDiagram ); 259 if( !aSubContainer.empty() ) 260 m_aChildMap[ aDiaOID ] = aSubContainer; 261 } 262 263 if( !m_bOrderingForElementSelector ) 264 createLegendTree( aTopLevelContainer, xChartDocument, xDiagram ); 265 } 266 267 // #i12587# support for shapes in chart 268 if ( !m_bOrderingForElementSelector ) 269 { 270 createAdditionalShapesTree( aTopLevelContainer ); 271 } 272 273 // Chart Area 274 if( !m_bOrderingForElementSelector ) 275 aTopLevelContainer.push_back( 276 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) ); 277 278 if( ! aTopLevelContainer.empty()) 279 m_aChildMap[ ObjectHierarchy::getRootNodeOID() ] = aTopLevelContainer; 280 } 281 282 void ImplObjectHierarchy::createLegendTree( 283 ObjectHierarchy::tChildContainer & rContainer, 284 const Reference< XChartDocument > & xChartDoc, 285 const Reference< XDiagram > & xDiagram ) 286 { 287 if( xDiagram.is() && LegendHelper::hasLegend( xDiagram ) ) 288 { 289 ObjectHierarchy::tOID aLegendOID( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram->getLegend(), Reference< frame::XModel >( xChartDoc, uno::UNO_QUERY ) ) ) ); 290 rContainer.push_back( aLegendOID ); 291 292 // iterate over child shapes of legend and search for matching CIDs 293 if( m_pExplicitValueProvider ) 294 { 295 Reference< container::XIndexAccess > xLegendShapeContainer( 296 m_pExplicitValueProvider->getShapeForCID( aLegendOID.getObjectCID() ), uno::UNO_QUERY ); 297 ObjectHierarchy::tChildContainer aLegendEntryOIDs; 298 lcl_getChildOIDs( aLegendEntryOIDs, xLegendShapeContainer ); 299 300 m_aChildMap[ aLegendOID ] = aLegendEntryOIDs; 301 } 302 } 303 } 304 305 void ImplObjectHierarchy::createAxesTree( 306 ObjectHierarchy::tChildContainer & rContainer, 307 const Reference< XChartDocument > & xChartDoc, 308 const Reference< XDiagram > & xDiagram ) 309 { 310 Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); 311 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); 312 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); 313 bool bSupportsAxesGrids = ChartTypeHelper::isSupportingMainAxis( xChartType, nDimensionCount, 0 ); 314 if( bSupportsAxesGrids ) 315 { 316 Sequence< Reference< XAxis > > aAxes( AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ true ) ); 317 if( !m_bOrderingForElementSelector ) 318 ::std::transform( aAxes.getConstArray(), aAxes.getConstArray() + aAxes.getLength(), 319 ::std::back_inserter( rContainer ), 320 lcl_ObjectToOID( xChartDoc )); 321 322 // get all axes, also invisible ones 323 aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ false ); 324 // Grids 325 Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY ); 326 for( sal_Int32 nA=0; nA<aAxes.getLength(); ++nA ) 327 { 328 Reference< XAxis > xAxis( aAxes[nA] ); 329 if(!xAxis.is()) 330 continue; 331 332 sal_Int32 nCooSysIndex = 0; 333 sal_Int32 nDimensionIndex = 0; 334 sal_Int32 nAxisIndex = 0; 335 AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ); 336 if( nAxisIndex>0 && !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount, nDimensionIndex ) ) 337 continue; 338 339 if( m_bOrderingForElementSelector ) 340 { 341 // axis 342 if( AxisHelper::isAxisVisible( xAxis ) ) 343 rContainer.push_back( 344 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartModel ) ) ); 345 346 // axis title 347 lcl_addAxisTitle( aAxes[nA], rContainer, xChartModel ); 348 } 349 350 Reference< beans::XPropertySet > xGridProperties( xAxis->getGridProperties() ); 351 if( AxisHelper::isGridVisible( xGridProperties ) ) 352 { 353 //main grid 354 rContainer.push_back( 355 ObjectIdentifier( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel ) ) ) ); 356 } 357 358 Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() );; 359 sal_Int32 nSubGrid = 0; 360 for( nSubGrid = 0; nSubGrid < aSubGrids.getLength(); ++nSubGrid ) 361 { 362 Reference< beans::XPropertySet > xSubGridProperties( aSubGrids[nSubGrid] ); 363 if( AxisHelper::isGridVisible( xSubGridProperties ) ) 364 { 365 //sub grid 366 rContainer.push_back( 367 ObjectIdentifier( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel, nSubGrid ) ) ) ); 368 } 369 } 370 } 371 } 372 } 373 374 void ImplObjectHierarchy::createWallAndFloor( 375 ObjectHierarchy::tChildContainer & rContainer, 376 const Reference< XDiagram > & xDiagram ) 377 { 378 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); 379 bool bIsThreeD = ( nDimensionCount == 3 ); 380 bool bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram ); 381 if( bHasWall && bIsThreeD ) 382 { 383 rContainer.push_back( 384 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, rtl::OUString() ) ) ); 385 386 Reference< beans::XPropertySet > xFloor( xDiagram->getFloor()); 387 if( xFloor.is()) 388 rContainer.push_back( 389 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, rtl::OUString() ) ) ); 390 } 391 392 } 393 394 void ImplObjectHierarchy::createDiagramTree( 395 ObjectHierarchy::tChildContainer & rContainer, 396 const Reference< XChartDocument > & xChartDoc, 397 const Reference< XDiagram > & xDiagram ) 398 { 399 if( !m_bOrderingForElementSelector ) 400 { 401 createDataSeriesTree( rContainer, xDiagram ); 402 createAxesTree( rContainer, xChartDoc, xDiagram ); 403 createWallAndFloor( rContainer, xDiagram ); 404 } 405 else 406 { 407 createAxesTree( rContainer, xChartDoc, xDiagram ); 408 createDataSeriesTree( rContainer, xDiagram ); 409 } 410 } 411 412 void ImplObjectHierarchy::createDataSeriesTree( 413 ObjectHierarchy::tChildContainer & rOutDiagramSubContainer, 414 const Reference< XDiagram > & xDiagram ) 415 { 416 Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); 417 418 try 419 { 420 sal_Int32 nDiagramIndex = 0; 421 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); 422 Sequence< Reference< XCoordinateSystem > > aCooSysSeq( 423 xCooSysCnt->getCoordinateSystems()); 424 for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx ) 425 { 426 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); 427 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes()); 428 for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypeSeq.getLength(); ++nCTIdx ) 429 { 430 Reference< XChartType > xChartType( aChartTypeSeq[nCTIdx] ); 431 Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW ); 432 Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() ); 433 const sal_Int32 nNumberOfSeries = 434 ChartTypeHelper::getNumberOfDisplayedSeries( xChartType, aSeriesSeq.getLength()); 435 436 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<nNumberOfSeries; ++nSeriesIdx ) 437 { 438 OUString aSeriesParticle( 439 ObjectIdentifier::createParticleForSeries( 440 nDiagramIndex, nCooSysIdx, nCTIdx, nSeriesIdx )); 441 ObjectHierarchy::tOID aSeriesOID( 442 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForParticle( aSeriesParticle ) ) ); 443 rOutDiagramSubContainer.push_back( aSeriesOID ); 444 445 ObjectHierarchy::tChildContainer aSeriesSubContainer; 446 447 Reference< chart2::XDataSeries > xSeries( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ); 448 449 // data lablels 450 if( DataSeriesHelper::hasDataLabelsAtSeries( xSeries ) ) 451 { 452 rtl::OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) ); 453 aChildParticle+=(C2U("=")); 454 aSeriesSubContainer.push_back( 455 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForParticles( aSeriesParticle, aChildParticle ) ) ); 456 } 457 458 // Statistics 459 if( ChartTypeHelper::isSupportingStatisticProperties( xChartType, nDimensionCount ) ) 460 { 461 Reference< chart2::XRegressionCurveContainer > xCurveCnt( xSeries, uno::UNO_QUERY ); 462 if( xCurveCnt.is()) 463 { 464 Sequence< Reference< chart2::XRegressionCurve > > aCurves( xCurveCnt->getRegressionCurves()); 465 for( sal_Int32 nCurveIdx=0; nCurveIdx<aCurves.getLength(); ++nCurveIdx ) 466 { 467 bool bIsAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[nCurveIdx] ); 468 aSeriesSubContainer.push_back( 469 ObjectIdentifier( ObjectIdentifier::createDataCurveCID( aSeriesParticle, nCurveIdx, bIsAverageLine ) ) ); 470 if( RegressionCurveHelper::hasEquation( aCurves[nCurveIdx] ) ) 471 { 472 aSeriesSubContainer.push_back( 473 ObjectIdentifier( ObjectIdentifier::createDataCurveEquationCID( aSeriesParticle, nCurveIdx ) ) ); 474 } 475 } 476 Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY ); 477 Reference< beans::XPropertySet > xErrorBarProp; 478 if( xSeriesProp.is() && 479 (xSeriesProp->getPropertyValue( C2U("ErrorBarY")) >>= xErrorBarProp) && 480 xErrorBarProp.is()) 481 { 482 sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE; 483 if( ( xErrorBarProp->getPropertyValue( C2U("ErrorBarStyle")) >>= nStyle ) && 484 ( nStyle != ::com::sun::star::chart::ErrorBarStyle::NONE ) ) 485 { 486 aSeriesSubContainer.push_back( 487 ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierWithParent( 488 OBJECTTYPE_DATA_ERRORS, OUString(), aSeriesParticle ) ) ); 489 } 490 } 491 } 492 } 493 494 // Data Points 495 // iterate over child shapes of legend and search for matching CIDs 496 if( m_pExplicitValueProvider ) 497 { 498 Reference< container::XIndexAccess > xSeriesShapeContainer( 499 m_pExplicitValueProvider->getShapeForCID( aSeriesOID.getObjectCID() ), uno::UNO_QUERY ); 500 lcl_getChildOIDs( aSeriesSubContainer, xSeriesShapeContainer ); 501 } 502 503 if( ! aSeriesSubContainer.empty()) 504 m_aChildMap[ aSeriesOID ] = aSeriesSubContainer; 505 } 506 } 507 } 508 } 509 catch( uno::Exception & ex ) 510 { 511 ASSERT_EXCEPTION( ex ); 512 } 513 } 514 515 void ImplObjectHierarchy::createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer ) 516 { 517 try 518 { 519 if ( m_pExplicitValueProvider ) 520 { 521 Reference< drawing::XDrawPage > xDrawPage( m_pExplicitValueProvider->getDrawModelWrapper()->getMainDrawPage() ); 522 Reference< drawing::XShapes > xDrawPageShapes( xDrawPage, uno::UNO_QUERY_THROW ); 523 Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); 524 sal_Int32 nCount = xDrawPageShapes->getCount(); 525 for ( sal_Int32 i = 0; i < nCount; ++i ) 526 { 527 Reference< drawing::XShape > xShape; 528 if ( xDrawPageShapes->getByIndex( i ) >>= xShape ) 529 { 530 if ( xShape.is() && xShape != xChartRoot ) 531 { 532 rContainer.push_back( ObjectIdentifier( xShape ) ); 533 } 534 } 535 } 536 } 537 } 538 catch ( uno::Exception& ex ) 539 { 540 ASSERT_EXCEPTION( ex ); 541 } 542 } 543 544 bool ImplObjectHierarchy::hasChildren( const ObjectHierarchy::tOID& rParent ) 545 { 546 if ( rParent.isValid() ) 547 { 548 tChildMap::const_iterator aIt( m_aChildMap.find( rParent )); 549 if( aIt != m_aChildMap.end()) 550 return ! (aIt->second.empty()); 551 } 552 return false; 553 } 554 555 ObjectHierarchy::tChildContainer ImplObjectHierarchy::getChildren( const ObjectHierarchy::tOID& rParent ) 556 { 557 if ( rParent.isValid() ) 558 { 559 tChildMap::const_iterator aIt( m_aChildMap.find( rParent )); 560 if( aIt != m_aChildMap.end()) 561 return aIt->second; 562 } 563 return ObjectHierarchy::tChildContainer(); 564 } 565 566 ObjectHierarchy::tChildContainer ImplObjectHierarchy::getSiblings( const ObjectHierarchy::tOID& rNode ) 567 { 568 if ( rNode.isValid() && !ObjectHierarchy::isRootNode( rNode ) ) 569 { 570 for( tChildMap::const_iterator aIt( m_aChildMap.begin()); 571 aIt != m_aChildMap.end(); ++aIt ) 572 { 573 ObjectHierarchy::tChildContainer::const_iterator aElemIt( 574 ::std::find( aIt->second.begin(), aIt->second.end(), rNode )); 575 if( aElemIt != aIt->second.end()) 576 return aIt->second; 577 } 578 } 579 return ObjectHierarchy::tChildContainer(); 580 } 581 582 ObjectHierarchy::tOID ImplObjectHierarchy::getParentImpl( 583 const ObjectHierarchy::tOID & rParentOID, 584 const ObjectHierarchy::tOID & rOID ) 585 { 586 // search children 587 ObjectHierarchy::tChildContainer aChildren( getChildren( rParentOID )); 588 ObjectHierarchy::tChildContainer::const_iterator aIt( 589 ::std::find( aChildren.begin(), aChildren.end(), rOID )); 590 // recursion end 591 if( aIt != aChildren.end()) 592 return rParentOID; 593 594 for( aIt = aChildren.begin(); aIt != aChildren.end(); ++aIt ) 595 { 596 // recursion 597 ObjectHierarchy::tOID aTempParent( getParentImpl( *aIt, rOID )); 598 if ( aTempParent.isValid() ) 599 { 600 // exit on success 601 return aTempParent; 602 } 603 } 604 605 // exit on fail 606 return ObjectHierarchy::tOID(); 607 } 608 609 ObjectHierarchy::tOID ImplObjectHierarchy::getParent( 610 const ObjectHierarchy::tOID & rOID ) 611 { 612 return getParentImpl( ObjectHierarchy::getRootNodeOID(), rOID ); 613 } 614 615 } // namespace impl 616 617 618 ObjectHierarchy::ObjectHierarchy( 619 const Reference< XChartDocument > & xChartDocument, 620 ExplicitValueProvider * pExplicitValueProvider /* = 0 */, 621 bool bFlattenDiagram /* = false */, 622 bool bOrderingForElementSelector /* = false */) : 623 m_apImpl( new impl::ImplObjectHierarchy( xChartDocument, pExplicitValueProvider, bFlattenDiagram, bOrderingForElementSelector )) 624 {} 625 626 ObjectHierarchy::~ObjectHierarchy() 627 {} 628 629 ObjectHierarchy::tOID ObjectHierarchy::getRootNodeOID() 630 { 631 return ObjectIdentifier( C2U( "ROOT" ) ); 632 } 633 634 bool ObjectHierarchy::isRootNode( const ObjectHierarchy::tOID& rOID ) 635 { 636 return ( rOID == ObjectHierarchy::getRootNodeOID() ); 637 } 638 639 ObjectHierarchy::tChildContainer ObjectHierarchy::getTopLevelChildren() const 640 { 641 return m_apImpl->getChildren( ObjectHierarchy::getRootNodeOID()); 642 } 643 644 bool ObjectHierarchy::hasChildren( const tOID& rParent ) const 645 { 646 return m_apImpl->hasChildren( rParent ); 647 } 648 649 ObjectHierarchy::tChildContainer ObjectHierarchy::getChildren( 650 const ObjectHierarchy::tOID& rParent ) const 651 { 652 if ( rParent.isValid() ) 653 return m_apImpl->getChildren( rParent ); 654 655 return ObjectHierarchy::tChildContainer(); 656 } 657 658 ObjectHierarchy::tChildContainer ObjectHierarchy::getSiblings( 659 const ObjectHierarchy::tOID& rNode ) const 660 { 661 if ( rNode.isValid() && !isRootNode( rNode ) ) 662 return m_apImpl->getSiblings( rNode ); 663 664 return ObjectHierarchy::tChildContainer(); 665 } 666 667 ObjectHierarchy::tOID ObjectHierarchy::getParent( 668 const ObjectHierarchy::tOID& rNode ) const 669 { 670 return m_apImpl->getParent( rNode ); 671 } 672 673 sal_Int32 ObjectHierarchy::getIndexInParent( 674 const ObjectHierarchy::tOID& rNode ) const 675 { 676 tOID aParentOID( m_apImpl->getParent( rNode )); 677 tChildContainer aChildren( m_apImpl->getChildren( aParentOID ) ); 678 tChildContainer::const_iterator aIt( aChildren.begin() ); 679 for( sal_Int32 nIndex = 0; aIt != aChildren.end(); ++nIndex, ++aIt ) 680 { 681 if ( *aIt == rNode ) 682 return nIndex; 683 } 684 return -1; 685 } 686 687 // ================================================================================ 688 689 ObjectKeyNavigation::ObjectKeyNavigation( 690 const ObjectHierarchy::tOID & rCurrentOID, 691 const Reference< chart2::XChartDocument > & xChartDocument, 692 ExplicitValueProvider * pExplicitValueProvider /* = 0 */ ) : 693 m_aCurrentOID( rCurrentOID ), 694 m_xChartDocument( xChartDocument ), 695 m_pExplicitValueProvider( pExplicitValueProvider ), 696 m_bStepDownInDiagram( true ) 697 { 698 if ( !m_aCurrentOID.isValid() ) 699 { 700 setCurrentSelection( ObjectHierarchy::getRootNodeOID() ); 701 } 702 } 703 704 bool ObjectKeyNavigation::handleKeyEvent( 705 const awt::KeyEvent & rEvent ) 706 { 707 bool bResult = false; 708 709 switch( rEvent.KeyCode ) 710 { 711 case awt::Key::TAB: 712 if( rEvent.Modifiers & awt::KeyModifier::SHIFT ) 713 bResult = previous(); 714 else 715 bResult = next(); 716 break; 717 case awt::Key::HOME: 718 bResult = first(); 719 break; 720 case awt::Key::END: 721 bResult = last(); 722 break; 723 case awt::Key::F3: 724 if( rEvent.Modifiers & awt::KeyModifier::SHIFT ) 725 bResult = up(); 726 else 727 bResult = down(); 728 break; 729 case awt::Key::ESCAPE: 730 setCurrentSelection( ObjectIdentifier() ); 731 bResult = true; 732 break; 733 default: 734 bResult = false; 735 break; 736 } 737 return bResult; 738 } 739 740 void ObjectKeyNavigation::setCurrentSelection( const ObjectHierarchy::tOID& rOID ) 741 { 742 m_aCurrentOID = rOID; 743 } 744 745 ObjectHierarchy::tOID ObjectKeyNavigation::getCurrentSelection() const 746 { 747 return m_aCurrentOID; 748 } 749 750 bool ObjectKeyNavigation::first() 751 { 752 ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); 753 ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); 754 bool bResult = !aSiblings.empty(); 755 if( bResult ) 756 setCurrentSelection( aSiblings.front()); 757 else 758 bResult = veryFirst(); 759 return bResult; 760 } 761 762 bool ObjectKeyNavigation::last() 763 { 764 ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); 765 ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); 766 bool bResult = !aSiblings.empty(); 767 if( bResult ) 768 setCurrentSelection( aSiblings.back()); 769 else 770 bResult = veryLast(); 771 return bResult; 772 } 773 774 bool ObjectKeyNavigation::next() 775 { 776 ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); 777 ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); 778 bool bResult = !aSiblings.empty(); 779 if( bResult ) 780 { 781 ObjectHierarchy::tChildContainer::const_iterator aIt( 782 ::std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection())); 783 OSL_ASSERT( aIt != aSiblings.end()); 784 if( ++aIt == aSiblings.end()) 785 aIt = aSiblings.begin(); 786 setCurrentSelection( *aIt ); 787 } 788 else 789 bResult = veryFirst(); 790 791 return bResult; 792 } 793 794 bool ObjectKeyNavigation::previous() 795 { 796 ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); 797 ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection())); 798 bool bResult = !aSiblings.empty(); 799 if( bResult ) 800 { 801 ObjectHierarchy::tChildContainer::const_iterator aIt( 802 ::std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection())); 803 OSL_ASSERT( aIt != aSiblings.end()); 804 if( aIt == aSiblings.begin()) 805 aIt = aSiblings.end(); 806 --aIt; 807 setCurrentSelection( *aIt ); 808 } 809 else 810 bResult = veryLast(); 811 return bResult; 812 } 813 814 bool ObjectKeyNavigation::up() 815 { 816 ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); 817 bool bResult = !ObjectHierarchy::isRootNode( getCurrentSelection()); 818 if( bResult ) 819 setCurrentSelection( aHierarchy.getParent( getCurrentSelection())); 820 return bResult; 821 } 822 823 bool ObjectKeyNavigation::down() 824 { 825 ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); 826 bool bResult = aHierarchy.hasChildren( getCurrentSelection()); 827 if( bResult ) 828 { 829 ObjectHierarchy::tChildContainer aChildren = aHierarchy.getChildren( getCurrentSelection()); 830 OSL_ASSERT( !aChildren.empty()); 831 setCurrentSelection( aChildren.front()); 832 } 833 return bResult; 834 } 835 836 bool ObjectKeyNavigation::veryFirst() 837 { 838 ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); 839 ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren()); 840 bool bResult = !aChildren.empty(); 841 if( bResult ) 842 setCurrentSelection( aChildren.front()); 843 return bResult; 844 } 845 846 bool ObjectKeyNavigation::veryLast() 847 { 848 ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); 849 ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren()); 850 bool bResult = !aChildren.empty(); 851 if( bResult ) 852 setCurrentSelection( aChildren.back()); 853 return bResult; 854 } 855 856 } // namespace chart 857