diff options
Diffstat (limited to 'chart2/source/model/template/ChartTypeTemplate.cxx')
-rwxr-xr-x | chart2/source/model/template/ChartTypeTemplate.cxx | 932 |
1 files changed, 932 insertions, 0 deletions
diff --git a/chart2/source/model/template/ChartTypeTemplate.cxx b/chart2/source/model/template/ChartTypeTemplate.cxx new file mode 100755 index 000000000000..c922de69a2c7 --- /dev/null +++ b/chart2/source/model/template/ChartTypeTemplate.cxx @@ -0,0 +1,932 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "ChartTypeTemplate.hxx" +#include "PropertyHelper.hxx" +#include "macros.hxx" +#include "DataSeriesHelper.hxx" +#include "DataInterpreter.hxx" +#include "CommonConverters.hxx" +#include "ContainerHelper.hxx" +#include "ChartTypeHelper.hxx" + +#include "CartesianCoordinateSystem.hxx" +#include "AxisHelper.hxx" +#include "LegendHelper.hxx" +#include "DiagramHelper.hxx" +#include "ChartDebugTrace.hxx" +#include "AxisIndexDefines.hxx" +#include <cppuhelper/component_context.hxx> +#include <com/sun/star/chart/ChartSolidType.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/AxisType.hpp> + +#include <algorithm> +#include <iterator> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::rtl::OUString; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +// ====================================================================== + +namespace +{ + +void lcl_applyDefaultStyle( + const Reference< XDataSeries > & xSeries, + sal_Int32 nIndex, + const Reference< XDiagram > & xDiagram ) +{ + // @deprecated: correct default color should be found by view without + // setting color as hard attribute + if( xSeries.is() && xDiagram.is()) + { + Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY ); + Reference< chart2::XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); + if( xSeriesProp.is() && xColorScheme.is() ) + xSeriesProp->setPropertyValue( + C2U("Color"), + uno::makeAny( 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( C2U( "LabelPlacement" ) ) >>= nLabelPlacement) ) + { + bool bValid = false; + for( sal_Int32 nN = 0; nN < rAvailablePlacements.getLength(); nN++ ) + { + if( rAvailablePlacements[nN] == nLabelPlacement ) + { + bValid = true; + break; + } + } + if( !bValid ) + { + uno::Any aNewValue; + //otherwise use the first supported one + if( rAvailablePlacements.getLength() ) + aNewValue <<=rAvailablePlacements[0]; + xProp->setPropertyValue( C2U("LabelPlacement"), aNewValue ); + } + } +} + +void lcl_resetLabelPlacementIfDefault( const Reference< beans::XPropertySet >& xProp, sal_Int32 nDefaultPlacement ) +{ + + sal_Int32 nLabelPlacement=0; + if( xProp.is() && (xProp->getPropertyValue( C2U( "LabelPlacement" ) ) >>= nLabelPlacement) ) + { + if( nDefaultPlacement == nLabelPlacement ) + xProp->setPropertyValue( C2U("LabelPlacement"), uno::Any() ); + } +} + +void lcl_ensureCorrectMissingValueTreatment( const Reference< chart2::XDiagram >& xDiagram, const Reference< XChartType >& xChartType ) +{ + Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY ); + if( xDiaProp.is() ) + { + uno::Sequence < sal_Int32 > aAvailableMissingValueTreatment( + ::chart::ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) ); + + if( aAvailableMissingValueTreatment.getLength() ) + xDiaProp->setPropertyValue( C2U( "MissingValueTreatment" ), uno::makeAny( aAvailableMissingValueTreatment[0] ) ); + else + xDiaProp->setPropertyValue( C2U( "MissingValueTreatment" ), uno::Any() ); + } +} + +} // anonymous namespace + +namespace chart +{ + +ChartTypeTemplate::ChartTypeTemplate( + Reference< uno::XComponentContext > const & xContext, + const ::rtl::OUString & rServiceName ) : + m_xContext( xContext ), + m_aServiceName( rServiceName ) +{ +} + +ChartTypeTemplate::~ChartTypeTemplate() +{} + +// ____ XChartTypeTemplate ____ +uno::Reference< XDiagram > SAL_CALL ChartTypeTemplate::createDiagramByDataSource( + const uno::Reference< data::XDataSource >& xDataSource, + const uno::Sequence< beans::PropertyValue >& aArguments ) + throw (uno::RuntimeException) +{ + Reference< XDiagram > xDia; + + try + { + // create diagram + xDia.set( + GetComponentContext()->getServiceManager()->createInstanceWithContext( + C2U( "com.sun.star.chart2.Diagram" ), + GetComponentContext() ), + uno::UNO_QUERY_THROW ); + + // modify diagram + Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter()); + chart2::InterpretedData aData( + xInterpreter->interpretDataSource( + xDataSource, aArguments, Sequence< Reference< XDataSeries > >() )); + + Sequence< Sequence< Reference< XDataSeries > > > aSeries( aData.Series ); + sal_Int32 i, j, nCount = 0; + for( i=0; i<aSeries.getLength(); ++i ) + { + for( j=0; j<aSeries[i].getLength(); ++j, ++nCount ) + lcl_applyDefaultStyle( aSeries[i][j], nCount, xDia ); + } + + Sequence< Reference< XChartType > > aOldChartTypesSeq; + FillDiagram( xDia, aData.Series, aData.Categories, aOldChartTypesSeq, true ); + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + return xDia; +} + +sal_Bool SAL_CALL ChartTypeTemplate::supportsCategories() + throw (uno::RuntimeException) +{ + return sal_True; +} + +void SAL_CALL ChartTypeTemplate::changeDiagram( const uno::Reference< XDiagram >& xDiagram ) + throw (uno::RuntimeException) +{ + if( ! xDiagram.is()) + return; + + try + { + Sequence< Sequence< Reference< XDataSeries > > > aSeriesSeq( + DiagramHelper::getDataSeriesGroups( xDiagram )); + Sequence< Reference< XDataSeries > > aFlatSeriesSeq( FlattenSequence( aSeriesSeq )); + const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.getLength(); + + // chart-type specific interpretation of existing data series + Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter()); + chart2::InterpretedData aData; + aData.Series = aSeriesSeq; + aData.Categories = DiagramHelper::getCategoriesFromDiagram( xDiagram ); + + if( xInterpreter->isDataCompatible( aData ) ) + { + aData = xInterpreter->reinterpretDataSeries( aData ); + } + else + { + Reference< data::XDataSource > xSource( xInterpreter->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.realloc( 1 ); + aParam[0] = beans::PropertyValue( C2U("HasCategories"), -1, uno::makeAny( true ), + beans::PropertyState_DIRECT_VALUE ); + } + aData = xInterpreter->interpretDataSource( xSource, aParam, aFlatSeriesSeq ); + } + aSeriesSeq = aData.Series; + + sal_Int32 i, j, nIndex = 0; + for( i=0; i<aSeriesSeq.getLength(); ++i ) + for( j=0; j<aSeriesSeq[i].getLength(); ++j, ++nIndex ) + { + if( nIndex >= nFormerSeriesCount ) + lcl_applyDefaultStyle( aSeriesSeq[i][j], nIndex, xDiagram ); + } + + // remove charttype groups from all coordinate systems + Sequence< Reference< XChartType > > aOldChartTypesSeq( + DiagramHelper::getChartTypesFromDiagram(xDiagram) ); + + Reference< XCoordinateSystemContainer > xCoordSysCnt( xDiagram, uno::UNO_QUERY ); + OSL_ASSERT( xCoordSysCnt.is()); + if( xCoordSysCnt.is()) + { + Sequence< Reference< XCoordinateSystem > > aCooSysSeq( + xCoordSysCnt->getCoordinateSystems()); + for( sal_Int32 nCooSysIdx = 0; nCooSysIdx < aCooSysSeq.getLength(); ++nCooSysIdx ) + { + Reference< XChartTypeContainer > xContainer( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY ); + if( xContainer.is() ) + xContainer->setChartTypes( Sequence< Reference< XChartType > >() ); + } + } + + FillDiagram( xDiagram, aSeriesSeq, aData.Categories, aOldChartTypesSeq, false ); + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +void SAL_CALL ChartTypeTemplate::changeDiagramData( + const Reference< chart2::XDiagram >& xDiagram, + const Reference< chart2::data::XDataSource >& xDataSource, + const Sequence< beans::PropertyValue >& aArguments ) + throw (uno::RuntimeException) +{ + if( ! (xDiagram.is() && + xDataSource.is()) ) + return; + + try + { + // interpret new data and re-use existing series + Sequence< Reference< XDataSeries > > aFlatSeriesSeq( + ::chart::ContainerHelper::ContainerToSequence( DiagramHelper::getDataSeriesFromDiagram( xDiagram ))); + const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.getLength(); + Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter()); + chart2::InterpretedData aData = + xInterpreter->interpretDataSource( xDataSource, aArguments, aFlatSeriesSeq ); + + // data series + Sequence< Sequence< Reference< XDataSeries > > > aSeriesSeq( aData.Series ); + + sal_Int32 i, j, nIndex = 0; + for( i=0; i<aSeriesSeq.getLength(); ++i ) + for( j=0; j<aSeriesSeq[i].getLength(); ++j, ++nIndex ) + { + if( nIndex >= nFormerSeriesCount ) + { + lcl_applyDefaultStyle( aSeriesSeq[i][j], nIndex, xDiagram ); + applyStyle( aSeriesSeq[i][j], i, j, aSeriesSeq[i].getLength() ); + } + } + + // categories + DiagramHelper::setCategoriesToDiagram( aData.Categories, xDiagram, true, supportsCategories() ); + + Sequence< Reference< XChartType > > aChartTypes( + DiagramHelper::getChartTypesFromDiagram( xDiagram )); + sal_Int32 nMax = ::std::min( aChartTypes.getLength(), aSeriesSeq.getLength()); + for( i=0; i<nMax; ++i ) + { + Reference< XDataSeriesContainer > xDSCnt( aChartTypes[i], uno::UNO_QUERY_THROW ); + xDSCnt->setDataSeries( aSeriesSeq[i] ); + } +#if OSL_DEBUG_LEVEL >= CHART_TRACE_OSL_DEBUG_LEVEL + OSL_TRACE( "ChartTypeTemplate::changeDiagramData: Showing Diagram structure" ); + OSL_TRACE( "---------------------------------------------------------------" ); + debug::ChartDebugTraceDiagram( xDiagram ); +#endif + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +sal_Bool SAL_CALL ChartTypeTemplate::matchesTemplate( + const Reference< chart2::XDiagram >& xDiagram, + sal_Bool /* bAdaptProperties */ ) + throw (uno::RuntimeException) +{ + sal_Bool bResult = sal_False; + + if( ! xDiagram.is()) + return bResult; + + try + { + Reference< XCoordinateSystemContainer > xCooSysCnt( + xDiagram, uno::UNO_QUERY_THROW ); + Sequence< Reference< XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + + // need to have at least one coordinate system + bResult = (aCooSysSeq.getLength() > 0); + if( bResult ) + { + Sequence< Reference< XChartType > > aFormerlyUsedChartTypes; + const OUString aChartTypeToMatch( getChartTypeForNewSeries(aFormerlyUsedChartTypes)->getChartType()); + const sal_Int32 nDimensionToMatch = getDimension(); + for( sal_Int32 nCooSysIdx=0; bResult && (nCooSysIdx < aCooSysSeq.getLength()); ++nCooSysIdx ) + { + // match dimension + bResult = bResult && (aCooSysSeq[nCooSysIdx]->getDimension() == nDimensionToMatch); + + Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); + Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes()); + for( sal_Int32 nCTIdx=0; bResult && (nCTIdx < aChartTypeSeq.getLength()); ++nCTIdx ) + { + // match chart type + bResult = bResult && aChartTypeSeq[nCTIdx]->getChartType().equals( aChartTypeToMatch ); + bool bFound=false; + bool bAmbiguous=false; + // match stacking mode + bResult = bResult && + ( DiagramHelper::getStackModeFromChartType( + aChartTypeSeq[nCTIdx], bFound, bAmbiguous, + aCooSysSeq[nCooSysIdx] ) + == getStackMode( nCTIdx ) ); + } + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + return bResult; +} + +Reference< chart2::XDataInterpreter > SAL_CALL ChartTypeTemplate::getDataInterpreter() + throw (uno::RuntimeException) +{ + if( ! m_xDataInterpreter.is()) + m_xDataInterpreter.set( new DataInterpreter( GetComponentContext() ) ); + + return m_xDataInterpreter; +} + +void SAL_CALL ChartTypeTemplate::applyStyle( + const Reference< chart2::XDataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 /* nSeriesIndex */, + ::sal_Int32 /* nSeriesCount */ ) + throw (uno::RuntimeException) +{ + // sset stacking mode + Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY ); + if( xSeriesProp.is()) + { + try + { + StackMode eStackMode = getStackMode( nChartTypeIndex ); + const uno::Any aPropValue = uno::makeAny( + ( (eStackMode == StackMode_Y_STACKED) || + (eStackMode == StackMode_Y_STACKED_PERCENT) ) + ? chart2::StackingDirection_Y_STACKING + : (eStackMode == StackMode_Z_STACKED ) + ? chart2::StackingDirection_Z_STACKING + : chart2::StackingDirection_NO_STACKING ); + xSeriesProp->setPropertyValue( C2U("StackingDirection"), aPropValue ); + + //ensure valid label placement + { + uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + getChartTypeForIndex( nChartTypeIndex ), getDimension(), isSwapXAndY(), xSeries ) ); + lcl_ensureCorrectLabelPlacement( xSeriesProp, aAvailablePlacements ); + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + lcl_ensureCorrectLabelPlacement( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), aAvailablePlacements ); + } + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } +} + +void SAL_CALL ChartTypeTemplate::applyStyles( const Reference< chart2::XDiagram >& xDiagram ) + throw (uno::RuntimeException) +{ + // apply chart-type specific styles, like "symbols on" for example + Sequence< Sequence< Reference< XDataSeries > > > aNewSeriesSeq( + DiagramHelper::getDataSeriesGroups( xDiagram )); + for( sal_Int32 i=0; i<aNewSeriesSeq.getLength(); ++i ) + { + const sal_Int32 nNumSeries = aNewSeriesSeq[i].getLength(); + for( sal_Int32 j=0; j<nNumSeries; ++j ) + applyStyle( aNewSeriesSeq[i][j], i, j, nNumSeries ); + } + + //ensure valid empty cell handling (for first chart type...) + lcl_ensureCorrectMissingValueTreatment( xDiagram, getChartTypeForIndex( 0 ) ); +} + +void SAL_CALL ChartTypeTemplate::resetStyles( const Reference< chart2::XDiagram >& xDiagram ) + throw (uno::RuntimeException) +{ + // reset number format if we had percent stacking on + sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT); + if( bPercent ) + { + Sequence< Reference< chart2::XAxis > > aAxisSeq( AxisHelper::getAllAxesOfDiagram( xDiagram ) ); + for( sal_Int32 i=0; i<aAxisSeq.getLength(); ++i ) + { + if( 1== AxisHelper::getDimensionIndexOfAxis( aAxisSeq[i], xDiagram ) ) + { + Reference< beans::XPropertySet > xAxisProp( aAxisSeq[i], uno::UNO_QUERY ); + if( xAxisProp.is()) + { + // set number format to source format + uno::Any aValue( xAxisProp->getPropertyValue(C2U("NumberFormat"))); + if( aValue.hasValue()) + xAxisProp->setPropertyValue(C2U("NumberFormat"), uno::Any()); + } + } + } + } + + //reset label placement if default + { + uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); + if( xCooSysContainer.is() ) + { + uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); + for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS ) + { + uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] ); + + //iterate through all chart types in the current coordinate system + uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY ); + OSL_ASSERT( xChartTypeContainer.is()); + if( !xChartTypeContainer.is() ) + continue; + uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() ); + for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT ) + { + uno::Reference< XChartType > xChartType( aChartTypeList[nT] ); + + //iterate through all series in this chart type + uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY ); + OSL_ASSERT( xDataSeriesContainer.is()); + if( !xDataSeriesContainer.is() ) + continue; + + uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() ); + for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS ) + { + Reference< XDataSeries > xSeries(aSeriesList[nS]); + Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY ); + if(!xSeries.is() || !xSeriesProp.is() ) + continue; + + uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + xChartType, getDimension(), isSwapXAndY(), xSeries ) ); + if(!aAvailablePlacements.getLength()) + continue; + + sal_Int32 nDefaultPlacement = aAvailablePlacements[0]; + + lcl_resetLabelPlacementIfDefault( xSeriesProp, nDefaultPlacement ); + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + lcl_resetLabelPlacementIfDefault( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), nDefaultPlacement ); + } + } + } + } + } + + return; +} + +// ____ XServiceName ____ + ::rtl::OUString SAL_CALL ChartTypeTemplate::getServiceName() + throw (uno::RuntimeException) +{ + 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 Reference< chart2::XCoordinateSystemContainer > & xOutCooSysCnt ) +{ + if( ! xOutCooSysCnt.is()) + return; + Sequence< Reference< XChartType > > aFormerlyUsedChartTypes; + Reference< XChartType > xChartType( getChartTypeForNewSeries(aFormerlyUsedChartTypes)); + if( ! xChartType.is()) + return; + Reference< XCoordinateSystem > xCooSys( xChartType->createCoordinateSystem( getDimension())); + if( ! xCooSys.is()) + { + // chart type wants no coordinate systems + xOutCooSysCnt->setCoordinateSystems( Sequence< Reference< XCoordinateSystem > >()); + return; + } + // #i69680# make grid of first y-axis visible (was in the CooSys CTOR before) + if( xCooSys->getDimension() >= 2 ) + { + Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1, 0 )); + if( xAxis.is()) + AxisHelper::makeGridVisible( xAxis->getGridProperties() ); + } + + Sequence< Reference< XCoordinateSystem > > aCoordinateSystems( + xOutCooSysCnt->getCoordinateSystems()); + + if( aCoordinateSystems.getLength()) + { + bool bOk = true; + for( sal_Int32 i=0; bOk && i<aCoordinateSystems.getLength(); ++i ) + bOk = bOk && ( xCooSys->getCoordinateSystemType().equals( 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.getLength() ) + { + Reference< XCoordinateSystem > 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) + { + uno::Reference< XAxis > xAxis( xOldCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) ); + if( xAxis.is()) + { + xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex ); + } + } + } + } + + // set new coordinate systems + aCoordinateSystems.realloc( 1 ); + aCoordinateSystems[0] = xCooSys; + + xOutCooSysCnt->setCoordinateSystems( aCoordinateSystems ); +} + +void ChartTypeTemplate::adaptScales( + const Sequence< Reference< chart2::XCoordinateSystem > > & 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( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx ) + { + try + { + Reference< XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIdx] ); + if( !xCooSys.is() ) + continue; + + // attach categories to first axis + sal_Int32 nDim( xCooSys->getDimension()); + if( nDim > 0 ) + { + const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(0); + for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI) + { + Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,nI) ); + if( xAxis.is()) + { + ScaleData aData( xAxis->getScaleData() ); + aData.Categories = xCategories; + aData.AxisType = bSupportsCategories ? AxisType::CATEGORY : AxisType::REALNUMBER; + if( bSupportsCategories ) + AxisHelper::removeExplicitScaling( aData ); + 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) + { + Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1,nI )); + if( xAxis.is()) + { + sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT); + 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 & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } +} + +void ChartTypeTemplate::adaptDiagram( const Reference< XDiagram > & /* xDiagram */ ) +{ + return; +} + +void ChartTypeTemplate::createAxes( + const Sequence< Reference< XCoordinateSystem > > & rCoordSys ) +{ + //create missing axes + if( rCoordSys.getLength() > 0 ) + { + sal_Int32 nCooSysIdx = 0; + Reference< XCoordinateSystem > xCooSys( rCoordSys[nCooSysIdx] ); + 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 Sequence< Reference< XCoordinateSystem > > & rCoordSys ) +{ + //adapt properties of exsisting axes and remove superfluous axes + + if( rCoordSys.getLength() > 0 ) + { + for( sal_Int32 nCooSysIdx=0; nCooSysIdx < rCoordSys.getLength(); ++nCooSysIdx ) + { + Reference< XCoordinateSystem > xCooSys( rCoordSys[nCooSysIdx] ); + 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++ ) + { + Reference< XAxis > xAxis( AxisHelper::getAxis( nDim, nAxisIndex, xCooSys ) ); + if( !xAxis.is() ) + continue; + + if( nAxisIndex == MAIN_AXIS_INDEX || nAxisIndex == SECONDARY_AXIS_INDEX ) + { + // adapt scales + sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT); + if( bPercent && nDim == 1 ) + { + Reference< beans::XPropertySet > xAxisProp( xAxis, uno::UNO_QUERY ); + if( xAxisProp.is()) + { + // set number format to source format + uno::Any aValue( xAxisProp->getPropertyValue(C2U("NumberFormat"))); + if( aValue.hasValue()) + xAxisProp->setPropertyValue(C2U("NumberFormat"), uno::Any()); + } + } + } + } + } + } + } +} + +sal_Int32 ChartTypeTemplate::getAxisCountByDimension( sal_Int32 nDimension ) +{ + return (nDimension < getDimension()) ? 1 : 0; +} + +void ChartTypeTemplate::FillDiagram( + const Reference< XDiagram >& xDiagram, + const Sequence< Sequence< Reference< XDataSeries > > >& aSeriesSeq, + Reference< data::XLabeledDataSequence > xCategories, + const Sequence< Reference< XChartType > >& aOldChartTypesSeq, + bool /* bCreate */ ) +{ + adaptDiagram( xDiagram ); + + try + { + // create coordinate systems and scales + Reference< XCoordinateSystemContainer > xCoordSysCnt( xDiagram, uno::UNO_QUERY_THROW ); + createCoordinateSystems( xCoordSysCnt ); + Sequence< Reference< XCoordinateSystem > > aCoordinateSystems( xCoordSysCnt->getCoordinateSystems()); + createAxes( aCoordinateSystems ); + adaptAxes( aCoordinateSystems ); + adaptScales( aCoordinateSystems, xCategories ); + + // chart types + createChartTypes( aSeriesSeq, aCoordinateSystems, aOldChartTypesSeq ); + applyStyles( xDiagram ); + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + +#if OSL_DEBUG_LEVEL >= CHART_TRACE_OSL_DEBUG_LEVEL + OSL_TRACE( "ChartTypeTemplate::FillDiagram: Showing Diagram structure" ); + OSL_TRACE( "---------------------------------------------------------" ); + debug::ChartDebugTraceDiagram( xDiagram ); +#endif +} + +void ChartTypeTemplate::createChartTypes( + const Sequence< Sequence< Reference< XDataSeries > > > & aSeriesSeq, + const Sequence< Reference< XCoordinateSystem > > & rCoordSys, + const Sequence< Reference< XChartType > >& aOldChartTypesSeq ) +{ + if( rCoordSys.getLength() == 0 || + ! rCoordSys[0].is() ) + return; + + try + { + sal_Int32 nCooSysIdx=0; + Reference< XChartType > xCT; + if( aSeriesSeq.getLength() == 0 ) + { + // we need a new chart type + xCT.set( getChartTypeForNewSeries( aOldChartTypesSeq )); + Reference< XChartTypeContainer > xCTCnt( rCoordSys[nCooSysIdx], uno::UNO_QUERY_THROW ); + Sequence< Reference< XChartType > > aCTSeq( xCTCnt->getChartTypes()); + aCTSeq.realloc( 1 ); + aCTSeq[0] = xCT; + xCTCnt->setChartTypes( aCTSeq ); + } + else + { + for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx ) + { + if( nSeriesIdx == nCooSysIdx ) + { + // we need a new chart type + xCT.set( getChartTypeForNewSeries( aOldChartTypesSeq )); + Reference< XChartTypeContainer > xCTCnt( rCoordSys[nCooSysIdx], uno::UNO_QUERY_THROW ); + Sequence< Reference< XChartType > > aCTSeq( xCTCnt->getChartTypes()); + if( aCTSeq.getLength()) + { + aCTSeq[0] = xCT; + xCTCnt->setChartTypes( aCTSeq ); + } + else + xCTCnt->addChartType( xCT ); + + Reference< chart2::XDataSeriesContainer > xDSCnt( xCT, uno::UNO_QUERY_THROW ); + xDSCnt->setDataSeries( aSeriesSeq[nSeriesIdx] ); + } + else + { + // reuse existing chart type + OSL_ASSERT( xCT.is()); + Reference< chart2::XDataSeriesContainer > xDSCnt( xCT, uno::UNO_QUERY_THROW ); + Sequence< Reference< XDataSeries > > aNewSeriesSeq( xDSCnt->getDataSeries()); + sal_Int32 nNewStartIndex = aNewSeriesSeq.getLength(); + aNewSeriesSeq.realloc( nNewStartIndex + aSeriesSeq[nSeriesIdx].getLength() ); + ::std::copy( aSeriesSeq[nSeriesIdx].getConstArray(), + aSeriesSeq[nSeriesIdx].getConstArray() + aSeriesSeq[nSeriesIdx].getLength(), + aNewSeriesSeq.getArray() + nNewStartIndex ); + xDSCnt->setDataSeries( aNewSeriesSeq ); + } + + // spread the series over the available coordinate systems + if( rCoordSys.getLength() > (nCooSysIdx + 1) ) + ++nCooSysIdx; + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +void ChartTypeTemplate::copyPropertiesFromOldToNewCoordianteSystem( + const Sequence< Reference< XChartType > > & rOldChartTypesSeq, + const Reference< XChartType > & xNewChartType ) +{ + Reference< beans::XPropertySet > xDestination( xNewChartType, uno::UNO_QUERY ); + if( !xDestination.is() ) + return; + + OUString aNewChartType( xNewChartType->getChartType() ); + + Reference< beans::XPropertySet > xSource; + sal_Int32 nN=0; + for( nN=0; nN<rOldChartTypesSeq.getLength();++nN) + { + Reference< XChartType > xOldType( rOldChartTypesSeq[nN] ); + if( xOldType.is() && xOldType->getChartType().equals( aNewChartType ) ) + { + xSource.set( Reference< beans::XPropertySet >(xOldType, uno::UNO_QUERY ) ); + if( xSource.is() ) + break; + } + } + if( xSource.is() ) + comphelper::copyProperties( xSource, xDestination ); +} + +// ________ + +Sequence< OUString > ChartTypeTemplate::getSupportedServiceNames_Static() +{ + Sequence< OUString > aServices( 3 ); + aServices[ 0 ] = C2U( "com.sun.star.chart2.ChartTypeTemplate" ); + aServices[ 1 ] = C2U( "com.sun.star.layout.LayoutElement" ); + aServices[ 2 ] = C2U( "com.sun.star.beans.PropertySet" ); + return aServices; +} + +Reference< uno::XComponentContext > ChartTypeTemplate::GetComponentContext() const +{ + return m_xContext; +} + +// ================================================================================ + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +APPHELPER_XSERVICEINFO_IMPL( ChartTypeTemplate, + C2U( "com.sun.star.comp.chart.ChartTypeTemplate" )); +} // namespace chart |