diff options
Diffstat (limited to 'chart2/source/tools/DataSeriesHelper.cxx')
-rw-r--r-- | chart2/source/tools/DataSeriesHelper.cxx | 918 |
1 files changed, 918 insertions, 0 deletions
diff --git a/chart2/source/tools/DataSeriesHelper.cxx b/chart2/source/tools/DataSeriesHelper.cxx new file mode 100644 index 000000000000..acff332d4229 --- /dev/null +++ b/chart2/source/tools/DataSeriesHelper.cxx @@ -0,0 +1,918 @@ +/************************************************************************* + * + * 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 "DataSeriesHelper.hxx" +#include "DiagramHelper.hxx" +#include "DataSource.hxx" +#include "macros.hxx" +#include "ContainerHelper.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <com/sun/star/chart2/data/XTextualDataSequence.hpp> +#include <com/sun/star/chart2/StackingDirection.hpp> +#include <com/sun/star/chart2/data/LabelOrigin.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/SymbolStyle.hpp> +#include <com/sun/star/chart2/Symbol.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> + + +#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> +#include <rtl/ustrbuf.hxx> + +#include <functional> +#include <algorithm> +#include <iterator> +#include <vector> +#include <set> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; + +// ---------------------------------------- +namespace +{ + +class lcl_MatchesRole : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool > +{ +public: + explicit lcl_MatchesRole( const OUString & aRole, bool bMatchPrefix ) : + m_aRole( aRole ), + m_bMatchPrefix( bMatchPrefix ) + {} + + bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const + { + if(!xSeq.is()) + return false; + Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY ); + OUString aRole; + + if( m_bMatchPrefix ) + return ( xProp.is() && + (xProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Role" )) ) >>= aRole ) && + aRole.match( m_aRole )); + + return ( xProp.is() && + (xProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Role" )) ) >>= aRole ) && + m_aRole.equals( aRole )); + } + +private: + OUString m_aRole; + bool m_bMatchPrefix; +}; + +Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel( + const Reference< chart2::data::XDataSource > & xDataSource ) +{ + Reference< chart2::data::XLabeledDataSequence > xResult; + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences()); + + for( sal_Int32 i=0; i<aSequences.getLength(); ++i ) + { + OSL_ENSURE( aSequences[i].is(), "empty LabeledDataSequence" ); + // no values are set but a label exists + if( aSequences[i].is() && + ( ! aSequences[i]->getValues().is() && + aSequences[i]->getLabel().is())) + { + xResult.set( aSequences[i] ); + break; + } + } + + return xResult; +} + +void lcl_getCooSysAndChartTypeOfSeries( + const Reference< chart2::XDataSeries > & xSeries, + const Reference< chart2::XDiagram > & xDiagram, + Reference< chart2::XCoordinateSystem > & xOutCooSys, + Reference< chart2::XChartType > & xOutChartType ) +{ + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY ); + if( xCooSysCnt.is()) + { + Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx ) + { + Reference< chart2::XDataSeriesContainer > xSeriesCnt( aChartTypes[nCTIdx], uno::UNO_QUERY ); + if( xSeriesCnt.is()) + { + Sequence< Reference< chart2::XDataSeries > > aSeries( xSeriesCnt->getDataSeries()); + for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeries.getLength(); ++nSeriesIdx ) + { + if( aSeries[nSeriesIdx] == xSeries ) + { + xOutCooSys.set( aCooSysSeq[nCooSysIdx] ); + xOutChartType.set( aChartTypes[nCTIdx] ); + } + } + } + } + } + } +} + +void lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries, bool bInsert ) +{ + try + { + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( xSeriesProperties.is() ) + { + DataPointLabel aLabelAtSeries; + xSeriesProperties->getPropertyValue( C2U( "Label" ) ) >>= aLabelAtSeries; + aLabelAtSeries.ShowNumber = bInsert; + if( !bInsert ) + { + aLabelAtSeries.ShowNumberInPercent = false; + aLabelAtSeries.ShowCategoryName = false; + } + xSeriesProperties->setPropertyValue( C2U( "Label" ), uno::makeAny( aLabelAtSeries ) ); + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if( xPointProp.is() ) + { + DataPointLabel aLabel; + xPointProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel; + aLabel.ShowNumber = bInsert; + if( !bInsert ) + { + aLabel.ShowNumberInPercent = false; + aLabel.ShowCategoryName = false; + } + xPointProp->setPropertyValue( C2U( "Label" ), uno::makeAny( aLabel ) ); + } + } + } + } + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } +} + +} // anonymous namespace +// ---------------------------------------- + +namespace chart +{ + +namespace DataSeriesHelper +{ + +OUString GetRole( const uno::Reference< chart2::data::XLabeledDataSequence >& xLabeledDataSequence ) +{ + OUString aRet; + if( xLabeledDataSequence.is() ) + { + Reference< beans::XPropertySet > xProp( xLabeledDataSequence->getValues(), uno::UNO_QUERY ); + if( xProp.is() ) + xProp->getPropertyValue( C2U("Role") ) >>= aRet; + } + return aRet; +} + +Reference< chart2::data::XLabeledDataSequence > + getDataSequenceByRole( + const Reference< chart2::data::XDataSource > & xSource, OUString aRole, + bool bMatchPrefix /* = false */ ) +{ + Reference< chart2::data::XLabeledDataSequence > aNoResult; + if( ! xSource.is()) + return aNoResult; + Sequence< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq( xSource->getDataSequences()); + + const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray(); + const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength(); + const Reference< chart2::data::XLabeledDataSequence > * pMatch = + ::std::find_if( pBegin, pEnd, lcl_MatchesRole( aRole, bMatchPrefix )); + + if( pMatch != pEnd ) + return *pMatch; + + return aNoResult; +} + +::std::vector< Reference< chart2::data::XLabeledDataSequence > > + getAllDataSequencesByRole( const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aDataSequences, + OUString aRole, bool bMatchPrefix /* = false */ ) +{ + ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aResultVec; + ::std::remove_copy_if( aDataSequences.getConstArray(), aDataSequences.getConstArray() + aDataSequences.getLength(), + ::std::back_inserter( aResultVec ), + ::std::not1( lcl_MatchesRole( aRole, bMatchPrefix ))); + return aResultVec; +} + +Reference< chart2::data::XDataSource > + getDataSource( const Sequence< Reference< chart2::XDataSeries > > & aSeries ) +{ + ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSeqVec; + + for( sal_Int32 i = 0; i < aSeries.getLength(); ++i ) + { + Reference< chart2::data::XDataSource > xSource( aSeries[ i ], uno::UNO_QUERY ); + if( xSource.is()) + { + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences()); + ::std::copy( aSeq.getConstArray(), aSeq.getConstArray() + aSeq.getLength(), + ::std::back_inserter( aSeqVec )); + } + } + + return Reference< chart2::data::XDataSource >( + new DataSource( ContainerHelper::ContainerToSequence( aSeqVec ))); +} + +namespace +{ +OUString lcl_getDataSequenceLabel( const Reference< chart2::data::XDataSequence > & xSequence ) +{ + OUString aResult; + + Reference< chart2::data::XTextualDataSequence > xTextSeq( xSequence, uno::UNO_QUERY ); + if( xTextSeq.is()) + { + Sequence< OUString > aSeq( xTextSeq->getTextualData()); + + const sal_Int32 nMax = aSeq.getLength() - 1; + OUString aVal; + OUStringBuffer aBuf; + + for( sal_Int32 i = 0; i <= nMax; ++i ) + { + aBuf.append( aSeq[i] ); + if( i < nMax ) + aBuf.append( sal_Unicode( ' ' )); + } + aResult = aBuf.makeStringAndClear(); + } + else if( xSequence.is()) + { + Sequence< uno::Any > aSeq( xSequence->getData()); + + const sal_Int32 nMax = aSeq.getLength() - 1; + OUString aVal; + OUStringBuffer aBuf; + double fNum = 0; + + for( sal_Int32 i = 0; i <= nMax; ++i ) + { + if( aSeq[i] >>= aVal ) + { + aBuf.append( aVal ); + if( i < nMax ) + aBuf.append( sal_Unicode( ' ' )); + } + else if( aSeq[ i ] >>= fNum ) + { + aBuf.append( fNum ); + if( i < nMax ) + aBuf.append( sal_Unicode( ' ' )); + } + } + aResult = aBuf.makeStringAndClear(); + } + + return aResult; +} +} + +OUString getLabelForLabeledDataSequence( + const Reference< chart2::data::XLabeledDataSequence > & xLabeledSeq ) +{ + OUString aResult; + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getLabel()); + if( xSeq.is() ) + aResult = lcl_getDataSequenceLabel( xSeq ); + if( !xSeq.is() || !aResult.getLength() ) + { + // no label set or label content is empty -> use auto-generated one + Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() ); + if( xValueSeq.is() ) + { + Sequence< OUString > aLabels( xValueSeq->generateLabel( + chart2::data::LabelOrigin_SHORT_SIDE ) ); + // no labels returned is interpreted as: auto-generation not + // supported by sequence + if( aLabels.getLength() ) + aResult=aLabels[0]; + else + { + //todo?: maybe use the index of the series as name + //but as the index may change it would be better to have such a name persistent + //what is not possible at the moment + //--> maybe use the identifier as part of the name ... + aResult = lcl_getDataSequenceLabel( xValueSeq ); + } + } + } + } + return aResult; +} + +OUString getDataSeriesLabel( + const Reference< chart2::XDataSeries > & xSeries, + const OUString & rLabelSequenceRole ) +{ + OUString aResult; + + Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + ::chart::DataSeriesHelper::getDataSequenceByRole( xSource, rLabelSequenceRole )); + if( xLabeledSeq.is()) + aResult = getLabelForLabeledDataSequence( xLabeledSeq ); + else + { + // special case: labeled data series with only a label and no values may + // serve as label + xLabeledSeq.set( lcl_findLSequenceWithOnlyLabel( xSource )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getLabel()); + if( xSeq.is()) + aResult = lcl_getDataSequenceLabel( xSeq ); + } + } + + } + + return aResult; +} + +void setStackModeAtSeries( + const Sequence< Reference< chart2::XDataSeries > > & aSeries, + const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem, + StackMode eStackMode ) +{ + if( eStackMode == StackMode_AMBIGUOUS ) + return; + + const OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( "StackingDirection" )); + 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 ); + + std::set< sal_Int32 > aAxisIndexSet; + for( sal_Int32 i=0; i<aSeries.getLength(); ++i ) + { + try + { + Reference< beans::XPropertySet > xProp( aSeries[i], uno::UNO_QUERY ); + if( xProp.is() ) + { + xProp->setPropertyValue( aPropName, aPropValue ); + + sal_Int32 nAxisIndex; + xProp->getPropertyValue( C2U("AttachedAxisIndex") ) >>= nAxisIndex; + aAxisIndexSet.insert(nAxisIndex); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } + + if( xCorrespondingCoordinateSystem.is() && + 1 < xCorrespondingCoordinateSystem->getDimension() ) + { + sal_Int32 nAxisIndexCount = aAxisIndexSet.size(); + if( !nAxisIndexCount ) + { + aAxisIndexSet.insert(0); + nAxisIndexCount = aAxisIndexSet.size(); + } + + for( ::std::set< sal_Int32 >::const_iterator aIt = aAxisIndexSet.begin(); + aIt != aAxisIndexSet.end(); ++aIt ) + { + sal_Int32 nAxisIndex = *aIt; + Reference< chart2::XAxis > xAxis( + xCorrespondingCoordinateSystem->getAxisByDimension( 1, nAxisIndex )); + if( xAxis.is()) + { + sal_Bool bPercent = (eStackMode == StackMode_Y_STACKED_PERCENT); + chart2::ScaleData aScaleData = xAxis->getScaleData(); + + if( bPercent != (aScaleData.AxisType==chart2::AxisType::PERCENT) ) + { + if( bPercent ) + aScaleData.AxisType = chart2::AxisType::PERCENT; + else + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + xAxis->setScaleData( aScaleData ); + } + } + } + } +} + +sal_Int32 getAttachedAxisIndex( const Reference< chart2::XDataSeries > & xSeries ) +{ + sal_Int32 nRet = 0; + try + { + Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY ); + if( xProp.is() ) + { + xProp->getPropertyValue( C2U("AttachedAxisIndex") ) >>= nRet; + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + return nRet; +} + +sal_Int32 getNumberFormatKeyFromAxis( + const Reference< chart2::XDataSeries > & xSeries, + const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem, + sal_Int32 nDimensionIndex, + sal_Int32 nAxisIndex /* = -1 */ ) +{ + sal_Int32 nResult = 0; + if( nAxisIndex == -1 ) + nAxisIndex = getAttachedAxisIndex( xSeries ); + try + { + Reference< beans::XPropertySet > xAxisProp( + xCorrespondingCoordinateSystem->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY ); + if( xAxisProp.is()) + xAxisProp->getPropertyValue( C2U("NumberFormat")) >>= nResult; + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + return nResult; +} + +Reference< chart2::XCoordinateSystem > getCoordinateSystemOfSeries( + const Reference< chart2::XDataSeries > & xSeries, + const Reference< chart2::XDiagram > & xDiagram ) +{ + Reference< chart2::XCoordinateSystem > xResult; + Reference< chart2::XChartType > xDummy; + lcl_getCooSysAndChartTypeOfSeries( xSeries, xDiagram, xResult, xDummy ); + + return xResult; +} + +Reference< chart2::XChartType > getChartTypeOfSeries( + const Reference< chart2::XDataSeries > & xSeries, + const Reference< chart2::XDiagram > & xDiagram ) +{ + Reference< chart2::XChartType > xResult; + Reference< chart2::XCoordinateSystem > xDummy; + lcl_getCooSysAndChartTypeOfSeries( xSeries, xDiagram, xDummy, xResult ); + + return xResult; +} + +void deleteSeries( + const Reference< chart2::XDataSeries > & xSeries, + const Reference< chart2::XChartType > & xChartType ) +{ + try + { + Reference< chart2::XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY_THROW ); + ::std::vector< Reference< chart2::XDataSeries > > aSeries( + ContainerHelper::SequenceToVector( xSeriesCnt->getDataSeries())); + ::std::vector< Reference< chart2::XDataSeries > >::iterator aIt = + ::std::find( aSeries.begin(), aSeries.end(), xSeries ); + if( aIt != aSeries.end()) + { + aSeries.erase( aIt ); + xSeriesCnt->setDataSeries( ContainerHelper::ContainerToSequence( aSeries )); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +void switchSymbolsOnOrOff( const Reference< beans::XPropertySet > & xSeriesProperties, + bool bSymbolsOn, sal_Int32 nSeriesIndex ) +{ + if( !xSeriesProperties.is() ) + return; + + chart2::Symbol aSymbProp; + if( (xSeriesProperties->getPropertyValue( C2U( "Symbol" )) >>= aSymbProp ) ) + { + if( !bSymbolsOn ) + aSymbProp.Style = chart2::SymbolStyle_NONE; + else if( aSymbProp.Style == chart2::SymbolStyle_NONE ) + { + aSymbProp.Style = chart2::SymbolStyle_STANDARD; + aSymbProp.StandardSymbol = nSeriesIndex; + } + xSeriesProperties->setPropertyValue( C2U( "Symbol" ), uno::makeAny( aSymbProp )); + } + //todo: check attributed data points +} + +void switchLinesOnOrOff( const Reference< beans::XPropertySet > & xSeriesProperties, bool bLinesOn ) +{ + if( !xSeriesProperties.is() ) + return; + + if( bLinesOn ) + { + // keep line-styles that are not NONE + drawing::LineStyle eLineStyle; + if( (xSeriesProperties->getPropertyValue( C2U( "LineStyle" )) >>= eLineStyle ) && + eLineStyle == drawing::LineStyle_NONE ) + { + xSeriesProperties->setPropertyValue( C2U( "LineStyle" ), uno::makeAny( drawing::LineStyle_SOLID ) ); + } + } + else + xSeriesProperties->setPropertyValue( C2U( "LineStyle" ), uno::makeAny( drawing::LineStyle_NONE ) ); +} + +void makeLinesThickOrThin( const Reference< beans::XPropertySet > & xSeriesProperties, bool bThick ) +{ + if( !xSeriesProperties.is() ) + return; + + sal_Int32 nNewValue = bThick ? 80 : 0; + sal_Int32 nOldValue = 0; + if( (xSeriesProperties->getPropertyValue( C2U( "LineWidth" )) >>= nOldValue ) && + nOldValue != nNewValue ) + { + if( !(bThick && nOldValue>0)) + xSeriesProperties->setPropertyValue( C2U( "LineWidth" ), uno::makeAny( nNewValue ) ); + } +} + +void setPropertyAlsoToAllAttributedDataPoints( const Reference< chart2::XDataSeries >& xSeries, + const OUString& rPropertyName, const uno::Any& rPropertyValue ) +{ + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( !xSeriesProperties.is() ) + return; + + xSeriesProperties->setPropertyValue( rPropertyName, rPropertyValue ); + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if(!xPointProp.is()) + continue; + xPointProp->setPropertyValue( rPropertyName, rPropertyValue ); + } + } +} + +bool hasAttributedDataPointDifferentValue( const Reference< chart2::XDataSeries >& xSeries, + const OUString& rPropertyName, const uno::Any& rPropertyValue ) +{ + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( !xSeriesProperties.is() ) + return false; + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if(!xPointProp.is()) + continue; + uno::Any aPointValue( xPointProp->getPropertyValue( rPropertyName ) ); + if( !( rPropertyValue==aPointValue ) ) + return true; + } + } + return false; +} + +bool areAllSeriesAttachedToSameAxis( const uno::Reference< chart2::XChartType >& xChartType, sal_Int32 & rOutAxisIndex ) +{ + try + { + uno::Reference< chart2::XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDataSeriesContainer->getDataSeries()); + + const sal_Int32 nSeriesCount( aSeriesSeq.getLength()); + // AxisIndex can only be 0 or 1 + sal_Int32 nSeriesAtFirstAxis = 0; + sal_Int32 nSeriesAtSecondAxis = 0; + + for( sal_Int32 nI = 0; nI < nSeriesCount; ++nI ) + { + uno::Reference< chart2::XDataSeries > xSeries( aSeriesSeq[nI], uno::UNO_QUERY ); + sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex( xSeries ); + if( nAxisIndex == 0 ) + ++nSeriesAtFirstAxis; + else if( nAxisIndex == 1 ) + ++nSeriesAtSecondAxis; + } + OSL_ENSURE( nSeriesAtFirstAxis + nSeriesAtSecondAxis == nSeriesCount, "Invalid axis index found" ); + + if( nSeriesAtFirstAxis == nSeriesCount ) + rOutAxisIndex = 0; + else if( nSeriesAtSecondAxis == nSeriesCount ) + rOutAxisIndex = 1; + + return ( nSeriesAtFirstAxis == nSeriesCount || + nSeriesAtSecondAxis == nSeriesCount ); + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + return false; + } +} + +namespace +{ + +bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) +{ + if( !xDataSequence.is() ) + return false; + uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY ); + if( xProp.is() ) + { + uno::Sequence< sal_Int32 > aHiddenValues; + try + { + xProp->getPropertyValue( C2U( "HiddenValues" ) ) >>= aHiddenValues; + if( !aHiddenValues.getLength() ) + return true; + } + catch( uno::Exception& e ) + { + (void)e; // avoid warning + return true; + } + } + if( xDataSequence->getData().getLength() ) + return true; + return false; +} + +} + +bool hasUnhiddenData( const uno::Reference< chart2::XDataSeries >& xSeries ) +{ + uno::Reference< chart2::data::XDataSource > xDataSource = + uno::Reference< chart2::data::XDataSource >( xSeries, uno::UNO_QUERY ); + + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aDataSequences = xDataSource->getDataSequences(); + + for(sal_Int32 nN = aDataSequences.getLength();nN--;) + { + if( !aDataSequences[nN].is() ) + continue; + if( lcl_SequenceHasUnhiddenData( aDataSequences[nN]->getValues() ) ) + return true; + if( lcl_SequenceHasUnhiddenData( aDataSequences[nN]->getLabel() ) ) + return true; + } + return false; +} + +struct lcl_LessIndex +{ + inline bool operator() ( const sal_Int32& first, const sal_Int32& second ) + { + return ( first < second ); + } +}; + +sal_Int32 translateIndexFromHiddenToFullSequence( sal_Int32 nIndex, const Reference< chart2::data::XDataSequence >& xDataSequence, bool bTranslate ) +{ + if( !bTranslate ) + return nIndex; + + try + { + uno::Reference<beans::XPropertySet> xProp( xDataSequence, uno::UNO_QUERY ); + if( xProp.is()) + { + Sequence<sal_Int32> aHiddenIndicesSeq; + xProp->getPropertyValue( C2U("HiddenValues") ) >>= aHiddenIndicesSeq; + if( aHiddenIndicesSeq.getLength() ) + { + ::std::vector< sal_Int32 > aHiddenIndices( ContainerHelper::SequenceToVector( aHiddenIndicesSeq ) ); + ::std::sort( aHiddenIndices.begin(), aHiddenIndices.end(), lcl_LessIndex() ); + + sal_Int32 nHiddenCount = static_cast<sal_Int32>(aHiddenIndices.size()); + for( sal_Int32 nN = 0; nN < nHiddenCount; ++nN) + { + if( aHiddenIndices[nN] <= nIndex ) + nIndex += 1; + else + break; + } + } + } + } + catch (const beans::UnknownPropertyException&) + { + } + return nIndex; +} + +bool hasDataLabelsAtSeries( const Reference< chart2::XDataSeries >& xSeries ) +{ + bool bRet = false; + try + { + Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY ); + if( xProp.is() ) + { + DataPointLabel aLabel; + if( (xProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel) ) + bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent || aLabel.ShowCategoryName; + } + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } + return bRet; +} + +bool hasDataLabelsAtPoints( const Reference< chart2::XDataSeries >& xSeries ) +{ + bool bRet = false; + try + { + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( xSeriesProperties.is() ) + { + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if( xPointProp.is() ) + { + DataPointLabel aLabel; + if( (xPointProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel) ) + bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent || aLabel.ShowCategoryName; + if( bRet ) + break; + } + } + } + } + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } + return bRet; +} + +bool hasDataLabelAtPoint( const Reference< chart2::XDataSeries >& xSeries, sal_Int32 nPointIndex ) +{ + bool bRet = false; + try + { + Reference< beans::XPropertySet > xProp; + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( xSeriesProperties.is() ) + { + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) + { + ::std::vector< sal_Int32 > aIndices( ContainerHelper::SequenceToVector( aAttributedDataPointIndexList ) ); + ::std::vector< sal_Int32 >::iterator aIt = ::std::find( aIndices.begin(), aIndices.end(), nPointIndex ); + if( aIt != aIndices.end()) + xProp = xSeries->getDataPointByIndex(nPointIndex); + else + xProp = xSeriesProperties; + } + if( xProp.is() ) + { + DataPointLabel aLabel; + if( (xProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel) ) + bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent || aLabel.ShowCategoryName; + } + } + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } + return bRet; +} + +void insertDataLabelsToSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries ) +{ + lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( xSeries, true /*bInsert*/ ); +} + +void deleteDataLabelsFromSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries ) +{ + lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( xSeries, false /*bInsert*/ ); +} + + +void insertDataLabelToPoint( const Reference< beans::XPropertySet >& xPointProp ) +{ + try + { + if( xPointProp.is() ) + { + DataPointLabel aLabel; + xPointProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel; + aLabel.ShowNumber = true; + xPointProp->setPropertyValue( C2U( "Label" ), uno::makeAny( aLabel ) ); + } + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } +} + +void deleteDataLabelsFromPoint( const Reference< beans::XPropertySet >& xPointProp ) +{ + try + { + if( xPointProp.is() ) + { + DataPointLabel aLabel; + xPointProp->getPropertyValue( C2U( "Label" ) ) >>= aLabel; + aLabel.ShowNumber = false; + aLabel.ShowNumberInPercent = false; + aLabel.ShowCategoryName = false; + xPointProp->setPropertyValue( C2U( "Label" ), uno::makeAny( aLabel ) ); + } + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } +} + +} // namespace DataSeriesHelper +} // namespace chart |