diff options
Diffstat (limited to 'chart2/source/model/template/ChartTypeTemplate.cxx')
-rw-r--r-- | chart2/source/model/template/ChartTypeTemplate.cxx | 861 |
1 files changed, 861 insertions, 0 deletions
diff --git a/chart2/source/model/template/ChartTypeTemplate.cxx b/chart2/source/model/template/ChartTypeTemplate.cxx new file mode 100644 index 000000000..a785635f9 --- /dev/null +++ b/chart2/source/model/template/ChartTypeTemplate.cxx @@ -0,0 +1,861 @@ +/* -*- 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 <ChartTypeTemplate.hxx> +#include <DataInterpreter.hxx> +#include <CommonConverters.hxx> +#include <ChartTypeHelper.hxx> +#include <ChartType.hxx> +#include <DataSeries.hxx> +#include <DataSource.hxx> + +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <Diagram.hxx> +#include <DiagramHelper.hxx> +#include <AxisIndexDefines.hxx> +#include <BaseCoordinateSystem.hxx> +#include <unonames.hxx> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/StackingDirection.hpp> +#include <com/sun/star/chart2/XColorScheme.hpp> +#include <tools/diagnose_ex.h> +#include <comphelper/property.hxx> + +#include <algorithm> +#include <cstddef> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +void lcl_applyDefaultStyle( + const rtl::Reference< ::chart::DataSeries > & xSeries, + sal_Int32 nIndex, + const rtl::Reference< ::chart::Diagram > & xDiagram ) +{ + // @deprecated: correct default color should be found by view without + // setting color as hard attribute + if( xSeries.is() && xDiagram.is()) + { + Reference< chart2::XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); + if( xColorScheme.is() ) + xSeries->setPropertyValue( + "Color", + uno::Any( xColorScheme->getColorByIndex( nIndex ))); + } +} + +void lcl_ensureCorrectLabelPlacement( const Reference< beans::XPropertySet >& xProp, const uno::Sequence < sal_Int32 >& rAvailablePlacements ) +{ + sal_Int32 nLabelPlacement=0; + if( !(xProp.is() && (xProp->getPropertyValue( "LabelPlacement" ) >>= nLabelPlacement)) ) + return; + + bool bValid = false; + for( sal_Int32 i : rAvailablePlacements ) + { + if( i == nLabelPlacement ) + { + bValid = true; + break; + } + } + if( !bValid ) + { + uno::Any aNewValue; + //otherwise use the first supported one + if( rAvailablePlacements.hasElements() ) + aNewValue <<=rAvailablePlacements[0]; + xProp->setPropertyValue( "LabelPlacement", aNewValue ); + } +} + +void lcl_resetLabelPlacementIfDefault( const Reference< beans::XPropertySet >& xProp, sal_Int32 nDefaultPlacement ) +{ + + sal_Int32 nLabelPlacement=0; + if( xProp.is() && (xProp->getPropertyValue( "LabelPlacement" ) >>= nLabelPlacement) ) + { + if( nDefaultPlacement == nLabelPlacement ) + xProp->setPropertyValue( "LabelPlacement", uno::Any() ); + } +} + +void lcl_ensureCorrectMissingValueTreatment( const rtl::Reference< ::chart::Diagram >& xDiagram, const rtl::Reference< ::chart::ChartType >& xChartType ) +{ + if( xDiagram.is() ) + { + uno::Sequence < sal_Int32 > aAvailableMissingValueTreatment( + ::chart::ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) ); + + if( aAvailableMissingValueTreatment.hasElements() ) + xDiagram->setPropertyValue( "MissingValueTreatment", uno::Any( aAvailableMissingValueTreatment[0] ) ); + else + xDiagram->setPropertyValue( "MissingValueTreatment", uno::Any() ); + } +} + +} // anonymous namespace + +namespace chart +{ + +ChartTypeTemplate::ChartTypeTemplate( + Reference< uno::XComponentContext > const & xContext, + const OUString & rServiceName ) : + m_xContext( xContext ), + m_aServiceName( rServiceName ) +{ +} + +ChartTypeTemplate::~ChartTypeTemplate() +{} + +// ____ ChartTypeTemplate ____ +rtl::Reference< Diagram > ChartTypeTemplate::createDiagramByDataSource2( + const uno::Reference< data::XDataSource >& xDataSource, + const uno::Sequence< beans::PropertyValue >& aArguments ) +{ + rtl::Reference< Diagram > xDia; + + try + { + // create diagram + xDia = new Diagram(GetComponentContext()); + + // modify diagram + rtl::Reference< DataInterpreter > xInterpreter( getDataInterpreter2()); + InterpretedData aData( + xInterpreter->interpretDataSource( + xDataSource, aArguments, {} )); + + sal_Int32 nCount = 0; + for( auto const & i : aData.Series ) + for( auto const & j : i ) + lcl_applyDefaultStyle( j, nCount++, xDia ); + + std::vector< rtl::Reference< ChartType > > aOldChartTypesSeq; + FillDiagram( xDia, aData.Series, aData.Categories, aOldChartTypesSeq ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xDia; +} + +sal_Bool SAL_CALL ChartTypeTemplate::supportsCategories() +{ + return true; +} + +void ChartTypeTemplate::changeDiagram( const rtl::Reference< Diagram >& xDiagram ) +{ + if( ! xDiagram.is()) + return; + + try + { + std::vector< std::vector< rtl::Reference< DataSeries > > > aSeriesSeq = + DiagramHelper::getDataSeriesGroups( xDiagram ); + std::vector< rtl::Reference< DataSeries > > aFlatSeriesSeq( FlattenSequence( aSeriesSeq )); + const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.size(); + + // chart-type specific interpretation of existing data series + rtl::Reference< DataInterpreter > xInterpreter( getDataInterpreter2()); + InterpretedData aData; + aData.Series = aSeriesSeq; + aData.Categories = DiagramHelper::getCategoriesFromDiagram( xDiagram ); + + if( xInterpreter->isDataCompatible( aData ) ) + { + aData = xInterpreter->reinterpretDataSeries( aData ); + } + else + { + rtl::Reference< DataSource > xSource = DataInterpreter::mergeInterpretedData( aData ); + // todo: get a "range-union" from the data provider by calling + // OUString aRange = getRangeRepresentationByData( xSource ); + // xSource.set( getDataByRangeRepresentation( aRange, aParam )); + // where aParam == ?? + Sequence< beans::PropertyValue > aParam; + if( aData.Categories.is()) + { + aParam = { beans::PropertyValue( "HasCategories", -1, uno::Any( true ), + beans::PropertyState_DIRECT_VALUE ) }; + } + aData = xInterpreter->interpretDataSource( xSource, aParam, aFlatSeriesSeq ); + } + aSeriesSeq = aData.Series; + + sal_Int32 nIndex = 0; + for( auto const & i : std::as_const(aSeriesSeq) ) + for( auto const & j : i ) + { + if( nIndex >= nFormerSeriesCount ) + lcl_applyDefaultStyle( j, nIndex++, xDiagram ); + } + + // remove charttype groups from all coordinate systems + std::vector< rtl::Reference< ChartType > > aOldChartTypesSeq = + DiagramHelper::getChartTypesFromDiagram(xDiagram); + + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + coords->setChartTypes( Sequence< Reference< XChartType > >() ); + } + + FillDiagram( xDiagram, aSeriesSeq, aData.Categories, aOldChartTypesSeq ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartTypeTemplate::changeDiagramData( + const rtl::Reference< Diagram >& xDiagram, + const Reference< chart2::data::XDataSource >& xDataSource, + const Sequence< beans::PropertyValue >& aArguments ) +{ + if( ! (xDiagram.is() && + xDataSource.is()) ) + return; + + try + { + // interpret new data and re-use existing series + std::vector< rtl::Reference< DataSeries > > aFlatSeriesSeq = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.size(); + rtl::Reference< DataInterpreter > xInterpreter( getDataInterpreter2()); + InterpretedData aData = + xInterpreter->interpretDataSource( xDataSource, aArguments, aFlatSeriesSeq ); + + // data series + sal_Int32 nIndex = 0; + for( std::size_t i=0; i<aData.Series.size(); ++i ) + for( std::size_t j=0; j<aData.Series[i].size(); ++j, ++nIndex ) + { + if( nIndex >= nFormerSeriesCount ) + { + lcl_applyDefaultStyle( aData.Series[i][j], nIndex, xDiagram ); + applyStyle2( aData.Series[i][j], i, j, aData.Series[i].size() ); + } + } + + // categories + DiagramHelper::setCategoriesToDiagram( aData.Categories, xDiagram, true, supportsCategories() ); + + std::vector< rtl::Reference< ChartType > > aChartTypes = + DiagramHelper::getChartTypesFromDiagram( xDiagram ); + sal_Int32 nMax = std::min( aChartTypes.size(), aData.Series.size()); + for( sal_Int32 i=0; i<nMax; ++i ) + { + aChartTypes[i]->setDataSeries( aData.Series[i] ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool ChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool /* bAdaptProperties */ ) +{ + bool bResult = false; + + if( ! xDiagram.is()) + return bResult; + + try + { + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysSeq( + xDiagram->getBaseCoordinateSystems()); + + // need to have at least one coordinate system + bResult = !aCooSysSeq.empty(); + if( bResult ) + { + std::vector< rtl::Reference< ChartType > > aFormerlyUsedChartTypes; + rtl::Reference<ChartType> xOldCT = getChartTypeForNewSeries2(aFormerlyUsedChartTypes); + if (!xOldCT.is()) + return false; + + const OUString aChartTypeToMatch = xOldCT->getChartType(); + const sal_Int32 nDimensionToMatch = getDimension(); + for( std::size_t nCooSysIdx=0; bResult && (nCooSysIdx < aCooSysSeq.size()); ++nCooSysIdx ) + { + // match dimension + bResult = bResult && (aCooSysSeq[nCooSysIdx]->getDimension() == nDimensionToMatch); + + const std::vector< rtl::Reference< ChartType > > & aChartTypeSeq( aCooSysSeq[nCooSysIdx]->getChartTypes2()); + for( std::size_t nCTIdx=0; bResult && (nCTIdx < aChartTypeSeq.size()); ++nCTIdx ) + { + // match chart type + bResult = bResult && aChartTypeSeq[nCTIdx]->getChartType() == aChartTypeToMatch; + bool bFound=false; + bool bAmbiguous=false; + // match stacking mode + bResult = bResult && + ( DiagramHelper::getStackModeFromChartType( + aChartTypeSeq[nCTIdx], bFound, bAmbiguous, + aCooSysSeq[nCooSysIdx] ) + == getStackMode( nCTIdx ) ); + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return bResult; +} + +rtl::Reference< DataInterpreter > ChartTypeTemplate::getDataInterpreter2() +{ + if( ! m_xDataInterpreter.is()) + m_xDataInterpreter.set( new DataInterpreter ); + + return m_xDataInterpreter; +} + +void ChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 /* nSeriesIndex */, + ::sal_Int32 /* nSeriesCount */ ) +{ + // sset stacking mode + if( !xSeries.is()) + return; + + try + { + StackMode eStackMode = getStackMode( nChartTypeIndex ); + const uno::Any aPropValue( + ( (eStackMode == StackMode::YStacked) || + (eStackMode == StackMode::YStackedPercent) ) + ? chart2::StackingDirection_Y_STACKING + : (eStackMode == StackMode::ZStacked ) + ? chart2::StackingDirection_Z_STACKING + : chart2::StackingDirection_NO_STACKING ); + xSeries->setPropertyValue( "StackingDirection", aPropValue ); + + //ensure valid label placement + { + uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + getChartTypeForIndex( nChartTypeIndex ), isSwapXAndY(), xSeries ) ); + lcl_ensureCorrectLabelPlacement( xSeries, aAvailablePlacements ); + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + lcl_ensureCorrectLabelPlacement( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), aAvailablePlacements ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartTypeTemplate::applyStyles( const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + // apply chart-type specific styles, like "symbols on" for example + std::vector< std::vector< rtl::Reference< DataSeries > > > aNewSeriesSeq( + DiagramHelper::getDataSeriesGroups( xDiagram )); + for( std::size_t i=0; i<aNewSeriesSeq.size(); ++i ) + { + const sal_Int32 nNumSeries = aNewSeriesSeq[i].size(); + for( sal_Int32 j=0; j<nNumSeries; ++j ) + applyStyle2( aNewSeriesSeq[i][j], i, j, nNumSeries ); + } + + //ensure valid empty cell handling (for first chart type...) + lcl_ensureCorrectMissingValueTreatment( xDiagram, getChartTypeForIndex( 0 ) ); +} + +void ChartTypeTemplate::resetStyles2( const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + // reset number format if we had percent stacking on + bool bPercent = (getStackMode(0) == StackMode::YStackedPercent); + if( bPercent ) + { + const std::vector< rtl::Reference< Axis > > aAxisSeq( AxisHelper::getAllAxesOfDiagram( xDiagram ) ); + for( rtl::Reference< Axis > const & axis : aAxisSeq ) + { + if( AxisHelper::getDimensionIndexOfAxis( axis, xDiagram )== 1 ) + { + // set number format to source format + axis->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(true)); + axis->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any()); + } + } + } + + //reset label placement if default + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + //iterate through all chart types in the current coordinate system + for( rtl::Reference< ChartType > const & xChartType : xCooSys->getChartTypes2() ) + { + //iterate through all series in this chart type + for( rtl::Reference< DataSeries > const & xSeries : xChartType->getDataSeries2() ) + { + uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + xChartType, isSwapXAndY(), xSeries ) ); + if(!aAvailablePlacements.hasElements()) + continue; + + sal_Int32 nDefaultPlacement = aAvailablePlacements[0]; + + lcl_resetLabelPlacementIfDefault( xSeries, nDefaultPlacement ); + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + lcl_resetLabelPlacementIfDefault( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), nDefaultPlacement ); + } + } + } + +} + +// ____ XServiceName ____ + OUString SAL_CALL ChartTypeTemplate::getServiceName() +{ + return m_aServiceName; +} + +sal_Int32 ChartTypeTemplate::getDimension() const +{ + return 2; +} + +StackMode ChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const +{ + return StackMode::NONE; +} + +bool ChartTypeTemplate::isSwapXAndY() const +{ + return false; +} + +void ChartTypeTemplate::createCoordinateSystems( + const rtl::Reference< ::chart::Diagram > & xDiagram ) +{ + if( ! xDiagram.is()) + return; + std::vector< rtl::Reference< ChartType > > aFormerlyUsedChartTypes; + rtl::Reference< ChartType > xChartType( getChartTypeForNewSeries2(aFormerlyUsedChartTypes)); + if( ! xChartType.is()) + return; + rtl::Reference< BaseCoordinateSystem > xCooSys = xChartType->createCoordinateSystem2( getDimension()); + if( ! xCooSys.is()) + { + // chart type wants no coordinate systems + xDiagram->setCoordinateSystems( Sequence< Reference< XCoordinateSystem > >()); + return; + } + // #i69680# make grid of first y-axis visible (was in the CooSys CTOR before) + if( xCooSys->getDimension() >= 2 ) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( 1, 0 ); + if( xAxis.is()) + AxisHelper::makeGridVisible( xAxis->getGridProperties() ); + } + + std::vector< rtl::Reference< BaseCoordinateSystem > > aCoordinateSystems( + xDiagram->getBaseCoordinateSystems()); + + if( !aCoordinateSystems.empty() ) + { + bool bOk = true; + for( std::size_t i=0; bOk && i<aCoordinateSystems.size(); ++i ) + bOk = bOk && ( xCooSys->getCoordinateSystemType() == aCoordinateSystems[i]->getCoordinateSystemType() && + (xCooSys->getDimension() == aCoordinateSystems[i]->getDimension()) ); + // coordinate systems are ok + if( bOk ) + return; + // there are coordinate systems but they do not fit. So overwrite them. + } + + //copy as much info from former coordinate system as possible: + if( !aCoordinateSystems.empty() ) + { + rtl::Reference< BaseCoordinateSystem > xOldCooSys( aCoordinateSystems[0] ); + sal_Int32 nMaxDimensionCount = std::min( xCooSys->getDimension(), xOldCooSys->getDimension() ); + + for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nMaxDimensionCount; nDimensionIndex++) + { + const sal_Int32 nMaximumAxisIndex = xOldCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) + { + rtl::Reference< Axis > xAxis = xOldCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex ); + if( xAxis.is()) + { + xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex ); + } + } + } + } + + // set new coordinate systems + aCoordinateSystems = { xCooSys }; + + xDiagram->setCoordinateSystems( aCoordinateSystems ); +} + +void ChartTypeTemplate::adaptScales( + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysSeq, + const Reference< data::XLabeledDataSequence > & xCategories //@todo: in future there may be more than one sequence of categories (e.g. charttype with categories at x and y axis ) + ) +{ + bool bSupportsCategories( supportsCategories() ); + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : aCooSysSeq ) + { + try + { + // attach categories to first axis + sal_Int32 nDim( xCooSys->getDimension()); + if( nDim > 0 ) + { + const sal_Int32 nDimensionX = 0; + const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionX); + for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2(nDimensionX,nI); + if( xAxis.is()) + { + ScaleData aData( xAxis->getScaleData() ); + aData.Categories = xCategories; + if(bSupportsCategories) + { + rtl::Reference< ChartType > xChartType = getChartTypeForNewSeries2({}); + if( aData.AxisType == AxisType::CATEGORY ) + { + aData.ShiftedCategoryPosition = m_aServiceName.indexOf("Column") != -1 || m_aServiceName.indexOf("Bar") != -1 || m_aServiceName.endsWith("Close"); + } + bool bSupportsDates = ::chart::ChartTypeHelper::isSupportingDateAxis( xChartType, nDimensionX ); + if( aData.AxisType != AxisType::CATEGORY && ( aData.AxisType != AxisType::DATE || !bSupportsDates) ) + { + aData.AxisType = AxisType::CATEGORY; + aData.AutoDateAxis = true; + AxisHelper::removeExplicitScaling( aData ); + } + } + else + aData.AxisType = AxisType::REALNUMBER; + + xAxis->setScaleData( aData ); + } + } + } + // set percent stacking mode at second axis + if( nDim > 1 ) + { + const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(1); + for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( 1,nI ); + if( xAxis.is()) + { + bool bPercent = (getStackMode(0) == StackMode::YStackedPercent); + chart2::ScaleData aScaleData = xAxis->getScaleData(); + + if( bPercent != (aScaleData.AxisType==AxisType::PERCENT) ) + { + if( bPercent ) + aScaleData.AxisType = AxisType::PERCENT; + else + aScaleData.AxisType = AxisType::REALNUMBER; + xAxis->setScaleData( aScaleData ); + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +void ChartTypeTemplate::adaptDiagram( const rtl::Reference< ::chart::Diagram > & /* xDiagram */ ) +{ +} + +void ChartTypeTemplate::createAxes( + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys ) +{ + //create missing axes + if( rCoordSys.empty() ) + return; + + rtl::Reference< BaseCoordinateSystem > xCooSys( rCoordSys[0] ); + if(!xCooSys.is()) + return; + + //create main axis in first coordinate system + sal_Int32 nDimCount = xCooSys->getDimension(); + sal_Int32 nDim=0; + for( nDim=0; nDim<nDimCount; ++nDim ) + { + sal_Int32 nAxisCount = getAxisCountByDimension( nDim ); + if( nDim == 1 && + nAxisCount < 2 && AxisHelper::isSecondaryYAxisNeeded( xCooSys )) + nAxisCount = 2; + for( sal_Int32 nAxisIndex = 0; nAxisIndex < nAxisCount; ++nAxisIndex ) + { + Reference< XAxis > xAxis = AxisHelper::getAxis( nDim, nAxisIndex, xCooSys ); + if( !xAxis.is()) + { + // create and add axis + xAxis.set( AxisHelper::createAxis( + nDim, nAxisIndex, xCooSys, GetComponentContext() )); + } + } + } +} + +void ChartTypeTemplate::adaptAxes( + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys ) +{ + //adapt properties of existing axes and remove superfluous axes + + if( rCoordSys.empty() ) + return; + + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : rCoordSys ) + { + if( !xCooSys.is() ) + continue; + sal_Int32 nDimCount = xCooSys->getDimension(); + for( sal_Int32 nDim=0; nDim<nDimCount; ++nDim ) + { + sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension( nDim ); + for( sal_Int32 nAxisIndex=0; nAxisIndex<=nMaxAxisIndex; nAxisIndex++ ) + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDim, nAxisIndex, xCooSys ); + if( !xAxis.is() ) + continue; + + if( nAxisIndex == MAIN_AXIS_INDEX || nAxisIndex == SECONDARY_AXIS_INDEX ) + { + // adapt scales + bool bPercent = (getStackMode(0) == StackMode::YStackedPercent); + if( bPercent && nDim == 1 ) + { + // set number format to source format + xAxis->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(true)); + xAxis->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any()); + } + } + } + } + } +} + +sal_Int32 ChartTypeTemplate::getAxisCountByDimension( sal_Int32 nDimension ) +{ + return (nDimension < getDimension()) ? 1 : 0; +} + +void ChartTypeTemplate::FillDiagram( + const rtl::Reference< ::chart::Diagram >& xDiagram, + const std::vector< std::vector< rtl::Reference< DataSeries > > >& aSeriesSeq, + const uno::Reference< chart2::data::XLabeledDataSequence >& xCategories, + const std::vector< rtl::Reference< ChartType > >& aOldChartTypesSeq ) +{ + adaptDiagram( xDiagram ); + + try + { + // create coordinate systems and scales + createCoordinateSystems( xDiagram ); + std::vector< rtl::Reference< BaseCoordinateSystem > > aCoordinateSystems( xDiagram->getBaseCoordinateSystems()); + createAxes( aCoordinateSystems ); + adaptAxes( aCoordinateSystems ); + adaptScales( aCoordinateSystems, xCategories ); + + // chart types + createChartTypes( aSeriesSeq, aCoordinateSystems, aOldChartTypesSeq ); + applyStyles( xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartTypeTemplate::createChartTypes( + const std::vector< std::vector< rtl::Reference< DataSeries > > > & aSeriesSeq, + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > >& aOldChartTypesSeq ) +{ + if( rCoordSys.empty() ) + return; + + try + { + std::size_t nCooSysIdx=0; + rtl::Reference< ChartType > xCT; + if( aSeriesSeq.empty() ) + { + // we need a new chart type + xCT = getChartTypeForNewSeries2( aOldChartTypesSeq ); + rCoordSys[nCooSysIdx]->setChartTypes(std::vector{ xCT }); + } + else + { + for( std::size_t nSeriesIdx=0; nSeriesIdx<aSeriesSeq.size(); ++nSeriesIdx ) + { + if( nSeriesIdx == nCooSysIdx ) + { + // we need a new chart type + xCT = getChartTypeForNewSeries2( aOldChartTypesSeq ); + std::vector< rtl::Reference< ChartType > > aCTSeq( rCoordSys[nCooSysIdx]->getChartTypes2()); + if( !aCTSeq.empty()) + { + aCTSeq[0] = xCT; + rCoordSys[nCooSysIdx]->setChartTypes( aCTSeq ); + } + else + rCoordSys[nCooSysIdx]->addChartType( xCT ); + + xCT->setDataSeries( aSeriesSeq[nSeriesIdx] ); + } + else + { + // reuse existing chart type + OSL_ASSERT( xCT.is()); + std::vector< rtl::Reference< DataSeries > > aNewSeriesSeq = xCT->getDataSeries2(); + sal_Int32 nNewStartIndex = aNewSeriesSeq.size(); + aNewSeriesSeq.resize( nNewStartIndex + aSeriesSeq[nSeriesIdx].size() ); + std::copy( aSeriesSeq[nSeriesIdx].begin(), + aSeriesSeq[nSeriesIdx].end(), + aNewSeriesSeq.begin() + nNewStartIndex ); + xCT->setDataSeries( aNewSeriesSeq ); + } + + // spread the series over the available coordinate systems + if( rCoordSys.size() > (nCooSysIdx + 1) ) + ++nCooSysIdx; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( + const std::vector< rtl::Reference< ChartType > > & rOldChartTypesSeq, + const rtl::Reference< ChartType > & xNewChartType ) +{ + if( !xNewChartType.is() ) + return; + + OUString aNewChartType( xNewChartType->getChartType() ); + + Reference< beans::XPropertySet > xSource; + for( rtl::Reference< ChartType > const & xOldType : rOldChartTypesSeq ) + { + if( xOldType.is() && xOldType->getChartType() == aNewChartType ) + { + xSource = xOldType; + if( xSource.is() ) + break; + } + } + if( xSource.is() ) + comphelper::copyProperties( xSource, xNewChartType ); +} + +css::uno::Reference< css::uno::XInterface > ChartTypeTemplate::getDataInterpreter() +{ + return static_cast<cppu::OWeakObject*>(getDataInterpreter2().get()); +} +css::uno::Reference< css::chart2::XDiagram > ChartTypeTemplate::createDiagramByDataSource( + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) +{ + return createDiagramByDataSource2(xDataSource, aArguments); +} +void ChartTypeTemplate::changeDiagram( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram ) +{ + changeDiagram(rtl::Reference<Diagram>(dynamic_cast<Diagram*>(xDiagram.get()))); +} +void ChartTypeTemplate::changeDiagramData( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram, + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) +{ + changeDiagramData(rtl::Reference<Diagram>(dynamic_cast<Diagram*>(xDiagram.get())), xDataSource, aArguments); +} +sal_Bool ChartTypeTemplate::matchesTemplate( + const css::uno::Reference<css::chart2::XDiagram >& xDiagram, + sal_Bool bAdaptProperties ) +{ + return matchesTemplate2(dynamic_cast<Diagram*>(xDiagram.get()), static_cast<bool>(bAdaptProperties)); +} +css::uno::Reference< ::css::chart2::XChartType > ChartTypeTemplate::getChartTypeForNewSeries( + const css::uno::Sequence< css::uno::Reference< css::chart2::XChartType > >& aFormerlyUsedChartTypes ) +{ + std::vector< rtl::Reference< ::chart::ChartType > > aTmp; + aTmp.reserve(aFormerlyUsedChartTypes.getLength()); + for (auto const & rxChartType : aFormerlyUsedChartTypes) + aTmp.push_back(dynamic_cast<ChartType*>(rxChartType.get())); + return getChartTypeForNewSeries2(aTmp); +} +void ChartTypeTemplate::applyStyle( + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + applyStyle2(dynamic_cast<DataSeries*>(xSeries.get()), nChartTypeIndex, nSeriesIndex, nSeriesCount); +} +void ChartTypeTemplate::resetStyles( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram ) +{ + resetStyles2(dynamic_cast<Diagram*>(xDiagram.get())); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |