summaryrefslogtreecommitdiff
path: root/chart2/source/controller/main/ObjectHierarchy.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'chart2/source/controller/main/ObjectHierarchy.cxx')
-rw-r--r--chart2/source/controller/main/ObjectHierarchy.cxx860
1 files changed, 860 insertions, 0 deletions
diff --git a/chart2/source/controller/main/ObjectHierarchy.cxx b/chart2/source/controller/main/ObjectHierarchy.cxx
new file mode 100644
index 000000000000..19577eb4900e
--- /dev/null
+++ b/chart2/source/controller/main/ObjectHierarchy.cxx
@@ -0,0 +1,860 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * 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
+ * <http://www.openoffice.org/license.html>
+ * 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 "chartview/DrawModelWrapper.hxx"
+
+#include <map>
+#include <algorithm>
+
+#include <com/sun/star/chart2/XTitled.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/awt/Key.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+
+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_ObjectToOID : public ::std::unary_function< Reference< uno::XInterface >, ::chart::ObjectIdentifier >
+{
+ explicit lcl_ObjectToOID( const Reference< chart2::XChartDocument > & xChartDoc ) :
+ m_xModel( xChartDoc, uno::UNO_QUERY )
+ {}
+
+ ::chart::ObjectIdentifier operator() ( const Reference< uno::XInterface > & xObj )
+ {
+ return ::chart::ObjectIdentifier( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xObj, m_xModel ) );
+ }
+
+private:
+ Reference< frame::XModel > m_xModel;
+};
+
+void lcl_getChildOIDs(
+ ::chart::ObjectHierarchy::tChildContainer& rOutChildren,
+ const Reference< container::XIndexAccess >& xShapes )
+{
+ if( xShapes.is())
+ {
+ sal_Int32 nCount = xShapes->getCount();
+ for( sal_Int32 i=0; i<nCount; ++i)
+ {
+ Reference< beans::XPropertySet > 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( ::chart::ObjectIdentifier( aName ) );
+ }
+ Reference< container::XIndexAccess > xNewShapes( xShapeProp, uno::UNO_QUERY );
+ if( xNewShapes.is())
+ lcl_getChildOIDs( 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( ::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 ObjectHierarchy::tOID& rParent );
+ ObjectHierarchy::tChildContainer getChildren( const ObjectHierarchy::tOID& rParent );
+ ObjectHierarchy::tChildContainer getSiblings( const ObjectHierarchy::tOID& rNode );
+
+ ObjectHierarchy::tOID getParent( const ObjectHierarchy::tOID& rOID );
+
+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 );
+ void createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer );
+
+ ObjectHierarchy::tOID getParentImpl(
+ const ObjectHierarchy::tOID& rParentOID,
+ const ObjectHierarchy::tOID& rOID );
+
+ typedef ::std::map< ObjectHierarchy::tOID, 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 )
+{
+ m_aChildMap = tChildMap();//clear tree
+
+ 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 ) );
+ ObjectHierarchy::tOID aDiaOID;
+ if( xDiagram.is() )
+ aDiaOID = ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram, xModel ) );
+ ObjectHierarchy::tChildContainer aTopLevelContainer;
+
+ // First Level
+
+ // Chart Area
+ if( m_bOrderingForElementSelector )
+ {
+ aTopLevelContainer.push_back( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) );
+ if( xDiagram.is() )
+ {
+ aTopLevelContainer.push_back( aDiaOID );
+ 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( 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( 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<aAxes.getLength(); ++i )
+ lcl_addAxisTitle( aAxes[i], aTopLevelContainer, xModel );
+
+ // Diagram
+ aTopLevelContainer.push_back( aDiaOID );
+ }
+
+ if( m_bFlattenDiagram )
+ createDiagramTree( aTopLevelContainer, xChartDocument, xDiagram );
+ else
+ {
+ ObjectHierarchy::tChildContainer aSubContainer;
+ createDiagramTree( aSubContainer, xChartDocument, xDiagram );
+ if( !aSubContainer.empty() )
+ m_aChildMap[ aDiaOID ] = aSubContainer;
+ }
+
+ if( !m_bOrderingForElementSelector )
+ createLegendTree( aTopLevelContainer, xChartDocument, xDiagram );
+ }
+
+ // #i12587# support for shapes in chart
+ if ( !m_bOrderingForElementSelector )
+ {
+ createAdditionalShapesTree( aTopLevelContainer );
+ }
+
+ // Chart Area
+ if( !m_bOrderingForElementSelector )
+ aTopLevelContainer.push_back(
+ ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) );
+
+ if( ! aTopLevelContainer.empty())
+ m_aChildMap[ ObjectHierarchy::getRootNodeOID() ] = aTopLevelContainer;
+}
+
+void ImplObjectHierarchy::createLegendTree(
+ ObjectHierarchy::tChildContainer & rContainer,
+ const Reference< XChartDocument > & xChartDoc,
+ const Reference< XDiagram > & xDiagram )
+{
+ if( xDiagram.is() && LegendHelper::hasLegend( xDiagram ) )
+ {
+ ObjectHierarchy::tOID aLegendOID( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram->getLegend(), Reference< frame::XModel >( xChartDoc, uno::UNO_QUERY ) ) ) );
+ rContainer.push_back( aLegendOID );
+
+ // iterate over child shapes of legend and search for matching CIDs
+ if( m_pExplicitValueProvider )
+ {
+ Reference< container::XIndexAccess > xLegendShapeContainer(
+ m_pExplicitValueProvider->getShapeForCID( aLegendOID.getObjectCID() ), uno::UNO_QUERY );
+ ObjectHierarchy::tChildContainer aLegendEntryOIDs;
+ lcl_getChildOIDs( aLegendEntryOIDs, xLegendShapeContainer );
+
+ m_aChildMap[ aLegendOID ] = aLegendEntryOIDs;
+ }
+ }
+}
+
+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_ObjectToOID( 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<aAxes.getLength(); ++nA )
+ {
+ Reference< XAxis > 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( 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( ObjectIdentifier( 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( ObjectIdentifier( 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( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, rtl::OUString() ) ) );
+
+ Reference< beans::XPropertySet > xFloor( xDiagram->getFloor());
+ if( xFloor.is())
+ rContainer.push_back(
+ ObjectIdentifier( 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<aCooSysSeq.getLength(); ++nCooSysIdx )
+ {
+ Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
+ Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
+ for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypeSeq.getLength(); ++nCTIdx )
+ {
+ Reference< XChartType > 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<nNumberOfSeries; ++nSeriesIdx )
+ {
+ OUString aSeriesParticle(
+ ObjectIdentifier::createParticleForSeries(
+ nDiagramIndex, nCooSysIdx, nCTIdx, nSeriesIdx ));
+ ObjectHierarchy::tOID aSeriesOID(
+ ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForParticle( aSeriesParticle ) ) );
+ rOutDiagramSubContainer.push_back( aSeriesOID );
+
+ ObjectHierarchy::tChildContainer aSeriesSubContainer;
+
+ Reference< chart2::XDataSeries > 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( 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<aCurves.getLength(); ++nCurveIdx )
+ {
+ bool bIsAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[nCurveIdx] );
+ aSeriesSubContainer.push_back(
+ ObjectIdentifier( ObjectIdentifier::createDataCurveCID( aSeriesParticle, nCurveIdx, bIsAverageLine ) ) );
+ if( RegressionCurveHelper::hasEquation( aCurves[nCurveIdx] ) )
+ {
+ aSeriesSubContainer.push_back(
+ ObjectIdentifier( ObjectIdentifier::createDataCurveEquationCID( aSeriesParticle, nCurveIdx ) ) );
+ }
+ }
+ Reference< beans::XPropertySet > 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( 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( aSeriesOID.getObjectCID() ), uno::UNO_QUERY );
+ lcl_getChildOIDs( aSeriesSubContainer, xSeriesShapeContainer );
+ }
+
+ if( ! aSeriesSubContainer.empty())
+ m_aChildMap[ aSeriesOID ] = aSeriesSubContainer;
+ }
+ }
+ }
+ }
+ catch( uno::Exception & ex )
+ {
+ ASSERT_EXCEPTION( ex );
+ }
+}
+
+void ImplObjectHierarchy::createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer )
+{
+ try
+ {
+ if ( m_pExplicitValueProvider )
+ {
+ Reference< drawing::XDrawPage > xDrawPage( m_pExplicitValueProvider->getDrawModelWrapper()->getMainDrawPage() );
+ Reference< drawing::XShapes > xDrawPageShapes( xDrawPage, uno::UNO_QUERY_THROW );
+ Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) );
+ sal_Int32 nCount = xDrawPageShapes->getCount();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ Reference< drawing::XShape > xShape;
+ if ( xDrawPageShapes->getByIndex( i ) >>= xShape )
+ {
+ if ( xShape.is() && xShape != xChartRoot )
+ {
+ rContainer.push_back( ObjectIdentifier( xShape ) );
+ }
+ }
+ }
+ }
+ }
+ catch ( uno::Exception& ex )
+ {
+ ASSERT_EXCEPTION( ex );
+ }
+}
+
+bool ImplObjectHierarchy::hasChildren( const ObjectHierarchy::tOID& rParent )
+{
+ if ( rParent.isValid() )
+ {
+ tChildMap::const_iterator aIt( m_aChildMap.find( rParent ));
+ if( aIt != m_aChildMap.end())
+ return ! (aIt->second.empty());
+ }
+ return false;
+}
+
+ObjectHierarchy::tChildContainer ImplObjectHierarchy::getChildren( const ObjectHierarchy::tOID& rParent )
+{
+ if ( rParent.isValid() )
+ {
+ tChildMap::const_iterator aIt( m_aChildMap.find( rParent ));
+ if( aIt != m_aChildMap.end())
+ return aIt->second;
+ }
+ return ObjectHierarchy::tChildContainer();
+}
+
+ObjectHierarchy::tChildContainer ImplObjectHierarchy::getSiblings( const ObjectHierarchy::tOID& rNode )
+{
+ if ( rNode.isValid() && !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::tOID ImplObjectHierarchy::getParentImpl(
+ const ObjectHierarchy::tOID & rParentOID,
+ const ObjectHierarchy::tOID & rOID )
+{
+ // search children
+ ObjectHierarchy::tChildContainer aChildren( getChildren( rParentOID ));
+ ObjectHierarchy::tChildContainer::const_iterator aIt(
+ ::std::find( aChildren.begin(), aChildren.end(), rOID ));
+ // recursion end
+ if( aIt != aChildren.end())
+ return rParentOID;
+
+ for( aIt = aChildren.begin(); aIt != aChildren.end(); ++aIt )
+ {
+ // recursion
+ ObjectHierarchy::tOID aTempParent( getParentImpl( *aIt, rOID ));
+ if ( aTempParent.isValid() )
+ {
+ // exit on success
+ return aTempParent;
+ }
+ }
+
+ // exit on fail
+ return ObjectHierarchy::tOID();
+}
+
+ObjectHierarchy::tOID ImplObjectHierarchy::getParent(
+ const ObjectHierarchy::tOID & rOID )
+{
+ return getParentImpl( ObjectHierarchy::getRootNodeOID(), rOID );
+}
+
+} // 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()
+{}
+
+ObjectHierarchy::tOID ObjectHierarchy::getRootNodeOID()
+{
+ return ObjectIdentifier( C2U( "ROOT" ) );
+}
+
+bool ObjectHierarchy::isRootNode( const ObjectHierarchy::tOID& rOID )
+{
+ return ( rOID == ObjectHierarchy::getRootNodeOID() );
+}
+
+ObjectHierarchy::tChildContainer ObjectHierarchy::getTopLevelChildren() const
+{
+ return m_apImpl->getChildren( ObjectHierarchy::getRootNodeOID());
+}
+
+bool ObjectHierarchy::hasChildren( const tOID& rParent ) const
+{
+ return m_apImpl->hasChildren( rParent );
+}
+
+ObjectHierarchy::tChildContainer ObjectHierarchy::getChildren(
+ const ObjectHierarchy::tOID& rParent ) const
+{
+ if ( rParent.isValid() )
+ return m_apImpl->getChildren( rParent );
+
+ return ObjectHierarchy::tChildContainer();
+}
+
+ObjectHierarchy::tChildContainer ObjectHierarchy::getSiblings(
+ const ObjectHierarchy::tOID& rNode ) const
+{
+ if ( rNode.isValid() && !isRootNode( rNode ) )
+ return m_apImpl->getSiblings( rNode );
+
+ return ObjectHierarchy::tChildContainer();
+}
+
+ObjectHierarchy::tOID ObjectHierarchy::getParent(
+ const ObjectHierarchy::tOID& rNode ) const
+{
+ return m_apImpl->getParent( rNode );
+}
+
+sal_Int32 ObjectHierarchy::getIndexInParent(
+ const ObjectHierarchy::tOID& rNode ) const
+{
+ tOID aParentOID( m_apImpl->getParent( rNode ));
+ tChildContainer aChildren( m_apImpl->getChildren( aParentOID ) );
+ tChildContainer::const_iterator aIt( aChildren.begin() );
+ for( sal_Int32 nIndex = 0; aIt != aChildren.end(); ++nIndex, ++aIt )
+ {
+ if ( *aIt == rNode )
+ return nIndex;
+ }
+ return -1;
+}
+
+// ================================================================================
+
+ObjectKeyNavigation::ObjectKeyNavigation(
+ const ObjectHierarchy::tOID & rCurrentOID,
+ const Reference< chart2::XChartDocument > & xChartDocument,
+ ExplicitValueProvider * pExplicitValueProvider /* = 0 */ ) :
+ m_aCurrentOID( rCurrentOID ),
+ m_xChartDocument( xChartDocument ),
+ m_pExplicitValueProvider( pExplicitValueProvider ),
+ m_bStepDownInDiagram( true )
+{
+ if ( !m_aCurrentOID.isValid() )
+ {
+ setCurrentSelection( ObjectHierarchy::getRootNodeOID() );
+ }
+}
+
+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( ObjectIdentifier() );
+ bResult = true;
+ break;
+ default:
+ bResult = false;
+ break;
+ }
+ return bResult;
+}
+
+void ObjectKeyNavigation::setCurrentSelection( const ObjectHierarchy::tOID& rOID )
+{
+ m_aCurrentOID = rOID;
+}
+
+ObjectHierarchy::tOID ObjectKeyNavigation::getCurrentSelection() const
+{
+ return m_aCurrentOID;
+}
+
+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