bump product version to 4.1.6.2
[LibreOffice.git] / chart2 / source / tools / DiagramHelper.cxx
blob1356237d551572bdab953873309e7ebbe0230162
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "DiagramHelper.hxx"
21 #include "LegendHelper.hxx"
22 #include "PropertyHelper.hxx"
23 #include "macros.hxx"
24 #include "DataSeriesHelper.hxx"
25 #include "AxisHelper.hxx"
26 #include "ContainerHelper.hxx"
27 #include "ChartTypeHelper.hxx"
28 #include "ChartModelHelper.hxx"
29 #include "CommonConverters.hxx"
30 #include "ExplicitCategoriesProvider.hxx"
31 #include "servicenames_charttypes.hxx"
32 #include "RelativePositionHelper.hxx"
33 #include "ControllerLockGuard.hxx"
34 #include "NumberFormatterWrapper.hxx"
36 #include <com/sun/star/chart/MissingValueTreatment.hpp>
37 #include <com/sun/star/chart/XChartDocument.hpp>
38 #include <com/sun/star/chart/XDiagramPositioning.hpp>
39 #include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
40 #include <com/sun/star/chart2/XTitled.hpp>
41 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
42 #include <com/sun/star/chart2/XChartTypeTemplate.hpp>
43 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
44 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
45 #include <com/sun/star/chart2/InterpretedData.hpp>
46 #include <com/sun/star/chart2/AxisType.hpp>
47 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
48 #include <com/sun/star/chart2/RelativePosition.hpp>
49 #include <com/sun/star/chart2/RelativeSize.hpp>
51 #include <com/sun/star/util/NumberFormat.hpp>
52 #include <com/sun/star/util/XModifiable.hpp>
53 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
55 #include <unotools/saveopt.hxx>
56 #include <rtl/math.hxx>
57 #include <svl/zformat.hxx>
58 // header for class Application
59 #include <vcl/svapp.hxx>
61 using namespace ::com::sun::star;
62 using namespace ::com::sun::star::chart2;
63 using namespace ::std;
65 using ::com::sun::star::uno::Reference;
66 using ::com::sun::star::uno::Sequence;
67 using ::com::sun::star::uno::Any;
68 using ::com::sun::star::chart2::XAnyDescriptionAccess;
70 namespace chart
73 DiagramHelper::tTemplateWithServiceName
74 DiagramHelper::getTemplateForDiagram(
75 const Reference< XDiagram > & xDiagram,
76 const Reference< lang::XMultiServiceFactory > & xChartTypeManager,
77 const OUString & rPreferredTemplateName )
79 DiagramHelper::tTemplateWithServiceName aResult;
81 if( ! (xChartTypeManager.is() && xDiagram.is()))
82 return aResult;
84 Sequence< OUString > aServiceNames( xChartTypeManager->getAvailableServiceNames());
85 const sal_Int32 nLength = aServiceNames.getLength();
87 bool bHasPreferredTemplate = !rPreferredTemplateName.isEmpty();
88 bool bTemplateFound = false;
90 if( bHasPreferredTemplate )
92 Reference< XChartTypeTemplate > xTempl(
93 xChartTypeManager->createInstance( rPreferredTemplateName ), uno::UNO_QUERY );
95 if( xTempl.is() &&
96 xTempl->matchesTemplate( xDiagram, sal_True ))
98 aResult.first = xTempl;
99 aResult.second = rPreferredTemplateName;
100 bTemplateFound = true;
104 for( sal_Int32 i = 0; ! bTemplateFound && i < nLength; ++i )
108 if( ! bHasPreferredTemplate ||
109 ! rPreferredTemplateName.equals( aServiceNames[ i ] ))
111 Reference< XChartTypeTemplate > xTempl(
112 xChartTypeManager->createInstance( aServiceNames[ i ] ), uno::UNO_QUERY_THROW );
114 if( xTempl->matchesTemplate( xDiagram, sal_True ))
116 aResult.first = xTempl;
117 aResult.second = aServiceNames[ i ];
118 bTemplateFound = true;
122 catch( const uno::Exception & ex )
124 ASSERT_EXCEPTION( ex );
128 return aResult;
131 void DiagramHelper::setVertical(
132 const Reference< XDiagram > & xDiagram,
133 bool bVertical /* = true */ )
137 Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
138 if( xCnt.is())
140 Sequence< Reference< XCoordinateSystem > > aCooSys(
141 xCnt->getCoordinateSystems());
142 uno::Any aValue;
143 aValue <<= bVertical;
144 for( sal_Int32 i=0; i<aCooSys.getLength(); ++i )
146 uno::Reference< XCoordinateSystem > xCooSys( aCooSys[i] );
147 Reference< beans::XPropertySet > xProp( xCooSys, uno::UNO_QUERY );
148 bool bChanged = false;
149 if( xProp.is() )
151 bool bOldSwap = sal_False;
152 if( !(xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bOldSwap)
153 || bVertical != bOldSwap )
154 bChanged = true;
156 if( bChanged )
157 xProp->setPropertyValue( "SwapXAndYAxis", aValue );
159 if( xCooSys.is() )
161 const sal_Int32 nDimensionCount( xCooSys->getDimension() );
162 sal_Int32 nDimIndex = 0;
163 for(nDimIndex=0; nDimIndex<nDimensionCount; ++nDimIndex)
165 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
166 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
168 Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( nDimIndex,nI ));
169 if( xAxis.is() )
171 //adapt title rotation only when axis swapping has changed
172 if( bChanged )
174 Reference< XTitled > xTitled( xAxis, uno::UNO_QUERY );
175 if( xTitled.is())
177 Reference< beans::XPropertySet > xTitleProps( xTitled->getTitleObject(), uno::UNO_QUERY );
178 if( !xTitleProps.is() )
179 continue;
180 double fAngleDegree = 0.0;
181 xTitleProps->getPropertyValue( "TextRotation" ) >>= fAngleDegree;
182 if( !::rtl::math::approxEqual( fAngleDegree, 0.0 )
183 && !::rtl::math::approxEqual( fAngleDegree, 90.0 ) )
184 continue;
186 double fNewAngleDegree = 0.0;
187 if( !bVertical && nDimIndex == 1 )
188 fNewAngleDegree = 90.0;
189 else if( bVertical && nDimIndex == 0 )
190 fNewAngleDegree = 90.0;
192 xTitleProps->setPropertyValue( "TextRotation", uno::makeAny( fNewAngleDegree ));
202 catch( const uno::Exception & ex )
204 ASSERT_EXCEPTION( ex );
208 bool DiagramHelper::getVertical( const uno::Reference< chart2::XDiagram > & xDiagram,
209 bool& rbFound, bool& rbAmbiguous )
211 bool bValue = false;
212 rbFound = false;
213 rbAmbiguous = false;
215 Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
216 if( xCnt.is())
218 Sequence< Reference< XCoordinateSystem > > aCooSys(
219 xCnt->getCoordinateSystems());
220 for( sal_Int32 i=0; i<aCooSys.getLength(); ++i )
222 Reference< beans::XPropertySet > xProp( aCooSys[i], uno::UNO_QUERY );
223 if( xProp.is())
225 bool bCurrent = false;
226 if( xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bCurrent )
228 if( !rbFound )
230 bValue = bCurrent;
231 rbFound = true;
233 else if( bCurrent != bValue )
235 // ambiguous -> choose always first found
236 rbAmbiguous = true;
242 return bValue;
245 void DiagramHelper::setStackMode(
246 const Reference< XDiagram > & xDiagram,
247 StackMode eStackMode,
248 bool bOnlyAtFirstChartType /* = true */
253 if( eStackMode == StackMode_AMBIGUOUS )
254 return;
256 bool bValueFound = false;
257 bool bIsAmbiguous = false;
258 StackMode eOldStackMode = DiagramHelper::getStackMode( xDiagram, bValueFound, bIsAmbiguous );
260 if( eStackMode == eOldStackMode && !bIsAmbiguous )
261 return;
263 StackingDirection eNewDirection = StackingDirection_NO_STACKING;
264 if( eStackMode == StackMode_Y_STACKED || eStackMode == StackMode_Y_STACKED_PERCENT )
265 eNewDirection = StackingDirection_Y_STACKING;
266 else if( eStackMode == StackMode_Z_STACKED )
267 eNewDirection = StackingDirection_Z_STACKING;
269 uno::Any aNewDirection( uno::makeAny(eNewDirection) );
271 sal_Bool bPercent = sal_False;
272 if( eStackMode == StackMode_Y_STACKED_PERCENT )
273 bPercent = sal_True;
275 //iterate through all coordinate systems
276 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
277 if( !xCooSysContainer.is() )
278 return;
279 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
280 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
282 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
283 //set correct percent stacking
284 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(1);
285 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
287 Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1,nI ));
288 if( xAxis.is())
290 chart2::ScaleData aScaleData = xAxis->getScaleData();
291 if( (aScaleData.AxisType==AxisType::PERCENT) != bPercent )
293 if( bPercent )
294 aScaleData.AxisType = AxisType::PERCENT;
295 else
296 aScaleData.AxisType = AxisType::REALNUMBER;
297 xAxis->setScaleData( aScaleData );
301 //iterate through all chart types in the current coordinate system
302 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
303 if( !xChartTypeContainer.is() )
304 continue;
305 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
306 sal_Int32 nMax = aChartTypeList.getLength();
307 if( bOnlyAtFirstChartType
308 && nMax >= 1 )
309 nMax = 1;
310 for( sal_Int32 nT = 0; nT < nMax; ++nT )
312 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
314 //iterate through all series in this chart type
315 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
316 OSL_ASSERT( xDataSeriesContainer.is());
317 if( !xDataSeriesContainer.is() )
318 continue;
320 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
321 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
323 Reference< beans::XPropertySet > xProp( aSeriesList[nS], uno::UNO_QUERY );
324 if(xProp.is())
325 xProp->setPropertyValue( "StackingDirection", aNewDirection );
330 catch( const uno::Exception & ex )
332 ASSERT_EXCEPTION( ex );
336 StackMode DiagramHelper::getStackMode( const Reference< XDiagram > & xDiagram, bool& rbFound, bool& rbAmbiguous )
338 rbFound=false;
339 rbAmbiguous=false;
341 StackMode eGlobalStackMode = StackMode_NONE;
343 //iterate through all coordinate systems
344 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
345 if( !xCooSysContainer.is() )
346 return eGlobalStackMode;
347 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
348 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
350 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
352 //iterate through all chart types in the current coordinate system
353 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
354 if( !xChartTypeContainer.is() )
355 continue;
356 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
357 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
359 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
361 StackMode eLocalStackMode = DiagramHelper::getStackModeFromChartType(
362 xChartType, rbFound, rbAmbiguous, xCooSys );
364 if( rbFound && eLocalStackMode != eGlobalStackMode && nT>0 )
366 rbAmbiguous = true;
367 return eGlobalStackMode;
370 eGlobalStackMode = eLocalStackMode;
374 return eGlobalStackMode;
377 StackMode DiagramHelper::getStackModeFromChartType(
378 const Reference< XChartType > & xChartType,
379 bool& rbFound, bool& rbAmbiguous,
380 const Reference< XCoordinateSystem > & xCorrespondingCoordinateSystem )
382 StackMode eStackMode = StackMode_NONE;
383 rbFound = false;
384 rbAmbiguous = false;
388 Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW );
389 Sequence< Reference< chart2::XDataSeries > > aSeries( xDSCnt->getDataSeries());
391 chart2::StackingDirection eCommonDirection = chart2::StackingDirection_NO_STACKING;
392 bool bDirectionInitialized = false;
394 // first series is irrelvant for stacking, start with second, unless
395 // there is only one series
396 const sal_Int32 nSeriesCount = aSeries.getLength();
397 sal_Int32 i = (nSeriesCount == 1) ? 0: 1;
398 for( ; i<nSeriesCount; ++i )
400 rbFound = true;
401 Reference< beans::XPropertySet > xProp( aSeries[i], uno::UNO_QUERY_THROW );
402 chart2::StackingDirection eCurrentDirection = eCommonDirection;
403 // property is not MAYBEVOID
404 bool bSuccess = ( xProp->getPropertyValue( "StackingDirection" ) >>= eCurrentDirection );
405 OSL_ASSERT( bSuccess );
406 (void)(bSuccess); // avoid warning in non-debug builds
407 if( ! bDirectionInitialized )
409 eCommonDirection = eCurrentDirection;
410 bDirectionInitialized = true;
412 else
414 if( eCommonDirection != eCurrentDirection )
416 rbAmbiguous = true;
417 break;
422 if( rbFound )
424 if( eCommonDirection == chart2::StackingDirection_Z_STACKING )
425 eStackMode = StackMode_Z_STACKED;
426 else if( eCommonDirection == chart2::StackingDirection_Y_STACKING )
428 eStackMode = StackMode_Y_STACKED;
430 // percent stacking
431 if( xCorrespondingCoordinateSystem.is() )
433 if( 1 < xCorrespondingCoordinateSystem->getDimension() )
435 sal_Int32 nAxisIndex = 0;
436 if( nSeriesCount )
437 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(aSeries[0]);
439 Reference< chart2::XAxis > xAxis(
440 xCorrespondingCoordinateSystem->getAxisByDimension( 1,nAxisIndex ));
441 if( xAxis.is())
443 chart2::ScaleData aScaleData = xAxis->getScaleData();
444 if( aScaleData.AxisType==chart2::AxisType::PERCENT )
445 eStackMode = StackMode_Y_STACKED_PERCENT;
452 catch( const uno::Exception & ex )
454 ASSERT_EXCEPTION( ex );
457 return eStackMode;
460 sal_Int32 DiagramHelper::getDimension( const Reference< XDiagram > & xDiagram )
462 // -1: not yet set
463 sal_Int32 nResult = -1;
467 Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY );
468 if( xCooSysCnt.is() )
470 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
471 xCooSysCnt->getCoordinateSystems());
473 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
475 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
476 if(xCooSys.is())
478 nResult = xCooSys->getDimension();
479 break;
484 catch( const uno::Exception & ex )
486 ASSERT_EXCEPTION( ex );
489 return nResult;
492 void DiagramHelper::setDimension(
493 const Reference< XDiagram > & xDiagram,
494 sal_Int32 nNewDimensionCount )
496 if( ! xDiagram.is())
497 return;
499 if( DiagramHelper::getDimension( xDiagram ) == nNewDimensionCount )
500 return;
504 bool rbFound = false;
505 bool rbAmbiguous = true;
506 StackMode eStackMode = DiagramHelper::getStackMode( xDiagram, rbFound, rbAmbiguous );
507 bool bIsSupportingOnlyDeepStackingFor3D=false;
509 //change all coordinate systems:
510 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY_THROW );
511 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
512 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
514 Reference< XCoordinateSystem > xOldCooSys( aCooSysList[nCS], uno::UNO_QUERY );
515 Reference< XCoordinateSystem > xNewCooSys;
517 Reference< XChartTypeContainer > xChartTypeContainer( xOldCooSys, uno::UNO_QUERY );
518 if( !xChartTypeContainer.is() )
519 continue;
521 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
522 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
524 Reference< XChartType > xChartType( aChartTypeList[nT], uno::UNO_QUERY );
525 bIsSupportingOnlyDeepStackingFor3D = ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( xChartType );
526 if(!xNewCooSys.is())
528 xNewCooSys = xChartType->createCoordinateSystem( nNewDimensionCount );
529 break;
531 //@todo make sure that all following charttypes are also capable of the new dimension
532 //otherwise separate them in a different group
533 //BM: might be done in replaceCoordinateSystem()
536 // replace the old coordinate system at all places where it was used
537 DiagramHelper::replaceCoordinateSystem( xDiagram, xOldCooSys, xNewCooSys );
540 //correct stack mode if necessary
541 if( nNewDimensionCount==3 && eStackMode != StackMode_Z_STACKED && bIsSupportingOnlyDeepStackingFor3D )
542 DiagramHelper::setStackMode( xDiagram, StackMode_Z_STACKED );
543 else if( nNewDimensionCount==2 && eStackMode == StackMode_Z_STACKED )
544 DiagramHelper::setStackMode( xDiagram, StackMode_NONE );
546 catch( const uno::Exception & ex )
548 ASSERT_EXCEPTION( ex );
552 void DiagramHelper::replaceCoordinateSystem(
553 const Reference< XDiagram > & xDiagram,
554 const Reference< XCoordinateSystem > & xCooSysToReplace,
555 const Reference< XCoordinateSystem > & xReplacement )
557 OSL_ASSERT( xDiagram.is());
558 if( ! xDiagram.is())
559 return;
561 // update the coordinate-system container
562 Reference< XCoordinateSystemContainer > xCont( xDiagram, uno::UNO_QUERY );
563 if( xCont.is())
567 Reference< chart2::data::XLabeledDataSequence > xCategories = DiagramHelper::getCategoriesFromDiagram( xDiagram );
569 // move chart types of xCooSysToReplace to xReplacement
570 Reference< XChartTypeContainer > xCTCntCooSys( xCooSysToReplace, uno::UNO_QUERY_THROW );
571 Reference< XChartTypeContainer > xCTCntReplacement( xReplacement, uno::UNO_QUERY_THROW );
572 xCTCntReplacement->setChartTypes( xCTCntCooSys->getChartTypes());
574 xCont->removeCoordinateSystem( xCooSysToReplace );
575 xCont->addCoordinateSystem( xReplacement );
577 if( xCategories.is() )
578 DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram );
580 catch( const uno::Exception & ex )
582 ASSERT_EXCEPTION( ex );
587 bool DiagramHelper::isSeriesAttachedToMainAxis(
588 const uno::Reference< chart2::XDataSeries >& xDataSeries )
590 sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
591 return (nAxisIndex==0);
594 bool DiagramHelper::attachSeriesToAxis( bool bAttachToMainAxis
595 , const uno::Reference< chart2::XDataSeries >& xDataSeries
596 , const uno::Reference< chart2::XDiagram >& xDiagram
597 , const uno::Reference< uno::XComponentContext > & xContext
598 , bool bAdaptAxes )
600 bool bChanged = false;
602 //set property at axis
603 Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
604 if( !xProp.is() )
605 return bChanged;
607 sal_Int32 nNewAxisIndex = bAttachToMainAxis ? 0 : 1;
608 sal_Int32 nOldAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
609 uno::Reference< chart2::XAxis > xOldAxis( DiagramHelper::getAttachedAxis( xDataSeries, xDiagram ) );
611 if( nOldAxisIndex != nNewAxisIndex )
615 xProp->setPropertyValue( "AttachedAxisIndex", uno::makeAny( nNewAxisIndex ) );
616 bChanged = true;
618 catch( const uno::Exception & ex )
620 ASSERT_EXCEPTION( ex );
624 if( bChanged && xDiagram.is() )
626 uno::Reference< XAxis > xAxis( AxisHelper::getAxis( 1, bAttachToMainAxis, xDiagram ) );
627 if(!xAxis.is()) //create an axis if necessary
628 xAxis = AxisHelper::createAxis( 1, bAttachToMainAxis, xDiagram, xContext );
629 if( bAdaptAxes )
631 AxisHelper::makeAxisVisible( xAxis );
632 AxisHelper::hideAxisIfNoDataIsAttached( xOldAxis, xDiagram );
636 return bChanged;
639 uno::Reference< XAxis > DiagramHelper::getAttachedAxis(
640 const uno::Reference< XDataSeries >& xSeries,
641 const uno::Reference< XDiagram >& xDiagram )
643 return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), xDiagram );
646 uno::Reference< XChartType > DiagramHelper::getChartTypeOfSeries(
647 const uno::Reference< chart2::XDiagram >& xDiagram
648 , const uno::Reference< XDataSeries >& xGivenDataSeries )
650 if( !xGivenDataSeries.is() )
651 return 0;
652 if(!xDiagram.is())
653 return 0;
655 //iterate through the model to find the given xSeries
656 //the found parent indicates the charttype
658 //iterate through all coordinate systems
659 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
660 if( !xCooSysContainer.is())
661 return 0;
663 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
664 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
666 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
668 //iterate through all chart types in the current coordinate system
669 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
670 OSL_ASSERT( xChartTypeContainer.is());
671 if( !xChartTypeContainer.is() )
672 continue;
673 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
674 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
676 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
678 //iterate through all series in this chart type
679 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
680 OSL_ASSERT( xDataSeriesContainer.is());
681 if( !xDataSeriesContainer.is() )
682 continue;
684 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
685 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
687 if( xGivenDataSeries==aSeriesList[nS] )
688 return xChartType;
692 return 0;
695 ::std::vector< Reference< XDataSeries > >
696 DiagramHelper::getDataSeriesFromDiagram(
697 const Reference< XDiagram > & xDiagram )
699 ::std::vector< Reference< XDataSeries > > aResult;
703 Reference< XCoordinateSystemContainer > xCooSysCnt(
704 xDiagram, uno::UNO_QUERY_THROW );
705 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
706 xCooSysCnt->getCoordinateSystems());
707 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
709 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
710 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
711 for( sal_Int32 j=0; j<aChartTypeSeq.getLength(); ++j )
713 Reference< XDataSeriesContainer > xDSCnt( aChartTypeSeq[j], uno::UNO_QUERY_THROW );
714 Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() );
715 ::std::copy( aSeriesSeq.getConstArray(), aSeriesSeq.getConstArray() + aSeriesSeq.getLength(),
716 ::std::back_inserter( aResult ));
720 catch( const uno::Exception & ex )
722 ASSERT_EXCEPTION( ex );
725 return aResult;
728 Sequence< Sequence< Reference< XDataSeries > > >
729 DiagramHelper::getDataSeriesGroups( const Reference< XDiagram > & xDiagram )
731 vector< Sequence< Reference< XDataSeries > > > aResult;
733 //iterate through all coordinate systems
734 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
735 if( xCooSysContainer.is() )
737 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
738 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
740 //iterate through all chart types in the current coordinate system
741 Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
742 if( !xChartTypeContainer.is() )
743 continue;
744 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
745 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
747 Reference< XDataSeriesContainer > xDataSeriesContainer( aChartTypeList[nT], uno::UNO_QUERY );
748 if( !xDataSeriesContainer.is() )
749 continue;
750 aResult.push_back( xDataSeriesContainer->getDataSeries() );
754 return ContainerHelper::ContainerToSequence( aResult );
757 Reference< XChartType >
758 DiagramHelper::getChartTypeByIndex( const Reference< XDiagram >& xDiagram, sal_Int32 nIndex )
760 Reference< XChartType > xChartType;
762 //iterate through all coordinate systems
763 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
764 if( ! xCooSysContainer.is())
765 return xChartType;
767 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
768 sal_Int32 nTypesSoFar = 0;
769 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
771 Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
772 if( !xChartTypeContainer.is() )
773 continue;
774 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
775 if( nIndex >= 0 && nIndex < (nTypesSoFar + aChartTypeList.getLength()) )
777 xChartType.set( aChartTypeList[nIndex - nTypesSoFar] );
778 break;
780 nTypesSoFar += aChartTypeList.getLength();
783 return xChartType;
786 namespace
789 std::vector< Reference< XAxis > > lcl_getAxisHoldingCategoriesFromDiagram(
790 const Reference< XDiagram > & xDiagram )
792 std::vector< Reference< XAxis > > aRet;
794 Reference< XAxis > xResult;
795 // return first x-axis as fall-back
796 Reference< XAxis > xFallBack;
799 Reference< XCoordinateSystemContainer > xCooSysCnt(
800 xDiagram, uno::UNO_QUERY_THROW );
801 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
802 xCooSysCnt->getCoordinateSystems());
803 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
805 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
806 OSL_ASSERT( xCooSys.is());
807 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
809 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
810 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
812 Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
813 OSL_ASSERT( xAxis.is());
814 if( xAxis.is())
816 ScaleData aScaleData = xAxis->getScaleData();
817 if( aScaleData.Categories.is() || (aScaleData.AxisType == AxisType::CATEGORY) )
819 aRet.push_back(xAxis);
821 if( (nN == 0) && !xFallBack.is())
822 xFallBack.set( xAxis );
828 catch( const uno::Exception & ex )
830 ASSERT_EXCEPTION( ex );
833 if( aRet.empty() )
834 aRet.push_back(xFallBack);
836 return aRet;
839 } // anonymous namespace
841 bool DiagramHelper::isCategoryDiagram(
842 const Reference< XDiagram >& xDiagram )
846 Reference< XCoordinateSystemContainer > xCooSysCnt(
847 xDiagram, uno::UNO_QUERY_THROW );
848 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
849 xCooSysCnt->getCoordinateSystems());
850 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
852 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
853 OSL_ASSERT( xCooSys.is());
854 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
856 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
857 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
859 Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
860 OSL_ASSERT( xAxis.is());
861 if( xAxis.is())
863 ScaleData aScaleData = xAxis->getScaleData();
864 if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
865 return true;
871 catch( const uno::Exception & ex )
873 ASSERT_EXCEPTION( ex );
876 return false;
879 void DiagramHelper::setCategoriesToDiagram(
880 const Reference< chart2::data::XLabeledDataSequence >& xCategories,
881 const Reference< XDiagram >& xDiagram,
882 bool bSetAxisType /* = false */,
883 bool bCategoryAxis /* = true */ )
885 std::vector< Reference< chart2::XAxis > > aCatAxes(
886 lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
888 std::vector< Reference< chart2::XAxis > >::iterator aIt( aCatAxes.begin() );
889 std::vector< Reference< chart2::XAxis > >::const_iterator aEnd( aCatAxes.end() );
891 for( aIt = aCatAxes.begin(); aIt != aEnd; ++aIt )
893 Reference< chart2::XAxis > xCatAxis(*aIt);
894 if( xCatAxis.is())
896 ScaleData aScaleData( xCatAxis->getScaleData());
897 aScaleData.Categories = xCategories;
898 if( bSetAxisType )
900 if( bCategoryAxis )
901 aScaleData.AxisType = AxisType::CATEGORY;
902 else if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
903 aScaleData.AxisType = AxisType::REALNUMBER;
905 xCatAxis->setScaleData( aScaleData );
910 Reference< data::XLabeledDataSequence >
911 DiagramHelper::getCategoriesFromDiagram(
912 const Reference< XDiagram > & xDiagram )
914 Reference< data::XLabeledDataSequence > xResult;
918 std::vector< Reference< chart2::XAxis > > aCatAxes(
919 lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
920 std::vector< Reference< chart2::XAxis > >::iterator aIt( aCatAxes.begin() );
921 std::vector< Reference< chart2::XAxis > >::const_iterator aEnd( aCatAxes.end() );
922 //search for first categories
923 if( aIt != aEnd )
925 Reference< chart2::XAxis > xCatAxis(*aIt);
926 if( xCatAxis.is())
928 ScaleData aScaleData( xCatAxis->getScaleData());
929 if( aScaleData.Categories.is() )
931 xResult.set( aScaleData.Categories );
932 uno::Reference<beans::XPropertySet> xProp(aScaleData.Categories->getValues(), uno::UNO_QUERY );
933 if( xProp.is() )
937 xProp->setPropertyValue( "Role", uno::makeAny( OUString("categories") ) );
939 catch( const uno::Exception & ex )
941 ASSERT_EXCEPTION( ex );
948 catch( const uno::Exception & ex )
950 ASSERT_EXCEPTION( ex );
953 return xResult;
956 void lcl_generateAutomaticCategoriesFromChartType(
957 Sequence< OUString >& rRet,
958 const Reference< XChartType >& xChartType )
960 if(!xChartType.is())
961 return;
962 OUString aMainSeq( xChartType->getRoleOfSequenceForSeriesLabel() );
963 Reference< XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY );
964 if( xSeriesCnt.is() )
966 Sequence< Reference< XDataSeries > > aSeriesSeq( xSeriesCnt->getDataSeries() );
967 for( sal_Int32 nS = 0; nS < aSeriesSeq.getLength(); nS++ )
969 Reference< data::XDataSource > xDataSource( aSeriesSeq[nS], uno::UNO_QUERY );
970 if( !xDataSource.is() )
971 continue;
972 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
973 ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aMainSeq ));
974 if( !xLabeledSeq.is() )
975 continue;
976 Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() );
977 if( !xValueSeq.is() )
978 continue;
979 rRet = xValueSeq->generateLabel( chart2::data::LabelOrigin_LONG_SIDE );
980 if( rRet.getLength() )
981 return;
986 Sequence< OUString > DiagramHelper::generateAutomaticCategoriesFromCooSys( const Reference< XCoordinateSystem > & xCooSys )
988 Sequence< OUString > aRet;
990 Reference< XChartTypeContainer > xTypeCntr( xCooSys, uno::UNO_QUERY );
991 if( xTypeCntr.is() )
993 Sequence< Reference< XChartType > > aChartTypes( xTypeCntr->getChartTypes() );
994 for( sal_Int32 nN=0; nN<aChartTypes.getLength(); nN++ )
996 lcl_generateAutomaticCategoriesFromChartType( aRet, aChartTypes[nN] );
997 if( aRet.getLength() )
998 return aRet;
1001 return aRet;
1004 Sequence< OUString > DiagramHelper::getExplicitSimpleCategories(
1005 const Reference< XChartDocument >& xChartDoc )
1007 Sequence< OUString > aRet;
1008 uno::Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
1009 if(xChartModel.is())
1011 uno::Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
1012 ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, xChartModel );
1013 aRet = aExplicitCategoriesProvider.getSimpleCategories();
1015 return aRet;
1018 namespace
1020 void lcl_switchToDateCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
1022 if( !xAxis.is() )
1023 return;
1024 if( !xChartDoc.is() )
1025 return;
1027 ScaleData aScale( xAxis->getScaleData() );
1028 if( xChartDoc->hasInternalDataProvider() )
1030 //remove all content the is not of type double and remove multiple level
1031 Reference< XAnyDescriptionAccess > xDataAccess( xChartDoc->getDataProvider(), uno::UNO_QUERY );
1032 if( xDataAccess.is() )
1034 Sequence< Sequence< Any > > aAnyCategories( xDataAccess->getAnyRowDescriptions() );
1035 double fTest = 0.0;
1036 double fNan = 0.0;
1037 ::rtl::math::setNan( & fNan );
1038 sal_Int32 nN = aAnyCategories.getLength();
1039 for( ; nN--; )
1041 Sequence< Any >& rCat = aAnyCategories[nN];
1042 if( rCat.getLength() > 1 )
1043 rCat.realloc(1);
1044 if( rCat.getLength() == 1 )
1046 Any& rAny = rCat[0];
1047 if( !(rAny>>=fTest) )
1049 rAny = uno::makeAny(fNan);
1053 xDataAccess->setAnyRowDescriptions( aAnyCategories );
1055 //check the numberformat at the axis
1056 Reference< beans::XPropertySet > xAxisProps( xAxis, uno::UNO_QUERY );
1057 Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartDoc, uno::UNO_QUERY );
1058 if( xAxisProps.is() && xNumberFormatsSupplier.is() )
1060 sal_Int32 nNumberFormat = -1;
1061 xAxisProps->getPropertyValue( "NumberFormat" ) >>= nNumberFormat;
1063 Reference< util::XNumberFormats > xNumberFormats = Reference< util::XNumberFormats >( xNumberFormatsSupplier->getNumberFormats() );
1064 if( xNumberFormats.is() )
1066 Reference< beans::XPropertySet > xKeyProps;
1069 xKeyProps = xNumberFormats->getByKey( nNumberFormat );
1071 catch( const uno::Exception & ex )
1073 ASSERT_EXCEPTION( ex );
1075 sal_Int32 nType = util::NumberFormat::UNDEFINED;
1076 if( xKeyProps.is() )
1077 xKeyProps->getPropertyValue( "Type" ) >>= nType;
1078 if( !( nType & util::NumberFormat::DATE ) )
1080 //set a date format to the axis
1081 sal_Bool bCreate = sal_True;
1082 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
1083 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE, rLocaleDataWrapper.getLanguageTag().getLocale(), bCreate );
1084 if( aKeySeq.getLength() )
1086 xAxisProps->setPropertyValue( "NumberFormat", uno::makeAny(aKeySeq[0]) );
1092 if( aScale.AxisType != chart2::AxisType::DATE )
1093 AxisHelper::removeExplicitScaling( aScale );
1094 aScale.AxisType = chart2::AxisType::DATE;
1095 xAxis->setScaleData( aScale );
1098 void lcl_switchToTextCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
1100 if( !xAxis.is() )
1101 return;
1102 if( !xChartDoc.is() )
1103 return;
1104 ScaleData aScale( xAxis->getScaleData() );
1105 if( aScale.AxisType != chart2::AxisType::CATEGORY )
1106 AxisHelper::removeExplicitScaling( aScale );
1107 //todo migrate dates to text?
1108 aScale.AxisType = chart2::AxisType::CATEGORY;
1109 aScale.AutoDateAxis = false;
1110 xAxis->setScaleData( aScale );
1115 void DiagramHelper::switchToDateCategories( const Reference< XChartDocument >& xChartDoc )
1117 Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
1118 if(xChartModel.is())
1120 ControllerLockGuard aCtrlLockGuard( xChartModel );
1122 Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
1123 if( xCooSys.is() )
1125 Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
1126 lcl_switchToDateCategories( xChartDoc, xAxis );
1131 void DiagramHelper::switchToTextCategories( const Reference< XChartDocument >& xChartDoc )
1133 Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
1134 if(xChartModel.is())
1136 ControllerLockGuard aCtrlLockGuard( xChartModel );
1138 Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
1139 if( xCooSys.is() )
1141 Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
1142 lcl_switchToTextCategories( xChartDoc, xAxis );
1147 bool DiagramHelper::isSupportingDateAxis( const Reference< chart2::XDiagram >& xDiagram )
1149 return ::chart::ChartTypeHelper::isSupportingDateAxis(
1150 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ), DiagramHelper::getDimension( xDiagram ), 0 );
1153 bool DiagramHelper::isDateNumberFormat( sal_Int32 nNumberFormat, const Reference< util::XNumberFormats >& xNumberFormats )
1155 bool bIsDate = false;
1156 if( !xNumberFormats.is() )
1157 return bIsDate;
1159 Reference< beans::XPropertySet > xKeyProps = xNumberFormats->getByKey( nNumberFormat );
1160 if( xKeyProps.is() )
1162 sal_Int32 nType = util::NumberFormat::UNDEFINED;
1163 xKeyProps->getPropertyValue( "Type" ) >>= nType;
1164 bIsDate = nType & util::NumberFormat::DATE;
1166 return bIsDate;
1169 sal_Int32 DiagramHelper::getDateNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1171 sal_Int32 nRet=-1;
1172 Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1173 if( xNumberFormats.is() )
1175 sal_Bool bCreate = sal_True;
1176 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
1177 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE,
1178 rLocaleDataWrapper.getLanguageTag().getLocale(), bCreate );
1179 if( aKeySeq.getLength() )
1181 nRet = aKeySeq[0];
1185 //try to get a date format with full year display
1186 NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1187 SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1188 if( pNumFormatter )
1190 const SvNumberformat* pFormat = pNumFormatter->GetEntry( nRet );
1191 if( pFormat )
1192 nRet = pNumFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, pFormat->GetLanguage() );
1194 return nRet;
1197 sal_Int32 DiagramHelper::getPercentNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1199 sal_Int32 nRet=-1;
1200 Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1201 if( xNumberFormats.is() )
1203 sal_Bool bCreate = sal_True;
1204 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
1205 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::PERCENT,
1206 rLocaleDataWrapper.getLanguageTag().getLocale(), bCreate );
1207 if( aKeySeq.getLength() )
1209 nRet = aKeySeq[0];
1212 return nRet;
1215 Sequence< Reference< XChartType > >
1216 DiagramHelper::getChartTypesFromDiagram(
1217 const Reference< XDiagram > & xDiagram )
1219 ::std::vector< Reference< XChartType > > aResult;
1221 if(xDiagram.is())
1225 Reference< XCoordinateSystemContainer > xCooSysCnt(
1226 xDiagram, uno::UNO_QUERY_THROW );
1227 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
1228 xCooSysCnt->getCoordinateSystems());
1229 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
1231 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
1232 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
1233 ::std::copy( aChartTypeSeq.getConstArray(),
1234 aChartTypeSeq.getConstArray() + aChartTypeSeq.getLength(),
1235 ::std::back_inserter( aResult ));
1238 catch( const uno::Exception & ex )
1240 ASSERT_EXCEPTION( ex );
1244 return ContainerHelper::ContainerToSequence( aResult );
1247 bool DiagramHelper::areChartTypesCompatible( const Reference< ::chart2::XChartType >& xFirstType,
1248 const Reference< ::chart2::XChartType >& xSecondType )
1250 if( !xFirstType.is() || !xSecondType.is() )
1251 return false;
1253 ::std::vector< OUString > aFirstRoles( ContainerHelper::SequenceToVector( xFirstType->getSupportedMandatoryRoles() ) );
1254 ::std::vector< OUString > aSecondRoles( ContainerHelper::SequenceToVector( xSecondType->getSupportedMandatoryRoles() ) );
1255 ::std::sort( aFirstRoles.begin(), aFirstRoles.end() );
1256 ::std::sort( aSecondRoles.begin(), aSecondRoles.end() );
1257 return ( aFirstRoles == aSecondRoles );
1260 namespace
1263 * This method implements the logic of checking if a series can be moved
1264 * forward/backward. Depending on the "bDoMove" parameter the series will
1265 * be moved (bDoMove = true) or the function just will test if the
1266 * series can be moved without doing the move (bDoMove = false).
1268 * @param xDiagram
1269 * Reference to the diagram that contains the series.
1271 * @param xGivenDataSeries
1272 * Reference to the series that should moved or tested for moving.
1274 * @param bForward
1275 * Direction in which the series should be moved or tested for moving.
1277 * @param bDoMove
1278 * Should this function really move the series (true) or just test if it is
1279 * possible (false).
1282 * @returns
1283 * in case of bDoMove == true
1284 * - True : if the move was done
1285 * - False : the move failed
1286 * in case of bDoMove == false
1287 * - True : the series can be moved
1288 * - False : the series can not be moved
1292 bool lcl_moveSeriesOrCheckIfMoveIsAllowed(
1293 const Reference< XDiagram >& xDiagram,
1294 const Reference< XDataSeries >& xGivenDataSeries,
1295 bool bForward,
1296 bool bDoMove )
1298 bool bMovedOrMoveAllowed = false;
1302 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
1304 //find position of series.
1305 bool bFound = false;
1307 if( xGivenDataSeries.is() && xCooSysContainer.is() )
1309 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
1311 for( sal_Int32 nCS = 0; !bFound && nCS < aCooSysList.getLength(); ++nCS )
1313 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
1315 //iterate through all chart types in the current coordinate system
1316 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
1317 OSL_ASSERT( xChartTypeContainer.is());
1318 if( !xChartTypeContainer.is() )
1319 continue;
1320 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
1321 uno::Reference< XChartType > xFormerChartType;
1323 for( sal_Int32 nT = 0; !bFound && nT < aChartTypeList.getLength(); ++nT )
1325 uno::Reference< XChartType > xCurrentChartType( aChartTypeList[nT] );
1327 //iterate through all series in this chart type
1328 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xCurrentChartType, uno::UNO_QUERY );
1329 OSL_ASSERT( xDataSeriesContainer.is());
1330 if( !xDataSeriesContainer.is() )
1331 continue;
1333 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
1335 for( sal_Int32 nS = 0; !bFound && nS < aSeriesList.getLength(); ++nS )
1338 // We found the series we are interrested in !
1339 if( xGivenDataSeries==aSeriesList[nS] )
1341 sal_Int32 nOldSeriesIndex = nS;
1342 bFound = true;
1346 sal_Int32 nNewSeriesIndex = nS;
1348 if( bForward )
1349 nNewSeriesIndex--;
1350 else
1351 nNewSeriesIndex++;
1354 if( nNewSeriesIndex >= 0 && nNewSeriesIndex < aSeriesList.getLength() )
1356 //move series in the same charttype
1357 bMovedOrMoveAllowed = true;
1358 if( bDoMove )
1360 aSeriesList[ nOldSeriesIndex ] = aSeriesList[ nNewSeriesIndex ];
1361 aSeriesList[ nNewSeriesIndex ] = xGivenDataSeries;
1362 xDataSeriesContainer->setDataSeries( aSeriesList );
1365 else if( nNewSeriesIndex<0 )
1367 //exchange series with former charttype
1368 if( xFormerChartType.is() && DiagramHelper::areChartTypesCompatible( xFormerChartType, xCurrentChartType ) )
1370 bMovedOrMoveAllowed = true;
1371 if( bDoMove )
1373 uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xFormerChartType, uno::UNO_QUERY );
1374 if( xOtherDataSeriesContainer.is() )
1376 uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
1377 sal_Int32 nOtherSeriesIndex = aOtherSeriesList.getLength()-1;
1378 if( nOtherSeriesIndex >= 0 && nOtherSeriesIndex < aOtherSeriesList.getLength() )
1380 uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
1381 aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
1382 xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
1384 aSeriesList[nOldSeriesIndex]=xExchangeSeries;
1385 xDataSeriesContainer->setDataSeries(aSeriesList);
1391 else if( nT+1 < aChartTypeList.getLength() )
1393 //exchange series with next charttype
1394 uno::Reference< XChartType > xOtherChartType( aChartTypeList[nT+1] );
1395 if( xOtherChartType.is() && DiagramHelper::areChartTypesCompatible( xOtherChartType, xCurrentChartType ) )
1397 bMovedOrMoveAllowed = true;
1398 if( bDoMove )
1400 uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xOtherChartType, uno::UNO_QUERY );
1401 if( xOtherDataSeriesContainer.is() )
1403 uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
1404 sal_Int32 nOtherSeriesIndex = 0;
1405 if( nOtherSeriesIndex >= 0 && nOtherSeriesIndex < aOtherSeriesList.getLength() )
1407 uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
1408 aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
1409 xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
1411 aSeriesList[nOldSeriesIndex]=xExchangeSeries;
1412 xDataSeriesContainer->setDataSeries(aSeriesList);
1419 catch( const util::CloseVetoException& )
1422 catch( const uno::RuntimeException& )
1427 xFormerChartType = xCurrentChartType;
1432 catch( const util::CloseVetoException& )
1435 catch( const uno::RuntimeException& )
1438 return bMovedOrMoveAllowed;
1440 } // anonymous namespace
1443 bool DiagramHelper::isSeriesMoveable(
1444 const Reference< XDiagram >& xDiagram,
1445 const Reference< XDataSeries >& xGivenDataSeries,
1446 bool bForward )
1448 bool bIsMoveable = false;
1449 const bool bDoMove = false;
1451 bIsMoveable = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1452 xDiagram, xGivenDataSeries, bForward, bDoMove );
1454 return bIsMoveable;
1458 bool DiagramHelper::moveSeries( const Reference< XDiagram >& xDiagram, const Reference< XDataSeries >& xGivenDataSeries, bool bForward )
1460 bool bMoved = false;
1461 const bool bDoMove = true;
1463 bMoved = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1464 xDiagram, xGivenDataSeries, bForward, bDoMove );
1466 return bMoved;
1469 bool DiagramHelper::isSupportingFloorAndWall( const Reference<
1470 chart2::XDiagram >& xDiagram )
1472 //pies and donuts currently do not support this because of wrong files from older versions
1473 //todo: allow this in future again, if fileversion are available for ole objects (metastream)
1474 //thus the wrong bottom can be removed on import
1476 Sequence< Reference< chart2::XChartType > > aTypes(
1477 ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) );
1478 for( sal_Int32 nN = 0; nN < aTypes.getLength(); nN++ )
1480 Reference< chart2::XChartType > xType( aTypes[nN] );
1481 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
1482 return false;
1483 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
1484 return false;
1485 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
1486 return false;
1488 return true;
1491 bool DiagramHelper::isPieOrDonutChart( const ::com::sun::star::uno::Reference<
1492 ::com::sun::star::chart2::XDiagram >& xDiagram )
1494 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex(
1495 xDiagram, 0 ) );
1497 if( xChartType .is() )
1499 OUString aChartType = xChartType->getChartType();
1500 if( aChartType.equals(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
1501 return true;
1503 return false;
1506 sal_Int32 DiagramHelper::getGeometry3D(
1507 const uno::Reference< chart2::XDiagram > & xDiagram,
1508 bool& rbFound, bool& rbAmbiguous )
1510 sal_Int32 nCommonGeom( DataPointGeometry3D::CUBOID );
1511 rbFound = false;
1512 rbAmbiguous = false;
1514 ::std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
1515 DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
1517 if( aSeriesVec.empty())
1518 rbAmbiguous = true;
1520 for( ::std::vector< Reference< chart2::XDataSeries > >::const_iterator aIt =
1521 aSeriesVec.begin(); aIt != aSeriesVec.end(); ++aIt )
1525 sal_Int32 nGeom = 0;
1526 Reference< beans::XPropertySet > xProp( *aIt, uno::UNO_QUERY_THROW );
1527 if( xProp->getPropertyValue( "Geometry3D") >>= nGeom )
1529 if( ! rbFound )
1531 // first series
1532 nCommonGeom = nGeom;
1533 rbFound = true;
1535 // further series: compare for uniqueness
1536 else if( nCommonGeom != nGeom )
1538 rbAmbiguous = true;
1539 break;
1543 catch( const uno::Exception & ex )
1545 ASSERT_EXCEPTION( ex );
1549 return nCommonGeom;
1552 void DiagramHelper::setGeometry3D(
1553 const Reference< chart2::XDiagram > & xDiagram,
1554 sal_Int32 nNewGeometry )
1556 ::std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
1557 DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
1559 for( ::std::vector< Reference< chart2::XDataSeries > >::const_iterator aIt =
1560 aSeriesVec.begin(); aIt != aSeriesVec.end(); ++aIt )
1562 DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(
1563 *aIt, "Geometry3D", uno::makeAny( nNewGeometry ));
1567 sal_Int32 DiagramHelper::getCorrectedMissingValueTreatment(
1568 const Reference< chart2::XDiagram > & xDiagram,
1569 const Reference< chart2::XChartType >& xChartType )
1571 sal_Int32 nResult = ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP;
1572 uno::Sequence < sal_Int32 > aAvailableMissingValueTreatments(
1573 ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) );
1575 uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
1576 if( xDiaProp.is() && (xDiaProp->getPropertyValue( "MissingValueTreatment" ) >>= nResult) )
1578 //ensure that the set value is supported by this charttype
1579 for( sal_Int32 nN = 0; nN < aAvailableMissingValueTreatments.getLength(); nN++ )
1580 if( aAvailableMissingValueTreatments[nN] == nResult )
1581 return nResult; //ok
1584 //otherwise use the first supported one
1585 if( aAvailableMissingValueTreatments.getLength() )
1587 nResult = aAvailableMissingValueTreatments[0];
1588 return nResult;
1591 return nResult;
1594 DiagramPositioningMode DiagramHelper::getDiagramPositioningMode( const uno::Reference<
1595 chart2::XDiagram > & xDiagram )
1597 DiagramPositioningMode eMode = DiagramPositioningMode_AUTO;
1598 uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY );
1599 if( xDiaProps.is() )
1601 RelativePosition aRelPos;
1602 RelativeSize aRelSize;
1603 if( (xDiaProps->getPropertyValue("RelativePosition") >>= aRelPos ) &&
1604 (xDiaProps->getPropertyValue("RelativeSize") >>= aRelSize ) )
1606 bool bPosSizeExcludeAxes=false;
1607 xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxes;
1608 if( bPosSizeExcludeAxes )
1609 eMode = DiagramPositioningMode_EXCLUDING;
1610 else
1611 eMode = DiagramPositioningMode_INCLUDING;
1614 return eMode;
1617 void lcl_ensureRange0to1( double& rValue )
1619 if(rValue<0.0)
1620 rValue=0.0;
1621 if(rValue>1.0)
1622 rValue=1.0;
1625 bool DiagramHelper::setDiagramPositioning( const uno::Reference< frame::XModel >& xChartModel,
1626 const awt::Rectangle& rPosRect /*100th mm*/ )
1628 ControllerLockGuard aCtrlLockGuard( xChartModel );
1630 bool bChanged = false;
1631 awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
1632 uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
1633 if( !xDiaProps.is() )
1634 return bChanged;
1636 RelativePosition aOldPos;
1637 RelativeSize aOldSize;
1638 xDiaProps->getPropertyValue("RelativePosition" ) >>= aOldPos;
1639 xDiaProps->getPropertyValue("RelativeSize" ) >>= aOldSize;
1641 RelativePosition aNewPos;
1642 aNewPos.Anchor = drawing::Alignment_TOP_LEFT;
1643 aNewPos.Primary = double(rPosRect.X)/double(aPageSize.Width);
1644 aNewPos.Secondary = double(rPosRect.Y)/double(aPageSize.Height);
1646 chart2::RelativeSize aNewSize;
1647 aNewSize.Primary = double(rPosRect.Width)/double(aPageSize.Width);
1648 aNewSize.Secondary = double(rPosRect.Height)/double(aPageSize.Height);
1650 lcl_ensureRange0to1( aNewPos.Primary );
1651 lcl_ensureRange0to1( aNewPos.Secondary );
1652 lcl_ensureRange0to1( aNewSize.Primary );
1653 lcl_ensureRange0to1( aNewSize.Secondary );
1654 if( (aNewPos.Primary + aNewSize.Primary) > 1.0 )
1655 aNewPos.Primary = 1.0 - aNewSize.Primary;
1656 if( (aNewPos.Secondary + aNewSize.Secondary) > 1.0 )
1657 aNewPos.Secondary = 1.0 - aNewSize.Secondary;
1659 xDiaProps->setPropertyValue( "RelativePosition", uno::makeAny(aNewPos) );
1660 xDiaProps->setPropertyValue( "RelativeSize", uno::makeAny(aNewSize) );
1662 bChanged = (aOldPos.Anchor!=aNewPos.Anchor) ||
1663 (aOldPos.Primary!=aNewPos.Primary) ||
1664 (aOldPos.Secondary!=aNewPos.Secondary) ||
1665 (aOldSize.Primary!=aNewSize.Primary) ||
1666 (aOldSize.Secondary!=aNewSize.Secondary);
1667 return bChanged;
1670 awt::Rectangle DiagramHelper::getDiagramRectangleFromModel( const uno::Reference< frame::XModel >& xChartModel )
1672 awt::Rectangle aRet(-1,-1,-1,-1);
1674 uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
1675 if( !xDiaProps.is() )
1676 return aRet;
1678 awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
1680 RelativePosition aRelPos;
1681 RelativeSize aRelSize;
1682 xDiaProps->getPropertyValue("RelativePosition" ) >>= aRelPos;
1683 xDiaProps->getPropertyValue("RelativeSize" ) >>= aRelSize;
1685 awt::Size aAbsSize(
1686 static_cast< sal_Int32 >( aRelSize.Primary * aPageSize.Width ),
1687 static_cast< sal_Int32 >( aRelSize.Secondary * aPageSize.Height ));
1689 awt::Point aAbsPos(
1690 static_cast< sal_Int32 >( aRelPos.Primary * aPageSize.Width ),
1691 static_cast< sal_Int32 >( aRelPos.Secondary * aPageSize.Height ));
1693 awt::Point aAbsPosLeftTop = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( aAbsPos, aAbsSize, aRelPos.Anchor );
1695 aRet = awt::Rectangle(aAbsPosLeftTop.X, aAbsPosLeftTop.Y, aAbsSize.Width, aAbsSize.Height );
1697 return aRet;
1700 bool DiagramHelper::switchDiagramPositioningToExcludingPositioning(
1701 const uno::Reference< frame::XModel >& xChartModel
1702 , bool bResetModifiedState, bool bConvertAlsoFromAutoPositioning )
1704 //return true if something was changed
1705 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
1706 if( nCurrentODFVersion > SvtSaveOptions::ODFVER_012 )
1708 uno::Reference< ::com::sun::star::chart::XChartDocument > xOldDoc( xChartModel, uno::UNO_QUERY ) ;
1709 if( xOldDoc.is() )
1711 uno::Reference< ::com::sun::star::chart::XDiagramPositioning > xDiagramPositioning( xOldDoc->getDiagram(), uno::UNO_QUERY );
1712 if( xDiagramPositioning.is() && ( bConvertAlsoFromAutoPositioning || !xDiagramPositioning->isAutomaticDiagramPositioning() )
1713 && !xDiagramPositioning->isExcludingDiagramPositioning() )
1715 ControllerLockGuard aCtrlLockGuard( xChartModel );
1716 uno::Reference< util::XModifiable > xModifiable( xChartModel, uno::UNO_QUERY );
1717 bool bModelWasModified = xModifiable.is() && xModifiable->isModified();
1718 xDiagramPositioning->setDiagramPositionExcludingAxes( xDiagramPositioning->calculateDiagramPositionExcludingAxes() );
1719 if(bResetModifiedState && !bModelWasModified && xModifiable.is() )
1720 xModifiable->setModified(sal_False);
1721 return true;
1725 return false;
1728 } // namespace chart
1730 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */