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