Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / chart2 / source / view / main / ChartView.cxx
blob0e4d1124847b29db9d07dbf2962efd9cfad12b2f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_feature_desktop.h>
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>
66 #include <time.h>
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>
99 #include <rtl/ustring.hxx>
100 #include <sal/log.hxx>
102 #include <tools/diagnose_ex.h>
103 #include <tools/stream.hxx>
105 #include <memory>
106 namespace com { namespace sun { namespace star { namespace chart2 { class XChartDocument; } } } }
108 namespace chart {
110 using namespace ::com::sun::star;
111 using namespace ::com::sun::star::chart2;
112 using ::com::sun::star::uno::Reference;
113 using ::com::sun::star::uno::Sequence;
114 using ::com::sun::star::uno::Any;
116 namespace {
118 class theExplicitValueProviderUnoTunnelId : public rtl::Static<UnoTunnelIdInit, theExplicitValueProviderUnoTunnelId> {};
120 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
121 typedef std::map< VCoordinateSystem*, tFullAxisIndex > tCoordinateSystemMap;
123 /** This class handles a collection of coordinate systems and is used for
124 * executing some action on all coordinate systems such as
125 * `prepareAutomaticAxisScaling` and `setExplicitScaleAndIncrement`.
126 * Moreover it contains the `aAutoScaling` object that is an instance of
127 * the `ScaleAutomatism` class. The initialization of `aAutoScaling` is
128 * performed in the `SeriesPlotterContainer::initAxisUsageList` method and is
129 * used in the `SeriesPlotterContainer::doAutoScaling` for calculating explicit
130 * scale and increment objects (see `SeriesPlotterContainer::doAutoScaling`).
132 struct AxisUsage
134 AxisUsage();
135 ~AxisUsage();
137 void addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex );
138 std::vector< VCoordinateSystem* > getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex );
139 sal_Int32 getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex );
141 void prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex );
142 void setExplicitScaleAndIncrement( sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc );
144 ScaleAutomatism aAutoScaling;
146 private:
147 tCoordinateSystemMap aCoordinateSystems;
148 std::map< sal_Int32, sal_Int32 > aMaxIndexPerDimension;
151 AxisUsage::AxisUsage()
152 : aAutoScaling(AxisHelper::createDefaultScale(), Date(Date::SYSTEM))
156 AxisUsage::~AxisUsage()
158 aCoordinateSystems.clear();
161 void AxisUsage::addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
163 if(!pCooSys)
164 return;
166 tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex );
167 tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) );
169 //use one scale only once for each coordinate system
170 //main axis are preferred over secondary axis
171 //value scales are preferred
172 if(aFound!=aCoordinateSystems.end())
174 sal_Int32 nFoundAxisIndex = aFound->second.second;
175 if( nFoundAxisIndex < nAxisIndex )
176 return;
177 sal_Int32 nFoundDimension = aFound->second.first;
178 if( nFoundDimension ==1 )
179 return;
180 if( nFoundDimension < nDimensionIndex )
181 return;
183 aCoordinateSystems[pCooSys] = aFullAxisIndex;
185 //set maximum scale index
186 std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex);
187 if( aIter != aMaxIndexPerDimension.end() )
189 sal_Int32 nCurrentMaxIndex = aIter->second;
190 if( nCurrentMaxIndex < nAxisIndex )
191 aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex;
193 else
194 aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex;
197 std::vector< VCoordinateSystem* > AxisUsage::getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
199 std::vector< VCoordinateSystem* > aRet;
201 for (auto const& coordinateSystem : aCoordinateSystems)
203 if( coordinateSystem.second.first != nDimensionIndex )
204 continue;
205 if( coordinateSystem.second.second != nAxisIndex )
206 continue;
207 aRet.push_back( coordinateSystem.first );
210 return aRet;
213 sal_Int32 AxisUsage::getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex )
215 sal_Int32 nRet = -1;
216 std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex);
217 if( aIter != aMaxIndexPerDimension.end() )
218 nRet = aIter->second;
219 return nRet;
222 void AxisUsage::prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex )
224 std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex);
225 for (VCoordinateSystem * i : aVCooSysList)
226 i->prepareAutomaticAxisScaling(rScaleAutomatism, nDimIndex, nAxisIndex);
229 void AxisUsage::setExplicitScaleAndIncrement(
230 sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc )
232 std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex);
233 for (VCoordinateSystem* i : aVCooSysList)
234 i->setExplicitScaleAndIncrement(nDimIndex, nAxisIndex, rScale, rInc);
237 typedef std::vector<std::unique_ptr<VSeriesPlotter> > SeriesPlottersType;
239 /** This class is a container of `SeriesPlotter` objects (such as `PieChart`
240 * instances). It is used for initializing coordinate systems, axes and scales
241 * of all series plotters which belongs to the container.
243 class SeriesPlotterContainer
245 public:
246 explicit SeriesPlotterContainer( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList );
247 ~SeriesPlotterContainer();
249 /** It is used to set coordinate systems (`m_rVCooSysList`), this method
250 * is invoked by `ChartView::createShapes2D` before of
251 * `ChartView::impl_createDiagramAndContent`.
252 * Coordinate systems are retrieved through the `XCoordinateSystemContainer`
253 * interface implemented by a diagram object which is provided by the
254 * `ChartModel` object passed to the method (`rChartModel.getFirstDiagram()`).
256 * It is used for creating series plotters and appending them
257 * to `m_aSeriesPlotterList`. The created series plotters are initialized
258 * through data (number formats supplier, color scheme, data series),
259 * extracted from the chart model or the diagram objects. An exception is
260 * the explicit category provider that is retrieved through the
261 * `VCoordinateSystem` object used by the series plotter.
263 * It sets the minimum-maximum supplier for a coordinate system:
264 * this supplier is the series plotter itself which utilizes the given
265 * coordinate system. In fact `VSeriesPlotter` has `MinimumMaximumSupplier`
266 * as one of its base classes.
267 * Hence, for instance, a `PieChart`, which is a series plotter, is
268 * a `MinimumMaximumSupplier`, too.
270 void initializeCooSysAndSeriesPlotter( ChartModel& rModel );
272 /** This method is invoked by `ChartView::impl_createDiagramAndContent`.
273 * It iterates on every axis of every coordinate systems, and if the axis
274 * is not yet present in `m_aAxisUsageList` it creates a new `AxisUsage`
275 * object and initialize its `aAutoScaling` member to the `ScaleData`
276 * object of the current axis.
278 void initAxisUsageList(const Date& rNullDate);
281 * Perform automatic axis scaling and determine the amount and spacing of
282 * increments. It assumes that the caller has determined the size of the
283 * largest axis label text object prior to calling this method.
285 * The new axis scaling data will be stored in the VCoordinateSystem
286 * objects. The label alignment direction for each axis will also get
287 * determined during this process, and stored in VAxis.
289 * This method is invoked by `ChartView::impl_createDiagramAndContent`
290 * soon after `initAxisUsageList`.
291 * It initializes explicit scale and increment objects for all coordinate
292 * systems in `m_rVCooSysList`.
293 * This action is achieved by iterating on the `m_aAxisUsageList` container,
294 * and performing 3 steps:
295 * 1- call `VCoordinateSystem::prepareAutomaticAxisScaling` for setting
296 * scaling parameters of the `aAutoScaling` member (a `ScaleAutomatism`
297 * object) for the current `AxisUsage` instance
298 * (see `VCoordinateSystem::prepareAutomaticAxisScaling`);
299 * 2- calculate the explicit scale and increment objects
300 * (see ScaleAutomatism::calculateExplicitScaleAndIncrement);
301 * 3- set the explicit scale and increment objects for each coordinate
302 * system.
304 void doAutoScaling( ChartModel& rModel );
307 * After auto-scaling is performed, call this method to set the explicit
308 * scaling and increment data to all relevant VAxis objects.
310 void updateScalesAndIncrementsOnAxes();
313 * After auto-scaling is performed, call this method to set the explicit
314 * scaling data to all the plotters.
316 void setScalesFromCooSysToPlotter();
318 void setNumberFormatsFromAxes();
319 drawing::Direction3D getPreferredAspectRatio();
321 SeriesPlottersType& getSeriesPlotterList() { return m_aSeriesPlotterList; }
322 std::vector< std::unique_ptr<VCoordinateSystem> >& getCooSysList() { return m_rVCooSysList; }
323 std::vector< LegendEntryProvider* > getLegendEntryProviderList();
325 void AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel );
327 static bool isCategoryPositionShifted(
328 const chart2::ScaleData& rSourceScale, bool bHasComplexCategories );
330 private:
331 /** A vector of series plotters.
333 SeriesPlottersType m_aSeriesPlotterList;
335 /** A vector of coordinate systems.
337 std::vector< std::unique_ptr<VCoordinateSystem> >& m_rVCooSysList;
339 /** A map whose key is a `XAxis` interface and the related value is
340 * an object of `AxisUsage` type.
342 std::map< uno::Reference< XAxis >, AxisUsage > m_aAxisUsageList;
345 * Max axis index of all dimensions. Currently this can be either 0 or 1
346 * since we only support primary and secondary axes per dimension. The
347 * value of 0 means all dimensions have only primary axis, while 1 means
348 * at least one dimension has a secondary axis.
350 sal_Int32 m_nMaxAxisIndex;
352 sal_Int32 m_nDefaultDateNumberFormat;
355 SeriesPlotterContainer::SeriesPlotterContainer( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList )
356 : m_rVCooSysList( rVCooSysList )
357 , m_nMaxAxisIndex(0)
358 , m_nDefaultDateNumberFormat(0)
362 SeriesPlotterContainer::~SeriesPlotterContainer()
364 // - remove plotter from coordinatesystems
365 for(auto & nC : m_rVCooSysList)
366 nC->clearMinimumAndMaximumSupplierList();
369 std::vector< LegendEntryProvider* > SeriesPlotterContainer::getLegendEntryProviderList()
371 std::vector< LegendEntryProvider* > aRet( m_aSeriesPlotterList.size() );
372 sal_Int32 nN = 0;
373 for( const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList)
374 aRet[nN++] = aPlotter.get();
375 return aRet;
378 VCoordinateSystem* findInCooSysList( const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList
379 , const uno::Reference< XCoordinateSystem >& xCooSys )
381 for(auto & pVCooSys : rVCooSysList)
383 if(pVCooSys->getModel()==xCooSys)
384 return pVCooSys.get();
386 return nullptr;
389 VCoordinateSystem* lcl_getCooSysForPlotter( const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList, MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier )
391 if(!pMinimumAndMaximumSupplier)
392 return nullptr;
393 for(auto & pVCooSys : rVCooSysList)
395 if(pVCooSys->hasMinimumAndMaximumSupplier( pMinimumAndMaximumSupplier ))
396 return pVCooSys.get();
398 return nullptr;
401 VCoordinateSystem* addCooSysToList( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList
402 , const uno::Reference< XCoordinateSystem >& xCooSys
403 , ChartModel& rChartModel )
405 VCoordinateSystem* pExistingVCooSys = findInCooSysList( rVCooSysList, xCooSys );
406 if( pExistingVCooSys )
407 return pExistingVCooSys;
409 std::unique_ptr<VCoordinateSystem> pVCooSys = VCoordinateSystem::createCoordinateSystem(xCooSys );
410 if(!pVCooSys)
411 return nullptr;
413 OUString aCooSysParticle( ObjectIdentifier::createParticleForCoordinateSystem( xCooSys, rChartModel ) );
414 pVCooSys->setParticle(aCooSysParticle);
416 pVCooSys->setExplicitCategoriesProvider( new ExplicitCategoriesProvider(xCooSys, rChartModel) );
417 rVCooSysList.push_back( std::move(pVCooSys) );
418 return rVCooSysList.back().get();
421 void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter(
422 ChartModel& rChartModel )
424 uno::Reference< XDiagram > xDiagram( rChartModel.getFirstDiagram() );
425 if( !xDiagram.is())
426 return;
428 uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( static_cast< ::cppu::OWeakObject* >( &rChartModel ), uno::UNO_QUERY );
429 if( rChartModel.hasInternalDataProvider() && DiagramHelper::isSupportingDateAxis( xDiagram ) )
430 m_nDefaultDateNumberFormat=DiagramHelper::getDateNumberFormat( xNumberFormatsSupplier );
432 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
433 if(!nDimensionCount)
435 //@todo handle mixed dimension
436 nDimensionCount = 2;
439 bool bSortByXValues = false;
440 bool bConnectBars = false;
441 bool bGroupBarsPerAxis = true;
442 bool bIncludeHiddenCells = true;
443 bool bSecondaryYaxisVisible = true;
444 sal_Int32 nStartingAngle = 90;
445 sal_Int32 n3DRelativeHeight = 100;
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;
455 if (nDimensionCount == 3)
457 xDiaProp->getPropertyValue( "3DRelativeHeight" ) >>= n3DRelativeHeight;
460 catch( const uno::Exception & )
462 DBG_UNHANDLED_EXCEPTION("chart2" );
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
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 )
480 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
481 VCoordinateSystem* pVCooSys = addCooSysToList(m_rVCooSysList,xCooSys,rChartModel);
482 // Let's check whether the secondary Y axis is visible
485 Reference< beans::XPropertySet > xAxisProp(xCooSys->getAxisByDimension(1, 1), uno::UNO_QUERY);
486 if (xAxisProp.is())
488 xAxisProp->getPropertyValue("Show") >>= bSecondaryYaxisVisible;
491 catch (const lang::IndexOutOfBoundsException&)
493 TOOLS_WARN_EXCEPTION("chart2", "" );
495 //iterate through all chart types in the current coordinate system
496 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
497 OSL_ASSERT( xChartTypeContainer.is());
498 if( !xChartTypeContainer.is() )
499 continue;
500 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
501 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
503 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
504 if(nDimensionCount == 3 && xChartType->getChartType().equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE))
506 uno::Reference< beans::XPropertySet > xPropertySet( xChartType, uno::UNO_QUERY );
507 if (xPropertySet.is())
511 sal_Int32 n3DRelativeHeightOldValue(100);
512 uno::Any aAny = xPropertySet->getPropertyValue( "3DRelativeHeight" );
513 aAny >>= n3DRelativeHeightOldValue;
514 if (n3DRelativeHeightOldValue != n3DRelativeHeight)
515 xPropertySet->setPropertyValue( "3DRelativeHeight", uno::Any(n3DRelativeHeight) );
517 catch (const uno::Exception&) { }
521 bool bExcludingPositioning = DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_EXCLUDING;
522 VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( xChartType, nDimensionCount, bExcludingPositioning );
523 if( !pPlotter )
524 continue;
526 m_aSeriesPlotterList.push_back( std::unique_ptr<VSeriesPlotter>(pPlotter) );
527 pPlotter->setNumberFormatsSupplier( xNumberFormatsSupplier );
528 pPlotter->setColorScheme( xColorScheme );
529 if(pVCooSys)
530 pPlotter->setExplicitCategoriesProvider( pVCooSys->getExplicitCategoriesProvider() );
531 sal_Int32 nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( xDiagram, xChartType );
533 if(pVCooSys)
534 pVCooSys->addMinimumAndMaximumSupplier(pPlotter);
536 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
537 OSL_ASSERT( xDataSeriesContainer.is());
538 if( !xDataSeriesContainer.is() )
539 continue;
541 sal_Int32 zSlot=-1;
542 sal_Int32 xSlot=-1;
543 sal_Int32 ySlot=-1;
544 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
545 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
547 uno::Reference< XDataSeries > xDataSeries( aSeriesList[nS], uno::UNO_QUERY );
548 if(!xDataSeries.is())
549 continue;
550 if( !bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries) )
551 continue;
553 std::unique_ptr<VDataSeries> pSeries(new VDataSeries( xDataSeries ));
555 pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex);
556 nGlobalSeriesIndex++;
558 if( bSortByXValues )
559 pSeries->doSortByXValues();
561 pSeries->setConnectBars( bConnectBars );
562 pSeries->setGroupBarsPerAxis( bGroupBarsPerAxis );
563 pSeries->setStartingAngle( nStartingAngle );
565 pSeries->setMissingValueTreatment( nMissingValueTreatment );
567 OUString aSeriesParticle( ObjectIdentifier::createParticleForSeries( 0, nCS, nT, nS ) );
568 pSeries->setParticle(aSeriesParticle);
570 OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) );
571 pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole);
573 //ignore secondary axis for charttypes that do not support them
574 if( pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX &&
575 ( !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ) ||
576 !bSecondaryYaxisVisible ) )
578 pSeries->setAttachedAxisIndex(MAIN_AXIS_INDEX);
581 StackingDirection eDirection = pSeries->getStackingDirection();
582 switch(eDirection)
584 case StackingDirection_NO_STACKING:
585 xSlot++; ySlot=-1;
586 if(zSlot<0)
587 zSlot=0;
588 break;
589 case StackingDirection_Y_STACKING:
590 ySlot++;
591 if(xSlot<0)
592 xSlot=0;
593 if(zSlot<0)
594 zSlot=0;
595 break;
596 case StackingDirection_Z_STACKING:
597 zSlot++; xSlot=-1; ySlot=-1;
598 break;
599 default:
600 // UNO enums have one additional auto-generated case
601 break;
603 pPlotter->addSeries( std::move(pSeries), zSlot, xSlot, ySlot );
608 //transport seriesnames to the coordinatesystems if needed
609 if( !m_aSeriesPlotterList.empty() )
611 uno::Sequence< OUString > aSeriesNames;
612 bool bSeriesNamesInitialized = false;
613 for(auto & pVCooSys : m_rVCooSysList)
615 if( pVCooSys->needSeriesNamesForAxis() )
617 if(!bSeriesNamesInitialized)
619 aSeriesNames = m_aSeriesPlotterList[0]->getSeriesNames();
620 bSeriesNamesInitialized = true;
622 pVCooSys->setSeriesNamesForAxis( aSeriesNames );
628 bool SeriesPlotterContainer::isCategoryPositionShifted(
629 const chart2::ScaleData& rSourceScale, bool bHasComplexCategories )
631 if (rSourceScale.AxisType == AxisType::CATEGORY && rSourceScale.ShiftedCategoryPosition)
632 return true;
634 if (rSourceScale.AxisType == AxisType::CATEGORY && bHasComplexCategories)
635 return true;
637 if (rSourceScale.AxisType == AxisType::DATE)
638 return true;
640 if (rSourceScale.AxisType == AxisType::SERIES)
641 return true;
643 return false;
646 void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate)
648 m_aAxisUsageList.clear();
650 // Loop through coordinate systems in the diagram (though for now
651 // there should only be one coordinate system per diagram).
652 for (auto & pVCooSys : m_rVCooSysList)
654 uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel();
655 sal_Int32 nDimCount = xCooSys->getDimension();
657 for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex)
659 bool bDateAxisAllowed = ChartTypeHelper::isSupportingDateAxis(
660 AxisHelper::getChartTypeByIndex(xCooSys, 0), nDimIndex);
662 // Each dimension may have primary and secondary axes.
663 const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
664 for (sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; ++nAxisIndex)
666 uno::Reference<XAxis> xAxis = xCooSys->getAxisByDimension(nDimIndex, nAxisIndex);
668 if (!xAxis.is())
669 continue;
671 if (m_aAxisUsageList.find(xAxis) == m_aAxisUsageList.end())
673 // Create axis usage object for this axis.
675 chart2::ScaleData aSourceScale = xAxis->getScaleData();
676 ExplicitCategoriesProvider* pCatProvider = pVCooSys->getExplicitCategoriesProvider();
677 if (nDimIndex == 0)
678 AxisHelper::checkDateAxis( aSourceScale, pCatProvider, bDateAxisAllowed );
680 bool bHasComplexCat = pCatProvider && pCatProvider->hasComplexCategories();
681 aSourceScale.ShiftedCategoryPosition = isCategoryPositionShifted(aSourceScale, bHasComplexCat);
683 m_aAxisUsageList[xAxis].aAutoScaling = ScaleAutomatism(aSourceScale, rNullDate);
686 AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis];
687 rAxisUsage.addCoordinateSystem(pVCooSys.get(), nDimIndex, nAxisIndex);
692 // Determine the highest axis index of all dimensions.
693 m_nMaxAxisIndex = 0;
694 for (const auto & pVCooSys : m_rVCooSysList)
696 uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel();
697 sal_Int32 nDimCount = xCooSys->getDimension();
699 for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex)
701 for (auto & axisUsage : m_aAxisUsageList)
703 sal_Int32 nLocalMax = axisUsage.second.getMaxAxisIndexForDimension(nDimIndex);
704 if (m_nMaxAxisIndex < nLocalMax)
705 m_nMaxAxisIndex = nLocalMax;
711 void SeriesPlotterContainer::setScalesFromCooSysToPlotter()
713 //set scales to plotter to enable them to provide the preferred scene AspectRatio
714 for( const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
716 VSeriesPlotter* pSeriesPlotter = aPlotter.get();
717 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter );
718 if(pVCooSys)
720 pSeriesPlotter->setScales( pVCooSys->getExplicitScales(0,0), pVCooSys->getPropertySwapXAndYAxis() );
721 sal_Int32 nMaxAxisIndex = pVCooSys->getMaximumAxisIndexByDimension(1);//only additional value axis are relevant for series plotter
722 for( sal_Int32 nI=1; nI<=nMaxAxisIndex; nI++ )
723 pSeriesPlotter->addSecondaryValueScale( pVCooSys->getExplicitScale(1,nI), nI );
728 void SeriesPlotterContainer::setNumberFormatsFromAxes()
730 //set numberformats to plotter to enable them to display the data labels in the numberformat of the axis
731 for( const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
733 VSeriesPlotter* pSeriesPlotter = aPlotter.get();
734 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter );
735 if(pVCooSys)
737 AxesNumberFormats aAxesNumberFormats;
738 const uno::Reference< XCoordinateSystem >& xCooSys = pVCooSys->getModel();
739 sal_Int32 nDimensionCount = xCooSys->getDimension();
740 for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nDimensionCount; ++nDimensionIndex)
742 const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
743 for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex)
747 Reference< beans::XPropertySet > xAxisProp( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY );
748 if( xAxisProp.is())
750 sal_Int32 nNumberFormatKey(0);
751 if( xAxisProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey )
753 aAxesNumberFormats.setFormat( nNumberFormatKey, nDimensionIndex, nAxisIndex );
755 else if( nDimensionIndex==0 )
757 //provide a default date format for date axis with own data
758 aAxesNumberFormats.setFormat( m_nDefaultDateNumberFormat, nDimensionIndex, nAxisIndex );
762 catch( const lang::IndexOutOfBoundsException& )
764 TOOLS_WARN_EXCEPTION("chart2", "" );
768 pSeriesPlotter->setAxesNumberFormats( aAxesNumberFormats );
773 void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes()
775 for(auto & nC : m_rVCooSysList)
776 nC->updateScalesAndIncrementsOnAxes();
779 void SeriesPlotterContainer::doAutoScaling( ChartModel& rChartModel )
781 if (m_aSeriesPlotterList.empty() || m_aAxisUsageList.empty())
782 // We need these two containers populated to do auto-scaling. Bail out.
783 return;
785 //iterate over the main scales first than secondary axis
786 for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; ++nAxisIndex)
788 // - first do autoscale for all x and z scales (because they are treated independent)
789 for (auto & axisUsage : m_aAxisUsageList)
791 AxisUsage& rAxisUsage = axisUsage.second;
793 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 0, nAxisIndex);
794 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 2, nAxisIndex);
796 ExplicitScaleData aExplicitScale;
797 ExplicitIncrementData aExplicitIncrement;
798 rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement );
800 rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement);
801 rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement);
804 // - second do autoscale for the dependent y scales (the coordinate systems are prepared with x and z scales already )
805 for (auto & axisUsage : m_aAxisUsageList)
807 AxisUsage& rAxisUsage = axisUsage.second;
809 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAxisIndex);
811 ExplicitScaleData aExplicitScale;
812 ExplicitIncrementData aExplicitIncrement;
813 rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement );
815 rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement);
816 rAxisUsage.setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScale, aExplicitIncrement);
817 rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement);
820 AdaptScaleOfYAxisWithoutAttachedSeries( rChartModel );
823 void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel )
825 //issue #i80518#
826 for( sal_Int32 nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ )
828 for (auto & axisUsage : m_aAxisUsageList)
830 AxisUsage& rAxisUsage = axisUsage.second;
831 std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems( 1, nAxisIndex );
832 if( aVCooSysList_Y.empty() )
833 continue;
835 uno::Reference< XDiagram > xDiagram( rModel.getFirstDiagram() );
836 if (!xDiagram.is())
837 continue;
839 bool bSeriesAttachedToThisAxis = false;
840 sal_Int32 nAttachedAxisIndex = -1;
842 std::vector< Reference< XDataSeries > > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
843 for (auto const& series : aSeriesVector)
845 sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series);
846 if( nAxisIndex == nCurrentIndex )
848 bSeriesAttachedToThisAxis = true;
849 break;
851 else if( nAttachedAxisIndex<0 || nAttachedAxisIndex>nCurrentIndex )
852 nAttachedAxisIndex=nCurrentIndex;
856 if (bSeriesAttachedToThisAxis || nAttachedAxisIndex < 0)
857 continue;
859 for(VCoordinateSystem* nC : aVCooSysList_Y)
861 nC->prepareAutomaticAxisScaling( rAxisUsage.aAutoScaling, 1, nAttachedAxisIndex );
863 ExplicitScaleData aExplicitScaleSource = nC->getExplicitScale( 1,nAttachedAxisIndex );
864 ExplicitIncrementData aExplicitIncrementSource = nC->getExplicitIncrement( 1,nAttachedAxisIndex );
866 ExplicitScaleData aExplicitScaleDest = nC->getExplicitScale( 1,nAxisIndex );
867 ExplicitIncrementData aExplicitIncrementDest = nC->getExplicitIncrement( 1,nAxisIndex );
869 aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation;
870 aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling;
871 aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType;
873 aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue;
875 ScaleData aScale( rAxisUsage.aAutoScaling.getScale() );
876 if( !aScale.Minimum.hasValue() )
878 bool bNewMinOK = true;
879 double fMax=0.0;
880 if( aScale.Maximum >>= fMax )
881 bNewMinOK = (aExplicitScaleSource.Minimum <= fMax);
882 if( bNewMinOK )
883 aExplicitScaleDest.Minimum = aExplicitScaleSource.Minimum;
885 else
886 aExplicitIncrementDest.BaseValue = aExplicitScaleDest.Minimum;
888 if( !aScale.Maximum.hasValue() )
890 bool bNewMaxOK = true;
891 double fMin=0.0;
892 if( aScale.Minimum >>= fMin )
893 bNewMaxOK = (fMin <= aExplicitScaleSource.Maximum);
894 if( bNewMaxOK )
895 aExplicitScaleDest.Maximum = aExplicitScaleSource.Maximum;
897 if( !aScale.Origin.hasValue() )
898 aExplicitScaleDest.Origin = aExplicitScaleSource.Origin;
900 if( !aScale.IncrementData.Distance.hasValue() )
901 aExplicitIncrementDest.Distance = aExplicitIncrementSource.Distance;
903 bool bAutoMinorInterval = true;
904 if( aScale.IncrementData.SubIncrements.hasElements() )
905 bAutoMinorInterval = !( aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() );
906 if( bAutoMinorInterval )
908 if( !aExplicitIncrementDest.SubIncrements.empty() && !aExplicitIncrementSource.SubIncrements.empty() )
909 aExplicitIncrementDest.SubIncrements[0].IntervalCount =
910 aExplicitIncrementSource.SubIncrements[0].IntervalCount;
913 nC->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScaleDest, aExplicitIncrementDest );
918 if( AxisHelper::isAxisPositioningEnabled() )
920 //correct origin for y main axis (the origin is where the other main axis crosses)
921 sal_Int32 nAxisIndex=0;
922 sal_Int32 nDimensionIndex=1;
923 for (auto & axisUsage : m_aAxisUsageList)
925 AxisUsage& rAxisUsage = axisUsage.second;
926 std::vector< VCoordinateSystem* > aVCooSysList = rAxisUsage.getCoordinateSystems(nDimensionIndex,nAxisIndex);
927 size_t nC;
928 for( nC=0; nC < aVCooSysList.size(); nC++)
930 ExplicitScaleData aExplicitScale( aVCooSysList[nC]->getExplicitScale( nDimensionIndex, nAxisIndex ) );
931 ExplicitIncrementData aExplicitIncrement( aVCooSysList[nC]->getExplicitIncrement( nDimensionIndex, nAxisIndex ) );
933 Reference< chart2::XCoordinateSystem > xCooSys( aVCooSysList[nC]->getModel() );
934 Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) );
935 Reference< beans::XPropertySet > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ), uno::UNO_QUERY );
937 css::chart::ChartAxisPosition eCrossingMainAxisPos( css::chart::ChartAxisPosition_ZERO );
938 if( xCrossingMainAxis.is() )
940 xCrossingMainAxis->getPropertyValue("CrossoverPosition") >>= eCrossingMainAxisPos;
941 if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_VALUE )
943 double fValue = 0.0;
944 xCrossingMainAxis->getPropertyValue("CrossoverValue") >>= fValue;
945 aExplicitScale.Origin = fValue;
947 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_ZERO )
948 aExplicitScale.Origin = 0.0;
949 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_START )
950 aExplicitScale.Origin = aExplicitScale.Minimum;
951 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_END )
952 aExplicitScale.Origin = aExplicitScale.Maximum;
955 aVCooSysList[nC]->setExplicitScaleAndIncrement( nDimensionIndex, nAxisIndex, aExplicitScale, aExplicitIncrement );
961 drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio()
963 drawing::Direction3D aPreferredAspectRatio(1.0,1.0,1.0);
965 //get a list of all preferred aspect ratios and combine them
966 //first with special demands wins (less or equal zero <-> arbitrary)
967 double fx, fy, fz;
968 fx = fy = fz = -1.0;
969 for( const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
971 drawing::Direction3D aSingleRatio( aPlotter->getPreferredDiagramAspectRatio() );
972 if( fx<0 && aSingleRatio.DirectionX>0 )
973 fx = aSingleRatio.DirectionX;
975 if( fy<0 && aSingleRatio.DirectionY>0 )
977 if( fx>0 && aSingleRatio.DirectionX>0 )
978 fy = fx*aSingleRatio.DirectionY/aSingleRatio.DirectionX;
979 else if( fz>0 && aSingleRatio.DirectionZ>0 )
980 fy = fz*aSingleRatio.DirectionY/aSingleRatio.DirectionZ;
981 else
982 fy = aSingleRatio.DirectionY;
985 if( fz<0 && aSingleRatio.DirectionZ>0 )
987 if( fx>0 && aSingleRatio.DirectionX>0 )
988 fz = fx*aSingleRatio.DirectionZ/aSingleRatio.DirectionX;
989 else if( fy>0 && aSingleRatio.DirectionY>0 )
990 fz = fy*aSingleRatio.DirectionZ/aSingleRatio.DirectionY;
991 else
992 fz = aSingleRatio.DirectionZ;
995 if( fx>0 && fy>0 && fz>0 )
996 break;
998 aPreferredAspectRatio = drawing::Direction3D(fx, fy, fz);
999 return aPreferredAspectRatio;
1004 struct CreateShapeParam2D
1006 css::awt::Rectangle maRemainingSpace;
1008 std::shared_ptr<SeriesPlotterContainer> mpSeriesPlotterContainer;
1010 std::shared_ptr<VTitle> mpVTitleX;
1011 std::shared_ptr<VTitle> mpVTitleY;
1012 std::shared_ptr<VTitle> mpVTitleZ;
1014 std::shared_ptr<VTitle> mpVTitleSecondX;
1015 std::shared_ptr<VTitle> mpVTitleSecondY;
1017 css::uno::Reference<css::drawing::XShape> mxMarkHandles;
1018 css::uno::Reference<css::drawing::XShape> mxPlotAreaWithAxes;
1020 css::uno::Reference<css::drawing::XShapes> mxDiagramWithAxesShapes;
1022 bool mbAutoPosTitleX;
1023 bool mbAutoPosTitleY;
1024 bool mbAutoPosTitleZ;
1026 bool mbAutoPosSecondTitleX;
1027 bool mbAutoPosSecondTitleY;
1029 bool mbUseFixedInnerSize;
1031 CreateShapeParam2D() :
1032 mbAutoPosTitleX(true),
1033 mbAutoPosTitleY(true),
1034 mbAutoPosTitleZ(true),
1035 mbAutoPosSecondTitleX(true),
1036 mbAutoPosSecondTitleY(true),
1037 mbUseFixedInnerSize(false) {}
1040 const uno::Sequence<sal_Int8>& ExplicitValueProvider::getUnoTunnelId()
1042 return theExplicitValueProviderUnoTunnelId::get().getSeq();
1045 ChartView::ChartView(
1046 uno::Reference<uno::XComponentContext> const & xContext,
1047 ChartModel& rModel)
1048 : m_aMutex()
1049 , m_xCC(xContext)
1050 , mrChartModel(rModel)
1051 , m_xShapeFactory()
1052 , m_xDrawPage()
1053 , m_pDrawModelWrapper()
1054 , m_aListenerContainer( m_aMutex )
1055 , m_bViewDirty(true)
1056 , m_bInViewUpdate(false)
1057 , m_bViewUpdatePending(false)
1058 , m_bRefreshAddIn(true)
1059 , m_aPageResolution(1000,1000)
1060 , m_bPointsWereSkipped(false)
1061 , m_nScaleXNumerator(1)
1062 , m_nScaleXDenominator(1)
1063 , m_nScaleYNumerator(1)
1064 , m_nScaleYDenominator(1)
1065 , m_bSdrViewIsInEditMode(false)
1066 , m_aResultingDiagramRectangleExcludingAxes(0,0,0,0)
1068 init();
1071 void ChartView::init()
1073 if( !m_pDrawModelWrapper.get() )
1075 SolarMutexGuard aSolarGuard;
1076 m_pDrawModelWrapper = std::make_shared< DrawModelWrapper >();
1077 m_xShapeFactory = m_pDrawModelWrapper->getShapeFactory();
1078 m_xDrawPage = m_pDrawModelWrapper->getMainDrawPage();
1079 StartListening( m_pDrawModelWrapper->getSdrModel() );
1083 void SAL_CALL ChartView::initialize( const uno::Sequence< uno::Any >& )
1085 init();
1088 ChartView::~ChartView()
1090 maTimeBased.maTimer.Stop();
1091 // #i120831#. In ChartView::initialize(), m_xShapeFactory is created from SdrModel::getUnoModel() and indirectly
1092 // from SfxBaseModel, it needs call dispose() to make sure SfxBaseModel object is freed correctly.
1093 uno::Reference< lang::XComponent > xComp( m_xShapeFactory, uno::UNO_QUERY);
1094 if ( xComp.is() )
1095 xComp->dispose();
1097 if( m_pDrawModelWrapper.get() )
1099 SolarMutexGuard aSolarGuard;
1100 EndListening( m_pDrawModelWrapper->getSdrModel() );
1101 m_pDrawModelWrapper.reset();
1103 m_xDrawPage = nullptr;
1104 impl_deleteCoordinateSystems();
1107 void ChartView::impl_deleteCoordinateSystems()
1109 //delete all coordinate systems
1110 m_aVCooSysList.clear();
1113 // datatransfer::XTransferable
1114 namespace
1116 const OUString lcl_aGDIMetaFileMIMEType(
1117 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" );
1118 const OUString lcl_aGDIMetaFileMIMETypeHighContrast(
1119 "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" );
1120 } // anonymous namespace
1122 void ChartView::getMetaFile( const uno::Reference< io::XOutputStream >& xOutStream
1123 , bool bUseHighContrast )
1125 if( !m_xDrawPage.is() )
1126 return;
1128 // creating the graphic exporter
1129 uno::Reference< drawing::XGraphicExportFilter > xExporter = drawing::GraphicExportFilter::create( m_xCC );
1131 uno::Sequence< beans::PropertyValue > aProps(3);
1132 aProps[0].Name = "FilterName";
1133 aProps[0].Value <<= OUString("SVM");
1135 aProps[1].Name = "OutputStream";
1136 aProps[1].Value <<= xOutStream;
1138 uno::Sequence< beans::PropertyValue > aFilterData(8);
1139 aFilterData[0].Name = "ExportOnlyBackground";
1140 aFilterData[0].Value <<= false;
1141 aFilterData[1].Name = "HighContrast";
1142 aFilterData[1].Value <<= bUseHighContrast;
1144 aFilterData[2].Name = "Version";
1145 const sal_Int32 nVersion = SOFFICE_FILEFORMAT_50;
1146 aFilterData[2].Value <<= nVersion;
1148 aFilterData[3].Name = "CurrentPage";
1149 aFilterData[3].Value <<= uno::Reference< uno::XInterface >( m_xDrawPage, uno::UNO_QUERY );
1151 //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
1152 aFilterData[4].Name = "ScaleXNumerator";
1153 aFilterData[4].Value <<= m_nScaleXNumerator;
1154 aFilterData[5].Name = "ScaleXDenominator";
1155 aFilterData[5].Value <<= m_nScaleXDenominator;
1156 aFilterData[6].Name = "ScaleYNumerator";
1157 aFilterData[6].Value <<= m_nScaleYNumerator;
1158 aFilterData[7].Name = "ScaleYDenominator";
1159 aFilterData[7].Value <<= m_nScaleYDenominator;
1162 aProps[2].Name = "FilterData";
1163 aProps[2].Value <<= aFilterData;
1165 xExporter->setSourceDocument( uno::Reference< lang::XComponent >( m_xDrawPage, uno::UNO_QUERY) );
1166 if( xExporter->filter( aProps ) )
1168 xOutStream->flush();
1169 xOutStream->closeOutput();
1170 uno::Reference< io::XSeekable > xSeekable( xOutStream, uno::UNO_QUERY );
1171 if( xSeekable.is() )
1172 xSeekable->seek(0);
1176 uno::Any SAL_CALL ChartView::getTransferData( const datatransfer::DataFlavor& aFlavor )
1178 bool bHighContrastMetaFile( aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast);
1179 uno::Any aRet;
1180 if( ! (bHighContrastMetaFile || aFlavor.MimeType == lcl_aGDIMetaFileMIMEType) )
1181 return aRet;
1183 update();
1185 SvMemoryStream aStream( 1024, 1024 );
1186 utl::OStreamWrapper* pStreamWrapper = new utl::OStreamWrapper( aStream );
1188 uno::Reference< io::XOutputStream > xOutStream( pStreamWrapper );
1189 uno::Reference< io::XInputStream > xInStream( pStreamWrapper );
1190 uno::Reference< io::XSeekable > xSeekable( pStreamWrapper );
1192 if( xOutStream.is() )
1194 this->getMetaFile( xOutStream, bHighContrastMetaFile );
1196 if( xInStream.is() && xSeekable.is() )
1198 xSeekable->seek(0);
1199 sal_Int32 nBytesToRead = xInStream->available();
1200 uno::Sequence< sal_Int8 > aSeq( nBytesToRead );
1201 xInStream->readBytes( aSeq, nBytesToRead);
1202 aRet <<= aSeq;
1203 xInStream->closeInput();
1207 return aRet;
1209 uno::Sequence< datatransfer::DataFlavor > SAL_CALL ChartView::getTransferDataFlavors()
1211 uno::Sequence< datatransfer::DataFlavor > aRet(2);
1213 aRet[0] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMEType,
1214 "GDIMetaFile",
1215 cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
1216 aRet[1] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast,
1217 "GDIMetaFile",
1218 cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
1220 return aRet;
1222 sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
1224 return ( aFlavor.MimeType == lcl_aGDIMetaFileMIMEType ||
1225 aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast );
1228 // ____ XUnoTunnel ___
1229 ::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier )
1231 if( isUnoTunnelId<ExplicitValueProvider>(aIdentifier) )
1233 ExplicitValueProvider* pProvider = this;
1234 return reinterpret_cast<sal_Int64>(pProvider);
1236 return 0;
1239 // lang::XServiceInfo
1241 OUString SAL_CALL ChartView::getImplementationName()
1243 return CHART_VIEW_SERVICE_IMPLEMENTATION_NAME;
1246 sal_Bool SAL_CALL ChartView::supportsService( const OUString& rServiceName )
1248 return cppu::supportsService(this, rServiceName);
1251 css::uno::Sequence< OUString > SAL_CALL ChartView::getSupportedServiceNames()
1253 return { CHART_VIEW_SERVICE_NAME };
1256 static ::basegfx::B3DHomMatrix createTransformationSceneToScreen(
1257 const ::basegfx::B2IRectangle& rDiagramRectangleWithoutAxes )
1259 ::basegfx::B3DHomMatrix aM;
1260 aM.scale(double(rDiagramRectangleWithoutAxes.getWidth())/FIXED_SIZE_FOR_3D_CHART_VOLUME
1261 , -double(rDiagramRectangleWithoutAxes.getHeight())/FIXED_SIZE_FOR_3D_CHART_VOLUME, 1.0 );
1262 aM.translate(double(rDiagramRectangleWithoutAxes.getMinX())
1263 , double(rDiagramRectangleWithoutAxes.getMinY()+rDiagramRectangleWithoutAxes.getHeight()-1), 0);
1264 return aM;
1267 namespace
1270 bool lcl_IsPieOrDonut( const uno::Reference< XDiagram >& xDiagram )
1272 //special treatment for pie charts
1273 //the size is checked after complete creation to get the datalabels into the given space
1275 //todo: this is just a workaround at the moment for pie and donut labels
1276 return DiagramHelper::isPieOrDonutChart( xDiagram );
1279 void lcl_setDefaultWritingMode( const std::shared_ptr< DrawModelWrapper >& pDrawModelWrapper, ChartModel& rModel)
1281 //get writing mode from parent document:
1282 if( SvtLanguageOptions().IsCTLFontEnabled() )
1286 sal_Int16 nWritingMode=-1;
1287 uno::Reference< beans::XPropertySet > xParentProps( rModel.getParent(), uno::UNO_QUERY );
1288 uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSupplier( xParentProps, uno::UNO_QUERY );
1289 if( xStyleFamiliesSupplier.is() )
1291 uno::Reference< container::XNameAccess > xStylesFamilies( xStyleFamiliesSupplier->getStyleFamilies() );
1292 if( xStylesFamilies.is() )
1294 if( !xStylesFamilies->hasByName( "PageStyles" ) )
1296 //draw/impress is parent document
1297 uno::Reference< lang::XMultiServiceFactory > xFatcory( xParentProps, uno::UNO_QUERY );
1298 if( xFatcory.is() )
1300 uno::Reference< beans::XPropertySet > xDrawDefaults( xFatcory->createInstance( "com.sun.star.drawing.Defaults" ), uno::UNO_QUERY );
1301 if( xDrawDefaults.is() )
1302 xDrawDefaults->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1305 else
1307 uno::Reference< container::XNameAccess > xPageStyles( xStylesFamilies->getByName( "PageStyles" ), uno::UNO_QUERY );
1308 if( xPageStyles.is() )
1310 OUString aPageStyle;
1312 uno::Reference< text::XTextDocument > xTextDocument( xParentProps, uno::UNO_QUERY );
1313 if( xTextDocument.is() )
1315 //writer is parent document
1316 //retrieve the current page style from the text cursor property PageStyleName
1318 uno::Reference< text::XTextEmbeddedObjectsSupplier > xTextEmbeddedObjectsSupplier( xTextDocument, uno::UNO_QUERY );
1319 if( xTextEmbeddedObjectsSupplier.is() )
1321 uno::Reference< container::XNameAccess > xEmbeddedObjects( xTextEmbeddedObjectsSupplier->getEmbeddedObjects() );
1322 if( xEmbeddedObjects.is() )
1324 uno::Sequence< OUString > aNames( xEmbeddedObjects->getElementNames() );
1326 sal_Int32 nCount = aNames.getLength();
1327 for( sal_Int32 nN=0; nN<nCount; nN++ )
1329 uno::Reference< beans::XPropertySet > xEmbeddedProps( xEmbeddedObjects->getByName( aNames[nN] ), uno::UNO_QUERY );
1330 if( xEmbeddedProps.is() )
1332 static OUString aChartCLSID = SvGlobalName( SO3_SCH_CLASSID ).GetHexName();
1333 OUString aCLSID;
1334 xEmbeddedProps->getPropertyValue( "CLSID" ) >>= aCLSID;
1335 if( aCLSID == aChartCLSID )
1337 uno::Reference< text::XTextContent > xEmbeddedObject( xEmbeddedProps, uno::UNO_QUERY );
1338 if( xEmbeddedObject.is() )
1340 uno::Reference< text::XTextRange > xAnchor( xEmbeddedObject->getAnchor() );
1341 if( xAnchor.is() )
1343 uno::Reference< beans::XPropertySet > xAnchorProps( xAnchor, uno::UNO_QUERY );
1344 if( xAnchorProps.is() )
1346 xAnchorProps->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1348 uno::Reference< text::XText > xText( xAnchor->getText() );
1349 if( xText.is() )
1351 uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY );
1352 if( xTextCursorProps.is() )
1353 xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle;
1357 break;
1363 if( aPageStyle.isEmpty() )
1365 uno::Reference< text::XText > xText( xTextDocument->getText() );
1366 if( xText.is() )
1368 uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY );
1369 if( xTextCursorProps.is() )
1370 xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle;
1374 else
1376 //Calc is parent document
1377 xParentProps->getPropertyValue( "PageStyle" ) >>= aPageStyle;
1378 if(aPageStyle.isEmpty())
1379 aPageStyle = "Default";
1381 if( nWritingMode == -1 || nWritingMode == text::WritingMode2::PAGE )
1383 uno::Reference< beans::XPropertySet > xPageStyle( xPageStyles->getByName( aPageStyle ), uno::UNO_QUERY );
1384 if( xPageStyle.is() )
1385 xPageStyle->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1391 if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE )
1393 if( pDrawModelWrapper.get() )
1394 pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SvxFrameDirectionItem(static_cast<SvxFrameDirection>(nWritingMode), EE_PARA_WRITINGDIR) );
1397 catch( const uno::Exception& )
1399 DBG_UNHANDLED_EXCEPTION("chart2" );
1404 sal_Int16 lcl_getDefaultWritingModeFromPool( const std::shared_ptr<DrawModelWrapper>& pDrawModelWrapper )
1406 sal_Int16 nWritingMode = text::WritingMode2::LR_TB;
1407 if(!pDrawModelWrapper)
1408 return nWritingMode;
1410 const SfxPoolItem& rItem = pDrawModelWrapper->GetItemPool().GetDefaultItem(EE_PARA_WRITINGDIR);
1411 nWritingMode
1412 = static_cast<sal_Int16>(static_cast<const SvxFrameDirectionItem&>(rItem).GetValue());
1413 return nWritingMode;
1416 } //end anonymous namespace
1418 awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D& rParam, const awt::Size& rPageSize )
1420 //return the used rectangle
1421 awt::Rectangle aUsedOuterRect(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y, 0, 0);
1423 uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() );
1424 if( !xDiagram.is())
1425 return aUsedOuterRect;
1427 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
1428 if(!nDimensionCount)
1430 //@todo handle mixed dimension
1431 nDimensionCount = 2;
1434 basegfx::B2IRectangle aAvailableOuterRect = BaseGFXHelper::makeRectangle(rParam.maRemainingSpace);
1436 const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList( rParam.mpSeriesPlotterContainer->getCooSysList() );
1437 SeriesPlottersType& rSeriesPlotterList = rParam.mpSeriesPlotterContainer->getSeriesPlotterList();
1439 //create VAxis, so they can give necessary information for automatic scaling
1440 uno::Reference<chart2::XChartDocument> const xChartDoc(&mrChartModel);
1441 uno::Reference<util::XNumberFormatsSupplier> const xNumberFormatsSupplier(
1442 mrChartModel.getNumberFormatsSupplier());
1443 size_t nC = 0;
1444 for( nC=0; nC < rVCooSysList.size(); nC++)
1446 VCoordinateSystem* pVCooSys = rVCooSysList[nC].get();
1447 if(nDimensionCount==3)
1449 uno::Reference<beans::XPropertySet> xSceneProperties( xDiagram, uno::UNO_QUERY );
1450 CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xSceneProperties ) );
1451 CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xSceneProperties ) );
1452 CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xSceneProperties ) );
1453 pVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos );
1456 pVCooSys->createVAxisList(xChartDoc, rPageSize, rParam.maRemainingSpace, rParam.mbUseFixedInnerSize);
1459 // - prepare list of all axis and how they are used
1460 Date aNullDate = NumberFormatterWrapper( xNumberFormatsSupplier ).getNullDate();
1461 rParam.mpSeriesPlotterContainer->initAxisUsageList(aNullDate);
1462 rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel );
1463 rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter();
1464 rParam.mpSeriesPlotterContainer->setNumberFormatsFromAxes();
1466 //create shapes
1468 //aspect ratio
1469 drawing::Direction3D aPreferredAspectRatio =
1470 rParam.mpSeriesPlotterContainer->getPreferredAspectRatio();
1472 uno::Reference< drawing::XShapes > xSeriesTargetInFrontOfAxis;
1473 uno::Reference< drawing::XShapes > xSeriesTargetBehindAxis;
1474 VDiagram aVDiagram(xDiagram, aPreferredAspectRatio, nDimensionCount);
1475 {//create diagram
1476 aVDiagram.init(rParam.mxDiagramWithAxesShapes, m_xShapeFactory);
1477 aVDiagram.createShapes(
1478 awt::Point(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y),
1479 awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height));
1481 xSeriesTargetInFrontOfAxis = aVDiagram.getCoordinateRegion();
1482 // It is preferable to use full size than minimum for pie charts
1483 if (!rParam.mbUseFixedInnerSize)
1484 aVDiagram.reduceToMimimumSize();
1487 uno::Reference< drawing::XShapes > xTextTargetShapes =
1488 ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory)->createGroup2D(rParam.mxDiagramWithAxesShapes);
1490 // - create axis and grids for all coordinate systems
1492 //init all coordinate systems
1493 for( nC=0; nC < rVCooSysList.size(); nC++)
1495 VCoordinateSystem* pVCooSys = rVCooSysList[nC].get();
1496 pVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis,xTextTargetShapes,m_xShapeFactory,xSeriesTargetBehindAxis);
1498 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1499 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1501 pVCooSys->initVAxisInList();
1504 //calculate resulting size respecting axis label layout and fontscaling
1506 uno::Reference< drawing::XShape > xBoundingShape(rParam.mxDiagramWithAxesShapes, uno::UNO_QUERY);
1507 ::basegfx::B2IRectangle aConsumedOuterRect;
1509 //use first coosys only so far; todo: calculate for more than one coosys if we have more in future
1510 //todo: this is just a workaround at the moment for pie and donut labels
1511 bool bIsPieOrDonut = lcl_IsPieOrDonut(xDiagram);
1512 if( !bIsPieOrDonut && (!rVCooSysList.empty()) )
1514 VCoordinateSystem* pVCooSys = rVCooSysList[0].get();
1515 pVCooSys->createMaximumAxesLabels();
1517 aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape);
1518 ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() );
1519 if (!rParam.mbUseFixedInnerSize)
1520 aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect );
1522 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1523 createTransformationSceneToScreen( aNewInnerRect ) ));
1525 //redo autoscaling to get size and text dependent automatic main increment count
1526 rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel );
1527 rParam.mpSeriesPlotterContainer->updateScalesAndIncrementsOnAxes();
1528 rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter();
1530 pVCooSys->createAxesLabels();
1532 bool bLessSpaceConsumedThanExpected = false;
1534 aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape);
1535 if( aConsumedOuterRect.getMinX() > aAvailableOuterRect.getMinX()
1536 || aConsumedOuterRect.getMaxX() < aAvailableOuterRect.getMaxX()
1537 || aConsumedOuterRect.getMinY() > aAvailableOuterRect.getMinY()
1538 || aConsumedOuterRect.getMinY() < aAvailableOuterRect.getMaxY() )
1539 bLessSpaceConsumedThanExpected = true;
1542 if (bLessSpaceConsumedThanExpected && !rParam.mbUseFixedInnerSize)
1544 aVDiagram.adjustInnerSize( aConsumedOuterRect );
1545 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1546 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1548 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
1551 //create axes and grids for the final size
1552 for( nC=0; nC < rVCooSysList.size(); nC++)
1554 VCoordinateSystem* pVCooSys = rVCooSysList[nC].get();
1556 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1557 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1559 pVCooSys->createAxesShapes();
1560 pVCooSys->createGridShapes();
1563 // - create data series for all charttypes
1564 m_bPointsWereSkipped = false;
1565 for( const std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1567 VSeriesPlotter* pSeriesPlotter = aPlotter.get();
1568 uno::Reference< drawing::XShapes > xSeriesTarget;
1569 if( pSeriesPlotter->WantToPlotInFrontOfAxisLine() )
1570 xSeriesTarget = xSeriesTargetInFrontOfAxis;
1571 else
1573 xSeriesTarget = xSeriesTargetBehindAxis;
1574 OSL_ENSURE( !bIsPieOrDonut, "not implemented yet! - during a complete recreation this shape is destroyed so no series can be created anymore" );
1576 pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,m_xShapeFactory,OUString() );
1577 pSeriesPlotter->setPageReferenceSize( rPageSize );
1578 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter );
1579 if(nDimensionCount==2)
1580 pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() );
1581 //better performance for big data
1583 //calculate resolution for coordinate system
1584 Sequence<sal_Int32> aCoordinateSystemResolution = pVCooSys->getCoordinateSystemResolution( rPageSize, m_aPageResolution );
1585 pSeriesPlotter->setCoordinateSystemResolution( aCoordinateSystemResolution );
1588 pSeriesPlotter->createShapes();
1589 m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped();
1592 //recreate all with corrected sizes if requested
1593 if( bIsPieOrDonut )
1595 m_bPointsWereSkipped = false;
1597 aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape);
1598 ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() );
1599 if (!rParam.mbUseFixedInnerSize)
1600 aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect );
1602 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1604 aPlotter->releaseShapes();
1607 //clear and recreate
1608 ShapeFactory::removeSubShapes( xSeriesTargetInFrontOfAxis ); //xSeriesTargetBehindAxis is a sub shape of xSeriesTargetInFrontOfAxis and will be removed here
1609 xSeriesTargetBehindAxis.clear();
1610 ShapeFactory::removeSubShapes( xTextTargetShapes );
1612 //set new transformation
1613 for( nC=0; nC < rVCooSysList.size(); nC++)
1615 VCoordinateSystem* pVCooSys = rVCooSysList[nC].get();
1616 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1617 createTransformationSceneToScreen( aNewInnerRect ) ));
1620 // - create data series for all charttypes
1621 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1623 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, aPlotter.get() );
1624 if(nDimensionCount==2)
1625 aPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() );
1626 aPlotter->createShapes();
1627 m_bPointsWereSkipped = m_bPointsWereSkipped || aPlotter->PointsWereSkipped();
1630 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1631 aPlotter->rearrangeLabelToAvoidOverlapIfRequested(rPageSize);
1634 if (rParam.mbUseFixedInnerSize)
1636 aUsedOuterRect = awt::Rectangle( aConsumedOuterRect.getMinX(), aConsumedOuterRect.getMinY(), aConsumedOuterRect.getWidth(), aConsumedOuterRect.getHeight() );
1638 else
1639 aUsedOuterRect = rParam.maRemainingSpace;
1641 bool bSnapRectToUsedArea = false;
1642 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1644 bSnapRectToUsedArea = aPlotter->shouldSnapRectToUsedArea();
1645 if(bSnapRectToUsedArea)
1646 break;
1648 if(bSnapRectToUsedArea)
1650 if (rParam.mbUseFixedInnerSize)
1651 m_aResultingDiagramRectangleExcludingAxes = getRectangleOfObject( "PlotAreaExcludingAxes" );
1652 else
1654 ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle();
1655 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() );
1658 else
1660 if (rParam.mbUseFixedInnerSize)
1661 m_aResultingDiagramRectangleExcludingAxes = rParam.maRemainingSpace;
1662 else
1664 ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle();
1665 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() );
1669 if (rParam.mxMarkHandles.is())
1671 awt::Point aPos(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y);
1672 awt::Size aSize(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height);
1674 bool bPosSizeExcludeAxesProperty = true;
1675 uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY_THROW );
1676 xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxesProperty;
1677 if (rParam.mbUseFixedInnerSize || bPosSizeExcludeAxesProperty)
1679 aPos = awt::Point( m_aResultingDiagramRectangleExcludingAxes.X, m_aResultingDiagramRectangleExcludingAxes.Y );
1680 aSize = awt::Size( m_aResultingDiagramRectangleExcludingAxes.Width, m_aResultingDiagramRectangleExcludingAxes.Height );
1682 rParam.mxMarkHandles->setPosition(aPos);
1683 rParam.mxMarkHandles->setSize(aSize);
1686 return aUsedOuterRect;
1689 bool ChartView::getExplicitValuesForAxis(
1690 uno::Reference< XAxis > xAxis
1691 , ExplicitScaleData& rExplicitScale
1692 , ExplicitIncrementData& rExplicitIncrement )
1694 SolarMutexGuard aSolarGuard;
1696 impl_updateView();
1698 if(!xAxis.is())
1699 return false;
1701 uno::Reference< XCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstDiagram() ) );
1702 const VCoordinateSystem* pVCooSys = findInCooSysList(m_aVCooSysList,xCooSys);
1703 if(!pVCooSys)
1704 return false;
1706 sal_Int32 nDimensionIndex=-1;
1707 sal_Int32 nAxisIndex=-1;
1708 if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) )
1710 rExplicitScale = pVCooSys->getExplicitScale(nDimensionIndex,nAxisIndex);
1711 rExplicitIncrement = pVCooSys->getExplicitIncrement(nDimensionIndex,nAxisIndex);
1712 if( rExplicitScale.ShiftedCategoryPosition )
1714 //remove 'one' from max
1715 if( rExplicitScale.AxisType == css::chart2::AxisType::DATE )
1717 Date aMaxDate(rExplicitScale.NullDate); aMaxDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Maximum));
1718 //for explicit scales with shifted categories we need one interval more
1719 switch( rExplicitScale.TimeResolution )
1721 case css::chart::TimeUnit::DAY:
1722 --aMaxDate;
1723 break;
1724 case css::chart::TimeUnit::MONTH:
1725 aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1);
1726 break;
1727 case css::chart::TimeUnit::YEAR:
1728 aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1);
1729 break;
1731 rExplicitScale.Maximum = aMaxDate - rExplicitScale.NullDate;
1733 else if( rExplicitScale.AxisType == css::chart2::AxisType::CATEGORY )
1734 rExplicitScale.Maximum -= 1.0;
1735 else if( rExplicitScale.AxisType == css::chart2::AxisType::SERIES )
1736 rExplicitScale.Maximum -= 1.0;
1738 return true;
1740 return false;
1743 SdrPage* ChartView::getSdrPage()
1745 auto pSvxDrawPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>(m_xDrawPage);
1746 if(pSvxDrawPage)
1747 return pSvxDrawPage->GetSdrPage();
1749 return nullptr;
1752 uno::Reference< drawing::XShape > ChartView::getShapeForCID( const OUString& rObjectCID )
1754 SolarMutexGuard aSolarGuard;
1755 SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() );
1756 if( pObj )
1757 return uno::Reference< drawing::XShape >( pObj->getUnoShape(), uno::UNO_QUERY);
1758 return nullptr;
1761 awt::Rectangle ChartView::getDiagramRectangleExcludingAxes()
1763 impl_updateView();
1764 return m_aResultingDiagramRectangleExcludingAxes;
1767 awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool bSnapRect )
1769 impl_updateView();
1771 awt::Rectangle aRet;
1772 uno::Reference< drawing::XShape > xShape( getShapeForCID(rObjectCID) );
1773 if(xShape.is())
1775 //special handling for axis for old api:
1776 //same special handling for diagram
1777 ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) );
1778 if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_DIAGRAM )
1780 SolarMutexGuard aSolarGuard;
1781 SvxShape* pRoot = comphelper::getUnoTunnelImplementation<SvxShape>( xShape );
1782 if( pRoot )
1784 SdrObject* pRootSdrObject = pRoot->GetSdrObject();
1785 if( pRootSdrObject )
1787 SdrObjList* pRootList = pRootSdrObject->GetSubList();
1788 if( pRootList )
1790 OUString aShapeName = "MarkHandles";
1791 if( eObjectType == OBJECTTYPE_DIAGRAM )
1792 aShapeName = "PlotAreaIncludingAxes";
1793 SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( aShapeName, pRootList );
1794 if( pShape )
1795 xShape.set( pShape->getUnoShape(), uno::UNO_QUERY);
1801 awt::Size aSize( xShape->getSize() );
1802 awt::Point aPoint( xShape->getPosition() );
1803 aRet = awt::Rectangle( aPoint.X, aPoint.Y, aSize.Width, aSize.Height );
1804 if( bSnapRect )
1806 //for rotated objects the shape size and position differs from the visible rectangle
1807 SvxShape* pShape = comphelper::getUnoTunnelImplementation<SvxShape>( xShape );
1808 if( pShape )
1810 SdrObject* pSdrObject = pShape->GetSdrObject();
1811 if( pSdrObject )
1813 tools::Rectangle aSnapRect( pSdrObject->GetSnapRect() );
1814 aRet = awt::Rectangle(aSnapRect.Left(),aSnapRect.Top(),aSnapRect.GetWidth(),aSnapRect.GetHeight());
1819 return aRet;
1822 std::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper()
1824 return m_pDrawModelWrapper;
1827 namespace
1829 sal_Int32 lcl_getDiagramTitleSpace()
1831 return 200; //=0,2 cm spacing
1833 bool lcl_getPropertySwapXAndYAxis( const uno::Reference< XDiagram >& xDiagram )
1835 bool bSwapXAndY = false;
1837 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
1838 if( xCooSysContainer.is() )
1840 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
1841 if( aCooSysList.hasElements() )
1843 uno::Reference<beans::XPropertySet> xProp(aCooSysList[0], uno::UNO_QUERY );
1844 if( xProp.is()) try
1846 xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY;
1848 catch( const uno::Exception& )
1850 TOOLS_WARN_EXCEPTION("chart2", "" );
1854 return bSwapXAndY;
1859 sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForAxis(
1860 const Reference< chart2::XAxis >& xAxis
1861 , const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem
1862 , const Reference<chart2::XChartDocument>& xChartDoc)
1864 return AxisHelper::getExplicitNumberFormatKeyForAxis( xAxis, xCorrespondingCoordinateSystem, xChartDoc
1865 , true /*bSearchForParallelAxisIfNothingIsFound*/ );
1868 sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel(
1869 const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp,
1870 const uno::Reference< XDataSeries >& xSeries,
1871 sal_Int32 nPointIndex /*-1 for whole series*/,
1872 const uno::Reference< XDiagram >& xDiagram
1875 sal_Int32 nFormat=0;
1876 if( !xSeriesOrPointProp.is() )
1877 return nFormat;
1879 bool bLinkToSource = true;
1882 xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource;
1884 catch ( const beans::UnknownPropertyException& ) {}
1886 xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat;
1887 sal_Int32 nOldFormat = nFormat;
1888 if (bLinkToSource)
1890 uno::Reference< chart2::XChartType > xChartType( DataSeriesHelper::getChartTypeOfSeries( xSeries, xDiagram ) );
1892 bool bFormatFound = false;
1893 if( ChartTypeHelper::shouldLabelNumberFormatKeyBeDetectedFromYAxis( xChartType ) )
1895 uno::Reference< beans::XPropertySet > xAttachedAxisProps( DiagramHelper::getAttachedAxis( xSeries, xDiagram ), uno::UNO_QUERY );
1896 if (xAttachedAxisProps.is() && (xAttachedAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat))
1897 bFormatFound = true;
1899 if( !bFormatFound )
1901 Reference< chart2::data::XDataSource > xSeriesSource( xSeries, uno::UNO_QUERY );
1902 OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) );
1904 Reference< data::XLabeledDataSequence > xLabeledSequence(
1905 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, aRole ));
1906 if( xLabeledSequence.is() )
1908 Reference< data::XDataSequence > xValues( xLabeledSequence->getValues() );
1909 if( xValues.is() )
1910 nFormat = xValues->getNumberFormatKeyByIndex( nPointIndex );
1914 if (nFormat >= 0 && nOldFormat != nFormat)
1915 xSeriesOrPointProp->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any(nFormat));
1918 if(nFormat<0)
1919 nFormat=0;
1920 return nFormat;
1923 sal_Int32 ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel(
1924 const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp,
1925 const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
1927 sal_Int32 nFormat=0;
1928 if( !xSeriesOrPointProp.is() )
1929 return nFormat;
1930 if( !(xSeriesOrPointProp->getPropertyValue("PercentageNumberFormat") >>= nFormat) )
1932 nFormat = DiagramHelper::getPercentNumberFormat( xNumberFormatsSupplier );
1934 if(nFormat<0)
1935 nFormat=0;
1936 return nFormat;
1939 awt::Rectangle ExplicitValueProvider::AddSubtractAxisTitleSizes(
1940 ChartModel& rModel
1941 , const Reference< uno::XInterface >& xChartView
1942 , const awt::Rectangle& rPositionAndSize, bool bSubtract )
1944 awt::Rectangle aRet(rPositionAndSize);
1946 //add axis title sizes to the diagram size
1947 uno::Reference< chart2::XTitle > xTitle_Height( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, rModel ) );
1948 uno::Reference< chart2::XTitle > xTitle_Width( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, rModel ) );
1949 uno::Reference< chart2::XTitle > xSecondTitle_Height( TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, rModel ) );
1950 uno::Reference< chart2::XTitle > xSecondTitle_Width( TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, rModel ) );
1951 if( xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() || xSecondTitle_Width.is() )
1953 ExplicitValueProvider* pExplicitValueProvider = comphelper::getUnoTunnelImplementation<ExplicitValueProvider>(xChartView);
1954 if( pExplicitValueProvider )
1956 //detect whether x axis points into x direction or not
1957 if( lcl_getPropertySwapXAndYAxis( rModel.getFirstDiagram() ) )
1959 std::swap( xTitle_Height, xTitle_Width );
1960 std::swap( xSecondTitle_Height, xSecondTitle_Width );
1963 sal_Int32 nTitleSpaceWidth = 0;
1964 sal_Int32 nTitleSpaceHeight = 0;
1965 sal_Int32 nSecondTitleSpaceWidth = 0;
1966 sal_Int32 nSecondTitleSpaceHeight = 0;
1968 if( xTitle_Height.is() )
1970 OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Height, rModel ) );
1971 nTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height;
1972 if( nTitleSpaceHeight )
1973 nTitleSpaceHeight+=lcl_getDiagramTitleSpace();
1975 if( xTitle_Width.is() )
1977 OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Width, rModel ) );
1978 nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width;
1979 if(nTitleSpaceWidth)
1980 nTitleSpaceWidth+=lcl_getDiagramTitleSpace();
1982 if( xSecondTitle_Height.is() )
1984 OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Height, rModel ) );
1985 nSecondTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height;
1986 if( nSecondTitleSpaceHeight )
1987 nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace();
1989 if( xSecondTitle_Width.is() )
1991 OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Width, rModel ) );
1992 nSecondTitleSpaceWidth += pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width;
1993 if( nSecondTitleSpaceWidth )
1994 nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace();
1996 if( bSubtract )
1998 aRet.X += nTitleSpaceWidth;
1999 aRet.Y += nSecondTitleSpaceHeight;
2000 aRet.Width -= (nTitleSpaceWidth + nSecondTitleSpaceWidth);
2001 aRet.Height -= (nTitleSpaceHeight + nSecondTitleSpaceHeight);
2003 else
2006 aRet.X -= nTitleSpaceWidth;
2007 aRet.Y -= nSecondTitleSpaceHeight;
2008 aRet.Width += nTitleSpaceWidth + nSecondTitleSpaceWidth;
2009 aRet.Height += nTitleSpaceHeight + nSecondTitleSpaceHeight;
2013 return aRet;
2016 namespace {
2018 double lcl_getPageLayoutDistancePercentage()
2020 return 0.02;
2023 bool getAvailablePosAndSizeForDiagram(
2024 CreateShapeParam2D& rParam, const awt::Size & rPageSize, const uno::Reference<XDiagram>& xDiagram )
2026 rParam.mbUseFixedInnerSize = false;
2028 //@todo: we need a size dependent on the axis labels
2029 sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage());
2030 sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage());
2031 rParam.maRemainingSpace.X += nXDistance;
2032 rParam.maRemainingSpace.Width -= 2*nXDistance;
2033 rParam.maRemainingSpace.Y += nYDistance;
2034 rParam.maRemainingSpace.Height -= 2*nYDistance;
2036 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
2037 return false;
2039 uno::Reference< beans::XPropertySet > xProp(xDiagram, uno::UNO_QUERY);
2041 bool bPosSizeExcludeAxes = false;
2042 if( xProp.is() )
2043 xProp->getPropertyValue( "PosSizeExcludeAxes" ) >>= bPosSizeExcludeAxes;
2045 //size:
2046 css::chart2::RelativeSize aRelativeSize;
2047 if( xProp.is() && (xProp->getPropertyValue( "RelativeSize" )>>=aRelativeSize) )
2049 rParam.maRemainingSpace.Height = static_cast<sal_Int32>(aRelativeSize.Secondary*rPageSize.Height);
2050 rParam.maRemainingSpace.Width = static_cast<sal_Int32>(aRelativeSize.Primary*rPageSize.Width);
2051 rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes;
2054 //position:
2055 chart2::RelativePosition aRelativePosition;
2056 if( xProp.is() && (xProp->getPropertyValue( "RelativePosition" )>>=aRelativePosition) )
2058 //@todo decide whether x is primary or secondary
2060 //the coordinates re relative to the page
2061 double fX = aRelativePosition.Primary*rPageSize.Width;
2062 double fY = aRelativePosition.Secondary*rPageSize.Height;
2064 awt::Point aPos = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
2065 awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)),
2066 awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height),
2067 aRelativePosition.Anchor);
2069 rParam.maRemainingSpace.X = aPos.X;
2070 rParam.maRemainingSpace.Y = aPos.Y;
2072 rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes;
2075 //ensure that the diagram does not lap out right side or out of bottom
2076 if (rParam.maRemainingSpace.Y + rParam.maRemainingSpace.Height > rPageSize.Height)
2077 rParam.maRemainingSpace.Height = rPageSize.Height - rParam.maRemainingSpace.Y;
2079 if (rParam.maRemainingSpace.X + rParam.maRemainingSpace.Width > rPageSize.Width)
2080 rParam.maRemainingSpace.Width = rPageSize.Width - rParam.maRemainingSpace.X;
2082 return true;
2085 enum TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z };
2087 void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment
2088 , awt::Rectangle const & rDiagramPlusAxesRect, const awt::Size & rPageSize )
2090 if(!pVTitle)
2091 return;
2093 awt::Point aNewPosition(0,0);
2094 awt::Size aTitleSize = pVTitle->getFinalSize();
2095 sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage());
2096 sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage());
2097 switch( eAlignment )
2099 case ALIGN_TOP:
2100 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2
2101 , rDiagramPlusAxesRect.Y - aTitleSize.Height/2 - nYDistance );
2102 break;
2103 case ALIGN_BOTTOM:
2104 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2
2105 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2 + nYDistance );
2106 break;
2107 case ALIGN_LEFT:
2108 aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance
2109 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 );
2110 break;
2111 case ALIGN_RIGHT:
2112 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance
2113 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 );
2114 break;
2115 case ALIGN_Z:
2116 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance
2117 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 );
2118 break;
2119 default:
2120 break;
2123 sal_Int32 nMaxY = rPageSize.Height - aTitleSize.Height/2;
2124 sal_Int32 nMaxX = rPageSize.Width - aTitleSize.Width/2;
2125 sal_Int32 nMinX = aTitleSize.Width/2;
2126 sal_Int32 nMinY = aTitleSize.Height/2;
2127 if( aNewPosition.Y > nMaxY )
2128 aNewPosition.Y = nMaxY;
2129 if( aNewPosition.X > nMaxX )
2130 aNewPosition.X = nMaxX;
2131 if( aNewPosition.Y < nMinY )
2132 aNewPosition.Y = nMinY;
2133 if( aNewPosition.X < nMinX )
2134 aNewPosition.X = nMinX;
2136 pVTitle->changePosition( aNewPosition );
2139 std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType
2140 , const uno::Reference< drawing::XShapes>& xPageShapes
2141 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2142 , ChartModel& rModel
2143 , awt::Rectangle& rRemainingSpace
2144 , const awt::Size & rPageSize
2145 , TitleAlignment eAlignment
2146 , bool& rbAutoPosition )
2148 std::shared_ptr<VTitle> apVTitle;
2150 // #i109336# Improve auto positioning in chart
2151 double fPercentage = lcl_getPageLayoutDistancePercentage();
2152 sal_Int32 nXDistance = static_cast< sal_Int32 >( rPageSize.Width * fPercentage );
2153 sal_Int32 nYDistance = static_cast< sal_Int32 >( rPageSize.Height * fPercentage );
2154 if ( eType == TitleHelper::MAIN_TITLE )
2156 nYDistance += 135; // 1/100 mm
2158 else if ( eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION )
2160 nYDistance = 420; // 1/100 mm
2162 else if ( eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION )
2164 nXDistance = 450; // 1/100 mm
2167 uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, rModel ) );
2168 OUString aCompleteString = TitleHelper::getCompleteString(xTitle);
2169 if (aCompleteString.isEmpty())
2170 return apVTitle;
2172 //create title
2173 apVTitle.reset(new VTitle(xTitle));
2174 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForObject(xTitle, rModel);
2175 apVTitle->init(xPageShapes, xShapeFactory, aCID);
2176 apVTitle->createShapes(awt::Point(0,0), rPageSize);
2177 awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize();
2178 awt::Size aTitleSize = apVTitle->getFinalSize();
2180 //position
2181 rbAutoPosition = true;
2182 awt::Point aNewPosition(0,0);
2183 chart2::RelativePosition aRelativePosition;
2184 uno::Reference<beans::XPropertySet> xProp(xTitle, uno::UNO_QUERY);
2185 if (xProp.is() && (xProp->getPropertyValue("RelativePosition") >>= aRelativePosition))
2187 rbAutoPosition = false;
2189 //@todo decide whether x is primary or secondary
2190 double fX = aRelativePosition.Primary*rPageSize.Width;
2191 double fY = aRelativePosition.Secondary*rPageSize.Height;
2193 double fAnglePi = apVTitle->getRotationAnglePi();
2194 aNewPosition = RelativePositionHelper::getCenterOfAnchoredObject(
2195 awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY))
2196 , aTitleUnrotatedSize, aRelativePosition.Anchor, fAnglePi );
2198 else //auto position
2200 switch( eAlignment )
2202 case ALIGN_TOP:
2203 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2
2204 , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance );
2205 break;
2206 case ALIGN_BOTTOM:
2207 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2
2208 , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance );
2209 break;
2210 case ALIGN_LEFT:
2211 aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance
2212 , rRemainingSpace.Y + rRemainingSpace.Height/2 );
2213 break;
2214 case ALIGN_RIGHT:
2215 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance
2216 , rRemainingSpace.Y + rRemainingSpace.Height/2 );
2217 break;
2218 default:
2219 break;
2223 apVTitle->changePosition( aNewPosition );
2225 //remaining space
2226 switch( eAlignment )
2228 case ALIGN_TOP:
2229 // Push the remaining space down from top.
2230 rRemainingSpace.Y += ( aTitleSize.Height + nYDistance );
2231 rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance );
2232 break;
2233 case ALIGN_BOTTOM:
2234 // Push the remaining space up from bottom.
2235 rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance );
2236 break;
2237 case ALIGN_LEFT:
2238 // Push the remaining space to the right from left edge.
2239 rRemainingSpace.X += ( aTitleSize.Width + nXDistance );
2240 rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance );
2241 break;
2242 case ALIGN_RIGHT:
2243 // Push the remaining space to the left from right edge.
2244 rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance );
2245 break;
2246 default:
2247 break;
2250 return apVTitle;
2253 bool lcl_createLegend( const uno::Reference< XLegend > & xLegend
2254 , const uno::Reference< drawing::XShapes>& xPageShapes
2255 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2256 , const uno::Reference< uno::XComponentContext > & xContext
2257 , awt::Rectangle & rRemainingSpace
2258 , const awt::Size & rPageSize
2259 , ChartModel& rModel
2260 , const std::vector< LegendEntryProvider* >& rLegendEntryProviderList
2261 , sal_Int16 nDefaultWritingMode )
2263 if (!VLegend::isVisible(xLegend))
2264 return false;
2266 VLegend aVLegend( xLegend, xContext, rLegendEntryProviderList,
2267 xPageShapes, xShapeFactory, rModel);
2268 aVLegend.setDefaultWritingMode( nDefaultWritingMode );
2269 aVLegend.createShapes( awt::Size( rRemainingSpace.Width, rRemainingSpace.Height ),
2270 rPageSize );
2271 aVLegend.changePosition( rRemainingSpace, rPageSize );
2272 return true;
2275 void lcl_createButtons(const uno::Reference<drawing::XShapes>& xPageShapes,
2276 const uno::Reference<lang::XMultiServiceFactory>& xShapeFactory,
2277 ChartModel& rModel,
2278 awt::Rectangle& rRemainingSpace)
2280 uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY);
2281 if (!xPivotTableDataProvider.is())
2282 return;
2284 uno::Reference<beans::XPropertySet> xModelPage(rModel.getPageBackground());
2286 awt::Size aSize(4000, 700); // size of the button
2288 long x = 0;
2290 if (xPivotTableDataProvider->getPageFields().hasElements())
2292 x = 0;
2294 const css::uno::Sequence<chart2::data::PivotTableFieldEntry> aPivotFieldEntries = xPivotTableDataProvider->getPageFields();
2295 for (css::chart2::data::PivotTableFieldEntry const & rPageFieldEntry : aPivotFieldEntries)
2297 std::unique_ptr<VButton> pButton(new VButton);
2298 pButton->init(xPageShapes, xShapeFactory);
2299 awt::Point aNewPosition(rRemainingSpace.X + x + 100, rRemainingSpace.Y + 100);
2300 sal_Int32 nDimensionIndex = rPageFieldEntry.DimensionIndex;
2301 OUString aFieldOutputDescription = xPivotTableDataProvider->getFieldOutputDescription(nDimensionIndex);
2302 pButton->setLabel(rPageFieldEntry.Name + " | " + aFieldOutputDescription);
2303 pButton->setCID("FieldButton.Page." + OUString::number(nDimensionIndex));
2304 pButton->setPosition(aNewPosition);
2305 pButton->setSize(aSize);
2306 if (rPageFieldEntry.HasHiddenMembers)
2307 pButton->setArrowColor(Color(0x0000FF));
2309 pButton->createShapes(xModelPage);
2310 x += aSize.Width + 100;
2312 rRemainingSpace.Y += (aSize.Height + 100 + 100);
2313 rRemainingSpace.Height -= (aSize.Height + 100 + 100);
2316 aSize = awt::Size(3000, 700); // size of the button
2318 if (xPivotTableDataProvider->getRowFields().hasElements())
2320 x = 200;
2321 const css::uno::Sequence<chart2::data::PivotTableFieldEntry> aPivotFieldEntries = xPivotTableDataProvider->getRowFields();
2322 for (css::chart2::data::PivotTableFieldEntry const & rRowFieldEntry : aPivotFieldEntries)
2325 std::unique_ptr<VButton> pButton(new VButton);
2326 pButton->init(xPageShapes, xShapeFactory);
2327 awt::Point aNewPosition(rRemainingSpace.X + x + 100,
2328 rRemainingSpace.Y + rRemainingSpace.Height - aSize.Height - 100);
2329 pButton->setLabel(rRowFieldEntry.Name);
2330 pButton->setCID("FieldButton.Row." + OUString::number(rRowFieldEntry.DimensionIndex));
2331 pButton->setPosition(aNewPosition);
2332 pButton->setSize(aSize);
2333 if ( rRowFieldEntry.Name == "Data" )
2335 pButton->setBGColor( Color(0x00F6F6F6) );
2336 pButton->showArrow( false );
2338 else if (rRowFieldEntry.HasHiddenMembers)
2339 pButton->setArrowColor(Color(0x0000FF));
2340 pButton->createShapes(xModelPage);
2341 x += aSize.Width + 100;
2343 rRemainingSpace.Height -= (aSize.Height + 100 + 100);
2347 void formatPage(
2348 ChartModel& rChartModel
2349 , const awt::Size& rPageSize
2350 , const uno::Reference< drawing::XShapes >& xTarget
2351 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2356 uno::Reference< beans::XPropertySet > xModelPage( rChartModel.getPageBackground());
2357 if( ! xModelPage.is())
2358 return;
2360 if( !xShapeFactory.is() )
2361 return;
2363 //format page
2364 tPropertyNameValueMap aNameValueMap;
2365 PropertyMapper::getValueMap( aNameValueMap, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xModelPage );
2367 OUString aCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) );
2368 aNameValueMap.emplace( "Name", uno::Any( aCID ) ); //CID OUString
2370 tNameSequence aNames;
2371 tAnySequence aValues;
2372 PropertyMapper::getMultiPropertyListsFromValueMap( aNames, aValues, aNameValueMap );
2374 ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(xShapeFactory);
2375 pShapeFactory->createRectangle(
2376 xTarget, rPageSize, awt::Point(0, 0), aNames, aValues);
2378 catch( const uno::Exception & )
2380 DBG_UNHANDLED_EXCEPTION("chart2" );
2384 void lcl_removeEmptyGroupShapes( const Reference< drawing::XShapes>& xParent )
2386 if(!xParent.is())
2387 return;
2388 Reference< drawing::XShapeGroup > xParentGroup( xParent, uno::UNO_QUERY );
2389 if( !xParentGroup.is() )
2391 Reference< drawing::XDrawPage > xPage( xParent, uno::UNO_QUERY );
2392 if( !xPage.is() )
2393 return;
2396 //iterate from back!
2397 for( sal_Int32 nN = xParent->getCount(); nN--; )
2399 uno::Any aAny = xParent->getByIndex( nN );
2400 Reference< drawing::XShapes> xShapes;
2401 if( aAny >>= xShapes )
2402 lcl_removeEmptyGroupShapes( xShapes );
2403 if( xShapes.is() && xShapes->getCount()==0 )
2405 //remove empty group shape
2406 Reference< drawing::XShapeGroup > xGroup( xShapes, uno::UNO_QUERY );
2407 Reference< drawing::XShape > xShape( xShapes, uno::UNO_QUERY );
2408 if( xGroup.is() )
2409 xParent->remove( xShape );
2416 void ChartView::impl_refreshAddIn()
2418 if( !m_bRefreshAddIn )
2419 return;
2421 uno::Reference< beans::XPropertySet > xProp( static_cast< ::cppu::OWeakObject* >( &mrChartModel ), uno::UNO_QUERY );
2422 if( xProp.is()) try
2424 uno::Reference< util::XRefreshable > xAddIn;
2425 xProp->getPropertyValue( "AddIn" ) >>= xAddIn;
2426 if( xAddIn.is() )
2428 bool bRefreshAddInAllowed = true;
2429 xProp->getPropertyValue( "RefreshAddInAllowed" ) >>= bRefreshAddInAllowed;
2430 if( bRefreshAddInAllowed )
2431 xAddIn->refresh();
2434 catch( const uno::Exception& )
2436 TOOLS_WARN_EXCEPTION("chart2", "" );
2440 static const char* envChartDummyFactory = getenv("CHART_DUMMY_FACTORY");
2442 void ChartView::createShapes()
2444 SolarMutexGuard aSolarGuard;
2446 osl::MutexGuard aTimedGuard(maTimeMutex);
2447 if(mrChartModel.isTimeBased())
2449 maTimeBased.bTimeBased = true;
2452 //make sure add-in is refreshed after creating the shapes
2453 const ::comphelper::ScopeGuard aGuard( [this]() { this->impl_refreshAddIn(); } );
2455 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle(0,0,0,0);
2456 impl_deleteCoordinateSystems();
2457 if( m_pDrawModelWrapper )
2459 // #i12587# support for shapes in chart
2460 m_pDrawModelWrapper->getSdrModel().EnableUndo( false );
2461 m_pDrawModelWrapper->clearMainDrawPage();
2464 lcl_setDefaultWritingMode( m_pDrawModelWrapper, mrChartModel );
2466 awt::Size aPageSize = mrChartModel.getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
2468 ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory);
2469 if(!mxRootShape.is())
2470 mxRootShape = pShapeFactory->getOrCreateChartRootShape( m_xDrawPage );
2472 SdrPage* pPage = ChartView::getSdrPage();
2473 if(pPage) //it is necessary to use the implementation here as the uno page does not provide a propertyset
2474 pPage->SetSize(Size(aPageSize.Width,aPageSize.Height));
2475 else
2477 OSL_FAIL("could not set page size correctly");
2479 ShapeFactory::setPageSize(mxRootShape, aPageSize);
2481 createShapes2D(aPageSize);
2483 // #i12587# support for shapes in chart
2484 if ( m_pDrawModelWrapper )
2486 m_pDrawModelWrapper->getSdrModel().EnableUndo( true );
2489 if(maTimeBased.bTimeBased)
2491 maTimeBased.nFrame++;
2495 // util::XEventListener (base of XCloseListener)
2496 void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ )
2500 void ChartView::impl_updateView( bool bCheckLockedCtrler )
2502 if( !m_pDrawModelWrapper )
2503 return;
2505 // #i12587# support for shapes in chart
2506 if ( m_bSdrViewIsInEditMode )
2508 return;
2511 if (bCheckLockedCtrler && mrChartModel.hasControllersLocked())
2512 return;
2514 if( m_bViewDirty && !m_bInViewUpdate )
2516 m_bInViewUpdate = true;
2517 //bool bOldRefreshAddIn = m_bRefreshAddIn;
2518 //m_bRefreshAddIn = false;
2521 impl_notifyModeChangeListener("invalid");
2523 //prepare draw model
2525 SolarMutexGuard aSolarGuard;
2526 m_pDrawModelWrapper->lockControllers();
2529 //create chart view
2531 m_bViewDirty = false;
2532 m_bViewUpdatePending = false;
2533 createShapes();
2535 if( m_bViewDirty )
2537 //avoid recursions due to add-in
2538 m_bRefreshAddIn = false;
2539 m_bViewDirty = false;
2540 m_bViewUpdatePending = false;
2541 //delete old chart view
2542 createShapes();
2543 m_bRefreshAddIn = true;
2547 m_bViewDirty = m_bViewUpdatePending;
2548 m_bViewUpdatePending = false;
2549 m_bInViewUpdate = false;
2551 catch( const uno::Exception& )
2553 DBG_UNHANDLED_EXCEPTION("chart2" );
2554 m_bViewDirty = m_bViewUpdatePending;
2555 m_bViewUpdatePending = false;
2556 m_bInViewUpdate = false;
2560 SolarMutexGuard aSolarGuard;
2561 m_pDrawModelWrapper->unlockControllers();
2564 impl_notifyModeChangeListener("valid");
2566 //m_bRefreshAddIn = bOldRefreshAddIn;
2570 // ____ XModifyListener ____
2571 void SAL_CALL ChartView::modified( const lang::EventObject& /* aEvent */ )
2573 m_bViewDirty = true;
2574 if( m_bInViewUpdate )
2575 m_bViewUpdatePending = true;
2577 impl_notifyModeChangeListener("dirty");
2580 //SfxListener
2581 void ChartView::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
2583 //#i77362 change notification for changes on additional shapes are missing
2584 if( m_bInViewUpdate )
2585 return;
2587 // #i12587# support for shapes in chart
2588 if ( m_bSdrViewIsInEditMode )
2590 uno::Reference< view::XSelectionSupplier > xSelectionSupplier( mrChartModel.getCurrentController(), uno::UNO_QUERY );
2591 if ( xSelectionSupplier.is() )
2593 OUString aSelObjCID;
2594 uno::Any aSelObj( xSelectionSupplier->getSelection() );
2595 aSelObj >>= aSelObjCID;
2596 if ( !aSelObjCID.isEmpty() )
2598 return;
2603 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
2604 return;
2605 const SdrHint* pSdrHint = static_cast< const SdrHint* >(&rHint);
2607 bool bShapeChanged = false;
2608 switch( pSdrHint->GetKind() )
2610 case SdrHintKind::ObjectChange:
2611 bShapeChanged = true;
2612 break;
2613 case SdrHintKind::ObjectInserted:
2614 bShapeChanged = true;
2615 break;
2616 case SdrHintKind::ObjectRemoved:
2617 bShapeChanged = true;
2618 break;
2619 case SdrHintKind::ModelCleared:
2620 bShapeChanged = true;
2621 break;
2622 case SdrHintKind::EndEdit:
2623 bShapeChanged = true;
2624 break;
2625 default:
2626 break;
2629 if(bShapeChanged)
2631 //#i76053# do not send view modified notifications for changes on the hidden page which contains e.g. the symbols for the dialogs
2632 if( ChartView::getSdrPage() != pSdrHint->GetPage() )
2633 bShapeChanged=false;
2636 if(!bShapeChanged)
2637 return;
2639 mrChartModel.setModified(true);
2642 void ChartView::impl_notifyModeChangeListener( const OUString& rNewMode )
2646 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer
2647 .getContainer( cppu::UnoType<util::XModeChangeListener>::get());
2648 if( pIC )
2650 util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode );
2651 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
2652 while( aIt.hasMoreElements() )
2654 uno::Reference< util::XModeChangeListener > xListener( aIt.next(), uno::UNO_QUERY );
2655 if( xListener.is() )
2656 xListener->modeChanged( aEvent );
2660 catch( const uno::Exception& )
2662 DBG_UNHANDLED_EXCEPTION("chart2");
2666 // ____ XModeChangeBroadcaster ____
2668 void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener )
2670 m_aListenerContainer.addInterface(
2671 cppu::UnoType<util::XModeChangeListener>::get(), xListener );
2673 void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener )
2675 m_aListenerContainer.removeInterface(
2676 cppu::UnoType<util::XModeChangeListener>::get(), xListener );
2678 void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ )
2682 void SAL_CALL ChartView::removeModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ )
2687 // ____ XUpdatable ____
2688 void SAL_CALL ChartView::update()
2690 impl_updateView();
2692 //#i100778# migrate all imported or old documents to a plot area sizing exclusive axes (in case the save settings allow for this):
2693 //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.
2694 //When a view update is requested (what happens for creating the metafile or displaying
2695 //the chart in edit mode or printing) it is most likely that all necessary information is available - like the underlying spreadsheet data for example.
2696 //Those data are important for the correct axis label sizes which are needed during conversion.
2697 if( DiagramHelper::switchDiagramPositioningToExcludingPositioning( mrChartModel, true, false ) )
2698 impl_updateView();
2701 void SAL_CALL ChartView::updateSoft()
2703 update();
2706 void SAL_CALL ChartView::updateHard()
2708 impl_updateView(false);
2711 // ____ XPropertySet ____
2712 Reference< beans::XPropertySetInfo > SAL_CALL ChartView::getPropertySetInfo()
2714 OSL_FAIL("not implemented");
2715 return nullptr;
2718 void SAL_CALL ChartView::setPropertyValue( const OUString& rPropertyName
2719 , const Any& rValue )
2721 if( rPropertyName == "Resolution" )
2723 awt::Size aNewResolution;
2724 if( ! (rValue >>= aNewResolution) )
2725 throw lang::IllegalArgumentException( "Property 'Resolution' requires value of type awt::Size", nullptr, 0 );
2727 if( m_aPageResolution.Width!=aNewResolution.Width || m_aPageResolution.Height!=aNewResolution.Height )
2729 //set modified only when the new resolution is higher and points were skipped before
2730 bool bSetModified = m_bPointsWereSkipped && (m_aPageResolution.Width<aNewResolution.Width || m_aPageResolution.Height<aNewResolution.Height);
2732 m_aPageResolution = aNewResolution;
2734 if( bSetModified )
2735 this->modified( lang::EventObject( static_cast< uno::XWeak* >( this ) ) );
2738 else if( rPropertyName == "ZoomFactors" )
2740 //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
2741 uno::Sequence< beans::PropertyValue > aZoomFactors;
2742 if( ! (rValue >>= aZoomFactors) )
2743 throw lang::IllegalArgumentException( "Property 'ZoomFactors' requires value of type Sequence< PropertyValue >", nullptr, 0 );
2745 sal_Int32 nFilterArgs = aZoomFactors.getLength();
2746 beans::PropertyValue* pDataValues = aZoomFactors.getArray();
2747 while( nFilterArgs-- )
2749 if ( pDataValues->Name == "ScaleXNumerator" )
2750 pDataValues->Value >>= m_nScaleXNumerator;
2751 else if ( pDataValues->Name == "ScaleXDenominator" )
2752 pDataValues->Value >>= m_nScaleXDenominator;
2753 else if ( pDataValues->Name == "ScaleYNumerator" )
2754 pDataValues->Value >>= m_nScaleYNumerator;
2755 else if ( pDataValues->Name == "ScaleYDenominator" )
2756 pDataValues->Value >>= m_nScaleYDenominator;
2758 pDataValues++;
2761 else if( rPropertyName == "SdrViewIsInEditMode" )
2763 //#i77362 change notification for changes on additional shapes are missing
2764 if( ! (rValue >>= m_bSdrViewIsInEditMode) )
2765 throw lang::IllegalArgumentException( "Property 'SdrViewIsInEditMode' requires value of type sal_Bool", nullptr, 0 );
2767 else
2768 throw beans::UnknownPropertyException( "unknown property was tried to set to chart wizard " + rPropertyName, nullptr );
2771 Any SAL_CALL ChartView::getPropertyValue( const OUString& rPropertyName )
2773 if( rPropertyName != "Resolution" )
2774 throw beans::UnknownPropertyException( "unknown property was tried to get from chart wizard " + rPropertyName, nullptr );
2776 return Any(m_aPageResolution);
2779 void SAL_CALL ChartView::addPropertyChangeListener(
2780 const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* xListener */ )
2782 OSL_FAIL("not implemented");
2784 void SAL_CALL ChartView::removePropertyChangeListener(
2785 const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* aListener */ )
2787 OSL_FAIL("not implemented");
2790 void SAL_CALL ChartView::addVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ )
2792 OSL_FAIL("not implemented");
2795 void SAL_CALL ChartView::removeVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ )
2797 OSL_FAIL("not implemented");
2800 // ____ XMultiServiceFactory ____
2802 Reference< uno::XInterface > ChartView::createInstance( const OUString& aServiceSpecifier )
2804 SolarMutexGuard aSolarGuard;
2806 SdrModel* pModel = ( m_pDrawModelWrapper ? &m_pDrawModelWrapper->getSdrModel() : nullptr );
2807 if ( pModel )
2809 if ( aServiceSpecifier == "com.sun.star.drawing.DashTable" )
2811 if ( !m_xDashTable.is() )
2813 m_xDashTable = SvxUnoDashTable_createInstance( pModel );
2815 return m_xDashTable;
2817 else if ( aServiceSpecifier == "com.sun.star.drawing.GradientTable" )
2819 if ( !m_xGradientTable.is() )
2821 m_xGradientTable = SvxUnoGradientTable_createInstance( pModel );
2823 return m_xGradientTable;
2825 else if ( aServiceSpecifier == "com.sun.star.drawing.HatchTable" )
2827 if ( !m_xHatchTable.is() )
2829 m_xHatchTable = SvxUnoHatchTable_createInstance( pModel );
2831 return m_xHatchTable;
2833 else if ( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" )
2835 if ( !m_xBitmapTable.is() )
2837 m_xBitmapTable = SvxUnoBitmapTable_createInstance( pModel );
2839 return m_xBitmapTable;
2841 else if ( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" )
2843 if ( !m_xTransGradientTable.is() )
2845 m_xTransGradientTable = SvxUnoTransGradientTable_createInstance( pModel );
2847 return m_xTransGradientTable;
2849 else if ( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" )
2851 if ( !m_xMarkerTable.is() )
2853 m_xMarkerTable = SvxUnoMarkerTable_createInstance( pModel );
2855 return m_xMarkerTable;
2859 return nullptr;
2862 Reference< uno::XInterface > ChartView::createInstanceWithArguments( const OUString& ServiceSpecifier, const uno::Sequence< uno::Any >& Arguments )
2864 OSL_ENSURE( Arguments.hasElements(), "ChartView::createInstanceWithArguments: arguments are ignored" );
2865 return createInstance( ServiceSpecifier );
2868 uno::Sequence< OUString > ChartView::getAvailableServiceNames()
2870 uno::Sequence< OUString > aServiceNames( 6 );
2872 aServiceNames[0] = "com.sun.star.drawing.DashTable";
2873 aServiceNames[1] = "com.sun.star.drawing.GradientTable";
2874 aServiceNames[2] = "com.sun.star.drawing.HatchTable";
2875 aServiceNames[3] = "com.sun.star.drawing.BitmapTable";
2876 aServiceNames[4] = "com.sun.star.drawing.TransparencyGradientTable";
2877 aServiceNames[5] = "com.sun.star.drawing.MarkerTable";
2879 return aServiceNames;
2882 OUString ChartView::dump()
2884 #if HAVE_FEATURE_DESKTOP
2885 // Used for unit tests and in chartcontroller only, no need to drag in this when cross-compiling
2886 // for non-desktop
2887 impl_updateView();
2888 uno::Reference< drawing::XShapes > xShapes( m_xDrawPage, uno::UNO_QUERY_THROW );
2889 sal_Int32 n = xShapes->getCount();
2890 OUStringBuffer aBuffer;
2891 for(sal_Int32 i = 0; i < n; ++i)
2893 uno::Reference< drawing::XShapes > xShape(xShapes->getByIndex(i), uno::UNO_QUERY);
2894 if(xShape.is())
2896 OUString aString = XShapeDumper::dump(mxRootShape);
2897 aBuffer.append(aString);
2899 else
2901 uno::Reference< drawing::XShape > xSingleShape(xShapes->getByIndex(i), uno::UNO_QUERY);
2902 if(!xSingleShape.is())
2903 continue;
2904 OUString aString = XShapeDumper::dump(xSingleShape);
2905 aBuffer.append(aString);
2907 aBuffer.append("\n\n");
2910 return aBuffer.makeStringAndClear();
2911 #else
2912 return OUString();
2913 #endif
2916 void ChartView::setViewDirty()
2918 osl::MutexGuard aGuard(maTimeMutex);
2919 m_bViewDirty = true;
2922 IMPL_LINK_NOARG(ChartView, UpdateTimeBased, Timer *, void)
2924 setViewDirty();
2925 update();
2928 void ChartView::createShapes2D( const awt::Size& rPageSize )
2930 ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(m_xShapeFactory);
2932 // todo: it would be nicer to just pass the page m_xDrawPage and format it,
2933 // but the draw page does not support XPropertySet
2934 formatPage( mrChartModel, rPageSize, mxRootShape, m_xShapeFactory );
2936 CreateShapeParam2D aParam;
2937 aParam.maRemainingSpace.X = 0;
2938 aParam.maRemainingSpace.Y = 0;
2939 aParam.maRemainingSpace.Width = rPageSize.Width;
2940 aParam.maRemainingSpace.Height = rPageSize.Height;
2942 //create the group shape for diagram and axes first to have title and legends on top of it
2943 uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() );
2944 OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ) );//todo: other index if more than one diagram is possible
2945 uno::Reference< drawing::XShapes > xDiagramPlusAxesPlusMarkHandlesGroup_Shapes(
2946 pShapeFactory->createGroup2D(mxRootShape,aDiagramCID) );
2948 aParam.mxMarkHandles = pShapeFactory->createInvisibleRectangle(
2949 xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0));
2950 ShapeFactory::setShapeName(aParam.mxMarkHandles, "MarkHandles");
2952 aParam.mxPlotAreaWithAxes = pShapeFactory->createInvisibleRectangle(
2953 xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0, 0));
2954 ShapeFactory::setShapeName(aParam.mxPlotAreaWithAxes, "PlotAreaIncludingAxes");
2956 aParam.mxDiagramWithAxesShapes = pShapeFactory->createGroup2D(xDiagramPlusAxesPlusMarkHandlesGroup_Shapes);
2958 bool bAutoPositionDummy = true;
2960 // create buttons
2961 lcl_createButtons(mxRootShape, m_xShapeFactory, mrChartModel, aParam.maRemainingSpace);
2963 lcl_createTitle(
2964 TitleHelper::MAIN_TITLE, mxRootShape, m_xShapeFactory, mrChartModel,
2965 aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy);
2966 if (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)
2967 return;
2969 lcl_createTitle(
2970 TitleHelper::SUB_TITLE, mxRootShape, m_xShapeFactory, mrChartModel,
2971 aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy );
2972 if (aParam.maRemainingSpace.Width <= 0|| aParam.maRemainingSpace.Height <= 0)
2973 return;
2975 aParam.mpSeriesPlotterContainer.reset(new SeriesPlotterContainer(m_aVCooSysList));
2976 aParam.mpSeriesPlotterContainer->initializeCooSysAndSeriesPlotter( mrChartModel );
2977 if(maTimeBased.bTimeBased && maTimeBased.nFrame != 0)
2979 SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList();
2980 size_t n = rSeriesPlotter.size();
2981 for(size_t i = 0; i < n; ++i)
2983 std::vector<VDataSeries*> aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries();
2984 std::vector< VDataSeries* >& rAllOldDataSeries =
2985 maTimeBased.m_aDataSeriesList[i];
2986 size_t m = std::min(aAllNewDataSeries.size(), rAllOldDataSeries.size());
2987 for(size_t j = 0; j < m; ++j)
2989 aAllNewDataSeries[j]->setOldTimeBased(
2990 rAllOldDataSeries[j], (maTimeBased.nFrame % 60)/60.0);
2995 lcl_createLegend(
2996 LegendHelper::getLegend( mrChartModel ), mxRootShape, m_xShapeFactory, m_xCC,
2997 aParam.maRemainingSpace, rPageSize, mrChartModel, aParam.mpSeriesPlotterContainer->getLegendEntryProviderList(),
2998 lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) );
2999 if (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)
3000 return;
3002 if (!createAxisTitleShapes2D(aParam, rPageSize))
3003 return;
3005 bool bDummy = false;
3006 bool bIsVertical = DiagramHelper::getVertical(xDiagram, bDummy, bDummy);
3008 if (getAvailablePosAndSizeForDiagram(aParam, rPageSize, mrChartModel.getFirstDiagram()))
3010 awt::Rectangle aUsedOuterRect = impl_createDiagramAndContent(aParam, rPageSize);
3012 if (aParam.mxPlotAreaWithAxes.is())
3014 aParam.mxPlotAreaWithAxes->setPosition(awt::Point(aUsedOuterRect.X, aUsedOuterRect.Y));
3015 aParam.mxPlotAreaWithAxes->setSize(awt::Size(aUsedOuterRect.Width, aUsedOuterRect.Height));
3018 //correct axis title position
3019 awt::Rectangle aDiagramPlusAxesRect( aUsedOuterRect );
3020 if (aParam.mbAutoPosTitleX)
3021 changePositionOfAxisTitle(aParam.mpVTitleX.get(), ALIGN_BOTTOM, aDiagramPlusAxesRect, rPageSize);
3022 if (aParam.mbAutoPosTitleY)
3023 changePositionOfAxisTitle(aParam.mpVTitleY.get(), ALIGN_LEFT, aDiagramPlusAxesRect, rPageSize);
3024 if (aParam.mbAutoPosTitleZ)
3025 changePositionOfAxisTitle(aParam.mpVTitleZ.get(), ALIGN_Z, aDiagramPlusAxesRect, rPageSize);
3026 if (aParam.mbAutoPosSecondTitleX)
3027 changePositionOfAxisTitle(aParam.mpVTitleSecondX.get(), bIsVertical? ALIGN_RIGHT : ALIGN_TOP, aDiagramPlusAxesRect, rPageSize);
3028 if (aParam.mbAutoPosSecondTitleY)
3029 changePositionOfAxisTitle(aParam.mpVTitleSecondY.get(), bIsVertical? ALIGN_TOP : ALIGN_RIGHT, aDiagramPlusAxesRect, rPageSize);
3032 //cleanup: remove all empty group shapes to avoid grey border lines:
3033 lcl_removeEmptyGroupShapes( mxRootShape );
3035 if(maTimeBased.bTimeBased && maTimeBased.nFrame % 60 == 0)
3037 // create copy of the data for next frame
3038 SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList();
3039 size_t n = rSeriesPlotter.size();
3040 maTimeBased.m_aDataSeriesList.clear();
3041 maTimeBased.m_aDataSeriesList.resize(n);
3042 for(size_t i = 0; i < n; ++i)
3044 std::vector<VDataSeries*> aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries();
3045 std::vector<VDataSeries*>& rAllOldDataSeries = maTimeBased.m_aDataSeriesList[i];
3046 size_t m = aAllNewDataSeries.size();
3047 for(size_t j = 0; j < m; ++j)
3049 rAllOldDataSeries.push_back( aAllNewDataSeries[j]->
3050 createCopyForTimeBased() );
3054 maTimeBased.maTimer.Stop();
3057 if(maTimeBased.bTimeBased && !maTimeBased.maTimer.IsActive())
3059 maTimeBased.maTimer.SetTimeout(15);
3060 maTimeBased.maTimer.SetInvokeHandler(LINK(this, ChartView, UpdateTimeBased));
3061 maTimeBased.maTimer.Start();
3065 bool ChartView::createAxisTitleShapes2D( CreateShapeParam2D& rParam, const css::awt::Size& rPageSize )
3067 uno::Reference<XDiagram> xDiagram = mrChartModel.getFirstDiagram();
3069 Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
3070 sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram );
3072 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) )
3073 rParam.mpVTitleX = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, mxRootShape, m_xShapeFactory, mrChartModel
3074 , rParam.maRemainingSpace, rPageSize, ALIGN_BOTTOM, rParam.mbAutoPosTitleX );
3075 if (rParam.maRemainingSpace.Width <= 0 ||rParam.maRemainingSpace.Height <= 0)
3076 return false;
3078 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) )
3079 rParam.mpVTitleY = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, mxRootShape, m_xShapeFactory, mrChartModel
3080 , rParam.maRemainingSpace, rPageSize, ALIGN_LEFT, rParam.mbAutoPosTitleY );
3081 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3082 return false;
3084 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) )
3085 rParam.mpVTitleZ = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3086 , rParam.maRemainingSpace, rPageSize, ALIGN_RIGHT, rParam.mbAutoPosTitleZ );
3087 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3088 return false;
3090 bool bDummy = false;
3091 bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy );
3093 if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) )
3094 rParam.mpVTitleSecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3095 , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_RIGHT : ALIGN_TOP, rParam.mbAutoPosSecondTitleX );
3096 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3097 return false;
3099 if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) )
3100 rParam.mpVTitleSecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3101 , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_TOP : ALIGN_RIGHT, rParam.mbAutoPosSecondTitleY );
3102 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3103 return false;
3105 return true;
3108 } //namespace chart
3110 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3111 com_sun_star_comp_chart2_ChartView_get_implementation(css::uno::XComponentContext *context,
3112 css::uno::Sequence<css::uno::Any> const &)
3114 ::chart::ChartModel *pChartModel = new ::chart::ChartModel(context);
3115 return cppu::acquire(new ::chart::ChartView(context, *pChartModel));
3118 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */