/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ #include "PieChartTypeTemplate.hxx" #include "macros.hxx" #include "CommonConverters.hxx" #include "DiagramHelper.hxx" #include "servicenames_charttypes.hxx" #include "DataSeriesHelper.hxx" #include "ContainerHelper.hxx" #include "BaseGFXHelper.hxx" #include "AxisHelper.hxx" #include "ThreeDHelper.hxx" #include "PropertyHelper.hxx" #include #include #include #include #include #include #include using namespace ::com::sun::star; using ::rtl::OUString; using ::com::sun::star::beans::Property; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Any; using ::osl::MutexGuard; namespace { static const ::rtl::OUString lcl_aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.PieChartTypeTemplate" )); enum { PROP_PIE_TEMPLATE_DEFAULT_OFFSET, PROP_PIE_TEMPLATE_OFFSET_MODE, PROP_PIE_TEMPLATE_DIMENSION, PROP_PIE_TEMPLATE_USE_RINGS }; void lcl_AddPropertiesToVector( ::std::vector< Property > & rOutProperties ) { rOutProperties.push_back( Property( C2U( "OffsetMode" ), PROP_PIE_TEMPLATE_OFFSET_MODE, ::getCppuType( reinterpret_cast< const chart2::PieChartOffsetMode * >(0)), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::MAYBEDEFAULT )); rOutProperties.push_back( Property( C2U( "DefaultOffset" ), PROP_PIE_TEMPLATE_DEFAULT_OFFSET, ::getCppuType( reinterpret_cast< const double * >(0)), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::MAYBEDEFAULT )); rOutProperties.push_back( Property( C2U( "Dimension" ), PROP_PIE_TEMPLATE_DIMENSION, ::getCppuType( reinterpret_cast< const sal_Int32 * >(0)), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::MAYBEDEFAULT )); rOutProperties.push_back( Property( C2U( "UseRings" ), PROP_PIE_TEMPLATE_USE_RINGS, ::getBooleanCppuType(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::MAYBEDEFAULT )); } struct StaticPieChartTypeTemplateDefaults_Initializer { ::chart::tPropertyValueMap* operator()() { static ::chart::tPropertyValueMap aStaticDefaults; lcl_AddDefaultsToMap( aStaticDefaults ); return &aStaticDefaults; } private: void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) { ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_PIE_TEMPLATE_OFFSET_MODE, chart2::PieChartOffsetMode_NONE ); ::chart::PropertyHelper::setPropertyValueDefault< double >( rOutMap, PROP_PIE_TEMPLATE_DEFAULT_OFFSET, 0.5 ); ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_PIE_TEMPLATE_DIMENSION, 2 ); ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_PIE_TEMPLATE_USE_RINGS, false ); } }; struct StaticPieChartTypeTemplateDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticPieChartTypeTemplateDefaults_Initializer > { }; struct StaticPieChartTypeTemplateInfoHelper_Initializer { ::cppu::OPropertyArrayHelper* operator()() { static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); return &aPropHelper; } private: uno::Sequence< Property > lcl_GetPropertySequence() { ::std::vector< ::com::sun::star::beans::Property > aProperties; lcl_AddPropertiesToVector( aProperties ); ::std::sort( aProperties.begin(), aProperties.end(), ::chart::PropertyNameLess() ); return ::chart::ContainerHelper::ContainerToSequence( aProperties ); } }; struct StaticPieChartTypeTemplateInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticPieChartTypeTemplateInfoHelper_Initializer > { }; struct StaticPieChartTypeTemplateInfo_Initializer { uno::Reference< beans::XPropertySetInfo >* operator()() { static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticPieChartTypeTemplateInfoHelper::get() ) ); return &xPropertySetInfo; } }; struct StaticPieChartTypeTemplateInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticPieChartTypeTemplateInfo_Initializer > { }; } // anonymous namespace namespace chart { PieChartTypeTemplate::PieChartTypeTemplate( uno::Reference< uno::XComponentContext > const & xContext, const ::rtl::OUString & rServiceName, chart2::PieChartOffsetMode eMode, bool bRings /* = false */, sal_Int32 nDim /* = 2 */ ) : ChartTypeTemplate( xContext, rServiceName ), ::property::OPropertySet( m_aMutex ) { setFastPropertyValue_NoBroadcast( PROP_PIE_TEMPLATE_OFFSET_MODE, uno::makeAny( eMode )); setFastPropertyValue_NoBroadcast( PROP_PIE_TEMPLATE_DIMENSION, uno::makeAny( nDim )); setFastPropertyValue_NoBroadcast( PROP_PIE_TEMPLATE_USE_RINGS, uno::makeAny( sal_Bool( bRings ))); } PieChartTypeTemplate::~PieChartTypeTemplate() {} // ____ OPropertySet ____ uno::Any PieChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle ) const throw(beans::UnknownPropertyException) { const tPropertyValueMap& rStaticDefaults = *StaticPieChartTypeTemplateDefaults::get(); tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); if( aFound == rStaticDefaults.end() ) return uno::Any(); return (*aFound).second; } ::cppu::IPropertyArrayHelper & SAL_CALL PieChartTypeTemplate::getInfoHelper() { return *StaticPieChartTypeTemplateInfoHelper::get(); } // ____ XPropertySet ____ uno::Reference< beans::XPropertySetInfo > SAL_CALL PieChartTypeTemplate::getPropertySetInfo() throw (uno::RuntimeException) { return *StaticPieChartTypeTemplateInfo::get(); } // ____ ChartTypeTemplate ____ sal_Int32 PieChartTypeTemplate::getDimension() const { sal_Int32 nDim = 2; try { // note: UNO-methods are never const const_cast< PieChartTypeTemplate * >( this )-> getFastPropertyValue( PROP_PIE_TEMPLATE_DIMENSION ) >>= nDim; } catch( beans::UnknownPropertyException & ex ) { ASSERT_EXCEPTION( ex ); } return nDim; } sal_Int32 PieChartTypeTemplate::getAxisCountByDimension( sal_Int32 /*nDimension*/ ) { return 0; } void PieChartTypeTemplate::adaptAxes( const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > & /*rCoordSys*/ ) { // hide existing axes //hhhh todo } void PieChartTypeTemplate::adaptScales( const Sequence< Reference< chart2::XCoordinateSystem > > & aCooSysSeq, const Reference< chart2::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 ) ) { ChartTypeTemplate::adaptScales( aCooSysSeq, xCategories ); //remove explicit scalings from radius axis //and ensure correct orientation of scales for donuts for( sal_Int32 nCooSysIdx=0; nCooSysIdx xAxis( AxisHelper::getAxis( 1 /*nDimensionIndex*/,0 /*nAxisIndex*/ , aCooSysSeq[nCooSysIdx] ) ); if( xAxis.is() ) { chart2::ScaleData aScaleData( xAxis->getScaleData() ); AxisHelper::removeExplicitScaling( aScaleData ); aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; xAxis->setScaleData( aScaleData ); } xAxis = AxisHelper::getAxis( 0 /*nDimensionIndex*/,0 /*nAxisIndex*/ , aCooSysSeq[nCooSysIdx] ); if( xAxis.is() ) { chart2::ScaleData aScaleData( xAxis->getScaleData() ); aScaleData.Orientation = chart2::AxisOrientation_REVERSE; xAxis->setScaleData( aScaleData ); } } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } } void PieChartTypeTemplate::createChartTypes( const Sequence< Sequence< Reference< chart2::XDataSeries > > > & aSeriesSeq, const Sequence< Reference< chart2::XCoordinateSystem > > & rCoordSys, const Sequence< Reference< chart2::XChartType > >& /* aOldChartTypesSeq */ ) { if( rCoordSys.getLength() == 0 || ! rCoordSys[0].is() ) return; try { Reference< lang::XMultiServiceFactory > xFact( GetComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW ); Reference< chart2::XChartType > xCT( xFact->createInstance( CHART2_SERVICE_NAME_CHARTTYPE_PIE ), uno::UNO_QUERY_THROW ); Reference< beans::XPropertySet > xCTProp( xCT, uno::UNO_QUERY ); if( xCTProp.is()) { xCTProp->setPropertyValue( C2U( "UseRings" ), getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS )); } Reference< chart2::XChartTypeContainer > xCTCnt( rCoordSys[0], uno::UNO_QUERY_THROW ); xCTCnt->setChartTypes( Sequence< Reference< chart2::XChartType > >( &xCT, 1 )); if( aSeriesSeq.getLength() > 0 ) { Reference< chart2::XDataSeriesContainer > xDSCnt( xCT, uno::UNO_QUERY_THROW ); Sequence< Reference< chart2::XDataSeries > > aFlatSeriesSeq( FlattenSequence( aSeriesSeq )); xDSCnt->setDataSeries( aFlatSeriesSeq ); DataSeriesHelper::setStackModeAtSeries( aFlatSeriesSeq, rCoordSys[0], getStackMode( 0 )); } } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } // ____ XChartTypeTemplate ____ sal_Bool SAL_CALL PieChartTypeTemplate::matchesTemplate( const uno::Reference< chart2::XDiagram >& xDiagram, sal_Bool bAdaptProperties ) throw (uno::RuntimeException) { sal_Bool bResult = ChartTypeTemplate::matchesTemplate( xDiagram, bAdaptProperties ); sal_Bool bTemplateUsesRings = sal_False; getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS ) >>= bTemplateUsesRings; chart2::PieChartOffsetMode ePieOffsetMode; getFastPropertyValue( PROP_PIE_TEMPLATE_OFFSET_MODE ) >>= ePieOffsetMode; //check offset-mode if( bResult ) { try { double fOffset=0.0; bool bAllOffsetsEqual = true; ::std::vector< Reference< chart2::XDataSeries > > aSeriesVec( DiagramHelper::getDataSeriesFromDiagram( xDiagram )); //check offset of outer series if( aSeriesVec.size() ) { sal_Int32 nOuterSeriesIndex = 0; //@todo in future this will depend on Orientation of the radius axis scale Reference< chart2::XDataSeries > xSeries( aSeriesVec[nOuterSeriesIndex] ); Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY_THROW ); xProp->getPropertyValue( C2U( "Offset" )) >>= fOffset; //get AttributedDataPoints uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; if( xProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) { for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) { uno::Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); if(xPointProp.is()) { double fPointOffset=0.0; if( (xProp->getPropertyValue( C2U( "Offset" )) >>= fPointOffset ) ) { if( ! ::rtl::math::approxEqual( fPointOffset, fOffset ) ) { bAllOffsetsEqual = false; break; } } } } } } chart2::PieChartOffsetMode eOffsetMode = chart2::PieChartOffsetMode_NONE; if( bAllOffsetsEqual && fOffset > 0.0 ) { eOffsetMode = chart2::PieChartOffsetMode_ALL_EXPLODED; if( bAdaptProperties ) setFastPropertyValue_NoBroadcast( PROP_PIE_TEMPLATE_DEFAULT_OFFSET, uno::makeAny( fOffset )); } bResult = ( eOffsetMode == ePieOffsetMode ); } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); bResult = false; } } //check UseRings if( bResult ) { uno::Reference< beans::XPropertySet > xCTProp( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ), uno::UNO_QUERY_THROW ); sal_Bool bUseRings = false; if( xCTProp->getPropertyValue( C2U( "UseRings" )) >>= bUseRings ) { bResult = ( bTemplateUsesRings == bUseRings ); } } return bResult; } Reference< chart2::XChartType > PieChartTypeTemplate::getChartTypeForIndex( sal_Int32 /*nChartTypeIndex*/ ) { Reference< chart2::XChartType > xResult; try { Reference< lang::XMultiServiceFactory > xFact( GetComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW ); xResult.set( xFact->createInstance( CHART2_SERVICE_NAME_CHARTTYPE_PIE ), uno::UNO_QUERY_THROW ); Reference< beans::XPropertySet > xCTProp( xResult, uno::UNO_QUERY ); if( xCTProp.is()) { xCTProp->setPropertyValue( C2U( "UseRings" ), getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS )); } } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } return xResult; } Reference< chart2::XChartType > SAL_CALL PieChartTypeTemplate::getChartTypeForNewSeries( const uno::Sequence< Reference< chart2::XChartType > >& aFormerlyUsedChartTypes ) throw (uno::RuntimeException) { Reference< chart2::XChartType > xResult; try { Reference< lang::XMultiServiceFactory > xFact( GetComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW ); xResult.set( xFact->createInstance( CHART2_SERVICE_NAME_CHARTTYPE_PIE ), uno::UNO_QUERY_THROW ); ChartTypeTemplate::copyPropertiesFromOldToNewCoordianteSystem( aFormerlyUsedChartTypes, xResult ); Reference< beans::XPropertySet > xCTProp( xResult, uno::UNO_QUERY ); if( xCTProp.is()) { xCTProp->setPropertyValue( C2U( "UseRings" ), getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS )); } } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } return xResult; } void SAL_CALL PieChartTypeTemplate::applyStyle( const Reference< chart2::XDataSeries >& xSeries, ::sal_Int32 nChartTypeIndex, ::sal_Int32 nSeriesIndex, ::sal_Int32 nSeriesCount ) throw (uno::RuntimeException) { ChartTypeTemplate::applyStyle( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); try { uno::Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY_THROW ); sal_Bool bTemplateUsesRings = sal_False; getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS ) >>= bTemplateUsesRings; sal_Int32 nOuterSeriesIndex = 0; //@todo in future this will depend on Orientation of the radius axis scale if( nSeriesIndex == nOuterSeriesIndex ) { const OUString aOffsetPropName( RTL_CONSTASCII_USTRINGPARAM("Offset")); // get offset mode chart2::PieChartOffsetMode ePieOffsetMode; this->getFastPropertyValue( PROP_PIE_TEMPLATE_OFFSET_MODE ) >>= ePieOffsetMode; // get default offset double fDefaultOffset = 0.5; this->getFastPropertyValue( PROP_PIE_TEMPLATE_DEFAULT_OFFSET ) >>= fDefaultOffset; double fOffsetToSet = fDefaultOffset; uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; xProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList; // determine whether to set the new offset bool bSetOffset = ( ePieOffsetMode == chart2::PieChartOffsetMode_ALL_EXPLODED ); if( !bSetOffset && (ePieOffsetMode == chart2::PieChartOffsetMode_NONE) ) { // set offset to 0 if the offset was exactly "all exploded" // before (individual offsets are kept) double fOffset = 0.0; if( (xProp->getPropertyValue( aOffsetPropName ) >>= fOffset) && ::rtl::math::approxEqual( fOffset, fDefaultOffset )) { fOffsetToSet = 0.0; bSetOffset = true; for( sal_Int32 nPtIdx=0; nPtIdx xPointProp( xSeries->getDataPointByIndex( aAttributedDataPointIndexList[ nPtIdx ] )); uno::Reference< beans::XPropertyState > xPointState( xPointProp, uno::UNO_QUERY ); double fPointOffset = 0.0; if( xPointState.is() && (xPointState->getPropertyState( aOffsetPropName ) == beans::PropertyState_DIRECT_VALUE) && xPointProp.is() && (xPointProp->getPropertyValue( aOffsetPropName ) >>= fPointOffset ) && ! ::rtl::math::approxEqual( fPointOffset, fDefaultOffset ) ) { bSetOffset = false; break; } } } } if( bSetOffset ) { // set the offset to the series and to the attributed data points xProp->setPropertyValue( aOffsetPropName, uno::makeAny( fOffsetToSet )); // remove hard attributes from data points for( sal_Int32 nPtIdx=0; nPtIdx xPointState( xSeries->getDataPointByIndex( aAttributedDataPointIndexList[ nPtIdx ] ), uno::UNO_QUERY ); if( xPointState.is()) xPointState->setPropertyToDefault( aOffsetPropName ); } } } // line style DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, C2U( "BorderStyle" ), uno::makeAny( drawing::LineStyle_NONE ) ); // vary colors by point xProp->setPropertyValue( C2U("VaryColorsByPoint"), uno::makeAny( true )); } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } void SAL_CALL PieChartTypeTemplate::resetStyles( const Reference< chart2::XDiagram >& xDiagram ) throw (uno::RuntimeException) { // reset axes and grids Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY ); if( xCooSysCnt.is()) { Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); ChartTypeTemplate::createAxes( aCooSysSeq ); //reset scale orientation for( sal_Int32 nCooSysIdx=0; nCooSysIdx xAxis( AxisHelper::getAxis( 0 /*nDimensionIndex*/,0 /*nAxisIndex*/ , aCooSysSeq[nCooSysIdx] ) ); if( xAxis.is() ) { chart2::ScaleData aScaleData( xAxis->getScaleData() ); aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; xAxis->setScaleData( aScaleData ); } xAxis = AxisHelper::getAxis( 1, 0, aCooSysSeq[nCooSysIdx] ); if( xAxis.is() ) { chart2::ScaleData aScaleData( xAxis->getScaleData() ); aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; xAxis->setScaleData( aScaleData ); } } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } } ChartTypeTemplate::resetStyles( xDiagram ); // vary colors by point, // line style ::std::vector< Reference< chart2::XDataSeries > > aSeriesVec( DiagramHelper::getDataSeriesFromDiagram( xDiagram )); uno::Any aLineStyleAny( uno::makeAny( drawing::LineStyle_NONE )); for( ::std::vector< Reference< chart2::XDataSeries > >::iterator aIt( aSeriesVec.begin()); aIt != aSeriesVec.end(); ++aIt ) { Reference< beans::XPropertyState > xState( *aIt, uno::UNO_QUERY ); if( xState.is()) { xState->setPropertyToDefault( C2U("VaryColorsByPoint")); Reference< beans::XPropertySet > xProp( xState, uno::UNO_QUERY ); if( xProp.is() && xProp->getPropertyValue( C2U("BorderStyle")) == aLineStyleAny ) { xState->setPropertyToDefault( C2U("BorderStyle")); } } } //reset scene properties ThreeDHelper::setDefaultRotation( uno::Reference< beans::XPropertySet >( xDiagram, uno::UNO_QUERY ), false ); } // ____ XChartTypeTemplate ____ void PieChartTypeTemplate::adaptDiagram( const uno::Reference< chart2::XDiagram >& xDiagram ) { if( !xDiagram.is() ) return; //different default for scene geometry: ThreeDHelper::setDefaultRotation( uno::Reference< beans::XPropertySet >( xDiagram, uno::UNO_QUERY ), true ); } // ---------------------------------------- uno::Sequence< ::rtl::OUString > PieChartTypeTemplate::getSupportedServiceNames_Static() { uno::Sequence< ::rtl::OUString > aServices( 2 ); aServices[ 0 ] = lcl_aServiceName; aServices[ 1 ] = C2U( "com.sun.star.chart2.ChartTypeTemplate" ); return aServices; } // implement XServiceInfo methods basing upon getSupportedServiceNames_Static APPHELPER_XSERVICEINFO_IMPL( PieChartTypeTemplate, lcl_aServiceName ); IMPLEMENT_FORWARD_XINTERFACE2( PieChartTypeTemplate, ChartTypeTemplate, OPropertySet ) IMPLEMENT_FORWARD_XTYPEPROVIDER2( PieChartTypeTemplate, ChartTypeTemplate, OPropertySet ) } // namespace chart /* vim:set shiftwidth=4 softtabstop=4 expandtab: */