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