xref: /AOO41X/main/chart2/source/controller/main/ObjectHierarchy.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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