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 : #include "ObjectHierarchy.hxx"
21 : #include "ObjectIdentifier.hxx"
22 : #include "ChartModelHelper.hxx"
23 : #include "DiagramHelper.hxx"
24 : #include "RegressionCurveHelper.hxx"
25 : #include "AxisHelper.hxx"
26 : #include "chartview/ExplicitValueProvider.hxx"
27 : #include "macros.hxx"
28 : #include "LineProperties.hxx"
29 : #include "ChartTypeHelper.hxx"
30 : #include "DataSeriesHelper.hxx"
31 : #include "LegendHelper.hxx"
32 : #include "chartview/DrawModelWrapper.hxx"
33 : #include <unonames.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 1582 : void lcl_addAxisTitle( const Reference< XAxis >& xAxis, ::chart::ObjectHierarchy::tChildContainer& rContainer, const Reference< frame::XModel >& xChartModel )
103 : {
104 1582 : Reference< XTitled > xAxisTitled( xAxis, uno::UNO_QUERY );
105 1582 : if( xAxisTitled.is())
106 : {
107 1582 : Reference< XTitle > xAxisTitle( xAxisTitled->getTitleObject());
108 1582 : if( xAxisTitle.is())
109 : rContainer.push_back(
110 0 : ::chart::ObjectIdentifier( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xAxisTitle, xChartModel ) ) );
111 1582 : }
112 1582 : }
113 :
114 : } // anonymous namespace
115 :
116 : namespace chart
117 : {
118 :
119 : namespace impl
120 : {
121 :
122 820 : 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 : static 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 820 : 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 820 : m_bOrderingForElementSelector( bOrderingForElementSelector )
178 : {
179 820 : createTree( xChartDocument );
180 : // don't remember this helper to avoid access after lifetime
181 820 : m_pExplicitValueProvider = 0;
182 820 : }
183 :
184 820 : void ImplObjectHierarchy::createTree( const Reference< XChartDocument >& xChartDocument )
185 : {
186 820 : m_aChildMap = tChildMap();//clear tree
187 :
188 820 : if( !xChartDocument.is() )
189 820 : return;
190 :
191 : //@todo: change ObjectIdentifier to take an XChartDocument rather than XModel
192 820 : Reference< frame::XModel > xModel( xChartDocument, uno::UNO_QUERY );
193 1640 : Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartDocument ) );
194 1640 : ObjectHierarchy::tOID aDiaOID;
195 820 : if( xDiagram.is() )
196 804 : aDiaOID = ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram, xModel ) );
197 1640 : ObjectHierarchy::tChildContainer aTopLevelContainer;
198 :
199 : // First Level
200 :
201 : // Chart Area
202 820 : if( m_bOrderingForElementSelector )
203 : {
204 820 : aTopLevelContainer.push_back( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) );
205 820 : if( xDiagram.is() )
206 : {
207 804 : aTopLevelContainer.push_back( aDiaOID );
208 804 : createWallAndFloor( aTopLevelContainer, xDiagram );
209 804 : createLegendTree( aTopLevelContainer, xChartDocument, xDiagram );
210 : }
211 : }
212 :
213 : // Main Title
214 1640 : Reference< XTitled > xDocTitled( xChartDocument, uno::UNO_QUERY );
215 820 : if( xDocTitled.is())
216 : {
217 820 : Reference< XTitle > xMainTitle( xDocTitled->getTitleObject());
218 820 : if( xMainTitle.is())
219 : aTopLevelContainer.push_back(
220 474 : ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xMainTitle, xModel ) ) );
221 : }
222 :
223 820 : if( xDiagram.is())
224 : {
225 : // Sub Title. Note: This is interpreted of being top level
226 804 : Reference< XTitled > xDiaTitled( xDiagram, uno::UNO_QUERY );
227 804 : if( xDiaTitled.is())
228 : {
229 804 : Reference< XTitle > xSubTitle( xDiaTitled->getTitleObject());
230 804 : if( xSubTitle.is())
231 : aTopLevelContainer.push_back(
232 301 : ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xSubTitle, xModel ) ) );
233 : }
234 :
235 804 : 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 804 : if( m_bFlattenDiagram )
247 804 : 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 804 : if( !m_bOrderingForElementSelector )
257 0 : createLegendTree( aTopLevelContainer, xChartDocument, xDiagram );
258 : }
259 :
260 : // #i12587# support for shapes in chart
261 820 : if ( !m_bOrderingForElementSelector )
262 : {
263 0 : createAdditionalShapesTree( aTopLevelContainer );
264 : }
265 :
266 : // Chart Area
267 820 : if( !m_bOrderingForElementSelector )
268 : aTopLevelContainer.push_back(
269 0 : ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) );
270 :
271 820 : if( ! aTopLevelContainer.empty())
272 1640 : m_aChildMap[ ObjectHierarchy::getRootNodeOID() ] = aTopLevelContainer;
273 : }
274 :
275 804 : void ImplObjectHierarchy::createLegendTree(
276 : ObjectHierarchy::tChildContainer & rContainer,
277 : const Reference< XChartDocument > & xChartDoc,
278 : const Reference< XDiagram > & xDiagram )
279 : {
280 804 : if( xDiagram.is() && LegendHelper::hasLegend( xDiagram ) )
281 : {
282 776 : ObjectHierarchy::tOID aLegendOID( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram->getLegend(), Reference< frame::XModel >( xChartDoc, uno::UNO_QUERY ) ) ) );
283 776 : rContainer.push_back( aLegendOID );
284 :
285 : // iterate over child shapes of legend and search for matching CIDs
286 776 : 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 776 : }
295 : }
296 804 : }
297 :
298 804 : void ImplObjectHierarchy::createAxesTree(
299 : ObjectHierarchy::tChildContainer & rContainer,
300 : const Reference< XChartDocument > & xChartDoc,
301 : const Reference< XDiagram > & xDiagram )
302 : {
303 804 : Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
304 804 : sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
305 1608 : uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
306 804 : bool bSupportsAxesGrids = ChartTypeHelper::isSupportingMainAxis( xChartType, nDimensionCount, 0 );
307 804 : if( bSupportsAxesGrids )
308 : {
309 790 : Sequence< Reference< XAxis > > aAxes( AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ true ) );
310 790 : 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 790 : aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ false );
317 : // Grids
318 1580 : Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
319 2372 : for( sal_Int32 nA=0; nA<aAxes.getLength(); ++nA )
320 : {
321 1582 : Reference< XAxis > xAxis( aAxes[nA] );
322 1582 : if(!xAxis.is())
323 0 : continue;
324 :
325 1582 : sal_Int32 nCooSysIndex = 0;
326 1582 : sal_Int32 nDimensionIndex = 0;
327 1582 : sal_Int32 nAxisIndex = 0;
328 1582 : AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex );
329 1582 : if( nAxisIndex>0 && !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount, nDimensionIndex ) )
330 0 : continue;
331 :
332 1582 : if( m_bOrderingForElementSelector )
333 : {
334 : // axis
335 1582 : if( AxisHelper::isAxisVisible( xAxis ) )
336 : rContainer.push_back(
337 1373 : ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartModel ) ) );
338 :
339 : // axis title
340 1582 : lcl_addAxisTitle( aAxes[nA], rContainer, xChartModel );
341 : }
342 :
343 3164 : Reference< beans::XPropertySet > xGridProperties( xAxis->getGridProperties() );
344 1582 : if( AxisHelper::isGridVisible( xGridProperties ) )
345 : {
346 : //main grid
347 : rContainer.push_back(
348 626 : ObjectIdentifier( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel ) ) ) );
349 : }
350 :
351 3164 : Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() );;
352 1582 : sal_Int32 nSubGrid = 0;
353 3164 : for( nSubGrid = 0; nSubGrid < aSubGrids.getLength(); ++nSubGrid )
354 : {
355 1582 : Reference< beans::XPropertySet > xSubGridProperties( aSubGrids[nSubGrid] );
356 1582 : if( AxisHelper::isGridVisible( xSubGridProperties ) )
357 : {
358 : //sub grid
359 : rContainer.push_back(
360 0 : ObjectIdentifier( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel, nSubGrid ) ) ) );
361 : }
362 1582 : }
363 2372 : }
364 804 : }
365 804 : }
366 :
367 804 : void ImplObjectHierarchy::createWallAndFloor(
368 : ObjectHierarchy::tChildContainer & rContainer,
369 : const Reference< XDiagram > & xDiagram )
370 : {
371 804 : sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
372 804 : bool bIsThreeD = ( nDimensionCount == 3 );
373 804 : bool bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram );
374 804 : if( bHasWall && bIsThreeD )
375 : {
376 : rContainer.push_back(
377 6 : ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, OUString() ) ) );
378 :
379 6 : Reference< beans::XPropertySet > xFloor( xDiagram->getFloor());
380 6 : if( xFloor.is())
381 : rContainer.push_back(
382 6 : ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, OUString() ) ) );
383 : }
384 :
385 804 : }
386 :
387 804 : void ImplObjectHierarchy::createDiagramTree(
388 : ObjectHierarchy::tChildContainer & rContainer,
389 : const Reference< XChartDocument > & xChartDoc,
390 : const Reference< XDiagram > & xDiagram )
391 : {
392 804 : 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 804 : createAxesTree( rContainer, xChartDoc, xDiagram );
401 804 : createDataSeriesTree( rContainer, xDiagram );
402 : }
403 804 : }
404 :
405 804 : void ImplObjectHierarchy::createDataSeriesTree(
406 : ObjectHierarchy::tChildContainer & rOutDiagramSubContainer,
407 : const Reference< XDiagram > & xDiagram )
408 : {
409 804 : Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
410 :
411 : try
412 : {
413 804 : sal_Int32 nDiagramIndex = 0;
414 804 : sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
415 : Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
416 804 : xCooSysCnt->getCoordinateSystems());
417 1606 : for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
418 : {
419 802 : Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
420 1604 : Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
421 1604 : for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypeSeq.getLength(); ++nCTIdx )
422 : {
423 802 : Reference< XChartType > xChartType( aChartTypeSeq[nCTIdx] );
424 1604 : Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW );
425 1604 : Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() );
426 : const sal_Int32 nNumberOfSeries =
427 802 : ChartTypeHelper::getNumberOfDisplayedSeries( xChartType, aSeriesSeq.getLength());
428 :
429 3180 : for( sal_Int32 nSeriesIdx=0; nSeriesIdx<nNumberOfSeries; ++nSeriesIdx )
430 : {
431 : OUString aSeriesParticle(
432 : ObjectIdentifier::createParticleForSeries(
433 2378 : nDiagramIndex, nCooSysIdx, nCTIdx, nSeriesIdx ));
434 : ObjectHierarchy::tOID aSeriesOID(
435 4756 : ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForParticle( aSeriesParticle ) ) );
436 2378 : rOutDiagramSubContainer.push_back( aSeriesOID );
437 :
438 4756 : ObjectHierarchy::tChildContainer aSeriesSubContainer;
439 :
440 4756 : Reference< chart2::XDataSeries > xSeries( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY );
441 :
442 : // data lablels
443 2378 : 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 2378 : if( ChartTypeHelper::isSupportingStatisticProperties( xChartType, nDimensionCount ) )
453 : {
454 2346 : Reference< chart2::XRegressionCurveContainer > xCurveCnt( xSeries, uno::UNO_QUERY );
455 2346 : if( xCurveCnt.is())
456 : {
457 2346 : Sequence< Reference< chart2::XRegressionCurve > > aCurves( xCurveCnt->getRegressionCurves());
458 2352 : 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 4692 : Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY );
470 4692 : Reference< beans::XPropertySet > xErrorBarProp;
471 11730 : if( xSeriesProp.is() &&
472 14076 : (xSeriesProp->getPropertyValue( CHART_UNONAME_ERRORBAR_Y) >>= xErrorBarProp) &&
473 2346 : xErrorBarProp.is())
474 : {
475 858 : sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE;
476 1716 : if( ( xErrorBarProp->getPropertyValue( "ErrorBarStyle") >>= nStyle ) &&
477 858 : ( 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 11730 : if( xSeriesProp.is() &&
486 14076 : (xSeriesProp->getPropertyValue(CHART_UNONAME_ERRORBAR_X) >>= xErrorBarProp) &&
487 2346 : 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 2346 : }
498 2346 : }
499 : }
500 :
501 : // Data Points
502 : // iterate over child shapes of legend and search for matching CIDs
503 2378 : 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 2378 : if( ! aSeriesSubContainer.empty())
511 6 : m_aChildMap[ aSeriesOID ] = aSeriesSubContainer;
512 2378 : }
513 802 : }
514 1606 : }
515 : }
516 0 : catch( const uno::Exception & ex )
517 : {
518 : ASSERT_EXCEPTION( ex );
519 804 : }
520 804 : }
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 8390 : ObjectHierarchy::tChildContainer ImplObjectHierarchy::getChildren( const ObjectHierarchy::tOID& rParent )
563 : {
564 8390 : if ( rParent.isValid() )
565 : {
566 8390 : tChildMap::const_iterator aIt( m_aChildMap.find( rParent ));
567 8390 : if( aIt != m_aChildMap.end())
568 826 : return aIt->second;
569 : }
570 7564 : 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 820 : ObjectHierarchy::ObjectHierarchy(
625 : const Reference< XChartDocument > & xChartDocument,
626 : ExplicitValueProvider * pExplicitValueProvider /* = 0 */,
627 : bool bFlattenDiagram /* = false */,
628 : bool bOrderingForElementSelector /* = false */) :
629 820 : m_apImpl( new impl::ImplObjectHierarchy( xChartDocument, pExplicitValueProvider, bFlattenDiagram, bOrderingForElementSelector ))
630 820 : {}
631 :
632 820 : ObjectHierarchy::~ObjectHierarchy()
633 820 : {}
634 :
635 1640 : ObjectHierarchy::tOID ObjectHierarchy::getRootNodeOID()
636 : {
637 1640 : return ObjectIdentifier( "ROOT" );
638 : }
639 :
640 0 : bool ObjectHierarchy::isRootNode( const ObjectHierarchy::tOID& rOID )
641 : {
642 0 : return ( rOID == ObjectHierarchy::getRootNodeOID() );
643 : }
644 :
645 0 : ObjectHierarchy::tChildContainer ObjectHierarchy::getTopLevelChildren() const
646 : {
647 0 : return m_apImpl->getChildren( ObjectHierarchy::getRootNodeOID());
648 : }
649 :
650 0 : bool ObjectHierarchy::hasChildren( const tOID& rParent ) const
651 : {
652 0 : return m_apImpl->hasChildren( rParent );
653 : }
654 :
655 8390 : ObjectHierarchy::tChildContainer ObjectHierarchy::getChildren(
656 : const ObjectHierarchy::tOID& rParent ) const
657 : {
658 8390 : if ( rParent.isValid() )
659 8390 : return m_apImpl->getChildren( rParent );
660 :
661 0 : return ObjectHierarchy::tChildContainer();
662 : }
663 :
664 0 : ObjectHierarchy::tChildContainer ObjectHierarchy::getSiblings(
665 : const ObjectHierarchy::tOID& rNode ) const
666 : {
667 0 : if ( rNode.isValid() && !isRootNode( rNode ) )
668 0 : return m_apImpl->getSiblings( rNode );
669 :
670 0 : return ObjectHierarchy::tChildContainer();
671 : }
672 :
673 0 : ObjectHierarchy::tOID ObjectHierarchy::getParent(
674 : const ObjectHierarchy::tOID& rNode ) const
675 : {
676 0 : return m_apImpl->getParent( rNode );
677 : }
678 :
679 0 : sal_Int32 ObjectHierarchy::getIndexInParent(
680 : const ObjectHierarchy::tOID& rNode ) const
681 : {
682 0 : tOID aParentOID( m_apImpl->getParent( rNode ));
683 0 : tChildContainer aChildren( m_apImpl->getChildren( aParentOID ) );
684 0 : tChildContainer::const_iterator aIt( aChildren.begin() );
685 0 : for( sal_Int32 nIndex = 0; aIt != aChildren.end(); ++nIndex, ++aIt )
686 : {
687 0 : if ( *aIt == rNode )
688 0 : return nIndex;
689 : }
690 0 : return -1;
691 : }
692 :
693 0 : ObjectKeyNavigation::ObjectKeyNavigation(
694 : const ObjectHierarchy::tOID & rCurrentOID,
695 : const Reference< chart2::XChartDocument > & xChartDocument,
696 : ExplicitValueProvider * pExplicitValueProvider /* = 0 */ ) :
697 : m_aCurrentOID( rCurrentOID ),
698 : m_xChartDocument( xChartDocument ),
699 : m_pExplicitValueProvider( pExplicitValueProvider ),
700 0 : m_bStepDownInDiagram( true )
701 : {
702 0 : if ( !m_aCurrentOID.isValid() )
703 : {
704 0 : setCurrentSelection( ObjectHierarchy::getRootNodeOID() );
705 : }
706 0 : }
707 :
708 0 : bool ObjectKeyNavigation::handleKeyEvent(
709 : const awt::KeyEvent & rEvent )
710 : {
711 0 : bool bResult = false;
712 :
713 0 : switch( rEvent.KeyCode )
714 : {
715 : case awt::Key::TAB:
716 0 : if( rEvent.Modifiers & awt::KeyModifier::SHIFT )
717 0 : bResult = previous();
718 : else
719 0 : bResult = next();
720 0 : break;
721 : case awt::Key::HOME:
722 0 : bResult = first();
723 0 : break;
724 : case awt::Key::END:
725 0 : bResult = last();
726 0 : break;
727 : case awt::Key::F3:
728 0 : if( rEvent.Modifiers & awt::KeyModifier::SHIFT )
729 0 : bResult = up();
730 : else
731 0 : bResult = down();
732 0 : break;
733 : case awt::Key::ESCAPE:
734 0 : setCurrentSelection( ObjectIdentifier() );
735 0 : bResult = true;
736 0 : break;
737 : default:
738 0 : bResult = false;
739 0 : break;
740 : }
741 0 : return bResult;
742 : }
743 :
744 0 : void ObjectKeyNavigation::setCurrentSelection( const ObjectHierarchy::tOID& rOID )
745 : {
746 0 : m_aCurrentOID = rOID;
747 0 : }
748 :
749 0 : bool ObjectKeyNavigation::first()
750 : {
751 0 : ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram );
752 0 : ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) );
753 0 : bool bResult = !aSiblings.empty();
754 0 : if( bResult )
755 0 : setCurrentSelection( aSiblings.front());
756 : else
757 0 : bResult = veryFirst();
758 0 : return bResult;
759 : }
760 :
761 0 : bool ObjectKeyNavigation::last()
762 : {
763 0 : ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram );
764 0 : ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) );
765 0 : bool bResult = !aSiblings.empty();
766 0 : if( bResult )
767 0 : setCurrentSelection( aSiblings.back());
768 : else
769 0 : bResult = veryLast();
770 0 : return bResult;
771 : }
772 :
773 0 : bool ObjectKeyNavigation::next()
774 : {
775 0 : ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram );
776 0 : ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) );
777 0 : bool bResult = !aSiblings.empty();
778 0 : if( bResult )
779 : {
780 : ObjectHierarchy::tChildContainer::const_iterator aIt(
781 0 : ::std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection()));
782 : OSL_ASSERT( aIt != aSiblings.end());
783 0 : if( ++aIt == aSiblings.end())
784 0 : aIt = aSiblings.begin();
785 0 : setCurrentSelection( *aIt );
786 : }
787 : else
788 0 : bResult = veryFirst();
789 :
790 0 : return bResult;
791 : }
792 :
793 0 : bool ObjectKeyNavigation::previous()
794 : {
795 0 : ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram );
796 0 : ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection()));
797 0 : bool bResult = !aSiblings.empty();
798 0 : if( bResult )
799 : {
800 : ObjectHierarchy::tChildContainer::const_iterator aIt(
801 0 : ::std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection()));
802 : OSL_ASSERT( aIt != aSiblings.end());
803 0 : if( aIt == aSiblings.begin())
804 0 : aIt = aSiblings.end();
805 0 : --aIt;
806 0 : setCurrentSelection( *aIt );
807 : }
808 : else
809 0 : bResult = veryLast();
810 0 : return bResult;
811 : }
812 :
813 0 : bool ObjectKeyNavigation::up()
814 : {
815 0 : ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram );
816 0 : bool bResult = !ObjectHierarchy::isRootNode( getCurrentSelection());
817 0 : if( bResult )
818 0 : setCurrentSelection( aHierarchy.getParent( getCurrentSelection()));
819 0 : return bResult;
820 : }
821 :
822 0 : bool ObjectKeyNavigation::down()
823 : {
824 0 : ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram );
825 0 : bool bResult = aHierarchy.hasChildren( getCurrentSelection());
826 0 : if( bResult )
827 : {
828 0 : ObjectHierarchy::tChildContainer aChildren = aHierarchy.getChildren( getCurrentSelection());
829 : OSL_ASSERT( !aChildren.empty());
830 0 : setCurrentSelection( aChildren.front());
831 : }
832 0 : return bResult;
833 : }
834 :
835 0 : bool ObjectKeyNavigation::veryFirst()
836 : {
837 0 : ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram );
838 0 : ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren());
839 0 : bool bResult = !aChildren.empty();
840 0 : if( bResult )
841 0 : setCurrentSelection( aChildren.front());
842 0 : return bResult;
843 : }
844 :
845 0 : bool ObjectKeyNavigation::veryLast()
846 : {
847 0 : ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider, m_bStepDownInDiagram );
848 0 : ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren());
849 0 : bool bResult = !aChildren.empty();
850 0 : if( bResult )
851 0 : setCurrentSelection( aChildren.back());
852 0 : return bResult;
853 : }
854 :
855 57 : } // namespace chart
856 :
857 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|