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