xref: /core/chart2/source/view/main/ChartView.cxx (revision 0d1253c2)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_features.h>
21 
22 #include <ChartView.hxx>
23 #include <chartview/DrawModelWrapper.hxx>
24 #include <NumberFormatterWrapper.hxx>
25 #include <VDiagram.hxx>
26 #include "VTitle.hxx"
27 #include "VButton.hxx"
28 #include <ShapeFactory.hxx>
29 #include <VCoordinateSystem.hxx>
30 #include <VSeriesPlotter.hxx>
31 #include <CommonConverters.hxx>
32 #include <TitleHelper.hxx>
33 #include <LegendHelper.hxx>
34 #include "VLegend.hxx"
35 #include <PropertyMapper.hxx>
36 #include <ChartModel.hxx>
37 #include <ChartTypeHelper.hxx>
38 #include <ScaleAutomatism.hxx>
39 #include <ObjectIdentifier.hxx>
40 #include <DiagramHelper.hxx>
41 #include <RelativePositionHelper.hxx>
42 #include <servicenames.hxx>
43 #include <AxisHelper.hxx>
44 #include <AxisIndexDefines.hxx>
45 #include <BaseGFXHelper.hxx>
46 #include <DataSeriesHelper.hxx>
47 #include <DateHelper.hxx>
48 #include <ExplicitCategoriesProvider.hxx>
49 #include <defines.hxx>
50 #include <unonames.hxx>
51 #include <editeng/frmdiritem.hxx>
52 #include <tools/globname.hxx>
53 #include <comphelper/fileformat.h>
54 #include <comphelper/scopeguard.hxx>
55 #include <comphelper/servicehelper.hxx>
56 #include <cppuhelper/supportsservice.hxx>
57 #include <unotools/streamwrap.hxx>
58 #include <svx/svdpage.hxx>
59 #include <svx/unopage.hxx>
60 #include <svx/unoshape.hxx>
61 #include <vcl/svapp.hxx>
62 #include <osl/mutex.hxx>
63 #include <svx/unofill.hxx>
64 #include <drawinglayer/XShapeDumper.hxx>
65 
66 #include <time.h>
67 
68 #include <com/sun/star/awt/Size.hpp>
69 #include <com/sun/star/awt/Point.hpp>
70 #include <com/sun/star/chart/ChartAxisPosition.hpp>
71 #include <com/sun/star/chart/TimeUnit.hpp>
72 #include <com/sun/star/chart2/AxisType.hpp>
73 #include <com/sun/star/chart2/StackingDirection.hpp>
74 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
75 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
76 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
77 #include <com/sun/star/chart2/RelativePosition.hpp>
78 #include <com/sun/star/chart2/RelativeSize.hpp>
79 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
80 #include <com/sun/star/chart2/data/PivotTableFieldEntry.hpp>
81 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
82 #include <com/sun/star/drawing/XShapeGroup.hpp>
83 #include <com/sun/star/embed/Aspects.hpp>
84 #include <com/sun/star/io/XSeekable.hpp>
85 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
86 #include <com/sun/star/util/XRefreshable.hpp>
87 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
88 #include <com/sun/star/text/XText.hpp>
89 #include <com/sun/star/text/XTextDocument.hpp>
90 #include <com/sun/star/text/WritingMode2.hpp>
91 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
92 #include <com/sun/star/view/XSelectionSupplier.hpp>
93 #include <svl/itempool.hxx>
94 #include <svl/languageoptions.hxx>
95 #include <comphelper/classids.hxx>
96 #include <servicenames_charttypes.hxx>
97 
98 
99 #include <rtl/ustring.hxx>
100 #include <sal/log.hxx>
101 
102 #include <tools/diagnose_ex.h>
103 
104 #include <memory>
105 namespace com { namespace sun { namespace star { namespace chart2 { class XChartDocument; } } } }
106 
107 namespace chart {
108 
109 using namespace ::com::sun::star;
110 using namespace ::com::sun::star::chart2;
111 using ::com::sun::star::uno::Reference;
112 using ::com::sun::star::uno::Sequence;
113 using ::com::sun::star::uno::Any;
114 
115 namespace {
116 
117 class theExplicitValueProviderUnoTunnelId  : public rtl::Static<UnoTunnelIdInit, theExplicitValueProviderUnoTunnelId> {};
118 
119 typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex; //first index is the dimension, second index is the axis index that indicates whether this is a main or secondary axis
120 typedef std::map< VCoordinateSystem*, tFullAxisIndex > tCoordinateSystemMap;
121 
122 /** This class handles a collection of coordinate systems and is used for
123  *  executing some action on all coordinate systems such as
124  *  `prepareAutomaticAxisScaling` and `setExplicitScaleAndIncrement`.
125  *  Moreover it contains the `aAutoScaling` object that is an instance of
126  *  the `ScaleAutomatism` class. The initialization of `aAutoScaling` is
127  *  performed in the `SeriesPlotterContainer::initAxisUsageList` method and is
128  *  used in the `SeriesPlotterContainer::doAutoScaling` for calculating explicit
129  *  scale and increment objects (see `SeriesPlotterContainer::doAutoScaling`).
130  */
131 struct AxisUsage
132 {
133     AxisUsage();
134     ~AxisUsage();
135 
136     void addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex );
137     std::vector< VCoordinateSystem* > getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex );
138     sal_Int32 getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex );
139 
140     void prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex );
141     void setExplicitScaleAndIncrement( sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc );
142 
143     ScaleAutomatism aAutoScaling;
144 
145 private:
146     tCoordinateSystemMap    aCoordinateSystems;
147     std::map< sal_Int32, sal_Int32 > aMaxIndexPerDimension;
148 };
149 
150 AxisUsage::AxisUsage()
151     : aAutoScaling(AxisHelper::createDefaultScale(), Date(Date::SYSTEM))
152 {
153 }
154 
155 AxisUsage::~AxisUsage()
156 {
157     aCoordinateSystems.clear();
158 }
159 
160 void AxisUsage::addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
161 {
162     if(!pCooSys)
163         return;
164 
165     tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex );
166     tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) );
167 
168     //use one scale only once for each coordinate system
169     //main axis are preferred over secondary axis
170     //value scales are preferred
171     if(aFound!=aCoordinateSystems.end())
172     {
173         sal_Int32 nFoundAxisIndex = aFound->second.second;
174         if( nFoundAxisIndex < nAxisIndex )
175             return;
176         sal_Int32 nFoundDimension = aFound->second.first;
177         if( nFoundDimension ==1 )
178             return;
179         if( nFoundDimension < nDimensionIndex )
180             return;
181     }
182     aCoordinateSystems[pCooSys] = aFullAxisIndex;
183 
184     //set maximum scale index
185     std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex);
186     if( aIter != aMaxIndexPerDimension.end() )
187     {
188         sal_Int32 nCurrentMaxIndex = aIter->second;
189         if( nCurrentMaxIndex < nAxisIndex )
190             aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex;
191     }
192     else
193         aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex;
194 }
195 
196 std::vector< VCoordinateSystem* > AxisUsage::getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
197 {
198     std::vector< VCoordinateSystem* > aRet;
199 
200     for (auto const& coordinateSystem : aCoordinateSystems)
201     {
202         if( coordinateSystem.second.first != nDimensionIndex )
203             continue;
204         if( coordinateSystem.second.second != nAxisIndex )
205             continue;
206         aRet.push_back( coordinateSystem.first );
207     }
208 
209     return aRet;
210 }
211 
212 sal_Int32 AxisUsage::getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex )
213 {
214     sal_Int32 nRet = -1;
215     std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex);
216     if( aIter != aMaxIndexPerDimension.end() )
217         nRet = aIter->second;
218     return nRet;
219 }
220 
221 void AxisUsage::prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex )
222 {
223     std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex);
224     for (VCoordinateSystem * i : aVCooSysList)
225         i->prepareAutomaticAxisScaling(rScaleAutomatism, nDimIndex, nAxisIndex);
226 }
227 
228 void AxisUsage::setExplicitScaleAndIncrement(
229     sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc )
230 {
231     std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex);
232     for (VCoordinateSystem* i : aVCooSysList)
233         i->setExplicitScaleAndIncrement(nDimIndex, nAxisIndex, rScale, rInc);
234 }
235 
236 typedef std::vector<std::unique_ptr<VSeriesPlotter> > SeriesPlottersType;
237 
238 /** This class is a container of `SeriesPlotter` objects (such as `PieChart`
239  *  instances). It is used for initializing coordinate systems, axes and scales
240  *  of all series plotters which belongs to the container.
241  */
242 class SeriesPlotterContainer
243 {
244 public:
245     explicit SeriesPlotterContainer( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList );
246     ~SeriesPlotterContainer();
247 
248     /** It is used to set coordinate systems (`m_rVCooSysList`), this method
249      *  is invoked by `ChartView::createShapes2D` before of
250      *  `ChartView::impl_createDiagramAndContent`.
251      *  Coordinate systems are retrieved through the `XCoordinateSystemContainer`
252      *  interface implemented by a diagram object which is provided by the
253      *  `ChartModel` object passed to the method (`rChartModel.getFirstDiagram()`).
254      *
255      *  It is used for creating series plotters and appending them
256      *  to `m_aSeriesPlotterList`. The created series plotters are initialized
257      *  through data (number formats supplier, color scheme, data series),
258      *  extracted from the chart model or the diagram objects. An exception is
259      *  the explicit category provider that is retrieved through the
260      *  `VCoordinateSystem` object used by the series plotter.
261      *
262      *  It sets the minimum-maximum supplier for a coordinate system:
263      *  this supplier is the series plotter itself which utilizes the given
264      *  coordinate system. In fact `VSeriesPlotter` has `MinimumMaximumSupplier`
265      *  as one of its base classes.
266      *  Hence, for instance, a `PieChart`, which is a series plotter, is
267      *  a `MinimumMaximumSupplier`, too.
268      */
269     void initializeCooSysAndSeriesPlotter( ChartModel& rModel );
270 
271     /** This method is invoked by `ChartView::impl_createDiagramAndContent`.
272      *  It iterates on every axis of every coordinate systems, and if the axis
273      *  is not yet present in `m_aAxisUsageList` it creates a new `AxisUsage`
274      *  object and initialize its `aAutoScaling` member to the `ScaleData`
275      *  object of the current axis.
276      */
277     void initAxisUsageList(const Date& rNullDate);
278 
279     /**
280      * Perform automatic axis scaling and determine the amount and spacing of
281      * increments.  It assumes that the caller has determined the size of the
282      * largest axis label text object prior to calling this method.
283      *
284      * The new axis scaling data will be stored in the VCoordinateSystem
285      * objects.  The label alignment direction for each axis will also get
286      * determined during this process, and stored in VAxis.
287      *
288      * This method is invoked by `ChartView::impl_createDiagramAndContent`
289      * soon after `initAxisUsageList`.
290      * It initializes explicit scale and increment objects for all coordinate
291      * systems in `m_rVCooSysList`.
292      * This action is achieved by iterating on the `m_aAxisUsageList` container,
293      * and performing 3 steps:
294      *   1- call `VCoordinateSystem::prepareAutomaticAxisScaling` for setting
295      *      scaling parameters of the `aAutoScaling` member (a `ScaleAutomatism`
296      *      object) for the current `AxisUsage` instance
297      *      (see `VCoordinateSystem::prepareAutomaticAxisScaling`);
298      *   2- calculate the explicit scale and increment objects
299      *      (see ScaleAutomatism::calculateExplicitScaleAndIncrement);
300      *   3- set the explicit scale and increment objects for each coordinate
301      *      system.
302      */
303     void doAutoScaling( ChartModel& rModel );
304 
305     /**
306      * After auto-scaling is performed, call this method to set the explicit
307      * scaling and increment data to all relevant VAxis objects.
308      */
309     void updateScalesAndIncrementsOnAxes();
310 
311     /**
312      * After auto-scaling is performed, call this method to set the explicit
313      * scaling data to all the plotters.
314      */
315     void setScalesFromCooSysToPlotter();
316 
317     void setNumberFormatsFromAxes();
318     drawing::Direction3D getPreferredAspectRatio();
319 
320     SeriesPlottersType& getSeriesPlotterList() { return m_aSeriesPlotterList; }
321     std::vector< std::unique_ptr<VCoordinateSystem> >& getCooSysList() { return m_rVCooSysList; }
322     std::vector< LegendEntryProvider* > getLegendEntryProviderList();
323 
324     void AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel );
325 
326     bool isCategoryPositionShifted(
327         const chart2::ScaleData& rSourceScale, bool bHasComplexCategories ) const;
328 
329 private:
330     /** A vector of series plotters.
331      */
332     SeriesPlottersType m_aSeriesPlotterList;
333 
334     /** A vector of coordinate systems.
335      */
336     std::vector< std::unique_ptr<VCoordinateSystem> >& m_rVCooSysList;
337 
338     /** A map whose key is a `XAxis` interface and the related value is
339      *  an object of `AxisUsage` type.
340      */
341     std::map< uno::Reference< XAxis >, AxisUsage > m_aAxisUsageList;
342 
343     /**
344      * Max axis index of all dimensions.  Currently this can be either 0 or 1
345      * since we only support primary and secondary axes per dimension.  The
346      * value of 0 means all dimensions have only primary axis, while 1 means
347      * at least one dimension has a secondary axis.
348      */
349     sal_Int32 m_nMaxAxisIndex;
350 
351     bool m_bChartTypeUsesShiftedCategoryPositionPerDefault;
352     sal_Int32 m_nDefaultDateNumberFormat;
353 };
354 
355 SeriesPlotterContainer::SeriesPlotterContainer( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList )
356         : m_rVCooSysList( rVCooSysList )
357         , m_nMaxAxisIndex(0)
358         , m_bChartTypeUsesShiftedCategoryPositionPerDefault(false)
359         , m_nDefaultDateNumberFormat(0)
360 {
361 }
362 
363 SeriesPlotterContainer::~SeriesPlotterContainer()
364 {
365     // - remove plotter from coordinatesystems
366     for(auto & nC : m_rVCooSysList)
367         nC->clearMinimumAndMaximumSupplierList();
368 }
369 
370 std::vector< LegendEntryProvider* > SeriesPlotterContainer::getLegendEntryProviderList()
371 {
372     std::vector< LegendEntryProvider* > aRet( m_aSeriesPlotterList.size() );
373     sal_Int32 nN = 0;
374     for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList)
375         aRet[nN++] = aPlotter.get();
376     return aRet;
377 }
378 
379 VCoordinateSystem* findInCooSysList( const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList
380                                     , const uno::Reference< XCoordinateSystem >& xCooSys )
381 {
382     for(auto & pVCooSys : rVCooSysList)
383     {
384         if(pVCooSys->getModel()==xCooSys)
385             return pVCooSys.get();
386     }
387     return nullptr;
388 }
389 
390 VCoordinateSystem* lcl_getCooSysForPlotter( const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList, MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier )
391 {
392     if(!pMinimumAndMaximumSupplier)
393         return nullptr;
394     for(auto & pVCooSys : rVCooSysList)
395     {
396         if(pVCooSys->hasMinimumAndMaximumSupplier( pMinimumAndMaximumSupplier ))
397             return pVCooSys.get();
398     }
399     return nullptr;
400 }
401 
402 VCoordinateSystem* addCooSysToList( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList
403             , const uno::Reference< XCoordinateSystem >& xCooSys
404             , ChartModel& rChartModel )
405 {
406     VCoordinateSystem* pExistingVCooSys = findInCooSysList( rVCooSysList, xCooSys );
407     if( pExistingVCooSys )
408         return pExistingVCooSys;
409 
410     std::unique_ptr<VCoordinateSystem> pVCooSys = VCoordinateSystem::createCoordinateSystem(xCooSys );
411     if(!pVCooSys)
412         return nullptr;
413 
414     OUString aCooSysParticle( ObjectIdentifier::createParticleForCoordinateSystem( xCooSys, rChartModel ) );
415     pVCooSys->setParticle(aCooSysParticle);
416 
417     pVCooSys->setExplicitCategoriesProvider( new ExplicitCategoriesProvider(xCooSys, rChartModel) );
418     rVCooSysList.push_back( std::move(pVCooSys) );
419     return rVCooSysList.back().get();
420 }
421 
422 void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter(
423               ChartModel& rChartModel )
424 {
425     uno::Reference< XDiagram > xDiagram( rChartModel.getFirstDiagram() );
426     if( !xDiagram.is())
427         return;
428 
429     uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( static_cast< ::cppu::OWeakObject* >( &rChartModel ), uno::UNO_QUERY );
430     if( rChartModel.hasInternalDataProvider() && DiagramHelper::isSupportingDateAxis( xDiagram ) )
431             m_nDefaultDateNumberFormat=DiagramHelper::getDateNumberFormat( xNumberFormatsSupplier );
432 
433     sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
434     if(!nDimensionCount)
435     {
436         //@todo handle mixed dimension
437         nDimensionCount = 2;
438     }
439 
440     bool bSortByXValues = false;
441     bool bConnectBars = false;
442     bool bGroupBarsPerAxis = true;
443     bool bIncludeHiddenCells = true;
444     sal_Int32 nStartingAngle = 90;
445     sal_Int32 n3DRelativeHeight = 100;
446     try
447     {
448         uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY_THROW );
449         xDiaProp->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= bSortByXValues;
450         xDiaProp->getPropertyValue( "ConnectBars" ) >>= bConnectBars;
451         xDiaProp->getPropertyValue( "GroupBarsPerAxis" ) >>= bGroupBarsPerAxis;
452         xDiaProp->getPropertyValue( "IncludeHiddenCells" ) >>= bIncludeHiddenCells;
453         xDiaProp->getPropertyValue( "StartingAngle" ) >>= nStartingAngle;
454 
455         if (nDimensionCount == 3)
456         {
457             xDiaProp->getPropertyValue( "3DRelativeHeight" ) >>= n3DRelativeHeight;
458         }
459     }
460     catch( const uno::Exception & )
461     {
462         DBG_UNHANDLED_EXCEPTION("chart2" );
463     }
464 
465     //prepare for autoscaling and shape creation
466     // - create plotter for charttypes (for each first scale group at each plotter, as they are independent)
467     // - add series to plotter (thus each charttype can provide minimum and maximum values for autoscaling)
468     // - add plotter to coordinate systems
469 
470     //iterate through all coordinate systems
471     uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
472     OSL_ASSERT( xCooSysContainer.is());
473     if( !xCooSysContainer.is())
474         return;
475     uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme());
476     uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
477     sal_Int32 nGlobalSeriesIndex = 0;//for automatic symbols
478     for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
479     {
480         uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
481         VCoordinateSystem* pVCooSys = addCooSysToList(m_rVCooSysList,xCooSys,rChartModel);
482 
483         //iterate through all chart types in the current coordinate system
484         uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
485         OSL_ASSERT( xChartTypeContainer.is());
486         if( !xChartTypeContainer.is() )
487             continue;
488         uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
489         for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
490         {
491             uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
492             if(nDimensionCount == 3 && xChartType->getChartType().equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE))
493             {
494                 uno::Reference< beans::XPropertySet > xPropertySet( xChartType, uno::UNO_QUERY );
495                 if (xPropertySet.is())
496                 {
497                     try
498                     {
499                         sal_Int32 n3DRelativeHeightOldValue(100);
500                         uno::Any aAny = xPropertySet->getPropertyValue( "3DRelativeHeight" );
501                         aAny >>= n3DRelativeHeightOldValue;
502                         if (n3DRelativeHeightOldValue != n3DRelativeHeight)
503                             xPropertySet->setPropertyValue( "3DRelativeHeight", uno::Any(n3DRelativeHeight) );
504                     }
505                     catch (const uno::Exception&) { }
506                 }
507             }
508 
509             if(nT==0)
510                 m_bChartTypeUsesShiftedCategoryPositionPerDefault = ChartTypeHelper::shiftCategoryPosAtXAxisPerDefault( xChartType );
511 
512             bool bExcludingPositioning = DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_EXCLUDING;
513             VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( xChartType, nDimensionCount, bExcludingPositioning );
514             if( !pPlotter )
515                 continue;
516 
517             m_aSeriesPlotterList.push_back( std::unique_ptr<VSeriesPlotter>(pPlotter) );
518             pPlotter->setNumberFormatsSupplier( xNumberFormatsSupplier );
519             pPlotter->setColorScheme( xColorScheme );
520             if(pVCooSys)
521                 pPlotter->setExplicitCategoriesProvider( pVCooSys->getExplicitCategoriesProvider() );
522             sal_Int32 nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( xDiagram, xChartType );
523 
524             if(pVCooSys)
525                 pVCooSys->addMinimumAndMaximumSupplier(pPlotter);
526 
527             uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
528             OSL_ASSERT( xDataSeriesContainer.is());
529             if( !xDataSeriesContainer.is() )
530                 continue;
531 
532             sal_Int32 zSlot=-1;
533             sal_Int32 xSlot=-1;
534             sal_Int32 ySlot=-1;
535             uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
536             for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
537             {
538                 uno::Reference< XDataSeries > xDataSeries( aSeriesList[nS], uno::UNO_QUERY );
539                 if(!xDataSeries.is())
540                     continue;
541                 if( !bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries) )
542                     continue;
543 
544                 std::unique_ptr<VDataSeries> pSeries(new VDataSeries( xDataSeries ));
545 
546                 pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex);
547                 nGlobalSeriesIndex++;
548 
549                 if( bSortByXValues )
550                     pSeries->doSortByXValues();
551 
552                 pSeries->setConnectBars( bConnectBars );
553                 pSeries->setGroupBarsPerAxis( bGroupBarsPerAxis );
554                 pSeries->setStartingAngle( nStartingAngle );
555 
556                 pSeries->setMissingValueTreatment( nMissingValueTreatment );
557 
558                 OUString aSeriesParticle( ObjectIdentifier::createParticleForSeries( 0, nCS, nT, nS ) );
559                 pSeries->setParticle(aSeriesParticle);
560 
561                 OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) );
562                 pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole);
563 
564                 //ignore secondary axis for charttypes that do not support them
565                 if( pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX &&
566                     !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ) )
567                 {
568                     pSeries->setAttachedAxisIndex(MAIN_AXIS_INDEX);
569                 }
570 
571                 StackingDirection eDirection = pSeries->getStackingDirection();
572                 switch(eDirection)
573                 {
574                     case StackingDirection_NO_STACKING:
575                         xSlot++; ySlot=-1;
576                         if(zSlot<0)
577                             zSlot=0;
578                         break;
579                     case StackingDirection_Y_STACKING:
580                         ySlot++;
581                         if(xSlot<0)
582                             xSlot=0;
583                         if(zSlot<0)
584                             zSlot=0;
585                         break;
586                     case StackingDirection_Z_STACKING:
587                         zSlot++; xSlot=-1; ySlot=-1;
588                         break;
589                     default:
590                         // UNO enums have one additional auto-generated case
591                         break;
592                 }
593                 pPlotter->addSeries( std::move(pSeries), zSlot, xSlot, ySlot );
594             }
595         }
596     }
597 
598     //transport seriesnames to the coordinatesystems if needed
599     if( !m_aSeriesPlotterList.empty() )
600     {
601         uno::Sequence< OUString > aSeriesNames;
602         bool bSeriesNamesInitialized = false;
603         for(auto & pVCooSys : m_rVCooSysList)
604         {
605             if( pVCooSys->needSeriesNamesForAxis() )
606             {
607                 if(!bSeriesNamesInitialized)
608                 {
609                     aSeriesNames = m_aSeriesPlotterList[0]->getSeriesNames();
610                     bSeriesNamesInitialized = true;
611                 }
612                 pVCooSys->setSeriesNamesForAxis( aSeriesNames );
613             }
614         }
615     }
616 }
617 
618 bool SeriesPlotterContainer::isCategoryPositionShifted(
619     const chart2::ScaleData& rSourceScale, bool bHasComplexCategories ) const
620 {
621     if (rSourceScale.AxisType == AxisType::CATEGORY && m_bChartTypeUsesShiftedCategoryPositionPerDefault)
622         return true;
623 
624     if (rSourceScale.AxisType==AxisType::CATEGORY && bHasComplexCategories)
625         return true;
626 
627     if (rSourceScale.AxisType == AxisType::DATE)
628         return true;
629 
630     if (rSourceScale.AxisType == AxisType::SERIES)
631         return true;
632 
633     return false;
634 }
635 
636 void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate)
637 {
638     m_aAxisUsageList.clear();
639 
640     // Loop through coordinate systems in the diagram (though for now
641     // there should only be one coordinate system per diagram).
642     for (auto & pVCooSys : m_rVCooSysList)
643     {
644         uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel();
645         sal_Int32 nDimCount = xCooSys->getDimension();
646 
647         for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex)
648         {
649             bool bDateAxisAllowed = ChartTypeHelper::isSupportingDateAxis(
650                 AxisHelper::getChartTypeByIndex(xCooSys, 0), nDimIndex);
651 
652             // Each dimension may have primary and secondary axes.
653             const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
654             for (sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; ++nAxisIndex)
655             {
656                 uno::Reference<XAxis> xAxis = xCooSys->getAxisByDimension(nDimIndex, nAxisIndex);
657 
658                 if (!xAxis.is())
659                     continue;
660 
661                 if (m_aAxisUsageList.find(xAxis) == m_aAxisUsageList.end())
662                 {
663                     // Create axis usage object for this axis.
664 
665                     chart2::ScaleData aSourceScale = xAxis->getScaleData();
666                     ExplicitCategoriesProvider* pCatProvider = pVCooSys->getExplicitCategoriesProvider();
667                     if (nDimIndex == 0)
668                         AxisHelper::checkDateAxis( aSourceScale, pCatProvider, bDateAxisAllowed );
669 
670                     bool bHasComplexCat = pCatProvider && pCatProvider->hasComplexCategories();
671                     aSourceScale.ShiftedCategoryPosition = isCategoryPositionShifted(aSourceScale, bHasComplexCat);
672 
673                     m_aAxisUsageList[xAxis].aAutoScaling = ScaleAutomatism(aSourceScale, rNullDate);
674                 }
675 
676                 AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis];
677                 rAxisUsage.addCoordinateSystem(pVCooSys.get(), nDimIndex, nAxisIndex);
678             }
679         }
680     }
681 
682     // Determine the highest axis index of all dimensions.
683     m_nMaxAxisIndex = 0;
684     for (auto & pVCooSys : m_rVCooSysList)
685     {
686         uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel();
687         sal_Int32 nDimCount = xCooSys->getDimension();
688 
689         for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex)
690         {
691             for (auto & axisUsage : m_aAxisUsageList)
692             {
693                 sal_Int32 nLocalMax = axisUsage.second.getMaxAxisIndexForDimension(nDimIndex);
694                 if (m_nMaxAxisIndex < nLocalMax)
695                     m_nMaxAxisIndex = nLocalMax;
696             }
697         }
698     }
699 }
700 
701 void SeriesPlotterContainer::setScalesFromCooSysToPlotter()
702 {
703     //set scales to plotter to enable them to provide the preferred scene AspectRatio
704     for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
705     {
706         VSeriesPlotter* pSeriesPlotter = aPlotter.get();
707         VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter );
708         if(pVCooSys)
709         {
710             pSeriesPlotter->setScales( pVCooSys->getExplicitScales(0,0), pVCooSys->getPropertySwapXAndYAxis() );
711             sal_Int32 nMaxAxisIndex = pVCooSys->getMaximumAxisIndexByDimension(1);//only additional value axis are relevant for series plotter
712             for( sal_Int32 nI=1; nI<=nMaxAxisIndex; nI++ )
713                 pSeriesPlotter->addSecondaryValueScale( pVCooSys->getExplicitScale(1,nI), nI );
714         }
715     }
716 }
717 
718 void SeriesPlotterContainer::setNumberFormatsFromAxes()
719 {
720     //set numberformats to plotter to enable them to display the data labels in the numberformat of the axis
721     for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
722     {
723         VSeriesPlotter* pSeriesPlotter = aPlotter.get();
724         VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter );
725         if(pVCooSys)
726         {
727             AxesNumberFormats aAxesNumberFormats;
728             const uno::Reference< XCoordinateSystem >& xCooSys = pVCooSys->getModel();
729             sal_Int32 nDimensionCount = xCooSys->getDimension();
730             for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nDimensionCount; ++nDimensionIndex)
731             {
732                 const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
733                 for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex)
734                 {
735                     try
736                     {
737                         Reference< beans::XPropertySet > xAxisProp( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY );
738                         if( xAxisProp.is())
739                         {
740                             sal_Int32 nNumberFormatKey(0);
741                             if( xAxisProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey )
742                             {
743                                 aAxesNumberFormats.setFormat( nNumberFormatKey, nDimensionIndex, nAxisIndex );
744                             }
745                             else if( nDimensionIndex==0 )
746                             {
747                                 //provide a default date format for date axis with own data
748                                 aAxesNumberFormats.setFormat( m_nDefaultDateNumberFormat, nDimensionIndex, nAxisIndex );
749                             }
750                         }
751                     }
752                     catch( const lang::IndexOutOfBoundsException& e )
753                     {
754                         SAL_WARN("chart2", "Exception caught. " << e );
755                     }
756                 }
757             }
758             pSeriesPlotter->setAxesNumberFormats( aAxesNumberFormats );
759         }
760     }
761 }
762 
763 void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes()
764 {
765     for(auto & nC : m_rVCooSysList)
766         nC->updateScalesAndIncrementsOnAxes();
767 }
768 
769 void SeriesPlotterContainer::doAutoScaling( ChartModel& rChartModel )
770 {
771     if (m_aSeriesPlotterList.empty() || m_aAxisUsageList.empty())
772         // We need these two containers populated to do auto-scaling.  Bail out.
773         return;
774 
775     //iterate over the main scales first than secondary axis
776     for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; ++nAxisIndex)
777     {
778         // - first do autoscale for all x and z scales (because they are treated independent)
779         for (auto & axisUsage : m_aAxisUsageList)
780         {
781             AxisUsage& rAxisUsage = axisUsage.second;
782 
783             rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 0, nAxisIndex);
784             rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 2, nAxisIndex);
785 
786             ExplicitScaleData       aExplicitScale;
787             ExplicitIncrementData   aExplicitIncrement;
788             rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement );
789 
790             rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement);
791             rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement);
792         }
793 
794         // - second do autoscale for the dependent y scales (the coordinate systems are prepared with x and z scales already )
795         for (auto & axisUsage : m_aAxisUsageList)
796         {
797             AxisUsage& rAxisUsage = axisUsage.second;
798 
799             rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAxisIndex);
800 
801             ExplicitScaleData       aExplicitScale;
802             ExplicitIncrementData   aExplicitIncrement;
803             rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement );
804 
805             rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement);
806             rAxisUsage.setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScale, aExplicitIncrement);
807             rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement);
808         }
809     }
810     AdaptScaleOfYAxisWithoutAttachedSeries( rChartModel );
811 }
812 
813 void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel )
814 {
815     //issue #i80518#
816     for( sal_Int32 nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ )
817     {
818         for (auto & axisUsage : m_aAxisUsageList)
819         {
820             AxisUsage& rAxisUsage = axisUsage.second;
821             std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems( 1, nAxisIndex );
822             if( aVCooSysList_Y.empty() )
823                 continue;
824 
825             uno::Reference< XDiagram > xDiagram( rModel.getFirstDiagram() );
826             if (!xDiagram.is())
827                 continue;
828 
829             bool bSeriesAttachedToThisAxis = false;
830             sal_Int32 nAttachedAxisIndex = -1;
831             {
832                 std::vector< Reference< XDataSeries > > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
833                 for (auto const& series : aSeriesVector)
834                 {
835                     sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series);
836                     if( nAxisIndex == nCurrentIndex )
837                     {
838                         bSeriesAttachedToThisAxis = true;
839                         break;
840                     }
841                     else if( nAttachedAxisIndex<0 || nAttachedAxisIndex>nCurrentIndex )
842                         nAttachedAxisIndex=nCurrentIndex;
843                 }
844             }
845 
846             if (bSeriesAttachedToThisAxis || nAttachedAxisIndex < 0)
847                 continue;
848 
849             for(VCoordinateSystem* nC : aVCooSysList_Y)
850             {
851                 nC->prepareAutomaticAxisScaling( rAxisUsage.aAutoScaling, 1, nAttachedAxisIndex );
852 
853                 ExplicitScaleData aExplicitScaleSource = nC->getExplicitScale( 1,nAttachedAxisIndex );
854                 ExplicitIncrementData aExplicitIncrementSource = nC->getExplicitIncrement( 1,nAttachedAxisIndex );
855 
856                 ExplicitScaleData aExplicitScaleDest = nC->getExplicitScale( 1,nAxisIndex );
857                 ExplicitIncrementData aExplicitIncrementDest = nC->getExplicitIncrement( 1,nAxisIndex );
858 
859                 aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation;
860                 aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling;
861                 aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType;
862 
863                 aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue;
864 
865                 ScaleData aScale( rAxisUsage.aAutoScaling.getScale() );
866                 if( !aScale.Minimum.hasValue() )
867                 {
868                     bool bNewMinOK = true;
869                     double fMax=0.0;
870                     if( aScale.Maximum >>= fMax )
871                         bNewMinOK = (aExplicitScaleSource.Minimum <= fMax);
872                     if( bNewMinOK )
873                         aExplicitScaleDest.Minimum = aExplicitScaleSource.Minimum;
874                 }
875                 else
876                     aExplicitIncrementDest.BaseValue = aExplicitScaleDest.Minimum;
877 
878                 if( !aScale.Maximum.hasValue() )
879                 {
880                     bool bNewMaxOK = true;
881                     double fMin=0.0;
882                     if( aScale.Minimum >>= fMin )
883                         bNewMaxOK = (fMin <= aExplicitScaleSource.Maximum);
884                     if( bNewMaxOK )
885                         aExplicitScaleDest.Maximum = aExplicitScaleSource.Maximum;
886                 }
887                 if( !aScale.Origin.hasValue() )
888                     aExplicitScaleDest.Origin = aExplicitScaleSource.Origin;
889 
890                 if( !aScale.IncrementData.Distance.hasValue() )
891                     aExplicitIncrementDest.Distance = aExplicitIncrementSource.Distance;
892 
893                 bool bAutoMinorInterval = true;
894                 if( aScale.IncrementData.SubIncrements.getLength() )
895                     bAutoMinorInterval = !( aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() );
896                 if( bAutoMinorInterval )
897                 {
898                     if( !aExplicitIncrementDest.SubIncrements.empty() && !aExplicitIncrementSource.SubIncrements.empty() )
899                         aExplicitIncrementDest.SubIncrements[0].IntervalCount =
900                             aExplicitIncrementSource.SubIncrements[0].IntervalCount;
901                 }
902 
903                 nC->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScaleDest, aExplicitIncrementDest );
904             }
905         }
906     }
907 
908     if( AxisHelper::isAxisPositioningEnabled() )
909     {
910         //correct origin for y main axis (the origin is where the other main axis crosses)
911         sal_Int32 nAxisIndex=0;
912         sal_Int32 nDimensionIndex=1;
913         for (auto & axisUsage : m_aAxisUsageList)
914         {
915             AxisUsage& rAxisUsage = axisUsage.second;
916             std::vector< VCoordinateSystem* > aVCooSysList = rAxisUsage.getCoordinateSystems(nDimensionIndex,nAxisIndex);
917             size_t nC;
918             for( nC=0; nC < aVCooSysList.size(); nC++)
919             {
920                 ExplicitScaleData aExplicitScale( aVCooSysList[nC]->getExplicitScale( nDimensionIndex, nAxisIndex ) );
921                 ExplicitIncrementData aExplicitIncrement( aVCooSysList[nC]->getExplicitIncrement( nDimensionIndex, nAxisIndex ) );
922 
923                 Reference< chart2::XCoordinateSystem > xCooSys( aVCooSysList[nC]->getModel() );
924                 Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) );
925                 Reference< beans::XPropertySet > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ), uno::UNO_QUERY );
926 
927                 css::chart::ChartAxisPosition eCrossingMainAxisPos( css::chart::ChartAxisPosition_ZERO );
928                 if( xCrossingMainAxis.is() )
929                 {
930                     xCrossingMainAxis->getPropertyValue("CrossoverPosition") >>= eCrossingMainAxisPos;
931                     if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_VALUE )
932                     {
933                         double fValue = 0.0;
934                         xCrossingMainAxis->getPropertyValue("CrossoverValue") >>= fValue;
935                         aExplicitScale.Origin = fValue;
936                     }
937                     else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_ZERO )
938                         aExplicitScale.Origin = 0.0;
939                     else  if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_START )
940                         aExplicitScale.Origin = aExplicitScale.Minimum;
941                     else  if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_END )
942                         aExplicitScale.Origin = aExplicitScale.Maximum;
943                 }
944 
945                 aVCooSysList[nC]->setExplicitScaleAndIncrement( nDimensionIndex, nAxisIndex, aExplicitScale, aExplicitIncrement );
946             }
947         }
948     }
949 }
950 
951 drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio()
952 {
953     drawing::Direction3D aPreferredAspectRatio(1.0,1.0,1.0);
954 
955     //get a list of all preferred aspect ratios and combine them
956     //first with special demands wins (less or equal zero <-> arbitrary)
957     double fx, fy, fz;
958     fx = fy = fz = -1.0;
959     for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
960     {
961         drawing::Direction3D aSingleRatio( aPlotter->getPreferredDiagramAspectRatio() );
962         if( fx<0 && aSingleRatio.DirectionX>0 )
963             fx = aSingleRatio.DirectionX;
964 
965         if( fy<0 && aSingleRatio.DirectionY>0 )
966         {
967             if( fx>0 && aSingleRatio.DirectionX>0 )
968                 fy = fx*aSingleRatio.DirectionY/aSingleRatio.DirectionX;
969             else if( fz>0 && aSingleRatio.DirectionZ>0 )
970                 fy = fz*aSingleRatio.DirectionY/aSingleRatio.DirectionZ;
971             else
972                 fy = aSingleRatio.DirectionY;
973         }
974 
975         if( fz<0 && aSingleRatio.DirectionZ>0 )
976         {
977             if( fx>0 && aSingleRatio.DirectionX>0 )
978                 fz = fx*aSingleRatio.DirectionZ/aSingleRatio.DirectionX;
979             else if( fy>0 && aSingleRatio.DirectionY>0 )
980                 fz = fy*aSingleRatio.DirectionZ/aSingleRatio.DirectionY;
981             else
982                 fz = aSingleRatio.DirectionZ;
983         }
984 
985         if( fx>0 && fy>0 && fz>0 )
986             break;
987     }
988     aPreferredAspectRatio = drawing::Direction3D(fx, fy, fz);
989     return aPreferredAspectRatio;
990 }
991 
992 }
993 
994 struct CreateShapeParam2D
995 {
996     css::awt::Rectangle maRemainingSpace;
997 
998     std::shared_ptr<SeriesPlotterContainer> mpSeriesPlotterContainer;
999 
1000     std::shared_ptr<VTitle> mpVTitleX;
1001     std::shared_ptr<VTitle> mpVTitleY;
1002     std::shared_ptr<VTitle> mpVTitleZ;
1003 
1004     std::shared_ptr<VTitle> mpVTitleSecondX;
1005     std::shared_ptr<VTitle> mpVTitleSecondY;
1006 
1007     css::uno::Reference<css::drawing::XShape> mxMarkHandles;
1008     css::uno::Reference<css::drawing::XShape> mxPlotAreaWithAxes;
1009 
1010     css::uno::Reference<css::drawing::XShapes> mxDiagramWithAxesShapes;
1011 
1012     bool mbAutoPosTitleX;
1013     bool mbAutoPosTitleY;
1014     bool mbAutoPosTitleZ;
1015 
1016     bool mbAutoPosSecondTitleX;
1017     bool mbAutoPosSecondTitleY;
1018 
1019     bool mbUseFixedInnerSize;
1020 
1021     CreateShapeParam2D() :
1022         mbAutoPosTitleX(true),
1023         mbAutoPosTitleY(true),
1024         mbAutoPosTitleZ(true),
1025         mbAutoPosSecondTitleX(true),
1026         mbAutoPosSecondTitleY(true),
1027         mbUseFixedInnerSize(false) {}
1028 };
1029 
1030 const uno::Sequence<sal_Int8>& ExplicitValueProvider::getUnoTunnelId()
1031 {
1032     return theExplicitValueProviderUnoTunnelId::get().getSeq();
1033 }
1034 
1035 ExplicitValueProvider* ExplicitValueProvider::getExplicitValueProvider(
1036         const Reference< uno::XInterface >& xChartView )
1037 {
1038     ExplicitValueProvider* pExplicitValueProvider=nullptr;
1039 
1040     Reference< lang::XUnoTunnel > xTunnel( xChartView, uno::UNO_QUERY );
1041     if( xTunnel.is() )
1042     {
1043         pExplicitValueProvider = reinterpret_cast<ExplicitValueProvider*>(xTunnel->getSomething(
1044             ExplicitValueProvider::getUnoTunnelId() ));
1045     }
1046     return pExplicitValueProvider;
1047 }
1048 
1049 ChartView::ChartView(
1050         uno::Reference<uno::XComponentContext> const & xContext,
1051         ChartModel& rModel)
1052     : m_aMutex()
1053     , m_xCC(xContext)
1054     , mrChartModel(rModel)
1055     , m_xShapeFactory()
1056     , m_xDrawPage()
1057     , m_pDrawModelWrapper()
1058     , m_aListenerContainer( m_aMutex )
1059     , m_bViewDirty(true)
1060     , m_bInViewUpdate(false)
1061     , m_bViewUpdatePending(false)
1062     , m_bRefreshAddIn(true)
1063     , m_aPageResolution(1000,1000)
1064     , m_bPointsWereSkipped(false)
1065     , m_nScaleXNumerator(1)
1066     , m_nScaleXDenominator(1)
1067     , m_nScaleYNumerator(1)
1068     , m_nScaleYDenominator(1)
1069     , m_bSdrViewIsInEditMode(false)
1070     , m_aResultingDiagramRectangleExcludingAxes(0,0,0,0)
1071 {
1072     init();
1073 }
1074 
1075 void ChartView::init()
1076 {
1077     if( !m_pDrawModelWrapper.get() )
1078     {
1079         SolarMutexGuard aSolarGuard;
1080         m_pDrawModelWrapper = std::make_shared< DrawModelWrapper >();
1081         m_xShapeFactory = m_pDrawModelWrapper->getShapeFactory();
1082         m_xDrawPage = m_pDrawModelWrapper->getMainDrawPage();
1083         StartListening( m_pDrawModelWrapper->getSdrModel() );
1084     }
1085 }
1086 
1087 void SAL_CALL ChartView::initialize( const uno::Sequence< uno::Any >& )
1088 {
1089     init();
1090 }
1091 
1092 ChartView::~ChartView()
1093 {
1094     maTimeBased.maTimer.Stop();
1095     // #i120831#. In ChartView::initialize(), m_xShapeFactory is created from SdrModel::getUnoModel() and indirectly
1096     //   from SfxBaseModel, it needs call dispose() to make sure SfxBaseModel object is freed correctly.
1097     uno::Reference< lang::XComponent > xComp( m_xShapeFactory, uno::UNO_QUERY);
1098     if ( xComp.is() )
1099         xComp->dispose();
1100 
1101     if( m_pDrawModelWrapper.get() )
1102     {
1103         SolarMutexGuard aSolarGuard;
1104         EndListening( m_pDrawModelWrapper->getSdrModel() );
1105         m_pDrawModelWrapper.reset();
1106     }
1107     m_xDrawPage = nullptr;
1108     impl_deleteCoordinateSystems();
1109 }
1110 
1111 void ChartView::impl_deleteCoordinateSystems()
1112 {
1113     //delete all coordinate systems
1114     m_aVCooSysList.clear();
1115 }
1116 
1117 // datatransfer::XTransferable
1118 namespace
1119 {
1120 const OUString lcl_aGDIMetaFileMIMEType(
1121     "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" );
1122 const OUString lcl_aGDIMetaFileMIMETypeHighContrast(
1123     "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" );
1124 } // anonymous namespace
1125 
1126 void ChartView::getMetaFile( const uno::Reference< io::XOutputStream >& xOutStream
1127                            , bool bUseHighContrast )
1128 {
1129     if( !m_xDrawPage.is() )
1130         return;
1131 
1132     // creating the graphic exporter
1133     uno::Reference< drawing::XGraphicExportFilter > xExporter = drawing::GraphicExportFilter::create( m_xCC );
1134 
1135     uno::Sequence< beans::PropertyValue > aProps(3);
1136     aProps[0].Name = "FilterName";
1137     aProps[0].Value <<= OUString("SVM");
1138 
1139     aProps[1].Name = "OutputStream";
1140     aProps[1].Value <<= xOutStream;
1141 
1142     uno::Sequence< beans::PropertyValue > aFilterData(8);
1143     aFilterData[0].Name = "ExportOnlyBackground";
1144     aFilterData[0].Value <<= false;
1145     aFilterData[1].Name = "HighContrast";
1146     aFilterData[1].Value <<= bUseHighContrast;
1147 
1148     aFilterData[2].Name = "Version";
1149     const sal_Int32 nVersion = SOFFICE_FILEFORMAT_50;
1150     aFilterData[2].Value <<= nVersion;
1151 
1152     aFilterData[3].Name = "CurrentPage";
1153     aFilterData[3].Value <<= uno::Reference< uno::XInterface >( m_xDrawPage, uno::UNO_QUERY );
1154 
1155     //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
1156     aFilterData[4].Name = "ScaleXNumerator";
1157     aFilterData[4].Value <<= m_nScaleXNumerator;
1158     aFilterData[5].Name = "ScaleXDenominator";
1159     aFilterData[5].Value <<= m_nScaleXDenominator;
1160     aFilterData[6].Name = "ScaleYNumerator";
1161     aFilterData[6].Value <<= m_nScaleYNumerator;
1162     aFilterData[7].Name = "ScaleYDenominator";
1163     aFilterData[7].Value <<= m_nScaleYDenominator;
1164 
1165 
1166     aProps[2].Name = "FilterData";
1167     aProps[2].Value <<= aFilterData;
1168 
1169     xExporter->setSourceDocument( uno::Reference< lang::XComponent >( m_xDrawPage, uno::UNO_QUERY) );
1170     if( xExporter->filter( aProps ) )
1171     {
1172         xOutStream->flush();
1173         xOutStream->closeOutput();
1174         uno::Reference< io::XSeekable > xSeekable( xOutStream, uno::UNO_QUERY );
1175         if( xSeekable.is() )
1176             xSeekable->seek(0);
1177     }
1178 }
1179 
1180 uno::Any SAL_CALL ChartView::getTransferData( const datatransfer::DataFlavor& aFlavor )
1181 {
1182     bool bHighContrastMetaFile( aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast);
1183     uno::Any aRet;
1184     if( ! (bHighContrastMetaFile || aFlavor.MimeType == lcl_aGDIMetaFileMIMEType) )
1185         return aRet;
1186 
1187     update();
1188 
1189     SvMemoryStream aStream( 1024, 1024 );
1190     utl::OStreamWrapper* pStreamWrapper = new utl::OStreamWrapper( aStream );
1191 
1192     uno::Reference< io::XOutputStream > xOutStream( pStreamWrapper );
1193     uno::Reference< io::XInputStream > xInStream( pStreamWrapper );
1194     uno::Reference< io::XSeekable > xSeekable( pStreamWrapper );
1195 
1196     if( xOutStream.is() )
1197     {
1198         this->getMetaFile( xOutStream, bHighContrastMetaFile );
1199 
1200         if( xInStream.is() && xSeekable.is() )
1201         {
1202             xSeekable->seek(0);
1203             sal_Int32 nBytesToRead = xInStream->available();
1204             uno::Sequence< sal_Int8 > aSeq( nBytesToRead );
1205             xInStream->readBytes( aSeq, nBytesToRead);
1206             aRet <<= aSeq;
1207             xInStream->closeInput();
1208         }
1209     }
1210 
1211     return aRet;
1212 }
1213 uno::Sequence< datatransfer::DataFlavor > SAL_CALL ChartView::getTransferDataFlavors()
1214 {
1215     uno::Sequence< datatransfer::DataFlavor > aRet(2);
1216 
1217     aRet[0] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMEType,
1218         "GDIMetaFile",
1219         cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
1220     aRet[1] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast,
1221         "GDIMetaFile",
1222         cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
1223 
1224     return aRet;
1225 }
1226 sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
1227 {
1228     return ( aFlavor.MimeType == lcl_aGDIMetaFileMIMEType ||
1229              aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast );
1230 }
1231 
1232 // ____ XUnoTunnel ___
1233 ::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier )
1234 {
1235     if( aIdentifier.getLength() == 16 && memcmp( ExplicitValueProvider::getUnoTunnelId().getConstArray(),
1236                                                          aIdentifier.getConstArray(), 16 ) == 0 )
1237     {
1238         ExplicitValueProvider* pProvider = this;
1239         return reinterpret_cast<sal_Int64>(pProvider);
1240     }
1241     return 0;
1242 }
1243 
1244 // lang::XServiceInfo
1245 
1246 OUString SAL_CALL ChartView::getImplementationName()
1247 {
1248     return OUString(CHART_VIEW_SERVICE_IMPLEMENTATION_NAME);
1249 }
1250 
1251 sal_Bool SAL_CALL ChartView::supportsService( const OUString& rServiceName )
1252 {
1253     return cppu::supportsService(this, rServiceName);
1254 }
1255 
1256 css::uno::Sequence< OUString > SAL_CALL ChartView::getSupportedServiceNames()
1257 {
1258     return { CHART_VIEW_SERVICE_NAME };
1259 }
1260 
1261 static ::basegfx::B3DHomMatrix createTransformationSceneToScreen(
1262     const ::basegfx::B2IRectangle& rDiagramRectangleWithoutAxes )
1263 {
1264     ::basegfx::B3DHomMatrix aM;
1265     aM.scale(double(rDiagramRectangleWithoutAxes.getWidth())/FIXED_SIZE_FOR_3D_CHART_VOLUME
1266             , -double(rDiagramRectangleWithoutAxes.getHeight())/FIXED_SIZE_FOR_3D_CHART_VOLUME, 1.0 );
1267     aM.translate(double(rDiagramRectangleWithoutAxes.getMinX())
1268         , double(rDiagramRectangleWithoutAxes.getMinY()+rDiagramRectangleWithoutAxes.getHeight()-1), 0);
1269     return aM;
1270 }
1271 
1272 namespace
1273 {
1274 
1275 bool lcl_IsPieOrDonut( const uno::Reference< XDiagram >& xDiagram )
1276 {
1277     //special treatment for pie charts
1278     //the size is checked after complete creation to get the datalabels into the given space
1279 
1280     //todo: this is just a workaround at the moment for pie and donut labels
1281     return DiagramHelper::isPieOrDonutChart( xDiagram );
1282 }
1283 
1284 void lcl_setDefaultWritingMode( const std::shared_ptr< DrawModelWrapper >& pDrawModelWrapper, ChartModel& rModel)
1285 {
1286     //get writing mode from parent document:
1287     if( SvtLanguageOptions().IsCTLFontEnabled() )
1288     {
1289         try
1290         {
1291             sal_Int16 nWritingMode=-1;
1292             uno::Reference< beans::XPropertySet > xParentProps( rModel.getParent(), uno::UNO_QUERY );
1293             uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSupplier( xParentProps, uno::UNO_QUERY );
1294             if( xStyleFamiliesSupplier.is() )
1295             {
1296                 uno::Reference< container::XNameAccess > xStylesFamilies( xStyleFamiliesSupplier->getStyleFamilies() );
1297                 if( xStylesFamilies.is() )
1298                 {
1299                     if( !xStylesFamilies->hasByName( "PageStyles" ) )
1300                     {
1301                         //draw/impress is parent document
1302                         uno::Reference< lang::XMultiServiceFactory > xFatcory( xParentProps, uno::UNO_QUERY );
1303                         if( xFatcory.is() )
1304                         {
1305                             uno::Reference< beans::XPropertySet > xDrawDefaults( xFatcory->createInstance( "com.sun.star.drawing.Defaults" ), uno::UNO_QUERY );
1306                             if( xDrawDefaults.is() )
1307                                 xDrawDefaults->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1308                         }
1309                     }
1310                     else
1311                     {
1312                         uno::Reference< container::XNameAccess > xPageStyles( xStylesFamilies->getByName( "PageStyles" ), uno::UNO_QUERY );
1313                         if( xPageStyles.is() )
1314                         {
1315                             OUString aPageStyle;
1316 
1317                             uno::Reference< text::XTextDocument > xTextDocument( xParentProps, uno::UNO_QUERY );
1318                             if( xTextDocument.is() )
1319                             {
1320                                 //writer is parent document
1321                                 //retrieve the current page style from the text cursor property PageStyleName
1322 
1323                                 uno::Reference< text::XTextEmbeddedObjectsSupplier > xTextEmbeddedObjectsSupplier( xTextDocument, uno::UNO_QUERY );
1324                                 if( xTextEmbeddedObjectsSupplier.is() )
1325                                 {
1326                                     uno::Reference< container::XNameAccess > xEmbeddedObjects( xTextEmbeddedObjectsSupplier->getEmbeddedObjects() );
1327                                     if( xEmbeddedObjects.is() )
1328                                     {
1329                                         uno::Sequence< OUString > aNames( xEmbeddedObjects->getElementNames() );
1330 
1331                                         sal_Int32 nCount = aNames.getLength();
1332                                         for( sal_Int32 nN=0; nN<nCount; nN++ )
1333                                         {
1334                                             uno::Reference< beans::XPropertySet > xEmbeddedProps( xEmbeddedObjects->getByName( aNames[nN] ), uno::UNO_QUERY );
1335                                             if( xEmbeddedProps.is() )
1336                                             {
1337                                                 static OUString aChartCLSID = SvGlobalName( SO3_SCH_CLASSID ).GetHexName();
1338                                                 OUString aCLSID;
1339                                                 xEmbeddedProps->getPropertyValue( "CLSID" ) >>= aCLSID;
1340                                                 if( aCLSID == aChartCLSID )
1341                                                 {
1342                                                     uno::Reference< text::XTextContent > xEmbeddedObject( xEmbeddedProps, uno::UNO_QUERY );
1343                                                     if( xEmbeddedObject.is() )
1344                                                     {
1345                                                         uno::Reference< text::XTextRange > xAnchor( xEmbeddedObject->getAnchor() );
1346                                                         if( xAnchor.is() )
1347                                                         {
1348                                                             uno::Reference< beans::XPropertySet > xAnchorProps( xAnchor, uno::UNO_QUERY );
1349                                                             if( xAnchorProps.is() )
1350                                                             {
1351                                                                 xAnchorProps->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1352                                                             }
1353                                                             uno::Reference< text::XText > xText( xAnchor->getText() );
1354                                                             if( xText.is() )
1355                                                             {
1356                                                                 uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY );
1357                                                                 if( xTextCursorProps.is() )
1358                                                                     xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle;
1359                                                             }
1360                                                         }
1361                                                     }
1362                                                     break;
1363                                                 }
1364                                             }
1365                                         }
1366                                     }
1367                                 }
1368                                 if( aPageStyle.isEmpty() )
1369                                 {
1370                                     uno::Reference< text::XText > xText( xTextDocument->getText() );
1371                                     if( xText.is() )
1372                                     {
1373                                         uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY );
1374                                         if( xTextCursorProps.is() )
1375                                             xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle;
1376                                     }
1377                                 }
1378                             }
1379                             else
1380                             {
1381                                 //Calc is parent document
1382                                 xParentProps->getPropertyValue( "PageStyle" ) >>= aPageStyle;
1383                                 if(aPageStyle.isEmpty())
1384                                     aPageStyle = "Default";
1385                             }
1386                             if( nWritingMode == -1 || nWritingMode == text::WritingMode2::PAGE )
1387                             {
1388                                 uno::Reference< beans::XPropertySet > xPageStyle( xPageStyles->getByName( aPageStyle ), uno::UNO_QUERY );
1389                                 if( xPageStyle.is() )
1390                                     xPageStyle->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1391                             }
1392                         }
1393                     }
1394                 }
1395             }
1396             if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE )
1397             {
1398                 if( pDrawModelWrapper.get() )
1399                     pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SvxFrameDirectionItem(static_cast<SvxFrameDirection>(nWritingMode), EE_PARA_WRITINGDIR) );
1400             }
1401         }
1402         catch( const uno::Exception& )
1403         {
1404             DBG_UNHANDLED_EXCEPTION("chart2" );
1405         }
1406     }
1407 }
1408 
1409 sal_Int16 lcl_getDefaultWritingModeFromPool( const std::shared_ptr<DrawModelWrapper>& pDrawModelWrapper )
1410 {
1411     sal_Int16 nWritingMode = text::WritingMode2::LR_TB;
1412     if(!pDrawModelWrapper)
1413         return nWritingMode;
1414 
1415     const SfxPoolItem& rItem = pDrawModelWrapper->GetItemPool().GetDefaultItem(EE_PARA_WRITINGDIR);
1416     nWritingMode
1417         = static_cast<sal_Int16>(static_cast<const SvxFrameDirectionItem&>(rItem).GetValue());
1418     return nWritingMode;
1419 }
1420 
1421 } //end anonymous namespace
1422 
1423 awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D& rParam, const awt::Size& rPageSize )
1424 {
1425     //return the used rectangle
1426     awt::Rectangle aUsedOuterRect(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y, 0, 0);
1427 
1428     uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() );
1429     if( !xDiagram.is())
1430         return aUsedOuterRect;
1431 
1432     sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
1433     if(!nDimensionCount)
1434     {
1435         //@todo handle mixed dimension
1436         nDimensionCount = 2;
1437     }
1438 
1439     basegfx::B2IRectangle aAvailableOuterRect = BaseGFXHelper::makeRectangle(rParam.maRemainingSpace);
1440 
1441     const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList( rParam.mpSeriesPlotterContainer->getCooSysList() );
1442     SeriesPlottersType& rSeriesPlotterList = rParam.mpSeriesPlotterContainer->getSeriesPlotterList();
1443 
1444     //create VAxis, so they can give necessary information for automatic scaling
1445     uno::Reference<chart2::XChartDocument> const xChartDoc(&mrChartModel);
1446     uno::Reference<util::XNumberFormatsSupplier> const xNumberFormatsSupplier(
1447             mrChartModel.getNumberFormatsSupplier());
1448     size_t nC = 0;
1449     for( nC=0; nC < rVCooSysList.size(); nC++)
1450     {
1451         VCoordinateSystem* pVCooSys = rVCooSysList[nC].get();
1452         if(nDimensionCount==3)
1453         {
1454             uno::Reference<beans::XPropertySet> xSceneProperties( xDiagram, uno::UNO_QUERY );
1455             CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xSceneProperties ) );
1456             CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xSceneProperties ) );
1457             CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xSceneProperties ) );
1458             pVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos );
1459         }
1460 
1461         pVCooSys->createVAxisList(xChartDoc, rPageSize, rParam.maRemainingSpace, rParam.mbUseFixedInnerSize);
1462     }
1463 
1464     // - prepare list of all axis and how they are used
1465     Date aNullDate = NumberFormatterWrapper( xNumberFormatsSupplier ).getNullDate();
1466     rParam.mpSeriesPlotterContainer->initAxisUsageList(aNullDate);
1467     rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel );
1468     rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter();
1469     rParam.mpSeriesPlotterContainer->setNumberFormatsFromAxes();
1470 
1471     //create shapes
1472 
1473     //aspect ratio
1474     drawing::Direction3D aPreferredAspectRatio =
1475         rParam.mpSeriesPlotterContainer->getPreferredAspectRatio();
1476 
1477     uno::Reference< drawing::XShapes > xSeriesTargetInFrontOfAxis;
1478     uno::Reference< drawing::XShapes > xSeriesTargetBehindAxis;
1479     VDiagram aVDiagram(xDiagram, aPreferredAspectRatio, nDimensionCount);
1480     bool bIsPieOrDonut = lcl_IsPieOrDonut(xDiagram);
1481     {//create diagram
1482         aVDiagram.init(rParam.mxDiagramWithAxesShapes, m_xShapeFactory);
1483         aVDiagram.createShapes(
1484             awt::Point(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y),
1485             awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height));
1486 
1487         xSeriesTargetInFrontOfAxis = aVDiagram.getCoordinateRegion();
1488         // It is preferable to use full size than minimum for pie charts
1489         if (!bIsPieOrDonut && !rParam.mbUseFixedInnerSize)
1490             aVDiagram.reduceToMimimumSize();
1491     }
1492 
1493     uno::Reference< drawing::XShapes > xTextTargetShapes =
1494         ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory)->createGroup2D(rParam.mxDiagramWithAxesShapes);
1495 
1496     // - create axis and grids for all coordinate systems
1497 
1498     //init all coordinate systems
1499     for( nC=0; nC < rVCooSysList.size(); nC++)
1500     {
1501         VCoordinateSystem* pVCooSys = rVCooSysList[nC].get();
1502         pVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis,xTextTargetShapes,m_xShapeFactory,xSeriesTargetBehindAxis);
1503 
1504         pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1505             createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1506 
1507         pVCooSys->initVAxisInList();
1508     }
1509 
1510     //calculate resulting size respecting axis label layout and fontscaling
1511 
1512     uno::Reference< drawing::XShape > xBoundingShape(rParam.mxDiagramWithAxesShapes, uno::UNO_QUERY);
1513     ::basegfx::B2IRectangle aConsumedOuterRect;
1514 
1515     //use first coosys only so far; todo: calculate for more than one coosys if we have more in future
1516     //todo: this is just a workaround at the moment for pie and donut labels
1517     if( !bIsPieOrDonut && (!rVCooSysList.empty()) )
1518     {
1519         VCoordinateSystem* pVCooSys = rVCooSysList[0].get();
1520         pVCooSys->createMaximumAxesLabels();
1521 
1522         aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape);
1523         ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() );
1524         if (!rParam.mbUseFixedInnerSize)
1525             aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect );
1526 
1527         pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1528             createTransformationSceneToScreen( aNewInnerRect ) ));
1529 
1530         //redo autoscaling to get size and text dependent automatic main increment count
1531         rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel );
1532         rParam.mpSeriesPlotterContainer->updateScalesAndIncrementsOnAxes();
1533         rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter();
1534 
1535         pVCooSys->createAxesLabels();
1536 
1537         bool bLessSpaceConsumedThanExpected = false;
1538         {
1539             aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape);
1540             if( aConsumedOuterRect.getMinX() > aAvailableOuterRect.getMinX()
1541                 || aConsumedOuterRect.getMaxX() < aAvailableOuterRect.getMaxX()
1542                 || aConsumedOuterRect.getMinY() > aAvailableOuterRect.getMinY()
1543                 || aConsumedOuterRect.getMinY() < aAvailableOuterRect.getMaxY() )
1544                 bLessSpaceConsumedThanExpected = true;
1545         }
1546 
1547         if (bLessSpaceConsumedThanExpected && !rParam.mbUseFixedInnerSize)
1548         {
1549             aVDiagram.adjustInnerSize( aConsumedOuterRect );
1550             pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1551                 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1552         }
1553         pVCooSys->updatePositions();//todo: logically this belongs to the condition above, but it seems also to be necessary to give the axes group shapes the right bounding rects for hit test -  probably caused by bug i106183 -> check again if fixed
1554     }
1555 
1556     //create axes and grids for the final size
1557     for( nC=0; nC < rVCooSysList.size(); nC++)
1558     {
1559         VCoordinateSystem* pVCooSys = rVCooSysList[nC].get();
1560 
1561         pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1562             createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1563 
1564         pVCooSys->createAxesShapes();
1565         pVCooSys->createGridShapes();
1566     }
1567 
1568     // - create data series for all charttypes
1569     m_bPointsWereSkipped = false;
1570     for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1571     {
1572         VSeriesPlotter* pSeriesPlotter = aPlotter.get();
1573         uno::Reference< drawing::XShapes > xSeriesTarget;
1574         if( pSeriesPlotter->WantToPlotInFrontOfAxisLine() )
1575             xSeriesTarget = xSeriesTargetInFrontOfAxis;
1576         else
1577         {
1578             xSeriesTarget = xSeriesTargetBehindAxis;
1579             OSL_ENSURE( !bIsPieOrDonut, "not implemented yet! - during a complete recreation this shape is destroyed so no series can be created anymore" );
1580         }
1581         pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,m_xShapeFactory,OUString() );
1582         pSeriesPlotter->setPageReferenceSize( rPageSize );
1583         VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter );
1584         if(nDimensionCount==2)
1585             pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() );
1586         //better performance for big data
1587         {
1588             //calculate resolution for coordinate system
1589             Sequence<sal_Int32> aCoordinateSystemResolution = pVCooSys->getCoordinateSystemResolution( rPageSize, m_aPageResolution );
1590             pSeriesPlotter->setCoordinateSystemResolution( aCoordinateSystemResolution );
1591         }
1592 
1593         pSeriesPlotter->createShapes();
1594         m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped();
1595     }
1596 
1597     //recreate all with corrected sizes if requested
1598     if( bIsPieOrDonut )
1599     {
1600         m_bPointsWereSkipped = false;
1601 
1602         aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape);
1603         ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() );
1604         if (!rParam.mbUseFixedInnerSize)
1605             aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect );
1606 
1607         for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1608         {
1609             aPlotter->releaseShapes();
1610         }
1611 
1612         //clear and recreate
1613         ShapeFactory::removeSubShapes( xSeriesTargetInFrontOfAxis ); //xSeriesTargetBehindAxis is a sub shape of xSeriesTargetInFrontOfAxis and will be removed here
1614         xSeriesTargetBehindAxis.clear();
1615         ShapeFactory::removeSubShapes( xTextTargetShapes );
1616 
1617         //set new transformation
1618         for( nC=0; nC < rVCooSysList.size(); nC++)
1619         {
1620             VCoordinateSystem* pVCooSys = rVCooSysList[nC].get();
1621             pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1622                 createTransformationSceneToScreen( aNewInnerRect ) ));
1623         }
1624 
1625         // - create data series for all charttypes
1626         for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1627         {
1628             VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, aPlotter.get() );
1629             if(nDimensionCount==2)
1630                 aPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() );
1631             aPlotter->createShapes();
1632             m_bPointsWereSkipped = m_bPointsWereSkipped || aPlotter->PointsWereSkipped();
1633         }
1634 
1635         for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1636             aPlotter->rearrangeLabelToAvoidOverlapIfRequested(rPageSize);
1637     }
1638 
1639     if (rParam.mbUseFixedInnerSize)
1640     {
1641         aUsedOuterRect = awt::Rectangle( aConsumedOuterRect.getMinX(), aConsumedOuterRect.getMinY(), aConsumedOuterRect.getWidth(), aConsumedOuterRect.getHeight() );
1642     }
1643     else
1644         aUsedOuterRect = rParam.maRemainingSpace;
1645 
1646     bool bSnapRectToUsedArea = false;
1647     for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1648     {
1649         bSnapRectToUsedArea = aPlotter->shouldSnapRectToUsedArea();
1650         if(bSnapRectToUsedArea)
1651             break;
1652     }
1653     if(bSnapRectToUsedArea)
1654     {
1655         if (rParam.mbUseFixedInnerSize)
1656             m_aResultingDiagramRectangleExcludingAxes = getRectangleOfObject( "PlotAreaExcludingAxes" );
1657         else
1658         {
1659             ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle();
1660             m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() );
1661         }
1662     }
1663     else
1664     {
1665         if (rParam.mbUseFixedInnerSize)
1666             m_aResultingDiagramRectangleExcludingAxes = rParam.maRemainingSpace;
1667         else
1668         {
1669             ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle();
1670             m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() );
1671         }
1672     }
1673 
1674     if (rParam.mxMarkHandles.is())
1675     {
1676         awt::Point aPos(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y);
1677         awt::Size  aSize(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height);
1678 
1679         bool bPosSizeExcludeAxesProperty = true;
1680         uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY_THROW );
1681         xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxesProperty;
1682         if (rParam.mbUseFixedInnerSize || bPosSizeExcludeAxesProperty)
1683         {
1684             aPos = awt::Point( m_aResultingDiagramRectangleExcludingAxes.X, m_aResultingDiagramRectangleExcludingAxes.Y );
1685             aSize = awt::Size( m_aResultingDiagramRectangleExcludingAxes.Width, m_aResultingDiagramRectangleExcludingAxes.Height );
1686         }
1687         rParam.mxMarkHandles->setPosition(aPos);
1688         rParam.mxMarkHandles->setSize(aSize);
1689     }
1690 
1691     return aUsedOuterRect;
1692 }
1693 
1694 bool ChartView::getExplicitValuesForAxis(
1695                      uno::Reference< XAxis > xAxis
1696                      , ExplicitScaleData&  rExplicitScale
1697                      , ExplicitIncrementData& rExplicitIncrement )
1698 {
1699     SolarMutexGuard aSolarGuard;
1700 
1701     impl_updateView();
1702 
1703     if(!xAxis.is())
1704         return false;
1705 
1706     uno::Reference< XCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstDiagram() ) );
1707     const VCoordinateSystem* pVCooSys = findInCooSysList(m_aVCooSysList,xCooSys);
1708     if(!pVCooSys)
1709         return false;
1710 
1711     sal_Int32 nDimensionIndex=-1;
1712     sal_Int32 nAxisIndex=-1;
1713     if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) )
1714     {
1715         rExplicitScale = pVCooSys->getExplicitScale(nDimensionIndex,nAxisIndex);
1716         rExplicitIncrement = pVCooSys->getExplicitIncrement(nDimensionIndex,nAxisIndex);
1717         if( rExplicitScale.ShiftedCategoryPosition )
1718         {
1719             //remove 'one' from max
1720             if( rExplicitScale.AxisType == css::chart2::AxisType::DATE )
1721             {
1722                 Date aMaxDate(rExplicitScale.NullDate); aMaxDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Maximum));
1723                 //for explicit scales with shifted categories we need one interval more
1724                 switch( rExplicitScale.TimeResolution )
1725                 {
1726                 case css::chart::TimeUnit::DAY:
1727                     --aMaxDate;
1728                     break;
1729                 case css::chart::TimeUnit::MONTH:
1730                     aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1);
1731                     break;
1732                 case css::chart::TimeUnit::YEAR:
1733                     aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1);
1734                     break;
1735                 }
1736                 rExplicitScale.Maximum = aMaxDate - rExplicitScale.NullDate;
1737             }
1738             else if( rExplicitScale.AxisType == css::chart2::AxisType::CATEGORY )
1739                 rExplicitScale.Maximum -= 1.0;
1740             else if( rExplicitScale.AxisType == css::chart2::AxisType::SERIES )
1741                 rExplicitScale.Maximum -= 1.0;
1742         }
1743         return true;
1744     }
1745     return false;
1746 }
1747 
1748 SdrPage* ChartView::getSdrPage()
1749 {
1750     SdrPage* pPage=nullptr;
1751     Reference< lang::XUnoTunnel> xUnoTunnel(m_xDrawPage,uno::UNO_QUERY);
1752     if(xUnoTunnel.is())
1753     {
1754         SvxDrawPage* pSvxDrawPage = reinterpret_cast<SvxDrawPage*>(xUnoTunnel->getSomething(
1755             SvxDrawPage::getUnoTunnelId() ));
1756         if(pSvxDrawPage)
1757         {
1758             pPage = pSvxDrawPage->GetSdrPage();
1759         }
1760     }
1761     return pPage;
1762 }
1763 
1764 uno::Reference< drawing::XShape > ChartView::getShapeForCID( const OUString& rObjectCID )
1765 {
1766     SolarMutexGuard aSolarGuard;
1767     SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() );
1768     if( pObj )
1769         return uno::Reference< drawing::XShape >( pObj->getUnoShape(), uno::UNO_QUERY);
1770     return nullptr;
1771 }
1772 
1773 awt::Rectangle ChartView::getDiagramRectangleExcludingAxes()
1774 {
1775     impl_updateView();
1776     return m_aResultingDiagramRectangleExcludingAxes;
1777 }
1778 
1779 awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool bSnapRect )
1780 {
1781     impl_updateView();
1782 
1783     awt::Rectangle aRet;
1784     uno::Reference< drawing::XShape > xShape( getShapeForCID(rObjectCID) );
1785     if(xShape.is())
1786     {
1787         //special handling for axis for old api:
1788         //same special handling for diagram
1789         ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) );
1790         if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_DIAGRAM )
1791         {
1792             SolarMutexGuard aSolarGuard;
1793             SvxShape* pRoot = SvxShape::getImplementation( xShape );
1794             if( pRoot )
1795             {
1796                 SdrObject* pRootSdrObject = pRoot->GetSdrObject();
1797                 if( pRootSdrObject )
1798                 {
1799                     SdrObjList* pRootList = pRootSdrObject->GetSubList();
1800                     if( pRootList )
1801                     {
1802                         OUString aShapeName = "MarkHandles";
1803                         if( eObjectType == OBJECTTYPE_DIAGRAM )
1804                             aShapeName = "PlotAreaIncludingAxes";
1805                         SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( aShapeName, pRootList );
1806                         if( pShape )
1807                             xShape.set( pShape->getUnoShape(), uno::UNO_QUERY);
1808                     }
1809                 }
1810             }
1811         }
1812 
1813         awt::Size aSize( xShape->getSize() );
1814         awt::Point aPoint( xShape->getPosition() );
1815         aRet = awt::Rectangle( aPoint.X, aPoint.Y, aSize.Width, aSize.Height );
1816         if( bSnapRect )
1817         {
1818             //for rotated objects the shape size and position differs from the visible rectangle
1819             SvxShape* pShape = SvxShape::getImplementation( xShape );
1820             if( pShape )
1821             {
1822                 SdrObject* pSdrObject = pShape->GetSdrObject();
1823                 if( pSdrObject )
1824                 {
1825                     tools::Rectangle aSnapRect( pSdrObject->GetSnapRect() );
1826                     aRet = awt::Rectangle(aSnapRect.Left(),aSnapRect.Top(),aSnapRect.GetWidth(),aSnapRect.GetHeight());
1827                 }
1828             }
1829         }
1830     }
1831     return aRet;
1832 }
1833 
1834 std::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper()
1835 {
1836     return m_pDrawModelWrapper;
1837 }
1838 
1839 namespace
1840 {
1841 sal_Int32 lcl_getDiagramTitleSpace()
1842 {
1843     return 200; //=0,2 cm spacing
1844 }
1845 bool lcl_getPropertySwapXAndYAxis( const uno::Reference< XDiagram >& xDiagram )
1846 {
1847     bool bSwapXAndY = false;
1848 
1849     uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
1850     if( xCooSysContainer.is() )
1851     {
1852         uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
1853         if( aCooSysList.getLength() )
1854         {
1855             uno::Reference<beans::XPropertySet> xProp(aCooSysList[0], uno::UNO_QUERY );
1856             if( xProp.is()) try
1857             {
1858                 xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY;
1859             }
1860             catch( const uno::Exception& e )
1861             {
1862                 SAL_WARN("chart2", "Exception caught. " << e );
1863             }
1864         }
1865     }
1866     return bSwapXAndY;
1867 }
1868 
1869 }
1870 
1871 sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForAxis(
1872                   const Reference< chart2::XAxis >& xAxis
1873                 , const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem
1874                 , const Reference<chart2::XChartDocument>& xChartDoc)
1875 {
1876     return AxisHelper::getExplicitNumberFormatKeyForAxis( xAxis, xCorrespondingCoordinateSystem, xChartDoc
1877         , true /*bSearchForParallelAxisIfNothingIsFound*/ );
1878 }
1879 
1880 sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel(
1881         const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp,
1882         const uno::Reference< XDataSeries >& xSeries,
1883         sal_Int32 nPointIndex /*-1 for whole series*/,
1884         const uno::Reference< XDiagram >& xDiagram
1885         )
1886 {
1887     sal_Int32 nFormat=0;
1888     if( !xSeriesOrPointProp.is() )
1889         return nFormat;
1890 
1891     bool bLinkToSource = true;
1892     try
1893     {
1894         xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource;
1895     }
1896     catch ( const beans::UnknownPropertyException& ) {}
1897 
1898     xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat;
1899     sal_Int32 nOldFormat = nFormat;
1900     if (bLinkToSource)
1901     {
1902         uno::Reference< chart2::XChartType > xChartType( DataSeriesHelper::getChartTypeOfSeries( xSeries, xDiagram ) );
1903 
1904         bool bFormatFound = false;
1905         if( ChartTypeHelper::shouldLabelNumberFormatKeyBeDetectedFromYAxis( xChartType ) )
1906         {
1907             uno::Reference< beans::XPropertySet > xAttachedAxisProps( DiagramHelper::getAttachedAxis( xSeries, xDiagram ), uno::UNO_QUERY );
1908             if (xAttachedAxisProps.is() && (xAttachedAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat))
1909                 bFormatFound = true;
1910         }
1911         if( !bFormatFound )
1912         {
1913             Reference< chart2::data::XDataSource > xSeriesSource( xSeries, uno::UNO_QUERY );
1914             OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) );
1915 
1916             Reference< data::XLabeledDataSequence > xLabeledSequence(
1917                 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, aRole ));
1918             if( xLabeledSequence.is() )
1919             {
1920                 Reference< data::XDataSequence > xValues( xLabeledSequence->getValues() );
1921                 if( xValues.is() )
1922                     nFormat = xValues->getNumberFormatKeyByIndex( nPointIndex );
1923             }
1924         }
1925 
1926         if (nFormat >= 0 && nOldFormat != nFormat)
1927             xSeriesOrPointProp->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any(nFormat));
1928     }
1929 
1930     if(nFormat<0)
1931         nFormat=0;
1932     return nFormat;
1933 }
1934 
1935 sal_Int32 ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel(
1936         const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp,
1937         const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1938 {
1939     sal_Int32 nFormat=0;
1940     if( !xSeriesOrPointProp.is() )
1941         return nFormat;
1942     if( !(xSeriesOrPointProp->getPropertyValue("PercentageNumberFormat") >>= nFormat) )
1943     {
1944         nFormat = DiagramHelper::getPercentNumberFormat( xNumberFormatsSupplier );
1945     }
1946     if(nFormat<0)
1947         nFormat=0;
1948     return nFormat;
1949 }
1950 
1951 awt::Rectangle ExplicitValueProvider::AddSubtractAxisTitleSizes(
1952             ChartModel& rModel
1953             , const Reference< uno::XInterface >& xChartView
1954             , const awt::Rectangle& rPositionAndSize, bool bSubtract )
1955 {
1956     awt::Rectangle aRet(rPositionAndSize);
1957 
1958     //add axis title sizes to the diagram size
1959     uno::Reference< chart2::XTitle > xTitle_Height( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, rModel ) );
1960     uno::Reference< chart2::XTitle > xTitle_Width( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, rModel ) );
1961     uno::Reference< chart2::XTitle > xSecondTitle_Height( TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, rModel ) );
1962     uno::Reference< chart2::XTitle > xSecondTitle_Width( TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, rModel ) );
1963     if( xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() || xSecondTitle_Width.is() )
1964     {
1965         ExplicitValueProvider* pExplicitValueProvider = ExplicitValueProvider::getExplicitValueProvider(xChartView);
1966         if( pExplicitValueProvider )
1967         {
1968             //detect whether x axis points into x direction or not
1969             if( lcl_getPropertySwapXAndYAxis( rModel.getFirstDiagram() ) )
1970             {
1971                 std::swap( xTitle_Height, xTitle_Width );
1972                 std::swap( xSecondTitle_Height, xSecondTitle_Width );
1973             }
1974 
1975             sal_Int32 nTitleSpaceWidth = 0;
1976             sal_Int32 nTitleSpaceHeight = 0;
1977             sal_Int32 nSecondTitleSpaceWidth = 0;
1978             sal_Int32 nSecondTitleSpaceHeight = 0;
1979 
1980             if( xTitle_Height.is() )
1981             {
1982                 OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Height, rModel ) );
1983                 nTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height;
1984                 if( nTitleSpaceHeight )
1985                     nTitleSpaceHeight+=lcl_getDiagramTitleSpace();
1986             }
1987             if( xTitle_Width.is() )
1988             {
1989                 OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Width, rModel ) );
1990                 nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width;
1991                 if(nTitleSpaceWidth)
1992                     nTitleSpaceWidth+=lcl_getDiagramTitleSpace();
1993             }
1994             if( xSecondTitle_Height.is() )
1995             {
1996                 OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Height, rModel ) );
1997                 nSecondTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height;
1998                 if( nSecondTitleSpaceHeight )
1999                     nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace();
2000             }
2001             if( xSecondTitle_Width.is() )
2002             {
2003                 OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Width, rModel ) );
2004                 nSecondTitleSpaceWidth += pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width;
2005                 if( nSecondTitleSpaceWidth )
2006                     nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace();
2007             }
2008             if( bSubtract )
2009             {
2010                 aRet.X += nTitleSpaceWidth;
2011                 aRet.Y += nSecondTitleSpaceHeight;
2012                 aRet.Width -= (nTitleSpaceWidth + nSecondTitleSpaceWidth);
2013                 aRet.Height -= (nTitleSpaceHeight + nSecondTitleSpaceHeight);
2014             }
2015             else
2016             {
2017 
2018                 aRet.X -= nTitleSpaceWidth;
2019                 aRet.Y -= nSecondTitleSpaceHeight;
2020                 aRet.Width += nTitleSpaceWidth + nSecondTitleSpaceWidth;
2021                 aRet.Height += nTitleSpaceHeight + nSecondTitleSpaceHeight;
2022             }
2023         }
2024     }
2025     return aRet;
2026 }
2027 
2028 namespace {
2029 
2030 double lcl_getPageLayoutDistancePercentage()
2031 {
2032     return 0.02;
2033 }
2034 
2035 bool getAvailablePosAndSizeForDiagram(
2036     CreateShapeParam2D& rParam, const awt::Size & rPageSize, const uno::Reference<XDiagram>& xDiagram )
2037 {
2038     rParam.mbUseFixedInnerSize = false;
2039 
2040     //@todo: we need a size dependent on the axis labels
2041     sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage());
2042     sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage());
2043     rParam.maRemainingSpace.X += nXDistance;
2044     rParam.maRemainingSpace.Width -= 2*nXDistance;
2045     rParam.maRemainingSpace.Y += nYDistance;
2046     rParam.maRemainingSpace.Height -= 2*nYDistance;
2047 
2048     if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
2049         return false;
2050 
2051     uno::Reference< beans::XPropertySet > xProp(xDiagram, uno::UNO_QUERY);
2052 
2053     bool bPosSizeExcludeAxes = false;
2054     if( xProp.is() )
2055         xProp->getPropertyValue( "PosSizeExcludeAxes" ) >>= bPosSizeExcludeAxes;
2056 
2057     //size:
2058     css::chart2::RelativeSize aRelativeSize;
2059     if( xProp.is() && (xProp->getPropertyValue( "RelativeSize" )>>=aRelativeSize) )
2060     {
2061         rParam.maRemainingSpace.Height = static_cast<sal_Int32>(aRelativeSize.Secondary*rPageSize.Height);
2062         rParam.maRemainingSpace.Width = static_cast<sal_Int32>(aRelativeSize.Primary*rPageSize.Width);
2063         rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes;
2064     }
2065 
2066     //position:
2067     chart2::RelativePosition aRelativePosition;
2068     if( xProp.is() && (xProp->getPropertyValue( "RelativePosition" )>>=aRelativePosition) )
2069     {
2070         //@todo decide whether x is primary or secondary
2071 
2072         //the coordinates re relative to the page
2073         double fX = aRelativePosition.Primary*rPageSize.Width;
2074         double fY = aRelativePosition.Secondary*rPageSize.Height;
2075 
2076         awt::Point aPos = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
2077             awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)),
2078             awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height),
2079             aRelativePosition.Anchor);
2080 
2081         rParam.maRemainingSpace.X = aPos.X;
2082         rParam.maRemainingSpace.Y = aPos.Y;
2083 
2084         rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes;
2085     }
2086 
2087     //ensure that the diagram does not lap out right side or out of bottom
2088     if (rParam.maRemainingSpace.Y + rParam.maRemainingSpace.Height > rPageSize.Height)
2089         rParam.maRemainingSpace.Height = rPageSize.Height - rParam.maRemainingSpace.Y;
2090 
2091     if (rParam.maRemainingSpace.X + rParam.maRemainingSpace.Width > rPageSize.Width)
2092         rParam.maRemainingSpace.Width = rPageSize.Width - rParam.maRemainingSpace.X;
2093 
2094     return true;
2095 }
2096 
2097 enum TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z };
2098 
2099 void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment
2100                                , awt::Rectangle const & rDiagramPlusAxesRect, const awt::Size & rPageSize )
2101 {
2102     if(!pVTitle)
2103         return;
2104 
2105     awt::Point aNewPosition(0,0);
2106     awt::Size aTitleSize = pVTitle->getFinalSize();
2107     sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage());
2108     sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage());
2109     switch( eAlignment )
2110     {
2111     case ALIGN_TOP:
2112         aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2
2113                                     , rDiagramPlusAxesRect.Y - aTitleSize.Height/2  - nYDistance );
2114         break;
2115     case ALIGN_BOTTOM:
2116         aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2
2117                                     , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2  + nYDistance );
2118         break;
2119     case ALIGN_LEFT:
2120         aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance
2121                                     , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 );
2122         break;
2123     case ALIGN_RIGHT:
2124         aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance
2125                                     , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 );
2126         break;
2127     case ALIGN_Z:
2128         aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance
2129                                     , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 );
2130        break;
2131     default:
2132         break;
2133     }
2134 
2135     sal_Int32 nMaxY = rPageSize.Height - aTitleSize.Height/2;
2136     sal_Int32 nMaxX = rPageSize.Width - aTitleSize.Width/2;
2137     sal_Int32 nMinX = aTitleSize.Width/2;
2138     sal_Int32 nMinY = aTitleSize.Height/2;
2139     if( aNewPosition.Y > nMaxY )
2140         aNewPosition.Y = nMaxY;
2141     if( aNewPosition.X > nMaxX )
2142         aNewPosition.X = nMaxX;
2143     if( aNewPosition.Y < nMinY )
2144         aNewPosition.Y = nMinY;
2145     if( aNewPosition.X < nMinX )
2146         aNewPosition.X = nMinX;
2147 
2148     pVTitle->changePosition( aNewPosition );
2149 }
2150 
2151 std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType
2152                 , const uno::Reference< drawing::XShapes>& xPageShapes
2153                 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2154                 , ChartModel& rModel
2155                 , awt::Rectangle& rRemainingSpace
2156                 , const awt::Size & rPageSize
2157                 , TitleAlignment eAlignment
2158                 , bool& rbAutoPosition )
2159 {
2160     std::shared_ptr<VTitle> apVTitle;
2161 
2162     // #i109336# Improve auto positioning in chart
2163     double fPercentage = lcl_getPageLayoutDistancePercentage();
2164     sal_Int32 nXDistance = static_cast< sal_Int32 >( rPageSize.Width * fPercentage );
2165     sal_Int32 nYDistance = static_cast< sal_Int32 >( rPageSize.Height * fPercentage );
2166     if ( eType == TitleHelper::MAIN_TITLE )
2167     {
2168         nYDistance += 135; // 1/100 mm
2169     }
2170     else if ( eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION )
2171     {
2172         nYDistance = 420; // 1/100 mm
2173     }
2174     else if ( eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION )
2175     {
2176         nXDistance = 450; // 1/100 mm
2177     }
2178 
2179     uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, rModel ) );
2180     OUString aCompleteString = TitleHelper::getCompleteString(xTitle);
2181     if (aCompleteString.isEmpty())
2182         return apVTitle;
2183 
2184     //create title
2185     apVTitle.reset(new VTitle(xTitle));
2186     OUString aCID = ObjectIdentifier::createClassifiedIdentifierForObject(xTitle, rModel);
2187     apVTitle->init(xPageShapes, xShapeFactory, aCID);
2188     apVTitle->createShapes(awt::Point(0,0), rPageSize);
2189     awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize();
2190     awt::Size aTitleSize = apVTitle->getFinalSize();
2191 
2192     //position
2193     rbAutoPosition = true;
2194     awt::Point aNewPosition(0,0);
2195     chart2::RelativePosition aRelativePosition;
2196     uno::Reference<beans::XPropertySet> xProp(xTitle, uno::UNO_QUERY);
2197     if (xProp.is() && (xProp->getPropertyValue("RelativePosition") >>= aRelativePosition))
2198     {
2199         rbAutoPosition = false;
2200 
2201         //@todo decide whether x is primary or secondary
2202         double fX = aRelativePosition.Primary*rPageSize.Width;
2203         double fY = aRelativePosition.Secondary*rPageSize.Height;
2204 
2205         double fAnglePi = apVTitle->getRotationAnglePi();
2206         aNewPosition = RelativePositionHelper::getCenterOfAnchoredObject(
2207                 awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY))
2208                 , aTitleUnrotatedSize, aRelativePosition.Anchor, fAnglePi );
2209     }
2210     else //auto position
2211     {
2212         switch( eAlignment )
2213         {
2214         case ALIGN_TOP:
2215             aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2
2216                                      , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance );
2217             break;
2218         case ALIGN_BOTTOM:
2219             aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2
2220                                      , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance );
2221             break;
2222         case ALIGN_LEFT:
2223             aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance
2224                                      , rRemainingSpace.Y + rRemainingSpace.Height/2 );
2225             break;
2226         case ALIGN_RIGHT:
2227             aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance
2228                                      , rRemainingSpace.Y + rRemainingSpace.Height/2 );
2229             break;
2230         default:
2231             break;
2232 
2233         }
2234     }
2235     apVTitle->changePosition( aNewPosition );
2236 
2237     //remaining space
2238     switch( eAlignment )
2239     {
2240         case ALIGN_TOP:
2241             // Push the remaining space down from top.
2242             rRemainingSpace.Y += ( aTitleSize.Height + nYDistance );
2243             rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance );
2244             break;
2245         case ALIGN_BOTTOM:
2246             // Push the remaining space up from bottom.
2247             rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance );
2248             break;
2249         case ALIGN_LEFT:
2250             // Push the remaining space to the right from left edge.
2251             rRemainingSpace.X += ( aTitleSize.Width + nXDistance );
2252             rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance );
2253             break;
2254         case ALIGN_RIGHT:
2255             // Push the remaining space to the left from right edge.
2256             rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance );
2257             break;
2258         default:
2259             break;
2260     }
2261 
2262     return apVTitle;
2263 }
2264 
2265 bool lcl_createLegend( const uno::Reference< XLegend > & xLegend
2266                    , const uno::Reference< drawing::XShapes>& xPageShapes
2267                    , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2268                    , const uno::Reference< uno::XComponentContext > & xContext
2269                    , awt::Rectangle & rRemainingSpace
2270                    , const awt::Size & rPageSize
2271                    , ChartModel& rModel
2272                    , const std::vector< LegendEntryProvider* >& rLegendEntryProviderList
2273                    , sal_Int16 nDefaultWritingMode )
2274 {
2275     if (!VLegend::isVisible(xLegend))
2276         return false;
2277 
2278     VLegend aVLegend( xLegend, xContext, rLegendEntryProviderList,
2279             xPageShapes, xShapeFactory, rModel);
2280     aVLegend.setDefaultWritingMode( nDefaultWritingMode );
2281     aVLegend.createShapes( awt::Size( rRemainingSpace.Width, rRemainingSpace.Height ),
2282                            rPageSize );
2283     aVLegend.changePosition( rRemainingSpace, rPageSize );
2284     return true;
2285 }
2286 
2287 void lcl_createButtons(const uno::Reference<drawing::XShapes>& xPageShapes,
2288                        const uno::Reference<lang::XMultiServiceFactory>& xShapeFactory,
2289                        ChartModel& rModel,
2290                        awt::Rectangle& rRemainingSpace)
2291 {
2292     uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY);
2293     if (!xPivotTableDataProvider.is())
2294         return;
2295 
2296     uno::Reference<beans::XPropertySet> xModelPage(rModel.getPageBackground());
2297 
2298     awt::Size aSize(4000, 700); // size of the button
2299 
2300     long x = 0;
2301 
2302     if (xPivotTableDataProvider->getPageFields().hasElements())
2303     {
2304         x = 0;
2305 
2306         for (css::chart2::data::PivotTableFieldEntry const & rPageFieldEntry : xPivotTableDataProvider->getPageFields())
2307         {
2308             std::unique_ptr<VButton> pButton(new VButton);
2309             pButton->init(xPageShapes, xShapeFactory);
2310             awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100, rRemainingSpace.Y + 100);
2311             sal_Int32 nDimensionIndex = rPageFieldEntry.DimensionIndex;
2312             OUString aFieldOutputDescription = xPivotTableDataProvider->getFieldOutputDescription(nDimensionIndex);
2313             pButton->setLabel(rPageFieldEntry.Name + " | " + aFieldOutputDescription);
2314             pButton->setCID("FieldButton.Page." + OUString::number(nDimensionIndex));
2315             pButton->setPosition(aNewPosition);
2316             pButton->setSize(aSize);
2317             if (rPageFieldEntry.HasHiddenMembers)
2318                 pButton->setArrowColor(Color(0x0000FF));
2319 
2320             pButton->createShapes(xModelPage);
2321             x += aSize.Width + 100;
2322         }
2323         rRemainingSpace.Y += (aSize.Height + 100 + 100);
2324         rRemainingSpace.Height -= (aSize.Height + 100 + 100);
2325     }
2326 
2327     aSize = awt::Size(3000, 700); // size of the button
2328 
2329     if (xPivotTableDataProvider->getRowFields().hasElements())
2330     {
2331         x = 200;
2332         for (css::chart2::data::PivotTableFieldEntry const & rRowFieldEntry : xPivotTableDataProvider->getRowFields())
2333         {
2334 
2335             std::unique_ptr<VButton> pButton(new VButton);
2336             pButton->init(xPageShapes, xShapeFactory);
2337             awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100,
2338                                                  rRemainingSpace.Y + rRemainingSpace.Height - aSize.Height - 100);
2339             pButton->setLabel(rRowFieldEntry.Name);
2340             pButton->setCID("FieldButton.Row." + OUString::number(rRowFieldEntry.DimensionIndex));
2341             pButton->setPosition(aNewPosition);
2342             pButton->setSize(aSize);
2343             if ( rRowFieldEntry.Name == "Data" )
2344             {
2345                 pButton->setBGColor( Color(0x00F6F6F6) );
2346                 pButton->showArrow( false );
2347             }
2348             else if (rRowFieldEntry.HasHiddenMembers)
2349                 pButton->setArrowColor(Color(0x0000FF));
2350             pButton->createShapes(xModelPage);
2351             x += aSize.Width + 100;
2352         }
2353         rRemainingSpace.Height -= (aSize.Height + 100 + 100);
2354     }
2355 }
2356 
2357 void formatPage(
2358       ChartModel& rChartModel
2359     , const awt::Size& rPageSize
2360     , const uno::Reference< drawing::XShapes >& xTarget
2361     , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2362     )
2363 {
2364     try
2365     {
2366         uno::Reference< beans::XPropertySet > xModelPage( rChartModel.getPageBackground());
2367         if( ! xModelPage.is())
2368             return;
2369 
2370         if( !xShapeFactory.is() )
2371             return;
2372 
2373         //format page
2374         tPropertyNameValueMap aNameValueMap;
2375         PropertyMapper::getValueMap( aNameValueMap, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xModelPage );
2376 
2377         OUString aCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) );
2378         aNameValueMap.emplace( "Name", uno::Any( aCID ) ); //CID OUString
2379 
2380         tNameSequence aNames;
2381         tAnySequence aValues;
2382         PropertyMapper::getMultiPropertyListsFromValueMap( aNames, aValues, aNameValueMap );
2383 
2384         ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(xShapeFactory);
2385         pShapeFactory->createRectangle(
2386             xTarget, rPageSize, awt::Point(0, 0), aNames, aValues);
2387     }
2388     catch( const uno::Exception & )
2389     {
2390         DBG_UNHANDLED_EXCEPTION("chart2" );
2391     }
2392 }
2393 
2394 void lcl_removeEmptyGroupShapes( const Reference< drawing::XShapes>& xParent )
2395 {
2396     if(!xParent.is())
2397         return;
2398     Reference< drawing::XShapeGroup > xParentGroup( xParent, uno::UNO_QUERY );
2399     if( !xParentGroup.is() )
2400     {
2401         Reference< drawing::XDrawPage > xPage( xParent, uno::UNO_QUERY );
2402         if( !xPage.is() )
2403             return;
2404     }
2405 
2406     //iterate from back!
2407     for( sal_Int32 nN = xParent->getCount(); nN--; )
2408     {
2409         uno::Any aAny = xParent->getByIndex( nN );
2410         Reference< drawing::XShapes> xShapes;
2411         if( aAny >>= xShapes )
2412             lcl_removeEmptyGroupShapes( xShapes );
2413         if( xShapes.is() && xShapes->getCount()==0 )
2414         {
2415             //remove empty group shape
2416             Reference< drawing::XShapeGroup > xGroup( xShapes, uno::UNO_QUERY );
2417             Reference< drawing::XShape > xShape( xShapes, uno::UNO_QUERY );
2418             if( xGroup.is() )
2419                 xParent->remove( xShape );
2420         }
2421     }
2422 }
2423 
2424 }
2425 
2426 void ChartView::impl_refreshAddIn()
2427 {
2428     if( !m_bRefreshAddIn )
2429         return;
2430 
2431     uno::Reference< beans::XPropertySet > xProp( static_cast< ::cppu::OWeakObject* >( &mrChartModel ), uno::UNO_QUERY );
2432     if( xProp.is()) try
2433     {
2434         uno::Reference< util::XRefreshable > xAddIn;
2435         xProp->getPropertyValue( "AddIn" ) >>= xAddIn;
2436         if( xAddIn.is() )
2437         {
2438             bool bRefreshAddInAllowed = true;
2439             xProp->getPropertyValue( "RefreshAddInAllowed" ) >>= bRefreshAddInAllowed;
2440             if( bRefreshAddInAllowed )
2441                 xAddIn->refresh();
2442         }
2443     }
2444     catch( const uno::Exception& e )
2445     {
2446         SAL_WARN("chart2", "Exception caught. " << e );
2447     }
2448 }
2449 
2450 static const char* envChartDummyFactory = getenv("CHART_DUMMY_FACTORY");
2451 
2452 void ChartView::createShapes()
2453 {
2454     SolarMutexGuard aSolarGuard;
2455 
2456     osl::ResettableMutexGuard aTimedGuard(maTimeMutex);
2457     if(mrChartModel.isTimeBased())
2458     {
2459         maTimeBased.bTimeBased = true;
2460     }
2461 
2462     //make sure add-in is refreshed after creating the shapes
2463     const ::comphelper::ScopeGuard aGuard( [this]() { this->impl_refreshAddIn(); } );
2464 
2465     m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle(0,0,0,0);
2466     impl_deleteCoordinateSystems();
2467     if( m_pDrawModelWrapper )
2468     {
2469         // #i12587# support for shapes in chart
2470         m_pDrawModelWrapper->getSdrModel().EnableUndo( false );
2471         m_pDrawModelWrapper->clearMainDrawPage();
2472     }
2473 
2474     lcl_setDefaultWritingMode( m_pDrawModelWrapper, mrChartModel );
2475 
2476     awt::Size aPageSize = mrChartModel.getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
2477 
2478     ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory);
2479     if(!mxRootShape.is())
2480         mxRootShape = pShapeFactory->getOrCreateChartRootShape( m_xDrawPage );
2481 
2482     SdrPage* pPage = ChartView::getSdrPage();
2483     if(pPage) //it is necessary to use the implementation here as the uno page does not provide a propertyset
2484         pPage->SetSize(Size(aPageSize.Width,aPageSize.Height));
2485     else
2486     {
2487         OSL_FAIL("could not set page size correctly");
2488     }
2489     ShapeFactory::setPageSize(mxRootShape, aPageSize);
2490 
2491     createShapes2D(aPageSize);
2492 
2493     // #i12587# support for shapes in chart
2494     if ( m_pDrawModelWrapper )
2495     {
2496         m_pDrawModelWrapper->getSdrModel().EnableUndo( true );
2497     }
2498 
2499     if(maTimeBased.bTimeBased)
2500     {
2501         maTimeBased.nFrame++;
2502     }
2503 }
2504 
2505 // util::XEventListener (base of XCloseListener)
2506 void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ )
2507 {
2508 }
2509 
2510 void ChartView::impl_updateView( bool bCheckLockedCtrler )
2511 {
2512     if( !m_pDrawModelWrapper )
2513         return;
2514 
2515     // #i12587# support for shapes in chart
2516     if ( m_bSdrViewIsInEditMode )
2517     {
2518         return;
2519     }
2520 
2521     if (bCheckLockedCtrler && mrChartModel.hasControllersLocked())
2522         return;
2523 
2524     if( m_bViewDirty && !m_bInViewUpdate )
2525     {
2526         m_bInViewUpdate = true;
2527         //bool bOldRefreshAddIn = m_bRefreshAddIn;
2528         //m_bRefreshAddIn = false;
2529         try
2530         {
2531             impl_notifyModeChangeListener("invalid");
2532 
2533             //prepare draw model
2534             {
2535                 SolarMutexGuard aSolarGuard;
2536                 m_pDrawModelWrapper->lockControllers();
2537             }
2538 
2539             //create chart view
2540             {
2541                 m_bViewDirty = false;
2542                 m_bViewUpdatePending = false;
2543                 createShapes();
2544 
2545                 if( m_bViewDirty )
2546                 {
2547                     //avoid recursions due to add-in
2548                     m_bRefreshAddIn = false;
2549                     m_bViewDirty = false;
2550                     m_bViewUpdatePending = false;
2551                     //delete old chart view
2552                     createShapes();
2553                     m_bRefreshAddIn = true;
2554                 }
2555             }
2556 
2557             m_bViewDirty = m_bViewUpdatePending;
2558             m_bViewUpdatePending = false;
2559             m_bInViewUpdate = false;
2560         }
2561         catch( const uno::Exception& )
2562         {
2563             DBG_UNHANDLED_EXCEPTION("chart2" );
2564             m_bViewDirty = m_bViewUpdatePending;
2565             m_bViewUpdatePending = false;
2566             m_bInViewUpdate = false;
2567         }
2568 
2569         {
2570             SolarMutexGuard aSolarGuard;
2571             m_pDrawModelWrapper->unlockControllers();
2572         }
2573 
2574         impl_notifyModeChangeListener("valid");
2575 
2576         //m_bRefreshAddIn = bOldRefreshAddIn;
2577     }
2578 }
2579 
2580 // ____ XModifyListener ____
2581 void SAL_CALL ChartView::modified( const lang::EventObject& /* aEvent */ )
2582 {
2583     m_bViewDirty = true;
2584     if( m_bInViewUpdate )
2585         m_bViewUpdatePending = true;
2586 
2587     impl_notifyModeChangeListener("dirty");
2588 }
2589 
2590 //SfxListener
2591 void ChartView::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
2592 {
2593     //#i77362 change notification for changes on additional shapes are missing
2594     if( m_bInViewUpdate )
2595         return;
2596 
2597     // #i12587# support for shapes in chart
2598     if ( m_bSdrViewIsInEditMode )
2599     {
2600         uno::Reference< view::XSelectionSupplier > xSelectionSupplier( mrChartModel.getCurrentController(), uno::UNO_QUERY );
2601         if ( xSelectionSupplier.is() )
2602         {
2603             OUString aSelObjCID;
2604             uno::Any aSelObj( xSelectionSupplier->getSelection() );
2605             aSelObj >>= aSelObjCID;
2606             if ( !aSelObjCID.isEmpty() )
2607             {
2608                 return;
2609             }
2610         }
2611     }
2612 
2613     const SdrHint* pSdrHint = dynamic_cast< const SdrHint* >(&rHint);
2614     if( !pSdrHint )
2615         return;
2616 
2617     bool bShapeChanged = false;
2618     switch( pSdrHint->GetKind() )
2619     {
2620          case SdrHintKind::ObjectChange:
2621             bShapeChanged = true;
2622             break;
2623         case SdrHintKind::ObjectInserted:
2624             bShapeChanged = true;
2625             break;
2626         case SdrHintKind::ObjectRemoved:
2627             bShapeChanged = true;
2628             break;
2629         case SdrHintKind::ModelCleared:
2630             bShapeChanged = true;
2631             break;
2632         case SdrHintKind::EndEdit:
2633             bShapeChanged = true;
2634             break;
2635         default:
2636             break;
2637     }
2638 
2639     if(bShapeChanged)
2640     {
2641         //#i76053# do not send view modified notifications for changes on the hidden page which contains e.g. the symbols for the dialogs
2642         if( ChartView::getSdrPage() != pSdrHint->GetPage() )
2643             bShapeChanged=false;
2644     }
2645 
2646     if(!bShapeChanged)
2647         return;
2648 
2649     mrChartModel.setModified(true);
2650 }
2651 
2652 void ChartView::impl_notifyModeChangeListener( const OUString& rNewMode )
2653 {
2654     try
2655     {
2656         ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer
2657             .getContainer( cppu::UnoType<util::XModeChangeListener>::get());
2658         if( pIC )
2659         {
2660             util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode );
2661             ::cppu::OInterfaceIteratorHelper aIt( *pIC );
2662             while( aIt.hasMoreElements() )
2663             {
2664                 uno::Reference< util::XModeChangeListener > xListener( aIt.next(), uno::UNO_QUERY );
2665                 if( xListener.is() )
2666                     xListener->modeChanged( aEvent );
2667             }
2668         }
2669     }
2670     catch( const uno::Exception& )
2671     {
2672         DBG_UNHANDLED_EXCEPTION("chart2");
2673     }
2674 }
2675 
2676 // ____ XModeChangeBroadcaster ____
2677 
2678 void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener )
2679 {
2680     m_aListenerContainer.addInterface(
2681         cppu::UnoType<util::XModeChangeListener>::get(), xListener );
2682 }
2683 void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener )
2684 {
2685     m_aListenerContainer.removeInterface(
2686         cppu::UnoType<util::XModeChangeListener>::get(), xListener );
2687 }
2688 void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ )
2689 {
2690 
2691 }
2692 void SAL_CALL ChartView::removeModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ )
2693 {
2694 
2695 }
2696 
2697 // ____ XUpdatable ____
2698 void SAL_CALL ChartView::update()
2699 {
2700     impl_updateView();
2701 
2702     //#i100778# migrate all imported or old documents to a plot area sizing exclusive axes (in case the save settings allow for this):
2703     //Although in general it is a bad idea to change the model from within the view this is exceptionally the best place to do this special conversion.
2704     //When a view update is requested (what happens for creating the metafile or displaying
2705     //the chart in edit mode or printing) it is most likely that all necessary information are available - like the underlying spreadsheet data for example.
2706     //Those data are important for the correct axis label sizes which are needed during conversion.
2707     if( DiagramHelper::switchDiagramPositioningToExcludingPositioning( mrChartModel, true, false ) )
2708         impl_updateView();
2709 }
2710 
2711 void SAL_CALL ChartView::updateSoft()
2712 {
2713     update();
2714 }
2715 
2716 void SAL_CALL ChartView::updateHard()
2717 {
2718     impl_updateView(false);
2719 }
2720 
2721 // ____ XPropertySet ____
2722 Reference< beans::XPropertySetInfo > SAL_CALL ChartView::getPropertySetInfo()
2723 {
2724     OSL_FAIL("not implemented");
2725     return nullptr;
2726 }
2727 
2728 void SAL_CALL ChartView::setPropertyValue( const OUString& rPropertyName
2729                                                      , const Any& rValue )
2730 {
2731     if( rPropertyName == "Resolution" )
2732     {
2733         awt::Size aNewResolution;
2734         if( ! (rValue >>= aNewResolution) )
2735             throw lang::IllegalArgumentException( "Property 'Resolution' requires value of type awt::Size", nullptr, 0 );
2736 
2737         if( m_aPageResolution.Width!=aNewResolution.Width || m_aPageResolution.Height!=aNewResolution.Height )
2738         {
2739             //set modified only when the new resolution is higher and points were skipped before
2740             bool bSetModified = m_bPointsWereSkipped && (m_aPageResolution.Width<aNewResolution.Width || m_aPageResolution.Height<aNewResolution.Height);
2741 
2742             m_aPageResolution = aNewResolution;
2743 
2744             if( bSetModified )
2745                 this->modified( lang::EventObject(  static_cast< uno::XWeak* >( this )  ) );
2746         }
2747     }
2748     else if( rPropertyName == "ZoomFactors" )
2749     {
2750         //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
2751         uno::Sequence< beans::PropertyValue > aZoomFactors;
2752         if( ! (rValue >>= aZoomFactors) )
2753             throw lang::IllegalArgumentException( "Property 'ZoomFactors' requires value of type Sequence< PropertyValue >", nullptr, 0 );
2754 
2755         sal_Int32 nFilterArgs = aZoomFactors.getLength();
2756         beans::PropertyValue* pDataValues = aZoomFactors.getArray();
2757         while( nFilterArgs-- )
2758         {
2759             if ( pDataValues->Name == "ScaleXNumerator" )
2760                 pDataValues->Value >>= m_nScaleXNumerator;
2761             else if ( pDataValues->Name == "ScaleXDenominator" )
2762                 pDataValues->Value >>= m_nScaleXDenominator;
2763             else if ( pDataValues->Name == "ScaleYNumerator" )
2764                 pDataValues->Value >>= m_nScaleYNumerator;
2765             else if ( pDataValues->Name == "ScaleYDenominator" )
2766                 pDataValues->Value >>= m_nScaleYDenominator;
2767 
2768             pDataValues++;
2769         }
2770     }
2771     else if( rPropertyName == "SdrViewIsInEditMode" )
2772     {
2773         //#i77362 change notification for changes on additional shapes are missing
2774         if( ! (rValue >>= m_bSdrViewIsInEditMode) )
2775             throw lang::IllegalArgumentException( "Property 'SdrViewIsInEditMode' requires value of type sal_Bool", nullptr, 0 );
2776     }
2777     else
2778         throw beans::UnknownPropertyException( "unknown property was tried to set to chart wizard", nullptr );
2779 }
2780 
2781 Any SAL_CALL ChartView::getPropertyValue( const OUString& rPropertyName )
2782 {
2783     if( rPropertyName != "Resolution" )
2784         throw beans::UnknownPropertyException( "unknown property was tried to get from chart wizard", nullptr );
2785 
2786     return Any(m_aPageResolution);
2787 }
2788 
2789 void SAL_CALL ChartView::addPropertyChangeListener(
2790     const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* xListener */ )
2791 {
2792     OSL_FAIL("not implemented");
2793 }
2794 void SAL_CALL ChartView::removePropertyChangeListener(
2795     const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* aListener */ )
2796 {
2797     OSL_FAIL("not implemented");
2798 }
2799 
2800 void SAL_CALL ChartView::addVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ )
2801 {
2802     OSL_FAIL("not implemented");
2803 }
2804 
2805 void SAL_CALL ChartView::removeVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ )
2806 {
2807     OSL_FAIL("not implemented");
2808 }
2809 
2810 // ____ XMultiServiceFactory ____
2811 
2812 Reference< uno::XInterface > ChartView::createInstance( const OUString& aServiceSpecifier )
2813 {
2814     SolarMutexGuard aSolarGuard;
2815 
2816     SdrModel* pModel = ( m_pDrawModelWrapper ? &m_pDrawModelWrapper->getSdrModel() : nullptr );
2817     if ( pModel )
2818     {
2819         if ( aServiceSpecifier == "com.sun.star.drawing.DashTable" )
2820         {
2821             if ( !m_xDashTable.is() )
2822             {
2823                 m_xDashTable = SvxUnoDashTable_createInstance( pModel );
2824             }
2825             return m_xDashTable;
2826         }
2827         else if ( aServiceSpecifier == "com.sun.star.drawing.GradientTable" )
2828         {
2829             if ( !m_xGradientTable.is() )
2830             {
2831                 m_xGradientTable = SvxUnoGradientTable_createInstance( pModel );
2832             }
2833             return m_xGradientTable;
2834         }
2835         else if ( aServiceSpecifier == "com.sun.star.drawing.HatchTable" )
2836         {
2837             if ( !m_xHatchTable.is() )
2838             {
2839                 m_xHatchTable = SvxUnoHatchTable_createInstance( pModel );
2840             }
2841             return m_xHatchTable;
2842         }
2843         else if ( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" )
2844         {
2845             if ( !m_xBitmapTable.is() )
2846             {
2847                 m_xBitmapTable = SvxUnoBitmapTable_createInstance( pModel );
2848             }
2849             return m_xBitmapTable;
2850         }
2851         else if ( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" )
2852         {
2853             if ( !m_xTransGradientTable.is() )
2854             {
2855                 m_xTransGradientTable = SvxUnoTransGradientTable_createInstance( pModel );
2856             }
2857             return m_xTransGradientTable;
2858         }
2859         else if ( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" )
2860         {
2861             if ( !m_xMarkerTable.is() )
2862             {
2863                 m_xMarkerTable = SvxUnoMarkerTable_createInstance( pModel );
2864             }
2865             return m_xMarkerTable;
2866         }
2867     }
2868 
2869     return nullptr;
2870 }
2871 
2872 Reference< uno::XInterface > ChartView::createInstanceWithArguments( const OUString& ServiceSpecifier, const uno::Sequence< uno::Any >& Arguments )
2873 {
2874     OSL_ENSURE( Arguments.getLength(), "ChartView::createInstanceWithArguments: arguments are ignored" );
2875     return createInstance( ServiceSpecifier );
2876 }
2877 
2878 uno::Sequence< OUString > ChartView::getAvailableServiceNames()
2879 {
2880     uno::Sequence< OUString > aServiceNames( 6 );
2881 
2882     aServiceNames[0] = "com.sun.star.drawing.DashTable";
2883     aServiceNames[1] = "com.sun.star.drawing.GradientTable";
2884     aServiceNames[2] = "com.sun.star.drawing.HatchTable";
2885     aServiceNames[3] = "com.sun.star.drawing.BitmapTable";
2886     aServiceNames[4] = "com.sun.star.drawing.TransparencyGradientTable";
2887     aServiceNames[5] = "com.sun.star.drawing.MarkerTable";
2888 
2889     return aServiceNames;
2890 }
2891 
2892 OUString ChartView::dump()
2893 {
2894 #if HAVE_FEATURE_DESKTOP
2895     // Used for unit tests and in chartcontroller only, no need to drag in this when cross-compiling
2896     // for non-desktop
2897     impl_updateView();
2898     uno::Reference< drawing::XShapes > xShapes( m_xDrawPage, uno::UNO_QUERY_THROW );
2899     sal_Int32 n = xShapes->getCount();
2900     OUStringBuffer aBuffer;
2901     for(sal_Int32 i = 0; i < n; ++i)
2902     {
2903         uno::Reference< drawing::XShapes > xShape(xShapes->getByIndex(i), uno::UNO_QUERY);
2904         if(xShape.is())
2905         {
2906             XShapeDumper dumper;
2907             OUString aString = XShapeDumper::dump(mxRootShape);
2908             aBuffer.append(aString);
2909         }
2910         else
2911         {
2912             uno::Reference< drawing::XShape > xSingleShape(xShapes->getByIndex(i), uno::UNO_QUERY);
2913             if(!xSingleShape.is())
2914                 continue;
2915             XShapeDumper dumper;
2916             OUString aString = XShapeDumper::dump(xSingleShape);
2917             aBuffer.append(aString);
2918         }
2919         aBuffer.append("\n\n");
2920     }
2921 
2922     return aBuffer.makeStringAndClear();
2923 #else
2924     return OUString();
2925 #endif
2926 }
2927 
2928 void ChartView::setViewDirty()
2929 {
2930     osl::ResettableMutexGuard aGuard(maTimeMutex);
2931     m_bViewDirty = true;
2932 }
2933 
2934 IMPL_LINK_NOARG(ChartView, UpdateTimeBased, Timer *, void)
2935 {
2936     setViewDirty();
2937     update();
2938 }
2939 
2940 void ChartView::createShapes2D( const awt::Size& rPageSize )
2941 {
2942     ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory);
2943 
2944     // todo: it would be nicer to just pass the page m_xDrawPage and format it,
2945     // but the draw page does not support XPropertySet
2946     formatPage( mrChartModel, rPageSize, mxRootShape, m_xShapeFactory );
2947 
2948     CreateShapeParam2D aParam;
2949     aParam.maRemainingSpace.X = 0;
2950     aParam.maRemainingSpace.Y = 0;
2951     aParam.maRemainingSpace.Width = rPageSize.Width;
2952     aParam.maRemainingSpace.Height = rPageSize.Height;
2953 
2954     //create the group shape for diagram and axes first to have title and legends on top of it
2955     uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() );
2956     OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ) );//todo: other index if more than one diagram is possible
2957     uno::Reference< drawing::XShapes > xDiagramPlusAxesPlusMarkHandlesGroup_Shapes(
2958             pShapeFactory->createGroup2D(mxRootShape,aDiagramCID) );
2959 
2960     aParam.mxMarkHandles = pShapeFactory->createInvisibleRectangle(
2961         xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0));
2962     ShapeFactory::setShapeName(aParam.mxMarkHandles, "MarkHandles");
2963 
2964     aParam.mxPlotAreaWithAxes = pShapeFactory->createInvisibleRectangle(
2965         xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0, 0));
2966     ShapeFactory::setShapeName(aParam.mxPlotAreaWithAxes, "PlotAreaIncludingAxes");
2967 
2968     aParam.mxDiagramWithAxesShapes = pShapeFactory->createGroup2D(xDiagramPlusAxesPlusMarkHandlesGroup_Shapes);
2969 
2970     bool bAutoPositionDummy = true;
2971 
2972     // create buttons
2973     lcl_createButtons(mxRootShape, m_xShapeFactory, mrChartModel, aParam.maRemainingSpace);
2974 
2975     lcl_createTitle(
2976         TitleHelper::MAIN_TITLE, mxRootShape, m_xShapeFactory, mrChartModel,
2977         aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy);
2978     if (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)
2979         return;
2980 
2981     lcl_createTitle(
2982         TitleHelper::SUB_TITLE, mxRootShape, m_xShapeFactory, mrChartModel,
2983         aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy );
2984     if (aParam.maRemainingSpace.Width <= 0|| aParam.maRemainingSpace.Height <= 0)
2985         return;
2986 
2987     aParam.mpSeriesPlotterContainer.reset(new SeriesPlotterContainer(m_aVCooSysList));
2988     aParam.mpSeriesPlotterContainer->initializeCooSysAndSeriesPlotter( mrChartModel );
2989     if(maTimeBased.bTimeBased && maTimeBased.nFrame != 0)
2990     {
2991         SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList();
2992         size_t n = rSeriesPlotter.size();
2993         for(size_t i = 0; i < n; ++i)
2994         {
2995             std::vector<VDataSeries*> aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries();
2996             std::vector< VDataSeries* >& rAllOldDataSeries =
2997                 maTimeBased.m_aDataSeriesList[i];
2998             size_t m = std::min(aAllNewDataSeries.size(), rAllOldDataSeries.size());
2999             for(size_t j = 0; j < m; ++j)
3000             {
3001                 aAllNewDataSeries[j]->setOldTimeBased(
3002                         rAllOldDataSeries[j], (maTimeBased.nFrame % 60)/60.0);
3003             }
3004         }
3005     }
3006 
3007     lcl_createLegend(
3008         LegendHelper::getLegend( mrChartModel ), mxRootShape, m_xShapeFactory, m_xCC,
3009         aParam.maRemainingSpace, rPageSize, mrChartModel, aParam.mpSeriesPlotterContainer->getLegendEntryProviderList(),
3010         lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) );
3011     if (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)
3012         return;
3013 
3014     if (!createAxisTitleShapes2D(aParam, rPageSize))
3015         return;
3016 
3017     bool bDummy = false;
3018     bool bIsVertical = DiagramHelper::getVertical(xDiagram, bDummy, bDummy);
3019 
3020     if (getAvailablePosAndSizeForDiagram(aParam, rPageSize, mrChartModel.getFirstDiagram()))
3021     {
3022         awt::Rectangle aUsedOuterRect = impl_createDiagramAndContent(aParam, rPageSize);
3023 
3024         if (aParam.mxPlotAreaWithAxes.is())
3025         {
3026             aParam.mxPlotAreaWithAxes->setPosition(awt::Point(aUsedOuterRect.X, aUsedOuterRect.Y));
3027             aParam.mxPlotAreaWithAxes->setSize(awt::Size(aUsedOuterRect.Width, aUsedOuterRect.Height));
3028         }
3029 
3030         //correct axis title position
3031         awt::Rectangle aDiagramPlusAxesRect( aUsedOuterRect );
3032         if (aParam.mbAutoPosTitleX)
3033             changePositionOfAxisTitle(aParam.mpVTitleX.get(), ALIGN_BOTTOM, aDiagramPlusAxesRect, rPageSize);
3034         if (aParam.mbAutoPosTitleY)
3035             changePositionOfAxisTitle(aParam.mpVTitleY.get(), ALIGN_LEFT, aDiagramPlusAxesRect, rPageSize);
3036         if (aParam.mbAutoPosTitleZ)
3037             changePositionOfAxisTitle(aParam.mpVTitleZ.get(), ALIGN_Z, aDiagramPlusAxesRect, rPageSize);
3038         if (aParam.mbAutoPosSecondTitleX)
3039             changePositionOfAxisTitle(aParam.mpVTitleSecondX.get(), bIsVertical? ALIGN_RIGHT : ALIGN_TOP, aDiagramPlusAxesRect, rPageSize);
3040         if (aParam.mbAutoPosSecondTitleY)
3041             changePositionOfAxisTitle(aParam.mpVTitleSecondY.get(), bIsVertical? ALIGN_TOP : ALIGN_RIGHT, aDiagramPlusAxesRect, rPageSize);
3042     }
3043 
3044     //cleanup: remove all empty group shapes to avoid grey border lines:
3045     lcl_removeEmptyGroupShapes( mxRootShape );
3046 
3047     if(maTimeBased.bTimeBased && maTimeBased.nFrame % 60 == 0)
3048     {
3049         // create copy of the data for next frame
3050         SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList();
3051         size_t n = rSeriesPlotter.size();
3052         maTimeBased.m_aDataSeriesList.clear();
3053         maTimeBased.m_aDataSeriesList.resize(n);
3054         for(size_t i = 0; i < n; ++i)
3055         {
3056             std::vector<VDataSeries*> aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries();
3057             std::vector<VDataSeries*>& rAllOldDataSeries = maTimeBased.m_aDataSeriesList[i];
3058             size_t m = aAllNewDataSeries.size();
3059             for(size_t j = 0; j < m; ++j)
3060             {
3061                 rAllOldDataSeries.push_back( aAllNewDataSeries[j]->
3062                         createCopyForTimeBased() );
3063             }
3064         }
3065 
3066         maTimeBased.maTimer.Stop();
3067     }
3068 
3069     if(maTimeBased.bTimeBased && !maTimeBased.maTimer.IsActive())
3070     {
3071         maTimeBased.maTimer.SetTimeout(15);
3072         maTimeBased.maTimer.SetInvokeHandler(LINK(this, ChartView, UpdateTimeBased));
3073         maTimeBased.maTimer.Start();
3074     }
3075 }
3076 
3077 bool ChartView::createAxisTitleShapes2D( CreateShapeParam2D& rParam, const css::awt::Size& rPageSize )
3078 {
3079     uno::Reference<XDiagram> xDiagram = mrChartModel.getFirstDiagram();
3080 
3081     Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
3082     sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram );
3083 
3084     if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) )
3085         rParam.mpVTitleX = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, mxRootShape, m_xShapeFactory, mrChartModel
3086                 , rParam.maRemainingSpace, rPageSize, ALIGN_BOTTOM, rParam.mbAutoPosTitleX );
3087     if (rParam.maRemainingSpace.Width <= 0 ||rParam.maRemainingSpace.Height <= 0)
3088         return false;
3089 
3090     if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) )
3091         rParam.mpVTitleY = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, mxRootShape, m_xShapeFactory, mrChartModel
3092                 , rParam.maRemainingSpace, rPageSize, ALIGN_LEFT, rParam.mbAutoPosTitleY );
3093     if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3094         return false;
3095 
3096     if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) )
3097         rParam.mpVTitleZ = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3098                 , rParam.maRemainingSpace, rPageSize, ALIGN_RIGHT, rParam.mbAutoPosTitleZ );
3099     if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3100         return false;
3101 
3102     bool bDummy = false;
3103     bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy );
3104 
3105     if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) )
3106         rParam.mpVTitleSecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3107                 , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_RIGHT : ALIGN_TOP, rParam.mbAutoPosSecondTitleX );
3108     if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3109         return false;
3110 
3111     if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) )
3112         rParam.mpVTitleSecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3113                 , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_TOP : ALIGN_RIGHT, rParam.mbAutoPosSecondTitleY );
3114     if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3115         return false;
3116 
3117     return true;
3118 }
3119 
3120 } //namespace chart
3121 
3122 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3123 com_sun_star_comp_chart2_ChartView_get_implementation(css::uno::XComponentContext *context,
3124                                                          css::uno::Sequence<css::uno::Any> const &)
3125 {
3126     ::chart::ChartModel *pChartModel = new ::chart::ChartModel(context);
3127     return cppu::acquire(new ::chart::ChartView(context, *pChartModel));
3128 }
3129 
3130 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3131