diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2022-04-18 20:08:57 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2022-04-18 15:57:51 +0200 |
commit | dc8cbdae0a96708872cbfb6bd6e21deec2ce9a0b (patch) | |
tree | a9e87d9d1f2fe60549e3ecdb300810a1a5b4544f | |
parent | 45cdc2e83ff4a6464de4618c22dc2a402442d524 (diff) |
chart2: extract SeriesPlotterContainer into its own file
Change-Id: If190f0d99d5686e90fa56487744a9a663b345fad
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133121
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r-- | chart2/Library_chartcore.mk | 1 | ||||
-rw-r--r-- | chart2/source/view/main/ChartView.cxx | 757 | ||||
-rw-r--r-- | chart2/source/view/main/SeriesPlotterContainer.cxx | 737 | ||||
-rw-r--r-- | chart2/source/view/main/SeriesPlotterContainer.hxx | 158 |
4 files changed, 902 insertions, 751 deletions
diff --git a/chart2/Library_chartcore.mk b/chart2/Library_chartcore.mk index a9a23159b436..cf118a094b36 100644 --- a/chart2/Library_chartcore.mk +++ b/chart2/Library_chartcore.mk @@ -104,6 +104,7 @@ $(eval $(call gb_Library_add_exception_objects,chartcore,\ chart2/source/view/main/PlottingPositionHelper \ chart2/source/view/main/PolarLabelPositionHelper \ chart2/source/view/main/PropertyMapper \ + chart2/source/view/main/SeriesPlotterContainer \ chart2/source/view/main/ShapeFactory \ chart2/source/view/main/Stripe \ chart2/source/view/main/VDataSeries \ diff --git a/chart2/source/view/main/ChartView.cxx b/chart2/source/view/main/ChartView.cxx index 0a93015ad19e..958423b9f10f 100644 --- a/chart2/source/view/main/ChartView.cxx +++ b/chart2/source/view/main/ChartView.cxx @@ -19,6 +19,8 @@ #include <config_feature_desktop.h> +#include "SeriesPlotterContainer.hxx" + #include <ChartView.hxx> #include <chartview/DrawModelWrapper.hxx> #include <Diagram.hxx> @@ -111,6 +113,7 @@ #include <memory> #include <libxml/xmlwriter.h> + namespace com::sun::star::chart2 { class XChartDocument; } namespace chart { @@ -121,754 +124,6 @@ using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Any; -namespace { - -typedef std::vector<std::unique_ptr<VSeriesPlotter> > SeriesPlottersType; - -/** This class is a container of `SeriesPlotter` objects (such as `PieChart` - * instances). It is used for initializing coordinate systems, axes and scales - * of all series plotters which belongs to the container. - */ -class SeriesPlotterContainer -{ -public: - explicit SeriesPlotterContainer( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList ); - ~SeriesPlotterContainer(); - - /** It is used to set coordinate systems (`m_rVCooSysList`), this method - * is invoked by `ChartView::createShapes2D` before of - * `ChartView::impl_createDiagramAndContent`. - * Coordinate systems are retrieved through the `XCoordinateSystemContainer` - * interface implemented by a diagram object which is provided by the - * `ChartModel` object passed to the method (`rChartModel.getFirstDiagram()`). - * - * It is used for creating series plotters and appending them - * to `m_aSeriesPlotterList`. The created series plotters are initialized - * through data (number formats supplier, color scheme, data series), - * extracted from the chart model or the diagram objects. An exception is - * the explicit category provider that is retrieved through the - * `VCoordinateSystem` object used by the series plotter. - * - * It sets the minimum-maximum supplier for a coordinate system: - * this supplier is the series plotter itself which utilizes the given - * coordinate system. In fact `VSeriesPlotter` has `MinimumMaximumSupplier` - * as one of its base classes. - * Hence, for instance, a `PieChart`, which is a series plotter, is - * a `MinimumMaximumSupplier`, too. - */ - void initializeCooSysAndSeriesPlotter( ChartModel& rModel ); - - /** This method is invoked by `ChartView::impl_createDiagramAndContent`. - * It iterates on every axis of every coordinate systems, and if the axis - * is not yet present in `m_aAxisUsageList` it creates a new `AxisUsage` - * object and initialize its `aAutoScaling` member to the `ScaleData` - * object of the current axis. - */ - void initAxisUsageList(const Date& rNullDate); - - /** - * Perform automatic axis scaling and determine the amount and spacing of - * increments. It assumes that the caller has determined the size of the - * largest axis label text object prior to calling this method. - * - * The new axis scaling data will be stored in the VCoordinateSystem - * objects. The label alignment direction for each axis will also get - * determined during this process, and stored in VAxis. - * - * This method is invoked by `ChartView::impl_createDiagramAndContent` - * soon after `initAxisUsageList`. - * It initializes explicit scale and increment objects for all coordinate - * systems in `m_rVCooSysList`. - * This action is achieved by iterating on the `m_aAxisUsageList` container, - * and performing 3 steps: - * 1- call `VCoordinateSystem::prepareAutomaticAxisScaling` for setting - * scaling parameters of the `aAutoScaling` member (a `ScaleAutomatism` - * object) for the current `AxisUsage` instance - * (see `VCoordinateSystem::prepareAutomaticAxisScaling`); - * 2- calculate the explicit scale and increment objects - * (see ScaleAutomatism::calculateExplicitScaleAndIncrement); - * 3- set the explicit scale and increment objects for each coordinate - * system. - */ - void doAutoScaling( ChartModel& rModel ); - - /** - * After auto-scaling is performed, call this method to set the explicit - * scaling and increment data to all relevant VAxis objects. - */ - void updateScalesAndIncrementsOnAxes(); - - /** - * After auto-scaling is performed, call this method to set the explicit - * scaling data to all the plotters. - */ - void setScalesFromCooSysToPlotter(); - - void setNumberFormatsFromAxes(); - drawing::Direction3D getPreferredAspectRatio(); - - SeriesPlottersType& getSeriesPlotterList() { return m_aSeriesPlotterList; } - std::vector< std::unique_ptr<VCoordinateSystem> >& getCooSysList() { return m_rVCooSysList; } - std::vector< LegendEntryProvider* > getLegendEntryProviderList(); - - void AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel ); - - bool isCategoryPositionShifted( - const chart2::ScaleData& rSourceScale, bool bHasComplexCategories ); - -private: - /** A vector of series plotters. - */ - SeriesPlottersType m_aSeriesPlotterList; - - /** A vector of coordinate systems. - */ - std::vector< std::unique_ptr<VCoordinateSystem> >& m_rVCooSysList; - - /** A map whose key is a `XAxis` interface and the related value is - * an object of `AxisUsage` type. - */ - std::map< rtl::Reference< Axis >, AxisUsage > m_aAxisUsageList; - - /** - * Max axis index of all dimensions. Currently this can be either 0 or 1 - * since we only support primary and secondary axes per dimension. The - * value of 0 means all dimensions have only primary axis, while 1 means - * at least one dimension has a secondary axis. - */ - sal_Int32 m_nMaxAxisIndex; - - bool m_bChartTypeUsesShiftedCategoryPositionPerDefault; - sal_Int32 m_nDefaultDateNumberFormat; -}; - -SeriesPlotterContainer::SeriesPlotterContainer( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList ) - : m_rVCooSysList( rVCooSysList ) - , m_nMaxAxisIndex(0) - , m_bChartTypeUsesShiftedCategoryPositionPerDefault(false) - , m_nDefaultDateNumberFormat(0) -{ -} - -SeriesPlotterContainer::~SeriesPlotterContainer() -{ - // - remove plotter from coordinatesystems - for(auto & nC : m_rVCooSysList) - nC->clearMinimumAndMaximumSupplierList(); -} - -std::vector< LegendEntryProvider* > SeriesPlotterContainer::getLegendEntryProviderList() -{ - std::vector< LegendEntryProvider* > aRet( m_aSeriesPlotterList.size() ); - sal_Int32 nN = 0; - for( const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList) - aRet[nN++] = aPlotter.get(); - return aRet; -} - -VCoordinateSystem* findInCooSysList( const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList - , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) -{ - for(auto & pVCooSys : rVCooSysList) - { - if(pVCooSys->getModel()==xCooSys) - return pVCooSys.get(); - } - return nullptr; -} - -VCoordinateSystem* lcl_getCooSysForPlotter( const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList, MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) -{ - if(!pMinimumAndMaximumSupplier) - return nullptr; - for(auto & pVCooSys : rVCooSysList) - { - if(pVCooSys->hasMinimumAndMaximumSupplier( pMinimumAndMaximumSupplier )) - return pVCooSys.get(); - } - return nullptr; -} - -VCoordinateSystem* addCooSysToList( std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList - , const rtl::Reference< BaseCoordinateSystem >& xCooSys - , ChartModel& rChartModel ) -{ - VCoordinateSystem* pExistingVCooSys = findInCooSysList( rVCooSysList, xCooSys ); - if( pExistingVCooSys ) - return pExistingVCooSys; - - std::unique_ptr<VCoordinateSystem> pVCooSys = VCoordinateSystem::createCoordinateSystem(xCooSys ); - if(!pVCooSys) - return nullptr; - - OUString aCooSysParticle( ObjectIdentifier::createParticleForCoordinateSystem( xCooSys, &rChartModel ) ); - pVCooSys->setParticle(aCooSysParticle); - - pVCooSys->setExplicitCategoriesProvider( new ExplicitCategoriesProvider(xCooSys, rChartModel) ); - rVCooSysList.push_back( std::move(pVCooSys) ); - return rVCooSysList.back().get(); -} - -void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter( - ChartModel& rChartModel ) -{ - rtl::Reference< Diagram > xDiagram = rChartModel.getFirstChartDiagram(); - if( !xDiagram.is()) - return; - - uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( &rChartModel ); - if( rChartModel.hasInternalDataProvider() && DiagramHelper::isSupportingDateAxis( xDiagram ) ) - m_nDefaultDateNumberFormat=DiagramHelper::getDateNumberFormat( xNumberFormatsSupplier ); - - sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); - if(!nDimensionCount) - { - //@todo handle mixed dimension - nDimensionCount = 2; - } - - bool bSortByXValues = false; - bool bConnectBars = false; - bool bGroupBarsPerAxis = true; - bool bIncludeHiddenCells = true; - bool bSecondaryYaxisVisible = true; - sal_Int32 nStartingAngle = 90; - sal_Int32 n3DRelativeHeight = 100; - try - { - xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= bSortByXValues; - xDiagram->getPropertyValue( "ConnectBars" ) >>= bConnectBars; - xDiagram->getPropertyValue( "GroupBarsPerAxis" ) >>= bGroupBarsPerAxis; - xDiagram->getPropertyValue( "IncludeHiddenCells" ) >>= bIncludeHiddenCells; - xDiagram->getPropertyValue( "StartingAngle" ) >>= nStartingAngle; - - if (nDimensionCount == 3) - { - xDiagram->getPropertyValue( "3DRelativeHeight" ) >>= n3DRelativeHeight; - } - } - catch( const uno::Exception & ) - { - DBG_UNHANDLED_EXCEPTION("chart2" ); - } - - //prepare for autoscaling and shape creation - // - create plotter for charttypes (for each first scale group at each plotter, as they are independent) - // - add series to plotter (thus each charttype can provide minimum and maximum values for autoscaling) - // - add plotter to coordinate systems - - //iterate through all coordinate systems - uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); - auto & rCooSysList = xDiagram->getBaseCoordinateSystems(); - sal_Int32 nGlobalSeriesIndex = 0;//for automatic symbols - for( sal_Int32 nCS = 0; nCS < static_cast<sal_Int32>(rCooSysList.size()); ++nCS ) - { - rtl::Reference< BaseCoordinateSystem > xCooSys( rCooSysList[nCS] ); - VCoordinateSystem* pVCooSys = addCooSysToList(m_rVCooSysList,xCooSys,rChartModel); - // Let's check whether the secondary Y axis is visible - try - { - if (xCooSys->getMaximumAxisIndexByDimension(1) > 0) - { - rtl::Reference< Axis > xAxisProp = xCooSys->getAxisByDimension2(1, 1); - xAxisProp->getPropertyValue("Show") >>= bSecondaryYaxisVisible; - } - } - catch (const lang::IndexOutOfBoundsException&) - { - TOOLS_WARN_EXCEPTION("chart2", "" ); - } - //iterate through all chart types in the current coordinate system - std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() ); - for( sal_Int32 nT = 0; nT < static_cast<sal_Int32>(aChartTypeList.size()); ++nT ) - { - rtl::Reference< ChartType > xChartType( aChartTypeList[nT] ); - if(nDimensionCount == 3 && xChartType->getChartType().equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE)) - { - try - { - sal_Int32 n3DRelativeHeightOldValue(100); - uno::Any aAny = xChartType->getPropertyValue( "3DRelativeHeight" ); - aAny >>= n3DRelativeHeightOldValue; - if (n3DRelativeHeightOldValue != n3DRelativeHeight) - xChartType->setPropertyValue( "3DRelativeHeight", uno::Any(n3DRelativeHeight) ); - } - catch (const uno::Exception&) { } - } - - if(nT==0) - m_bChartTypeUsesShiftedCategoryPositionPerDefault = ChartTypeHelper::shiftCategoryPosAtXAxisPerDefault( xChartType ); - - bool bExcludingPositioning = DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_EXCLUDING; - VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( xChartType, nDimensionCount, bExcludingPositioning ); - if( !pPlotter ) - continue; - - m_aSeriesPlotterList.push_back( std::unique_ptr<VSeriesPlotter>(pPlotter) ); - pPlotter->setNumberFormatsSupplier( xNumberFormatsSupplier ); - pPlotter->setColorScheme( xColorScheme ); - if(pVCooSys) - pPlotter->setExplicitCategoriesProvider( pVCooSys->getExplicitCategoriesProvider() ); - sal_Int32 nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( xDiagram, xChartType ); - - if(pVCooSys) - pVCooSys->addMinimumAndMaximumSupplier(pPlotter); - - sal_Int32 zSlot=-1; - sal_Int32 xSlot=-1; - sal_Int32 ySlot=-1; - const std::vector< rtl::Reference< DataSeries > > & aSeriesList = xChartType->getDataSeries2(); - for( sal_Int32 nS = 0; nS < static_cast<sal_Int32>(aSeriesList.size()); ++nS ) - { - rtl::Reference<DataSeries> const & xDataSeries = aSeriesList[nS]; - if( !bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries) ) - continue; - - std::unique_ptr<VDataSeries> pSeries(new VDataSeries( xDataSeries )); - - pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex); - nGlobalSeriesIndex++; - - if( bSortByXValues ) - pSeries->doSortByXValues(); - - pSeries->setConnectBars( bConnectBars ); - pSeries->setGroupBarsPerAxis( bGroupBarsPerAxis ); - pSeries->setStartingAngle( nStartingAngle ); - - pSeries->setMissingValueTreatment( nMissingValueTreatment ); - - OUString aSeriesParticle( ObjectIdentifier::createParticleForSeries( 0, nCS, nT, nS ) ); - pSeries->setParticle(aSeriesParticle); - - OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) ); - pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole); - - //ignore secondary axis for charttypes that do not support them - if( pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX && - ( !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ) || - !bSecondaryYaxisVisible ) ) - { - pSeries->setAttachedAxisIndex(MAIN_AXIS_INDEX); - } - - StackingDirection eDirection = pSeries->getStackingDirection(); - switch(eDirection) - { - case StackingDirection_NO_STACKING: - xSlot++; ySlot=-1; - if(zSlot<0) - zSlot=0; - break; - case StackingDirection_Y_STACKING: - ySlot++; - if(xSlot<0) - xSlot=0; - if(zSlot<0) - zSlot=0; - break; - case StackingDirection_Z_STACKING: - zSlot++; xSlot=-1; ySlot=-1; - break; - default: - // UNO enums have one additional auto-generated case - break; - } - pPlotter->addSeries( std::move(pSeries), zSlot, xSlot, ySlot ); - } - } - } - - //transport seriesnames to the coordinatesystems if needed - if( m_aSeriesPlotterList.empty() ) - return; - - uno::Sequence< OUString > aSeriesNames; - bool bSeriesNamesInitialized = false; - for(auto & pVCooSys : m_rVCooSysList) - { - if( pVCooSys->needSeriesNamesForAxis() ) - { - if(!bSeriesNamesInitialized) - { - aSeriesNames = m_aSeriesPlotterList[0]->getSeriesNames(); - bSeriesNamesInitialized = true; - } - pVCooSys->setSeriesNamesForAxis( aSeriesNames ); - } - } -} - -bool SeriesPlotterContainer::isCategoryPositionShifted( - const chart2::ScaleData& rSourceScale, bool bHasComplexCategories ) -{ - if (rSourceScale.AxisType == AxisType::CATEGORY) - return bHasComplexCategories || rSourceScale.ShiftedCategoryPosition || m_bChartTypeUsesShiftedCategoryPositionPerDefault; - - if (rSourceScale.AxisType == AxisType::DATE) - return rSourceScale.ShiftedCategoryPosition; - - return rSourceScale.AxisType == AxisType::SERIES; -} - -void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate) -{ - m_aAxisUsageList.clear(); - - // Loop through coordinate systems in the diagram (though for now - // there should only be one coordinate system per diagram). - for (auto & pVCooSys : m_rVCooSysList) - { - rtl::Reference<BaseCoordinateSystem> xCooSys = pVCooSys->getModel(); - sal_Int32 nDimCount = xCooSys->getDimension(); - bool bComplexCategoryAllowed = ChartTypeHelper::isSupportingComplexCategory(AxisHelper::getChartTypeByIndex(xCooSys, 0)); - - for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex) - { - bool bDateAxisAllowed = ChartTypeHelper::isSupportingDateAxis( - AxisHelper::getChartTypeByIndex(xCooSys, 0), nDimIndex); - - // Each dimension may have primary and secondary axes. - const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex); - for (sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; ++nAxisIndex) - { - rtl::Reference<Axis> xAxis = xCooSys->getAxisByDimension2(nDimIndex, nAxisIndex); - - if (!xAxis.is()) - continue; - - if (m_aAxisUsageList.find(xAxis) == m_aAxisUsageList.end()) - { - // Create axis usage object for this axis. - - chart2::ScaleData aSourceScale = xAxis->getScaleData(); - ExplicitCategoriesProvider* pCatProvider = pVCooSys->getExplicitCategoriesProvider(); - if (nDimIndex == 0) - AxisHelper::checkDateAxis( aSourceScale, pCatProvider, bDateAxisAllowed ); - - bool bHasComplexCat = pCatProvider && pCatProvider->hasComplexCategories() && bComplexCategoryAllowed; - aSourceScale.ShiftedCategoryPosition = isCategoryPositionShifted(aSourceScale, bHasComplexCat); - - m_aAxisUsageList[xAxis].aAutoScaling = ScaleAutomatism(aSourceScale, rNullDate); - } - - AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis]; - rAxisUsage.addCoordinateSystem(pVCooSys.get(), nDimIndex, nAxisIndex); - } - } - } - - // Determine the highest axis index of all dimensions. - m_nMaxAxisIndex = 0; - for (const auto & pVCooSys : m_rVCooSysList) - { - uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel(); - sal_Int32 nDimCount = xCooSys->getDimension(); - - for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex) - { - for (auto & axisUsage : m_aAxisUsageList) - { - sal_Int32 nLocalMax = axisUsage.second.getMaxAxisIndexForDimension(nDimIndex); - if (m_nMaxAxisIndex < nLocalMax) - m_nMaxAxisIndex = nLocalMax; - } - } - } -} - -void SeriesPlotterContainer::setScalesFromCooSysToPlotter() -{ - //set scales to plotter to enable them to provide the preferred scene AspectRatio - for( const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList ) - { - VSeriesPlotter* pSeriesPlotter = aPlotter.get(); - VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter ); - if(pVCooSys) - { - pSeriesPlotter->setScales( pVCooSys->getExplicitScales(0,0), pVCooSys->getPropertySwapXAndYAxis() ); - sal_Int32 nMaxAxisIndex = pVCooSys->getMaximumAxisIndexByDimension(1);//only additional value axis are relevant for series plotter - for( sal_Int32 nI=1; nI<=nMaxAxisIndex; nI++ ) - pSeriesPlotter->addSecondaryValueScale( pVCooSys->getExplicitScale(1,nI), nI ); - } - } -} - -void SeriesPlotterContainer::setNumberFormatsFromAxes() -{ - //set numberformats to plotter to enable them to display the data labels in the numberformat of the axis - for( const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList ) - { - VSeriesPlotter* pSeriesPlotter = aPlotter.get(); - VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter ); - if(pVCooSys) - { - AxesNumberFormats aAxesNumberFormats; - const rtl::Reference< BaseCoordinateSystem >& xCooSys = pVCooSys->getModel(); - sal_Int32 nDimensionCount = xCooSys->getDimension(); - for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nDimensionCount; ++nDimensionIndex) - { - const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); - for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) - { - try - { - rtl::Reference< Axis > xAxisProp = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex ); - if( xAxisProp.is()) - { - sal_Int32 nNumberFormatKey(0); - if( xAxisProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey ) - { - aAxesNumberFormats.setFormat( nNumberFormatKey, nDimensionIndex, nAxisIndex ); - } - else if( nDimensionIndex==0 ) - { - //provide a default date format for date axis with own data - aAxesNumberFormats.setFormat( m_nDefaultDateNumberFormat, nDimensionIndex, nAxisIndex ); - } - } - } - catch( const lang::IndexOutOfBoundsException& ) - { - TOOLS_WARN_EXCEPTION("chart2", "" ); - } - } - } - } - } -} - -void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes() -{ - for(auto & nC : m_rVCooSysList) - nC->updateScalesAndIncrementsOnAxes(); -} - -void SeriesPlotterContainer::doAutoScaling( ChartModel& rChartModel ) -{ - if (m_aSeriesPlotterList.empty() || m_aAxisUsageList.empty()) - // We need these two containers populated to do auto-scaling. Bail out. - return; - - //iterate over the main scales first than secondary axis - for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; ++nAxisIndex) - { - // - first do autoscale for all x and z scales (because they are treated independent) - for (auto & axisUsage : m_aAxisUsageList) - { - AxisUsage& rAxisUsage = axisUsage.second; - - rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 0, nAxisIndex); - rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 2, nAxisIndex); - - ExplicitScaleData aExplicitScale; - ExplicitIncrementData aExplicitIncrement; - rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement ); - - rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement); - rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement); - } - - // - second do autoscale for the dependent y scales (the coordinate systems are prepared with x and z scales already ) - for (auto & axisUsage : m_aAxisUsageList) - { - AxisUsage& rAxisUsage = axisUsage.second; - - rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAxisIndex); - - ExplicitScaleData aExplicitScale; - ExplicitIncrementData aExplicitIncrement; - rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement ); - - rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, aExplicitIncrement); - rAxisUsage.setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScale, aExplicitIncrement); - rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, aExplicitIncrement); - } - } - AdaptScaleOfYAxisWithoutAttachedSeries( rChartModel ); -} - -void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries( ChartModel& rModel ) -{ - //issue #i80518# - for( sal_Int32 nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ ) - { - for (auto & axisUsage : m_aAxisUsageList) - { - AxisUsage& rAxisUsage = axisUsage.second; - std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems( 1, nAxisIndex ); - if( aVCooSysList_Y.empty() ) - continue; - - rtl::Reference< Diagram > xDiagram( rModel.getFirstChartDiagram() ); - if (!xDiagram.is()) - continue; - - bool bSeriesAttachedToThisAxis = false; - sal_Int32 nAttachedAxisIndex = -1; - { - std::vector< rtl::Reference< DataSeries > > aSeriesVector = DiagramHelper::getDataSeriesFromDiagram( xDiagram ); - for (auto const& series : aSeriesVector) - { - sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series); - if( nAxisIndex == nCurrentIndex ) - { - bSeriesAttachedToThisAxis = true; - break; - } - else if( nAttachedAxisIndex<0 || nAttachedAxisIndex>nCurrentIndex ) - nAttachedAxisIndex=nCurrentIndex; - } - } - - if (bSeriesAttachedToThisAxis || nAttachedAxisIndex < 0) - continue; - - for(VCoordinateSystem* nC : aVCooSysList_Y) - { - nC->prepareAutomaticAxisScaling( rAxisUsage.aAutoScaling, 1, nAttachedAxisIndex ); - - ExplicitScaleData aExplicitScaleSource = nC->getExplicitScale( 1,nAttachedAxisIndex ); - ExplicitIncrementData aExplicitIncrementSource = nC->getExplicitIncrement( 1,nAttachedAxisIndex ); - - ExplicitScaleData aExplicitScaleDest = nC->getExplicitScale( 1,nAxisIndex ); - ExplicitIncrementData aExplicitIncrementDest = nC->getExplicitIncrement( 1,nAxisIndex ); - - aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation; - aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling; - aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType; - - aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue; - - ScaleData aScale( rAxisUsage.aAutoScaling.getScale() ); - if( !aScale.Minimum.hasValue() ) - { - bool bNewMinOK = true; - double fMax=0.0; - if( aScale.Maximum >>= fMax ) - bNewMinOK = (aExplicitScaleSource.Minimum <= fMax); - if( bNewMinOK ) - aExplicitScaleDest.Minimum = aExplicitScaleSource.Minimum; - } - else - aExplicitIncrementDest.BaseValue = aExplicitScaleDest.Minimum; - - if( !aScale.Maximum.hasValue() ) - { - bool bNewMaxOK = true; - double fMin=0.0; - if( aScale.Minimum >>= fMin ) - bNewMaxOK = (fMin <= aExplicitScaleSource.Maximum); - if( bNewMaxOK ) - aExplicitScaleDest.Maximum = aExplicitScaleSource.Maximum; - } - if( !aScale.Origin.hasValue() ) - aExplicitScaleDest.Origin = aExplicitScaleSource.Origin; - - if( !aScale.IncrementData.Distance.hasValue() ) - aExplicitIncrementDest.Distance = aExplicitIncrementSource.Distance; - - bool bAutoMinorInterval = true; - if( aScale.IncrementData.SubIncrements.hasElements() ) - bAutoMinorInterval = !( aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() ); - if( bAutoMinorInterval ) - { - if( !aExplicitIncrementDest.SubIncrements.empty() && !aExplicitIncrementSource.SubIncrements.empty() ) - aExplicitIncrementDest.SubIncrements[0].IntervalCount = - aExplicitIncrementSource.SubIncrements[0].IntervalCount; - } - - nC->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScaleDest, aExplicitIncrementDest ); - } - } - } - - if( !AxisHelper::isAxisPositioningEnabled() ) - return; - - //correct origin for y main axis (the origin is where the other main axis crosses) - sal_Int32 nAxisIndex=0; - sal_Int32 nDimensionIndex=1; - for (auto & axisUsage : m_aAxisUsageList) - { - AxisUsage& rAxisUsage = axisUsage.second; - std::vector< VCoordinateSystem* > aVCooSysList = rAxisUsage.getCoordinateSystems(nDimensionIndex,nAxisIndex); - size_t nC; - for( nC=0; nC < aVCooSysList.size(); nC++) - { - ExplicitScaleData aExplicitScale( aVCooSysList[nC]->getExplicitScale( nDimensionIndex, nAxisIndex ) ); - ExplicitIncrementData aExplicitIncrement( aVCooSysList[nC]->getExplicitIncrement( nDimensionIndex, nAxisIndex ) ); - - rtl::Reference< BaseCoordinateSystem > xCooSys( aVCooSysList[nC]->getModel() ); - rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex ); - rtl::Reference< Axis > xCrossingMainAxis = AxisHelper::getCrossingMainAxis( xAxis, xCooSys ); - - if( xCrossingMainAxis.is() ) - { - css::chart::ChartAxisPosition eCrossingMainAxisPos( css::chart::ChartAxisPosition_ZERO ); - xCrossingMainAxis->getPropertyValue("CrossoverPosition") >>= eCrossingMainAxisPos; - if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_VALUE ) - { - double fValue = 0.0; - xCrossingMainAxis->getPropertyValue("CrossoverValue") >>= fValue; - aExplicitScale.Origin = fValue; - } - else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_ZERO ) - aExplicitScale.Origin = 0.0; - else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_START ) - aExplicitScale.Origin = aExplicitScale.Minimum; - else if( eCrossingMainAxisPos == css::chart::ChartAxisPosition_END ) - aExplicitScale.Origin = aExplicitScale.Maximum; - } - - aVCooSysList[nC]->setExplicitScaleAndIncrement( nDimensionIndex, nAxisIndex, aExplicitScale, aExplicitIncrement ); - } - } -} - -drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio() -{ - drawing::Direction3D aPreferredAspectRatio(1.0,1.0,1.0); - - //get a list of all preferred aspect ratios and combine them - //first with special demands wins (less or equal zero <-> arbitrary) - double fx, fy, fz; - fx = fy = fz = -1.0; - for( const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList ) - { - drawing::Direction3D aSingleRatio( aPlotter->getPreferredDiagramAspectRatio() ); - if( fx<0 && aSingleRatio.DirectionX>0 ) - fx = aSingleRatio.DirectionX; - - if( fy<0 && aSingleRatio.DirectionY>0 ) - { - if( fx>0 && aSingleRatio.DirectionX>0 ) - fy = fx*aSingleRatio.DirectionY/aSingleRatio.DirectionX; - else if( fz>0 && aSingleRatio.DirectionZ>0 ) - fy = fz*aSingleRatio.DirectionY/aSingleRatio.DirectionZ; - else - fy = aSingleRatio.DirectionY; - } - - if( fz<0 && aSingleRatio.DirectionZ>0 ) - { - if( fx>0 && aSingleRatio.DirectionX>0 ) - fz = fx*aSingleRatio.DirectionZ/aSingleRatio.DirectionX; - else if( fy>0 && aSingleRatio.DirectionY>0 ) - fz = fy*aSingleRatio.DirectionZ/aSingleRatio.DirectionY; - else - fz = aSingleRatio.DirectionZ; - } - - if( fx>0 && fy>0 && fz>0 ) - break; - } - aPreferredAspectRatio = drawing::Direction3D(fx, fy, fz); - return aPreferredAspectRatio; -} - -} - struct CreateShapeParam2D { css::awt::Rectangle maRemainingSpace; @@ -1424,7 +679,7 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D } pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,OUString() ); pSeriesPlotter->setPageReferenceSize( rPageSize ); - VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); + VCoordinateSystem* pVCooSys = SeriesPlotterContainer::getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); if(nDimensionCount==2) pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); //better performance for big data @@ -1475,7 +730,7 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D // - create data series for all charttypes for( std::unique_ptr<VSeriesPlotter>& aPlotter : rSeriesPlotterList ) { - VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, aPlotter.get() ); + VCoordinateSystem* pVCooSys = SeriesPlotterContainer::getCooSysForPlotter( rVCooSysList, aPlotter.get() ); if(nDimensionCount==2) aPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); // Now we can move data labels in case of pie or donut chart! @@ -1555,7 +810,7 @@ bool ChartView::getExplicitValuesForAxis( return false; rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstChartDiagram() ); - const VCoordinateSystem* pVCooSys = findInCooSysList(m_aVCooSysList,xCooSys); + const VCoordinateSystem* pVCooSys = SeriesPlotterContainer::findInCooSysList(m_aVCooSysList, xCooSys); if(!pVCooSys) return false; diff --git a/chart2/source/view/main/SeriesPlotterContainer.cxx b/chart2/source/view/main/SeriesPlotterContainer.cxx new file mode 100644 index 000000000000..427c9c169b11 --- /dev/null +++ b/chart2/source/view/main/SeriesPlotterContainer.cxx @@ -0,0 +1,737 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "SeriesPlotterContainer.hxx" + +#include <ChartView.hxx> +#include <Diagram.hxx> +#include <ChartType.hxx> +#include <DataSeries.hxx> +#include <ChartModel.hxx> +#include <ChartTypeHelper.hxx> +#include <ObjectIdentifier.hxx> +#include <DiagramHelper.hxx> +#include <Axis.hxx> +#include <AxisIndexDefines.hxx> +#include <DataSeriesHelper.hxx> +#include <ExplicitCategoriesProvider.hxx> +#include <unonames.hxx> + +#include <com/sun/star/chart/ChartAxisPosition.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> + +#include <comphelper/classids.hxx> +#include <servicenames_charttypes.hxx> +#include <tools/diagnose_ex.h> + +namespace chart +{ +using namespace ::css; +using namespace ::css::chart2; + +using ::css::uno::Reference; +using ::css::uno::Sequence; +using ::css::uno::Any; + +SeriesPlotterContainer::SeriesPlotterContainer( + std::vector<std::unique_ptr<VCoordinateSystem>>& rVCooSysList) + : m_rVCooSysList(rVCooSysList) + , m_nMaxAxisIndex(0) + , m_bChartTypeUsesShiftedCategoryPositionPerDefault(false) + , m_nDefaultDateNumberFormat(0) +{ +} + +SeriesPlotterContainer::~SeriesPlotterContainer() +{ + // - remove plotter from coordinatesystems + for (auto& nC : m_rVCooSysList) + nC->clearMinimumAndMaximumSupplierList(); +} + +std::vector<LegendEntryProvider*> SeriesPlotterContainer::getLegendEntryProviderList() +{ + std::vector<LegendEntryProvider*> aRet(m_aSeriesPlotterList.size()); + sal_Int32 nN = 0; + for (const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList) + aRet[nN++] = aPlotter.get(); + return aRet; +} + +VCoordinateSystem* SeriesPlotterContainer::findInCooSysList( + const std::vector<std::unique_ptr<VCoordinateSystem>>& rVCooSysList, + const rtl::Reference<BaseCoordinateSystem>& xCooSys) +{ + for (auto& pVCooSys : rVCooSysList) + { + if (pVCooSys->getModel() == xCooSys) + return pVCooSys.get(); + } + return nullptr; +} + +VCoordinateSystem* SeriesPlotterContainer::getCooSysForPlotter( + const std::vector<std::unique_ptr<VCoordinateSystem>>& rVCooSysList, + MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier) +{ + if (!pMinimumAndMaximumSupplier) + return nullptr; + for (auto& pVCooSys : rVCooSysList) + { + if (pVCooSys->hasMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier)) + return pVCooSys.get(); + } + return nullptr; +} + +VCoordinateSystem* SeriesPlotterContainer::addCooSysToList( + std::vector<std::unique_ptr<VCoordinateSystem>>& rVCooSysList, + const rtl::Reference<BaseCoordinateSystem>& xCooSys, ChartModel& rChartModel) +{ + VCoordinateSystem* pExistingVCooSys + = SeriesPlotterContainer::findInCooSysList(rVCooSysList, xCooSys); + if (pExistingVCooSys) + return pExistingVCooSys; + + std::unique_ptr<VCoordinateSystem> pVCooSys + = VCoordinateSystem::createCoordinateSystem(xCooSys); + if (!pVCooSys) + return nullptr; + + OUString aCooSysParticle( + ObjectIdentifier::createParticleForCoordinateSystem(xCooSys, &rChartModel)); + pVCooSys->setParticle(aCooSysParticle); + + pVCooSys->setExplicitCategoriesProvider(new ExplicitCategoriesProvider(xCooSys, rChartModel)); + rVCooSysList.push_back(std::move(pVCooSys)); + return rVCooSysList.back().get(); +} + +void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter(ChartModel& rChartModel) +{ + rtl::Reference<Diagram> xDiagram = rChartModel.getFirstChartDiagram(); + if (!xDiagram.is()) + return; + + uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(&rChartModel); + if (rChartModel.hasInternalDataProvider() && DiagramHelper::isSupportingDateAxis(xDiagram)) + m_nDefaultDateNumberFormat = DiagramHelper::getDateNumberFormat(xNumberFormatsSupplier); + + sal_Int32 nDimensionCount = DiagramHelper::getDimension(xDiagram); + if (!nDimensionCount) + { + //@todo handle mixed dimension + nDimensionCount = 2; + } + + bool bSortByXValues = false; + bool bConnectBars = false; + bool bGroupBarsPerAxis = true; + bool bIncludeHiddenCells = true; + bool bSecondaryYaxisVisible = true; + sal_Int32 nStartingAngle = 90; + sal_Int32 n3DRelativeHeight = 100; + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= bSortByXValues; + xDiagram->getPropertyValue("ConnectBars") >>= bConnectBars; + xDiagram->getPropertyValue("GroupBarsPerAxis") >>= bGroupBarsPerAxis; + xDiagram->getPropertyValue("IncludeHiddenCells") >>= bIncludeHiddenCells; + xDiagram->getPropertyValue("StartingAngle") >>= nStartingAngle; + + if (nDimensionCount == 3) + { + xDiagram->getPropertyValue("3DRelativeHeight") >>= n3DRelativeHeight; + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + //prepare for autoscaling and shape creation + // - create plotter for charttypes (for each first scale group at each plotter, as they are independent) + // - add series to plotter (thus each charttype can provide minimum and maximum values for autoscaling) + // - add plotter to coordinate systems + + //iterate through all coordinate systems + uno::Reference<XColorScheme> xColorScheme(xDiagram->getDefaultColorScheme()); + auto& rCooSysList = xDiagram->getBaseCoordinateSystems(); + sal_Int32 nGlobalSeriesIndex = 0; //for automatic symbols + for (sal_Int32 nCS = 0; nCS < static_cast<sal_Int32>(rCooSysList.size()); ++nCS) + { + rtl::Reference<BaseCoordinateSystem> xCooSys(rCooSysList[nCS]); + VCoordinateSystem* pVCooSys + = SeriesPlotterContainer::addCooSysToList(m_rVCooSysList, xCooSys, rChartModel); + // Let's check whether the secondary Y axis is visible + try + { + if (xCooSys->getMaximumAxisIndexByDimension(1) > 0) + { + rtl::Reference<Axis> xAxisProp = xCooSys->getAxisByDimension2(1, 1); + xAxisProp->getPropertyValue("Show") >>= bSecondaryYaxisVisible; + } + } + catch (const lang::IndexOutOfBoundsException&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + //iterate through all chart types in the current coordinate system + std::vector<rtl::Reference<ChartType>> aChartTypeList(xCooSys->getChartTypes2()); + for (sal_Int32 nT = 0; nT < static_cast<sal_Int32>(aChartTypeList.size()); ++nT) + { + rtl::Reference<ChartType> xChartType(aChartTypeList[nT]); + if (nDimensionCount == 3 + && xChartType->getChartType().equalsIgnoreAsciiCase( + CHART2_SERVICE_NAME_CHARTTYPE_PIE)) + { + try + { + sal_Int32 n3DRelativeHeightOldValue(100); + uno::Any aAny = xChartType->getPropertyValue("3DRelativeHeight"); + aAny >>= n3DRelativeHeightOldValue; + if (n3DRelativeHeightOldValue != n3DRelativeHeight) + xChartType->setPropertyValue("3DRelativeHeight", + uno::Any(n3DRelativeHeight)); + } + catch (const uno::Exception&) + { + } + } + + if (nT == 0) + m_bChartTypeUsesShiftedCategoryPositionPerDefault + = ChartTypeHelper::shiftCategoryPosAtXAxisPerDefault(xChartType); + + bool bExcludingPositioning = DiagramHelper::getDiagramPositioningMode(xDiagram) + == DiagramPositioningMode_EXCLUDING; + VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( + xChartType, nDimensionCount, bExcludingPositioning); + if (!pPlotter) + continue; + + m_aSeriesPlotterList.push_back(std::unique_ptr<VSeriesPlotter>(pPlotter)); + pPlotter->setNumberFormatsSupplier(xNumberFormatsSupplier); + pPlotter->setColorScheme(xColorScheme); + if (pVCooSys) + pPlotter->setExplicitCategoriesProvider(pVCooSys->getExplicitCategoriesProvider()); + sal_Int32 nMissingValueTreatment + = DiagramHelper::getCorrectedMissingValueTreatment(xDiagram, xChartType); + + if (pVCooSys) + pVCooSys->addMinimumAndMaximumSupplier(pPlotter); + + sal_Int32 zSlot = -1; + sal_Int32 xSlot = -1; + sal_Int32 ySlot = -1; + const std::vector<rtl::Reference<DataSeries>>& aSeriesList + = xChartType->getDataSeries2(); + for (sal_Int32 nS = 0; nS < static_cast<sal_Int32>(aSeriesList.size()); ++nS) + { + rtl::Reference<DataSeries> const& xDataSeries = aSeriesList[nS]; + if (!bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries)) + continue; + + std::unique_ptr<VDataSeries> pSeries(new VDataSeries(xDataSeries)); + + pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex); + nGlobalSeriesIndex++; + + if (bSortByXValues) + pSeries->doSortByXValues(); + + pSeries->setConnectBars(bConnectBars); + pSeries->setGroupBarsPerAxis(bGroupBarsPerAxis); + pSeries->setStartingAngle(nStartingAngle); + + pSeries->setMissingValueTreatment(nMissingValueTreatment); + + OUString aSeriesParticle(ObjectIdentifier::createParticleForSeries(0, nCS, nT, nS)); + pSeries->setParticle(aSeriesParticle); + + OUString aRole(ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( + xChartType)); + pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole); + + //ignore secondary axis for charttypes that do not support them + if (pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX + && (!ChartTypeHelper::isSupportingSecondaryAxis(xChartType, nDimensionCount) + || !bSecondaryYaxisVisible)) + { + pSeries->setAttachedAxisIndex(MAIN_AXIS_INDEX); + } + + StackingDirection eDirection = pSeries->getStackingDirection(); + switch (eDirection) + { + case StackingDirection_NO_STACKING: + xSlot++; + ySlot = -1; + if (zSlot < 0) + zSlot = 0; + break; + case StackingDirection_Y_STACKING: + ySlot++; + if (xSlot < 0) + xSlot = 0; + if (zSlot < 0) + zSlot = 0; + break; + case StackingDirection_Z_STACKING: + zSlot++; + xSlot = -1; + ySlot = -1; + break; + default: + // UNO enums have one additional auto-generated case + break; + } + pPlotter->addSeries(std::move(pSeries), zSlot, xSlot, ySlot); + } + } + } + + //transport seriesnames to the coordinatesystems if needed + if (m_aSeriesPlotterList.empty()) + return; + + uno::Sequence<OUString> aSeriesNames; + bool bSeriesNamesInitialized = false; + for (auto& pVCooSys : m_rVCooSysList) + { + if (pVCooSys->needSeriesNamesForAxis()) + { + if (!bSeriesNamesInitialized) + { + aSeriesNames = m_aSeriesPlotterList[0]->getSeriesNames(); + bSeriesNamesInitialized = true; + } + pVCooSys->setSeriesNamesForAxis(aSeriesNames); + } + } +} + +bool SeriesPlotterContainer::isCategoryPositionShifted(const chart2::ScaleData& rSourceScale, + bool bHasComplexCategories) +{ + if (rSourceScale.AxisType == AxisType::CATEGORY) + return bHasComplexCategories || rSourceScale.ShiftedCategoryPosition + || m_bChartTypeUsesShiftedCategoryPositionPerDefault; + + if (rSourceScale.AxisType == AxisType::DATE) + return rSourceScale.ShiftedCategoryPosition; + + return rSourceScale.AxisType == AxisType::SERIES; +} + +void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate) +{ + m_aAxisUsageList.clear(); + + // Loop through coordinate systems in the diagram (though for now + // there should only be one coordinate system per diagram). + for (auto& pVCooSys : m_rVCooSysList) + { + rtl::Reference<BaseCoordinateSystem> xCooSys = pVCooSys->getModel(); + sal_Int32 nDimCount = xCooSys->getDimension(); + bool bComplexCategoryAllowed = ChartTypeHelper::isSupportingComplexCategory( + AxisHelper::getChartTypeByIndex(xCooSys, 0)); + + for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex) + { + bool bDateAxisAllowed = ChartTypeHelper::isSupportingDateAxis( + AxisHelper::getChartTypeByIndex(xCooSys, 0), nDimIndex); + + // Each dimension may have primary and secondary axes. + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex); + for (sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; ++nAxisIndex) + { + rtl::Reference<Axis> xAxis = xCooSys->getAxisByDimension2(nDimIndex, nAxisIndex); + + if (!xAxis.is()) + continue; + + if (m_aAxisUsageList.find(xAxis) == m_aAxisUsageList.end()) + { + // Create axis usage object for this axis. + + chart2::ScaleData aSourceScale = xAxis->getScaleData(); + ExplicitCategoriesProvider* pCatProvider + = pVCooSys->getExplicitCategoriesProvider(); + if (nDimIndex == 0) + AxisHelper::checkDateAxis(aSourceScale, pCatProvider, bDateAxisAllowed); + + bool bHasComplexCat = pCatProvider && pCatProvider->hasComplexCategories() + && bComplexCategoryAllowed; + aSourceScale.ShiftedCategoryPosition + = isCategoryPositionShifted(aSourceScale, bHasComplexCat); + + m_aAxisUsageList[xAxis].aAutoScaling = ScaleAutomatism(aSourceScale, rNullDate); + } + + AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis]; + rAxisUsage.addCoordinateSystem(pVCooSys.get(), nDimIndex, nAxisIndex); + } + } + } + + // Determine the highest axis index of all dimensions. + m_nMaxAxisIndex = 0; + for (const auto& pVCooSys : m_rVCooSysList) + { + uno::Reference<XCoordinateSystem> xCooSys = pVCooSys->getModel(); + sal_Int32 nDimCount = xCooSys->getDimension(); + + for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex) + { + for (auto& axisUsage : m_aAxisUsageList) + { + sal_Int32 nLocalMax = axisUsage.second.getMaxAxisIndexForDimension(nDimIndex); + if (m_nMaxAxisIndex < nLocalMax) + m_nMaxAxisIndex = nLocalMax; + } + } + } +} + +void SeriesPlotterContainer::setScalesFromCooSysToPlotter() +{ + //set scales to plotter to enable them to provide the preferred scene AspectRatio + for (const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList) + { + VSeriesPlotter* pSeriesPlotter = aPlotter.get(); + VCoordinateSystem* pVCooSys + = SeriesPlotterContainer::getCooSysForPlotter(m_rVCooSysList, pSeriesPlotter); + if (pVCooSys) + { + pSeriesPlotter->setScales(pVCooSys->getExplicitScales(0, 0), + pVCooSys->getPropertySwapXAndYAxis()); + sal_Int32 nMaxAxisIndex = pVCooSys->getMaximumAxisIndexByDimension( + 1); //only additional value axis are relevant for series plotter + for (sal_Int32 nI = 1; nI <= nMaxAxisIndex; nI++) + pSeriesPlotter->addSecondaryValueScale(pVCooSys->getExplicitScale(1, nI), nI); + } + } +} + +void SeriesPlotterContainer::setNumberFormatsFromAxes() +{ + //set numberformats to plotter to enable them to display the data labels in the numberformat of the axis + for (const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList) + { + VSeriesPlotter* pSeriesPlotter = aPlotter.get(); + VCoordinateSystem* pVCooSys + = SeriesPlotterContainer::getCooSysForPlotter(m_rVCooSysList, pSeriesPlotter); + if (pVCooSys) + { + AxesNumberFormats aAxesNumberFormats; + const rtl::Reference<BaseCoordinateSystem>& xCooSys = pVCooSys->getModel(); + sal_Int32 nDimensionCount = xCooSys->getDimension(); + for (sal_Int32 nDimensionIndex = 0; nDimensionIndex < nDimensionCount; + ++nDimensionIndex) + { + const sal_Int32 nMaximumAxisIndex + = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for (sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaximumAxisIndex; ++nAxisIndex) + { + try + { + rtl::Reference<Axis> xAxisProp + = xCooSys->getAxisByDimension2(nDimensionIndex, nAxisIndex); + if (xAxisProp.is()) + { + sal_Int32 nNumberFormatKey(0); + if (xAxisProp->getPropertyValue(CHART_UNONAME_NUMFMT) + >>= nNumberFormatKey) + { + aAxesNumberFormats.setFormat(nNumberFormatKey, nDimensionIndex, + nAxisIndex); + } + else if (nDimensionIndex == 0) + { + //provide a default date format for date axis with own data + aAxesNumberFormats.setFormat(m_nDefaultDateNumberFormat, + nDimensionIndex, nAxisIndex); + } + } + } + catch (const lang::IndexOutOfBoundsException&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + } + } + } +} + +void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes() +{ + for (auto& nC : m_rVCooSysList) + nC->updateScalesAndIncrementsOnAxes(); +} + +void SeriesPlotterContainer::doAutoScaling(ChartModel& rChartModel) +{ + if (m_aSeriesPlotterList.empty() || m_aAxisUsageList.empty()) + // We need these two containers populated to do auto-scaling. Bail out. + return; + + //iterate over the main scales first than secondary axis + for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; ++nAxisIndex) + { + // - first do autoscale for all x and z scales (because they are treated independent) + for (auto& axisUsage : m_aAxisUsageList) + { + AxisUsage& rAxisUsage = axisUsage.second; + + rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 0, nAxisIndex); + rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 2, nAxisIndex); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement(aExplicitScale, + aExplicitIncrement); + + rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, + aExplicitIncrement); + rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, + aExplicitIncrement); + } + + // - second do autoscale for the dependent y scales (the coordinate systems are prepared with x and z scales already ) + for (auto& axisUsage : m_aAxisUsageList) + { + AxisUsage& rAxisUsage = axisUsage.second; + + rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAxisIndex); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement(aExplicitScale, + aExplicitIncrement); + + rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, + aExplicitIncrement); + rAxisUsage.setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScale, + aExplicitIncrement); + rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, + aExplicitIncrement); + } + } + AdaptScaleOfYAxisWithoutAttachedSeries(rChartModel); +} + +void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries(ChartModel& rModel) +{ + //issue #i80518# + for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; nAxisIndex++) + { + for (auto& axisUsage : m_aAxisUsageList) + { + AxisUsage& rAxisUsage = axisUsage.second; + std::vector<VCoordinateSystem*> aVCooSysList_Y + = rAxisUsage.getCoordinateSystems(1, nAxisIndex); + if (aVCooSysList_Y.empty()) + continue; + + rtl::Reference<Diagram> xDiagram(rModel.getFirstChartDiagram()); + if (!xDiagram.is()) + continue; + + bool bSeriesAttachedToThisAxis = false; + sal_Int32 nAttachedAxisIndex = -1; + { + std::vector<rtl::Reference<DataSeries>> aSeriesVector + = DiagramHelper::getDataSeriesFromDiagram(xDiagram); + for (auto const& series : aSeriesVector) + { + sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series); + if (nAxisIndex == nCurrentIndex) + { + bSeriesAttachedToThisAxis = true; + break; + } + else if (nAttachedAxisIndex < 0 || nAttachedAxisIndex > nCurrentIndex) + nAttachedAxisIndex = nCurrentIndex; + } + } + + if (bSeriesAttachedToThisAxis || nAttachedAxisIndex < 0) + continue; + + for (VCoordinateSystem* nC : aVCooSysList_Y) + { + nC->prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAttachedAxisIndex); + + ExplicitScaleData aExplicitScaleSource + = nC->getExplicitScale(1, nAttachedAxisIndex); + ExplicitIncrementData aExplicitIncrementSource + = nC->getExplicitIncrement(1, nAttachedAxisIndex); + + ExplicitScaleData aExplicitScaleDest = nC->getExplicitScale(1, nAxisIndex); + ExplicitIncrementData aExplicitIncrementDest + = nC->getExplicitIncrement(1, nAxisIndex); + + aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation; + aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling; + aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType; + + aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue; + + ScaleData aScale(rAxisUsage.aAutoScaling.getScale()); + if (!aScale.Minimum.hasValue()) + { + bool bNewMinOK = true; + double fMax = 0.0; + if (aScale.Maximum >>= fMax) + bNewMinOK = (aExplicitScaleSource.Minimum <= fMax); + if (bNewMinOK) + aExplicitScaleDest.Minimum = aExplicitScaleSource.Minimum; + } + else + aExplicitIncrementDest.BaseValue = aExplicitScaleDest.Minimum; + + if (!aScale.Maximum.hasValue()) + { + bool bNewMaxOK = true; + double fMin = 0.0; + if (aScale.Minimum >>= fMin) + bNewMaxOK = (fMin <= aExplicitScaleSource.Maximum); + if (bNewMaxOK) + aExplicitScaleDest.Maximum = aExplicitScaleSource.Maximum; + } + if (!aScale.Origin.hasValue()) + aExplicitScaleDest.Origin = aExplicitScaleSource.Origin; + + if (!aScale.IncrementData.Distance.hasValue()) + aExplicitIncrementDest.Distance = aExplicitIncrementSource.Distance; + + bool bAutoMinorInterval = true; + if (aScale.IncrementData.SubIncrements.hasElements()) + bAutoMinorInterval + = !(aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue()); + if (bAutoMinorInterval) + { + if (!aExplicitIncrementDest.SubIncrements.empty() + && !aExplicitIncrementSource.SubIncrements.empty()) + aExplicitIncrementDest.SubIncrements[0].IntervalCount + = aExplicitIncrementSource.SubIncrements[0].IntervalCount; + } + + nC->setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScaleDest, + aExplicitIncrementDest); + } + } + } + + if (!AxisHelper::isAxisPositioningEnabled()) + return; + + //correct origin for y main axis (the origin is where the other main axis crosses) + sal_Int32 nAxisIndex = 0; + sal_Int32 nDimensionIndex = 1; + for (auto& axisUsage : m_aAxisUsageList) + { + AxisUsage& rAxisUsage = axisUsage.second; + std::vector<VCoordinateSystem*> aVCooSysList + = rAxisUsage.getCoordinateSystems(nDimensionIndex, nAxisIndex); + size_t nC; + for (nC = 0; nC < aVCooSysList.size(); nC++) + { + ExplicitScaleData aExplicitScale( + aVCooSysList[nC]->getExplicitScale(nDimensionIndex, nAxisIndex)); + ExplicitIncrementData aExplicitIncrement( + aVCooSysList[nC]->getExplicitIncrement(nDimensionIndex, nAxisIndex)); + + rtl::Reference<BaseCoordinateSystem> xCooSys(aVCooSysList[nC]->getModel()); + rtl::Reference<Axis> xAxis = xCooSys->getAxisByDimension2(nDimensionIndex, nAxisIndex); + rtl::Reference<Axis> xCrossingMainAxis + = AxisHelper::getCrossingMainAxis(xAxis, xCooSys); + + if (xCrossingMainAxis.is()) + { + css::chart::ChartAxisPosition eCrossingMainAxisPos( + css::chart::ChartAxisPosition_ZERO); + xCrossingMainAxis->getPropertyValue("CrossoverPosition") >>= eCrossingMainAxisPos; + if (eCrossingMainAxisPos == css::chart::ChartAxisPosition_VALUE) + { + double fValue = 0.0; + xCrossingMainAxis->getPropertyValue("CrossoverValue") >>= fValue; + aExplicitScale.Origin = fValue; + } + else if (eCrossingMainAxisPos == css::chart::ChartAxisPosition_ZERO) + aExplicitScale.Origin = 0.0; + else if (eCrossingMainAxisPos == css::chart::ChartAxisPosition_START) + aExplicitScale.Origin = aExplicitScale.Minimum; + else if (eCrossingMainAxisPos == css::chart::ChartAxisPosition_END) + aExplicitScale.Origin = aExplicitScale.Maximum; + } + + aVCooSysList[nC]->setExplicitScaleAndIncrement(nDimensionIndex, nAxisIndex, + aExplicitScale, aExplicitIncrement); + } + } +} + +drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio() +{ + drawing::Direction3D aPreferredAspectRatio(1.0, 1.0, 1.0); + + //get a list of all preferred aspect ratios and combine them + //first with special demands wins (less or equal zero <-> arbitrary) + double fx, fy, fz; + fx = fy = fz = -1.0; + for (const std::unique_ptr<VSeriesPlotter>& aPlotter : m_aSeriesPlotterList) + { + drawing::Direction3D aSingleRatio(aPlotter->getPreferredDiagramAspectRatio()); + if (fx < 0 && aSingleRatio.DirectionX > 0) + fx = aSingleRatio.DirectionX; + + if (fy < 0 && aSingleRatio.DirectionY > 0) + { + if (fx > 0 && aSingleRatio.DirectionX > 0) + fy = fx * aSingleRatio.DirectionY / aSingleRatio.DirectionX; + else if (fz > 0 && aSingleRatio.DirectionZ > 0) + fy = fz * aSingleRatio.DirectionY / aSingleRatio.DirectionZ; + else + fy = aSingleRatio.DirectionY; + } + + if (fz < 0 && aSingleRatio.DirectionZ > 0) + { + if (fx > 0 && aSingleRatio.DirectionX > 0) + fz = fx * aSingleRatio.DirectionZ / aSingleRatio.DirectionX; + else if (fy > 0 && aSingleRatio.DirectionY > 0) + fz = fy * aSingleRatio.DirectionZ / aSingleRatio.DirectionY; + else + fz = aSingleRatio.DirectionZ; + } + + if (fx > 0 && fy > 0 && fz > 0) + break; + } + aPreferredAspectRatio = drawing::Direction3D(fx, fy, fz); + return aPreferredAspectRatio; +} + +} //end chart2 namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/SeriesPlotterContainer.hxx b/chart2/source/view/main/SeriesPlotterContainer.hxx new file mode 100644 index 000000000000..07677f2aca28 --- /dev/null +++ b/chart2/source/view/main/SeriesPlotterContainer.hxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_feature_desktop.h> +#include <VSeriesPlotter.hxx> +#include <BaseCoordinateSystem.hxx> +#include "AxisUsage.hxx" + +namespace chart +{ +typedef std::vector<std::unique_ptr<VSeriesPlotter>> SeriesPlottersType; + +/** This class is a container of `SeriesPlotter` objects (such as `PieChart` + * instances). It is used for initializing coordinate systems, axes and scales + * of all series plotters which belongs to the container. + */ +class SeriesPlotterContainer +{ +public: + explicit SeriesPlotterContainer(std::vector<std::unique_ptr<VCoordinateSystem>>& rVCooSysList); + ~SeriesPlotterContainer(); + + /** It is used to set coordinate systems (`m_rVCooSysList`), this method + * is invoked by `ChartView::createShapes2D` before of + * `ChartView::impl_createDiagramAndContent`. + * Coordinate systems are retrieved through the `XCoordinateSystemContainer` + * interface implemented by a diagram object which is provided by the + * `ChartModel` object passed to the method (`rChartModel.getFirstDiagram()`). + * + * It is used for creating series plotters and appending them + * to `m_aSeriesPlotterList`. The created series plotters are initialized + * through data (number formats supplier, color scheme, data series), + * extracted from the chart model or the diagram objects. An exception is + * the explicit category provider that is retrieved through the + * `VCoordinateSystem` object used by the series plotter. + * + * It sets the minimum-maximum supplier for a coordinate system: + * this supplier is the series plotter itself which utilizes the given + * coordinate system. In fact `VSeriesPlotter` has `MinimumMaximumSupplier` + * as one of its base classes. + * Hence, for instance, a `PieChart`, which is a series plotter, is + * a `MinimumMaximumSupplier`, too. + */ + void initializeCooSysAndSeriesPlotter(ChartModel& rModel); + + /** This method is invoked by `ChartView::impl_createDiagramAndContent`. + * It iterates on every axis of every coordinate systems, and if the axis + * is not yet present in `m_aAxisUsageList` it creates a new `AxisUsage` + * object and initialize its `aAutoScaling` member to the `ScaleData` + * object of the current axis. + */ + void initAxisUsageList(const Date& rNullDate); + + /** + * Perform automatic axis scaling and determine the amount and spacing of + * increments. It assumes that the caller has determined the size of the + * largest axis label text object prior to calling this method. + * + * The new axis scaling data will be stored in the VCoordinateSystem + * objects. The label alignment direction for each axis will also get + * determined during this process, and stored in VAxis. + * + * This method is invoked by `ChartView::impl_createDiagramAndContent` + * soon after `initAxisUsageList`. + * It initializes explicit scale and increment objects for all coordinate + * systems in `m_rVCooSysList`. + * This action is achieved by iterating on the `m_aAxisUsageList` container, + * and performing 3 steps: + * 1- call `VCoordinateSystem::prepareAutomaticAxisScaling` for setting + * scaling parameters of the `aAutoScaling` member (a `ScaleAutomatism` + * object) for the current `AxisUsage` instance + * (see `VCoordinateSystem::prepareAutomaticAxisScaling`); + * 2- calculate the explicit scale and increment objects + * (see ScaleAutomatism::calculateExplicitScaleAndIncrement); + * 3- set the explicit scale and increment objects for each coordinate + * system. + */ + void doAutoScaling(ChartModel& rModel); + + /** + * After auto-scaling is performed, call this method to set the explicit + * scaling and increment data to all relevant VAxis objects. + */ + void updateScalesAndIncrementsOnAxes(); + + /** + * After auto-scaling is performed, call this method to set the explicit + * scaling data to all the plotters. + */ + void setScalesFromCooSysToPlotter(); + + void setNumberFormatsFromAxes(); + css::drawing::Direction3D getPreferredAspectRatio(); + + SeriesPlottersType& getSeriesPlotterList() { return m_aSeriesPlotterList; } + std::vector<std::unique_ptr<VCoordinateSystem>>& getCooSysList() { return m_rVCooSysList; } + std::vector<LegendEntryProvider*> getLegendEntryProviderList(); + + void AdaptScaleOfYAxisWithoutAttachedSeries(ChartModel& rModel); + + bool isCategoryPositionShifted(const css::chart2::ScaleData& rSourceScale, + bool bHasComplexCategories); + + static VCoordinateSystem* + getCooSysForPlotter(const std::vector<std::unique_ptr<VCoordinateSystem>>& rVCooSysList, + MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier); + static VCoordinateSystem* + addCooSysToList(std::vector<std::unique_ptr<VCoordinateSystem>>& rVCooSysList, + const rtl::Reference<BaseCoordinateSystem>& xCooSys, ChartModel& rChartModel); + static VCoordinateSystem* + findInCooSysList(const std::vector<std::unique_ptr<VCoordinateSystem>>& rVCooSysList, + const rtl::Reference<BaseCoordinateSystem>& xCooSys); + +private: + /** A vector of series plotters. + */ + SeriesPlottersType m_aSeriesPlotterList; + + /** A vector of coordinate systems. + */ + std::vector<std::unique_ptr<VCoordinateSystem>>& m_rVCooSysList; + + /** A map whose key is a `XAxis` interface and the related value is + * an object of `AxisUsage` type. + */ + std::map<rtl::Reference<Axis>, AxisUsage> m_aAxisUsageList; + + /** + * Max axis index of all dimensions. Currently this can be either 0 or 1 + * since we only support primary and secondary axes per dimension. The + * value of 0 means all dimensions have only primary axis, while 1 means + * at least one dimension has a secondary axis. + */ + sal_Int32 m_nMaxAxisIndex; + + bool m_bChartTypeUsesShiftedCategoryPositionPerDefault; + sal_Int32 m_nDefaultDateNumberFormat; +}; + +} //end chart2 namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |