Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / chart2 / source / view / main / ChartView.cxx
blob22f268b19a4a18d9e31d4cf11aa4ee528f88362f
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_features.h>
22 #include <ChartView.hxx>
23 #include <chartview/DrawModelWrapper.hxx>
24 #include <NumberFormatterWrapper.hxx>
25 #include <ViewDefines.hxx>
26 #include <VDiagram.hxx>
27 #include "VTitle.hxx"
28 #include "VButton.hxx"
29 #include <AbstractShapeFactory.hxx>
30 #include <VCoordinateSystem.hxx>
31 #include <VSeriesPlotter.hxx>
32 #include <CommonConverters.hxx>
33 #include <TitleHelper.hxx>
34 #include <LegendHelper.hxx>
35 #include "VLegend.hxx"
36 #include <PropertyMapper.hxx>
37 #include <ChartModelHelper.hxx>
38 #include <ChartTypeHelper.hxx>
39 #include <ScaleAutomatism.hxx>
40 #include <MinimumAndMaximumSupplier.hxx>
41 #include <ObjectIdentifier.hxx>
42 #include <DiagramHelper.hxx>
43 #include <RelativePositionHelper.hxx>
44 #include <servicenames.hxx>
45 #include <AxisHelper.hxx>
46 #include <AxisIndexDefines.hxx>
47 #include <ControllerLockGuard.hxx>
48 #include <BaseGFXHelper.hxx>
49 #include <DataSeriesHelper.hxx>
50 #include <DateHelper.hxx>
51 #include <defines.hxx>
52 #include <unonames.hxx>
53 #if HAVE_FEATURE_OPENGL
54 #include <GL3DBarChart.hxx>
55 #endif
56 #include <editeng/frmdiritem.hxx>
57 #include <rtl/uuid.h>
58 #include <tools/globname.hxx>
59 #include <comphelper/fileformat.h>
60 #include <comphelper/scopeguard.hxx>
61 #include <comphelper/servicehelper.hxx>
62 #include <cppuhelper/supportsservice.hxx>
63 #include <unotools/streamwrap.hxx>
64 #include <unotools/localedatawrapper.hxx>
65 #include <svx/charthelper.hxx>
66 #include <svx/svdpage.hxx>
67 #include <svx/unopage.hxx>
68 #include <svx/unoshape.hxx>
69 #include <vcl/svapp.hxx>
70 #include <osl/mutex.hxx>
71 #include <svx/unofill.hxx>
72 #include <vcl/openglwin.hxx>
73 #if HAVE_FEATURE_OPENGL
74 #include <vcl/opengl/OpenGLContext.hxx>
75 #endif
76 #include <drawinglayer/XShapeDumper.hxx>
78 #include <time.h>
80 #include <com/sun/star/awt/Size.hpp>
81 #include <com/sun/star/awt/Point.hpp>
82 #include <com/sun/star/chart/ChartAxisPosition.hpp>
83 #include <com/sun/star/chart/DataLabelPlacement.hpp>
84 #include <com/sun/star/chart/MissingValueTreatment.hpp>
85 #include <com/sun/star/chart2/StackingDirection.hpp>
86 #include <com/sun/star/chart2/XChartDocument.hpp>
87 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
88 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
89 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
90 #include <com/sun/star/chart2/XTitled.hpp>
91 #include <com/sun/star/chart2/RelativePosition.hpp>
92 #include <com/sun/star/chart2/RelativeSize.hpp>
93 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
94 #include <com/sun/star/chart2/data/PivotTableFieldEntry.hpp>
95 #include <com/sun/star/drawing/FillStyle.hpp>
96 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
97 #include <com/sun/star/drawing/LineStyle.hpp>
98 #include <com/sun/star/drawing/XShapeGroup.hpp>
99 #include <com/sun/star/drawing/XShapeDescriptor.hpp>
100 #include <com/sun/star/document/XExporter.hpp>
101 #include <com/sun/star/document/XFilter.hpp>
102 #include <com/sun/star/embed/Aspects.hpp>
103 #include <com/sun/star/io/XSeekable.hpp>
104 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
105 #include <com/sun/star/util/XModifiable.hpp>
106 #include <com/sun/star/util/XRefreshable.hpp>
107 #include <com/sun/star/util/NumberFormat.hpp>
108 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
109 #include <com/sun/star/text/XText.hpp>
110 #include <com/sun/star/text/XTextDocument.hpp>
111 #include <com/sun/star/text/WritingMode2.hpp>
112 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
113 #include <com/sun/star/view/XSelectionSupplier.hpp>
114 #include <svl/itempool.hxx>
115 #include <svl/languageoptions.hxx>
116 #include <comphelper/classids.hxx>
117 #include <servicenames_charttypes.hxx>
120 #include <rtl/strbuf.hxx>
121 #include <rtl/ustring.hxx>
123 #include <osl/conditn.hxx>
124 #include <o3tl/make_unique.hxx>
125 #include <tools/diagnose_ex.h>
127 #include <memory>
129 namespace chart {
131 using namespace ::com::sun::star;
132 using namespace ::com::sun::star::chart2;
133 using ::com::sun::star::uno::Reference;
134 using ::com::sun::star::uno::Sequence;
135 using ::com::sun::star::uno::Any;
137 namespace {
139 class theExplicitValueProviderUnoTunnelId : public rtl::Static<UnoTunnelIdInit, theExplicitValueProviderUnoTunnelId> {};
141 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
142 typedef std::map< VCoordinateSystem*, tFullAxisIndex > tCoordinateSystemMap;
144 /** This class handles a collection of coordinate systems and is used for
145 * executing some action on all coordinate systems such as
146 * `prepareAutomaticAxisScaling` and `setExplicitScaleAndIncrement`.
147 * Moreover it contains the `aAutoScaling` object that is an instance of
148 * the `ScaleAutomatism` class. The initialization of `aAutoScaling` is
149 * performed in the `SeriesPlotterContainer::initAxisUsageList` method and is
150 * used in the `SeriesPlotterContainer::doAutoScaling` for calculating explicit
151 * scale and increment objects (see `SeriesPlotterContainer::doAutoScaling`).
153 struct AxisUsage
155 AxisUsage();
156 ~AxisUsage();
158 void addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex );
159 std::vector< VCoordinateSystem* > getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex );
160 sal_Int32 getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex );
162 void prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex );
163 void setExplicitScaleAndIncrement( sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc );
165 ScaleAutomatism aAutoScaling;
167 private:
168 tCoordinateSystemMap aCoordinateSystems;
169 std::map< sal_Int32, sal_Int32 > aMaxIndexPerDimension;
172 AxisUsage::AxisUsage()
173 : aAutoScaling(AxisHelper::createDefaultScale(), Date(Date::SYSTEM))
177 AxisUsage::~AxisUsage()
179 aCoordinateSystems.clear();
182 void AxisUsage::addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
184 if(!pCooSys)
185 return;
187 tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex );
188 tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) );
190 //use one scale only once for each coordinate system
191 //main axis are preferred over secondary axis
192 //value scales are preferred
193 if(aFound!=aCoordinateSystems.end())
195 sal_Int32 nFoundAxisIndex = aFound->second.second;
196 if( nFoundAxisIndex < nAxisIndex )
197 return;
198 sal_Int32 nFoundDimension = aFound->second.first;
199 if( nFoundDimension ==1 )
200 return;
201 if( nFoundDimension < nDimensionIndex )
202 return;
204 aCoordinateSystems[pCooSys] = aFullAxisIndex;
206 //set maximum scale index
207 std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex);
208 if( aIter != aMaxIndexPerDimension.end() )
210 sal_Int32 nCurrentMaxIndex = aIter->second;
211 if( nCurrentMaxIndex < nAxisIndex )
212 aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex;
214 else
215 aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex;
218 std::vector< VCoordinateSystem* > AxisUsage::getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
220 std::vector< VCoordinateSystem* > aRet;
222 for (auto const& coordinateSystem : aCoordinateSystems)
224 if( coordinateSystem.second.first != nDimensionIndex )
225 continue;
226 if( coordinateSystem.second.second != nAxisIndex )
227 continue;
228 aRet.push_back( coordinateSystem.first );
231 return aRet;
234 sal_Int32 AxisUsage::getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex )
236 sal_Int32 nRet = -1;
237 std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex);
238 if( aIter != aMaxIndexPerDimension.end() )
239 nRet = aIter->second;
240 return nRet;
243 void AxisUsage::prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex )
245 std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex);
246 for (VCoordinateSystem * i : aVCooSysList)
247 i->prepareAutomaticAxisScaling(rScaleAutomatism, nDimIndex, nAxisIndex);
250 void AxisUsage::setExplicitScaleAndIncrement(
251 sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc )
253 std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex);
254 for (VCoordinateSystem* i : aVCooSysList)
255 i->setExplicitScaleAndIncrement(nDimIndex, nAxisIndex, rScale, rInc);
258 typedef std::vector<std::unique_ptr<VSeriesPlotter> > SeriesPlottersType;
260 /** This class is a container of `SeriesPlotter` objects (such as `PieChart`
261 * instances). It is used for initializing coordinate systems, axes and scales
262 * of all series plotters which belongs to the container.
264 class SeriesPlotterContainer
266 public:
267 explicit SeriesPlotterContainer( std::vector< VCoordinateSystem* >& rVCooSysList );
268 ~SeriesPlotterContainer();
270 /** It is used to set coordinate systems (`m_rVCooSysList`), this method
271 * is invoked by `ChartView::createShapes2D` before of
272 * `ChartView::impl_createDiagramAndContent`.
273 * Coordinate systems are retrieved through the `XCoordinateSystemContainer`
274 * interface implemented by a diagram object which is provided by the
275 * `ChartModel` object passed to the method (`rChartModel.getFirstDiagram()`).
277 * It is used for creating series plotters and appending them
278 * to `m_aSeriesPlotterList`. The created series plotters are initialized
279 * through data (number formats supplier, color scheme, data series),
280 * extracted from the chart model or the diagram objects. An exception is
281 * the explicit category provider that is retrieved through the
282 * `VCoordinateSystem` object used by the series plotter.
284 * It sets the minimum-maximum supplier for a coordinate system:
285 * this supplier is the series plotter itself which utilizes the given
286 * coordinate system. In fact `VSeriesPlotter` has `MinimumMaximumSupplier`
287 * as one of its base classes.
288 * Hence, for instance, a `PieChart`, which is a series plotter, is
289 * a `MinimumMaximumSupplier`, too.
291 void initializeCooSysAndSeriesPlotter( ChartModel& rModel );
293 /** This method is invoked by `ChartView::impl_createDiagramAndContent`.
294 * It iterates on every axis of every coordinate systems, and if the axis
295 * is not yet present in `m_aAxisUsageList` it creates a new `AxisUsage`
296 * object and initialize its `aAutoScaling` member to the `ScaleData`
297 * object of the current axis.
299 void initAxisUsageList(const Date& rNullDate);
302 * Perform automatic axis scaling and determine the amount and spacing of
303 * increments. It assumes that the caller has determined the size of the
304 * largest axis label text object prior to calling this method.
306 * The new axis scaling data will be stored in the VCoordinateSystem
307 * objects. The label alignment direction for each axis will also get
308 * determined during this process, and stored in VAxis.
310 * This method is invoked by `ChartView::impl_createDiagramAndContent`
311 * soon after `initAxisUsageList`.
312 * It initializes explicit scale and increment objects for all coordinate
313 * systems in `m_rVCooSysList`.
314 * This action is achieved by iterating on the `m_aAxisUsageList` container,
315 * and performing 3 steps:
316 * 1- call `VCoordinateSystem::prepareAutomaticAxisScaling` for setting
317 * scaling parameters of the `aAutoScaling` member (a `ScaleAutomatism`
318 * object) for the current `AxisUsage` instance
319 * (see `VCoordinateSystem::prepareAutomaticAxisScaling`);
320 * 2- calculate the explicit scale and increment objects
321 * (see ScaleAutomatism::calculateExplicitScaleAndIncrement);
322 * 3- set the explicit scale and increment objects for each coordinate
323 * system.
325 void doAutoScaling( ChartModel& rModel );
328 * After auto-scaling is performed, call this method to set the explicit
329 * scaling and increment data to all relevant VAxis objects.
331 void updateScalesAndIncrementsOnAxes();
334 * After auto-scaling is performed, call this method to set the explicit
335 * scaling data to all the plotters.
337 void setScalesFromCooSysToPlotter();
339 void setNumberFormatsFromAxes();
340 drawing::Direction3D getPreferredAspectRatio();
342 SeriesPlottersType& getSeriesPlotterList() { return m_aSeriesPlotterList; }
343 std::vector< VCoordinateSystem* >& getCooSysList() { return m_rVCooSysList; }
344 std::vector< LegendEntryProvider* > getLegendEntryProviderList();
346 void AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel );
348 bool isCategoryPositionShifted(
349 const chart2::ScaleData& rSourceScale, bool bHasComplexCategories ) const;
351 private:
352 /** A vector of series plotters.
354 SeriesPlottersType m_aSeriesPlotterList;
356 /** A vector of coordinate systems.
358 std::vector< VCoordinateSystem* >& m_rVCooSysList;
360 /** A map whose key is a `XAxis` interface and the related value is
361 * an object of `AxisUsage` type.
363 std::map< uno::Reference< XAxis >, AxisUsage > m_aAxisUsageList;
366 * Max axis index of all dimensions. Currently this can be either 0 or 1
367 * since we only support primary and secondary axes per dimension. The
368 * value of 0 means all dimensions have only primary axis, while 1 means
369 * at least one dimension has a secondary axis.
371 sal_Int32 m_nMaxAxisIndex;
373 bool m_bChartTypeUsesShiftedCategoryPositionPerDefault;
374 sal_Int32 m_nDefaultDateNumberFormat;
377 SeriesPlotterContainer::SeriesPlotterContainer( std::vector< VCoordinateSystem* >& rVCooSysList )
378 : m_rVCooSysList( rVCooSysList )
379 , m_nMaxAxisIndex(0)
380 , m_bChartTypeUsesShiftedCategoryPositionPerDefault(false)
381 , m_nDefaultDateNumberFormat(0)
385 SeriesPlotterContainer::~SeriesPlotterContainer()
387 // - remove plotter from coordinatesystems
388 for(VCoordinateSystem* nC : m_rVCooSysList)
389 nC->clearMinimumAndMaximumSupplierList();
392 std::vector< LegendEntryProvider* > SeriesPlotterContainer::getLegendEntryProviderList()
394 std::vector< LegendEntryProvider* > aRet( m_aSeriesPlotterList.size() );
395 sal_Int32 nN = 0;
396 for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList)
397 aRet[nN++] = aPlotter.get();
398 return aRet;
401 VCoordinateSystem* findInCooSysList( const std::vector< VCoordinateSystem* >& rVCooSysList
402 , const uno::Reference< XCoordinateSystem >& xCooSys )
404 for(VCoordinateSystem* pVCooSys : rVCooSysList)
406 if(pVCooSys->getModel()==xCooSys)
407 return pVCooSys;
409 return nullptr;
412 VCoordinateSystem* lcl_getCooSysForPlotter( const std::vector< VCoordinateSystem* >& rVCooSysList, MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier )
414 if(!pMinimumAndMaximumSupplier)
415 return nullptr;
416 for(VCoordinateSystem* pVCooSys : rVCooSysList)
418 if(pVCooSys->hasMinimumAndMaximumSupplier( pMinimumAndMaximumSupplier ))
419 return pVCooSys;
421 return nullptr;
424 VCoordinateSystem* addCooSysToList( std::vector< VCoordinateSystem* >& rVCooSysList
425 , const uno::Reference< XCoordinateSystem >& xCooSys
426 , ChartModel& rChartModel )
428 VCoordinateSystem* pVCooSys = findInCooSysList( rVCooSysList, xCooSys );
429 if( !pVCooSys )
431 pVCooSys = VCoordinateSystem::createCoordinateSystem(xCooSys );
432 if(pVCooSys)
434 OUString aCooSysParticle( ObjectIdentifier::createParticleForCoordinateSystem( xCooSys, rChartModel ) );
435 pVCooSys->setParticle(aCooSysParticle);
437 pVCooSys->setExplicitCategoriesProvider( new ExplicitCategoriesProvider(xCooSys, rChartModel) );
439 rVCooSysList.push_back( pVCooSys );
442 return pVCooSys;
445 void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter(
446 ChartModel& rChartModel )
448 uno::Reference< XDiagram > xDiagram( rChartModel.getFirstDiagram() );
449 if( !xDiagram.is())
450 return;
452 uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( static_cast< ::cppu::OWeakObject* >( &rChartModel ), uno::UNO_QUERY );
453 if( rChartModel.hasInternalDataProvider() && DiagramHelper::isSupportingDateAxis( xDiagram ) )
454 m_nDefaultDateNumberFormat=DiagramHelper::getDateNumberFormat( xNumberFormatsSupplier );
456 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
457 if(!nDimensionCount)
459 //@todo handle mixed dimension
460 nDimensionCount = 2;
463 bool bSortByXValues = false;
464 bool bConnectBars = false;
465 bool bGroupBarsPerAxis = true;
466 bool bIncludeHiddenCells = true;
467 sal_Int32 nStartingAngle = 90;
468 sal_Int32 n3DRelativeHeight = 100;
471 uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY_THROW );
472 xDiaProp->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= bSortByXValues;
473 xDiaProp->getPropertyValue( "ConnectBars" ) >>= bConnectBars;
474 xDiaProp->getPropertyValue( "GroupBarsPerAxis" ) >>= bGroupBarsPerAxis;
475 xDiaProp->getPropertyValue( "IncludeHiddenCells" ) >>= bIncludeHiddenCells;
476 xDiaProp->getPropertyValue( "StartingAngle" ) >>= nStartingAngle;
478 if (nDimensionCount == 3)
480 xDiaProp->getPropertyValue( "3DRelativeHeight" ) >>= n3DRelativeHeight;
483 catch( const uno::Exception & )
485 DBG_UNHANDLED_EXCEPTION("chart2" );
488 //prepare for autoscaling and shape creation
489 // - create plotter for charttypes (for each first scale group at each plotter, as they are independent)
490 // - add series to plotter (thus each charttype can provide minimum and maximum values for autoscaling)
491 // - add plotter to coordinate systems
493 //iterate through all coordinate systems
494 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
495 OSL_ASSERT( xCooSysContainer.is());
496 if( !xCooSysContainer.is())
497 return;
498 uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme());
499 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
500 sal_Int32 nGlobalSeriesIndex = 0;//for automatic symbols
501 for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
503 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
504 VCoordinateSystem* pVCooSys = addCooSysToList(m_rVCooSysList,xCooSys,rChartModel);
506 //iterate through all chart types in the current coordinate system
507 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
508 OSL_ASSERT( xChartTypeContainer.is());
509 if( !xChartTypeContainer.is() )
510 continue;
511 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
512 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
514 uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
515 if(nDimensionCount == 3 && xChartType->getChartType().equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE))
517 uno::Reference< beans::XPropertySet > xPropertySet( xChartType, uno::UNO_QUERY );
518 if (xPropertySet.is())
522 sal_Int32 n3DRelativeHeightOldValue(100);
523 uno::Any aAny = xPropertySet->getPropertyValue( "3DRelativeHeight" );
524 aAny >>= n3DRelativeHeightOldValue;
525 if (n3DRelativeHeightOldValue != n3DRelativeHeight)
526 xPropertySet->setPropertyValue( "3DRelativeHeight", uno::Any(n3DRelativeHeight) );
528 catch (const uno::Exception&) { }
532 if(nT==0)
533 m_bChartTypeUsesShiftedCategoryPositionPerDefault = ChartTypeHelper::shiftCategoryPosAtXAxisPerDefault( xChartType );
535 bool bExcludingPositioning = DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_EXCLUDING;
536 VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( xChartType, nDimensionCount, bExcludingPositioning );
537 if( !pPlotter )
538 continue;
540 m_aSeriesPlotterList.push_back( std::unique_ptr<VSeriesPlotter>(pPlotter) );
541 pPlotter->setNumberFormatsSupplier( xNumberFormatsSupplier );
542 pPlotter->setColorScheme( xColorScheme );
543 if(pVCooSys)
544 pPlotter->setExplicitCategoriesProvider( pVCooSys->getExplicitCategoriesProvider() );
545 sal_Int32 nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( xDiagram, xChartType );
547 if(pVCooSys)
548 pVCooSys->addMinimumAndMaximumSupplier(pPlotter);
550 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
551 OSL_ASSERT( xDataSeriesContainer.is());
552 if( !xDataSeriesContainer.is() )
553 continue;
555 sal_Int32 zSlot=-1;
556 sal_Int32 xSlot=-1;
557 sal_Int32 ySlot=-1;
558 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
559 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
561 uno::Reference< XDataSeries > xDataSeries( aSeriesList[nS], uno::UNO_QUERY );
562 if(!xDataSeries.is())
563 continue;
564 if( !bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries) )
565 continue;
567 VDataSeries* pSeries = new VDataSeries( xDataSeries );
569 pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex);
570 nGlobalSeriesIndex++;
572 if( bSortByXValues )
573 pSeries->doSortByXValues();
575 pSeries->setConnectBars( bConnectBars );
576 pSeries->setGroupBarsPerAxis( bGroupBarsPerAxis );
577 pSeries->setStartingAngle( nStartingAngle );
579 pSeries->setMissingValueTreatment( nMissingValueTreatment );
581 OUString aSeriesParticle( ObjectIdentifier::createParticleForSeries( 0, nCS, nT, nS ) );
582 pSeries->setParticle(aSeriesParticle);
584 OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) );
585 pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole);
587 //ignore secondary axis for charttypes that do not support them
588 if( pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX &&
589 !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ) )
591 pSeries->setAttachedAxisIndex(MAIN_AXIS_INDEX);
594 StackingDirection eDirection = pSeries->getStackingDirection();
595 switch(eDirection)
597 case StackingDirection_NO_STACKING:
598 xSlot++; ySlot=-1;
599 if(zSlot<0)
600 zSlot=0;
601 break;
602 case StackingDirection_Y_STACKING:
603 ySlot++;
604 if(xSlot<0)
605 xSlot=0;
606 if(zSlot<0)
607 zSlot=0;
608 break;
609 case StackingDirection_Z_STACKING:
610 zSlot++; xSlot=-1; ySlot=-1;
611 break;
612 default:
613 // UNO enums have one additional auto-generated case
614 break;
616 pPlotter->addSeries( pSeries, zSlot, xSlot, ySlot );
621 //transport seriesnames to the coordinatesystems if needed
622 if( !m_aSeriesPlotterList.empty() )
624 uno::Sequence< OUString > aSeriesNames;
625 bool bSeriesNamesInitialized = false;
626 for(VCoordinateSystem* pVCooSys : m_rVCooSysList)
628 if(!pVCooSys)
629 continue;
630 if( pVCooSys->needSeriesNamesForAxis() )
632 if(!bSeriesNamesInitialized)
634 aSeriesNames = m_aSeriesPlotterList[0]->getSeriesNames();
635 bSeriesNamesInitialized = true;
637 pVCooSys->setSeriesNamesForAxis( aSeriesNames );
643 bool SeriesPlotterContainer::isCategoryPositionShifted(
644 const chart2::ScaleData& rSourceScale, bool bHasComplexCategories ) const
646 if (rSourceScale.AxisType == AxisType::CATEGORY && m_bChartTypeUsesShiftedCategoryPositionPerDefault)
647 return true;
649 if (rSourceScale.AxisType==AxisType::CATEGORY && bHasComplexCategories)
650 return true;
652 if (rSourceScale.AxisType == AxisType::DATE)
653 return true;
655 if (rSourceScale.AxisType == AxisType::SERIES)
656 return true;
658 return false;
661 void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate)
663 m_aAxisUsageList.clear();
665 // Loop through coordinate systems in the diagram (though for now
666 // there should only be one coordinate system per diagram).
667 for (VCoordinateSystem* pVCooSys : m_rVCooSysList)
669 uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel();
670 sal_Int32 nDimCount = xCooSys->getDimension();
672 for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex)
674 bool bDateAxisAllowed = ChartTypeHelper::isSupportingDateAxis(
675 AxisHelper::getChartTypeByIndex(xCooSys, 0), nDimIndex);
677 // Each dimension may have primary and secondary axes.
678 const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
679 for (sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; ++nAxisIndex)
681 uno::Reference<XAxis> xAxis = xCooSys->getAxisByDimension(nDimIndex, nAxisIndex);
683 if (!xAxis.is())
684 continue;
686 if (m_aAxisUsageList.find(xAxis) == m_aAxisUsageList.end())
688 // Create axis usage object for this axis.
690 chart2::ScaleData aSourceScale = xAxis->getScaleData();
691 ExplicitCategoriesProvider* pCatProvider = pVCooSys->getExplicitCategoriesProvider();
692 if (nDimIndex == 0)
693 AxisHelper::checkDateAxis( aSourceScale, pCatProvider, bDateAxisAllowed );
695 bool bHasComplexCat = pCatProvider && pCatProvider->hasComplexCategories();
696 aSourceScale.ShiftedCategoryPosition = isCategoryPositionShifted(aSourceScale, bHasComplexCat);
698 m_aAxisUsageList[xAxis].aAutoScaling = ScaleAutomatism(aSourceScale, rNullDate);
701 AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis];
702 rAxisUsage.addCoordinateSystem(pVCooSys, nDimIndex, nAxisIndex);
707 // Determine the highest axis index of all dimensions.
708 m_nMaxAxisIndex = 0;
709 for (VCoordinateSystem* pVCooSys : m_rVCooSysList)
711 uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel();
712 sal_Int32 nDimCount = xCooSys->getDimension();
714 for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex)
716 for (auto & axisUsage : m_aAxisUsageList)
718 sal_Int32 nLocalMax = axisUsage.second.getMaxAxisIndexForDimension(nDimIndex);
719 if (m_nMaxAxisIndex < nLocalMax)
720 m_nMaxAxisIndex = nLocalMax;
726 void SeriesPlotterContainer::setScalesFromCooSysToPlotter()
728 //set scales to plotter to enable them to provide the preferred scene AspectRatio
729 for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
731 VSeriesPlotter* pSeriesPlotter = aPlotter.get();
732 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter );
733 if(pVCooSys)
735 pSeriesPlotter->setScales( pVCooSys->getExplicitScales(0,0), pVCooSys->getPropertySwapXAndYAxis() );
736 sal_Int32 nMaxAxisIndex = pVCooSys->getMaximumAxisIndexByDimension(1);//only additional value axis are relevant for series plotter
737 for( sal_Int32 nI=1; nI<=nMaxAxisIndex; nI++ )
738 pSeriesPlotter->addSecondaryValueScale( pVCooSys->getExplicitScale(1,nI), nI );
743 void SeriesPlotterContainer::setNumberFormatsFromAxes()
745 //set numberformats to plotter to enable them to display the data labels in the numberformat of the axis
746 for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
748 VSeriesPlotter* pSeriesPlotter = aPlotter.get();
749 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter );
750 if(pVCooSys)
752 AxesNumberFormats aAxesNumberFormats;
753 uno::Reference< XCoordinateSystem > xCooSys = pVCooSys->getModel();
754 sal_Int32 nDimensionCount = xCooSys->getDimension();
755 for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nDimensionCount; ++nDimensionIndex)
757 const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
758 for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex)
762 Reference< beans::XPropertySet > xAxisProp( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY );
763 if( xAxisProp.is())
765 sal_Int32 nNumberFormatKey(0);
766 if( xAxisProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey )
768 aAxesNumberFormats.setFormat( nNumberFormatKey, nDimensionIndex, nAxisIndex );
770 else if( nDimensionIndex==0 )
772 //provide a default date format for date axis with own data
773 aAxesNumberFormats.setFormat( m_nDefaultDateNumberFormat, nDimensionIndex, nAxisIndex );
777 catch( const lang::IndexOutOfBoundsException& e )
779 SAL_WARN("chart2", "Exception caught. " << e );
783 pSeriesPlotter->setAxesNumberFormats( aAxesNumberFormats );
788 void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes()
790 for(VCoordinateSystem* nC : m_rVCooSysList)
791 nC->updateScalesAndIncrementsOnAxes();
794 void SeriesPlotterContainer::doAutoScaling( ChartModel& rChartModel )
796 if (m_aSeriesPlotterList.empty() || m_aAxisUsageList.empty())
797 // We need these two containers populated to do auto-scaling. Bail out.
798 return;
800 //iterate over the main scales first than secondary axis
801 for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; ++nAxisIndex)
803 // - first do autoscale for all x and z scales (because they are treated independent)
804 for (auto & axisUsage : m_aAxisUsageList)
806 AxisUsage& rAxisUsage = axisUsage.second;
808 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 0, nAxisIndex);
809 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 2, nAxisIndex);
811 ExplicitScaleData aExplicitScale;
812 ExplicitIncrementData aExplicitIncrement;
813 rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement );
815 rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement);
816 rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement);
819 // - second do autoscale for the dependent y scales (the coordinate systems are prepared with x and z scales already )
820 for (auto & axisUsage : m_aAxisUsageList)
822 AxisUsage& rAxisUsage = axisUsage.second;
824 rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAxisIndex);
826 ExplicitScaleData aExplicitScale;
827 ExplicitIncrementData aExplicitIncrement;
828 rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement );
830 rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement);
831 rAxisUsage.setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScale, aExplicitIncrement);
832 rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement);
835 AdaptScaleOfYAxisWithoutAttachedSeries( rChartModel );
838 void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel )
840 //issue #i80518#
841 for( sal_Int32 nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ )
843 for (auto & axisUsage : m_aAxisUsageList)
845 AxisUsage& rAxisUsage = axisUsage.second;
846 std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems( 1, nAxisIndex );
847 if( aVCooSysList_Y.empty() )
848 continue;
850 uno::Reference< XDiagram > xDiagram( rModel.getFirstDiagram() );
851 if (!xDiagram.is())
852 continue;
854 bool bSeriesAttachedToThisAxis = false;
855 sal_Int32 nAttachedAxisIndex = -1;
857 std::vector< Reference< XDataSeries > > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
858 for (auto const& series : aSeriesVector)
860 sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series);
861 if( nAxisIndex == nCurrentIndex )
863 bSeriesAttachedToThisAxis = true;
864 break;
866 else if( nAttachedAxisIndex<0 || nAttachedAxisIndex>nCurrentIndex )
867 nAttachedAxisIndex=nCurrentIndex;
871 if (bSeriesAttachedToThisAxis || nAttachedAxisIndex < 0)
872 continue;
874 for(VCoordinateSystem* nC : aVCooSysList_Y)
876 nC->prepareAutomaticAxisScaling( rAxisUsage.aAutoScaling, 1, nAttachedAxisIndex );
878 ExplicitScaleData aExplicitScaleSource = nC->getExplicitScale( 1,nAttachedAxisIndex );
879 ExplicitIncrementData aExplicitIncrementSource = nC->getExplicitIncrement( 1,nAttachedAxisIndex );
881 ExplicitScaleData aExplicitScaleDest = nC->getExplicitScale( 1,nAxisIndex );
882 ExplicitIncrementData aExplicitIncrementDest = nC->getExplicitIncrement( 1,nAxisIndex );
884 aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation;
885 aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling;
886 aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType;
888 aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue;
890 ScaleData aScale( rAxisUsage.aAutoScaling.getScale() );
891 if( !aScale.Minimum.hasValue() )
893 bool bNewMinOK = true;
894 double fMax=0.0;
895 if( aScale.Maximum >>= fMax )
896 bNewMinOK = (aExplicitScaleSource.Minimum <= fMax);
897 if( bNewMinOK )
898 aExplicitScaleDest.Minimum = aExplicitScaleSource.Minimum;
900 else
901 aExplicitIncrementDest.BaseValue = aExplicitScaleDest.Minimum;
903 if( !aScale.Maximum.hasValue() )
905 bool bNewMaxOK = true;
906 double fMin=0.0;
907 if( aScale.Minimum >>= fMin )
908 bNewMaxOK = (fMin <= aExplicitScaleSource.Maximum);
909 if( bNewMaxOK )
910 aExplicitScaleDest.Maximum = aExplicitScaleSource.Maximum;
912 if( !aScale.Origin.hasValue() )
913 aExplicitScaleDest.Origin = aExplicitScaleSource.Origin;
915 if( !aScale.IncrementData.Distance.hasValue() )
916 aExplicitIncrementDest.Distance = aExplicitIncrementSource.Distance;
918 bool bAutoMinorInterval = true;
919 if( aScale.IncrementData.SubIncrements.getLength() )
920 bAutoMinorInterval = !( aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() );
921 if( bAutoMinorInterval )
923 if( !aExplicitIncrementDest.SubIncrements.empty() && !aExplicitIncrementSource.SubIncrements.empty() )
924 aExplicitIncrementDest.SubIncrements[0].IntervalCount =
925 aExplicitIncrementSource.SubIncrements[0].IntervalCount;
928 nC->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScaleDest, aExplicitIncrementDest );
933 if( AxisHelper::isAxisPositioningEnabled() )
935 //correct origin for y main axis (the origin is where the other main axis crosses)
936 sal_Int32 nAxisIndex=0;
937 sal_Int32 nDimensionIndex=1;
938 for (auto & axisUsage : m_aAxisUsageList)
940 AxisUsage& rAxisUsage = axisUsage.second;
941 std::vector< VCoordinateSystem* > aVCooSysList = rAxisUsage.getCoordinateSystems(nDimensionIndex,nAxisIndex);
942 size_t nC;
943 for( nC=0; nC < aVCooSysList.size(); nC++)
945 ExplicitScaleData aExplicitScale( aVCooSysList[nC]->getExplicitScale( nDimensionIndex, nAxisIndex ) );
946 ExplicitIncrementData aExplicitIncrement( aVCooSysList[nC]->getExplicitIncrement( nDimensionIndex, nAxisIndex ) );
948 Reference< chart2::XCoordinateSystem > xCooSys( aVCooSysList[nC]->getModel() );
949 Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) );
950 Reference< beans::XPropertySet > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ), uno::UNO_QUERY );
952 css::chart::ChartAxisPosition eCrossingMainAxisPos( css::chart::ChartAxisPosition_ZERO );
953 if( xCrossingMainAxis.is() )
955 xCrossingMainAxis->getPropertyValue("CrossoverPosition") >>= eCrossingMainAxisPos;
956 if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_VALUE )
958 double fValue = 0.0;
959 xCrossingMainAxis->getPropertyValue("CrossoverValue") >>= fValue;
960 aExplicitScale.Origin = fValue;
962 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_ZERO )
963 aExplicitScale.Origin = 0.0;
964 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_START )
965 aExplicitScale.Origin = aExplicitScale.Minimum;
966 else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_END )
967 aExplicitScale.Origin = aExplicitScale.Maximum;
970 aVCooSysList[nC]->setExplicitScaleAndIncrement( nDimensionIndex, nAxisIndex, aExplicitScale, aExplicitIncrement );
976 drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio()
978 drawing::Direction3D aPreferredAspectRatio(1.0,1.0,1.0);
980 sal_Int32 nPlotterCount=0;
981 //get a list of all preferred aspect ratios and combine them
982 //first with special demands wins (less or equal zero <-> arbitrary)
983 double fx, fy, fz;
984 fx = fy = fz = -1.0;
985 for( std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList )
987 drawing::Direction3D aSingleRatio( aPlotter->getPreferredDiagramAspectRatio() );
988 if( fx<0 && aSingleRatio.DirectionX>0 )
989 fx = aSingleRatio.DirectionX;
991 if( fy<0 && aSingleRatio.DirectionY>0 )
993 if( fx>0 && aSingleRatio.DirectionX>0 )
994 fy = fx*aSingleRatio.DirectionY/aSingleRatio.DirectionX;
995 else if( fz>0 && aSingleRatio.DirectionZ>0 )
996 fy = fz*aSingleRatio.DirectionY/aSingleRatio.DirectionZ;
997 else
998 fy = aSingleRatio.DirectionY;
1001 if( fz<0 && aSingleRatio.DirectionZ>0 )
1003 if( fx>0 && aSingleRatio.DirectionX>0 )
1004 fz = fx*aSingleRatio.DirectionZ/aSingleRatio.DirectionX;
1005 else if( fy>0 && aSingleRatio.DirectionY>0 )
1006 fz = fy*aSingleRatio.DirectionZ/aSingleRatio.DirectionY;
1007 else
1008 fz = aSingleRatio.DirectionZ;
1011 if( fx>0 && fy>0 && fz>0 )
1012 break;
1013 ++nPlotterCount;
1015 aPreferredAspectRatio = drawing::Direction3D(fx, fy, fz);
1016 return aPreferredAspectRatio;
1021 struct CreateShapeParam2D
1023 css::awt::Rectangle maRemainingSpace;
1025 std::shared_ptr<SeriesPlotterContainer> mpSeriesPlotterContainer;
1027 std::shared_ptr<VTitle> mpVTitleX;
1028 std::shared_ptr<VTitle> mpVTitleY;
1029 std::shared_ptr<VTitle> mpVTitleZ;
1031 std::shared_ptr<VTitle> mpVTitleSecondX;
1032 std::shared_ptr<VTitle> mpVTitleSecondY;
1034 css::uno::Reference<css::drawing::XShape> mxMarkHandles;
1035 css::uno::Reference<css::drawing::XShape> mxPlotAreaWithAxes;
1037 css::uno::Reference<css::drawing::XShapes> mxDiagramWithAxesShapes;
1039 bool mbAutoPosTitleX;
1040 bool mbAutoPosTitleY;
1041 bool mbAutoPosTitleZ;
1043 bool mbAutoPosSecondTitleX;
1044 bool mbAutoPosSecondTitleY;
1046 bool mbUseFixedInnerSize;
1048 CreateShapeParam2D() :
1049 mbAutoPosTitleX(true),
1050 mbAutoPosTitleY(true),
1051 mbAutoPosTitleZ(true),
1052 mbAutoPosSecondTitleX(true),
1053 mbAutoPosSecondTitleY(true),
1054 mbUseFixedInnerSize(false) {}
1057 class GL2DRenderer : public IRenderer
1059 public:
1060 explicit GL2DRenderer(ChartView* pView);
1061 virtual ~GL2DRenderer() override;
1063 virtual void update() override;
1064 virtual void clickedAt(const Point& rPos, sal_uInt16 nButton) override;
1065 virtual void mouseDragMove(const Point& rBegin, const Point& rEnd, sal_uInt16 nButton) override;
1066 virtual void scroll(long nDelta) override;
1067 virtual void contextDestroyed() override;
1069 #if HAVE_FEATURE_OPENGL
1070 const OpenGLWindow* getOpenGLWindow() const;
1071 void updateOpenGLWindow();
1072 #endif
1073 private:
1074 ChartView* mpView;
1075 bool mbContextDestroyed;
1076 #if HAVE_FEATURE_OPENGL
1077 VclPtr<OpenGLWindow> mpWindow;
1078 #endif
1081 GL2DRenderer::GL2DRenderer(ChartView* pView)
1082 : mpView(pView)
1083 , mbContextDestroyed(false)
1084 #if HAVE_FEATURE_OPENGL
1085 , mpWindow(mpView->mrChartModel.getOpenGLWindow())
1086 #endif
1090 GL2DRenderer::~GL2DRenderer()
1092 #if HAVE_FEATURE_OPENGL
1093 SolarMutexGuard g;
1094 if(!mbContextDestroyed && mpWindow)
1095 mpWindow->setRenderer(nullptr);
1096 mpWindow.reset();
1097 #endif
1100 void GL2DRenderer::update()
1102 mpView->update();
1103 mpView->render();
1106 void GL2DRenderer::clickedAt(const Point&, sal_uInt16 )
1110 void GL2DRenderer::mouseDragMove(const Point& , const Point& , sal_uInt16 )
1114 void GL2DRenderer::scroll(long )
1118 void GL2DRenderer::contextDestroyed()
1120 mbContextDestroyed = true;
1123 #if HAVE_FEATURE_OPENGL
1125 const OpenGLWindow* GL2DRenderer::getOpenGLWindow() const
1127 return mpWindow;
1130 void GL2DRenderer::updateOpenGLWindow()
1132 if(mbContextDestroyed)
1133 return;
1135 OpenGLWindow* pWindow = mpView->mrChartModel.getOpenGLWindow();
1136 if(pWindow != mpWindow)
1138 if(mpWindow)
1140 mpWindow->setRenderer(nullptr);
1143 if(pWindow)
1145 pWindow->setRenderer(this);
1148 mpWindow = pWindow;
1151 #endif
1153 const uno::Sequence<sal_Int8>& ExplicitValueProvider::getUnoTunnelId()
1155 return theExplicitValueProviderUnoTunnelId::get().getSeq();
1158 ExplicitValueProvider* ExplicitValueProvider::getExplicitValueProvider(
1159 const Reference< uno::XInterface >& xChartView )
1161 ExplicitValueProvider* pExplicitValueProvider=nullptr;
1163 Reference< lang::XUnoTunnel > xTunnel( xChartView, uno::UNO_QUERY );
1164 if( xTunnel.is() )
1166 pExplicitValueProvider = reinterpret_cast<ExplicitValueProvider*>(xTunnel->getSomething(
1167 ExplicitValueProvider::getUnoTunnelId() ));
1169 return pExplicitValueProvider;
1172 ChartView::ChartView(
1173 uno::Reference<uno::XComponentContext> const & xContext,
1174 ChartModel& rModel)
1175 : m_aMutex()
1176 , m_xCC(xContext)
1177 , mrChartModel(rModel)
1178 , m_xShapeFactory()
1179 , m_xDrawPage()
1180 , m_pDrawModelWrapper()
1181 , m_aListenerContainer( m_aMutex )
1182 , m_bViewDirty(true)
1183 , m_bInViewUpdate(false)
1184 , m_bViewUpdatePending(false)
1185 , m_bRefreshAddIn(true)
1186 , m_aPageResolution(1000,1000)
1187 , m_bPointsWereSkipped(false)
1188 , m_nScaleXNumerator(1)
1189 , m_nScaleXDenominator(1)
1190 , m_nScaleYNumerator(1)
1191 , m_nScaleYDenominator(1)
1192 , m_bSdrViewIsInEditMode(false)
1193 , m_aResultingDiagramRectangleExcludingAxes(0,0,0,0)
1194 , mp2DRenderer(new GL2DRenderer(this))
1196 init();
1199 void ChartView::init()
1201 if( !m_pDrawModelWrapper.get() )
1203 SolarMutexGuard aSolarGuard;
1204 m_pDrawModelWrapper = std::make_shared< DrawModelWrapper >();
1205 m_xShapeFactory = m_pDrawModelWrapper->getShapeFactory();
1206 m_xDrawPage = m_pDrawModelWrapper->getMainDrawPage();
1207 StartListening( m_pDrawModelWrapper->getSdrModel() );
1211 void SAL_CALL ChartView::initialize( const uno::Sequence< uno::Any >& )
1213 init();
1216 ChartView::~ChartView()
1218 maTimeBased.maTimer.Stop();
1219 // #i120831#. In ChartView::initialize(), m_xShapeFactory is created from SdrModel::getUnoModel() and indirectly
1220 // from SfxBaseModel, it needs call dispose() to make sure SfxBaseModel object is freed correctly.
1221 uno::Reference< lang::XComponent > xComp( m_xShapeFactory, uno::UNO_QUERY);
1222 if ( xComp.is() )
1223 xComp->dispose();
1225 if( m_pDrawModelWrapper.get() )
1227 SolarMutexGuard aSolarGuard;
1228 EndListening( m_pDrawModelWrapper->getSdrModel() );
1229 m_pDrawModelWrapper.reset();
1231 m_xDrawPage = nullptr;
1232 impl_deleteCoordinateSystems();
1235 void ChartView::impl_deleteCoordinateSystems()
1237 //delete all coordinate systems
1238 std::vector< VCoordinateSystem* > aVectorToDeleteObjects;
1239 std::swap( aVectorToDeleteObjects, m_aVCooSysList );//#i109770#
1240 for (auto const& elem : aVectorToDeleteObjects)
1242 delete elem;
1244 aVectorToDeleteObjects.clear();
1247 // datatransfer::XTransferable
1248 namespace
1250 const OUString lcl_aGDIMetaFileMIMEType(
1251 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" );
1252 const OUString lcl_aGDIMetaFileMIMETypeHighContrast(
1253 "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" );
1254 } // anonymous namespace
1256 void ChartView::getMetaFile( const uno::Reference< io::XOutputStream >& xOutStream
1257 , bool bUseHighContrast )
1259 if( !m_xDrawPage.is() )
1260 return;
1262 // creating the graphic exporter
1263 uno::Reference< drawing::XGraphicExportFilter > xExporter = drawing::GraphicExportFilter::create( m_xCC );
1265 uno::Sequence< beans::PropertyValue > aProps(3);
1266 aProps[0].Name = "FilterName";
1267 aProps[0].Value <<= OUString("SVM");
1269 aProps[1].Name = "OutputStream";
1270 aProps[1].Value <<= xOutStream;
1272 uno::Sequence< beans::PropertyValue > aFilterData(8);
1273 aFilterData[0].Name = "ExportOnlyBackground";
1274 aFilterData[0].Value <<= false;
1275 aFilterData[1].Name = "HighContrast";
1276 aFilterData[1].Value <<= bUseHighContrast;
1278 aFilterData[2].Name = "Version";
1279 const sal_Int32 nVersion = SOFFICE_FILEFORMAT_50;
1280 aFilterData[2].Value <<= nVersion;
1282 aFilterData[3].Name = "CurrentPage";
1283 aFilterData[3].Value <<= uno::Reference< uno::XInterface >( m_xDrawPage, uno::UNO_QUERY );
1285 //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
1286 aFilterData[4].Name = "ScaleXNumerator";
1287 aFilterData[4].Value <<= m_nScaleXNumerator;
1288 aFilterData[5].Name = "ScaleXDenominator";
1289 aFilterData[5].Value <<= m_nScaleXDenominator;
1290 aFilterData[6].Name = "ScaleYNumerator";
1291 aFilterData[6].Value <<= m_nScaleYNumerator;
1292 aFilterData[7].Name = "ScaleYDenominator";
1293 aFilterData[7].Value <<= m_nScaleYDenominator;
1296 aProps[2].Name = "FilterData";
1297 aProps[2].Value <<= aFilterData;
1299 xExporter->setSourceDocument( uno::Reference< lang::XComponent >( m_xDrawPage, uno::UNO_QUERY) );
1300 if( xExporter->filter( aProps ) )
1302 xOutStream->flush();
1303 xOutStream->closeOutput();
1304 uno::Reference< io::XSeekable > xSeekable( xOutStream, uno::UNO_QUERY );
1305 if( xSeekable.is() )
1306 xSeekable->seek(0);
1310 uno::Any SAL_CALL ChartView::getTransferData( const datatransfer::DataFlavor& aFlavor )
1312 bool bHighContrastMetaFile( aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast);
1313 uno::Any aRet;
1314 if( ! (bHighContrastMetaFile || aFlavor.MimeType == lcl_aGDIMetaFileMIMEType) )
1315 return aRet;
1317 update();
1319 SvMemoryStream aStream( 1024, 1024 );
1320 utl::OStreamWrapper* pStreamWrapper = new utl::OStreamWrapper( aStream );
1322 uno::Reference< io::XOutputStream > xOutStream( pStreamWrapper );
1323 uno::Reference< io::XInputStream > xInStream( pStreamWrapper );
1324 uno::Reference< io::XSeekable > xSeekable( pStreamWrapper );
1326 if( xOutStream.is() )
1328 this->getMetaFile( xOutStream, bHighContrastMetaFile );
1330 if( xInStream.is() && xSeekable.is() )
1332 xSeekable->seek(0);
1333 sal_Int32 nBytesToRead = xInStream->available();
1334 uno::Sequence< sal_Int8 > aSeq( nBytesToRead );
1335 xInStream->readBytes( aSeq, nBytesToRead);
1336 aRet <<= aSeq;
1337 xInStream->closeInput();
1341 return aRet;
1343 uno::Sequence< datatransfer::DataFlavor > SAL_CALL ChartView::getTransferDataFlavors()
1345 uno::Sequence< datatransfer::DataFlavor > aRet(2);
1347 aRet[0] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMEType,
1348 "GDIMetaFile",
1349 cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
1350 aRet[1] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast,
1351 "GDIMetaFile",
1352 cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
1354 return aRet;
1356 sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
1358 return ( aFlavor.MimeType == lcl_aGDIMetaFileMIMEType ||
1359 aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast );
1362 // ____ XUnoTunnel ___
1363 ::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier )
1365 if( aIdentifier.getLength() == 16 && memcmp( ExplicitValueProvider::getUnoTunnelId().getConstArray(),
1366 aIdentifier.getConstArray(), 16 ) == 0 )
1368 ExplicitValueProvider* pProvider = this;
1369 return reinterpret_cast<sal_Int64>(pProvider);
1371 return 0;
1374 // lang::XServiceInfo
1376 OUString SAL_CALL ChartView::getImplementationName()
1378 return OUString(CHART_VIEW_SERVICE_IMPLEMENTATION_NAME);
1381 sal_Bool SAL_CALL ChartView::supportsService( const OUString& rServiceName )
1383 return cppu::supportsService(this, rServiceName);
1386 css::uno::Sequence< OUString > SAL_CALL ChartView::getSupportedServiceNames()
1388 return { CHART_VIEW_SERVICE_NAME };
1391 ::basegfx::B3DHomMatrix createTransformationSceneToScreen(
1392 const ::basegfx::B2IRectangle& rDiagramRectangleWithoutAxes )
1394 ::basegfx::B3DHomMatrix aM;
1395 aM.scale(double(rDiagramRectangleWithoutAxes.getWidth())/FIXED_SIZE_FOR_3D_CHART_VOLUME
1396 , -double(rDiagramRectangleWithoutAxes.getHeight())/FIXED_SIZE_FOR_3D_CHART_VOLUME, 1.0 );
1397 aM.translate(double(rDiagramRectangleWithoutAxes.getMinX())
1398 , double(rDiagramRectangleWithoutAxes.getMinY()+rDiagramRectangleWithoutAxes.getHeight()-1), 0);
1399 return aM;
1402 namespace
1405 bool lcl_IsPieOrDonut( const uno::Reference< XDiagram >& xDiagram )
1407 //special treatment for pie charts
1408 //the size is checked after complete creation to get the datalabels into the given space
1410 //todo: this is just a workaround at the moment for pie and donut labels
1411 return DiagramHelper::isPieOrDonutChart( xDiagram );
1414 void lcl_setDefaultWritingMode( const std::shared_ptr< DrawModelWrapper >& pDrawModelWrapper, ChartModel& rModel)
1416 //get writing mode from parent document:
1417 if( SvtLanguageOptions().IsCTLFontEnabled() )
1421 sal_Int16 nWritingMode=-1;
1422 uno::Reference< beans::XPropertySet > xParentProps( rModel.getParent(), uno::UNO_QUERY );
1423 uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSupplier( xParentProps, uno::UNO_QUERY );
1424 if( xStyleFamiliesSupplier.is() )
1426 uno::Reference< container::XNameAccess > xStylesFamilies( xStyleFamiliesSupplier->getStyleFamilies() );
1427 if( xStylesFamilies.is() )
1429 if( !xStylesFamilies->hasByName( "PageStyles" ) )
1431 //draw/impress is parent document
1432 uno::Reference< lang::XMultiServiceFactory > xFatcory( xParentProps, uno::UNO_QUERY );
1433 if( xFatcory.is() )
1435 uno::Reference< beans::XPropertySet > xDrawDefaults( xFatcory->createInstance( "com.sun.star.drawing.Defaults" ), uno::UNO_QUERY );
1436 if( xDrawDefaults.is() )
1437 xDrawDefaults->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1440 else
1442 uno::Reference< container::XNameAccess > xPageStyles( xStylesFamilies->getByName( "PageStyles" ), uno::UNO_QUERY );
1443 if( xPageStyles.is() )
1445 OUString aPageStyle;
1447 uno::Reference< text::XTextDocument > xTextDocument( xParentProps, uno::UNO_QUERY );
1448 if( xTextDocument.is() )
1450 //writer is parent document
1451 //retrieve the current page style from the text cursor property PageStyleName
1453 uno::Reference< text::XTextEmbeddedObjectsSupplier > xTextEmbeddedObjectsSupplier( xTextDocument, uno::UNO_QUERY );
1454 if( xTextEmbeddedObjectsSupplier.is() )
1456 uno::Reference< container::XNameAccess > xEmbeddedObjects( xTextEmbeddedObjectsSupplier->getEmbeddedObjects() );
1457 if( xEmbeddedObjects.is() )
1459 uno::Sequence< OUString > aNames( xEmbeddedObjects->getElementNames() );
1461 sal_Int32 nCount = aNames.getLength();
1462 for( sal_Int32 nN=0; nN<nCount; nN++ )
1464 uno::Reference< beans::XPropertySet > xEmbeddedProps( xEmbeddedObjects->getByName( aNames[nN] ), uno::UNO_QUERY );
1465 if( xEmbeddedProps.is() )
1467 static OUString aChartCLSID = SvGlobalName( SO3_SCH_CLASSID ).GetHexName();
1468 OUString aCLSID;
1469 xEmbeddedProps->getPropertyValue( "CLSID" ) >>= aCLSID;
1470 if( aCLSID == aChartCLSID )
1472 uno::Reference< text::XTextContent > xEmbeddedObject( xEmbeddedProps, uno::UNO_QUERY );
1473 if( xEmbeddedObject.is() )
1475 uno::Reference< text::XTextRange > xAnchor( xEmbeddedObject->getAnchor() );
1476 if( xAnchor.is() )
1478 uno::Reference< beans::XPropertySet > xAnchorProps( xAnchor, uno::UNO_QUERY );
1479 if( xAnchorProps.is() )
1481 xAnchorProps->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1483 uno::Reference< text::XText > xText( xAnchor->getText() );
1484 if( xText.is() )
1486 uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY );
1487 if( xTextCursorProps.is() )
1488 xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle;
1492 break;
1498 if( aPageStyle.isEmpty() )
1500 uno::Reference< text::XText > xText( xTextDocument->getText() );
1501 if( xText.is() )
1503 uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY );
1504 if( xTextCursorProps.is() )
1505 xTextCursorProps->getPropertyValue( "PageStyleName" ) >>= aPageStyle;
1509 else
1511 //Calc is parent document
1512 xParentProps->getPropertyValue( "PageStyle" ) >>= aPageStyle;
1513 if(aPageStyle.isEmpty())
1514 aPageStyle = "Default";
1516 if( nWritingMode == -1 || nWritingMode == text::WritingMode2::PAGE )
1518 uno::Reference< beans::XPropertySet > xPageStyle( xPageStyles->getByName( aPageStyle ), uno::UNO_QUERY );
1519 if( xPageStyle.is() )
1520 xPageStyle->getPropertyValue( "WritingMode" ) >>= nWritingMode;
1526 if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE )
1528 if( pDrawModelWrapper.get() )
1529 pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SvxFrameDirectionItem(static_cast<SvxFrameDirection>(nWritingMode), EE_PARA_WRITINGDIR) );
1532 catch( const uno::Exception& )
1534 DBG_UNHANDLED_EXCEPTION("chart2" );
1539 sal_Int16 lcl_getDefaultWritingModeFromPool( const std::shared_ptr<DrawModelWrapper>& pDrawModelWrapper )
1541 sal_Int16 nWritingMode = text::WritingMode2::LR_TB;
1542 if(!pDrawModelWrapper)
1543 return nWritingMode;
1545 const SfxPoolItem* pItem = &(pDrawModelWrapper->GetItemPool().GetDefaultItem( EE_PARA_WRITINGDIR ));
1546 if( pItem )
1547 nWritingMode = static_cast< sal_Int16 >(static_cast< const SvxFrameDirectionItem * >( pItem )->GetValue());
1548 return nWritingMode;
1551 } //end anonymous namespace
1553 awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D& rParam, const awt::Size& rPageSize )
1555 //return the used rectangle
1556 awt::Rectangle aUsedOuterRect(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y, 0, 0);
1558 uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() );
1559 if( !xDiagram.is())
1560 return aUsedOuterRect;
1562 sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
1563 if(!nDimensionCount)
1565 //@todo handle mixed dimension
1566 nDimensionCount = 2;
1569 basegfx::B2IRectangle aAvailableOuterRect = BaseGFXHelper::makeRectangle(rParam.maRemainingSpace);
1571 const std::vector< VCoordinateSystem* >& rVCooSysList( rParam.mpSeriesPlotterContainer->getCooSysList() );
1572 SeriesPlottersType& rSeriesPlotterList = rParam.mpSeriesPlotterContainer->getSeriesPlotterList();
1574 //create VAxis, so they can give necessary information for automatic scaling
1575 uno::Reference<chart2::XChartDocument> const xChartDoc(&mrChartModel);
1576 uno::Reference<util::XNumberFormatsSupplier> const xNumberFormatsSupplier(
1577 mrChartModel.getNumberFormatsSupplier());
1578 size_t nC = 0;
1579 for( nC=0; nC < rVCooSysList.size(); nC++)
1581 VCoordinateSystem* pVCooSys = rVCooSysList[nC];
1582 if(nDimensionCount==3)
1584 uno::Reference<beans::XPropertySet> xSceneProperties( xDiagram, uno::UNO_QUERY );
1585 CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xSceneProperties ) );
1586 CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xSceneProperties ) );
1587 CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xSceneProperties ) );
1588 pVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos );
1591 pVCooSys->createVAxisList(xChartDoc, rPageSize, rParam.maRemainingSpace, rParam.mbUseFixedInnerSize);
1594 // - prepare list of all axis and how they are used
1595 Date aNullDate = NumberFormatterWrapper( xNumberFormatsSupplier ).getNullDate();
1596 rParam.mpSeriesPlotterContainer->initAxisUsageList(aNullDate);
1597 rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel );
1598 rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter();
1599 rParam.mpSeriesPlotterContainer->setNumberFormatsFromAxes();
1601 //create shapes
1603 //aspect ratio
1604 drawing::Direction3D aPreferredAspectRatio =
1605 rParam.mpSeriesPlotterContainer->getPreferredAspectRatio();
1607 uno::Reference< drawing::XShapes > xSeriesTargetInFrontOfAxis(nullptr);
1608 uno::Reference< drawing::XShapes > xSeriesTargetBehindAxis(nullptr);
1609 VDiagram aVDiagram(xDiagram, aPreferredAspectRatio, nDimensionCount);
1610 bool bIsPieOrDonut = lcl_IsPieOrDonut(xDiagram);
1611 {//create diagram
1612 aVDiagram.init(rParam.mxDiagramWithAxesShapes, m_xShapeFactory);
1613 aVDiagram.createShapes(
1614 awt::Point(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y),
1615 awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height));
1617 xSeriesTargetInFrontOfAxis = aVDiagram.getCoordinateRegion();
1618 // It is preferable to use full size than minimum for pie charts
1619 if (!bIsPieOrDonut && !rParam.mbUseFixedInnerSize)
1620 aVDiagram.reduceToMimimumSize();
1623 uno::Reference< drawing::XShapes > xTextTargetShapes =
1624 AbstractShapeFactory::getOrCreateShapeFactory(m_xShapeFactory)->createGroup2D(rParam.mxDiagramWithAxesShapes);
1626 // - create axis and grids for all coordinate systems
1628 //init all coordinate systems
1629 for( nC=0; nC < rVCooSysList.size(); nC++)
1631 VCoordinateSystem* pVCooSys = rVCooSysList[nC];
1632 pVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis,xTextTargetShapes,m_xShapeFactory,xSeriesTargetBehindAxis);
1634 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1635 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1637 pVCooSys->initVAxisInList();
1640 //calculate resulting size respecting axis label layout and fontscaling
1642 uno::Reference< drawing::XShape > xBoundingShape(rParam.mxDiagramWithAxesShapes, uno::UNO_QUERY);
1643 ::basegfx::B2IRectangle aConsumedOuterRect;
1645 //use first coosys only so far; todo: calculate for more than one coosys if we have more in future
1646 //todo: this is just a workaround at the moment for pie and donut labels
1647 if( !bIsPieOrDonut && (!rVCooSysList.empty()) )
1649 VCoordinateSystem* pVCooSys = rVCooSysList[0];
1650 pVCooSys->createMaximumAxesLabels();
1652 aConsumedOuterRect = AbstractShapeFactory::getRectangleOfShape(xBoundingShape);
1653 ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() );
1654 if (!rParam.mbUseFixedInnerSize)
1655 aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect );
1657 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1658 createTransformationSceneToScreen( aNewInnerRect ) ));
1660 //redo autoscaling to get size and text dependent automatic main increment count
1661 rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel );
1662 rParam.mpSeriesPlotterContainer->updateScalesAndIncrementsOnAxes();
1663 rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter();
1665 pVCooSys->createAxesLabels();
1667 bool bLessSpaceConsumedThanExpected = false;
1669 aConsumedOuterRect = AbstractShapeFactory::getRectangleOfShape(xBoundingShape);
1670 if( aConsumedOuterRect.getMinX() > aAvailableOuterRect.getMinX()
1671 || aConsumedOuterRect.getMaxX() < aAvailableOuterRect.getMaxX()
1672 || aConsumedOuterRect.getMinY() > aAvailableOuterRect.getMinY()
1673 || aConsumedOuterRect.getMinY() < aAvailableOuterRect.getMaxY() )
1674 bLessSpaceConsumedThanExpected = true;
1677 if (bLessSpaceConsumedThanExpected && !rParam.mbUseFixedInnerSize)
1679 aVDiagram.adjustInnerSize( aConsumedOuterRect );
1680 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1681 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1683 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
1686 //create axes and grids for the final size
1687 for( nC=0; nC < rVCooSysList.size(); nC++)
1689 VCoordinateSystem* pVCooSys = rVCooSysList[nC];
1691 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1692 createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) ));
1694 pVCooSys->createAxesShapes();
1695 pVCooSys->createGridShapes();
1698 // - create data series for all charttypes
1699 m_bPointsWereSkipped = false;
1700 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1702 VSeriesPlotter* pSeriesPlotter = aPlotter.get();
1703 uno::Reference< drawing::XShapes > xSeriesTarget(nullptr);
1704 if( pSeriesPlotter->WantToPlotInFrontOfAxisLine() )
1705 xSeriesTarget = xSeriesTargetInFrontOfAxis;
1706 else
1708 xSeriesTarget = xSeriesTargetBehindAxis;
1709 OSL_ENSURE( !bIsPieOrDonut, "not implemented yet! - during a complete recreation this shape is destroyed so no series can be created anymore" );
1711 pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,m_xShapeFactory,OUString() );
1712 pSeriesPlotter->setPageReferenceSize( rPageSize );
1713 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter );
1714 if(nDimensionCount==2)
1715 pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() );
1716 //better performance for big data
1718 //calculate resolution for coordinate system
1719 Sequence<sal_Int32> aCoordinateSystemResolution = pVCooSys->getCoordinateSystemResolution( rPageSize, m_aPageResolution );
1720 pSeriesPlotter->setCoordinateSystemResolution( aCoordinateSystemResolution );
1723 pSeriesPlotter->createShapes();
1724 m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped();
1727 //recreate all with corrected sizes if requested
1728 if( bIsPieOrDonut )
1730 m_bPointsWereSkipped = false;
1732 aConsumedOuterRect = ::basegfx::B2IRectangle( AbstractShapeFactory::getRectangleOfShape(xBoundingShape) );
1733 ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() );
1734 if (!rParam.mbUseFixedInnerSize)
1735 aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect );
1737 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1739 aPlotter->releaseShapes();
1742 //clear and recreate
1743 AbstractShapeFactory::removeSubShapes( xSeriesTargetInFrontOfAxis ); //xSeriesTargetBehindAxis is a sub shape of xSeriesTargetInFrontOfAxis and will be removed here
1744 xSeriesTargetBehindAxis.clear();
1745 AbstractShapeFactory::removeSubShapes( xTextTargetShapes );
1747 //set new transformation
1748 for( nC=0; nC < rVCooSysList.size(); nC++)
1750 VCoordinateSystem* pVCooSys = rVCooSysList[nC];
1751 pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix(
1752 createTransformationSceneToScreen( aNewInnerRect ) ));
1755 // - create data series for all charttypes
1756 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1758 VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, aPlotter.get() );
1759 if(nDimensionCount==2)
1760 aPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() );
1761 aPlotter->createShapes();
1762 m_bPointsWereSkipped = m_bPointsWereSkipped || aPlotter->PointsWereSkipped();
1765 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1766 aPlotter->rearrangeLabelToAvoidOverlapIfRequested(rPageSize);
1769 if (rParam.mbUseFixedInnerSize)
1771 aUsedOuterRect = awt::Rectangle( aConsumedOuterRect.getMinX(), aConsumedOuterRect.getMinY(), aConsumedOuterRect.getWidth(), aConsumedOuterRect.getHeight() );
1773 else
1774 aUsedOuterRect = rParam.maRemainingSpace;
1776 bool bSnapRectToUsedArea = false;
1777 for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList )
1779 bSnapRectToUsedArea = aPlotter->shouldSnapRectToUsedArea();
1780 if(bSnapRectToUsedArea)
1781 break;
1783 if(bSnapRectToUsedArea)
1785 if (rParam.mbUseFixedInnerSize)
1786 m_aResultingDiagramRectangleExcludingAxes = getRectangleOfObject( "PlotAreaExcludingAxes" );
1787 else
1789 ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle();
1790 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() );
1793 else
1795 if (rParam.mbUseFixedInnerSize)
1796 m_aResultingDiagramRectangleExcludingAxes = rParam.maRemainingSpace;
1797 else
1799 ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle();
1800 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() );
1804 if (rParam.mxMarkHandles.is())
1806 awt::Point aPos(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y);
1807 awt::Size aSize(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height);
1809 bool bPosSizeExcludeAxesProperty = true;
1810 uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY_THROW );
1811 if( xDiaProps.is() )
1812 xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxesProperty;
1813 if (rParam.mbUseFixedInnerSize || bPosSizeExcludeAxesProperty)
1815 aPos = awt::Point( m_aResultingDiagramRectangleExcludingAxes.X, m_aResultingDiagramRectangleExcludingAxes.Y );
1816 aSize = awt::Size( m_aResultingDiagramRectangleExcludingAxes.Width, m_aResultingDiagramRectangleExcludingAxes.Height );
1818 rParam.mxMarkHandles->setPosition(aPos);
1819 rParam.mxMarkHandles->setSize(aSize);
1822 return aUsedOuterRect;
1825 bool ChartView::getExplicitValuesForAxis(
1826 uno::Reference< XAxis > xAxis
1827 , ExplicitScaleData& rExplicitScale
1828 , ExplicitIncrementData& rExplicitIncrement )
1830 impl_updateView();
1832 if(!xAxis.is())
1833 return false;
1835 uno::Reference< XCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstDiagram() ) );
1836 const VCoordinateSystem* pVCooSys = findInCooSysList(m_aVCooSysList,xCooSys);
1837 if(!pVCooSys)
1838 return false;
1840 sal_Int32 nDimensionIndex=-1;
1841 sal_Int32 nAxisIndex=-1;
1842 if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) )
1844 rExplicitScale = pVCooSys->getExplicitScale(nDimensionIndex,nAxisIndex);
1845 rExplicitIncrement = pVCooSys->getExplicitIncrement(nDimensionIndex,nAxisIndex);
1846 if( rExplicitScale.ShiftedCategoryPosition )
1848 //remove 'one' from max
1849 if( rExplicitScale.AxisType == css::chart2::AxisType::DATE )
1851 Date aMaxDate(rExplicitScale.NullDate); aMaxDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Maximum));
1852 //for explicit scales with shifted categories we need one interval more
1853 switch( rExplicitScale.TimeResolution )
1855 case css::chart::TimeUnit::DAY:
1856 --aMaxDate;
1857 break;
1858 case css::chart::TimeUnit::MONTH:
1859 aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1);
1860 break;
1861 case css::chart::TimeUnit::YEAR:
1862 aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1);
1863 break;
1865 rExplicitScale.Maximum = aMaxDate - rExplicitScale.NullDate;
1867 else if( rExplicitScale.AxisType == css::chart2::AxisType::CATEGORY )
1868 rExplicitScale.Maximum -= 1.0;
1869 else if( rExplicitScale.AxisType == css::chart2::AxisType::SERIES )
1870 rExplicitScale.Maximum -= 1.0;
1872 return true;
1874 return false;
1877 SdrPage* ChartView::getSdrPage()
1879 SdrPage* pPage=nullptr;
1880 Reference< lang::XUnoTunnel> xUnoTunnel(m_xDrawPage,uno::UNO_QUERY);
1881 if(xUnoTunnel.is())
1883 SvxDrawPage* pSvxDrawPage = reinterpret_cast<SvxDrawPage*>(xUnoTunnel->getSomething(
1884 SvxDrawPage::getUnoTunnelId() ));
1885 if(pSvxDrawPage)
1887 pPage = pSvxDrawPage->GetSdrPage();
1890 return pPage;
1893 uno::Reference< drawing::XShape > ChartView::getShapeForCID( const OUString& rObjectCID )
1895 SolarMutexGuard aSolarGuard;
1896 SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() );
1897 if( pObj )
1898 return uno::Reference< drawing::XShape >( pObj->getUnoShape(), uno::UNO_QUERY);
1899 return nullptr;
1902 awt::Rectangle ChartView::getDiagramRectangleExcludingAxes()
1904 impl_updateView();
1905 return m_aResultingDiagramRectangleExcludingAxes;
1908 awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool bSnapRect )
1910 impl_updateView();
1912 awt::Rectangle aRet;
1913 uno::Reference< drawing::XShape > xShape( getShapeForCID(rObjectCID) );
1914 if(xShape.is())
1916 //special handling for axis for old api:
1917 //same special handling for diagram
1918 ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) );
1919 if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_DIAGRAM )
1921 SolarMutexGuard aSolarGuard;
1922 SvxShape* pRoot = SvxShape::getImplementation( xShape );
1923 if( pRoot )
1925 SdrObject* pRootSdrObject = pRoot->GetSdrObject();
1926 if( pRootSdrObject )
1928 SdrObjList* pRootList = pRootSdrObject->GetSubList();
1929 if( pRootList )
1931 OUString aShapeName = "MarkHandles";
1932 if( eObjectType == OBJECTTYPE_DIAGRAM )
1933 aShapeName = "PlotAreaIncludingAxes";
1934 SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( aShapeName, pRootList );
1935 if( pShape )
1936 xShape.set( pShape->getUnoShape(), uno::UNO_QUERY);
1942 awt::Size aSize( xShape->getSize() );
1943 awt::Point aPoint( xShape->getPosition() );
1944 aRet = awt::Rectangle( aPoint.X, aPoint.Y, aSize.Width, aSize.Height );
1945 if( bSnapRect )
1947 //for rotated objects the shape size and position differs from the visible rectangle
1948 SvxShape* pShape = SvxShape::getImplementation( xShape );
1949 if( pShape )
1951 SdrObject* pSdrObject = pShape->GetSdrObject();
1952 if( pSdrObject )
1954 tools::Rectangle aSnapRect( pSdrObject->GetSnapRect() );
1955 aRet = awt::Rectangle(aSnapRect.Left(),aSnapRect.Top(),aSnapRect.GetWidth(),aSnapRect.GetHeight());
1960 return aRet;
1963 std::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper()
1965 return m_pDrawModelWrapper;
1968 namespace
1970 inline sal_Int32 lcl_getDiagramTitleSpace()
1972 return 200; //=0,2 cm spacing
1974 bool lcl_getPropertySwapXAndYAxis( const uno::Reference< XDiagram >& xDiagram )
1976 bool bSwapXAndY = false;
1978 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
1979 if( xCooSysContainer.is() )
1981 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
1982 if( aCooSysList.getLength() )
1984 uno::Reference<beans::XPropertySet> xProp(aCooSysList[0], uno::UNO_QUERY );
1985 if( xProp.is()) try
1987 xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY;
1989 catch( const uno::Exception& e )
1991 SAL_WARN("chart2", "Exception caught. " << e );
1995 return bSwapXAndY;
2000 sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForAxis(
2001 const Reference< chart2::XAxis >& xAxis
2002 , const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem
2003 , const Reference<chart2::XChartDocument>& xChartDoc)
2005 return AxisHelper::getExplicitNumberFormatKeyForAxis( xAxis, xCorrespondingCoordinateSystem, xChartDoc
2006 , true /*bSearchForParallelAxisIfNothingIsFound*/ );
2009 sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel(
2010 const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp,
2011 const uno::Reference< XDataSeries >& xSeries,
2012 sal_Int32 nPointIndex /*-1 for whole series*/,
2013 const uno::Reference< XDiagram >& xDiagram
2016 sal_Int32 nFormat=0;
2017 if( !xSeriesOrPointProp.is() )
2018 return nFormat;
2020 bool bLinkToSource = true;
2023 xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource;
2025 catch ( const beans::UnknownPropertyException& ) {}
2027 xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat;
2028 sal_Int32 nOldFormat = nFormat;
2029 if (bLinkToSource)
2031 uno::Reference< chart2::XChartType > xChartType( DataSeriesHelper::getChartTypeOfSeries( xSeries, xDiagram ) );
2033 bool bFormatFound = false;
2034 if( ChartTypeHelper::shouldLabelNumberFormatKeyBeDetectedFromYAxis( xChartType ) )
2036 uno::Reference< beans::XPropertySet > xAttachedAxisProps( DiagramHelper::getAttachedAxis( xSeries, xDiagram ), uno::UNO_QUERY );
2037 if (xAttachedAxisProps.is() && (xAttachedAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat))
2038 bFormatFound = true;
2040 if( !bFormatFound )
2042 Reference< chart2::data::XDataSource > xSeriesSource( xSeries, uno::UNO_QUERY );
2043 OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) );
2045 Reference< data::XLabeledDataSequence > xLabeledSequence(
2046 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, aRole ));
2047 if( xLabeledSequence.is() )
2049 Reference< data::XDataSequence > xValues( xLabeledSequence->getValues() );
2050 if( xValues.is() )
2051 nFormat = xValues->getNumberFormatKeyByIndex( nPointIndex );
2055 if (nFormat >= 0 && nOldFormat != nFormat)
2056 xSeriesOrPointProp->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any(nFormat));
2059 if(nFormat<0)
2060 nFormat=0;
2061 return nFormat;
2064 sal_Int32 ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel(
2065 const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp,
2066 const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
2068 sal_Int32 nFormat=0;
2069 if( !xSeriesOrPointProp.is() )
2070 return nFormat;
2071 if( !(xSeriesOrPointProp->getPropertyValue("PercentageNumberFormat") >>= nFormat) )
2073 nFormat = DiagramHelper::getPercentNumberFormat( xNumberFormatsSupplier );
2075 if(nFormat<0)
2076 nFormat=0;
2077 return nFormat;
2080 awt::Rectangle ExplicitValueProvider::AddSubtractAxisTitleSizes(
2081 ChartModel& rModel
2082 , const Reference< uno::XInterface >& xChartView
2083 , const awt::Rectangle& rPositionAndSize, bool bSubtract )
2085 awt::Rectangle aRet(rPositionAndSize);
2087 //add axis title sizes to the diagram size
2088 uno::Reference< chart2::XTitle > xTitle_Height( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, rModel ) );
2089 uno::Reference< chart2::XTitle > xTitle_Width( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, rModel ) );
2090 uno::Reference< chart2::XTitle > xSecondTitle_Height( TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, rModel ) );
2091 uno::Reference< chart2::XTitle > xSecondTitle_Width( TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, rModel ) );
2092 if( xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() || xSecondTitle_Width.is() )
2094 ExplicitValueProvider* pExplicitValueProvider = ExplicitValueProvider::getExplicitValueProvider(xChartView);
2095 if( pExplicitValueProvider )
2097 //detect whether x axis points into x direction or not
2098 if( lcl_getPropertySwapXAndYAxis( rModel.getFirstDiagram() ) )
2100 std::swap( xTitle_Height, xTitle_Width );
2101 std::swap( xSecondTitle_Height, xSecondTitle_Width );
2104 sal_Int32 nTitleSpaceWidth = 0;
2105 sal_Int32 nTitleSpaceHeight = 0;
2106 sal_Int32 nSecondTitleSpaceWidth = 0;
2107 sal_Int32 nSecondTitleSpaceHeight = 0;
2109 if( xTitle_Height.is() )
2111 OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Height, rModel ) );
2112 nTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height;
2113 if( nTitleSpaceHeight )
2114 nTitleSpaceHeight+=lcl_getDiagramTitleSpace();
2116 if( xTitle_Width.is() )
2118 OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Width, rModel ) );
2119 nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width;
2120 if(nTitleSpaceWidth)
2121 nTitleSpaceWidth+=lcl_getDiagramTitleSpace();
2123 if( xSecondTitle_Height.is() )
2125 OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Height, rModel ) );
2126 nSecondTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height;
2127 if( nSecondTitleSpaceHeight )
2128 nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace();
2130 if( xSecondTitle_Width.is() )
2132 OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Width, rModel ) );
2133 nSecondTitleSpaceWidth += pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width;
2134 if( nSecondTitleSpaceWidth )
2135 nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace();
2137 if( bSubtract )
2139 aRet.X += nTitleSpaceWidth;
2140 aRet.Y += nSecondTitleSpaceHeight;
2141 aRet.Width -= (nTitleSpaceWidth + nSecondTitleSpaceWidth);
2142 aRet.Height -= (nTitleSpaceHeight + nSecondTitleSpaceHeight);
2144 else
2147 aRet.X -= nTitleSpaceWidth;
2148 aRet.Y -= nSecondTitleSpaceHeight;
2149 aRet.Width += nTitleSpaceWidth + nSecondTitleSpaceWidth;
2150 aRet.Height += nTitleSpaceHeight + nSecondTitleSpaceHeight;
2154 return aRet;
2157 namespace {
2159 inline double lcl_getPageLayoutDistancePercentage()
2161 return 0.02;
2164 bool getAvailablePosAndSizeForDiagram(
2165 CreateShapeParam2D& rParam, const awt::Size & rPageSize, const uno::Reference<XDiagram>& xDiagram )
2167 rParam.mbUseFixedInnerSize = false;
2169 //@todo: we need a size dependent on the axis labels
2170 sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage());
2171 sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage());
2172 rParam.maRemainingSpace.X += nXDistance;
2173 rParam.maRemainingSpace.Width -= 2*nXDistance;
2174 rParam.maRemainingSpace.Y += nYDistance;
2175 rParam.maRemainingSpace.Height -= 2*nYDistance;
2177 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
2178 return false;
2180 uno::Reference< beans::XPropertySet > xProp(xDiagram, uno::UNO_QUERY);
2182 bool bPosSizeExcludeAxes = false;
2183 if( xProp.is() )
2184 xProp->getPropertyValue( "PosSizeExcludeAxes" ) >>= bPosSizeExcludeAxes;
2186 //size:
2187 css::chart2::RelativeSize aRelativeSize;
2188 if( xProp.is() && (xProp->getPropertyValue( "RelativeSize" )>>=aRelativeSize) )
2190 rParam.maRemainingSpace.Height = static_cast<sal_Int32>(aRelativeSize.Secondary*rPageSize.Height);
2191 rParam.maRemainingSpace.Width = static_cast<sal_Int32>(aRelativeSize.Primary*rPageSize.Width);
2192 rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes;
2195 //position:
2196 chart2::RelativePosition aRelativePosition;
2197 if( xProp.is() && (xProp->getPropertyValue( "RelativePosition" )>>=aRelativePosition) )
2199 //@todo decide whether x is primary or secondary
2201 //the coordinates re relative to the page
2202 double fX = aRelativePosition.Primary*rPageSize.Width;
2203 double fY = aRelativePosition.Secondary*rPageSize.Height;
2205 awt::Point aPos = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
2206 awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)),
2207 awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height),
2208 aRelativePosition.Anchor);
2210 rParam.maRemainingSpace.X = aPos.X;
2211 rParam.maRemainingSpace.Y = aPos.Y;
2213 rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes;
2216 //ensure that the diagram does not lap out right side or out of bottom
2217 if (rParam.maRemainingSpace.Y + rParam.maRemainingSpace.Height > rPageSize.Height)
2218 rParam.maRemainingSpace.Height = rPageSize.Height - rParam.maRemainingSpace.Y;
2220 if (rParam.maRemainingSpace.X + rParam.maRemainingSpace.Width > rPageSize.Width)
2221 rParam.maRemainingSpace.Width = rPageSize.Width - rParam.maRemainingSpace.X;
2223 return true;
2226 enum TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z };
2228 void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment
2229 , awt::Rectangle const & rDiagramPlusAxesRect, const awt::Size & rPageSize )
2231 if(!pVTitle)
2232 return;
2234 awt::Point aNewPosition(0,0);
2235 awt::Size aTitleSize = pVTitle->getFinalSize();
2236 sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage());
2237 sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage());
2238 switch( eAlignment )
2240 case ALIGN_TOP:
2241 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2
2242 , rDiagramPlusAxesRect.Y - aTitleSize.Height/2 - nYDistance );
2243 break;
2244 case ALIGN_BOTTOM:
2245 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2
2246 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2 + nYDistance );
2247 break;
2248 case ALIGN_LEFT:
2249 aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance
2250 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 );
2251 break;
2252 case ALIGN_RIGHT:
2253 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance
2254 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 );
2255 break;
2256 case ALIGN_Z:
2257 aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance
2258 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 );
2259 break;
2260 default:
2261 break;
2264 sal_Int32 nMaxY = rPageSize.Height - aTitleSize.Height/2;
2265 sal_Int32 nMaxX = rPageSize.Width - aTitleSize.Width/2;
2266 sal_Int32 nMinX = aTitleSize.Width/2;
2267 sal_Int32 nMinY = aTitleSize.Height/2;
2268 if( aNewPosition.Y > nMaxY )
2269 aNewPosition.Y = nMaxY;
2270 if( aNewPosition.X > nMaxX )
2271 aNewPosition.X = nMaxX;
2272 if( aNewPosition.Y < nMinY )
2273 aNewPosition.Y = nMinY;
2274 if( aNewPosition.X < nMinX )
2275 aNewPosition.X = nMinX;
2277 pVTitle->changePosition( aNewPosition );
2280 std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType
2281 , const uno::Reference< drawing::XShapes>& xPageShapes
2282 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2283 , ChartModel& rModel
2284 , awt::Rectangle& rRemainingSpace
2285 , const awt::Size & rPageSize
2286 , TitleAlignment eAlignment
2287 , bool& rbAutoPosition )
2289 std::shared_ptr<VTitle> apVTitle;
2291 // #i109336# Improve auto positioning in chart
2292 double fPercentage = lcl_getPageLayoutDistancePercentage();
2293 sal_Int32 nXDistance = static_cast< sal_Int32 >( rPageSize.Width * fPercentage );
2294 sal_Int32 nYDistance = static_cast< sal_Int32 >( rPageSize.Height * fPercentage );
2295 if ( eType == TitleHelper::MAIN_TITLE )
2297 nYDistance += 135; // 1/100 mm
2299 else if ( eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION )
2301 nYDistance = 420; // 1/100 mm
2303 else if ( eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION )
2305 nXDistance = 450; // 1/100 mm
2308 uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, rModel ) );
2309 OUString aCompleteString = TitleHelper::getCompleteString(xTitle);
2310 if (aCompleteString.isEmpty())
2311 return apVTitle;
2313 //create title
2314 apVTitle.reset(new VTitle(xTitle));
2315 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForObject(xTitle, rModel);
2316 apVTitle->init(xPageShapes, xShapeFactory, aCID);
2317 apVTitle->createShapes(awt::Point(0,0), rPageSize);
2318 awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize();
2319 awt::Size aTitleSize = apVTitle->getFinalSize();
2321 //position
2322 rbAutoPosition = true;
2323 awt::Point aNewPosition(0,0);
2324 chart2::RelativePosition aRelativePosition;
2325 uno::Reference<beans::XPropertySet> xProp(xTitle, uno::UNO_QUERY);
2326 if (xProp.is() && (xProp->getPropertyValue("RelativePosition") >>= aRelativePosition))
2328 rbAutoPosition = false;
2330 //@todo decide whether x is primary or secondary
2331 double fX = aRelativePosition.Primary*rPageSize.Width;
2332 double fY = aRelativePosition.Secondary*rPageSize.Height;
2334 double fAnglePi = apVTitle->getRotationAnglePi();
2335 aNewPosition = RelativePositionHelper::getCenterOfAnchoredObject(
2336 awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY))
2337 , aTitleUnrotatedSize, aRelativePosition.Anchor, fAnglePi );
2339 else //auto position
2341 switch( eAlignment )
2343 case ALIGN_TOP:
2344 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2
2345 , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance );
2346 break;
2347 case ALIGN_BOTTOM:
2348 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2
2349 , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance );
2350 break;
2351 case ALIGN_LEFT:
2352 aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance
2353 , rRemainingSpace.Y + rRemainingSpace.Height/2 );
2354 break;
2355 case ALIGN_RIGHT:
2356 aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance
2357 , rRemainingSpace.Y + rRemainingSpace.Height/2 );
2358 break;
2359 default:
2360 break;
2364 apVTitle->changePosition( aNewPosition );
2366 //remaining space
2367 switch( eAlignment )
2369 case ALIGN_TOP:
2370 // Push the remaining space down from top.
2371 rRemainingSpace.Y += ( aTitleSize.Height + nYDistance );
2372 rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance );
2373 break;
2374 case ALIGN_BOTTOM:
2375 // Push the remaining space up from bottom.
2376 rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance );
2377 break;
2378 case ALIGN_LEFT:
2379 // Push the remaining space to the right from left edge.
2380 rRemainingSpace.X += ( aTitleSize.Width + nXDistance );
2381 rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance );
2382 break;
2383 case ALIGN_RIGHT:
2384 // Push the remaining space to the left from right edge.
2385 rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance );
2386 break;
2387 default:
2388 break;
2391 return apVTitle;
2394 bool lcl_createLegend( const uno::Reference< XLegend > & xLegend
2395 , const uno::Reference< drawing::XShapes>& xPageShapes
2396 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2397 , const uno::Reference< uno::XComponentContext > & xContext
2398 , awt::Rectangle & rRemainingSpace
2399 , const awt::Size & rPageSize
2400 , ChartModel& rModel
2401 , const std::vector< LegendEntryProvider* >& rLegendEntryProviderList
2402 , sal_Int16 nDefaultWritingMode )
2404 if (!VLegend::isVisible(xLegend))
2405 return false;
2407 VLegend aVLegend( xLegend, xContext, rLegendEntryProviderList,
2408 xPageShapes, xShapeFactory, rModel);
2409 aVLegend.setDefaultWritingMode( nDefaultWritingMode );
2410 aVLegend.createShapes( awt::Size( rRemainingSpace.Width, rRemainingSpace.Height ),
2411 rPageSize );
2412 aVLegend.changePosition( rRemainingSpace, rPageSize );
2413 return true;
2416 void lcl_createButtons(const uno::Reference<drawing::XShapes>& xPageShapes,
2417 const uno::Reference<lang::XMultiServiceFactory>& xShapeFactory,
2418 ChartModel& rModel,
2419 awt::Rectangle& rRemainingSpace)
2421 uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY);
2422 if (!xPivotTableDataProvider.is())
2423 return;
2425 uno::Reference<beans::XPropertySet> xModelPage(rModel.getPageBackground());
2427 awt::Size aSize(4000, 700); // size of the button
2429 long x = 0;
2431 if (xPivotTableDataProvider->getPageFields().hasElements())
2433 x = 0;
2435 for (css::chart2::data::PivotTableFieldEntry const & rPageFieldEntry : xPivotTableDataProvider->getPageFields())
2437 std::unique_ptr<VButton> pButton(new VButton);
2438 pButton->init(xPageShapes, xShapeFactory);
2439 awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100, rRemainingSpace.Y + 100);
2440 sal_Int32 nDimensionIndex = rPageFieldEntry.DimensionIndex;
2441 OUString aFieldOutputDescription = xPivotTableDataProvider->getFieldOutputDescription(nDimensionIndex);
2442 pButton->setLabel(rPageFieldEntry.Name + " | " + aFieldOutputDescription);
2443 pButton->setCID("FieldButton.Page." + OUString::number(nDimensionIndex));
2444 pButton->setPosition(aNewPosition);
2445 pButton->setSize(aSize);
2446 if (rPageFieldEntry.HasHiddenMembers)
2447 pButton->setArrowColor(Color(0x0000FF));
2449 pButton->createShapes(xModelPage);
2450 x += aSize.Width + 100;
2452 rRemainingSpace.Y += (aSize.Height + 100 + 100);
2453 rRemainingSpace.Height -= (aSize.Height + 100 + 100);
2456 aSize = awt::Size(3000, 700); // size of the button
2458 if (xPivotTableDataProvider->getRowFields().hasElements())
2460 x = 200;
2461 for (css::chart2::data::PivotTableFieldEntry const & rRowFieldEntry : xPivotTableDataProvider->getRowFields())
2464 std::unique_ptr<VButton> pButton(new VButton);
2465 pButton->init(xPageShapes, xShapeFactory);
2466 awt::Point aNewPosition = awt::Point(rRemainingSpace.X + x + 100,
2467 rRemainingSpace.Y + rRemainingSpace.Height - aSize.Height - 100);
2468 pButton->setLabel(rRowFieldEntry.Name);
2469 pButton->setCID("FieldButton.Row." + OUString::number(rRowFieldEntry.DimensionIndex));
2470 pButton->setPosition(aNewPosition);
2471 pButton->setSize(aSize);
2472 if ( rRowFieldEntry.Name == "Data" )
2474 pButton->setBGColor( Color(0x00F6F6F6) );
2475 pButton->showArrow( false );
2477 else if (rRowFieldEntry.HasHiddenMembers)
2478 pButton->setArrowColor(Color(0x0000FF));
2479 pButton->createShapes(xModelPage);
2480 x += aSize.Width + 100;
2482 rRemainingSpace.Height -= (aSize.Height + 100 + 100);
2486 void formatPage(
2487 ChartModel& rChartModel
2488 , const awt::Size& rPageSize
2489 , const uno::Reference< drawing::XShapes >& xTarget
2490 , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory
2495 uno::Reference< beans::XPropertySet > xModelPage( rChartModel.getPageBackground());
2496 if( ! xModelPage.is())
2497 return;
2499 if( !xShapeFactory.is() )
2500 return;
2502 //format page
2503 tPropertyNameValueMap aNameValueMap;
2504 PropertyMapper::getValueMap( aNameValueMap, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xModelPage );
2506 OUString aCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) );
2507 aNameValueMap.emplace( "Name", uno::Any( aCID ) ); //CID OUString
2509 tNameSequence aNames;
2510 tAnySequence aValues;
2511 PropertyMapper::getMultiPropertyListsFromValueMap( aNames, aValues, aNameValueMap );
2513 AbstractShapeFactory* pShapeFactory = AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory);
2514 pShapeFactory->createRectangle(
2515 xTarget, rPageSize, awt::Point(0, 0), aNames, aValues);
2517 catch( const uno::Exception & )
2519 DBG_UNHANDLED_EXCEPTION("chart2" );
2523 void lcl_removeEmptyGroupShapes( const Reference< drawing::XShapes>& xParent )
2525 if(!xParent.is())
2526 return;
2527 Reference< drawing::XShapeGroup > xParentGroup( xParent, uno::UNO_QUERY );
2528 if( !xParentGroup.is() )
2530 Reference< drawing::XDrawPage > xPage( xParent, uno::UNO_QUERY );
2531 if( !xPage.is() )
2532 return;
2535 //iterate from back!
2536 for( sal_Int32 nN = xParent->getCount(); nN--; )
2538 uno::Any aAny = xParent->getByIndex( nN );
2539 Reference< drawing::XShapes> xShapes(nullptr);
2540 if( aAny >>= xShapes )
2541 lcl_removeEmptyGroupShapes( xShapes );
2542 if( xShapes.is() && xShapes->getCount()==0 )
2544 //remove empty group shape
2545 Reference< drawing::XShapeGroup > xGroup( xShapes, uno::UNO_QUERY );
2546 Reference< drawing::XShape > xShape( xShapes, uno::UNO_QUERY );
2547 if( xGroup.is() )
2548 xParent->remove( xShape );
2555 void ChartView::impl_refreshAddIn()
2557 if( !m_bRefreshAddIn )
2558 return;
2560 uno::Reference< beans::XPropertySet > xProp( static_cast< ::cppu::OWeakObject* >( &mrChartModel ), uno::UNO_QUERY );
2561 if( xProp.is()) try
2563 uno::Reference< util::XRefreshable > xAddIn;
2564 xProp->getPropertyValue( "AddIn" ) >>= xAddIn;
2565 if( xAddIn.is() )
2567 bool bRefreshAddInAllowed = true;
2568 xProp->getPropertyValue( "RefreshAddInAllowed" ) >>= bRefreshAddInAllowed;
2569 if( bRefreshAddInAllowed )
2570 xAddIn->refresh();
2573 catch( const uno::Exception& e )
2575 SAL_WARN("chart2", "Exception caught. " << e );
2580 * Is it a real 3D chart with a true 3D scene or a 3D chart in a 2D scene.
2582 bool ChartView::isReal3DChart()
2584 uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() );
2585 #if HAVE_FEATURE_OPENGL
2586 return ChartHelper::isGL3DDiagram(xDiagram);
2587 #else
2588 return false;
2589 #endif
2592 static const char* envChartDummyFactory = getenv("CHART_DUMMY_FACTORY");
2594 void ChartView::createShapes()
2596 osl::ResettableMutexGuard aTimedGuard(maTimeMutex);
2597 if(mrChartModel.isTimeBased())
2599 maTimeBased.bTimeBased = true;
2602 //make sure add-in is refreshed after creating the shapes
2603 const ::comphelper::ScopeGuard aGuard( [this]() { this->impl_refreshAddIn(); } );
2605 m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle(0,0,0,0);
2606 impl_deleteCoordinateSystems();
2607 if( m_pDrawModelWrapper )
2609 SolarMutexGuard aSolarGuard;
2610 // #i12587# support for shapes in chart
2611 m_pDrawModelWrapper->getSdrModel().EnableUndo( false );
2612 m_pDrawModelWrapper->clearMainDrawPage();
2615 lcl_setDefaultWritingMode( m_pDrawModelWrapper, mrChartModel );
2617 awt::Size aPageSize = mrChartModel.getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
2619 AbstractShapeFactory* pShapeFactory = AbstractShapeFactory::getOrCreateShapeFactory(m_xShapeFactory);
2620 if(!mxRootShape.is())
2621 mxRootShape = pShapeFactory->getOrCreateChartRootShape( m_xDrawPage );
2623 SdrPage* pPage = ChartView::getSdrPage();
2624 if(pPage) //it is necessary to use the implementation here as the uno page does not provide a propertyset
2625 pPage->SetSize(Size(aPageSize.Width,aPageSize.Height));
2626 else
2628 OSL_FAIL("could not set page size correctly");
2630 pShapeFactory->setPageSize(mxRootShape, aPageSize);
2631 pShapeFactory->clearPage(mxRootShape);
2632 #if HAVE_FEATURE_OPENGL
2633 #if HAVE_FEATURE_DESKTOP
2634 if(isReal3DChart())
2636 createShapes3D();
2637 return;
2639 else
2641 m_pGL3DPlotter.reset();
2643 // hide OpenGL window for now in normal charts
2644 OpenGLWindow* pWindow = mrChartModel.getOpenGLWindow();
2645 if(pWindow && !envChartDummyFactory)
2646 pWindow->Show(false);
2648 #endif
2649 #endif
2651 createShapes2D(aPageSize);
2653 // #i12587# support for shapes in chart
2654 if ( m_pDrawModelWrapper )
2656 SolarMutexGuard aSolarGuard;
2657 m_pDrawModelWrapper->getSdrModel().EnableUndo( true );
2660 if(maTimeBased.bTimeBased)
2662 maTimeBased.nFrame++;
2666 void ChartView::render()
2668 #if HAVE_FEATURE_OPENGL
2669 if(!isReal3DChart())
2671 AbstractShapeFactory* pShapeFactory = AbstractShapeFactory::getOrCreateShapeFactory(m_xShapeFactory);
2672 OpenGLWindow* pWindow = mrChartModel.getOpenGLWindow();
2673 if(pWindow)
2674 pWindow->setRenderer(mp2DRenderer.get());
2675 bool bRender = pShapeFactory->preRender(mxRootShape, pWindow);
2676 if(bRender)
2678 pShapeFactory->render(mxRootShape, pWindow != mp2DRenderer->getOpenGLWindow());
2679 pShapeFactory->postRender(pWindow);
2682 #else
2683 (void) this;
2684 #endif
2687 // util::XEventListener (base of XCloseListener)
2688 void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ )
2692 void ChartView::impl_updateView( bool bCheckLockedCtrler )
2694 if( !m_pDrawModelWrapper )
2695 return;
2697 // #i12587# support for shapes in chart
2698 if ( m_bSdrViewIsInEditMode )
2700 return;
2703 if (bCheckLockedCtrler && mrChartModel.hasControllersLocked())
2704 return;
2706 if( m_bViewDirty && !m_bInViewUpdate )
2708 m_bInViewUpdate = true;
2709 //bool bOldRefreshAddIn = m_bRefreshAddIn;
2710 //m_bRefreshAddIn = false;
2713 impl_notifyModeChangeListener("invalid");
2715 //prepare draw model
2717 SolarMutexGuard aSolarGuard;
2718 m_pDrawModelWrapper->lockControllers();
2721 //create chart view
2723 #if HAVE_FEATURE_OPENGL
2724 OpenGLWindow* pWindow = mrChartModel.getOpenGLWindow();
2725 if (pWindow && ChartHelper::isGL3DDiagram(mrChartModel.getFirstDiagram()))
2726 pWindow->Initialize();
2727 #endif
2728 m_bViewDirty = false;
2729 m_bViewUpdatePending = false;
2730 createShapes();
2732 if( m_bViewDirty )
2734 //avoid recursions due to add-in
2735 m_bRefreshAddIn = false;
2736 m_bViewDirty = false;
2737 m_bViewUpdatePending = false;
2738 //delete old chart view
2739 createShapes();
2740 m_bRefreshAddIn = true;
2744 m_bViewDirty = m_bViewUpdatePending;
2745 m_bViewUpdatePending = false;
2746 m_bInViewUpdate = false;
2748 catch( const uno::Exception& )
2750 DBG_UNHANDLED_EXCEPTION("chart2" );
2751 m_bViewDirty = m_bViewUpdatePending;
2752 m_bViewUpdatePending = false;
2753 m_bInViewUpdate = false;
2757 SolarMutexGuard aSolarGuard;
2758 m_pDrawModelWrapper->unlockControllers();
2761 impl_notifyModeChangeListener("valid");
2763 //m_bRefreshAddIn = bOldRefreshAddIn;
2767 // ____ XModifyListener ____
2768 void SAL_CALL ChartView::modified( const lang::EventObject& /* aEvent */ )
2770 m_bViewDirty = true;
2771 if( m_bInViewUpdate )
2772 m_bViewUpdatePending = true;
2774 impl_notifyModeChangeListener("dirty");
2777 //SfxListener
2778 void ChartView::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
2780 //#i77362 change notification for changes on additional shapes are missing
2781 if( m_bInViewUpdate )
2782 return;
2784 // #i12587# support for shapes in chart
2785 if ( m_bSdrViewIsInEditMode )
2787 uno::Reference< view::XSelectionSupplier > xSelectionSupplier( mrChartModel.getCurrentController(), uno::UNO_QUERY );
2788 if ( xSelectionSupplier.is() )
2790 OUString aSelObjCID;
2791 uno::Any aSelObj( xSelectionSupplier->getSelection() );
2792 aSelObj >>= aSelObjCID;
2793 if ( !aSelObjCID.isEmpty() )
2795 return;
2800 const SdrHint* pSdrHint = dynamic_cast< const SdrHint* >(&rHint);
2801 if( !pSdrHint )
2802 return;
2804 bool bShapeChanged = false;
2805 switch( pSdrHint->GetKind() )
2807 case SdrHintKind::ObjectChange:
2808 bShapeChanged = true;
2809 break;
2810 case SdrHintKind::ObjectInserted:
2811 bShapeChanged = true;
2812 break;
2813 case SdrHintKind::ObjectRemoved:
2814 bShapeChanged = true;
2815 break;
2816 case SdrHintKind::ModelCleared:
2817 bShapeChanged = true;
2818 break;
2819 case SdrHintKind::EndEdit:
2820 bShapeChanged = true;
2821 break;
2822 default:
2823 break;
2826 if(bShapeChanged)
2828 //#i76053# do not send view modified notifications for changes on the hidden page which contains e.g. the symbols for the dialogs
2829 if( ChartView::getSdrPage() != pSdrHint->GetPage() )
2830 bShapeChanged=false;
2833 if(!bShapeChanged)
2834 return;
2836 mrChartModel.setModified(true);
2839 void ChartView::impl_notifyModeChangeListener( const OUString& rNewMode )
2843 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer
2844 .getContainer( cppu::UnoType<util::XModeChangeListener>::get());
2845 if( pIC )
2847 util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode );
2848 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
2849 while( aIt.hasMoreElements() )
2851 uno::Reference< util::XModeChangeListener > xListener( aIt.next(), uno::UNO_QUERY );
2852 if( xListener.is() )
2853 xListener->modeChanged( aEvent );
2857 catch( const uno::Exception& )
2859 DBG_UNHANDLED_EXCEPTION("chart2");
2863 // ____ XModeChangeBroadcaster ____
2865 void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener )
2867 m_aListenerContainer.addInterface(
2868 cppu::UnoType<util::XModeChangeListener>::get(), xListener );
2870 void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener )
2872 m_aListenerContainer.removeInterface(
2873 cppu::UnoType<util::XModeChangeListener>::get(), xListener );
2875 void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ )
2879 void SAL_CALL ChartView::removeModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ )
2884 // ____ XUpdatable ____
2885 void SAL_CALL ChartView::update()
2887 impl_updateView();
2889 //#i100778# migrate all imported or old documents to a plot area sizing exclusive axes (in case the save settings allow for this):
2890 //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.
2891 //When a view update is requested (what happens for creating the metafile or displaying
2892 //the chart in edit mode or printing) it is most likely that all necessary information are available - like the underlying spreadsheet data for example.
2893 //Those data are important for the correct axis label sizes which are needed during conversion.
2894 if( DiagramHelper::switchDiagramPositioningToExcludingPositioning( mrChartModel, true, false ) )
2895 impl_updateView();
2898 void SAL_CALL ChartView::updateSoft()
2900 update();
2903 void SAL_CALL ChartView::updateHard()
2905 impl_updateView(false);
2908 // ____ XPropertySet ____
2909 Reference< beans::XPropertySetInfo > SAL_CALL ChartView::getPropertySetInfo()
2911 OSL_FAIL("not implemented");
2912 return nullptr;
2915 void SAL_CALL ChartView::setPropertyValue( const OUString& rPropertyName
2916 , const Any& rValue )
2918 if( rPropertyName == "Resolution" )
2920 awt::Size aNewResolution;
2921 if( ! (rValue >>= aNewResolution) )
2922 throw lang::IllegalArgumentException( "Property 'Resolution' requires value of type awt::Size", nullptr, 0 );
2924 if( m_aPageResolution.Width!=aNewResolution.Width || m_aPageResolution.Height!=aNewResolution.Height )
2926 //set modified only when the new resolution is higher and points were skipped before
2927 bool bSetModified = m_bPointsWereSkipped && (m_aPageResolution.Width<aNewResolution.Width || m_aPageResolution.Height<aNewResolution.Height);
2929 m_aPageResolution = aNewResolution;
2931 if( bSetModified )
2932 this->modified( lang::EventObject( static_cast< uno::XWeak* >( this ) ) );
2935 else if( rPropertyName == "ZoomFactors" )
2937 //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
2938 uno::Sequence< beans::PropertyValue > aZoomFactors;
2939 if( ! (rValue >>= aZoomFactors) )
2940 throw lang::IllegalArgumentException( "Property 'ZoomFactors' requires value of type Sequence< PropertyValue >", nullptr, 0 );
2942 sal_Int32 nFilterArgs = aZoomFactors.getLength();
2943 beans::PropertyValue* pDataValues = aZoomFactors.getArray();
2944 while( nFilterArgs-- )
2946 if ( pDataValues->Name == "ScaleXNumerator" )
2947 pDataValues->Value >>= m_nScaleXNumerator;
2948 else if ( pDataValues->Name == "ScaleXDenominator" )
2949 pDataValues->Value >>= m_nScaleXDenominator;
2950 else if ( pDataValues->Name == "ScaleYNumerator" )
2951 pDataValues->Value >>= m_nScaleYNumerator;
2952 else if ( pDataValues->Name == "ScaleYDenominator" )
2953 pDataValues->Value >>= m_nScaleYDenominator;
2955 pDataValues++;
2958 else if( rPropertyName == "SdrViewIsInEditMode" )
2960 //#i77362 change notification for changes on additional shapes are missing
2961 if( ! (rValue >>= m_bSdrViewIsInEditMode) )
2962 throw lang::IllegalArgumentException( "Property 'SdrViewIsInEditMode' requires value of type sal_Bool", nullptr, 0 );
2964 else
2965 throw beans::UnknownPropertyException( "unknown property was tried to set to chart wizard", nullptr );
2968 Any SAL_CALL ChartView::getPropertyValue( const OUString& rPropertyName )
2970 if( rPropertyName != "Resolution" )
2971 throw beans::UnknownPropertyException( "unknown property was tried to get from chart wizard", nullptr );
2973 return Any(m_aPageResolution);
2976 void SAL_CALL ChartView::addPropertyChangeListener(
2977 const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* xListener */ )
2979 OSL_FAIL("not implemented");
2981 void SAL_CALL ChartView::removePropertyChangeListener(
2982 const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* aListener */ )
2984 OSL_FAIL("not implemented");
2987 void SAL_CALL ChartView::addVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ )
2989 OSL_FAIL("not implemented");
2992 void SAL_CALL ChartView::removeVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ )
2994 OSL_FAIL("not implemented");
2997 // ____ XMultiServiceFactory ____
2999 Reference< uno::XInterface > ChartView::createInstance( const OUString& aServiceSpecifier )
3001 SolarMutexGuard aSolarGuard;
3003 SdrModel* pModel = ( m_pDrawModelWrapper ? &m_pDrawModelWrapper->getSdrModel() : nullptr );
3004 if ( pModel )
3006 if ( aServiceSpecifier == "com.sun.star.drawing.DashTable" )
3008 if ( !m_xDashTable.is() )
3010 m_xDashTable = SvxUnoDashTable_createInstance( pModel );
3012 return m_xDashTable;
3014 else if ( aServiceSpecifier == "com.sun.star.drawing.GradientTable" )
3016 if ( !m_xGradientTable.is() )
3018 m_xGradientTable = SvxUnoGradientTable_createInstance( pModel );
3020 return m_xGradientTable;
3022 else if ( aServiceSpecifier == "com.sun.star.drawing.HatchTable" )
3024 if ( !m_xHatchTable.is() )
3026 m_xHatchTable = SvxUnoHatchTable_createInstance( pModel );
3028 return m_xHatchTable;
3030 else if ( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" )
3032 if ( !m_xBitmapTable.is() )
3034 m_xBitmapTable = SvxUnoBitmapTable_createInstance( pModel );
3036 return m_xBitmapTable;
3038 else if ( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" )
3040 if ( !m_xTransGradientTable.is() )
3042 m_xTransGradientTable = SvxUnoTransGradientTable_createInstance( pModel );
3044 return m_xTransGradientTable;
3046 else if ( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" )
3048 if ( !m_xMarkerTable.is() )
3050 m_xMarkerTable = SvxUnoMarkerTable_createInstance( pModel );
3052 return m_xMarkerTable;
3056 return nullptr;
3059 Reference< uno::XInterface > ChartView::createInstanceWithArguments( const OUString& ServiceSpecifier, const uno::Sequence< uno::Any >& Arguments )
3061 OSL_ENSURE( Arguments.getLength(), "ChartView::createInstanceWithArguments: arguments are ignored" );
3062 return createInstance( ServiceSpecifier );
3065 uno::Sequence< OUString > ChartView::getAvailableServiceNames()
3067 uno::Sequence< OUString > aServiceNames( 6 );
3069 aServiceNames[0] = "com.sun.star.drawing.DashTable";
3070 aServiceNames[1] = "com.sun.star.drawing.GradientTable";
3071 aServiceNames[2] = "com.sun.star.drawing.HatchTable";
3072 aServiceNames[3] = "com.sun.star.drawing.BitmapTable";
3073 aServiceNames[4] = "com.sun.star.drawing.TransparencyGradientTable";
3074 aServiceNames[5] = "com.sun.star.drawing.MarkerTable";
3076 return aServiceNames;
3079 OUString ChartView::dump()
3081 #if HAVE_FEATURE_DESKTOP
3082 // Used for unit tests and in chartcontroller only, no need to drag in this when cross-compiling
3083 // for non-desktop
3084 impl_updateView();
3085 uno::Reference< drawing::XShapes > xShapes( m_xDrawPage, uno::UNO_QUERY_THROW );
3086 sal_Int32 n = xShapes->getCount();
3087 OUStringBuffer aBuffer;
3088 for(sal_Int32 i = 0; i < n; ++i)
3090 uno::Reference< drawing::XShapes > xShape(xShapes->getByIndex(i), uno::UNO_QUERY);
3091 if(xShape.is())
3093 XShapeDumper dumper;
3094 OUString aString = XShapeDumper::dump(mxRootShape);
3095 aBuffer.append(aString);
3097 else
3099 uno::Reference< drawing::XShape > xSingleShape(xShapes->getByIndex(i), uno::UNO_QUERY);
3100 if(!xSingleShape.is())
3101 continue;
3102 XShapeDumper dumper;
3103 OUString aString = XShapeDumper::dump(xSingleShape);
3104 aBuffer.append(aString);
3106 aBuffer.append("\n\n");
3109 return aBuffer.makeStringAndClear();
3110 #else
3111 return OUString();
3112 #endif
3115 void ChartView::setViewDirty()
3117 osl::ResettableMutexGuard aGuard(maTimeMutex);
3118 m_bViewDirty = true;
3121 IMPL_LINK_NOARG(ChartView, UpdateTimeBased, Timer *, void)
3123 setViewDirty();
3124 update();
3127 void ChartView::createShapes2D( const awt::Size& rPageSize )
3129 AbstractShapeFactory* pShapeFactory = AbstractShapeFactory::getOrCreateShapeFactory(m_xShapeFactory);
3131 SolarMutexGuard aSolarGuard;
3133 // todo: it would be nicer to just pass the page m_xDrawPage and format it,
3134 // but the draw page does not support XPropertySet
3135 formatPage( mrChartModel, rPageSize, mxRootShape, m_xShapeFactory );
3137 CreateShapeParam2D aParam;
3138 aParam.maRemainingSpace.X = 0;
3139 aParam.maRemainingSpace.Y = 0;
3140 aParam.maRemainingSpace.Width = rPageSize.Width;
3141 aParam.maRemainingSpace.Height = rPageSize.Height;
3143 //create the group shape for diagram and axes first to have title and legends on top of it
3144 uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() );
3145 OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ) );//todo: other index if more than one diagram is possible
3146 uno::Reference< drawing::XShapes > xDiagramPlusAxesPlusMarkHandlesGroup_Shapes(
3147 pShapeFactory->createGroup2D(mxRootShape,aDiagramCID) );
3149 aParam.mxMarkHandles = pShapeFactory->createInvisibleRectangle(
3150 xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0));
3151 AbstractShapeFactory::setShapeName(aParam.mxMarkHandles, "MarkHandles");
3153 aParam.mxPlotAreaWithAxes = pShapeFactory->createInvisibleRectangle(
3154 xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0, 0));
3155 AbstractShapeFactory::setShapeName(aParam.mxPlotAreaWithAxes, "PlotAreaIncludingAxes");
3157 aParam.mxDiagramWithAxesShapes = pShapeFactory->createGroup2D(xDiagramPlusAxesPlusMarkHandlesGroup_Shapes);
3159 bool bAutoPositionDummy = true;
3161 // create buttons
3162 lcl_createButtons(mxRootShape, m_xShapeFactory, mrChartModel, aParam.maRemainingSpace);
3164 lcl_createTitle(
3165 TitleHelper::MAIN_TITLE, mxRootShape, m_xShapeFactory, mrChartModel,
3166 aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy);
3167 if (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)
3168 return;
3170 lcl_createTitle(
3171 TitleHelper::SUB_TITLE, mxRootShape, m_xShapeFactory, mrChartModel,
3172 aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy );
3173 if (aParam.maRemainingSpace.Width <= 0|| aParam.maRemainingSpace.Height <= 0)
3174 return;
3176 aParam.mpSeriesPlotterContainer.reset(new SeriesPlotterContainer(m_aVCooSysList));
3177 aParam.mpSeriesPlotterContainer->initializeCooSysAndSeriesPlotter( mrChartModel );
3178 if(maTimeBased.bTimeBased && maTimeBased.nFrame != 0)
3180 SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList();
3181 size_t n = rSeriesPlotter.size();
3182 for(size_t i = 0; i < n; ++i)
3184 std::vector<VDataSeries*> aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries();
3185 std::vector< VDataSeries* >& rAllOldDataSeries =
3186 maTimeBased.m_aDataSeriesList[i];
3187 size_t m = std::min(aAllNewDataSeries.size(), rAllOldDataSeries.size());
3188 for(size_t j = 0; j < m; ++j)
3190 aAllNewDataSeries[j]->setOldTimeBased(
3191 rAllOldDataSeries[j], (maTimeBased.nFrame % 60)/60.0);
3196 lcl_createLegend(
3197 LegendHelper::getLegend( mrChartModel ), mxRootShape, m_xShapeFactory, m_xCC,
3198 aParam.maRemainingSpace, rPageSize, mrChartModel, aParam.mpSeriesPlotterContainer->getLegendEntryProviderList(),
3199 lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) );
3200 if (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)
3201 return;
3203 if (!createAxisTitleShapes2D(aParam, rPageSize))
3204 return;
3206 bool bDummy = false;
3207 bool bIsVertical = DiagramHelper::getVertical(xDiagram, bDummy, bDummy);
3209 if (getAvailablePosAndSizeForDiagram(aParam, rPageSize, mrChartModel.getFirstDiagram()))
3211 awt::Rectangle aUsedOuterRect = impl_createDiagramAndContent(aParam, rPageSize);
3213 if (aParam.mxPlotAreaWithAxes.is())
3215 aParam.mxPlotAreaWithAxes->setPosition(awt::Point(aUsedOuterRect.X, aUsedOuterRect.Y));
3216 aParam.mxPlotAreaWithAxes->setSize(awt::Size(aUsedOuterRect.Width, aUsedOuterRect.Height));
3219 //correct axis title position
3220 awt::Rectangle aDiagramPlusAxesRect( aUsedOuterRect );
3221 if (aParam.mbAutoPosTitleX)
3222 changePositionOfAxisTitle(aParam.mpVTitleX.get(), ALIGN_BOTTOM, aDiagramPlusAxesRect, rPageSize);
3223 if (aParam.mbAutoPosTitleY)
3224 changePositionOfAxisTitle(aParam.mpVTitleY.get(), ALIGN_LEFT, aDiagramPlusAxesRect, rPageSize);
3225 if (aParam.mbAutoPosTitleZ)
3226 changePositionOfAxisTitle(aParam.mpVTitleZ.get(), ALIGN_Z, aDiagramPlusAxesRect, rPageSize);
3227 if (aParam.mbAutoPosSecondTitleX)
3228 changePositionOfAxisTitle(aParam.mpVTitleSecondX.get(), bIsVertical? ALIGN_RIGHT : ALIGN_TOP, aDiagramPlusAxesRect, rPageSize);
3229 if (aParam.mbAutoPosSecondTitleY)
3230 changePositionOfAxisTitle(aParam.mpVTitleSecondY.get(), bIsVertical? ALIGN_TOP : ALIGN_RIGHT, aDiagramPlusAxesRect, rPageSize);
3233 //cleanup: remove all empty group shapes to avoid grey border lines:
3234 lcl_removeEmptyGroupShapes( mxRootShape );
3236 render();
3238 if(maTimeBased.bTimeBased && maTimeBased.nFrame % 60 == 0)
3240 // create copy of the data for next frame
3241 SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList();
3242 size_t n = rSeriesPlotter.size();
3243 maTimeBased.m_aDataSeriesList.clear();
3244 maTimeBased.m_aDataSeriesList.resize(n);
3245 for(size_t i = 0; i < n; ++i)
3247 std::vector<VDataSeries*> aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries();
3248 std::vector<VDataSeries*>& rAllOldDataSeries = maTimeBased.m_aDataSeriesList[i];
3249 size_t m = aAllNewDataSeries.size();
3250 for(size_t j = 0; j < m; ++j)
3252 rAllOldDataSeries.push_back( aAllNewDataSeries[j]->
3253 createCopyForTimeBased() );
3257 maTimeBased.maTimer.Stop();
3260 if(maTimeBased.bTimeBased && !maTimeBased.maTimer.IsActive())
3262 maTimeBased.maTimer.SetTimeout(15);
3263 maTimeBased.maTimer.SetInvokeHandler(LINK(this, ChartView, UpdateTimeBased));
3264 maTimeBased.maTimer.Start();
3268 bool ChartView::createAxisTitleShapes2D( CreateShapeParam2D& rParam, const css::awt::Size& rPageSize )
3270 uno::Reference<XDiagram> xDiagram = mrChartModel.getFirstDiagram();
3272 Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
3273 sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram );
3275 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) )
3276 rParam.mpVTitleX = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, mxRootShape, m_xShapeFactory, mrChartModel
3277 , rParam.maRemainingSpace, rPageSize, ALIGN_BOTTOM, rParam.mbAutoPosTitleX );
3278 if (rParam.maRemainingSpace.Width <= 0 ||rParam.maRemainingSpace.Height <= 0)
3279 return false;
3281 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) )
3282 rParam.mpVTitleY = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, mxRootShape, m_xShapeFactory, mrChartModel
3283 , rParam.maRemainingSpace, rPageSize, ALIGN_LEFT, rParam.mbAutoPosTitleY );
3284 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3285 return false;
3287 if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) )
3288 rParam.mpVTitleZ = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3289 , rParam.maRemainingSpace, rPageSize, ALIGN_RIGHT, rParam.mbAutoPosTitleZ );
3290 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3291 return false;
3293 bool bDummy = false;
3294 bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy );
3296 if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) )
3297 rParam.mpVTitleSecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3298 , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_RIGHT : ALIGN_TOP, rParam.mbAutoPosSecondTitleX );
3299 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3300 return false;
3302 if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) )
3303 rParam.mpVTitleSecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, mxRootShape, m_xShapeFactory, mrChartModel
3304 , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_TOP : ALIGN_RIGHT, rParam.mbAutoPosSecondTitleY );
3305 if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)
3306 return false;
3308 return true;
3311 void ChartView::createShapes3D()
3313 #if HAVE_FEATURE_OPENGL
3314 OpenGLWindow* pWindow = mrChartModel.getOpenGLWindow();
3315 if(!pWindow)
3316 return;
3318 if( pWindow->GetSizePixel().Width() == 0 || pWindow->GetSizePixel().Height() == 0 )
3320 awt::Size aPageSize = mrChartModel.getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
3321 Size aSize = pWindow->LogicToPixel(Size(aPageSize.Width, aPageSize.Height), MapMode(MapUnit::Map100thMM));
3322 pWindow->SetSizePixel(aSize);
3324 pWindow->Show();
3325 uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() );
3326 uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
3327 if( !xCooSysContainer.is())
3328 return;
3330 uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
3332 if (aCooSysList.getLength() != 1)
3333 // Supporting multiple coordinates in a truly 3D chart (which implies
3334 // it's a Cartesian coordinate system) is a bit of a challenge, if not
3335 // impossible.
3336 return;
3338 uno::Reference<XCoordinateSystem> xCooSys( aCooSysList[0] );
3340 //iterate through all chart types in the current coordinate system
3341 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
3342 OSL_ASSERT( xChartTypeContainer.is());
3343 if( !xChartTypeContainer.is() )
3344 return;
3346 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
3347 if (aChartTypeList.getLength() != 1)
3348 // Likewise, we can't really support multiple chart types here.
3349 return;
3351 uno::Reference< XChartType > xChartType( aChartTypeList[0] );
3353 if (!m_pGL3DPlotter)
3355 m_pGL3DPlotter.reset(new GL3DBarChart(xChartType, pWindow));
3357 else
3359 GL3DBarChart* pChart = dynamic_cast<GL3DBarChart*>(m_pGL3DPlotter.get());
3360 if (pChart)
3361 pChart->setOpenGLWindow(pWindow);
3364 uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
3365 OSL_ASSERT( xDataSeriesContainer.is());
3366 if( !xDataSeriesContainer.is() )
3367 return;
3369 std::vector<std::unique_ptr<VDataSeries> > aDataSeries;
3370 uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
3371 for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
3373 uno::Reference< XDataSeries > xDataSeries( aSeriesList[nS], uno::UNO_QUERY );
3374 if(!xDataSeries.is())
3375 continue;
3377 aDataSeries.push_back(o3tl::make_unique<VDataSeries>(xDataSeries));
3380 std::unique_ptr<ExplicitCategoriesProvider> pCatProvider(new ExplicitCategoriesProvider(xCooSys, mrChartModel));
3382 m_pGL3DPlotter->create3DShapes(aDataSeries, *pCatProvider);
3384 m_pGL3DPlotter->render();
3385 #endif
3388 #if HAVE_FEATURE_OPENGL
3390 void ChartView::updateOpenGLWindow()
3392 if(!isReal3DChart())
3393 mp2DRenderer->updateOpenGLWindow();
3396 #endif
3398 } //namespace chart
3400 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
3401 com_sun_star_comp_chart2_ChartView_get_implementation(css::uno::XComponentContext *context,
3402 css::uno::Sequence<css::uno::Any> const &)
3404 ::chart::ChartModel *pChartModel = new ::chart::ChartModel(context);
3405 return cppu::acquire(new ::chart::ChartView(context, *pChartModel));
3408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */