Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / chart2 / source / tools / DiagramHelper.cxx
blob22ddfb27acd5f3b4ed35504d145c893236a8151c
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 <DataSeriesHelper.hxx>
22 #include <AxisHelper.hxx>
23 #include <ChartTypeHelper.hxx>
24 #include <ChartModel.hxx>
25 #include <ChartModelHelper.hxx>
26 #include <ExplicitCategoriesProvider.hxx>
27 #include <servicenames_charttypes.hxx>
28 #include <RelativePositionHelper.hxx>
29 #include <ControllerLockGuard.hxx>
30 #include <NumberFormatterWrapper.hxx>
31 #include <unonames.hxx>
33 #include <com/sun/star/chart/MissingValueTreatment.hpp>
34 #include <com/sun/star/chart/XDiagramPositioning.hpp>
35 #include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
36 #include <com/sun/star/chart2/XTitled.hpp>
37 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
38 #include <com/sun/star/chart2/XChartTypeTemplate.hpp>
39 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
40 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
41 #include <com/sun/star/chart2/AxisType.hpp>
42 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
43 #include <com/sun/star/chart2/RelativePosition.hpp>
44 #include <com/sun/star/chart2/RelativeSize.hpp>
45 #include <com/sun/star/chart2/StackingDirection.hpp>
47 #include <com/sun/star/util/CloseVetoException.hpp>
48 #include <com/sun/star/util/NumberFormat.hpp>
49 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
51 #include <unotools/saveopt.hxx>
52 #include <rtl/math.hxx>
53 #include <svl/zforlist.hxx>
54 #include <vcl/svapp.hxx>
55 #include <vcl/settings.hxx>
56 #include <comphelper/sequence.hxx>
57 #include <tools/diagnose_ex.h>
58 #include <sal/log.hxx>
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::chart2;
62 using namespace ::std;
64 using ::com::sun::star::uno::Reference;
65 using ::com::sun::star::uno::Sequence;
66 using ::com::sun::star::uno::Any;
67 using ::com::sun::star::chart2::XAnyDescriptionAccess;
69 namespace chart
72 DiagramHelper::tTemplateWithServiceName
73 DiagramHelper::getTemplateForDiagram(
74 const Reference< XDiagram > & xDiagram,
75 const Reference< lang::XMultiServiceFactory > & xChartTypeManager )
77 DiagramHelper::tTemplateWithServiceName aResult;
79 if( ! (xChartTypeManager.is() && xDiagram.is()))
80 return aResult;
82 Sequence< OUString > aServiceNames( xChartTypeManager->getAvailableServiceNames());
83 const sal_Int32 nLength = aServiceNames.getLength();
85 bool bTemplateFound = false;
87 for( sal_Int32 i = 0; ! bTemplateFound && i < nLength; ++i )
89 try
91 Reference< XChartTypeTemplate > xTempl(
92 xChartTypeManager->createInstance( aServiceNames[ i ] ), uno::UNO_QUERY_THROW );
94 if (xTempl.is() && xTempl->matchesTemplate(xDiagram, true))
96 aResult.first = xTempl;
97 aResult.second = aServiceNames[ i ];
98 bTemplateFound = true;
101 catch( const uno::Exception & )
103 DBG_UNHANDLED_EXCEPTION("chart2");
107 return aResult;
110 void DiagramHelper::setVertical(
111 const Reference< XDiagram > & xDiagram,
112 bool bVertical /* = true */ )
116 Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
117 if (!xCnt.is())
118 return;
120 Sequence< Reference<XCoordinateSystem> > aCooSys = xCnt->getCoordinateSystems();
121 uno::Any aValue;
122 aValue <<= bVertical;
123 for( sal_Int32 i=0; i<aCooSys.getLength(); ++i )
125 uno::Reference< XCoordinateSystem > xCooSys( aCooSys[i] );
126 Reference< beans::XPropertySet > xProp( xCooSys, uno::UNO_QUERY );
127 bool bChanged = false;
128 if (xProp.is())
130 bool bOldSwap = false;
131 if( !(xProp->getPropertyValue("SwapXAndYAxis") >>= bOldSwap)
132 || bVertical != bOldSwap )
133 bChanged = true;
135 if( bChanged )
136 xProp->setPropertyValue("SwapXAndYAxis", aValue);
139 if (!xCooSys.is())
140 continue;
142 const sal_Int32 nDimensionCount = xCooSys->getDimension();
143 sal_Int32 nDimIndex = 0;
144 for (nDimIndex=0; nDimIndex < nDimensionCount; ++nDimIndex)
146 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
147 for (sal_Int32 nI = 0; nI <= nMaximumScaleIndex; ++nI)
149 Reference<chart2::XAxis> xAxis = xCooSys->getAxisByDimension(nDimIndex,nI);
150 if (!xAxis.is())
151 continue;
153 //adapt title rotation only when axis swapping has changed
154 if (!bChanged)
155 continue;
157 Reference< XTitled > xTitled( xAxis, uno::UNO_QUERY );
158 if (!xTitled.is())
159 continue;
161 Reference< beans::XPropertySet > xTitleProps( xTitled->getTitleObject(), uno::UNO_QUERY );
162 if (!xTitleProps.is())
163 continue;
165 double fAngleDegree = 0.0;
166 xTitleProps->getPropertyValue("TextRotation") >>= fAngleDegree;
167 if (fAngleDegree != 0.0 &&
168 !rtl::math::approxEqual(fAngleDegree, 90.0))
169 continue;
171 double fNewAngleDegree = 0.0;
172 if( !bVertical && nDimIndex == 1 )
173 fNewAngleDegree = 90.0;
174 else if( bVertical && nDimIndex == 0 )
175 fNewAngleDegree = 90.0;
177 xTitleProps->setPropertyValue("TextRotation", uno::Any(fNewAngleDegree));
182 catch( const uno::Exception & )
184 DBG_UNHANDLED_EXCEPTION("chart2");
188 bool DiagramHelper::getVertical( const uno::Reference< chart2::XDiagram > & xDiagram,
189 bool& rbFound, bool& rbAmbiguous )
191 bool bValue = false;
192 rbFound = false;
193 rbAmbiguous = false;
195 Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
196 if (!xCnt.is())
197 return false;
199 Sequence< Reference<XCoordinateSystem> > aCooSys = xCnt->getCoordinateSystems();
201 for (sal_Int32 i = 0; i < aCooSys.getLength(); ++i)
203 Reference<beans::XPropertySet> xProp(aCooSys[i], uno::UNO_QUERY);
204 if (!xProp.is())
205 continue;
207 bool bCurrent = false;
208 if (xProp->getPropertyValue("SwapXAndYAxis") >>= bCurrent)
210 if (!rbFound)
212 bValue = bCurrent;
213 rbFound = true;
215 else if (bCurrent != bValue)
217 // ambiguous -> choose always first found
218 rbAmbiguous = true;
222 return bValue;
225 void DiagramHelper::setStackMode(
226 const Reference< XDiagram > & xDiagram,
227 StackMode eStackMode
232 bool bValueFound = false;
233 bool bIsAmbiguous = false;
234 StackMode eOldStackMode = DiagramHelper::getStackMode( xDiagram, bValueFound, bIsAmbiguous );
236 if( eStackMode == eOldStackMode && !bIsAmbiguous )
237 return;
239 StackingDirection eNewDirection = StackingDirection_NO_STACKING;
240 if( eStackMode == StackMode::YStacked || eStackMode == StackMode::YStackedPercent )
241 eNewDirection = StackingDirection_Y_STACKING;
242 else if( eStackMode == StackMode::ZStacked )
243 eNewDirection = StackingDirection_Z_STACKING;
245 uno::Any aNewDirection( eNewDirection );
247 bool bPercent = false;
248 if( eStackMode == StackMode::YStackedPercent )
249 bPercent = true;
251 //iterate through all coordinate systems
252 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
253 if( !xCooSysContainer.is() )
254 return;
255 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
256 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
258 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
259 //set correct percent stacking
260 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(1);
261 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
263 Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1,nI ));
264 if( xAxis.is())
266 chart2::ScaleData aScaleData = xAxis->getScaleData();
267 if( (aScaleData.AxisType==AxisType::PERCENT) != bPercent )
269 if( bPercent )
270 aScaleData.AxisType = AxisType::PERCENT;
271 else
272 aScaleData.AxisType = AxisType::REALNUMBER;
273 xAxis->setScaleData( aScaleData );
277 //iterate through all chart types in the current coordinate system
278 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
279 if( !xChartTypeContainer.is() )
280 continue;
281 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
282 if (!aChartTypeList.hasElements())
283 continue;
285 uno::Reference< XChartType > xChartType( aChartTypeList[0] );
287 //iterate through all series in this chart type
288 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
289 OSL_ASSERT( xDataSeriesContainer.is());
290 if( !xDataSeriesContainer.is() )
291 continue;
293 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
294 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
296 Reference< beans::XPropertySet > xProp( aSeriesList[nS], uno::UNO_QUERY );
297 if(xProp.is())
298 xProp->setPropertyValue( "StackingDirection", aNewDirection );
302 catch( const uno::Exception & )
304 DBG_UNHANDLED_EXCEPTION("chart2");
308 StackMode DiagramHelper::getStackMode( const Reference< XDiagram > & xDiagram, bool& rbFound, bool& rbAmbiguous )
310 rbFound=false;
311 rbAmbiguous=false;
313 StackMode eGlobalStackMode = StackMode::NONE;
315 //iterate through all coordinate systems
316 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
317 if( !xCooSysContainer.is() )
318 return eGlobalStackMode;
319 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
320 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
322 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
324 //iterate through all chart types in the current coordinate system
325 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
326 if( !xChartTypeContainer.is() )
327 continue;
328 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
329 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
331 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
333 StackMode eLocalStackMode = DiagramHelper::getStackModeFromChartType(
334 xChartType, rbFound, rbAmbiguous, xCooSys );
336 if( rbFound && eLocalStackMode != eGlobalStackMode && nT>0 )
338 rbAmbiguous = true;
339 return eGlobalStackMode;
342 eGlobalStackMode = eLocalStackMode;
346 return eGlobalStackMode;
349 StackMode DiagramHelper::getStackModeFromChartType(
350 const Reference< XChartType > & xChartType,
351 bool& rbFound, bool& rbAmbiguous,
352 const Reference< XCoordinateSystem > & xCorrespondingCoordinateSystem )
354 StackMode eStackMode = StackMode::NONE;
355 rbFound = false;
356 rbAmbiguous = false;
360 Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW );
361 Sequence< Reference< chart2::XDataSeries > > aSeries( xDSCnt->getDataSeries());
363 chart2::StackingDirection eCommonDirection = chart2::StackingDirection_NO_STACKING;
364 bool bDirectionInitialized = false;
366 // first series is irrelevant for stacking, start with second, unless
367 // there is only one series
368 const sal_Int32 nSeriesCount = aSeries.getLength();
369 sal_Int32 i = (nSeriesCount == 1) ? 0: 1;
370 for( ; i<nSeriesCount; ++i )
372 rbFound = true;
373 Reference< beans::XPropertySet > xProp( aSeries[i], uno::UNO_QUERY_THROW );
374 chart2::StackingDirection eCurrentDirection = eCommonDirection;
375 // property is not MAYBEVOID
376 bool bSuccess = ( xProp->getPropertyValue( "StackingDirection" ) >>= eCurrentDirection );
377 OSL_ASSERT( bSuccess );
378 if( ! bDirectionInitialized )
380 eCommonDirection = eCurrentDirection;
381 bDirectionInitialized = true;
383 else
385 if( eCommonDirection != eCurrentDirection )
387 rbAmbiguous = true;
388 break;
393 if( rbFound )
395 if( eCommonDirection == chart2::StackingDirection_Z_STACKING )
396 eStackMode = StackMode::ZStacked;
397 else if( eCommonDirection == chart2::StackingDirection_Y_STACKING )
399 eStackMode = StackMode::YStacked;
401 // percent stacking
402 if( xCorrespondingCoordinateSystem.is() )
404 if( 1 < xCorrespondingCoordinateSystem->getDimension() )
406 sal_Int32 nAxisIndex = 0;
407 if( nSeriesCount )
408 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(aSeries[0]);
410 Reference< chart2::XAxis > xAxis(
411 xCorrespondingCoordinateSystem->getAxisByDimension( 1,nAxisIndex ));
412 if( xAxis.is())
414 chart2::ScaleData aScaleData = xAxis->getScaleData();
415 if( aScaleData.AxisType==chart2::AxisType::PERCENT )
416 eStackMode = StackMode::YStackedPercent;
423 catch( const uno::Exception & )
425 DBG_UNHANDLED_EXCEPTION("chart2");
428 return eStackMode;
431 sal_Int32 DiagramHelper::getDimension( const Reference< XDiagram > & xDiagram )
433 // -1: not yet set
434 sal_Int32 nResult = -1;
438 Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY );
439 if( xCooSysCnt.is() )
441 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
442 xCooSysCnt->getCoordinateSystems());
444 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
446 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
447 if(xCooSys.is())
449 nResult = xCooSys->getDimension();
450 break;
455 catch( const uno::Exception & )
457 DBG_UNHANDLED_EXCEPTION("chart2");
460 return nResult;
463 void DiagramHelper::setDimension(
464 const Reference< XDiagram > & xDiagram,
465 sal_Int32 nNewDimensionCount )
467 if( ! xDiagram.is())
468 return;
470 if( DiagramHelper::getDimension( xDiagram ) == nNewDimensionCount )
471 return;
475 bool rbFound = false;
476 bool rbAmbiguous = true;
477 StackMode eStackMode = DiagramHelper::getStackMode( xDiagram, rbFound, rbAmbiguous );
478 bool bIsSupportingOnlyDeepStackingFor3D=false;
480 //change all coordinate systems:
481 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY_THROW );
482 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
483 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
485 Reference< XCoordinateSystem > xOldCooSys( aCooSysList[nCS], uno::UNO_QUERY );
486 Reference< XCoordinateSystem > xNewCooSys;
488 Reference< XChartTypeContainer > xChartTypeContainer( xOldCooSys, uno::UNO_QUERY );
489 if( !xChartTypeContainer.is() )
490 continue;
492 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
493 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
495 Reference< XChartType > xChartType( aChartTypeList[nT], uno::UNO_QUERY );
496 bIsSupportingOnlyDeepStackingFor3D = ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( xChartType );
497 if(!xNewCooSys.is())
499 xNewCooSys = xChartType->createCoordinateSystem( nNewDimensionCount );
500 break;
502 //@todo make sure that all following charttypes are also capable of the new dimension
503 //otherwise separate them in a different group
504 //BM: might be done in replaceCoordinateSystem()
507 // replace the old coordinate system at all places where it was used
508 DiagramHelper::replaceCoordinateSystem( xDiagram, xOldCooSys, xNewCooSys );
511 //correct stack mode if necessary
512 if( nNewDimensionCount==3 && eStackMode != StackMode::ZStacked && bIsSupportingOnlyDeepStackingFor3D )
513 DiagramHelper::setStackMode( xDiagram, StackMode::ZStacked );
514 else if( nNewDimensionCount==2 && eStackMode == StackMode::ZStacked )
515 DiagramHelper::setStackMode( xDiagram, StackMode::NONE );
517 catch( const uno::Exception & )
519 DBG_UNHANDLED_EXCEPTION("chart2");
523 void DiagramHelper::replaceCoordinateSystem(
524 const Reference< XDiagram > & xDiagram,
525 const Reference< XCoordinateSystem > & xCooSysToReplace,
526 const Reference< XCoordinateSystem > & xReplacement )
528 OSL_ASSERT( xDiagram.is());
529 if( ! xDiagram.is())
530 return;
532 // update the coordinate-system container
533 Reference< XCoordinateSystemContainer > xCont( xDiagram, uno::UNO_QUERY );
534 if( xCont.is())
538 Reference< chart2::data::XLabeledDataSequence > xCategories = DiagramHelper::getCategoriesFromDiagram( xDiagram );
540 // move chart types of xCooSysToReplace to xReplacement
541 Reference< XChartTypeContainer > xCTCntCooSys( xCooSysToReplace, uno::UNO_QUERY_THROW );
542 Reference< XChartTypeContainer > xCTCntReplacement( xReplacement, uno::UNO_QUERY_THROW );
543 xCTCntReplacement->setChartTypes( xCTCntCooSys->getChartTypes());
545 xCont->removeCoordinateSystem( xCooSysToReplace );
546 xCont->addCoordinateSystem( xReplacement );
548 if( xCategories.is() )
549 DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram );
551 catch( const uno::Exception & )
553 DBG_UNHANDLED_EXCEPTION("chart2");
558 bool DiagramHelper::isSeriesAttachedToMainAxis(
559 const uno::Reference< chart2::XDataSeries >& xDataSeries )
561 sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
562 return (nAxisIndex==0);
565 bool DiagramHelper::attachSeriesToAxis( bool bAttachToMainAxis
566 , const uno::Reference< chart2::XDataSeries >& xDataSeries
567 , const uno::Reference< chart2::XDiagram >& xDiagram
568 , const uno::Reference< uno::XComponentContext > & xContext
569 , bool bAdaptAxes )
571 bool bChanged = false;
573 //set property at axis
574 Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
576 sal_Int32 nNewAxisIndex = bAttachToMainAxis ? 0 : 1;
577 sal_Int32 nOldAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
578 uno::Reference< chart2::XAxis > xOldAxis( DiagramHelper::getAttachedAxis( xDataSeries, xDiagram ) );
580 if( nOldAxisIndex != nNewAxisIndex )
584 xProp->setPropertyValue( "AttachedAxisIndex", uno::Any( nNewAxisIndex ) );
585 bChanged = true;
587 catch( const uno::Exception & )
589 DBG_UNHANDLED_EXCEPTION("chart2");
593 if( bChanged && xDiagram.is() )
595 uno::Reference< XAxis > xAxis( AxisHelper::getAxis( 1, bAttachToMainAxis, xDiagram ) );
596 if(!xAxis.is()) //create an axis if necessary
597 xAxis = AxisHelper::createAxis( 1, bAttachToMainAxis, xDiagram, xContext );
598 if( bAdaptAxes )
600 AxisHelper::makeAxisVisible( xAxis );
601 AxisHelper::hideAxisIfNoDataIsAttached( xOldAxis, xDiagram );
605 return bChanged;
608 uno::Reference< XAxis > DiagramHelper::getAttachedAxis(
609 const uno::Reference< XDataSeries >& xSeries,
610 const uno::Reference< XDiagram >& xDiagram )
612 return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), xDiagram );
615 uno::Reference< XChartType > DiagramHelper::getChartTypeOfSeries(
616 const uno::Reference< chart2::XDiagram >& xDiagram
617 , const uno::Reference< XDataSeries >& xGivenDataSeries )
619 if( !xGivenDataSeries.is() )
620 return nullptr;
621 if(!xDiagram.is())
622 return nullptr;
624 //iterate through the model to find the given xSeries
625 //the found parent indicates the charttype
627 //iterate through all coordinate systems
628 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
629 if( !xCooSysContainer.is())
630 return nullptr;
632 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
633 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
635 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
637 //iterate through all chart types in the current coordinate system
638 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
639 OSL_ASSERT( xChartTypeContainer.is());
640 if( !xChartTypeContainer.is() )
641 continue;
642 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
643 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
645 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
647 //iterate through all series in this chart type
648 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
649 OSL_ASSERT( xDataSeriesContainer.is());
650 if( !xDataSeriesContainer.is() )
651 continue;
653 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
654 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
656 if( xGivenDataSeries==aSeriesList[nS] )
657 return xChartType;
661 return nullptr;
664 std::vector< Reference< XDataSeries > >
665 DiagramHelper::getDataSeriesFromDiagram(
666 const Reference< XDiagram > & xDiagram )
668 std::vector< Reference< XDataSeries > > aResult;
672 Reference< XCoordinateSystemContainer > xCooSysCnt(
673 xDiagram, uno::UNO_QUERY_THROW );
674 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
675 xCooSysCnt->getCoordinateSystems());
676 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
678 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
679 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
680 for( sal_Int32 j=0; j<aChartTypeSeq.getLength(); ++j )
682 Reference< XDataSeriesContainer > xDSCnt( aChartTypeSeq[j], uno::UNO_QUERY_THROW );
683 Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() );
684 std::copy( aSeriesSeq.begin(), aSeriesSeq.end(),
685 std::back_inserter( aResult ));
689 catch( const uno::Exception & )
691 DBG_UNHANDLED_EXCEPTION("chart2");
694 return aResult;
697 Sequence< Sequence< Reference< XDataSeries > > >
698 DiagramHelper::getDataSeriesGroups( const Reference< XDiagram > & xDiagram )
700 vector< Sequence< Reference< XDataSeries > > > aResult;
702 //iterate through all coordinate systems
703 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
704 if( xCooSysContainer.is() )
706 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
707 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
709 //iterate through all chart types in the current coordinate system
710 Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
711 if( !xChartTypeContainer.is() )
712 continue;
713 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
714 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
716 Reference< XDataSeriesContainer > xDataSeriesContainer( aChartTypeList[nT], uno::UNO_QUERY );
717 if( !xDataSeriesContainer.is() )
718 continue;
719 aResult.push_back( xDataSeriesContainer->getDataSeries() );
723 return comphelper::containerToSequence( aResult );
726 Reference< XChartType >
727 DiagramHelper::getChartTypeByIndex( const Reference< XDiagram >& xDiagram, sal_Int32 nIndex )
729 Reference< XChartType > xChartType;
731 //iterate through all coordinate systems
732 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
733 if( ! xCooSysContainer.is())
734 return xChartType;
736 Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
737 sal_Int32 nTypesSoFar = 0;
738 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
740 Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
741 if( !xChartTypeContainer.is() )
742 continue;
743 Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
744 if( nIndex >= 0 && nIndex < (nTypesSoFar + aChartTypeList.getLength()) )
746 xChartType.set( aChartTypeList[nIndex - nTypesSoFar] );
747 break;
749 nTypesSoFar += aChartTypeList.getLength();
752 return xChartType;
755 namespace
758 std::vector< Reference< XAxis > > lcl_getAxisHoldingCategoriesFromDiagram(
759 const Reference< XDiagram > & xDiagram )
761 std::vector< Reference< XAxis > > aRet;
763 // return first x-axis as fall-back
764 Reference< XAxis > xFallBack;
767 Reference< XCoordinateSystemContainer > xCooSysCnt(
768 xDiagram, uno::UNO_QUERY_THROW );
769 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
770 xCooSysCnt->getCoordinateSystems());
771 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
773 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
774 OSL_ASSERT( xCooSys.is());
775 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
777 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
778 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
780 Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
781 OSL_ASSERT( xAxis.is());
782 if( xAxis.is())
784 ScaleData aScaleData = xAxis->getScaleData();
785 if( aScaleData.Categories.is() || (aScaleData.AxisType == AxisType::CATEGORY) )
787 aRet.push_back(xAxis);
789 if( (nN == 0) && !xFallBack.is())
790 xFallBack.set( xAxis );
796 catch( const uno::Exception & )
798 DBG_UNHANDLED_EXCEPTION("chart2" );
801 if( aRet.empty() )
802 aRet.push_back(xFallBack);
804 return aRet;
807 } // anonymous namespace
809 bool DiagramHelper::isCategoryDiagram(
810 const Reference< XDiagram >& xDiagram )
814 Reference< XCoordinateSystemContainer > xCooSysCnt(
815 xDiagram, uno::UNO_QUERY_THROW );
816 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
817 xCooSysCnt->getCoordinateSystems());
818 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
820 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
821 OSL_ASSERT( xCooSys.is());
822 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
824 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
825 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
827 Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
828 OSL_ASSERT( xAxis.is());
829 if( xAxis.is())
831 ScaleData aScaleData = xAxis->getScaleData();
832 if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
833 return true;
839 catch( const uno::Exception & )
841 DBG_UNHANDLED_EXCEPTION("chart2");
844 return false;
847 void DiagramHelper::setCategoriesToDiagram(
848 const Reference< chart2::data::XLabeledDataSequence >& xCategories,
849 const Reference< XDiagram >& xDiagram,
850 bool bSetAxisType /* = false */,
851 bool bCategoryAxis /* = true */ )
853 std::vector< Reference< chart2::XAxis > > aCatAxes(
854 lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
856 for (const Reference< chart2::XAxis >& xCatAxis : aCatAxes)
858 if( xCatAxis.is())
860 ScaleData aScaleData( xCatAxis->getScaleData());
861 aScaleData.Categories = xCategories;
862 if( bSetAxisType )
864 if( bCategoryAxis )
865 aScaleData.AxisType = AxisType::CATEGORY;
866 else if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
867 aScaleData.AxisType = AxisType::REALNUMBER;
869 xCatAxis->setScaleData( aScaleData );
874 Reference< data::XLabeledDataSequence >
875 DiagramHelper::getCategoriesFromDiagram(
876 const Reference< XDiagram > & xDiagram )
878 Reference< data::XLabeledDataSequence > xResult;
882 std::vector< Reference< chart2::XAxis > > aCatAxes(
883 lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
884 //search for first categories
885 if (!aCatAxes.empty())
887 Reference< chart2::XAxis > xCatAxis(aCatAxes[0]);
888 if( xCatAxis.is())
890 ScaleData aScaleData( xCatAxis->getScaleData());
891 if( aScaleData.Categories.is() )
893 xResult.set( aScaleData.Categories );
894 uno::Reference<beans::XPropertySet> xProp(aScaleData.Categories->getValues(), uno::UNO_QUERY );
895 if( xProp.is() )
899 xProp->setPropertyValue( "Role", uno::Any( OUString("categories") ) );
901 catch( const uno::Exception & )
903 DBG_UNHANDLED_EXCEPTION("chart2");
910 catch( const uno::Exception & )
912 DBG_UNHANDLED_EXCEPTION("chart2");
915 return xResult;
918 static void lcl_generateAutomaticCategoriesFromChartType(
919 Sequence< OUString >& rRet,
920 const Reference< XChartType >& xChartType )
922 if(!xChartType.is())
923 return;
924 OUString aMainSeq( xChartType->getRoleOfSequenceForSeriesLabel() );
925 Reference< XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY );
926 if( xSeriesCnt.is() )
928 Sequence< Reference< XDataSeries > > aSeriesSeq( xSeriesCnt->getDataSeries() );
929 for( sal_Int32 nS = 0; nS < aSeriesSeq.getLength(); nS++ )
931 Reference< data::XDataSource > xDataSource( aSeriesSeq[nS], uno::UNO_QUERY );
932 if( !xDataSource.is() )
933 continue;
934 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
935 ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aMainSeq ));
936 if( !xLabeledSeq.is() )
937 continue;
938 Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() );
939 if( !xValueSeq.is() )
940 continue;
941 rRet = xValueSeq->generateLabel( chart2::data::LabelOrigin_LONG_SIDE );
942 if( rRet.hasElements() )
943 return;
948 Sequence< OUString > DiagramHelper::generateAutomaticCategoriesFromCooSys( const Reference< XCoordinateSystem > & xCooSys )
950 Sequence< OUString > aRet;
952 Reference< XChartTypeContainer > xTypeCntr( xCooSys, uno::UNO_QUERY );
953 if( xTypeCntr.is() )
955 Sequence< Reference< XChartType > > aChartTypes( xTypeCntr->getChartTypes() );
956 for( sal_Int32 nN=0; nN<aChartTypes.getLength(); nN++ )
958 lcl_generateAutomaticCategoriesFromChartType( aRet, aChartTypes[nN] );
959 if( aRet.hasElements() )
960 return aRet;
963 return aRet;
966 Sequence< OUString > DiagramHelper::getExplicitSimpleCategories(
967 ChartModel& rModel )
969 uno::Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( rModel ) );
970 ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel );
971 return aExplicitCategoriesProvider.getSimpleCategories();
974 namespace
976 void lcl_switchToDateCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
978 if( !xAxis.is() )
979 return;
980 if( !xChartDoc.is() )
981 return;
983 ScaleData aScale( xAxis->getScaleData() );
984 if( xChartDoc->hasInternalDataProvider() )
986 //remove all content the is not of type double and remove multiple level
987 Reference< XAnyDescriptionAccess > xDataAccess( xChartDoc->getDataProvider(), uno::UNO_QUERY );
988 if( xDataAccess.is() )
990 Sequence< Sequence< Any > > aAnyCategories( xDataAccess->getAnyRowDescriptions() );
991 double fTest = 0.0;
992 double fNan = 0.0;
993 ::rtl::math::setNan( & fNan );
994 sal_Int32 nN = aAnyCategories.getLength();
995 for( ; nN--; )
997 Sequence< Any >& rCat = aAnyCategories[nN];
998 if( rCat.getLength() > 1 )
999 rCat.realloc(1);
1000 if( rCat.getLength() == 1 )
1002 Any& rAny = rCat[0];
1003 if( !(rAny>>=fTest) )
1005 rAny <<= fNan;
1009 xDataAccess->setAnyRowDescriptions( aAnyCategories );
1011 //check the numberformat at the axis
1012 Reference< beans::XPropertySet > xAxisProps( xAxis, uno::UNO_QUERY );
1013 Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartDoc, uno::UNO_QUERY );
1014 if( xAxisProps.is() && xNumberFormatsSupplier.is() )
1016 sal_Int32 nNumberFormat = -1;
1017 xAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormat;
1019 Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1020 if( xNumberFormats.is() )
1022 Reference< beans::XPropertySet > xKeyProps;
1025 xKeyProps = xNumberFormats->getByKey( nNumberFormat );
1027 catch( const uno::Exception & )
1029 DBG_UNHANDLED_EXCEPTION("chart2");
1031 sal_Int32 nType = util::NumberFormat::UNDEFINED;
1032 if( xKeyProps.is() )
1033 xKeyProps->getPropertyValue( "Type" ) >>= nType;
1034 if( !( nType & util::NumberFormat::DATE ) )
1036 //set a date format to the axis
1037 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
1038 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE, rLocaleDataWrapper.getLanguageTag().getLocale(), true/*bCreate*/ );
1039 if( aKeySeq.hasElements() )
1041 xAxisProps->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any(aKeySeq[0]));
1047 if( aScale.AxisType != chart2::AxisType::DATE )
1048 AxisHelper::removeExplicitScaling( aScale );
1049 aScale.AxisType = chart2::AxisType::DATE;
1050 xAxis->setScaleData( aScale );
1053 void lcl_switchToTextCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
1055 if( !xAxis.is() )
1056 return;
1057 if( !xChartDoc.is() )
1058 return;
1059 ScaleData aScale( xAxis->getScaleData() );
1060 if( aScale.AxisType != chart2::AxisType::CATEGORY )
1061 AxisHelper::removeExplicitScaling( aScale );
1062 //todo migrate dates to text?
1063 aScale.AxisType = chart2::AxisType::CATEGORY;
1064 aScale.AutoDateAxis = false;
1065 xAxis->setScaleData( aScale );
1070 void DiagramHelper::switchToDateCategories( const Reference< XChartDocument >& xChartDoc )
1072 if(xChartDoc.is())
1074 ControllerLockGuardUNO aCtrlLockGuard( xChartDoc );
1076 Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartDoc ) );
1077 if( xCooSys.is() )
1079 Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
1080 lcl_switchToDateCategories( xChartDoc, xAxis );
1085 void DiagramHelper::switchToTextCategories( const Reference< XChartDocument >& xChartDoc )
1087 if(xChartDoc.is())
1089 ControllerLockGuardUNO aCtrlLockGuard( xChartDoc );
1091 Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartDoc ) );
1092 if( xCooSys.is() )
1094 Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
1095 lcl_switchToTextCategories( xChartDoc, xAxis );
1100 bool DiagramHelper::isSupportingDateAxis( const Reference< chart2::XDiagram >& xDiagram )
1102 return ::chart::ChartTypeHelper::isSupportingDateAxis(
1103 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ), 0 );
1106 bool DiagramHelper::isDateNumberFormat( sal_Int32 nNumberFormat, const Reference< util::XNumberFormats >& xNumberFormats )
1108 bool bIsDate = false;
1109 if( !xNumberFormats.is() )
1110 return bIsDate;
1112 Reference< beans::XPropertySet > xKeyProps = xNumberFormats->getByKey( nNumberFormat );
1113 if( xKeyProps.is() )
1115 sal_Int32 nType = util::NumberFormat::UNDEFINED;
1116 xKeyProps->getPropertyValue( "Type" ) >>= nType;
1117 bIsDate = nType & util::NumberFormat::DATE;
1119 return bIsDate;
1122 sal_Int32 DiagramHelper::getDateNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1124 sal_Int32 nRet=-1;
1126 //try to get a date format with full year display
1127 const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
1128 NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1129 SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1130 if( pNumFormatter )
1132 nRet = pNumFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, rLanguageTag.getLanguageType() );
1134 else
1136 Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1137 if( xNumberFormats.is() )
1139 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE,
1140 rLanguageTag.getLocale(), true/*bCreate */);
1141 if( aKeySeq.hasElements() )
1143 nRet = aKeySeq[0];
1147 return nRet;
1150 sal_Int32 DiagramHelper::getDateTimeInputNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier, double fNumber )
1152 sal_Int32 nRet = 0;
1154 // Get the most detailed date/time format according to fNumber.
1155 NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1156 SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1157 if (!pNumFormatter)
1158 SAL_WARN("chart2", "DiagramHelper::getDateTimeInputNumberFormat - no SvNumberFormatter");
1159 else
1161 SvNumFormatType nType;
1162 // Obtain best matching date, time or datetime format.
1163 nRet = pNumFormatter->GuessDateTimeFormat( nType, fNumber, LANGUAGE_SYSTEM);
1164 // Obtain the corresponding edit format.
1165 nRet = pNumFormatter->GetEditFormat( fNumber, nRet, nType, LANGUAGE_SYSTEM, nullptr);
1167 return nRet;
1170 sal_Int32 DiagramHelper::getPercentNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1172 sal_Int32 nRet=-1;
1173 const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
1174 NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1175 SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1176 if( pNumFormatter )
1178 nRet = pNumFormatter->GetFormatIndex( NF_PERCENT_INT, rLanguageTag.getLanguageType() );
1180 else
1182 Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1183 if( xNumberFormats.is() )
1185 Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::PERCENT,
1186 rLanguageTag.getLocale(), true/*bCreate*/ );
1187 if( aKeySeq.hasElements() )
1189 // This *assumes* the sequence is sorted as in
1190 // NfIndexTableOffset and the first format is the integer 0%
1191 // format by chance... which usually is the case, but... anyway,
1192 // we usually also have a number formatter so don't reach here.
1193 nRet = aKeySeq[0];
1197 return nRet;
1200 Sequence< Reference< XChartType > >
1201 DiagramHelper::getChartTypesFromDiagram(
1202 const Reference< XDiagram > & xDiagram )
1204 std::vector< Reference< XChartType > > aResult;
1206 if(xDiagram.is())
1210 Reference< XCoordinateSystemContainer > xCooSysCnt(
1211 xDiagram, uno::UNO_QUERY_THROW );
1212 Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
1213 xCooSysCnt->getCoordinateSystems());
1214 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
1216 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
1217 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
1218 std::copy( aChartTypeSeq.begin(), aChartTypeSeq.end(),
1219 std::back_inserter( aResult ));
1222 catch( const uno::Exception & )
1224 DBG_UNHANDLED_EXCEPTION("chart2");
1228 return comphelper::containerToSequence( aResult );
1231 bool DiagramHelper::areChartTypesCompatible( const Reference< ::chart2::XChartType >& xFirstType,
1232 const Reference< ::chart2::XChartType >& xSecondType )
1234 if( !xFirstType.is() || !xSecondType.is() )
1235 return false;
1237 auto aFirstRoles( comphelper::sequenceToContainer<std::vector< OUString >>( xFirstType->getSupportedMandatoryRoles() ) );
1238 auto aSecondRoles( comphelper::sequenceToContainer<std::vector< OUString >>( xSecondType->getSupportedMandatoryRoles() ) );
1239 std::sort( aFirstRoles.begin(), aFirstRoles.end() );
1240 std::sort( aSecondRoles.begin(), aSecondRoles.end() );
1241 return ( aFirstRoles == aSecondRoles );
1244 namespace
1247 * This method implements the logic of checking if a series can be moved
1248 * forward/backward. Depending on the "bDoMove" parameter the series will
1249 * be moved (bDoMove = true) or the function just will test if the
1250 * series can be moved without doing the move (bDoMove = false).
1252 * @param xDiagram
1253 * Reference to the diagram that contains the series.
1255 * @param xGivenDataSeries
1256 * Reference to the series that should moved or tested for moving.
1258 * @param bForward
1259 * Direction in which the series should be moved or tested for moving.
1261 * @param bDoMove
1262 * Should this function really move the series (true) or just test if it is
1263 * possible (false).
1266 * @returns
1267 * in case of bDoMove == true
1268 * - True : if the move was done
1269 * - False : the move failed
1270 * in case of bDoMove == false
1271 * - True : the series can be moved
1272 * - False : the series can not be moved
1276 bool lcl_moveSeriesOrCheckIfMoveIsAllowed(
1277 const Reference< XDiagram >& xDiagram,
1278 const Reference< XDataSeries >& xGivenDataSeries,
1279 bool bForward,
1280 bool bDoMove )
1282 bool bMovedOrMoveAllowed = false;
1286 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
1288 if( xGivenDataSeries.is() && xCooSysContainer.is() )
1290 //find position of series.
1291 bool bFound = false;
1292 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
1294 for( sal_Int32 nCS = 0; !bFound && nCS < aCooSysList.getLength(); ++nCS )
1296 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
1298 //iterate through all chart types in the current coordinate system
1299 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
1300 OSL_ASSERT( xChartTypeContainer.is());
1301 if( !xChartTypeContainer.is() )
1302 continue;
1303 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
1304 uno::Reference< XChartType > xFormerChartType;
1306 for( sal_Int32 nT = 0; !bFound && nT < aChartTypeList.getLength(); ++nT )
1308 uno::Reference< XChartType > xCurrentChartType( aChartTypeList[nT] );
1310 //iterate through all series in this chart type
1311 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xCurrentChartType, uno::UNO_QUERY );
1312 OSL_ASSERT( xDataSeriesContainer.is());
1313 if( !xDataSeriesContainer.is() )
1314 continue;
1316 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
1318 for( sal_Int32 nS = 0; !bFound && nS < aSeriesList.getLength(); ++nS )
1321 // We found the series we are interested in!
1322 if( xGivenDataSeries==aSeriesList[nS] )
1324 sal_Int32 nOldSeriesIndex = nS;
1325 bFound = true;
1329 sal_Int32 nNewSeriesIndex = nS;
1331 if( bForward )
1332 nNewSeriesIndex--;
1333 else
1334 nNewSeriesIndex++;
1336 if( nNewSeriesIndex >= 0 && nNewSeriesIndex < aSeriesList.getLength() )
1338 //move series in the same charttype
1339 bMovedOrMoveAllowed = true;
1340 if( bDoMove )
1342 aSeriesList[ nOldSeriesIndex ] = aSeriesList[ nNewSeriesIndex ];
1343 aSeriesList[ nNewSeriesIndex ] = xGivenDataSeries;
1344 xDataSeriesContainer->setDataSeries( aSeriesList );
1347 else if( nNewSeriesIndex<0 )
1349 //exchange series with former charttype
1350 if( xFormerChartType.is() && DiagramHelper::areChartTypesCompatible( xFormerChartType, xCurrentChartType ) )
1352 bMovedOrMoveAllowed = true;
1353 if( bDoMove )
1355 uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xFormerChartType, uno::UNO_QUERY );
1356 if( xOtherDataSeriesContainer.is() )
1358 uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
1359 sal_Int32 nOtherSeriesIndex = aOtherSeriesList.getLength()-1;
1360 if( nOtherSeriesIndex >= 0 && nOtherSeriesIndex < aOtherSeriesList.getLength() )
1362 uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
1363 aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
1364 xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
1366 aSeriesList[nOldSeriesIndex]=xExchangeSeries;
1367 xDataSeriesContainer->setDataSeries(aSeriesList);
1373 else if( nT+1 < aChartTypeList.getLength() )
1375 //exchange series with next charttype
1376 uno::Reference< XChartType > xOtherChartType( aChartTypeList[nT+1] );
1377 if( xOtherChartType.is() && DiagramHelper::areChartTypesCompatible( xOtherChartType, xCurrentChartType ) )
1379 bMovedOrMoveAllowed = true;
1380 if( bDoMove )
1382 uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xOtherChartType, uno::UNO_QUERY );
1383 if( xOtherDataSeriesContainer.is() )
1385 uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
1386 if( aOtherSeriesList.hasElements() )
1388 uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[0] );
1389 aOtherSeriesList[0] = xGivenDataSeries;
1390 xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
1392 aSeriesList[nOldSeriesIndex]=xExchangeSeries;
1393 xDataSeriesContainer->setDataSeries(aSeriesList);
1400 catch( const util::CloseVetoException& )
1403 catch( const uno::RuntimeException& )
1408 xFormerChartType = xCurrentChartType;
1413 catch( const util::CloseVetoException& )
1416 catch( const uno::RuntimeException& )
1419 return bMovedOrMoveAllowed;
1421 } // anonymous namespace
1423 bool DiagramHelper::isSeriesMoveable(
1424 const Reference< XDiagram >& xDiagram,
1425 const Reference< XDataSeries >& xGivenDataSeries,
1426 bool bForward )
1428 const bool bDoMove = false;
1430 bool bIsMoveable = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1431 xDiagram, xGivenDataSeries, bForward, bDoMove );
1433 return bIsMoveable;
1436 bool DiagramHelper::moveSeries( const Reference< XDiagram >& xDiagram, const Reference< XDataSeries >& xGivenDataSeries, bool bForward )
1438 const bool bDoMove = true;
1440 bool bMoved = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1441 xDiagram, xGivenDataSeries, bForward, bDoMove );
1443 return bMoved;
1446 bool DiagramHelper::isSupportingFloorAndWall( const Reference<
1447 chart2::XDiagram >& xDiagram )
1449 //pies and donuts currently do not support this because of wrong files from older versions
1450 //todo: allow this in future again, if fileversion are available for ole objects (metastream)
1451 //thus the wrong bottom can be removed on import
1453 Sequence< Reference< chart2::XChartType > > aTypes(
1454 ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) );
1455 for( sal_Int32 nN = 0; nN < aTypes.getLength(); nN++ )
1457 Reference< chart2::XChartType > xType( aTypes[nN] );
1458 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
1459 return false;
1460 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
1461 return false;
1462 if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
1463 return false;
1465 return true;
1468 bool DiagramHelper::isPieOrDonutChart( const css::uno::Reference< css::chart2::XDiagram >& xDiagram )
1470 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex(
1471 xDiagram, 0 ) );
1473 if( xChartType .is() )
1475 OUString aChartType = xChartType->getChartType();
1476 if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE )
1477 return true;
1479 return false;
1482 sal_Int32 DiagramHelper::getGeometry3D(
1483 const uno::Reference< chart2::XDiagram > & xDiagram,
1484 bool& rbFound, bool& rbAmbiguous )
1486 sal_Int32 nCommonGeom( DataPointGeometry3D::CUBOID );
1487 rbFound = false;
1488 rbAmbiguous = false;
1490 std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
1491 DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
1493 if( aSeriesVec.empty())
1494 rbAmbiguous = true;
1496 for (auto const& series : aSeriesVec)
1500 sal_Int32 nGeom = 0;
1501 Reference< beans::XPropertySet > xProp(series, uno::UNO_QUERY_THROW);
1502 if( xProp->getPropertyValue( "Geometry3D") >>= nGeom )
1504 if( ! rbFound )
1506 // first series
1507 nCommonGeom = nGeom;
1508 rbFound = true;
1510 // further series: compare for uniqueness
1511 else if( nCommonGeom != nGeom )
1513 rbAmbiguous = true;
1514 break;
1518 catch( const uno::Exception & )
1520 DBG_UNHANDLED_EXCEPTION("chart2");
1524 return nCommonGeom;
1527 void DiagramHelper::setGeometry3D(
1528 const Reference< chart2::XDiagram > & xDiagram,
1529 sal_Int32 nNewGeometry )
1531 std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
1532 DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
1534 for (auto const& series : aSeriesVec)
1536 DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(
1537 series, "Geometry3D", uno::Any( nNewGeometry ));
1541 sal_Int32 DiagramHelper::getCorrectedMissingValueTreatment(
1542 const Reference< chart2::XDiagram > & xDiagram,
1543 const Reference< chart2::XChartType >& xChartType )
1545 sal_Int32 nResult = css::chart::MissingValueTreatment::LEAVE_GAP;
1546 uno::Sequence < sal_Int32 > aAvailableMissingValueTreatments(
1547 ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) );
1549 uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
1550 if( xDiaProp.is() && (xDiaProp->getPropertyValue( "MissingValueTreatment" ) >>= nResult) )
1552 //ensure that the set value is supported by this charttype
1553 for( sal_Int32 nN = 0; nN < aAvailableMissingValueTreatments.getLength(); nN++ )
1554 if( aAvailableMissingValueTreatments[nN] == nResult )
1555 return nResult; //ok
1558 //otherwise use the first supported one
1559 if( aAvailableMissingValueTreatments.hasElements() )
1561 nResult = aAvailableMissingValueTreatments[0];
1562 return nResult;
1565 return nResult;
1568 DiagramPositioningMode DiagramHelper::getDiagramPositioningMode( const uno::Reference<
1569 chart2::XDiagram > & xDiagram )
1571 DiagramPositioningMode eMode = DiagramPositioningMode_AUTO;
1572 uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY );
1573 if( xDiaProps.is() )
1575 RelativePosition aRelPos;
1576 RelativeSize aRelSize;
1577 if( (xDiaProps->getPropertyValue("RelativePosition") >>= aRelPos ) &&
1578 (xDiaProps->getPropertyValue("RelativeSize") >>= aRelSize ) )
1580 bool bPosSizeExcludeAxes=false;
1581 xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxes;
1582 if( bPosSizeExcludeAxes )
1583 eMode = DiagramPositioningMode_EXCLUDING;
1584 else
1585 eMode = DiagramPositioningMode_INCLUDING;
1588 return eMode;
1591 static void lcl_ensureRange0to1( double& rValue )
1593 if(rValue<0.0)
1594 rValue=0.0;
1595 if(rValue>1.0)
1596 rValue=1.0;
1599 bool DiagramHelper::setDiagramPositioning( const uno::Reference< frame::XModel >& xChartModel,
1600 const awt::Rectangle& rPosRect /*100th mm*/ )
1602 ControllerLockGuardUNO aCtrlLockGuard( xChartModel );
1604 bool bChanged = false;
1605 awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
1606 uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
1607 if( !xDiaProps.is() )
1608 return bChanged;
1610 RelativePosition aOldPos;
1611 RelativeSize aOldSize;
1612 xDiaProps->getPropertyValue("RelativePosition" ) >>= aOldPos;
1613 xDiaProps->getPropertyValue("RelativeSize" ) >>= aOldSize;
1615 RelativePosition aNewPos;
1616 aNewPos.Anchor = drawing::Alignment_TOP_LEFT;
1617 aNewPos.Primary = double(rPosRect.X)/double(aPageSize.Width);
1618 aNewPos.Secondary = double(rPosRect.Y)/double(aPageSize.Height);
1620 chart2::RelativeSize aNewSize;
1621 aNewSize.Primary = double(rPosRect.Width)/double(aPageSize.Width);
1622 aNewSize.Secondary = double(rPosRect.Height)/double(aPageSize.Height);
1624 lcl_ensureRange0to1( aNewPos.Primary );
1625 lcl_ensureRange0to1( aNewPos.Secondary );
1626 lcl_ensureRange0to1( aNewSize.Primary );
1627 lcl_ensureRange0to1( aNewSize.Secondary );
1628 if( (aNewPos.Primary + aNewSize.Primary) > 1.0 )
1629 aNewPos.Primary = 1.0 - aNewSize.Primary;
1630 if( (aNewPos.Secondary + aNewSize.Secondary) > 1.0 )
1631 aNewPos.Secondary = 1.0 - aNewSize.Secondary;
1633 xDiaProps->setPropertyValue( "RelativePosition", uno::Any(aNewPos) );
1634 xDiaProps->setPropertyValue( "RelativeSize", uno::Any(aNewSize) );
1636 bChanged = (aOldPos.Anchor!=aNewPos.Anchor) ||
1637 (aOldPos.Primary!=aNewPos.Primary) ||
1638 (aOldPos.Secondary!=aNewPos.Secondary) ||
1639 (aOldSize.Primary!=aNewSize.Primary) ||
1640 (aOldSize.Secondary!=aNewSize.Secondary);
1641 return bChanged;
1644 awt::Rectangle DiagramHelper::getDiagramRectangleFromModel( const uno::Reference< frame::XModel >& xChartModel )
1646 awt::Rectangle aRet(-1,-1,-1,-1);
1648 uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
1649 if( !xDiaProps.is() )
1650 return aRet;
1652 awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
1654 RelativePosition aRelPos;
1655 RelativeSize aRelSize;
1656 xDiaProps->getPropertyValue("RelativePosition" ) >>= aRelPos;
1657 xDiaProps->getPropertyValue("RelativeSize" ) >>= aRelSize;
1659 awt::Size aAbsSize(
1660 static_cast< sal_Int32 >( aRelSize.Primary * aPageSize.Width ),
1661 static_cast< sal_Int32 >( aRelSize.Secondary * aPageSize.Height ));
1663 awt::Point aAbsPos(
1664 static_cast< sal_Int32 >( aRelPos.Primary * aPageSize.Width ),
1665 static_cast< sal_Int32 >( aRelPos.Secondary * aPageSize.Height ));
1667 awt::Point aAbsPosLeftTop = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( aAbsPos, aAbsSize, aRelPos.Anchor );
1669 aRet = awt::Rectangle(aAbsPosLeftTop.X, aAbsPosLeftTop.Y, aAbsSize.Width, aAbsSize.Height );
1671 return aRet;
1674 bool DiagramHelper::switchDiagramPositioningToExcludingPositioning(
1675 ChartModel& rModel, bool bResetModifiedState, bool bConvertAlsoFromAutoPositioning )
1677 //return true if something was changed
1678 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
1679 if( nCurrentODFVersion > SvtSaveOptions::ODFVER_012 )
1681 uno::Reference< css::chart::XDiagramPositioning > xDiagramPositioning( rModel.getFirstDiagram(), uno::UNO_QUERY );
1682 if( xDiagramPositioning.is() && ( bConvertAlsoFromAutoPositioning || !xDiagramPositioning->isAutomaticDiagramPositioning() )
1683 && !xDiagramPositioning->isExcludingDiagramPositioning() )
1685 ControllerLockGuard aCtrlLockGuard( rModel );
1686 bool bModelWasModified = rModel.isModified();
1687 xDiagramPositioning->setDiagramPositionExcludingAxes( xDiagramPositioning->calculateDiagramPositionExcludingAxes() );
1688 if(bResetModifiedState && !bModelWasModified )
1689 rModel.setModified(false);
1690 return true;
1693 return false;
1696 } // namespace chart
1698 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */