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