diff options
Diffstat (limited to 'chart2/source/view/main/ChartView.cxx')
-rw-r--r-- | chart2/source/view/main/ChartView.cxx | 1380 |
1 files changed, 203 insertions, 1177 deletions
diff --git a/chart2/source/view/main/ChartView.cxx b/chart2/source/view/main/ChartView.cxx index d1ec2a672571..d01a877040b2 100644 --- a/chart2/source/view/main/ChartView.cxx +++ b/chart2/source/view/main/ChartView.cxx @@ -19,9 +19,13 @@ #include <config_feature_desktop.h> +#include "SeriesPlotterContainer.hxx" + #include <ChartView.hxx> #include <chartview/DrawModelWrapper.hxx> #include <Diagram.hxx> +#include <ChartType.hxx> +#include <DataSeries.hxx> #include <NumberFormatterWrapper.hxx> #include <VDiagram.hxx> #include "VTitle.hxx" @@ -32,6 +36,7 @@ #include <VSeriesPlotter.hxx> #include <CommonConverters.hxx> #include <TitleHelper.hxx> +#include <Legend.hxx> #include <LegendHelper.hxx> #include "VLegend.hxx" #include <PropertyMapper.hxx> @@ -42,13 +47,16 @@ #include <DiagramHelper.hxx> #include <RelativePositionHelper.hxx> #include <servicenames.hxx> +#include <Axis.hxx> #include <AxisHelper.hxx> +#include "AxisUsage.hxx" #include <AxisIndexDefines.hxx> #include <BaseGFXHelper.hxx> #include <DataSeriesHelper.hxx> #include <DateHelper.hxx> #include <ExplicitCategoriesProvider.hxx> #include <defines.hxx> +#include <comphelper/dumpxmltostring.hxx> #include <unonames.hxx> #include <editeng/frmdiritem.hxx> #include <editeng/eeitem.hxx> @@ -62,22 +70,20 @@ #include <unotools/streamwrap.hxx> #include <svx/svdpage.hxx> #include <svx/unopage.hxx> +#include <utility> #include <vcl/svapp.hxx> #include <osl/mutex.hxx> #include <svx/unofill.hxx> #include <drawinglayer/XShapeDumper.hxx> +#include <sfx2/objsh.hxx> #include <time.h> -#include <com/sun/star/awt/Size.hpp> #include <com/sun/star/awt/Point.hpp> #include <com/sun/star/chart/ChartAxisPosition.hpp> #include <com/sun/star/chart/TimeUnit.hpp> #include <com/sun/star/chart2/AxisType.hpp> #include <com/sun/star/chart2/StackingDirection.hpp> -#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> -#include <com/sun/star/chart2/XChartTypeContainer.hpp> -#include <com/sun/star/chart2/XDataSeriesContainer.hpp> #include <com/sun/star/chart2/RelativePosition.hpp> #include <com/sun/star/chart2/RelativeSize.hpp> #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> @@ -101,897 +107,19 @@ #include <rtl/ustring.hxx> -#include <tools/diagnose_ex.h> +#include <comphelper/diagnose_ex.hxx> #include <tools/stream.hxx> #include <memory> #include <libxml/xmlwriter.h> -namespace com::sun::star::chart2 { class XChartDocument; } namespace chart { using namespace ::com::sun::star; -using namespace ::com::sun::star::chart2; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Any; -namespace { - -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 -typedef std::map< VCoordinateSystem*, tFullAxisIndex > tCoordinateSystemMap; - -/** This class handles a collection of coordinate systems and is used for - * executing some action on all coordinate systems such as - * `prepareAutomaticAxisScaling` and `setExplicitScaleAndIncrement`. - * Moreover it contains the `aAutoScaling` object that is an instance of - * the `ScaleAutomatism` class. The initialization of `aAutoScaling` is - * performed in the `SeriesPlotterContainer::initAxisUsageList` method and is - * used in the `SeriesPlotterContainer::doAutoScaling` for calculating explicit - * scale and increment objects (see `SeriesPlotterContainer::doAutoScaling`). - */ -struct AxisUsage -{ - AxisUsage(); - ~AxisUsage(); - - void addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); - std::vector< VCoordinateSystem* > getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); - sal_Int32 getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex ); - - void prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ); - void setExplicitScaleAndIncrement( sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc ); - - ScaleAutomatism aAutoScaling; - -private: - tCoordinateSystemMap aCoordinateSystems; - std::map< sal_Int32, sal_Int32 > aMaxIndexPerDimension; -}; - -AxisUsage::AxisUsage() - : aAutoScaling(AxisHelper::createDefaultScale(), Date(Date::SYSTEM)) -{ -} - -AxisUsage::~AxisUsage() -{ - aCoordinateSystems.clear(); -} - -void AxisUsage::addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) -{ - if(!pCooSys) - return; - - tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); - tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) ); - - //use one scale only once for each coordinate system - //main axis are preferred over secondary axis - //value scales are preferred - if(aFound!=aCoordinateSystems.end()) - { - sal_Int32 nFoundAxisIndex = aFound->second.second; - if( nFoundAxisIndex < nAxisIndex ) - return; - sal_Int32 nFoundDimension = aFound->second.first; - if( nFoundDimension ==1 ) - return; - if( nFoundDimension < nDimensionIndex ) - return; - } - aCoordinateSystems[pCooSys] = aFullAxisIndex; - - //set maximum scale index - std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex); - if( aIter != aMaxIndexPerDimension.end() ) - { - sal_Int32 nCurrentMaxIndex = aIter->second; - if( nCurrentMaxIndex < nAxisIndex ) - aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex; - } - else - aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex; -} - -std::vector< VCoordinateSystem* > AxisUsage::getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) -{ - std::vector< VCoordinateSystem* > aRet; - - for (auto const& coordinateSystem : aCoordinateSystems) - { - if( coordinateSystem.second.first != nDimensionIndex ) - continue; - if( coordinateSystem.second.second != nAxisIndex ) - continue; - aRet.push_back( coordinateSystem.first ); - } - - return aRet; -} - -sal_Int32 AxisUsage::getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex ) -{ - sal_Int32 nRet = -1; - std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex); - if( aIter != aMaxIndexPerDimension.end() ) - nRet = aIter->second; - return nRet; -} - -void AxisUsage::prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) -{ - std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex); - for (VCoordinateSystem * i : aVCooSysList) - i->prepareAutomaticAxisScaling(rScaleAutomatism, nDimIndex, nAxisIndex); -} - -void AxisUsage::setExplicitScaleAndIncrement( - sal_Int32 nDimIndex, sal_Int32 nAxisIndex, const ExplicitScaleData& rScale, const ExplicitIncrementData& rInc ) -{ - std::vector<VCoordinateSystem*> aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex); - for (VCoordinateSystem* i : aVCooSysList) - i->setExplicitScaleAndIncrement(nDimIndex, nAxisIndex, rScale, rInc); -} - -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< uno::Reference< XAxis >, 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) - { - Reference< beans::XPropertySet > xAxisProp(xCooSys->getAxisByDimension(1, 1), uno::UNO_QUERY); - xAxisProp->getPropertyValue("Show") >>= bSecondaryYaxisVisible; - } - } - catch (const lang::IndexOutOfBoundsException&) - { - TOOLS_WARN_EXCEPTION("chart2", "" ); - } - //iterate through all chart types in the current coordinate system - uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xCooSys->getChartTypes() ); - for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT ) - { - uno::Reference< XChartType > xChartType( aChartTypeList[nT] ); - if(nDimensionCount == 3 && xChartType->getChartType().equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE)) - { - uno::Reference< beans::XPropertySet > xPropertySet( xChartType, uno::UNO_QUERY ); - if (xPropertySet.is()) - { - try - { - sal_Int32 n3DRelativeHeightOldValue(100); - uno::Any aAny = xPropertySet->getPropertyValue( "3DRelativeHeight" ); - aAny >>= n3DRelativeHeightOldValue; - if (n3DRelativeHeightOldValue != n3DRelativeHeight) - xPropertySet->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); - - uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY ); - OSL_ASSERT( xDataSeriesContainer.is()); - if( !xDataSeriesContainer.is() ) - continue; - - sal_Int32 zSlot=-1; - sal_Int32 xSlot=-1; - sal_Int32 ySlot=-1; - uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() ); - for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS ) - { - uno::Reference< XDataSeries > const & xDataSeries = aSeriesList[nS]; - if(!xDataSeries.is()) - continue; - 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) - { - uno::Reference<XCoordinateSystem> 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) - { - uno::Reference<XAxis> xAxis = xCooSys->getAxisByDimension(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 uno::Reference< XCoordinateSystem >& 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 - { - Reference< beans::XPropertySet > xAxisProp( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY ); - 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; - - uno::Reference< XDiagram > xDiagram( rModel.getFirstDiagram() ); - if (!xDiagram.is()) - continue; - - bool bSeriesAttachedToThisAxis = false; - sal_Int32 nAttachedAxisIndex = -1; - { - std::vector< Reference< XDataSeries > > 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 ) ); - - Reference< chart2::XCoordinateSystem > xCooSys( aVCooSysList[nC]->getModel() ); - Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) ); - Reference< beans::XPropertySet > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ), uno::UNO_QUERY ); - - 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; @@ -1028,18 +156,13 @@ struct CreateShapeParam2D mbUseFixedInnerSize(false) {} }; -const uno::Sequence<sal_Int8>& ExplicitValueProvider::getUnoTunnelId() -{ - static const comphelper::UnoIdInit theExplicitValueProviderUnoTunnelId; - return theExplicitValueProviderUnoTunnelId.getSeq(); -} + ChartView::ChartView( - uno::Reference<uno::XComponentContext> const & xContext, + uno::Reference<uno::XComponentContext> xContext, ChartModel& rModel) - : m_xCC(xContext) + : m_xCC(std::move(xContext)) , mrChartModel(rModel) - , m_aListenerContainer( m_aMutex ) , m_bViewDirty(true) , m_bInViewUpdate(false) , m_bViewUpdatePending(false) @@ -1101,10 +224,10 @@ void ChartView::impl_deleteCoordinateSystems() // datatransfer::XTransferable namespace { -constexpr OUStringLiteral lcl_aGDIMetaFileMIMEType( - u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" ); -constexpr OUStringLiteral lcl_aGDIMetaFileMIMETypeHighContrast( - u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" ); +constexpr OUString lcl_aGDIMetaFileMIMEType( + u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr ); +constexpr OUString lcl_aGDIMetaFileMIMETypeHighContrast( + u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr ); } // anonymous namespace void ChartView::getMetaFile( const uno::Reference< io::XOutputStream >& xOutStream @@ -1182,12 +305,6 @@ sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlav aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast ); } -// ____ XUnoTunnel ___ -::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier ) -{ - return comphelper::getSomethingImpl<ExplicitValueProvider>(aIdentifier, this); -} - // lang::XServiceInfo OUString SAL_CALL ChartView::getImplementationName() @@ -1219,19 +336,19 @@ static ::basegfx::B3DHomMatrix createTransformationSceneToScreen( namespace { -bool lcl_IsPieOrDonut( const uno::Reference< XDiagram >& xDiagram ) +bool lcl_IsPieOrDonut( const rtl::Reference< Diagram >& xDiagram ) { //special treatment for pie charts //the size is checked after complete creation to get the datalabels into the given space //todo: this is just a workaround at the moment for pie and donut labels - return DiagramHelper::isPieOrDonutChart( xDiagram ); + return xDiagram->isPieOrDonutChart(); } void lcl_setDefaultWritingMode( const std::shared_ptr< DrawModelWrapper >& pDrawModelWrapper, ChartModel& rModel) { //get writing mode from parent document: - if( !SvtCTLOptions().IsCTLFontEnabled() ) + if( !SvtCTLOptions::IsCTLFontEnabled() ) return; try @@ -1354,7 +471,7 @@ void lcl_setDefaultWritingMode( const std::shared_ptr< DrawModelWrapper >& pDraw if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE ) { if( pDrawModelWrapper ) - pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SvxFrameDirectionItem(static_cast<SvxFrameDirection>(nWritingMode), EE_PARA_WRITINGDIR) ); + pDrawModelWrapper->GetItemPool().SetUserDefaultItem(SvxFrameDirectionItem(static_cast<SvxFrameDirection>(nWritingMode), EE_PARA_WRITINGDIR) ); } } catch( const uno::Exception& ) @@ -1369,7 +486,7 @@ sal_Int16 lcl_getDefaultWritingModeFromPool( const std::shared_ptr<DrawModelWrap if(!pDrawModelWrapper) return nWritingMode; - const SfxPoolItem& rItem = pDrawModelWrapper->GetItemPool().GetDefaultItem(EE_PARA_WRITINGDIR); + const SfxPoolItem& rItem = pDrawModelWrapper->GetItemPool().GetUserOrPoolDefaultItem(EE_PARA_WRITINGDIR); nWritingMode = static_cast<sal_Int16>(static_cast<const SvxFrameDirectionItem&>(rItem).GetValue()); return nWritingMode; @@ -1382,11 +499,11 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D //return the used rectangle awt::Rectangle aUsedOuterRect(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y, 0, 0); - uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() ); + rtl::Reference< Diagram > xDiagram( mrChartModel.getFirstChartDiagram() ); if( !xDiagram.is()) return aUsedOuterRect; - sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + sal_Int32 nDimensionCount = xDiagram->getDimension(); if(!nDimensionCount) { //@todo handle mixed dimension @@ -1396,26 +513,23 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D basegfx::B2IRectangle aAvailableOuterRect = BaseGFXHelper::makeRectangle(rParam.maRemainingSpace); const std::vector< std::unique_ptr<VCoordinateSystem> >& rVCooSysList( rParam.mpSeriesPlotterContainer->getCooSysList() ); - SeriesPlottersType& rSeriesPlotterList = rParam.mpSeriesPlotterContainer->getSeriesPlotterList(); + auto& rSeriesPlotterList = rParam.mpSeriesPlotterContainer->getSeriesPlotterList(); //create VAxis, so they can give necessary information for automatic scaling - uno::Reference<chart2::XChartDocument> const xChartDoc(&mrChartModel); uno::Reference<util::XNumberFormatsSupplier> const xNumberFormatsSupplier( mrChartModel.getNumberFormatsSupplier()); - size_t nC = 0; - for( nC=0; nC < rVCooSysList.size(); nC++) + + for (auto& rpVCooSys : rVCooSysList) { - VCoordinateSystem* pVCooSys = rVCooSysList[nC].get(); - if(nDimensionCount==3) + if (nDimensionCount == 3) { - uno::Reference<beans::XPropertySet> xSceneProperties( xDiagram, uno::UNO_QUERY ); - CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xSceneProperties ) ); - CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xSceneProperties ) ); - CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xSceneProperties ) ); - pVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos ); + CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xDiagram ) ); + CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xDiagram ) ); + CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xDiagram ) ); + rpVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos ); } - - pVCooSys->createVAxisList(xChartDoc, rPageSize, rParam.maRemainingSpace, rParam.mbUseFixedInnerSize); + rpVCooSys->createVAxisList(&mrChartModel, rPageSize, rParam.maRemainingSpace, + rParam.mbUseFixedInnerSize, rSeriesPlotterList, getComponentContext()); } // - prepare list of all axis and how they are used @@ -1452,15 +566,14 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D // - create axis and grids for all coordinate systems //init all coordinate systems - for( nC=0; nC < rVCooSysList.size(); nC++) + for (auto& rpVCooSys : rVCooSysList) { - VCoordinateSystem* pVCooSys = rVCooSysList[nC].get(); - pVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis,xTextTargetShapes,xSeriesTargetBehindAxis); + rpVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis, xTextTargetShapes, xSeriesTargetBehindAxis); - pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + rpVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); - pVCooSys->initVAxisInList(); + rpVCooSys->initVAxisInList(); } //calculate resulting size respecting axis label layout and fontscaling @@ -1498,7 +611,9 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D || aConsumedOuterRect.getMaxX() < aAvailableOuterRect.getMaxX() || aConsumedOuterRect.getMinY() > aAvailableOuterRect.getMinY() || aConsumedOuterRect.getMinY() < aAvailableOuterRect.getMaxY() ) + { bLessSpaceConsumedThanExpected = true; + } } if (bLessSpaceConsumedThanExpected && !rParam.mbUseFixedInnerSize) @@ -1506,20 +621,28 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D aVDiagram.adjustInnerSize( aConsumedOuterRect ); pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + + // Need to re-adjust again if the labels have changed height because of + // text can break. Ideally this shouldn't be needed, but the chart height + // isn't readjusted otherwise. + pVCooSys->createAxesLabels(); + aConsumedOuterRect = ShapeFactory::getRectangleOfShape(*xBoundingShape); + aVDiagram.adjustInnerSize(aConsumedOuterRect); + pVCooSys->setTransformationSceneToScreen(B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen(aVDiagram.getCurrentRectangle()))); + } 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 } //create axes and grids for the final size - for( nC=0; nC < rVCooSysList.size(); nC++) + for (auto& rpVCooSys : rVCooSysList) { - VCoordinateSystem* pVCooSys = rVCooSysList[nC].get(); - - pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + rpVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); - pVCooSys->createAxesShapes(); - pVCooSys->createGridShapes(); + rpVCooSys->createAxesShapes(); + rpVCooSys->createGridShapes(); } // - create data series for all charttypes @@ -1537,7 +660,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 @@ -1578,17 +701,16 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D ShapeFactory::removeSubShapes( xTextTargetShapes ); //set new transformation - for( nC=0; nC < rVCooSysList.size(); nC++) + for (auto& rpVCooSys : rVCooSysList) { - VCoordinateSystem* pVCooSys = rVCooSysList[nC].get(); - pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( - createTransformationSceneToScreen( aNewInnerRect ) )); + auto aMatrix = createTransformationSceneToScreen(aNewInnerRect); + rpVCooSys->setTransformationSceneToScreen(B3DHomMatrixToHomogenMatrix(aMatrix)); } // - 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! @@ -1622,7 +744,7 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D else { ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); - m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() ); + m_aResultingDiagramRectangleExcludingAxes = BaseGFXHelper::toAwtRectangle(aConsumedInnerRect); } } else @@ -1632,7 +754,7 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D else { ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); - m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() ); + m_aResultingDiagramRectangleExcludingAxes = BaseGFXHelper::toAwtRectangle(aConsumedInnerRect); } } @@ -1642,8 +764,7 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D awt::Size aSize(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height); bool bPosSizeExcludeAxesProperty = true; - uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY_THROW ); - xDiaProps->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxesProperty; + xDiagram->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxesProperty; if (rParam.mbUseFixedInnerSize || bPosSizeExcludeAxesProperty) { aPos = awt::Point( m_aResultingDiagramRectangleExcludingAxes.X, m_aResultingDiagramRectangleExcludingAxes.Y ); @@ -1657,7 +778,7 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D } bool ChartView::getExplicitValuesForAxis( - uno::Reference< XAxis > xAxis + rtl::Reference< Axis > xAxis , ExplicitScaleData& rExplicitScale , ExplicitIncrementData& rExplicitIncrement ) { @@ -1668,8 +789,8 @@ bool ChartView::getExplicitValuesForAxis( if(!xAxis.is()) return false; - rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstDiagram() ); - const VCoordinateSystem* pVCooSys = findInCooSysList(m_aVCooSysList,xCooSys); + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstChartDiagram() ); + const VCoordinateSystem* pVCooSys = SeriesPlotterContainer::findInCooSysList(m_aVCooSysList, xCooSys); if(!pVCooSys) return false; @@ -1717,13 +838,17 @@ SdrPage* ChartView::getSdrPage() return nullptr; } -uno::Reference< drawing::XShape > ChartView::getShapeForCID( const OUString& rObjectCID ) +rtl::Reference< SvxShape > ChartView::getShapeForCID( const OUString& rObjectCID ) { SolarMutexGuard aSolarGuard; SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() ); - if( pObj ) - return uno::Reference< drawing::XShape >( pObj->getUnoShape(), uno::UNO_QUERY); - return nullptr; + if( !pObj ) + return nullptr; + + uno::Reference< drawing::XShape > xShape = pObj->getUnoShape(); + rtl::Reference<SvxShape> xShape2 = dynamic_cast<SvxShape*>(xShape.get()); + assert(xShape2 || !xShape); + return xShape2; } awt::Rectangle ChartView::getDiagramRectangleExcludingAxes() @@ -1737,7 +862,7 @@ awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool impl_updateView(); awt::Rectangle aRet; - uno::Reference< drawing::XShape > xShape( getShapeForCID(rObjectCID) ); + rtl::Reference< SvxShape > xShape = getShapeForCID(rObjectCID); if(xShape.is()) { //special handling for axis for old api: @@ -1746,7 +871,7 @@ awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_DIAGRAM ) { SolarMutexGuard aSolarGuard; - SdrObject* pRootSdrObject = SdrObject::getSdrObjectFromXShape( xShape ); + SdrObject* pRootSdrObject = xShape->GetSdrObject(); if( pRootSdrObject ) { SdrObjList* pRootList = pRootSdrObject->GetSubList(); @@ -1757,7 +882,10 @@ awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool aShapeName = "PlotAreaIncludingAxes"; SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( aShapeName, pRootList ); if( pShape ) - xShape.set( pShape->getUnoShape(), uno::UNO_QUERY); + { + xShape = dynamic_cast<SvxShape*>(pShape->getUnoShape().get()); + assert(xShape); + } } } } @@ -1768,7 +896,7 @@ awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool if( bSnapRect ) { //for rotated objects the shape size and position differs from the visible rectangle - SdrObject* pSdrObject = SdrObject::getSdrObjectFromXShape( xShape ); + SdrObject* pSdrObject = xShape->GetSdrObject(); if( pSdrObject ) { tools::Rectangle aSnapRect( pSdrObject->GetSnapRect() ); @@ -1786,168 +914,31 @@ std::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper() namespace { -sal_Int32 lcl_getDiagramTitleSpace() -{ - return 200; //=0,2 cm spacing -} -bool lcl_getPropertySwapXAndYAxis( const rtl::Reference< Diagram >& xDiagram ) -{ - bool bSwapXAndY = false; - if( xDiagram.is() ) - { - const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList( xDiagram->getBaseCoordinateSystems() ); - if( !aCooSysList.empty() ) - { - try - { - aCooSysList[0]->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY; - } - catch( const uno::Exception& ) - { - TOOLS_WARN_EXCEPTION("chart2", "" ); - } - } - } - return bSwapXAndY; -} +constexpr double constPageLayoutDistancePercentage = 0.02; +constexpr sal_Int32 constPageLayoutFixedDistance = 350; -} - -sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( - const Reference< chart2::XAxis >& xAxis - , const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem - , const Reference<chart2::XChartDocument>& xChartDoc) -{ - return AxisHelper::getExplicitNumberFormatKeyForAxis( xAxis, xCorrespondingCoordinateSystem, xChartDoc - , true /*bSearchForParallelAxisIfNothingIsFound*/ ); -} - -sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp ) +bool getAvailablePosAndSizeForDiagram( + CreateShapeParam2D& rParam, const awt::Size & rPageSize, rtl::Reference<Diagram> const& xDiagram) { - sal_Int32 nFormat=0; - if( !xSeriesOrPointProp.is() ) - return nFormat; + uno::Reference<beans::XPropertySet> const& xProp(xDiagram); + rParam.mbUseFixedInnerSize = false; - try - { - xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat; - } - catch (const beans::UnknownPropertyException&) {} + //@todo: we need a size dependent on the axis labels + rtl::Reference<ChartType> xChartType; + if (xDiagram) + xChartType = xDiagram->getChartTypeByIndex(0); - if(nFormat<0) - nFormat=0; - return nFormat; -} + sal_Int32 nXDistance = sal_Int32(rPageSize.Width * constPageLayoutDistancePercentage); + sal_Int32 nYDistance = sal_Int32(rPageSize.Height * constPageLayoutDistancePercentage); -sal_Int32 ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( - const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, - const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) -{ - sal_Int32 nFormat=0; - if( !xSeriesOrPointProp.is() ) - return nFormat; - if( !(xSeriesOrPointProp->getPropertyValue("PercentageNumberFormat") >>= nFormat) ) + // Only pie chart uses fixed size margins + if (xChartType.is() && xChartType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_PIE) { - nFormat = DiagramHelper::getPercentNumberFormat( xNumberFormatsSupplier ); + nXDistance = constPageLayoutFixedDistance; + nYDistance = constPageLayoutFixedDistance; } - if(nFormat<0) - nFormat=0; - return nFormat; -} - -awt::Rectangle ExplicitValueProvider::AddSubtractAxisTitleSizes( - ChartModel& rModel - , ExplicitValueProvider* pChartView - , const awt::Rectangle& rPositionAndSize, bool bSubtract ) -{ - awt::Rectangle aRet(rPositionAndSize); - - //add axis title sizes to the diagram size - uno::Reference< chart2::XTitle > xTitle_Height( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, rModel ) ); - uno::Reference< chart2::XTitle > xTitle_Width( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, rModel ) ); - uno::Reference< chart2::XTitle > xSecondTitle_Height( TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, rModel ) ); - uno::Reference< chart2::XTitle > xSecondTitle_Width( TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, rModel ) ); - if( xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() || xSecondTitle_Width.is() ) - { - ExplicitValueProvider* pExplicitValueProvider = pChartView; - if( pExplicitValueProvider ) - { - //detect whether x axis points into x direction or not - if( lcl_getPropertySwapXAndYAxis( rModel.getFirstChartDiagram() ) ) - { - std::swap( xTitle_Height, xTitle_Width ); - std::swap( xSecondTitle_Height, xSecondTitle_Width ); - } - - sal_Int32 nTitleSpaceWidth = 0; - sal_Int32 nTitleSpaceHeight = 0; - sal_Int32 nSecondTitleSpaceWidth = 0; - sal_Int32 nSecondTitleSpaceHeight = 0; - if( xTitle_Height.is() ) - { - OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Height, rModel ) ); - nTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; - if( nTitleSpaceHeight ) - nTitleSpaceHeight+=lcl_getDiagramTitleSpace(); - } - if( xTitle_Width.is() ) - { - OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Width, rModel ) ); - nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; - if(nTitleSpaceWidth) - nTitleSpaceWidth+=lcl_getDiagramTitleSpace(); - } - if( xSecondTitle_Height.is() ) - { - OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Height, rModel ) ); - nSecondTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; - if( nSecondTitleSpaceHeight ) - nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace(); - } - if( xSecondTitle_Width.is() ) - { - OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Width, rModel ) ); - nSecondTitleSpaceWidth += pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; - if( nSecondTitleSpaceWidth ) - nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace(); - } - if( bSubtract ) - { - aRet.X += nTitleSpaceWidth; - aRet.Y += nSecondTitleSpaceHeight; - aRet.Width -= (nTitleSpaceWidth + nSecondTitleSpaceWidth); - aRet.Height -= (nTitleSpaceHeight + nSecondTitleSpaceHeight); - } - else - { - - aRet.X -= nTitleSpaceWidth; - aRet.Y -= nSecondTitleSpaceHeight; - aRet.Width += nTitleSpaceWidth + nSecondTitleSpaceWidth; - aRet.Height += nTitleSpaceHeight + nSecondTitleSpaceHeight; - } - } - } - return aRet; -} - -namespace { - -double lcl_getPageLayoutDistancePercentage() -{ - return 0.02; -} - -bool getAvailablePosAndSizeForDiagram( - CreateShapeParam2D& rParam, const awt::Size & rPageSize, const uno::Reference< beans::XPropertySet >& xProp) -{ - rParam.mbUseFixedInnerSize = false; - - //@todo: we need a size dependent on the axis labels - sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage()); - sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage()); rParam.maRemainingSpace.X += nXDistance; rParam.maRemainingSpace.Width -= 2*nXDistance; rParam.maRemainingSpace.Y += nYDistance; @@ -2000,7 +991,7 @@ bool getAvailablePosAndSizeForDiagram( return true; } -enum TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z }; +enum class TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z }; void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment , awt::Rectangle const & rDiagramPlusAxesRect, const awt::Size & rPageSize ) @@ -2010,32 +1001,30 @@ void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment awt::Point aNewPosition(0,0); awt::Size aTitleSize = pVTitle->getFinalSize(); - sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage()); - sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage()); - switch( eAlignment ) + sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height * constPageLayoutDistancePercentage); + sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width * constPageLayoutDistancePercentage); + switch (eAlignment) { - case ALIGN_TOP: + case TitleAlignment::ALIGN_TOP: aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 , rDiagramPlusAxesRect.Y - aTitleSize.Height/2 - nYDistance ); break; - case ALIGN_BOTTOM: + case TitleAlignment::ALIGN_BOTTOM: aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2 + nYDistance ); break; - case ALIGN_LEFT: + case TitleAlignment::ALIGN_LEFT: aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); break; - case ALIGN_RIGHT: + case TitleAlignment::ALIGN_RIGHT: aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); break; - case ALIGN_Z: + case TitleAlignment::ALIGN_Z: aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 ); break; - default: - break; } sal_Int32 nMaxY = rPageSize.Height - aTitleSize.Height/2; @@ -2065,7 +1054,7 @@ std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType std::shared_ptr<VTitle> apVTitle; // #i109336# Improve auto positioning in chart - double fPercentage = lcl_getPageLayoutDistancePercentage(); + double fPercentage = constPageLayoutDistancePercentage; sal_Int32 nXDistance = static_cast< sal_Int32 >( rPageSize.Width * fPercentage ); sal_Int32 nYDistance = static_cast< sal_Int32 >( rPageSize.Height * fPercentage ); if ( eType == TitleHelper::MAIN_TITLE ) @@ -2081,7 +1070,7 @@ std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType nXDistance = 450; // 1/100 mm } - uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, rModel ) ); + rtl::Reference< Title > xTitle( TitleHelper::getTitle( eType, rModel ) ); OUString aCompleteString = TitleHelper::getCompleteString(xTitle); if (aCompleteString.isEmpty() || !VTitle::isVisible(xTitle)) return apVTitle; @@ -2108,7 +1097,7 @@ std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType bYAxisTitle = true; } apVTitle = std::make_shared<VTitle>(xTitle); - OUString aCID = ObjectIdentifier::createClassifiedIdentifierForObject(xTitle, rModel); + OUString aCID = ObjectIdentifier::createClassifiedIdentifierForObject(xTitle, &rModel); apVTitle->init(xPageShapes, aCID); apVTitle->createShapes(awt::Point(0, 0), rPageSize, aTextMaxWidth, bYAxisTitle); awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize(); @@ -2118,8 +1107,7 @@ std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType rbAutoPosition = true; awt::Point aNewPosition(0,0); chart2::RelativePosition aRelativePosition; - uno::Reference<beans::XPropertySet> xProp(xTitle, uno::UNO_QUERY); - if (xProp.is() && (xProp->getPropertyValue("RelativePosition") >>= aRelativePosition)) + if (xTitle.is() && (xTitle->getPropertyValue("RelativePosition") >>= aRelativePosition)) { rbAutoPosition = false; @@ -2136,23 +1124,23 @@ std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType { switch( eAlignment ) { - case ALIGN_TOP: + case TitleAlignment::ALIGN_TOP: aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance ); break; - case ALIGN_BOTTOM: + case TitleAlignment::ALIGN_BOTTOM: aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance ); break; - case ALIGN_LEFT: + case TitleAlignment::ALIGN_LEFT: aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance , rRemainingSpace.Y + rRemainingSpace.Height/2 ); break; - case ALIGN_RIGHT: + case TitleAlignment::ALIGN_RIGHT: aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance , rRemainingSpace.Y + rRemainingSpace.Height/2 ); break; - default: + case TitleAlignment::ALIGN_Z: break; } @@ -2162,32 +1150,32 @@ std::shared_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType //remaining space switch( eAlignment ) { - case ALIGN_TOP: + case TitleAlignment::ALIGN_TOP: // Push the remaining space down from top. rRemainingSpace.Y += ( aTitleSize.Height + nYDistance ); rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); break; - case ALIGN_BOTTOM: + case TitleAlignment::ALIGN_BOTTOM: // Push the remaining space up from bottom. rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); break; - case ALIGN_LEFT: + case TitleAlignment::ALIGN_LEFT: // Push the remaining space to the right from left edge. rRemainingSpace.X += ( aTitleSize.Width + nXDistance ); rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); break; - case ALIGN_RIGHT: + case TitleAlignment::ALIGN_RIGHT: // Push the remaining space to the left from right edge. rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); break; - default: + case TitleAlignment::ALIGN_Z: break; } return apVTitle; } -bool lcl_createLegend( const uno::Reference< XLegend > & xLegend +bool lcl_createLegend( const rtl::Reference< Legend > & xLegend , const rtl::Reference<SvxShapeGroupAnyD>& xPageShapes , const uno::Reference< uno::XComponentContext > & xContext , awt::Rectangle & rRemainingSpace @@ -2311,7 +1299,7 @@ void formatPage( } } -void lcl_removeEmptyGroupShapes( SdrObject& rParent ) +void lcl_removeEmptyGroupShapes( const SdrObject& rParent ) { SdrObjList* pObjList = rParent.getChildrenOfSdrObject(); if (!pObjList || pObjList->GetObjCount() == 0) @@ -2327,8 +1315,7 @@ void lcl_removeEmptyGroupShapes( SdrObject& rParent ) if (pChildObjList->GetObjCount() == 0) { //remove empty group shape - SdrObject* pRemoved = pObjList->NbcRemoveObject(nIdx); - SdrObject::Free( pRemoved ); + pObjList->NbcRemoveObject(nIdx); } else lcl_removeEmptyGroupShapes(*pChildSdrObject); @@ -2368,7 +1355,7 @@ void ChartView::createShapes() { SolarMutexGuard aSolarGuard; - osl::MutexGuard aTimedGuard(maTimeMutex); + std::unique_lock aTimedGuard(maTimeMutex); if(mrChartModel.isTimeBased()) { maTimeBased.bTimeBased = true; @@ -2393,9 +1380,12 @@ void ChartView::createShapes() if(!mxRootShape.is()) mxRootShape = ShapeFactory::getOrCreateChartRootShape( m_xDrawPage ); - SdrPage* pPage = ChartView::getSdrPage(); - if(pPage) //it is necessary to use the implementation here as the uno page does not provide a propertyset + SdrPage* pPage = getSdrPage(); + + if (pPage) //it is necessary to use the implementation here as the uno page does not provide a propertyset + { pPage->SetSize(Size(aPageSize.Width,aPageSize.Height)); + } else { OSL_FAIL("could not set page size correctly"); @@ -2421,6 +1411,35 @@ void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ ) { } +namespace +{ +// Disables setting the chart's modified state, as well as its parent's (if exists). +// Painting a chart must not set these states. +struct ChartModelDisableSetModified +{ + ChartModel& mrChartModel; + SfxObjectShell* mpParentShell; + bool mbWasUnmodified; + ChartModelDisableSetModified(ChartModel& rChartModel) + : mrChartModel(rChartModel) + , mpParentShell(SfxObjectShell::GetShellFromComponent(rChartModel.getParent())) + , mbWasUnmodified(!rChartModel.isModified()) + { + if (mpParentShell && mpParentShell->IsEnableSetModified()) + mpParentShell->EnableSetModified(false); + else + mpParentShell = nullptr; + } + ~ChartModelDisableSetModified() + { + if (mbWasUnmodified && mrChartModel.isModified()) + mrChartModel.setModified(false); + if (mpParentShell) + mpParentShell->EnableSetModified(true); + } +}; +} + void ChartView::impl_updateView( bool bCheckLockedCtrler ) { if( !m_pDrawModelWrapper ) @@ -2451,6 +1470,9 @@ void ChartView::impl_updateView( bool bCheckLockedCtrler ) m_pDrawModelWrapper->lockControllers(); } + // Rendering the chart must not set its (or its parent) modified status + ChartModelDisableSetModified dontSetModified(mrChartModel); + //create chart view { m_bViewDirty = false; @@ -2567,16 +1589,11 @@ void ChartView::impl_notifyModeChangeListener( const OUString& rNewMode ) { try { - comphelper::OInterfaceContainerHelper2* pIC = m_aListenerContainer - .getContainer( cppu::UnoType<util::XModeChangeListener>::get()); - if( pIC ) + std::unique_lock g(m_aMutex); + if( m_aModeChangeListeners.getLength(g) ) { util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode ); - comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); - while( aIt.hasMoreElements() ) - { - static_cast< util::XModeChangeListener* >( aIt.next() )->modeChanged( aEvent ); - } + m_aModeChangeListeners.notifyEach( g, &css::util::XModeChangeListener::modeChanged, aEvent); } } catch( const uno::Exception& ) @@ -2589,13 +1606,13 @@ void ChartView::impl_notifyModeChangeListener( const OUString& rNewMode ) void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) { - m_aListenerContainer.addInterface( - cppu::UnoType<util::XModeChangeListener>::get(), xListener ); + std::unique_lock g(m_aMutex); + m_aModeChangeListeners.addInterface(g, xListener ); } void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) { - m_aListenerContainer.removeInterface( - cppu::UnoType<util::XModeChangeListener>::get(), xListener ); + std::unique_lock g(m_aMutex); + m_aModeChangeListeners.removeInterface(g, xListener ); } void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) { @@ -2799,8 +1816,13 @@ uno::Sequence< OUString > ChartView::getAvailableServiceNames() return aServiceNames; } -OUString ChartView::dump() +OUString ChartView::dump(OUString const & kind) { + if (kind.isEmpty()) { + return comphelper::dumpXmlToString([this](auto writer) { return dumpAsXml(writer); }); + } + + // kind == "shapes": #if HAVE_FEATURE_DESKTOP // Used for unit tests and in chartcontroller only, no need to drag in this when cross-compiling // for non-desktop @@ -2847,7 +1869,7 @@ void ChartView::dumpAsXml(xmlTextWriterPtr pWriter) const void ChartView::setViewDirty() { - osl::MutexGuard aGuard(maTimeMutex); + std::unique_lock aGuard(maTimeMutex); m_bViewDirty = true; } @@ -2870,10 +1892,9 @@ void ChartView::createShapes2D( const awt::Size& rPageSize ) aParam.maRemainingSpace.Height = rPageSize.Height; //create the group shape for diagram and axes first to have title and legends on top of it - uno::Reference< XDiagram > xDiagram( mrChartModel.getFirstDiagram() ); - uno::Reference< beans::XPropertySet > xProp(xDiagram, uno::UNO_QUERY); + rtl::Reference< Diagram > xDiagram( mrChartModel.getFirstChartDiagram() ); bool bHasRelativeSize = false; - if( xProp.is() && xProp->getPropertyValue("RelativeSize").hasValue() ) + if( xDiagram.is() && xDiagram->getPropertyValue("RelativeSize").hasValue() ) bHasRelativeSize = true; OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ) );//todo: other index if more than one diagram is possible @@ -2897,13 +1918,13 @@ void ChartView::createShapes2D( const awt::Size& rPageSize ) lcl_createTitle( TitleHelper::MAIN_TITLE, mxRootShape, mrChartModel, - aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy); + aParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_TOP, bAutoPositionDummy); if (!bHasRelativeSize && (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)) return; lcl_createTitle( TitleHelper::SUB_TITLE, mxRootShape, mrChartModel, - aParam.maRemainingSpace, rPageSize, ALIGN_TOP, bAutoPositionDummy ); + aParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_TOP, bAutoPositionDummy ); if (!bHasRelativeSize && (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)) return; @@ -2911,7 +1932,7 @@ void ChartView::createShapes2D( const awt::Size& rPageSize ) aParam.mpSeriesPlotterContainer->initializeCooSysAndSeriesPlotter( mrChartModel ); if(maTimeBased.bTimeBased && maTimeBased.nFrame != 0) { - SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); + auto& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); size_t n = rSeriesPlotter.size(); for(size_t i = 0; i < n; ++i) { @@ -2928,7 +1949,7 @@ void ChartView::createShapes2D( const awt::Size& rPageSize ) } lcl_createLegend( - LegendHelper::getLegend( mrChartModel ), mxRootShape, m_xCC, + LegendHelper::getLegend( mrChartModel ), mxRootShape, getComponentContext(), aParam.maRemainingSpace, rPageSize, mrChartModel, aParam.mpSeriesPlotterContainer->getLegendEntryProviderList(), lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) ); @@ -2939,9 +1960,9 @@ void ChartView::createShapes2D( const awt::Size& rPageSize ) return; bool bDummy = false; - bool bIsVertical = DiagramHelper::getVertical(xDiagram, bDummy, bDummy); + bool bIsVertical = xDiagram && xDiagram->getVertical(bDummy, bDummy); - if (getAvailablePosAndSizeForDiagram(aParam, rPageSize, xProp)) + if (getAvailablePosAndSizeForDiagram(aParam, rPageSize, xDiagram)) { awt::Rectangle aUsedOuterRect = impl_createDiagramAndContent(aParam, rPageSize); @@ -2954,15 +1975,15 @@ void ChartView::createShapes2D( const awt::Size& rPageSize ) //correct axis title position awt::Rectangle aDiagramPlusAxesRect( aUsedOuterRect ); if (aParam.mbAutoPosTitleX) - changePositionOfAxisTitle(aParam.mpVTitleX.get(), ALIGN_BOTTOM, aDiagramPlusAxesRect, rPageSize); + changePositionOfAxisTitle(aParam.mpVTitleX.get(), TitleAlignment::ALIGN_BOTTOM, aDiagramPlusAxesRect, rPageSize); if (aParam.mbAutoPosTitleY) - changePositionOfAxisTitle(aParam.mpVTitleY.get(), ALIGN_LEFT, aDiagramPlusAxesRect, rPageSize); + changePositionOfAxisTitle(aParam.mpVTitleY.get(), TitleAlignment::ALIGN_LEFT, aDiagramPlusAxesRect, rPageSize); if (aParam.mbAutoPosTitleZ) - changePositionOfAxisTitle(aParam.mpVTitleZ.get(), ALIGN_Z, aDiagramPlusAxesRect, rPageSize); + changePositionOfAxisTitle(aParam.mpVTitleZ.get(), TitleAlignment::ALIGN_Z, aDiagramPlusAxesRect, rPageSize); if (aParam.mbAutoPosSecondTitleX) - changePositionOfAxisTitle(aParam.mpVTitleSecondX.get(), bIsVertical? ALIGN_RIGHT : ALIGN_TOP, aDiagramPlusAxesRect, rPageSize); + changePositionOfAxisTitle(aParam.mpVTitleSecondX.get(), bIsVertical? TitleAlignment::ALIGN_RIGHT : TitleAlignment::ALIGN_TOP, aDiagramPlusAxesRect, rPageSize); if (aParam.mbAutoPosSecondTitleY) - changePositionOfAxisTitle(aParam.mpVTitleSecondY.get(), bIsVertical? ALIGN_TOP : ALIGN_RIGHT, aDiagramPlusAxesRect, rPageSize); + changePositionOfAxisTitle(aParam.mpVTitleSecondY.get(), bIsVertical? TitleAlignment::ALIGN_TOP : TitleAlignment::ALIGN_RIGHT, aDiagramPlusAxesRect, rPageSize); } //cleanup: remove all empty group shapes to avoid grey border lines: @@ -2971,7 +1992,7 @@ void ChartView::createShapes2D( const awt::Size& rPageSize ) if(maTimeBased.bTimeBased && maTimeBased.nFrame % 60 == 0) { // create copy of the data for next frame - SeriesPlottersType& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); + auto& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); size_t n = rSeriesPlotter.size(); maTimeBased.m_aDataSeriesList.clear(); maTimeBased.m_aDataSeriesList.resize(n); @@ -3000,41 +2021,46 @@ void ChartView::createShapes2D( const awt::Size& rPageSize ) bool ChartView::createAxisTitleShapes2D( CreateShapeParam2D& rParam, const css::awt::Size& rPageSize, bool bHasRelativeSize ) { - uno::Reference<XDiagram> xDiagram = mrChartModel.getFirstDiagram(); + rtl::Reference<Diagram> xDiagram = mrChartModel.getFirstChartDiagram(); - Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); - sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram ); + rtl::Reference< ChartType > xChartType; + sal_Int32 nDimension = 0; + if (xDiagram) + { + xChartType = xDiagram->getChartTypeByIndex( 0 ); + nDimension = xDiagram->getDimension(); + } if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) ) rParam.mpVTitleX = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, mxRootShape, mrChartModel - , rParam.maRemainingSpace, rPageSize, ALIGN_BOTTOM, rParam.mbAutoPosTitleX ); + , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_BOTTOM, rParam.mbAutoPosTitleX ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) ) rParam.mpVTitleY = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, mxRootShape, mrChartModel - , rParam.maRemainingSpace, rPageSize, ALIGN_LEFT, rParam.mbAutoPosTitleY ); + , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_LEFT, rParam.mbAutoPosTitleY ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) ) rParam.mpVTitleZ = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, mxRootShape, mrChartModel - , rParam.maRemainingSpace, rPageSize, ALIGN_RIGHT, rParam.mbAutoPosTitleZ ); + , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_RIGHT, rParam.mbAutoPosTitleZ ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; bool bDummy = false; - bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy ); + bool bIsVertical = xDiagram && xDiagram->getVertical( bDummy, bDummy ); if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) ) rParam.mpVTitleSecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, mxRootShape, mrChartModel - , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_RIGHT : ALIGN_TOP, rParam.mbAutoPosSecondTitleX ); + , rParam.maRemainingSpace, rPageSize, bIsVertical? TitleAlignment::ALIGN_RIGHT : TitleAlignment::ALIGN_TOP, rParam.mbAutoPosSecondTitleX ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) ) rParam.mpVTitleSecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, mxRootShape, mrChartModel - , rParam.maRemainingSpace, rPageSize, bIsVertical? ALIGN_TOP : ALIGN_RIGHT, rParam.mbAutoPosSecondTitleY ); + , rParam.maRemainingSpace, rPageSize, bIsVertical? TitleAlignment::ALIGN_TOP : TitleAlignment::ALIGN_RIGHT, rParam.mbAutoPosSecondTitleY ); if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) return false; |