/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: ObjectHierarchy.cxx,v $ * $Revision: 1.7 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_chart2.hxx" #include "ObjectHierarchy.hxx" #include "ObjectIdentifier.hxx" #include "ChartModelHelper.hxx" #include "DiagramHelper.hxx" #include "RegressionCurveHelper.hxx" #include "AxisHelper.hxx" #include "chartview/ExplicitValueProvider.hxx" #include "macros.hxx" #include "LineProperties.hxx" #include "ChartTypeHelper.hxx" #include "DataSeriesHelper.hxx" #include "LegendHelper.hxx" #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::chart2; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::rtl::OUString; namespace { struct lcl_ObjectToCID : public ::std::unary_function< Reference< uno::XInterface >, OUString > { explicit lcl_ObjectToCID( const Reference< chart2::XChartDocument > & xChartDoc ) : m_xModel( xChartDoc, uno::UNO_QUERY ) {} OUString operator() ( const Reference< uno::XInterface > & xObj ) { return ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xObj, m_xModel ); } private: Reference< frame::XModel > m_xModel; }; void lcl_getChildCIDs( ::chart::ObjectHierarchy::tChildContainer & rOutChildren, const Reference< container::XIndexAccess > & xShapes ) { if( xShapes.is()) { sal_Int32 nCount = xShapes->getCount(); for( sal_Int32 i=0; i xShapeProp( xShapes->getByIndex( i ), uno::UNO_QUERY ); if( xShapeProp.is()) { Reference< beans::XPropertySetInfo > xInfo( xShapeProp->getPropertySetInfo()); OUString aName; if( xInfo.is() && xInfo->hasPropertyByName( C2U("Name")) && (xShapeProp->getPropertyValue( C2U("Name")) >>= aName ) && aName.getLength() > 0 && ::chart::ObjectIdentifier::isCID( aName )) { rOutChildren.push_back( aName ); } Reference< container::XIndexAccess > xNewShapes( xShapeProp, uno::UNO_QUERY ); if( xNewShapes.is()) lcl_getChildCIDs( rOutChildren, xNewShapes ); } } } } void lcl_addAxisTitle( const Reference< XAxis >& xAxis, ::chart::ObjectHierarchy::tChildContainer& rContainer, const Reference< frame::XModel >& xChartModel ) { Reference< XTitled > xAxisTitled( xAxis, uno::UNO_QUERY ); if( xAxisTitled.is()) { Reference< XTitle > xAxisTitle( xAxisTitled->getTitleObject()); if( xAxisTitle.is()) rContainer.push_back( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xAxisTitle, xChartModel )); } } } // anonymous namespace namespace chart { namespace impl { class ImplObjectHierarchy { public: explicit ImplObjectHierarchy( const Reference< XChartDocument > & xChartDocument, ExplicitValueProvider * pExplicitValueProvider, bool bFlattenDiagram, bool bOrderingForElementSelector ); bool hasChildren( const OUString & rParent ); ObjectHierarchy::tChildContainer getChildren( const OUString & rParent ); ObjectHierarchy::tChildContainer getSiblings( const OUString & rNode ); ObjectHierarchy::tCID getParent( const ObjectHierarchy::tCID & rCID ); private: void createTree( const Reference< XChartDocument > & xChartDocument ); void createAxesTree( ObjectHierarchy::tChildContainer & rContainer, const Reference< XChartDocument > & xChartDoc, const Reference< XDiagram > & xDiagram ); void createDiagramTree( ObjectHierarchy::tChildContainer & rContainer, const Reference< XChartDocument > & xChartDoc, const Reference< XDiagram > & xDiagram ); void createDataSeriesTree( ObjectHierarchy::tChildContainer & rOutDiagramSubContainer, const Reference< XDiagram > & xDiagram ); void createWallAndFloor( ObjectHierarchy::tChildContainer & rContainer, const Reference< XDiagram > & xDiagram ); void createLegendTree( ObjectHierarchy::tChildContainer & rContainer, const Reference< XChartDocument > & xChartDoc, const Reference< XDiagram > & xDiagram ); ObjectHierarchy::tCID getParentImpl( const ObjectHierarchy::tCID & rParentCID, const ObjectHierarchy::tCID & rCID ); typedef ::std::map< OUString, ObjectHierarchy::tChildContainer > tChildMap; tChildMap m_aChildMap; ExplicitValueProvider * m_pExplicitValueProvider; bool m_bFlattenDiagram; bool m_bOrderingForElementSelector; }; ImplObjectHierarchy::ImplObjectHierarchy( const Reference< XChartDocument > & xChartDocument, ExplicitValueProvider * pExplicitValueProvider, bool bFlattenDiagram, bool bOrderingForElementSelector ) : m_pExplicitValueProvider( pExplicitValueProvider ), m_bFlattenDiagram( bFlattenDiagram ), m_bOrderingForElementSelector( bOrderingForElementSelector ) { createTree( xChartDocument ); // don't remember this helper to avoid access after lifetime m_pExplicitValueProvider = 0; } void ImplObjectHierarchy::createTree( const Reference< XChartDocument > & xChartDocument ) { if( !xChartDocument.is()) return; //@todo: change ObjectIdentifier to take an XChartDocument rather than XModel Reference< frame::XModel > xModel( xChartDocument, uno::UNO_QUERY ); Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartDocument ) ); OUString aDiaCID( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram, xModel )); ObjectHierarchy::tChildContainer aTopLevelContainer; // First Level // Chart Area if( m_bOrderingForElementSelector ) { aTopLevelContainer.push_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ); aTopLevelContainer.push_back( aDiaCID ); createWallAndFloor( aTopLevelContainer, xDiagram ); createLegendTree( aTopLevelContainer, xChartDocument, xDiagram ); } // Main Title Reference< XTitled > xDocTitled( xChartDocument, uno::UNO_QUERY ); if( xDocTitled.is()) { Reference< XTitle > xMainTitle( xDocTitled->getTitleObject()); if( xMainTitle.is()) aTopLevelContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForObject( xMainTitle, xModel )); } if( xDiagram.is()) { // Sub Title. Note: This is interpreted of being top level Reference< XTitled > xDiaTitled( xDiagram, uno::UNO_QUERY ); if( xDiaTitled.is()) { Reference< XTitle > xSubTitle( xDiaTitled->getTitleObject()); if( xSubTitle.is()) aTopLevelContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForObject( xSubTitle, xModel )); } if( !m_bOrderingForElementSelector ) { // Axis Titles. Note: These are interpreted of being top level Sequence< Reference< XAxis > > aAxes( AxisHelper::getAllAxesOfDiagram( xDiagram ) ); for( sal_Int32 i=0; i & xChartDoc, const Reference< XDiagram > & xDiagram ) { if( xDiagram.is() && LegendHelper::hasLegend( xDiagram ) ) { OUString aLegendCID( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram->getLegend(), Reference< frame::XModel >( xChartDoc, uno::UNO_QUERY ) )); rContainer.push_back( aLegendCID ); // iterate over child shapes of legend and search for matching CIDs if( m_pExplicitValueProvider ) { Reference< container::XIndexAccess > xLegendShapeContainer( m_pExplicitValueProvider->getShapeForCID( aLegendCID ), uno::UNO_QUERY ); ObjectHierarchy::tChildContainer aLegendEntryCIDs; lcl_getChildCIDs( aLegendEntryCIDs, xLegendShapeContainer ); m_aChildMap[ aLegendCID ] = aLegendEntryCIDs; } } } void ImplObjectHierarchy::createAxesTree( ObjectHierarchy::tChildContainer & rContainer, const Reference< XChartDocument > & xChartDoc, const Reference< XDiagram > & xDiagram ) { Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); bool bSupportsAxesGrids = ChartTypeHelper::isSupportingMainAxis( xChartType, nDimensionCount, 0 ); if( bSupportsAxesGrids ) { Sequence< Reference< XAxis > > aAxes( AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ true ) ); if( !m_bOrderingForElementSelector ) ::std::transform( aAxes.getConstArray(), aAxes.getConstArray() + aAxes.getLength(), ::std::back_inserter( rContainer ), lcl_ObjectToCID( xChartDoc )); // get all axes, also invisible ones aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ false ); // Grids Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY ); for( sal_Int32 nA=0; nA xAxis( aAxes[nA] ); if(!xAxis.is()) continue; sal_Int32 nCooSysIndex = 0; sal_Int32 nDimensionIndex = 0; sal_Int32 nAxisIndex = 0; AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ); if( nAxisIndex>0 && !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount, nDimensionIndex ) ) continue; if( m_bOrderingForElementSelector ) { // axis if( AxisHelper::isAxisVisible( xAxis ) ) rContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartModel ) ); // axis title lcl_addAxisTitle( aAxes[nA], rContainer, xChartModel ); } Reference< beans::XPropertySet > xGridProperties( xAxis->getGridProperties() ); if( AxisHelper::isGridVisible( xGridProperties ) ) { //main grid rContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel ) ); } Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() );; sal_Int32 nSubGrid = 0; for( nSubGrid = 0; nSubGrid < aSubGrids.getLength(); ++nSubGrid ) { Reference< beans::XPropertySet > xSubGridProperties( aSubGrids[nSubGrid] ); if( AxisHelper::isGridVisible( xSubGridProperties ) ) { //sub grid rContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel, nSubGrid ) ); } } } } } void ImplObjectHierarchy::createWallAndFloor( ObjectHierarchy::tChildContainer & rContainer, const Reference< XDiagram > & xDiagram ) { sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); bool bIsThreeD = ( nDimensionCount == 3 ); bool bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram ); if( bHasWall && bIsThreeD ) { rContainer.push_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, rtl::OUString())); Reference< beans::XPropertySet > xFloor( xDiagram->getFloor()); if( xFloor.is()) rContainer.push_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, rtl::OUString())); } } void ImplObjectHierarchy::createDiagramTree( ObjectHierarchy::tChildContainer & rContainer, const Reference< XChartDocument > & xChartDoc, const Reference< XDiagram > & xDiagram ) { if( !m_bOrderingForElementSelector ) { createDataSeriesTree( rContainer, xDiagram ); createAxesTree( rContainer, xChartDoc, xDiagram ); createWallAndFloor( rContainer, xDiagram ); } else { createAxesTree( rContainer, xChartDoc, xDiagram ); createDataSeriesTree( rContainer, xDiagram ); } } void ImplObjectHierarchy::createDataSeriesTree( ObjectHierarchy::tChildContainer & rOutDiagramSubContainer, const Reference< XDiagram > & xDiagram ) { Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); try { sal_Int32 nDiagramIndex = 0; sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); Sequence< Reference< XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); for( sal_Int32 nCooSysIdx=0; nCooSysIdx xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes()); for( sal_Int32 nCTIdx=0; nCTIdx xChartType( aChartTypeSeq[nCTIdx] ); Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW ); Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() ); const sal_Int32 nNumberOfSeries = ChartTypeHelper::getNumberOfDisplayedSeries( xChartType, aSeriesSeq.getLength()); for( sal_Int32 nSeriesIdx=0; nSeriesIdx xSeries( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ); // data lablels if( DataSeriesHelper::hasDataLabelsAtSeries( xSeries ) ) { rtl::OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) ); aChildParticle+=(C2U("=")); aSeriesSubContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForParticles( aSeriesParticle, aChildParticle )); } // Statistics if( ChartTypeHelper::isSupportingStatisticProperties( xChartType, nDimensionCount ) ) { Reference< chart2::XRegressionCurveContainer > xCurveCnt( xSeries, uno::UNO_QUERY ); if( xCurveCnt.is()) { Sequence< Reference< chart2::XRegressionCurve > > aCurves( xCurveCnt->getRegressionCurves()); for( sal_Int32 nCurveIdx=0; nCurveIdx xSeriesProp( xSeries, uno::UNO_QUERY ); Reference< beans::XPropertySet > xErrorBarProp; if( xSeriesProp.is() && (xSeriesProp->getPropertyValue( C2U("ErrorBarY")) >>= xErrorBarProp) && xErrorBarProp.is()) { sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE; if( ( xErrorBarProp->getPropertyValue( C2U("ErrorBarStyle")) >>= nStyle ) && ( nStyle != ::com::sun::star::chart::ErrorBarStyle::NONE ) ) { aSeriesSubContainer.push_back( ObjectIdentifier::createClassifiedIdentifierWithParent( OBJECTTYPE_DATA_ERRORS, OUString(), aSeriesParticle )); } } } } // Data Points // iterate over child shapes of legend and search for matching CIDs if( m_pExplicitValueProvider ) { Reference< container::XIndexAccess > xSeriesShapeContainer( m_pExplicitValueProvider->getShapeForCID( aSeriesCID ), uno::UNO_QUERY ); lcl_getChildCIDs( aSeriesSubContainer, xSeriesShapeContainer ); } if( ! aSeriesSubContainer.empty()) m_aChildMap[ aSeriesCID ] = aSeriesSubContainer; } } } } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } bool ImplObjectHierarchy::hasChildren( const OUString & rParent ) { if( rParent.getLength()) { tChildMap::const_iterator aIt( m_aChildMap.find( rParent )); if( aIt != m_aChildMap.end()) return ! (aIt->second.empty()); } return false; } ObjectHierarchy::tChildContainer ImplObjectHierarchy::getChildren( const OUString & rParent ) { if( rParent.getLength()) { tChildMap::const_iterator aIt( m_aChildMap.find( rParent )); if( aIt != m_aChildMap.end()) return aIt->second; } return ObjectHierarchy::tChildContainer(); } ObjectHierarchy::tChildContainer ImplObjectHierarchy::getSiblings( const OUString & rNode ) { if( rNode.getLength() && !ObjectHierarchy::isRootNode( rNode )) { for( tChildMap::const_iterator aIt( m_aChildMap.begin()); aIt != m_aChildMap.end(); ++aIt ) { ObjectHierarchy::tChildContainer::const_iterator aElemIt( ::std::find( aIt->second.begin(), aIt->second.end(), rNode )); if( aElemIt != aIt->second.end()) return aIt->second; } } return ObjectHierarchy::tChildContainer(); } ObjectHierarchy::tCID ImplObjectHierarchy::getParentImpl( const ObjectHierarchy::tCID & rParentCID, const ObjectHierarchy::tCID & rCID ) { // search children ObjectHierarchy::tChildContainer aChildren( getChildren( rParentCID )); ObjectHierarchy::tChildContainer::const_iterator aIt( ::std::find( aChildren.begin(), aChildren.end(), rCID )); // recursion end if( aIt != aChildren.end()) return rParentCID; for( aIt = aChildren.begin(); aIt != aChildren.end(); ++aIt ) { // recursion ObjectHierarchy::tCID aTempParent( getParentImpl( *aIt, rCID )); if( aTempParent.getLength()) { // exit on success return aTempParent; } } // exit on fail return ObjectHierarchy::tCID(); } ObjectHierarchy::tCID ImplObjectHierarchy::getParent( const ObjectHierarchy::tCID & rCID ) { return getParentImpl( ObjectHierarchy::getRootNodeCID(), rCID ); } } // namespace impl ObjectHierarchy::ObjectHierarchy( const Reference< XChartDocument > & xChartDocument, ExplicitValueProvider * pExplicitValueProvider /* = 0 */, bool bFlattenDiagram /* = false */, bool bOrderingForElementSelector /* = false */) : m_apImpl( new impl::ImplObjectHierarchy( xChartDocument, pExplicitValueProvider, bFlattenDiagram, bOrderingForElementSelector )) {} ObjectHierarchy::~ObjectHierarchy() {} // static ObjectHierarchy::tCID ObjectHierarchy::getRootNodeCID() { return C2U("ROOT"); } // static bool ObjectHierarchy::isRootNode( const ObjectHierarchy::tCID & rCID ) { return rCID.equals( ObjectHierarchy::getRootNodeCID()); } ObjectHierarchy::tChildContainer ObjectHierarchy::getTopLevelChildren() const { return m_apImpl->getChildren( ObjectHierarchy::getRootNodeCID()); } bool ObjectHierarchy::hasChildren( const tCID & rParent ) const { return m_apImpl->hasChildren( rParent ); } ObjectHierarchy::tChildContainer ObjectHierarchy::getChildren( const ObjectHierarchy::tCID & rParent ) const { if( rParent.getLength()) return m_apImpl->getChildren( rParent ); return ObjectHierarchy::tChildContainer(); } ObjectHierarchy::tChildContainer ObjectHierarchy::getSiblings( const ObjectHierarchy::tCID & rNode ) const { if( rNode.getLength() && !isRootNode( rNode )) return m_apImpl->getSiblings( rNode ); return ObjectHierarchy::tChildContainer(); } ObjectHierarchy::tCID ObjectHierarchy::getParent( const ObjectHierarchy::tCID & rNode ) const { return m_apImpl->getParent( rNode ); } sal_Int32 ObjectHierarchy::getIndexInParent( const ObjectHierarchy::tCID & rNode ) const { tCID aParentCID( m_apImpl->getParent( rNode )); tChildContainer aChildren( m_apImpl->getChildren( aParentCID )); tChildContainer::const_iterator aIt( aChildren.begin()); for( sal_Int32 nIndex = 0; aIt != aChildren.end(); ++nIndex, ++aIt ) { if( aIt->equals( rNode )) return nIndex; } return -1; } // ================================================================================ ObjectKeyNavigation::ObjectKeyNavigation( const ObjectHierarchy::tCID & rCurrentCID, const Reference< chart2::XChartDocument > & xChartDocument, ExplicitValueProvider * pExplicitValueProvider /* = 0 */ ) : m_aCurrentCID( rCurrentCID ), m_xChartDocument( xChartDocument ), m_pExplicitValueProvider( pExplicitValueProvider ), m_bStepDownInDiagram( true ) { if( m_aCurrentCID.getLength() == 0 ) setCurrentSelection( ObjectHierarchy::getRootNodeCID()); } bool ObjectKeyNavigation::handleKeyEvent( const awt::KeyEvent & rEvent ) { bool bResult = false; switch( rEvent.KeyCode ) { case awt::Key::TAB: if( rEvent.Modifiers & awt::KeyModifier::SHIFT ) bResult = previous(); else bResult = next(); break; case awt::Key::HOME: bResult = first(); break; case awt::Key::END: bResult = last(); break; case awt::Key::F3: if( rEvent.Modifiers & awt::KeyModifier::SHIFT ) bResult = up(); else bResult = down(); break; case awt::Key::ESCAPE: setCurrentSelection( OUString()); bResult = true; break; default: bResult = false; break; } return bResult; } void ObjectKeyNavigation::setCurrentSelection( const ObjectHierarchy::tCID & rCID ) { m_aCurrentCID = rCID; } ObjectHierarchy::tCID ObjectKeyNavigation::getCurrentSelection() const { return m_aCurrentCID; } bool ObjectKeyNavigation::first() { ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection())); bool bResult = !aSiblings.empty(); if( bResult ) setCurrentSelection( aSiblings.front()); else bResult = veryFirst(); return bResult; } bool ObjectKeyNavigation::last() { ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection())); bool bResult = !aSiblings.empty(); if( bResult ) setCurrentSelection( aSiblings.back()); else bResult = veryLast(); return bResult; } bool ObjectKeyNavigation::next() { ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection())); bool bResult = !aSiblings.empty(); if( bResult ) { ObjectHierarchy::tChildContainer::const_iterator aIt( ::std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection())); OSL_ASSERT( aIt != aSiblings.end()); if( ++aIt == aSiblings.end()) aIt = aSiblings.begin(); setCurrentSelection( *aIt ); } else bResult = veryFirst(); return bResult; } bool ObjectKeyNavigation::previous() { ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection())); bool bResult = !aSiblings.empty(); if( bResult ) { ObjectHierarchy::tChildContainer::const_iterator aIt( ::std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection())); OSL_ASSERT( aIt != aSiblings.end()); if( aIt == aSiblings.begin()) aIt = aSiblings.end(); --aIt; setCurrentSelection( *aIt ); } else bResult = veryLast(); return bResult; } bool ObjectKeyNavigation::up() { ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); bool bResult = !ObjectHierarchy::isRootNode( getCurrentSelection()); if( bResult ) setCurrentSelection( aHierarchy.getParent( getCurrentSelection())); return bResult; } bool ObjectKeyNavigation::down() { ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); bool bResult = aHierarchy.hasChildren( getCurrentSelection()); if( bResult ) { ObjectHierarchy::tChildContainer aChildren = aHierarchy.getChildren( getCurrentSelection()); OSL_ASSERT( !aChildren.empty()); setCurrentSelection( aChildren.front()); } return bResult; } bool ObjectKeyNavigation::veryFirst() { ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren()); bool bResult = !aChildren.empty(); if( bResult ) setCurrentSelection( aChildren.front()); return bResult; } bool ObjectKeyNavigation::veryLast() { ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram ); ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren()); bool bResult = !aChildren.empty(); if( bResult ) setCurrentSelection( aChildren.back()); return bResult; } } // namespace chart