fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / chart2 / source / tools / DiagramHelper.cxx
blob5f1dd6e9cc679f7579f54900163d1712c76f2a48
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"
35 #include <unonames.hxx>
37 #include <com/sun/star/chart/MissingValueTreatment.hpp>
38 #include <com/sun/star/chart/XChartDocument.hpp>
39 #include <com/sun/star/chart/XDiagramPositioning.hpp>
40 #include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
41 #include <com/sun/star/chart2/XTitled.hpp>
42 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
43 #include <com/sun/star/chart2/XChartTypeTemplate.hpp>
44 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
45 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
46 #include <com/sun/star/chart2/InterpretedData.hpp>
47 #include <com/sun/star/chart2/AxisType.hpp>
48 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
49 #include <com/sun/star/chart2/RelativePosition.hpp>
50 #include <com/sun/star/chart2/RelativeSize.hpp>
52 #include <com/sun/star/util/NumberFormat.hpp>
53 #include <com/sun/star/util/XModifiable.hpp>
54 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
56 #include <unotools/saveopt.hxx>
57 #include <rtl/math.hxx>
58 #include <svl/zformat.hxx>
59 #include <vcl/svapp.hxx>
60 #include <vcl/settings.hxx>
62 using namespace ::com::sun::star;
63 using namespace ::com::sun::star::chart2;
64 using namespace ::std;
66 using ::com::sun::star::uno::Reference;
67 using ::com::sun::star::uno::Sequence;
68 using ::com::sun::star::uno::Any;
69 using ::com::sun::star::chart2::XAnyDescriptionAccess;
71 namespace chart
74 DiagramHelper::tTemplateWithServiceName
75 DiagramHelper::getTemplateForDiagram(
76 const Reference< XDiagram > & xDiagram,
77 const Reference< lang::XMultiServiceFactory > & xChartTypeManager,
78 const OUString & rPreferredTemplateName )
80 DiagramHelper::tTemplateWithServiceName aResult;
82 if( ! (xChartTypeManager.is() && xDiagram.is()))
83 return aResult;
85 Sequence< OUString > aServiceNames( xChartTypeManager->getAvailableServiceNames());
86 const sal_Int32 nLength = aServiceNames.getLength();
88 bool bHasPreferredTemplate = !rPreferredTemplateName.isEmpty();
89 bool bTemplateFound = false;
91 if( bHasPreferredTemplate )
93 Reference< XChartTypeTemplate > xTempl(
94 xChartTypeManager->createInstance( rPreferredTemplateName ), uno::UNO_QUERY );
96 if( xTempl.is() &&
97 xTempl->matchesTemplate( xDiagram, sal_True ))
99 aResult.first = xTempl;
100 aResult.second = rPreferredTemplateName;
101 bTemplateFound = true;
105 for( sal_Int32 i = 0; ! bTemplateFound && i < nLength; ++i )
109 if( ! bHasPreferredTemplate ||
110 ! rPreferredTemplateName.equals( aServiceNames[ i ] ))
112 Reference< XChartTypeTemplate > xTempl(
113 xChartTypeManager->createInstance( aServiceNames[ i ] ), uno::UNO_QUERY_THROW );
115 if (xTempl.is() && xTempl->matchesTemplate(xDiagram, true))
117 aResult.first = xTempl;
118 aResult.second = aServiceNames[ i ];
119 bTemplateFound = true;
123 catch( const uno::Exception & ex )
125 ASSERT_EXCEPTION( ex );
129 return aResult;
132 void DiagramHelper::setVertical(
133 const Reference< XDiagram > & xDiagram,
134 bool bVertical /* = true */ )
138 Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
139 if (!xCnt.is())
140 return;
142 Sequence< Reference<XCoordinateSystem> > aCooSys = xCnt->getCoordinateSystems();
143 uno::Any aValue;
144 aValue <<= bVertical;
145 for( sal_Int32 i=0; i<aCooSys.getLength(); ++i )
147 uno::Reference< XCoordinateSystem > xCooSys( aCooSys[i] );
148 Reference< beans::XPropertySet > xProp( xCooSys, uno::UNO_QUERY );
149 bool bChanged = false;
150 if (xProp.is())
152 bool bOldSwap = false;
153 if( !(xProp->getPropertyValue("SwapXAndYAxis") >>= bOldSwap)
154 || bVertical != bOldSwap )
155 bChanged = true;
157 if( bChanged )
158 xProp->setPropertyValue("SwapXAndYAxis", aValue);
161 if (!xCooSys.is())
162 continue;
164 const sal_Int32 nDimensionCount = xCooSys->getDimension();
165 sal_Int32 nDimIndex = 0;
166 for (nDimIndex=0; nDimIndex < nDimensionCount; ++nDimIndex)
168 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
169 for (sal_Int32 nI = 0; nI <= nMaximumScaleIndex; ++nI)
171 Reference<chart2::XAxis> xAxis = xCooSys->getAxisByDimension(nDimIndex,nI);
172 if (!xAxis.is())
173 continue;
175 //adapt title rotation only when axis swapping has changed
176 if (!bChanged)
177 continue;
179 Reference< XTitled > xTitled( xAxis, uno::UNO_QUERY );
180 if (!xTitled.is())
181 continue;
183 Reference< beans::XPropertySet > xTitleProps( xTitled->getTitleObject(), uno::UNO_QUERY );
184 if (!xTitleProps.is())
185 continue;
187 double fAngleDegree = 0.0;
188 xTitleProps->getPropertyValue("TextRotation") >>= fAngleDegree;
189 if (!rtl::math::approxEqual(fAngleDegree, 0.0) &&
190 !rtl::math::approxEqual(fAngleDegree, 90.0))
191 continue;
193 double fNewAngleDegree = 0.0;
194 if( !bVertical && nDimIndex == 1 )
195 fNewAngleDegree = 90.0;
196 else if( bVertical && nDimIndex == 0 )
197 fNewAngleDegree = 90.0;
199 xTitleProps->setPropertyValue("TextRotation", uno::makeAny(fNewAngleDegree));
204 catch( const uno::Exception & ex )
206 ASSERT_EXCEPTION( ex );
210 bool DiagramHelper::getVertical( const uno::Reference< chart2::XDiagram > & xDiagram,
211 bool& rbFound, bool& rbAmbiguous )
213 bool bValue = false;
214 rbFound = false;
215 rbAmbiguous = false;
217 Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
218 if (!xCnt.is())
219 return false;
221 Sequence< Reference<XCoordinateSystem> > aCooSys = xCnt->getCoordinateSystems();
223 for (sal_Int32 i = 0; i < aCooSys.getLength(); ++i)
225 Reference<beans::XPropertySet> xProp(aCooSys[i], uno::UNO_QUERY);
226 if (!xProp.is())
227 continue;
229 bool bCurrent = false;
230 if (xProp->getPropertyValue("SwapXAndYAxis") >>= bCurrent)
232 if (!rbFound)
234 bValue = bCurrent;
235 rbFound = true;
237 else if (bCurrent != bValue)
239 // ambiguous -> choose always first found
240 rbAmbiguous = true;
244 return bValue;
247 void DiagramHelper::setStackMode(
248 const Reference< XDiagram > & xDiagram,
249 StackMode eStackMode,
250 bool bOnlyAtFirstChartType /* = true */
255 if( eStackMode == StackMode_AMBIGUOUS )
256 return;
258 bool bValueFound = false;
259 bool bIsAmbiguous = false;
260 StackMode eOldStackMode = DiagramHelper::getStackMode( xDiagram, bValueFound, bIsAmbiguous );
262 if( eStackMode == eOldStackMode && !bIsAmbiguous )
263 return;
265 StackingDirection eNewDirection = StackingDirection_NO_STACKING;
266 if( eStackMode == StackMode_Y_STACKED || eStackMode == StackMode_Y_STACKED_PERCENT )
267 eNewDirection = StackingDirection_Y_STACKING;
268 else if( eStackMode == StackMode_Z_STACKED )
269 eNewDirection = StackingDirection_Z_STACKING;
271 uno::Any aNewDirection( uno::makeAny(eNewDirection) );
273 bool bPercent = false;
274 if( eStackMode == StackMode_Y_STACKED_PERCENT )
275 bPercent = true;
277 //iterate through all coordinate systems
278 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
279 if( !xCooSysContainer.is() )
280 return;
281 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
282 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
284 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
285 //set correct percent stacking
286 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(1);
287 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
289 Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1,nI ));
290 if( xAxis.is())
292 chart2::ScaleData aScaleData = xAxis->getScaleData();
293 if( (aScaleData.AxisType==AxisType::PERCENT) != bPercent )
295 if( bPercent )
296 aScaleData.AxisType = AxisType::PERCENT;
297 else
298 aScaleData.AxisType = AxisType::REALNUMBER;
299 xAxis->setScaleData( aScaleData );
303 //iterate through all chart types in the current coordinate system
304 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
305 if( !xChartTypeContainer.is() )
306 continue;
307 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
308 sal_Int32 nMax = aChartTypeList.getLength();
309 if( bOnlyAtFirstChartType
310 && nMax >= 1 )
311 nMax = 1;
312 for( sal_Int32 nT = 0; nT < nMax; ++nT )
314 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
316 //iterate through all series in this chart type
317 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
318 OSL_ASSERT( xDataSeriesContainer.is());
319 if( !xDataSeriesContainer.is() )
320 continue;
322 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
323 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
325 Reference< beans::XPropertySet > xProp( aSeriesList[nS], uno::UNO_QUERY );
326 if(xProp.is())
327 xProp->setPropertyValue( "StackingDirection", aNewDirection );
332 catch( const uno::Exception & ex )
334 ASSERT_EXCEPTION( ex );
338 StackMode DiagramHelper::getStackMode( const Reference< XDiagram > & xDiagram, bool& rbFound, bool& rbAmbiguous )
340 rbFound=false;
341 rbAmbiguous=false;
343 StackMode eGlobalStackMode = StackMode_NONE;
345 //iterate through all coordinate systems
346 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
347 if( !xCooSysContainer.is() )
348 return eGlobalStackMode;
349 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
350 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
352 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
354 //iterate through all chart types in the current coordinate system
355 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
356 if( !xChartTypeContainer.is() )
357 continue;
358 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
359 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
361 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
363 StackMode eLocalStackMode = DiagramHelper::getStackModeFromChartType(
364 xChartType, rbFound, rbAmbiguous, xCooSys );
366 if( rbFound && eLocalStackMode != eGlobalStackMode && nT>0 )
368 rbAmbiguous = true;
369 return eGlobalStackMode;
372 eGlobalStackMode = eLocalStackMode;
376 return eGlobalStackMode;
379 StackMode DiagramHelper::getStackModeFromChartType(
380 const Reference< XChartType > & xChartType,
381 bool& rbFound, bool& rbAmbiguous,
382 const Reference< XCoordinateSystem > & xCorrespondingCoordinateSystem )
384 StackMode eStackMode = StackMode_NONE;
385 rbFound = false;
386 rbAmbiguous = false;
390 Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW );
391 Sequence< Reference< chart2::XDataSeries > > aSeries( xDSCnt->getDataSeries());
393 chart2::StackingDirection eCommonDirection = chart2::StackingDirection_NO_STACKING;
394 bool bDirectionInitialized = false;
396 // first series is irrelvant for stacking, start with second, unless
397 // there is only one series
398 const sal_Int32 nSeriesCount = aSeries.getLength();
399 sal_Int32 i = (nSeriesCount == 1) ? 0: 1;
400 for( ; i<nSeriesCount; ++i )
402 rbFound = true;
403 Reference< beans::XPropertySet > xProp( aSeries[i], uno::UNO_QUERY_THROW );
404 chart2::StackingDirection eCurrentDirection = eCommonDirection;
405 // property is not MAYBEVOID
406 bool bSuccess = ( xProp->getPropertyValue( "StackingDirection" ) >>= eCurrentDirection );
407 OSL_ASSERT( bSuccess );
408 (void)(bSuccess); // avoid warning in non-debug builds
409 if( ! bDirectionInitialized )
411 eCommonDirection = eCurrentDirection;
412 bDirectionInitialized = true;
414 else
416 if( eCommonDirection != eCurrentDirection )
418 rbAmbiguous = true;
419 break;
424 if( rbFound )
426 if( eCommonDirection == chart2::StackingDirection_Z_STACKING )
427 eStackMode = StackMode_Z_STACKED;
428 else if( eCommonDirection == chart2::StackingDirection_Y_STACKING )
430 eStackMode = StackMode_Y_STACKED;
432 // percent stacking
433 if( xCorrespondingCoordinateSystem.is() )
435 if( 1 < xCorrespondingCoordinateSystem->getDimension() )
437 sal_Int32 nAxisIndex = 0;
438 if( nSeriesCount )
439 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(aSeries[0]);
441 Reference< chart2::XAxis > xAxis(
442 xCorrespondingCoordinateSystem->getAxisByDimension( 1,nAxisIndex ));
443 if( xAxis.is())
445 chart2::ScaleData aScaleData = xAxis->getScaleData();
446 if( aScaleData.AxisType==chart2::AxisType::PERCENT )
447 eStackMode = StackMode_Y_STACKED_PERCENT;
454 catch( const uno::Exception & ex )
456 ASSERT_EXCEPTION( ex );
459 return eStackMode;
462 sal_Int32 DiagramHelper::getDimension( const Reference< XDiagram > & xDiagram )
464 // -1: not yet set
465 sal_Int32 nResult = -1;
469 Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY );
470 if( xCooSysCnt.is() )
472 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
473 xCooSysCnt->getCoordinateSystems());
475 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
477 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
478 if(xCooSys.is())
480 nResult = xCooSys->getDimension();
481 break;
486 catch( const uno::Exception & ex )
488 ASSERT_EXCEPTION( ex );
491 return nResult;
494 void DiagramHelper::setDimension(
495 const Reference< XDiagram > & xDiagram,
496 sal_Int32 nNewDimensionCount )
498 if( ! xDiagram.is())
499 return;
501 if( DiagramHelper::getDimension( xDiagram ) == nNewDimensionCount )
502 return;
506 bool rbFound = false;
507 bool rbAmbiguous = true;
508 StackMode eStackMode = DiagramHelper::getStackMode( xDiagram, rbFound, rbAmbiguous );
509 bool bIsSupportingOnlyDeepStackingFor3D=false;
511 //change all coordinate systems:
512 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY_THROW );
513 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
514 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
516 Reference< XCoordinateSystem > xOldCooSys( aCooSysList[nCS], uno::UNO_QUERY );
517 Reference< XCoordinateSystem > xNewCooSys;
519 Reference< XChartTypeContainer > xChartTypeContainer( xOldCooSys, uno::UNO_QUERY );
520 if( !xChartTypeContainer.is() )
521 continue;
523 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
524 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
526 Reference< XChartType > xChartType( aChartTypeList[nT], uno::UNO_QUERY );
527 bIsSupportingOnlyDeepStackingFor3D = ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( xChartType );
528 if(!xNewCooSys.is())
530 xNewCooSys = xChartType->createCoordinateSystem( nNewDimensionCount );
531 break;
533 //@todo make sure that all following charttypes are also capable of the new dimension
534 //otherwise separate them in a different group
535 //BM: might be done in replaceCoordinateSystem()
538 // replace the old coordinate system at all places where it was used
539 DiagramHelper::replaceCoordinateSystem( xDiagram, xOldCooSys, xNewCooSys );
542 //correct stack mode if necessary
543 if( nNewDimensionCount==3 && eStackMode != StackMode_Z_STACKED && bIsSupportingOnlyDeepStackingFor3D )
544 DiagramHelper::setStackMode( xDiagram, StackMode_Z_STACKED );
545 else if( nNewDimensionCount==2 && eStackMode == StackMode_Z_STACKED )
546 DiagramHelper::setStackMode( xDiagram, StackMode_NONE );
548 catch( const uno::Exception & ex )
550 ASSERT_EXCEPTION( ex );
554 void DiagramHelper::replaceCoordinateSystem(
555 const Reference< XDiagram > & xDiagram,
556 const Reference< XCoordinateSystem > & xCooSysToReplace,
557 const Reference< XCoordinateSystem > & xReplacement )
559 OSL_ASSERT( xDiagram.is());
560 if( ! xDiagram.is())
561 return;
563 // update the coordinate-system container
564 Reference< XCoordinateSystemContainer > xCont( xDiagram, uno::UNO_QUERY );
565 if( xCont.is())
569 Reference< chart2::data::XLabeledDataSequence > xCategories = DiagramHelper::getCategoriesFromDiagram( xDiagram );
571 // move chart types of xCooSysToReplace to xReplacement
572 Reference< XChartTypeContainer > xCTCntCooSys( xCooSysToReplace, uno::UNO_QUERY_THROW );
573 Reference< XChartTypeContainer > xCTCntReplacement( xReplacement, uno::UNO_QUERY_THROW );
574 xCTCntReplacement->setChartTypes( xCTCntCooSys->getChartTypes());
576 xCont->removeCoordinateSystem( xCooSysToReplace );
577 xCont->addCoordinateSystem( xReplacement );
579 if( xCategories.is() )
580 DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram );
582 catch( const uno::Exception & ex )
584 ASSERT_EXCEPTION( ex );
589 bool DiagramHelper::isSeriesAttachedToMainAxis(
590 const uno::Reference< chart2::XDataSeries >& xDataSeries )
592 sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
593 return (nAxisIndex==0);
596 bool DiagramHelper::attachSeriesToAxis( bool bAttachToMainAxis
597 , const uno::Reference< chart2::XDataSeries >& xDataSeries
598 , const uno::Reference< chart2::XDiagram >& xDiagram
599 , const uno::Reference< uno::XComponentContext > & xContext
600 , bool bAdaptAxes )
602 bool bChanged = false;
604 //set property at axis
605 Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
606 if( !xProp.is() )
607 return bChanged;
609 sal_Int32 nNewAxisIndex = bAttachToMainAxis ? 0 : 1;
610 sal_Int32 nOldAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
611 uno::Reference< chart2::XAxis > xOldAxis( DiagramHelper::getAttachedAxis( xDataSeries, xDiagram ) );
613 if( nOldAxisIndex != nNewAxisIndex )
617 xProp->setPropertyValue( "AttachedAxisIndex", uno::makeAny( nNewAxisIndex ) );
618 bChanged = true;
620 catch( const uno::Exception & ex )
622 ASSERT_EXCEPTION( ex );
626 if( bChanged && xDiagram.is() )
628 uno::Reference< XAxis > xAxis( AxisHelper::getAxis( 1, bAttachToMainAxis, xDiagram ) );
629 if(!xAxis.is()) //create an axis if necessary
630 xAxis = AxisHelper::createAxis( 1, bAttachToMainAxis, xDiagram, xContext );
631 if( bAdaptAxes )
633 AxisHelper::makeAxisVisible( xAxis );
634 AxisHelper::hideAxisIfNoDataIsAttached( xOldAxis, xDiagram );
638 return bChanged;
641 uno::Reference< XAxis > DiagramHelper::getAttachedAxis(
642 const uno::Reference< XDataSeries >& xSeries,
643 const uno::Reference< XDiagram >& xDiagram )
645 return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), xDiagram );
648 uno::Reference< XChartType > DiagramHelper::getChartTypeOfSeries(
649 const uno::Reference< chart2::XDiagram >& xDiagram
650 , const uno::Reference< XDataSeries >& xGivenDataSeries )
652 if( !xGivenDataSeries.is() )
653 return 0;
654 if(!xDiagram.is())
655 return 0;
657 //iterate through the model to find the given xSeries
658 //the found parent indicates the charttype
660 //iterate through all coordinate systems
661 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
662 if( !xCooSysContainer.is())
663 return 0;
665 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
666 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
668 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
670 //iterate through all chart types in the current coordinate system
671 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
672 OSL_ASSERT( xChartTypeContainer.is());
673 if( !xChartTypeContainer.is() )
674 continue;
675 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
676 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
678 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
680 //iterate through all series in this chart type
681 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
682 OSL_ASSERT( xDataSeriesContainer.is());
683 if( !xDataSeriesContainer.is() )
684 continue;
686 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
687 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
689 if( xGivenDataSeries==aSeriesList[nS] )
690 return xChartType;
694 return 0;
697 ::std::vector< Reference< XDataSeries > >
698 DiagramHelper::getDataSeriesFromDiagram(
699 const Reference< XDiagram > & xDiagram )
701 ::std::vector< Reference< XDataSeries > > aResult;
705 Reference< XCoordinateSystemContainer > xCooSysCnt(
706 xDiagram, uno::UNO_QUERY_THROW );
707 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
708 xCooSysCnt->getCoordinateSystems());
709 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
711 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
712 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
713 for( sal_Int32 j=0; j<aChartTypeSeq.getLength(); ++j )
715 Reference< XDataSeriesContainer > xDSCnt( aChartTypeSeq[j], uno::UNO_QUERY_THROW );
716 Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() );
717 ::std::copy( aSeriesSeq.getConstArray(), aSeriesSeq.getConstArray() + aSeriesSeq.getLength(),
718 ::std::back_inserter( aResult ));
722 catch( const uno::Exception & ex )
724 ASSERT_EXCEPTION( ex );
727 return aResult;
730 Sequence< Sequence< Reference< XDataSeries > > >
731 DiagramHelper::getDataSeriesGroups( const Reference< XDiagram > & xDiagram )
733 vector< Sequence< Reference< XDataSeries > > > aResult;
735 //iterate through all coordinate systems
736 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
737 if( xCooSysContainer.is() )
739 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
740 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
742 //iterate through all chart types in the current coordinate system
743 Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
744 if( !xChartTypeContainer.is() )
745 continue;
746 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
747 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
749 Reference< XDataSeriesContainer > xDataSeriesContainer( aChartTypeList[nT], uno::UNO_QUERY );
750 if( !xDataSeriesContainer.is() )
751 continue;
752 aResult.push_back( xDataSeriesContainer->getDataSeries() );
756 return ContainerHelper::ContainerToSequence( aResult );
759 Reference< XChartType >
760 DiagramHelper::getChartTypeByIndex( const Reference< XDiagram >& xDiagram, sal_Int32 nIndex )
762 Reference< XChartType > xChartType;
764 //iterate through all coordinate systems
765 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
766 if( ! xCooSysContainer.is())
767 return xChartType;
769 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
770 sal_Int32 nTypesSoFar = 0;
771 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
773 Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
774 if( !xChartTypeContainer.is() )
775 continue;
776 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
777 if( nIndex >= 0 && nIndex < (nTypesSoFar + aChartTypeList.getLength()) )
779 xChartType.set( aChartTypeList[nIndex - nTypesSoFar] );
780 break;
782 nTypesSoFar += aChartTypeList.getLength();
785 return xChartType;
788 namespace
791 std::vector< Reference< XAxis > > lcl_getAxisHoldingCategoriesFromDiagram(
792 const Reference< XDiagram > & xDiagram )
794 std::vector< Reference< XAxis > > aRet;
796 Reference< XAxis > xResult;
797 // return first x-axis as fall-back
798 Reference< XAxis > xFallBack;
801 Reference< XCoordinateSystemContainer > xCooSysCnt(
802 xDiagram, uno::UNO_QUERY_THROW );
803 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
804 xCooSysCnt->getCoordinateSystems());
805 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
807 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
808 OSL_ASSERT( xCooSys.is());
809 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
811 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
812 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
814 Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
815 OSL_ASSERT( xAxis.is());
816 if( xAxis.is())
818 ScaleData aScaleData = xAxis->getScaleData();
819 if( aScaleData.Categories.is() || (aScaleData.AxisType == AxisType::CATEGORY) )
821 aRet.push_back(xAxis);
823 if( (nN == 0) && !xFallBack.is())
824 xFallBack.set( xAxis );
830 catch( const uno::Exception & ex )
832 ASSERT_EXCEPTION( ex );
835 if( aRet.empty() )
836 aRet.push_back(xFallBack);
838 return aRet;
841 } // anonymous namespace
843 bool DiagramHelper::isCategoryDiagram(
844 const Reference< XDiagram >& xDiagram )
848 Reference< XCoordinateSystemContainer > xCooSysCnt(
849 xDiagram, uno::UNO_QUERY_THROW );
850 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
851 xCooSysCnt->getCoordinateSystems());
852 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
854 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
855 OSL_ASSERT( xCooSys.is());
856 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
858 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
859 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
861 Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
862 OSL_ASSERT( xAxis.is());
863 if( xAxis.is())
865 ScaleData aScaleData = xAxis->getScaleData();
866 if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
867 return true;
873 catch( const uno::Exception & ex )
875 ASSERT_EXCEPTION( ex );
878 return false;
881 void DiagramHelper::setCategoriesToDiagram(
882 const Reference< chart2::data::XLabeledDataSequence >& xCategories,
883 const Reference< XDiagram >& xDiagram,
884 bool bSetAxisType /* = false */,
885 bool bCategoryAxis /* = true */ )
887 std::vector< Reference< chart2::XAxis > > aCatAxes(
888 lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
890 std::vector< Reference< chart2::XAxis > >::iterator aIt( aCatAxes.begin() );
891 std::vector< Reference< chart2::XAxis > >::const_iterator aEnd( aCatAxes.end() );
893 for( aIt = aCatAxes.begin(); aIt != aEnd; ++aIt )
895 Reference< chart2::XAxis > xCatAxis(*aIt);
896 if( xCatAxis.is())
898 ScaleData aScaleData( xCatAxis->getScaleData());
899 aScaleData.Categories = xCategories;
900 if( bSetAxisType )
902 if( bCategoryAxis )
903 aScaleData.AxisType = AxisType::CATEGORY;
904 else if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
905 aScaleData.AxisType = AxisType::REALNUMBER;
907 xCatAxis->setScaleData( aScaleData );
912 Reference< data::XLabeledDataSequence >
913 DiagramHelper::getCategoriesFromDiagram(
914 const Reference< XDiagram > & xDiagram )
916 Reference< data::XLabeledDataSequence > xResult;
920 std::vector< Reference< chart2::XAxis > > aCatAxes(
921 lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
922 std::vector< Reference< chart2::XAxis > >::iterator aIt( aCatAxes.begin() );
923 std::vector< Reference< chart2::XAxis > >::const_iterator aEnd( aCatAxes.end() );
924 //search for first categories
925 if( aIt != aEnd )
927 Reference< chart2::XAxis > xCatAxis(*aIt);
928 if( xCatAxis.is())
930 ScaleData aScaleData( xCatAxis->getScaleData());
931 if( aScaleData.Categories.is() )
933 xResult.set( aScaleData.Categories );
934 uno::Reference<beans::XPropertySet> xProp(aScaleData.Categories->getValues(), uno::UNO_QUERY );
935 if( xProp.is() )
939 xProp->setPropertyValue( "Role", uno::makeAny( OUString("categories") ) );
941 catch( const uno::Exception & ex )
943 ASSERT_EXCEPTION( ex );
950 catch( const uno::Exception & ex )
952 ASSERT_EXCEPTION( ex );
955 return xResult;
958 void lcl_generateAutomaticCategoriesFromChartType(
959 Sequence< OUString >& rRet,
960 const Reference< XChartType >& xChartType )
962 if(!xChartType.is())
963 return;
964 OUString aMainSeq( xChartType->getRoleOfSequenceForSeriesLabel() );
965 Reference< XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY );
966 if( xSeriesCnt.is() )
968 Sequence< Reference< XDataSeries > > aSeriesSeq( xSeriesCnt->getDataSeries() );
969 for( sal_Int32 nS = 0; nS < aSeriesSeq.getLength(); nS++ )
971 Reference< data::XDataSource > xDataSource( aSeriesSeq[nS], uno::UNO_QUERY );
972 if( !xDataSource.is() )
973 continue;
974 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
975 ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aMainSeq ));
976 if( !xLabeledSeq.is() )
977 continue;
978 Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() );
979 if( !xValueSeq.is() )
980 continue;
981 rRet = xValueSeq->generateLabel( chart2::data::LabelOrigin_LONG_SIDE );
982 if( rRet.getLength() )
983 return;
988 Sequence< OUString > DiagramHelper::generateAutomaticCategoriesFromCooSys( const Reference< XCoordinateSystem > & xCooSys )
990 Sequence< OUString > aRet;
992 Reference< XChartTypeContainer > xTypeCntr( xCooSys, uno::UNO_QUERY );
993 if( xTypeCntr.is() )
995 Sequence< Reference< XChartType > > aChartTypes( xTypeCntr->getChartTypes() );
996 for( sal_Int32 nN=0; nN<aChartTypes.getLength(); nN++ )
998 lcl_generateAutomaticCategoriesFromChartType( aRet, aChartTypes[nN] );
999 if( aRet.getLength() )
1000 return aRet;
1003 return aRet;
1006 Sequence< OUString > DiagramHelper::getExplicitSimpleCategories(
1007 ChartModel& rModel )
1009 uno::Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( rModel ) );
1010 ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel );
1011 return aExplicitCategoriesProvider.getSimpleCategories();
1014 namespace
1016 void lcl_switchToDateCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
1018 if( !xAxis.is() )
1019 return;
1020 if( !xChartDoc.is() )
1021 return;
1023 ScaleData aScale( xAxis->getScaleData() );
1024 if( xChartDoc->hasInternalDataProvider() )
1026 //remove all content the is not of type double and remove multiple level
1027 Reference< XAnyDescriptionAccess > xDataAccess( xChartDoc->getDataProvider(), uno::UNO_QUERY );
1028 if( xDataAccess.is() )
1030 Sequence< Sequence< Any > > aAnyCategories( xDataAccess->getAnyRowDescriptions() );
1031 double fTest = 0.0;
1032 double fNan = 0.0;
1033 ::rtl::math::setNan( & fNan );
1034 sal_Int32 nN = aAnyCategories.getLength();
1035 for( ; nN--; )
1037 Sequence< Any >& rCat = aAnyCategories[nN];
1038 if( rCat.getLength() > 1 )
1039 rCat.realloc(1);
1040 if( rCat.getLength() == 1 )
1042 Any& rAny = rCat[0];
1043 if( !(rAny>>=fTest) )
1045 rAny = uno::makeAny(fNan);
1049 xDataAccess->setAnyRowDescriptions( aAnyCategories );
1051 //check the numberformat at the axis
1052 Reference< beans::XPropertySet > xAxisProps( xAxis, uno::UNO_QUERY );
1053 Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartDoc, uno::UNO_QUERY );
1054 if( xAxisProps.is() && xNumberFormatsSupplier.is() )
1056 sal_Int32 nNumberFormat = -1;
1057 xAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormat;
1059 Reference< util::XNumberFormats > xNumberFormats = Reference< util::XNumberFormats >( xNumberFormatsSupplier->getNumberFormats() );
1060 if( xNumberFormats.is() )
1062 Reference< beans::XPropertySet > xKeyProps;
1065 xKeyProps = xNumberFormats->getByKey( nNumberFormat );
1067 catch( const uno::Exception & ex )
1069 ASSERT_EXCEPTION( ex );
1071 sal_Int32 nType = util::NumberFormat::UNDEFINED;
1072 if( xKeyProps.is() )
1073 xKeyProps->getPropertyValue( "Type" ) >>= nType;
1074 if( !( nType & util::NumberFormat::DATE ) )
1076 //set a date format to the axis
1077 bool bCreate = true;
1078 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
1079 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE, rLocaleDataWrapper.getLanguageTag().getLocale(), bCreate );
1080 if( aKeySeq.getLength() )
1082 xAxisProps->setPropertyValue(CHART_UNONAME_NUMFMT, uno::makeAny(aKeySeq[0]));
1088 if( aScale.AxisType != chart2::AxisType::DATE )
1089 AxisHelper::removeExplicitScaling( aScale );
1090 aScale.AxisType = chart2::AxisType::DATE;
1091 xAxis->setScaleData( aScale );
1094 void lcl_switchToTextCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
1096 if( !xAxis.is() )
1097 return;
1098 if( !xChartDoc.is() )
1099 return;
1100 ScaleData aScale( xAxis->getScaleData() );
1101 if( aScale.AxisType != chart2::AxisType::CATEGORY )
1102 AxisHelper::removeExplicitScaling( aScale );
1103 //todo migrate dates to text?
1104 aScale.AxisType = chart2::AxisType::CATEGORY;
1105 aScale.AutoDateAxis = false;
1106 xAxis->setScaleData( aScale );
1111 void DiagramHelper::switchToDateCategories( const Reference< XChartDocument >& xChartDoc )
1113 Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
1114 if(xChartModel.is())
1116 ControllerLockGuardUNO aCtrlLockGuard( xChartModel );
1118 Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
1119 if( xCooSys.is() )
1121 Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
1122 lcl_switchToDateCategories( xChartDoc, xAxis );
1127 void DiagramHelper::switchToTextCategories( const Reference< XChartDocument >& xChartDoc )
1129 Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
1130 if(xChartModel.is())
1132 ControllerLockGuardUNO aCtrlLockGuard( xChartModel );
1134 Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
1135 if( xCooSys.is() )
1137 Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
1138 lcl_switchToTextCategories( xChartDoc, xAxis );
1143 bool DiagramHelper::isSupportingDateAxis( const Reference< chart2::XDiagram >& xDiagram )
1145 return ::chart::ChartTypeHelper::isSupportingDateAxis(
1146 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ), DiagramHelper::getDimension( xDiagram ), 0 );
1149 bool DiagramHelper::isDateNumberFormat( sal_Int32 nNumberFormat, const Reference< util::XNumberFormats >& xNumberFormats )
1151 bool bIsDate = false;
1152 if( !xNumberFormats.is() )
1153 return bIsDate;
1155 Reference< beans::XPropertySet > xKeyProps = xNumberFormats->getByKey( nNumberFormat );
1156 if( xKeyProps.is() )
1158 sal_Int32 nType = util::NumberFormat::UNDEFINED;
1159 xKeyProps->getPropertyValue( "Type" ) >>= nType;
1160 bIsDate = nType & util::NumberFormat::DATE;
1162 return bIsDate;
1165 sal_Int32 DiagramHelper::getDateNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1167 sal_Int32 nRet=-1;
1168 Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1169 if( xNumberFormats.is() )
1171 bool bCreate = true;
1172 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
1173 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE,
1174 rLocaleDataWrapper.getLanguageTag().getLocale(), bCreate );
1175 if( aKeySeq.getLength() )
1177 nRet = aKeySeq[0];
1181 //try to get a date format with full year display
1182 NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1183 SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1184 if( pNumFormatter )
1186 const SvNumberformat* pFormat = pNumFormatter->GetEntry( nRet );
1187 if( pFormat )
1188 nRet = pNumFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, pFormat->GetLanguage() );
1190 return nRet;
1193 sal_Int32 DiagramHelper::getDateTimeInputNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier, double fNumber )
1195 sal_Int32 nRet = 0;
1197 // Get the most detailed date/time format according to fNumber.
1198 NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1199 SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1200 if (!pNumFormatter)
1201 SAL_WARN("chart2", "DiagramHelper::getDateTimeInputNumberFormat - no SvNumberFormatter");
1202 else
1204 // Categorize the format according to the implementation of
1205 // SvNumberFormatter::GetEditFormat(), making assumptions about what
1206 // would be time only.
1207 /* TODO: implement a method at SvNumberFormatter that does this and
1208 * call instead, if Chart isn't able transport the proper format of the
1209 * Axis, which of course would be much better.. */
1210 short nType;
1211 if (0.0 <= fNumber && fNumber < 1.0)
1213 // Clearly a time.
1214 nType = util::NumberFormat::TIME;
1215 nRet = pNumFormatter->GetFormatIndex( NF_TIME_HHMM, LANGUAGE_SYSTEM);
1217 else if (fabs( fNumber) * 24 < 0x7fff)
1219 // Assuming time within 32k hours or 3.7 years.
1220 nType = util::NumberFormat::TIME;
1221 nRet = pNumFormatter->GetFormatIndex( NF_TIME_HH_MMSS, LANGUAGE_SYSTEM);
1223 else if (rtl::math::approxFloor( fNumber) != fNumber)
1225 // Date+Time.
1226 nType = util::NumberFormat::DATETIME;
1227 nRet = pNumFormatter->GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, LANGUAGE_SYSTEM);
1229 else
1231 // Date only.
1232 nType = util::NumberFormat::DATE;
1233 nRet = pNumFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, LANGUAGE_SYSTEM);
1236 // Obtain the corresponding edit format.
1237 nRet = pNumFormatter->GetEditFormat( fNumber, nRet, nType, LANGUAGE_SYSTEM, NULL);
1239 return nRet;
1242 sal_Int32 DiagramHelper::getPercentNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1244 sal_Int32 nRet=-1;
1245 Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1246 if( xNumberFormats.is() )
1248 bool bCreate = true;
1249 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
1250 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::PERCENT,
1251 rLocaleDataWrapper.getLanguageTag().getLocale(), bCreate );
1252 if( aKeySeq.getLength() )
1254 nRet = aKeySeq[0];
1257 return nRet;
1260 Sequence< Reference< XChartType > >
1261 DiagramHelper::getChartTypesFromDiagram(
1262 const Reference< XDiagram > & xDiagram )
1264 ::std::vector< Reference< XChartType > > aResult;
1266 if(xDiagram.is())
1270 Reference< XCoordinateSystemContainer > xCooSysCnt(
1271 xDiagram, uno::UNO_QUERY_THROW );
1272 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
1273 xCooSysCnt->getCoordinateSystems());
1274 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
1276 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
1277 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
1278 ::std::copy( aChartTypeSeq.getConstArray(),
1279 aChartTypeSeq.getConstArray() + aChartTypeSeq.getLength(),
1280 ::std::back_inserter( aResult ));
1283 catch( const uno::Exception & ex )
1285 ASSERT_EXCEPTION( ex );
1289 return ContainerHelper::ContainerToSequence( aResult );
1292 bool DiagramHelper::areChartTypesCompatible( const Reference< ::chart2::XChartType >& xFirstType,
1293 const Reference< ::chart2::XChartType >& xSecondType )
1295 if( !xFirstType.is() || !xSecondType.is() )
1296 return false;
1298 ::std::vector< OUString > aFirstRoles( ContainerHelper::SequenceToVector( xFirstType->getSupportedMandatoryRoles() ) );
1299 ::std::vector< OUString > aSecondRoles( ContainerHelper::SequenceToVector( xSecondType->getSupportedMandatoryRoles() ) );
1300 ::std::sort( aFirstRoles.begin(), aFirstRoles.end() );
1301 ::std::sort( aSecondRoles.begin(), aSecondRoles.end() );
1302 return ( aFirstRoles == aSecondRoles );
1305 namespace
1308 * This method implements the logic of checking if a series can be moved
1309 * forward/backward. Depending on the "bDoMove" parameter the series will
1310 * be moved (bDoMove = true) or the function just will test if the
1311 * series can be moved without doing the move (bDoMove = false).
1313 * @param xDiagram
1314 * Reference to the diagram that contains the series.
1316 * @param xGivenDataSeries
1317 * Reference to the series that should moved or tested for moving.
1319 * @param bForward
1320 * Direction in which the series should be moved or tested for moving.
1322 * @param bDoMove
1323 * Should this function really move the series (true) or just test if it is
1324 * possible (false).
1327 * @returns
1328 * in case of bDoMove == true
1329 * - True : if the move was done
1330 * - False : the move failed
1331 * in case of bDoMove == false
1332 * - True : the series can be moved
1333 * - False : the series can not be moved
1337 bool lcl_moveSeriesOrCheckIfMoveIsAllowed(
1338 const Reference< XDiagram >& xDiagram,
1339 const Reference< XDataSeries >& xGivenDataSeries,
1340 bool bForward,
1341 bool bDoMove )
1343 bool bMovedOrMoveAllowed = false;
1347 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
1349 if( xGivenDataSeries.is() && xCooSysContainer.is() )
1351 //find position of series.
1352 bool bFound = false;
1353 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
1355 for( sal_Int32 nCS = 0; !bFound && nCS < aCooSysList.getLength(); ++nCS )
1357 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
1359 //iterate through all chart types in the current coordinate system
1360 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
1361 OSL_ASSERT( xChartTypeContainer.is());
1362 if( !xChartTypeContainer.is() )
1363 continue;
1364 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
1365 uno::Reference< XChartType > xFormerChartType;
1367 for( sal_Int32 nT = 0; !bFound && nT < aChartTypeList.getLength(); ++nT )
1369 uno::Reference< XChartType > xCurrentChartType( aChartTypeList[nT] );
1371 //iterate through all series in this chart type
1372 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xCurrentChartType, uno::UNO_QUERY );
1373 OSL_ASSERT( xDataSeriesContainer.is());
1374 if( !xDataSeriesContainer.is() )
1375 continue;
1377 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
1379 for( sal_Int32 nS = 0; !bFound && nS < aSeriesList.getLength(); ++nS )
1382 // We found the series we are interrested in !
1383 if( xGivenDataSeries==aSeriesList[nS] )
1385 sal_Int32 nOldSeriesIndex = nS;
1386 bFound = true;
1390 sal_Int32 nNewSeriesIndex = nS;
1392 if( bForward )
1393 nNewSeriesIndex--;
1394 else
1395 nNewSeriesIndex++;
1397 if( nNewSeriesIndex >= 0 && nNewSeriesIndex < aSeriesList.getLength() )
1399 //move series in the same charttype
1400 bMovedOrMoveAllowed = true;
1401 if( bDoMove )
1403 aSeriesList[ nOldSeriesIndex ] = aSeriesList[ nNewSeriesIndex ];
1404 aSeriesList[ nNewSeriesIndex ] = xGivenDataSeries;
1405 xDataSeriesContainer->setDataSeries( aSeriesList );
1408 else if( nNewSeriesIndex<0 )
1410 //exchange series with former charttype
1411 if( xFormerChartType.is() && DiagramHelper::areChartTypesCompatible( xFormerChartType, xCurrentChartType ) )
1413 bMovedOrMoveAllowed = true;
1414 if( bDoMove )
1416 uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xFormerChartType, uno::UNO_QUERY );
1417 if( xOtherDataSeriesContainer.is() )
1419 uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
1420 sal_Int32 nOtherSeriesIndex = aOtherSeriesList.getLength()-1;
1421 if( nOtherSeriesIndex >= 0 && nOtherSeriesIndex < aOtherSeriesList.getLength() )
1423 uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
1424 aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
1425 xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
1427 aSeriesList[nOldSeriesIndex]=xExchangeSeries;
1428 xDataSeriesContainer->setDataSeries(aSeriesList);
1434 else if( nT+1 < aChartTypeList.getLength() )
1436 //exchange series with next charttype
1437 uno::Reference< XChartType > xOtherChartType( aChartTypeList[nT+1] );
1438 if( xOtherChartType.is() && DiagramHelper::areChartTypesCompatible( xOtherChartType, xCurrentChartType ) )
1440 bMovedOrMoveAllowed = true;
1441 if( bDoMove )
1443 uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xOtherChartType, uno::UNO_QUERY );
1444 if( xOtherDataSeriesContainer.is() )
1446 uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
1447 sal_Int32 nOtherSeriesIndex = 0;
1448 if( nOtherSeriesIndex >= 0 && nOtherSeriesIndex < aOtherSeriesList.getLength() )
1450 uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
1451 aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
1452 xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
1454 aSeriesList[nOldSeriesIndex]=xExchangeSeries;
1455 xDataSeriesContainer->setDataSeries(aSeriesList);
1462 catch( const util::CloseVetoException& )
1465 catch( const uno::RuntimeException& )
1470 xFormerChartType = xCurrentChartType;
1475 catch( const util::CloseVetoException& )
1478 catch( const uno::RuntimeException& )
1481 return bMovedOrMoveAllowed;
1483 } // anonymous namespace
1485 bool DiagramHelper::isSeriesMoveable(
1486 const Reference< XDiagram >& xDiagram,
1487 const Reference< XDataSeries >& xGivenDataSeries,
1488 bool bForward )
1490 const bool bDoMove = false;
1492 bool bIsMoveable = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1493 xDiagram, xGivenDataSeries, bForward, bDoMove );
1495 return bIsMoveable;
1498 bool DiagramHelper::moveSeries( const Reference< XDiagram >& xDiagram, const Reference< XDataSeries >& xGivenDataSeries, bool bForward )
1500 const bool bDoMove = true;
1502 bool bMoved = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1503 xDiagram, xGivenDataSeries, bForward, bDoMove );
1505 return bMoved;
1508 bool DiagramHelper::isSupportingFloorAndWall( const Reference<
1509 chart2::XDiagram >& xDiagram )
1511 //pies and donuts currently do not support this because of wrong files from older versions
1512 //todo: allow this in future again, if fileversion are available for ole objects (metastream)
1513 //thus the wrong bottom can be removed on import
1515 Sequence< Reference< chart2::XChartType > > aTypes(
1516 ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) );
1517 for( sal_Int32 nN = 0; nN < aTypes.getLength(); nN++ )
1519 Reference< chart2::XChartType > xType( aTypes[nN] );
1520 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
1521 return false;
1522 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
1523 return false;
1524 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
1525 return false;
1527 return true;
1530 bool DiagramHelper::isPieOrDonutChart( const ::com::sun::star::uno::Reference<
1531 ::com::sun::star::chart2::XDiagram >& xDiagram )
1533 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex(
1534 xDiagram, 0 ) );
1536 if( xChartType .is() )
1538 OUString aChartType = xChartType->getChartType();
1539 if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE )
1540 return true;
1542 return false;
1545 sal_Int32 DiagramHelper::getGeometry3D(
1546 const uno::Reference< chart2::XDiagram > & xDiagram,
1547 bool& rbFound, bool& rbAmbiguous )
1549 sal_Int32 nCommonGeom( DataPointGeometry3D::CUBOID );
1550 rbFound = false;
1551 rbAmbiguous = false;
1553 ::std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
1554 DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
1556 if( aSeriesVec.empty())
1557 rbAmbiguous = true;
1559 for( ::std::vector< Reference< chart2::XDataSeries > >::const_iterator aIt =
1560 aSeriesVec.begin(); aIt != aSeriesVec.end(); ++aIt )
1564 sal_Int32 nGeom = 0;
1565 Reference< beans::XPropertySet > xProp( *aIt, uno::UNO_QUERY_THROW );
1566 if( xProp->getPropertyValue( "Geometry3D") >>= nGeom )
1568 if( ! rbFound )
1570 // first series
1571 nCommonGeom = nGeom;
1572 rbFound = true;
1574 // further series: compare for uniqueness
1575 else if( nCommonGeom != nGeom )
1577 rbAmbiguous = true;
1578 break;
1582 catch( const uno::Exception & ex )
1584 ASSERT_EXCEPTION( ex );
1588 return nCommonGeom;
1591 void DiagramHelper::setGeometry3D(
1592 const Reference< chart2::XDiagram > & xDiagram,
1593 sal_Int32 nNewGeometry )
1595 ::std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
1596 DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
1598 for( ::std::vector< Reference< chart2::XDataSeries > >::const_iterator aIt =
1599 aSeriesVec.begin(); aIt != aSeriesVec.end(); ++aIt )
1601 DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(
1602 *aIt, "Geometry3D", uno::makeAny( nNewGeometry ));
1606 sal_Int32 DiagramHelper::getCorrectedMissingValueTreatment(
1607 const Reference< chart2::XDiagram > & xDiagram,
1608 const Reference< chart2::XChartType >& xChartType )
1610 sal_Int32 nResult = ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP;
1611 uno::Sequence < sal_Int32 > aAvailableMissingValueTreatments(
1612 ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) );
1614 uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
1615 if( xDiaProp.is() && (xDiaProp->getPropertyValue( "MissingValueTreatment" ) >>= nResult) )
1617 //ensure that the set value is supported by this charttype
1618 for( sal_Int32 nN = 0; nN < aAvailableMissingValueTreatments.getLength(); nN++ )
1619 if( aAvailableMissingValueTreatments[nN] == nResult )
1620 return nResult; //ok
1623 //otherwise use the first supported one
1624 if( aAvailableMissingValueTreatments.getLength() )
1626 nResult = aAvailableMissingValueTreatments[0];
1627 return nResult;
1630 return nResult;
1633 DiagramPositioningMode DiagramHelper::getDiagramPositioningMode( const uno::Reference<
1634 chart2::XDiagram > & xDiagram )
1636 DiagramPositioningMode eMode = DiagramPositioningMode_AUTO;
1637 uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY );
1638 if( xDiaProps.is() )
1640 RelativePosition aRelPos;
1641 RelativeSize aRelSize;
1642 if( (xDiaProps->getPropertyValue("RelativePosition") >>= aRelPos ) &&
1643 (xDiaProps->getPropertyValue("RelativeSize") >>= aRelSize ) )
1645 bool bPosSizeExcludeAxes=false;
1646 xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxes;
1647 if( bPosSizeExcludeAxes )
1648 eMode = DiagramPositioningMode_EXCLUDING;
1649 else
1650 eMode = DiagramPositioningMode_INCLUDING;
1653 return eMode;
1656 void lcl_ensureRange0to1( double& rValue )
1658 if(rValue<0.0)
1659 rValue=0.0;
1660 if(rValue>1.0)
1661 rValue=1.0;
1664 bool DiagramHelper::setDiagramPositioning( const uno::Reference< frame::XModel >& xChartModel,
1665 const awt::Rectangle& rPosRect /*100th mm*/ )
1667 ControllerLockGuardUNO aCtrlLockGuard( xChartModel );
1669 bool bChanged = false;
1670 awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
1671 uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
1672 if( !xDiaProps.is() )
1673 return bChanged;
1675 RelativePosition aOldPos;
1676 RelativeSize aOldSize;
1677 xDiaProps->getPropertyValue("RelativePosition" ) >>= aOldPos;
1678 xDiaProps->getPropertyValue("RelativeSize" ) >>= aOldSize;
1680 RelativePosition aNewPos;
1681 aNewPos.Anchor = drawing::Alignment_TOP_LEFT;
1682 aNewPos.Primary = double(rPosRect.X)/double(aPageSize.Width);
1683 aNewPos.Secondary = double(rPosRect.Y)/double(aPageSize.Height);
1685 chart2::RelativeSize aNewSize;
1686 aNewSize.Primary = double(rPosRect.Width)/double(aPageSize.Width);
1687 aNewSize.Secondary = double(rPosRect.Height)/double(aPageSize.Height);
1689 lcl_ensureRange0to1( aNewPos.Primary );
1690 lcl_ensureRange0to1( aNewPos.Secondary );
1691 lcl_ensureRange0to1( aNewSize.Primary );
1692 lcl_ensureRange0to1( aNewSize.Secondary );
1693 if( (aNewPos.Primary + aNewSize.Primary) > 1.0 )
1694 aNewPos.Primary = 1.0 - aNewSize.Primary;
1695 if( (aNewPos.Secondary + aNewSize.Secondary) > 1.0 )
1696 aNewPos.Secondary = 1.0 - aNewSize.Secondary;
1698 xDiaProps->setPropertyValue( "RelativePosition", uno::makeAny(aNewPos) );
1699 xDiaProps->setPropertyValue( "RelativeSize", uno::makeAny(aNewSize) );
1701 bChanged = (aOldPos.Anchor!=aNewPos.Anchor) ||
1702 (aOldPos.Primary!=aNewPos.Primary) ||
1703 (aOldPos.Secondary!=aNewPos.Secondary) ||
1704 (aOldSize.Primary!=aNewSize.Primary) ||
1705 (aOldSize.Secondary!=aNewSize.Secondary);
1706 return bChanged;
1709 awt::Rectangle DiagramHelper::getDiagramRectangleFromModel( const uno::Reference< frame::XModel >& xChartModel )
1711 awt::Rectangle aRet(-1,-1,-1,-1);
1713 uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
1714 if( !xDiaProps.is() )
1715 return aRet;
1717 awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
1719 RelativePosition aRelPos;
1720 RelativeSize aRelSize;
1721 xDiaProps->getPropertyValue("RelativePosition" ) >>= aRelPos;
1722 xDiaProps->getPropertyValue("RelativeSize" ) >>= aRelSize;
1724 awt::Size aAbsSize(
1725 static_cast< sal_Int32 >( aRelSize.Primary * aPageSize.Width ),
1726 static_cast< sal_Int32 >( aRelSize.Secondary * aPageSize.Height ));
1728 awt::Point aAbsPos(
1729 static_cast< sal_Int32 >( aRelPos.Primary * aPageSize.Width ),
1730 static_cast< sal_Int32 >( aRelPos.Secondary * aPageSize.Height ));
1732 awt::Point aAbsPosLeftTop = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( aAbsPos, aAbsSize, aRelPos.Anchor );
1734 aRet = awt::Rectangle(aAbsPosLeftTop.X, aAbsPosLeftTop.Y, aAbsSize.Width, aAbsSize.Height );
1736 return aRet;
1739 bool DiagramHelper::switchDiagramPositioningToExcludingPositioning(
1740 ChartModel& rModel, bool bResetModifiedState, bool bConvertAlsoFromAutoPositioning )
1742 //return true if something was changed
1743 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
1744 if( nCurrentODFVersion > SvtSaveOptions::ODFVER_012 )
1746 uno::Reference< ::com::sun::star::chart::XDiagramPositioning > xDiagramPositioning( rModel.getFirstDiagram(), uno::UNO_QUERY );
1747 if( xDiagramPositioning.is() && ( bConvertAlsoFromAutoPositioning || !xDiagramPositioning->isAutomaticDiagramPositioning() )
1748 && !xDiagramPositioning->isExcludingDiagramPositioning() )
1750 ControllerLockGuard aCtrlLockGuard( rModel );
1751 bool bModelWasModified = rModel.isModified();
1752 xDiagramPositioning->setDiagramPositionExcludingAxes( xDiagramPositioning->calculateDiagramPositionExcludingAxes() );
1753 if(bResetModifiedState && !bModelWasModified )
1754 rModel.setModified(sal_False);
1755 return true;
1758 return false;
1761 } // namespace chart
1763 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */