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