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