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