xref: /core/chart2/source/tools/DiagramHelper.cxx (revision 21b22421)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <DiagramHelper.hxx>
21 #include <DataSeriesHelper.hxx>
22 #include <AxisHelper.hxx>
23 #include <ContainerHelper.hxx>
24 #include <ChartTypeHelper.hxx>
25 #include <ChartModel.hxx>
26 #include <ChartModelHelper.hxx>
27 #include <ExplicitCategoriesProvider.hxx>
28 #include <servicenames_charttypes.hxx>
29 #include <RelativePositionHelper.hxx>
30 #include <ControllerLockGuard.hxx>
31 #include <NumberFormatterWrapper.hxx>
32 #include <unonames.hxx>
33 
34 #include <com/sun/star/chart/MissingValueTreatment.hpp>
35 #include <com/sun/star/chart/XDiagramPositioning.hpp>
36 #include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
37 #include <com/sun/star/chart2/XTitled.hpp>
38 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
39 #include <com/sun/star/chart2/XChartTypeTemplate.hpp>
40 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
41 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
42 #include <com/sun/star/chart2/AxisType.hpp>
43 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
44 #include <com/sun/star/chart2/RelativePosition.hpp>
45 #include <com/sun/star/chart2/RelativeSize.hpp>
46 #include <com/sun/star/chart2/StackingDirection.hpp>
47 
48 #include <com/sun/star/util/CloseVetoException.hpp>
49 #include <com/sun/star/util/NumberFormat.hpp>
50 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
51 
52 #include <unotools/saveopt.hxx>
53 #include <rtl/math.hxx>
54 #include <svl/zforlist.hxx>
55 #include <vcl/svapp.hxx>
56 #include <vcl/settings.hxx>
57 #include <comphelper/sequence.hxx>
58 #include <tools/diagnose_ex.h>
59 #include <sal/log.hxx>
60 
61 using namespace ::com::sun::star;
62 using namespace ::com::sun::star::chart2;
63 using namespace ::std;
64 
65 using ::com::sun::star::uno::Reference;
66 using ::com::sun::star::uno::Sequence;
67 using ::com::sun::star::uno::Any;
68 using ::com::sun::star::chart2::XAnyDescriptionAccess;
69 
70 namespace chart
71 {
72 
73 DiagramHelper::tTemplateWithServiceName
74     DiagramHelper::getTemplateForDiagram(
75         const Reference< XDiagram > & xDiagram,
76         const Reference< lang::XMultiServiceFactory > & xChartTypeManager )
77 {
78     DiagramHelper::tTemplateWithServiceName aResult;
79 
80     if( ! (xChartTypeManager.is() && xDiagram.is()))
81         return aResult;
82 
83     Sequence< OUString > aServiceNames( xChartTypeManager->getAvailableServiceNames());
84     const sal_Int32 nLength = aServiceNames.getLength();
85 
86     bool bTemplateFound = false;
87 
88     for( sal_Int32 i = 0; ! bTemplateFound && i < nLength; ++i )
89     {
90         try
91         {
92             Reference< XChartTypeTemplate > xTempl(
93                 xChartTypeManager->createInstance( aServiceNames[ i ] ), uno::UNO_QUERY_THROW );
94 
95             if (xTempl.is() && xTempl->matchesTemplate(xDiagram, true))
96             {
97                 aResult.first = xTempl;
98                 aResult.second = aServiceNames[ i ];
99                 bTemplateFound = true;
100             }
101         }
102         catch( const uno::Exception & )
103         {
104             DBG_UNHANDLED_EXCEPTION("chart2");
105         }
106     }
107 
108     return aResult;
109 }
110 
111 void DiagramHelper::setVertical(
112     const Reference< XDiagram > & xDiagram,
113     bool bVertical /* = true */ )
114 {
115     try
116     {
117         Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
118         if (!xCnt.is())
119             return;
120 
121         Sequence< Reference<XCoordinateSystem> > aCooSys = xCnt->getCoordinateSystems();
122         uno::Any aValue;
123         aValue <<= bVertical;
124         for( sal_Int32 i=0; i<aCooSys.getLength(); ++i )
125         {
126             uno::Reference< XCoordinateSystem > xCooSys( aCooSys[i] );
127             Reference< beans::XPropertySet > xProp( xCooSys, uno::UNO_QUERY );
128             bool bChanged = false;
129             if (xProp.is())
130             {
131                 bool bOldSwap = false;
132                 if( !(xProp->getPropertyValue("SwapXAndYAxis") >>= bOldSwap)
133                     || bVertical != bOldSwap )
134                     bChanged = true;
135 
136                 if( bChanged )
137                     xProp->setPropertyValue("SwapXAndYAxis", aValue);
138             }
139 
140             if (!xCooSys.is())
141                 continue;
142 
143             const sal_Int32 nDimensionCount = xCooSys->getDimension();
144             sal_Int32 nDimIndex = 0;
145             for (nDimIndex=0; nDimIndex < nDimensionCount; ++nDimIndex)
146             {
147                 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
148                 for (sal_Int32 nI = 0; nI <= nMaximumScaleIndex; ++nI)
149                 {
150                     Reference<chart2::XAxis> xAxis = xCooSys->getAxisByDimension(nDimIndex,nI);
151                     if (!xAxis.is())
152                         continue;
153 
154                     //adapt title rotation only when axis swapping has changed
155                     if (!bChanged)
156                         continue;
157 
158                     Reference< XTitled > xTitled( xAxis, uno::UNO_QUERY );
159                     if (!xTitled.is())
160                         continue;
161 
162                     Reference< beans::XPropertySet > xTitleProps( xTitled->getTitleObject(), uno::UNO_QUERY );
163                     if (!xTitleProps.is())
164                         continue;
165 
166                     double fAngleDegree = 0.0;
167                     xTitleProps->getPropertyValue("TextRotation") >>= fAngleDegree;
168                     if (fAngleDegree != 0.0 &&
169                         !rtl::math::approxEqual(fAngleDegree, 90.0))
170                         continue;
171 
172                     double fNewAngleDegree = 0.0;
173                     if( !bVertical && nDimIndex == 1 )
174                         fNewAngleDegree = 90.0;
175                     else if( bVertical && nDimIndex == 0 )
176                         fNewAngleDegree = 90.0;
177 
178                     xTitleProps->setPropertyValue("TextRotation", uno::Any(fNewAngleDegree));
179                 }
180             }
181         }
182     }
183     catch( const uno::Exception & )
184     {
185         DBG_UNHANDLED_EXCEPTION("chart2");
186     }
187 }
188 
189 bool DiagramHelper::getVertical( const uno::Reference< chart2::XDiagram > & xDiagram,
190                              bool& rbFound, bool& rbAmbiguous )
191 {
192     bool bValue = false;
193     rbFound = false;
194     rbAmbiguous = false;
195 
196     Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
197     if (!xCnt.is())
198         return false;
199 
200     Sequence< Reference<XCoordinateSystem> > aCooSys = xCnt->getCoordinateSystems();
201 
202     for (sal_Int32 i = 0; i < aCooSys.getLength(); ++i)
203     {
204         Reference<beans::XPropertySet> xProp(aCooSys[i], uno::UNO_QUERY);
205         if (!xProp.is())
206             continue;
207 
208         bool bCurrent = false;
209         if (xProp->getPropertyValue("SwapXAndYAxis") >>= bCurrent)
210         {
211             if (!rbFound)
212             {
213                 bValue = bCurrent;
214                 rbFound = true;
215             }
216             else if (bCurrent != bValue)
217             {
218                 // ambiguous -> choose always first found
219                 rbAmbiguous = true;
220             }
221         }
222     }
223     return bValue;
224 }
225 
226 void DiagramHelper::setStackMode(
227     const Reference< XDiagram > & xDiagram,
228     StackMode eStackMode
229 )
230 {
231     try
232     {
233         bool bValueFound = false;
234         bool bIsAmbiguous = false;
235         StackMode eOldStackMode = DiagramHelper::getStackMode( xDiagram, bValueFound, bIsAmbiguous );
236 
237         if( eStackMode == eOldStackMode && !bIsAmbiguous )
238             return;
239 
240         StackingDirection eNewDirection = StackingDirection_NO_STACKING;
241         if( eStackMode == StackMode::YStacked || eStackMode == StackMode::YStackedPercent )
242             eNewDirection = StackingDirection_Y_STACKING;
243         else if( eStackMode == StackMode::ZStacked )
244             eNewDirection = StackingDirection_Z_STACKING;
245 
246         uno::Any aNewDirection( eNewDirection );
247 
248         bool bPercent = false;
249         if( eStackMode == StackMode::YStackedPercent )
250             bPercent = true;
251 
252         //iterate through all coordinate systems
253         uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
254         if( !xCooSysContainer.is() )
255             return;
256         uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
257         for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
258         {
259             uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
260             //set correct percent stacking
261             const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(1);
262             for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
263             {
264                 Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1,nI ));
265                 if( xAxis.is())
266                 {
267                     chart2::ScaleData aScaleData = xAxis->getScaleData();
268                     if( (aScaleData.AxisType==AxisType::PERCENT) != bPercent )
269                     {
270                         if( bPercent )
271                             aScaleData.AxisType = AxisType::PERCENT;
272                         else
273                             aScaleData.AxisType = AxisType::REALNUMBER;
274                         xAxis->setScaleData( aScaleData );
275                     }
276                 }
277             }
278             //iterate through all chart types in the current coordinate system
279             uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
280             if( !xChartTypeContainer.is() )
281                 continue;
282             uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
283             if (!aChartTypeList.getLength())
284                 continue;
285 
286             uno::Reference< XChartType > xChartType( aChartTypeList[0] );
287 
288             //iterate through all series in this chart type
289             uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
290             OSL_ASSERT( xDataSeriesContainer.is());
291             if( !xDataSeriesContainer.is() )
292                 continue;
293 
294             uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
295             for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
296             {
297                 Reference< beans::XPropertySet > xProp( aSeriesList[nS], uno::UNO_QUERY );
298                 if(xProp.is())
299                     xProp->setPropertyValue( "StackingDirection", aNewDirection );
300             }
301         }
302     }
303     catch( const uno::Exception & )
304     {
305         DBG_UNHANDLED_EXCEPTION("chart2");
306     }
307 }
308 
309 StackMode DiagramHelper::getStackMode( const Reference< XDiagram > & xDiagram, bool& rbFound, bool& rbAmbiguous )
310 {
311     rbFound=false;
312     rbAmbiguous=false;
313 
314     StackMode eGlobalStackMode = StackMode::NONE;
315 
316     //iterate through all coordinate systems
317     uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
318     if( !xCooSysContainer.is() )
319         return eGlobalStackMode;
320     uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
321     for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
322     {
323         uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
324 
325         //iterate through all chart types in the current coordinate system
326         uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
327         if( !xChartTypeContainer.is() )
328             continue;
329         uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
330         for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
331         {
332             uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
333 
334             StackMode eLocalStackMode = DiagramHelper::getStackModeFromChartType(
335                 xChartType, rbFound, rbAmbiguous, xCooSys );
336 
337             if( rbFound && eLocalStackMode != eGlobalStackMode && nT>0 )
338             {
339                 rbAmbiguous = true;
340                 return eGlobalStackMode;
341             }
342 
343             eGlobalStackMode = eLocalStackMode;
344         }
345     }
346 
347     return eGlobalStackMode;
348 }
349 
350 StackMode DiagramHelper::getStackModeFromChartType(
351     const Reference< XChartType > & xChartType,
352     bool& rbFound, bool& rbAmbiguous,
353     const Reference< XCoordinateSystem > & xCorrespondingCoordinateSystem )
354 {
355     StackMode eStackMode = StackMode::NONE;
356     rbFound = false;
357     rbAmbiguous = false;
358 
359     try
360     {
361         Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW );
362         Sequence< Reference< chart2::XDataSeries > > aSeries( xDSCnt->getDataSeries());
363 
364         chart2::StackingDirection eCommonDirection = chart2::StackingDirection_NO_STACKING;
365         bool bDirectionInitialized = false;
366 
367         // first series is irrelevant for stacking, start with second, unless
368         // there is only one series
369         const sal_Int32 nSeriesCount = aSeries.getLength();
370         sal_Int32 i = (nSeriesCount == 1) ? 0: 1;
371         for( ; i<nSeriesCount; ++i )
372         {
373             rbFound = true;
374             Reference< beans::XPropertySet > xProp( aSeries[i], uno::UNO_QUERY_THROW );
375             chart2::StackingDirection eCurrentDirection = eCommonDirection;
376             // property is not MAYBEVOID
377             bool bSuccess = ( xProp->getPropertyValue( "StackingDirection" ) >>= eCurrentDirection );
378             OSL_ASSERT( bSuccess );
379             if( ! bDirectionInitialized )
380             {
381                 eCommonDirection = eCurrentDirection;
382                 bDirectionInitialized = true;
383             }
384             else
385             {
386                 if( eCommonDirection != eCurrentDirection )
387                 {
388                     rbAmbiguous = true;
389                     break;
390                 }
391             }
392         }
393 
394         if( rbFound )
395         {
396             if( eCommonDirection == chart2::StackingDirection_Z_STACKING )
397                 eStackMode = StackMode::ZStacked;
398             else if( eCommonDirection == chart2::StackingDirection_Y_STACKING )
399             {
400                 eStackMode = StackMode::YStacked;
401 
402                 // percent stacking
403                 if( xCorrespondingCoordinateSystem.is() )
404                 {
405                     if( 1 < xCorrespondingCoordinateSystem->getDimension() )
406                     {
407                         sal_Int32 nAxisIndex = 0;
408                         if( nSeriesCount )
409                             nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(aSeries[0]);
410 
411                         Reference< chart2::XAxis > xAxis(
412                             xCorrespondingCoordinateSystem->getAxisByDimension( 1,nAxisIndex ));
413                         if( xAxis.is())
414                         {
415                             chart2::ScaleData aScaleData = xAxis->getScaleData();
416                             if( aScaleData.AxisType==chart2::AxisType::PERCENT )
417                                 eStackMode = StackMode::YStackedPercent;
418                         }
419                     }
420                 }
421             }
422         }
423     }
424     catch( const uno::Exception & )
425     {
426         DBG_UNHANDLED_EXCEPTION("chart2");
427     }
428 
429     return eStackMode;
430 }
431 
432 sal_Int32 DiagramHelper::getDimension( const Reference< XDiagram > & xDiagram )
433 {
434     // -1: not yet set
435     sal_Int32 nResult = -1;
436 
437     try
438     {
439         Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY );
440         if( xCooSysCnt.is() )
441         {
442             Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
443                 xCooSysCnt->getCoordinateSystems());
444 
445             for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
446             {
447                 Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
448                 if(xCooSys.is())
449                 {
450                     nResult = xCooSys->getDimension();
451                     break;
452                 }
453             }
454         }
455     }
456     catch( const uno::Exception & )
457     {
458         DBG_UNHANDLED_EXCEPTION("chart2");
459     }
460 
461     return nResult;
462 }
463 
464 void DiagramHelper::setDimension(
465     const Reference< XDiagram > & xDiagram,
466     sal_Int32 nNewDimensionCount )
467 {
468     if( ! xDiagram.is())
469         return;
470 
471     if( DiagramHelper::getDimension( xDiagram ) == nNewDimensionCount )
472         return;
473 
474     try
475     {
476         bool rbFound = false;
477         bool rbAmbiguous = true;
478         StackMode eStackMode = DiagramHelper::getStackMode( xDiagram, rbFound, rbAmbiguous );
479         bool bIsSupportingOnlyDeepStackingFor3D=false;
480 
481         //change all coordinate systems:
482         Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY_THROW );
483         Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
484         for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
485         {
486             Reference< XCoordinateSystem > xOldCooSys( aCooSysList[nCS], uno::UNO_QUERY );
487             Reference< XCoordinateSystem > xNewCooSys;
488 
489             Reference< XChartTypeContainer > xChartTypeContainer( xOldCooSys, uno::UNO_QUERY );
490             if( !xChartTypeContainer.is() )
491                 continue;
492 
493             Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
494             for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
495             {
496                 Reference< XChartType > xChartType( aChartTypeList[nT], uno::UNO_QUERY );
497                 bIsSupportingOnlyDeepStackingFor3D = ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( xChartType );
498                 if(!xNewCooSys.is())
499                 {
500                     xNewCooSys = xChartType->createCoordinateSystem( nNewDimensionCount );
501                     break;
502                 }
503                 //@todo make sure that all following charttypes are also capable of the new dimension
504                 //otherwise separate them in a different group
505                 //BM: might be done in replaceCoordinateSystem()
506             }
507 
508             // replace the old coordinate system at all places where it was used
509             DiagramHelper::replaceCoordinateSystem( xDiagram, xOldCooSys, xNewCooSys );
510         }
511 
512         //correct stack mode if necessary
513         if( nNewDimensionCount==3 && eStackMode != StackMode::ZStacked && bIsSupportingOnlyDeepStackingFor3D )
514             DiagramHelper::setStackMode( xDiagram, StackMode::ZStacked );
515         else if( nNewDimensionCount==2 && eStackMode == StackMode::ZStacked )
516             DiagramHelper::setStackMode( xDiagram, StackMode::NONE );
517     }
518     catch( const uno::Exception & )
519     {
520         DBG_UNHANDLED_EXCEPTION("chart2");
521     }
522 }
523 
524 void DiagramHelper::replaceCoordinateSystem(
525     const Reference< XDiagram > & xDiagram,
526     const Reference< XCoordinateSystem > & xCooSysToReplace,
527     const Reference< XCoordinateSystem > & xReplacement )
528 {
529     OSL_ASSERT( xDiagram.is());
530     if( ! xDiagram.is())
531         return;
532 
533     // update the coordinate-system container
534     Reference< XCoordinateSystemContainer > xCont( xDiagram, uno::UNO_QUERY );
535     if( xCont.is())
536     {
537         try
538         {
539             Reference< chart2::data::XLabeledDataSequence > xCategories = DiagramHelper::getCategoriesFromDiagram( xDiagram );
540 
541             // move chart types of xCooSysToReplace to xReplacement
542             Reference< XChartTypeContainer > xCTCntCooSys( xCooSysToReplace, uno::UNO_QUERY_THROW );
543             Reference< XChartTypeContainer > xCTCntReplacement( xReplacement, uno::UNO_QUERY_THROW );
544             xCTCntReplacement->setChartTypes( xCTCntCooSys->getChartTypes());
545 
546             xCont->removeCoordinateSystem( xCooSysToReplace );
547             xCont->addCoordinateSystem( xReplacement );
548 
549             if( xCategories.is() )
550                 DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram );
551         }
552         catch( const uno::Exception & )
553         {
554             DBG_UNHANDLED_EXCEPTION("chart2");
555         }
556     }
557 }
558 
559 bool DiagramHelper::isSeriesAttachedToMainAxis(
560                           const uno::Reference< chart2::XDataSeries >& xDataSeries )
561 {
562     sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
563     return (nAxisIndex==0);
564 }
565 
566 bool DiagramHelper::attachSeriesToAxis( bool bAttachToMainAxis
567                         , const uno::Reference< chart2::XDataSeries >& xDataSeries
568                         , const uno::Reference< chart2::XDiagram >& xDiagram
569                         , const uno::Reference< uno::XComponentContext > & xContext
570                         , bool bAdaptAxes )
571 {
572     bool bChanged = false;
573 
574     //set property at axis
575     Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
576 
577     sal_Int32 nNewAxisIndex = bAttachToMainAxis ? 0 : 1;
578     sal_Int32 nOldAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
579     uno::Reference< chart2::XAxis > xOldAxis( DiagramHelper::getAttachedAxis( xDataSeries, xDiagram ) );
580 
581     if( nOldAxisIndex != nNewAxisIndex )
582     {
583         try
584         {
585             xProp->setPropertyValue( "AttachedAxisIndex", uno::Any( nNewAxisIndex ) );
586             bChanged = true;
587         }
588         catch( const uno::Exception & )
589         {
590             DBG_UNHANDLED_EXCEPTION("chart2");
591         }
592     }
593 
594     if( bChanged && xDiagram.is() )
595     {
596         uno::Reference< XAxis > xAxis( AxisHelper::getAxis( 1, bAttachToMainAxis, xDiagram ) );
597         if(!xAxis.is()) //create an axis if necessary
598             xAxis = AxisHelper::createAxis( 1, bAttachToMainAxis, xDiagram, xContext );
599         if( bAdaptAxes )
600         {
601             AxisHelper::makeAxisVisible( xAxis );
602             AxisHelper::hideAxisIfNoDataIsAttached( xOldAxis, xDiagram );
603         }
604     }
605 
606     return bChanged;
607 }
608 
609 uno::Reference< XAxis > DiagramHelper::getAttachedAxis(
610         const uno::Reference< XDataSeries >& xSeries,
611         const uno::Reference< XDiagram >& xDiagram )
612 {
613     return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), xDiagram );
614 }
615 
616 uno::Reference< XChartType > DiagramHelper::getChartTypeOfSeries(
617                                 const uno::Reference< chart2::XDiagram >&   xDiagram
618                               , const uno::Reference< XDataSeries >&        xGivenDataSeries )
619 {
620     if( !xGivenDataSeries.is() )
621         return nullptr;
622     if(!xDiagram.is())
623         return nullptr;
624 
625     //iterate through the model to find the given xSeries
626     //the found parent indicates the charttype
627 
628     //iterate through all coordinate systems
629     uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
630     if( !xCooSysContainer.is())
631         return nullptr;
632 
633     uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
634     for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
635     {
636         uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
637 
638         //iterate through all chart types in the current coordinate system
639         uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
640         OSL_ASSERT( xChartTypeContainer.is());
641         if( !xChartTypeContainer.is() )
642             continue;
643         uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
644         for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
645         {
646             uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
647 
648             //iterate through all series in this chart type
649             uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
650             OSL_ASSERT( xDataSeriesContainer.is());
651             if( !xDataSeriesContainer.is() )
652                 continue;
653 
654             uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
655             for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
656             {
657                 if( xGivenDataSeries==aSeriesList[nS] )
658                     return xChartType;
659             }
660         }
661     }
662     return nullptr;
663 }
664 
665 std::vector< Reference< XDataSeries > >
666     DiagramHelper::getDataSeriesFromDiagram(
667         const Reference< XDiagram > & xDiagram )
668 {
669     std::vector< Reference< XDataSeries > > aResult;
670 
671     try
672     {
673         Reference< XCoordinateSystemContainer > xCooSysCnt(
674             xDiagram, uno::UNO_QUERY_THROW );
675         Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
676             xCooSysCnt->getCoordinateSystems());
677         for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
678         {
679             Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
680             Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
681             for( sal_Int32 j=0; j<aChartTypeSeq.getLength(); ++j )
682             {
683                 Reference< XDataSeriesContainer > xDSCnt( aChartTypeSeq[j], uno::UNO_QUERY_THROW );
684                 Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() );
685                 std::copy( aSeriesSeq.begin(), aSeriesSeq.end(),
686                              std::back_inserter( aResult ));
687             }
688         }
689     }
690     catch( const uno::Exception & )
691     {
692         DBG_UNHANDLED_EXCEPTION("chart2");
693     }
694 
695     return aResult;
696 }
697 
698 Sequence< Sequence< Reference< XDataSeries > > >
699         DiagramHelper::getDataSeriesGroups( const Reference< XDiagram > & xDiagram )
700 {
701     vector< Sequence< Reference< XDataSeries > > > aResult;
702 
703     //iterate through all coordinate systems
704     Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
705     if( xCooSysContainer.is() )
706     {
707         Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
708         for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
709         {
710             //iterate through all chart types in the current coordinate system
711             Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
712             if( !xChartTypeContainer.is() )
713                 continue;
714             Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
715             for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
716             {
717                 Reference< XDataSeriesContainer > xDataSeriesContainer( aChartTypeList[nT], uno::UNO_QUERY );
718                 if( !xDataSeriesContainer.is() )
719                     continue;
720                 aResult.push_back( xDataSeriesContainer->getDataSeries() );
721             }
722         }
723     }
724     return comphelper::containerToSequence( aResult );
725 }
726 
727 Reference< XChartType >
728     DiagramHelper::getChartTypeByIndex( const Reference< XDiagram >& xDiagram, sal_Int32 nIndex )
729 {
730     Reference< XChartType > xChartType;
731 
732     //iterate through all coordinate systems
733     Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
734     if( ! xCooSysContainer.is())
735         return xChartType;
736 
737     Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
738     sal_Int32 nTypesSoFar = 0;
739     for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
740     {
741         Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
742         if( !xChartTypeContainer.is() )
743             continue;
744         Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
745         if( nIndex >= 0 && nIndex < (nTypesSoFar + aChartTypeList.getLength()) )
746         {
747             xChartType.set( aChartTypeList[nIndex - nTypesSoFar] );
748             break;
749         }
750         nTypesSoFar += aChartTypeList.getLength();
751     }
752 
753     return xChartType;
754 }
755 
756 namespace
757 {
758 
759 std::vector< Reference< XAxis > > lcl_getAxisHoldingCategoriesFromDiagram(
760     const Reference< XDiagram > & xDiagram )
761 {
762     std::vector< Reference< XAxis > > aRet;
763 
764     // return first x-axis as fall-back
765     Reference< XAxis > xFallBack;
766     try
767     {
768         Reference< XCoordinateSystemContainer > xCooSysCnt(
769             xDiagram, uno::UNO_QUERY_THROW );
770         Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
771             xCooSysCnt->getCoordinateSystems());
772         for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
773         {
774             Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
775             OSL_ASSERT( xCooSys.is());
776             for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
777             {
778                 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
779                 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
780                 {
781                     Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
782                     OSL_ASSERT( xAxis.is());
783                     if( xAxis.is())
784                     {
785                         ScaleData aScaleData = xAxis->getScaleData();
786                         if( aScaleData.Categories.is() || (aScaleData.AxisType == AxisType::CATEGORY) )
787                         {
788                             aRet.push_back(xAxis);
789                         }
790                         if( (nN == 0) && !xFallBack.is())
791                             xFallBack.set( xAxis );
792                     }
793                 }
794             }
795         }
796     }
797     catch( const uno::Exception & )
798     {
799         DBG_UNHANDLED_EXCEPTION("chart2" );
800     }
801 
802     if( aRet.empty() )
803         aRet.push_back(xFallBack);
804 
805     return aRet;
806 }
807 
808 } // anonymous namespace
809 
810 bool DiagramHelper::isCategoryDiagram(
811             const Reference< XDiagram >& xDiagram )
812 {
813     try
814     {
815         Reference< XCoordinateSystemContainer > xCooSysCnt(
816             xDiagram, uno::UNO_QUERY_THROW );
817         Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
818             xCooSysCnt->getCoordinateSystems());
819         for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
820         {
821             Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
822             OSL_ASSERT( xCooSys.is());
823             for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
824             {
825                 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
826                 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
827                 {
828                     Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
829                     OSL_ASSERT( xAxis.is());
830                     if( xAxis.is())
831                     {
832                         ScaleData aScaleData = xAxis->getScaleData();
833                         if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
834                             return true;
835                     }
836                 }
837             }
838         }
839     }
840     catch( const uno::Exception & )
841     {
842         DBG_UNHANDLED_EXCEPTION("chart2");
843     }
844 
845     return false;
846 }
847 
848 void DiagramHelper::setCategoriesToDiagram(
849     const Reference< chart2::data::XLabeledDataSequence >& xCategories,
850     const Reference< XDiagram >& xDiagram,
851     bool bSetAxisType  /* = false */,
852     bool bCategoryAxis /* = true */ )
853 {
854     std::vector< Reference< chart2::XAxis > > aCatAxes(
855         lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
856 
857     for (const Reference< chart2::XAxis >& xCatAxis : aCatAxes)
858     {
859         if( xCatAxis.is())
860         {
861             ScaleData aScaleData( xCatAxis->getScaleData());
862             aScaleData.Categories = xCategories;
863             if( bSetAxisType )
864             {
865                 if( bCategoryAxis )
866                     aScaleData.AxisType = AxisType::CATEGORY;
867                 else if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
868                     aScaleData.AxisType = AxisType::REALNUMBER;
869             }
870             xCatAxis->setScaleData( aScaleData );
871         }
872     }
873 }
874 
875 Reference< data::XLabeledDataSequence >
876     DiagramHelper::getCategoriesFromDiagram(
877         const Reference< XDiagram > & xDiagram )
878 {
879     Reference< data::XLabeledDataSequence > xResult;
880 
881     try
882     {
883         std::vector< Reference< chart2::XAxis > > aCatAxes(
884             lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
885         //search for first categories
886         if (!aCatAxes.empty())
887         {
888             Reference< chart2::XAxis > xCatAxis(aCatAxes[0]);
889             if( xCatAxis.is())
890             {
891                 ScaleData aScaleData( xCatAxis->getScaleData());
892                 if( aScaleData.Categories.is() )
893                 {
894                     xResult.set( aScaleData.Categories );
895                     uno::Reference<beans::XPropertySet> xProp(aScaleData.Categories->getValues(), uno::UNO_QUERY );
896                     if( xProp.is() )
897                     {
898                         try
899                         {
900                             xProp->setPropertyValue( "Role", uno::Any( OUString("categories") ) );
901                         }
902                         catch( const uno::Exception & )
903                         {
904                             DBG_UNHANDLED_EXCEPTION("chart2");
905                         }
906                     }
907                 }
908             }
909         }
910     }
911     catch( const uno::Exception & )
912     {
913         DBG_UNHANDLED_EXCEPTION("chart2");
914     }
915 
916     return xResult;
917 }
918 
919 static void lcl_generateAutomaticCategoriesFromChartType(
920             Sequence< OUString >& rRet,
921             const Reference< XChartType >& xChartType )
922 {
923     if(!xChartType.is())
924         return;
925     OUString aMainSeq( xChartType->getRoleOfSequenceForSeriesLabel() );
926     Reference< XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY );
927     if( xSeriesCnt.is() )
928     {
929         Sequence< Reference< XDataSeries > > aSeriesSeq( xSeriesCnt->getDataSeries() );
930         for( sal_Int32 nS = 0; nS < aSeriesSeq.getLength(); nS++ )
931         {
932             Reference< data::XDataSource > xDataSource( aSeriesSeq[nS], uno::UNO_QUERY );
933             if( !xDataSource.is() )
934                 continue;
935             Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
936                 ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aMainSeq ));
937             if( !xLabeledSeq.is() )
938                 continue;
939             Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() );
940             if( !xValueSeq.is() )
941                 continue;
942             rRet = xValueSeq->generateLabel( chart2::data::LabelOrigin_LONG_SIDE );
943             if( rRet.getLength() )
944                 return;
945         }
946     }
947 }
948 
949 Sequence< OUString > DiagramHelper::generateAutomaticCategoriesFromCooSys( const Reference< XCoordinateSystem > & xCooSys )
950 {
951     Sequence< OUString > aRet;
952 
953     Reference< XChartTypeContainer > xTypeCntr( xCooSys, uno::UNO_QUERY );
954     if( xTypeCntr.is() )
955     {
956         Sequence< Reference< XChartType > > aChartTypes( xTypeCntr->getChartTypes() );
957         for( sal_Int32 nN=0; nN<aChartTypes.getLength(); nN++ )
958         {
959             lcl_generateAutomaticCategoriesFromChartType( aRet, aChartTypes[nN] );
960             if( aRet.getLength() )
961                 return aRet;
962         }
963     }
964     return aRet;
965 }
966 
967 Sequence< OUString > DiagramHelper::getExplicitSimpleCategories(
968             ChartModel& rModel )
969 {
970     uno::Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( rModel ) );
971     ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel );
972     return aExplicitCategoriesProvider.getSimpleCategories();
973 }
974 
975 namespace
976 {
977 void lcl_switchToDateCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
978 {
979     if( !xAxis.is() )
980         return;
981     if( !xChartDoc.is() )
982         return;
983 
984     ScaleData aScale( xAxis->getScaleData() );
985     if( xChartDoc->hasInternalDataProvider() )
986     {
987         //remove all content the is not of type double and remove multiple level
988         Reference< XAnyDescriptionAccess > xDataAccess( xChartDoc->getDataProvider(), uno::UNO_QUERY );
989         if( xDataAccess.is() )
990         {
991             Sequence< Sequence< Any > > aAnyCategories( xDataAccess->getAnyRowDescriptions() );
992             double fTest = 0.0;
993             double fNan = 0.0;
994             ::rtl::math::setNan( & fNan );
995             sal_Int32 nN = aAnyCategories.getLength();
996             for( ; nN--; )
997             {
998                 Sequence< Any >& rCat = aAnyCategories[nN];
999                 if( rCat.getLength() > 1 )
1000                     rCat.realloc(1);
1001                 if( rCat.getLength() == 1 )
1002                 {
1003                     Any& rAny = rCat[0];
1004                     if( !(rAny>>=fTest) )
1005                     {
1006                         rAny <<= fNan;
1007                     }
1008                 }
1009             }
1010             xDataAccess->setAnyRowDescriptions( aAnyCategories );
1011         }
1012         //check the numberformat at the axis
1013         Reference< beans::XPropertySet > xAxisProps( xAxis, uno::UNO_QUERY );
1014         Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartDoc, uno::UNO_QUERY );
1015         if( xAxisProps.is() && xNumberFormatsSupplier.is() )
1016         {
1017             sal_Int32 nNumberFormat = -1;
1018             xAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormat;
1019 
1020             Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1021             if( xNumberFormats.is() )
1022             {
1023                 Reference< beans::XPropertySet > xKeyProps;
1024                 try
1025                 {
1026                     xKeyProps = xNumberFormats->getByKey( nNumberFormat );
1027                 }
1028                 catch( const uno::Exception & )
1029                 {
1030                     DBG_UNHANDLED_EXCEPTION("chart2");
1031                 }
1032                 sal_Int32 nType = util::NumberFormat::UNDEFINED;
1033                 if( xKeyProps.is() )
1034                     xKeyProps->getPropertyValue( "Type" ) >>= nType;
1035                 if( !( nType & util::NumberFormat::DATE ) )
1036                 {
1037                     //set a date format to the axis
1038                     const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
1039                     Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE,  rLocaleDataWrapper.getLanguageTag().getLocale(), true/*bCreate*/ );
1040                     if( aKeySeq.getLength() )
1041                     {
1042                         xAxisProps->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any(aKeySeq[0]));
1043                     }
1044                 }
1045             }
1046         }
1047     }
1048     if( aScale.AxisType != chart2::AxisType::DATE )
1049         AxisHelper::removeExplicitScaling( aScale );
1050     aScale.AxisType = chart2::AxisType::DATE;
1051     xAxis->setScaleData( aScale );
1052 }
1053 
1054 void lcl_switchToTextCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
1055 {
1056     if( !xAxis.is() )
1057         return;
1058     if( !xChartDoc.is() )
1059         return;
1060     ScaleData aScale( xAxis->getScaleData() );
1061     if( aScale.AxisType != chart2::AxisType::CATEGORY )
1062         AxisHelper::removeExplicitScaling( aScale );
1063     //todo migrate dates to text?
1064     aScale.AxisType = chart2::AxisType::CATEGORY;
1065     aScale.AutoDateAxis = false;
1066     xAxis->setScaleData( aScale );
1067 }
1068 
1069 }
1070 
1071 void DiagramHelper::switchToDateCategories( const Reference< XChartDocument >& xChartDoc )
1072 {
1073     Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
1074     if(xChartModel.is())
1075     {
1076         ControllerLockGuardUNO aCtrlLockGuard( xChartModel );
1077 
1078         Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
1079         if( xCooSys.is() )
1080         {
1081             Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
1082             lcl_switchToDateCategories( xChartDoc, xAxis );
1083         }
1084     }
1085 }
1086 
1087 void DiagramHelper::switchToTextCategories( const Reference< XChartDocument >& xChartDoc )
1088 {
1089     Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
1090     if(xChartModel.is())
1091     {
1092         ControllerLockGuardUNO aCtrlLockGuard( xChartModel );
1093 
1094         Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
1095         if( xCooSys.is() )
1096         {
1097             Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
1098             lcl_switchToTextCategories( xChartDoc, xAxis );
1099         }
1100     }
1101 }
1102 
1103 bool DiagramHelper::isSupportingDateAxis( const Reference< chart2::XDiagram >& xDiagram )
1104 {
1105     return ::chart::ChartTypeHelper::isSupportingDateAxis(
1106             DiagramHelper::getChartTypeByIndex( xDiagram, 0 ), 0 );
1107 }
1108 
1109 bool DiagramHelper::isDateNumberFormat( sal_Int32 nNumberFormat, const Reference< util::XNumberFormats >& xNumberFormats )
1110 {
1111     bool bIsDate = false;
1112     if( !xNumberFormats.is() )
1113         return bIsDate;
1114 
1115     Reference< beans::XPropertySet > xKeyProps = xNumberFormats->getByKey( nNumberFormat );
1116     if( xKeyProps.is() )
1117     {
1118         sal_Int32 nType = util::NumberFormat::UNDEFINED;
1119         xKeyProps->getPropertyValue( "Type" ) >>= nType;
1120         bIsDate = nType & util::NumberFormat::DATE;
1121     }
1122     return bIsDate;
1123 }
1124 
1125 sal_Int32 DiagramHelper::getDateNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1126 {
1127     sal_Int32 nRet=-1;
1128 
1129     //try to get a date format with full year display
1130     const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
1131     NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1132     SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1133     if( pNumFormatter )
1134     {
1135         nRet = pNumFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, rLanguageTag.getLanguageType() );
1136     }
1137     else
1138     {
1139         Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1140         if( xNumberFormats.is() )
1141         {
1142             Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE,
1143                     rLanguageTag.getLocale(), true/*bCreate */);
1144             if( aKeySeq.getLength() )
1145             {
1146                 nRet = aKeySeq[0];
1147             }
1148         }
1149     }
1150     return nRet;
1151 }
1152 
1153 sal_Int32 DiagramHelper::getDateTimeInputNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier, double fNumber )
1154 {
1155     sal_Int32 nRet = 0;
1156 
1157     // Get the most detailed date/time format according to fNumber.
1158     NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1159     SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1160     if (!pNumFormatter)
1161         SAL_WARN("chart2", "DiagramHelper::getDateTimeInputNumberFormat - no SvNumberFormatter");
1162     else
1163     {
1164         SvNumFormatType nType;
1165         // Obtain best matching date, time or datetime format.
1166         nRet = pNumFormatter->GuessDateTimeFormat( nType, fNumber, LANGUAGE_SYSTEM);
1167         // Obtain the corresponding edit format.
1168         nRet = pNumFormatter->GetEditFormat( fNumber, nRet, nType, LANGUAGE_SYSTEM, nullptr);
1169     }
1170     return nRet;
1171 }
1172 
1173 sal_Int32 DiagramHelper::getPercentNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1174 {
1175     sal_Int32 nRet=-1;
1176     const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
1177     NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
1178     SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
1179     if( pNumFormatter )
1180     {
1181         nRet = pNumFormatter->GetFormatIndex( NF_PERCENT_INT, rLanguageTag.getLanguageType() );
1182     }
1183     else
1184     {
1185         Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
1186         if( xNumberFormats.is() )
1187         {
1188             Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::PERCENT,
1189                     rLanguageTag.getLocale(), true/*bCreate*/ );
1190             if( aKeySeq.getLength() )
1191             {
1192                 // This *assumes* the sequence is sorted as in
1193                 // NfIndexTableOffset and the first format is the integer 0%
1194                 // format by chance.. which usually is the case, but.. anyway,
1195                 // we usually also have a number formatter so don't reach here.
1196                 nRet = aKeySeq[0];
1197             }
1198         }
1199     }
1200     return nRet;
1201 }
1202 
1203 Sequence< Reference< XChartType > >
1204     DiagramHelper::getChartTypesFromDiagram(
1205         const Reference< XDiagram > & xDiagram )
1206 {
1207     std::vector< Reference< XChartType > > aResult;
1208 
1209     if(xDiagram.is())
1210     {
1211         try
1212         {
1213             Reference< XCoordinateSystemContainer > xCooSysCnt(
1214                 xDiagram, uno::UNO_QUERY_THROW );
1215             Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
1216                 xCooSysCnt->getCoordinateSystems());
1217             for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
1218             {
1219                 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
1220                 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
1221                 std::copy( aChartTypeSeq.begin(), aChartTypeSeq.end(),
1222                              std::back_inserter( aResult ));
1223             }
1224         }
1225         catch( const uno::Exception & )
1226         {
1227             DBG_UNHANDLED_EXCEPTION("chart2");
1228         }
1229     }
1230 
1231     return comphelper::containerToSequence( aResult );
1232 }
1233 
1234 bool DiagramHelper::areChartTypesCompatible( const Reference< ::chart2::XChartType >& xFirstType,
1235                 const Reference< ::chart2::XChartType >& xSecondType )
1236 {
1237     if( !xFirstType.is() || !xSecondType.is() )
1238         return false;
1239 
1240     std::vector< OUString > aFirstRoles( ContainerHelper::SequenceToVector( xFirstType->getSupportedMandatoryRoles() ) );
1241     std::vector< OUString > aSecondRoles( ContainerHelper::SequenceToVector( xSecondType->getSupportedMandatoryRoles() ) );
1242     std::sort( aFirstRoles.begin(), aFirstRoles.end() );
1243     std::sort( aSecondRoles.begin(), aSecondRoles.end() );
1244     return ( aFirstRoles == aSecondRoles );
1245 }
1246 
1247 namespace
1248 {
1249      /**
1250      * This method implements the logic of checking if a series can be moved
1251      * forward/backward. Depending on the "bDoMove" parameter the series will
1252      * be moved (bDoMove = true) or the function just will test if the
1253      * series can be moved without doing the move (bDoMove = false).
1254      *
1255      * @param xDiagram
1256      *  Reference to the diagram that contains the series.
1257      *
1258      * @param xGivenDataSeries
1259      *  Reference to the series that should moved or tested for moving.
1260      *
1261      * @param bForward
1262      *  Direction in which the series should be moved or tested for moving.
1263      *
1264      * @param bDoMove
1265      *  Should this function really move the series (true) or just test if it is
1266      *  possible (false).
1267      *
1268      *
1269      * @returns
1270      *  in case of bDoMove == true
1271      *      - True : if the move was done
1272      *      - False : the move failed
1273      *  in case of bDoMove == false
1274      *      - True : the series can be moved
1275      *      - False : the series can not be moved
1276      *
1277      */
1278 
1279 bool lcl_moveSeriesOrCheckIfMoveIsAllowed(
1280     const Reference< XDiagram >& xDiagram,
1281     const Reference< XDataSeries >& xGivenDataSeries,
1282     bool bForward,
1283     bool bDoMove )
1284 {
1285     bool bMovedOrMoveAllowed = false;
1286 
1287     try
1288     {
1289         uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
1290 
1291         if( xGivenDataSeries.is() && xCooSysContainer.is() )
1292         {
1293             //find position of series.
1294             bool bFound = false;
1295             uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
1296 
1297             for( sal_Int32 nCS = 0; !bFound && nCS < aCooSysList.getLength(); ++nCS )
1298             {
1299                 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
1300 
1301                 //iterate through all chart types in the current coordinate system
1302                 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
1303                 OSL_ASSERT( xChartTypeContainer.is());
1304                 if( !xChartTypeContainer.is() )
1305                     continue;
1306                 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
1307                 uno::Reference< XChartType > xFormerChartType;
1308 
1309                 for( sal_Int32 nT = 0; !bFound && nT < aChartTypeList.getLength(); ++nT )
1310                 {
1311                     uno::Reference< XChartType > xCurrentChartType( aChartTypeList[nT] );
1312 
1313                     //iterate through all series in this chart type
1314                     uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xCurrentChartType, uno::UNO_QUERY );
1315                     OSL_ASSERT( xDataSeriesContainer.is());
1316                     if( !xDataSeriesContainer.is() )
1317                         continue;
1318 
1319                     uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
1320 
1321                     for( sal_Int32 nS = 0; !bFound && nS < aSeriesList.getLength(); ++nS )
1322                     {
1323 
1324                         // We found the series we are interested in!
1325                         if( xGivenDataSeries==aSeriesList[nS] )
1326                         {
1327                             sal_Int32 nOldSeriesIndex = nS;
1328                             bFound = true;
1329 
1330                             try
1331                             {
1332                                 sal_Int32 nNewSeriesIndex = nS;
1333 
1334                                 if( bForward )
1335                                     nNewSeriesIndex--;
1336                                 else
1337                                     nNewSeriesIndex++;
1338 
1339                                 if( nNewSeriesIndex >= 0 && nNewSeriesIndex < aSeriesList.getLength() )
1340                                 {
1341                                     //move series in the same charttype
1342                                     bMovedOrMoveAllowed = true;
1343                                     if( bDoMove )
1344                                     {
1345                                         aSeriesList[ nOldSeriesIndex ] = aSeriesList[ nNewSeriesIndex ];
1346                                         aSeriesList[ nNewSeriesIndex ] = xGivenDataSeries;
1347                                         xDataSeriesContainer->setDataSeries( aSeriesList );
1348                                     }
1349                                 }
1350                                 else if( nNewSeriesIndex<0 )
1351                                 {
1352                                     //exchange series with former charttype
1353                                     if( xFormerChartType.is() && DiagramHelper::areChartTypesCompatible( xFormerChartType, xCurrentChartType ) )
1354                                     {
1355                                         bMovedOrMoveAllowed = true;
1356                                         if( bDoMove )
1357                                         {
1358                                             uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xFormerChartType, uno::UNO_QUERY );
1359                                             if( xOtherDataSeriesContainer.is() )
1360                                             {
1361                                                 uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
1362                                                 sal_Int32 nOtherSeriesIndex = aOtherSeriesList.getLength()-1;
1363                                                 if( nOtherSeriesIndex >= 0 && nOtherSeriesIndex < aOtherSeriesList.getLength() )
1364                                                 {
1365                                                     uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
1366                                                     aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
1367                                                     xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
1368 
1369                                                     aSeriesList[nOldSeriesIndex]=xExchangeSeries;
1370                                                     xDataSeriesContainer->setDataSeries(aSeriesList);
1371                                                 }
1372                                             }
1373                                         }
1374                                     }
1375                                 }
1376                                 else if( nT+1 < aChartTypeList.getLength() )
1377                                 {
1378                                     //exchange series with next charttype
1379                                     uno::Reference< XChartType > xOtherChartType( aChartTypeList[nT+1] );
1380                                     if( xOtherChartType.is() && DiagramHelper::areChartTypesCompatible( xOtherChartType, xCurrentChartType ) )
1381                                     {
1382                                         bMovedOrMoveAllowed = true;
1383                                         if( bDoMove )
1384                                         {
1385                                             uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xOtherChartType, uno::UNO_QUERY );
1386                                             if( xOtherDataSeriesContainer.is() )
1387                                             {
1388                                                 uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
1389                                                 if( 0 < aOtherSeriesList.getLength() )
1390                                                 {
1391                                                     uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[0] );
1392                                                     aOtherSeriesList[0] = xGivenDataSeries;
1393                                                     xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
1394 
1395                                                     aSeriesList[nOldSeriesIndex]=xExchangeSeries;
1396                                                     xDataSeriesContainer->setDataSeries(aSeriesList);
1397                                                 }
1398                                             }
1399                                         }
1400                                     }
1401                                 }
1402                             }
1403                             catch( const util::CloseVetoException& )
1404                             {
1405                             }
1406                             catch( const uno::RuntimeException& )
1407                             {
1408                             }
1409                         }
1410                     }
1411                     xFormerChartType = xCurrentChartType;
1412                 }
1413             }
1414         }
1415     }
1416     catch( const util::CloseVetoException& )
1417     {
1418     }
1419     catch( const uno::RuntimeException& )
1420     {
1421     }
1422     return bMovedOrMoveAllowed;
1423 }
1424 } // anonymous namespace
1425 
1426 bool DiagramHelper::isSeriesMoveable(
1427     const Reference< XDiagram >& xDiagram,
1428     const Reference< XDataSeries >& xGivenDataSeries,
1429     bool bForward )
1430 {
1431     const bool bDoMove = false;
1432 
1433     bool bIsMoveable = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1434         xDiagram, xGivenDataSeries, bForward, bDoMove );
1435 
1436     return bIsMoveable;
1437 }
1438 
1439 bool DiagramHelper::moveSeries( const Reference< XDiagram >& xDiagram, const Reference< XDataSeries >& xGivenDataSeries, bool bForward )
1440 {
1441     const bool bDoMove = true;
1442 
1443     bool bMoved = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1444         xDiagram, xGivenDataSeries, bForward, bDoMove );
1445 
1446     return bMoved;
1447 }
1448 
1449 bool DiagramHelper::isSupportingFloorAndWall( const Reference<
1450                 chart2::XDiagram >& xDiagram )
1451 {
1452     //pies and donuts currently do not support this because of wrong files from older versions
1453     //todo: allow this in future again, if fileversion are available for ole objects (metastream)
1454     //thus the wrong bottom can be removed on import
1455 
1456     Sequence< Reference< chart2::XChartType > > aTypes(
1457             ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) );
1458     for( sal_Int32 nN = 0; nN < aTypes.getLength(); nN++ )
1459     {
1460         Reference< chart2::XChartType > xType( aTypes[nN] );
1461         if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
1462             return false;
1463         if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
1464             return false;
1465         if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
1466             return false;
1467     }
1468     return true;
1469 }
1470 
1471 bool DiagramHelper::isPieOrDonutChart( const css::uno::Reference< css::chart2::XDiagram >& xDiagram )
1472 {
1473     uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex(
1474         xDiagram, 0 ) );
1475 
1476     if( xChartType .is() )
1477     {
1478         OUString aChartType = xChartType->getChartType();
1479         if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE )
1480             return true;
1481     }
1482     return false;
1483 }
1484 
1485 sal_Int32 DiagramHelper::getGeometry3D(
1486     const uno::Reference< chart2::XDiagram > & xDiagram,
1487     bool& rbFound, bool& rbAmbiguous )
1488 {
1489     sal_Int32 nCommonGeom( DataPointGeometry3D::CUBOID );
1490     rbFound = false;
1491     rbAmbiguous = false;
1492 
1493     std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
1494         DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
1495 
1496     if( aSeriesVec.empty())
1497         rbAmbiguous = true;
1498 
1499     for (auto const& series : aSeriesVec)
1500     {
1501         try
1502         {
1503             sal_Int32 nGeom = 0;
1504             Reference< beans::XPropertySet > xProp(series, uno::UNO_QUERY_THROW);
1505             if( xProp->getPropertyValue( "Geometry3D") >>= nGeom )
1506             {
1507                 if( ! rbFound )
1508                 {
1509                     // first series
1510                     nCommonGeom = nGeom;
1511                     rbFound = true;
1512                 }
1513                 // further series: compare for uniqueness
1514                 else if( nCommonGeom != nGeom )
1515                 {
1516                     rbAmbiguous = true;
1517                     break;
1518                 }
1519             }
1520         }
1521         catch( const uno::Exception & )
1522         {
1523             DBG_UNHANDLED_EXCEPTION("chart2");
1524         }
1525     }
1526 
1527     return nCommonGeom;
1528 }
1529 
1530 void DiagramHelper::setGeometry3D(
1531     const Reference< chart2::XDiagram > & xDiagram,
1532     sal_Int32 nNewGeometry )
1533 {
1534     std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
1535         DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
1536 
1537     for (auto const& series : aSeriesVec)
1538     {
1539         DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(
1540             series, "Geometry3D", uno::Any( nNewGeometry ));
1541     }
1542 }
1543 
1544 sal_Int32 DiagramHelper::getCorrectedMissingValueTreatment(
1545             const Reference< chart2::XDiagram > & xDiagram,
1546             const Reference< chart2::XChartType >& xChartType )
1547 {
1548     sal_Int32 nResult = css::chart::MissingValueTreatment::LEAVE_GAP;
1549     uno::Sequence < sal_Int32 > aAvailableMissingValueTreatments(
1550                 ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) );
1551 
1552     uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
1553     if( xDiaProp.is() && (xDiaProp->getPropertyValue( "MissingValueTreatment" ) >>= nResult) )
1554     {
1555         //ensure that the set value is supported by this charttype
1556         for( sal_Int32 nN = 0; nN < aAvailableMissingValueTreatments.getLength(); nN++ )
1557             if( aAvailableMissingValueTreatments[nN] == nResult )
1558                 return nResult; //ok
1559     }
1560 
1561     //otherwise use the first supported one
1562     if( aAvailableMissingValueTreatments.getLength() )
1563     {
1564         nResult = aAvailableMissingValueTreatments[0];
1565         return nResult;
1566     }
1567 
1568     return nResult;
1569 }
1570 
1571 DiagramPositioningMode DiagramHelper::getDiagramPositioningMode( const uno::Reference<
1572                 chart2::XDiagram > & xDiagram )
1573 {
1574     DiagramPositioningMode eMode = DiagramPositioningMode_AUTO;
1575     uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY );
1576     if( xDiaProps.is() )
1577     {
1578         RelativePosition aRelPos;
1579         RelativeSize aRelSize;
1580         if( (xDiaProps->getPropertyValue("RelativePosition") >>= aRelPos ) &&
1581             (xDiaProps->getPropertyValue("RelativeSize") >>= aRelSize ) )
1582         {
1583             bool bPosSizeExcludeAxes=false;
1584             xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxes;
1585             if( bPosSizeExcludeAxes )
1586                 eMode = DiagramPositioningMode_EXCLUDING;
1587             else
1588                 eMode = DiagramPositioningMode_INCLUDING;
1589         }
1590     }
1591     return eMode;
1592 }
1593 
1594 static void lcl_ensureRange0to1( double& rValue )
1595 {
1596     if(rValue<0.0)
1597         rValue=0.0;
1598     if(rValue>1.0)
1599         rValue=1.0;
1600 }
1601 
1602 bool DiagramHelper::setDiagramPositioning( const uno::Reference< frame::XModel >& xChartModel,
1603         const awt::Rectangle& rPosRect /*100th mm*/ )
1604 {
1605     ControllerLockGuardUNO aCtrlLockGuard( xChartModel );
1606 
1607     bool bChanged = false;
1608     awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
1609     uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
1610     if( !xDiaProps.is() )
1611         return bChanged;
1612 
1613     RelativePosition aOldPos;
1614     RelativeSize aOldSize;
1615     xDiaProps->getPropertyValue("RelativePosition" ) >>= aOldPos;
1616     xDiaProps->getPropertyValue("RelativeSize" ) >>= aOldSize;
1617 
1618     RelativePosition aNewPos;
1619     aNewPos.Anchor = drawing::Alignment_TOP_LEFT;
1620     aNewPos.Primary = double(rPosRect.X)/double(aPageSize.Width);
1621     aNewPos.Secondary = double(rPosRect.Y)/double(aPageSize.Height);
1622 
1623     chart2::RelativeSize aNewSize;
1624     aNewSize.Primary = double(rPosRect.Width)/double(aPageSize.Width);
1625     aNewSize.Secondary = double(rPosRect.Height)/double(aPageSize.Height);
1626 
1627     lcl_ensureRange0to1( aNewPos.Primary );
1628     lcl_ensureRange0to1( aNewPos.Secondary );
1629     lcl_ensureRange0to1( aNewSize.Primary );
1630     lcl_ensureRange0to1( aNewSize.Secondary );
1631     if( (aNewPos.Primary + aNewSize.Primary) > 1.0 )
1632         aNewPos.Primary = 1.0 - aNewSize.Primary;
1633     if( (aNewPos.Secondary + aNewSize.Secondary) > 1.0 )
1634         aNewPos.Secondary = 1.0 - aNewSize.Secondary;
1635 
1636     xDiaProps->setPropertyValue( "RelativePosition", uno::Any(aNewPos) );
1637     xDiaProps->setPropertyValue( "RelativeSize", uno::Any(aNewSize) );
1638 
1639     bChanged = (aOldPos.Anchor!=aNewPos.Anchor) ||
1640         (aOldPos.Primary!=aNewPos.Primary) ||
1641         (aOldPos.Secondary!=aNewPos.Secondary) ||
1642         (aOldSize.Primary!=aNewSize.Primary) ||
1643         (aOldSize.Secondary!=aNewSize.Secondary);
1644     return bChanged;
1645 }
1646 
1647 awt::Rectangle DiagramHelper::getDiagramRectangleFromModel( const uno::Reference< frame::XModel >& xChartModel )
1648 {
1649     awt::Rectangle aRet(-1,-1,-1,-1);
1650 
1651     uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
1652     if( !xDiaProps.is() )
1653         return aRet;
1654 
1655     awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
1656 
1657     RelativePosition aRelPos;
1658     RelativeSize aRelSize;
1659     xDiaProps->getPropertyValue("RelativePosition" ) >>= aRelPos;
1660     xDiaProps->getPropertyValue("RelativeSize" ) >>= aRelSize;
1661 
1662     awt::Size aAbsSize(
1663         static_cast< sal_Int32 >( aRelSize.Primary * aPageSize.Width ),
1664         static_cast< sal_Int32 >( aRelSize.Secondary * aPageSize.Height ));
1665 
1666     awt::Point aAbsPos(
1667         static_cast< sal_Int32 >( aRelPos.Primary * aPageSize.Width ),
1668         static_cast< sal_Int32 >( aRelPos.Secondary * aPageSize.Height ));
1669 
1670     awt::Point aAbsPosLeftTop = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( aAbsPos, aAbsSize, aRelPos.Anchor );
1671 
1672     aRet = awt::Rectangle(aAbsPosLeftTop.X, aAbsPosLeftTop.Y, aAbsSize.Width, aAbsSize.Height );
1673 
1674     return aRet;
1675 }
1676 
1677 bool DiagramHelper::switchDiagramPositioningToExcludingPositioning(
1678     ChartModel& rModel, bool bResetModifiedState, bool bConvertAlsoFromAutoPositioning )
1679 {
1680     //return true if something was changed
1681     const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
1682     if( nCurrentODFVersion > SvtSaveOptions::ODFVER_012 )
1683     {
1684         uno::Reference< css::chart::XDiagramPositioning > xDiagramPositioning( rModel.getFirstDiagram(), uno::UNO_QUERY );
1685         if( xDiagramPositioning.is() && ( bConvertAlsoFromAutoPositioning || !xDiagramPositioning->isAutomaticDiagramPositioning() )
1686                 && !xDiagramPositioning->isExcludingDiagramPositioning() )
1687         {
1688             ControllerLockGuard aCtrlLockGuard( rModel );
1689             bool bModelWasModified = rModel.isModified();
1690             xDiagramPositioning->setDiagramPositionExcludingAxes( xDiagramPositioning->calculateDiagramPositionExcludingAxes() );
1691             if(bResetModifiedState && !bModelWasModified )
1692                 rModel.setModified(false);
1693             return true;
1694         }
1695     }
1696     return false;
1697 }
1698 
1699 } //  namespace chart
1700 
1701 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1702