diff options
Diffstat (limited to 'chart2/source/model/main/DataSeries.cxx')
-rw-r--r-- | chart2/source/model/main/DataSeries.cxx | 351 |
1 files changed, 260 insertions, 91 deletions
diff --git a/chart2/source/model/main/DataSeries.cxx b/chart2/source/model/main/DataSeries.cxx index b873c19650b9..38f2c474b47a 100644 --- a/chart2/source/model/main/DataSeries.cxx +++ b/chart2/source/model/main/DataSeries.cxx @@ -18,20 +18,22 @@ */ #include <DataSeries.hxx> -#include "DataSeriesProperties.hxx" +#include <DataSeriesProperties.hxx> #include "DataPointProperties.hxx" #include <CharacterProperties.hxx> #include <UserDefinedProperties.hxx> #include "DataPoint.hxx" #include <DataSeriesHelper.hxx> #include <CloneHelper.hxx> +#include <RegressionCurveModel.hxx> #include <ModifyListenerHelper.hxx> -#include <EventListenerHelper.hxx> +#include <com/sun/star/chart2/data/XTextualDataSequence.hpp> #include <com/sun/star/container/NoSuchElementException.hpp> #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> #include <cppuhelper/supportsservice.hxx> -#include <tools/diagnose_ex.h> +#include <comphelper/diagnose_ex.hxx> #include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> #include <algorithm> @@ -44,46 +46,43 @@ using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Reference; using ::osl::MutexGuard; -namespace +namespace chart { - -struct StaticDataSeriesDefaults : public rtl::StaticWithInit< ::chart::tPropertyValueMap, StaticDataSeriesDefaults > +const ::chart::tPropertyValueMap & StaticDataSeriesDefaults() { - ::chart::tPropertyValueMap operator()() - { - ::chart::tPropertyValueMap aStaticDefaults; - ::chart::DataSeriesProperties::AddDefaultsToMap( aStaticDefaults ); - ::chart::CharacterProperties::AddDefaultsToMap( aStaticDefaults ); - float fDefaultCharHeight = 10.0; - ::chart::PropertyHelper::setPropertyValue( aStaticDefaults, ::chart::CharacterProperties::PROP_CHAR_CHAR_HEIGHT, fDefaultCharHeight ); - ::chart::PropertyHelper::setPropertyValue( aStaticDefaults, ::chart::CharacterProperties::PROP_CHAR_ASIAN_CHAR_HEIGHT, fDefaultCharHeight ); - ::chart::PropertyHelper::setPropertyValue( aStaticDefaults, ::chart::CharacterProperties::PROP_CHAR_COMPLEX_CHAR_HEIGHT, fDefaultCharHeight ); - return aStaticDefaults; - } + static const ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aMap; + ::chart::DataSeriesProperties::AddDefaultsToMap( aMap ); + ::chart::CharacterProperties::AddDefaultsToMap( aMap ); + float fDefaultCharHeight = 10.0; + ::chart::PropertyHelper::setPropertyValue( aMap, ::chart::CharacterProperties::PROP_CHAR_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( aMap, ::chart::CharacterProperties::PROP_CHAR_ASIAN_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( aMap, ::chart::CharacterProperties::PROP_CHAR_COMPLEX_CHAR_HEIGHT, fDefaultCharHeight ); + return aMap; + }(); + return aStaticDefaults; }; +} // namespace chart -struct StaticDataSeriesInfoHelper : public rtl::StaticWithInit< ::cppu::OPropertyArrayHelper, StaticDataSeriesInfoHelper, StaticDataSeriesInfoHelper, uno::Sequence< Property > > +namespace { - uno::Sequence< Property > operator()() - { - std::vector< css::beans::Property > aProperties; - ::chart::DataSeriesProperties::AddPropertiesToVector( aProperties ); - ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); - ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); - std::sort( aProperties.begin(), aProperties.end(), - ::chart::PropertyNameLess() ); +::cppu::OPropertyArrayHelper& StaticDataSeriesInfoHelper() +{ + static ::cppu::OPropertyArrayHelper oHelper = []() + { + std::vector< css::beans::Property > aProperties; + ::chart::DataSeriesProperties::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); - return comphelper::containerToSequence( aProperties ); - } -}; + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); -struct StaticDataSeriesInfo : public rtl::StaticWithInit< uno::Reference< beans::XPropertySetInfo >, StaticDataSeriesInfo > -{ - uno::Reference< beans::XPropertySetInfo > operator()() - { - return ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDataSeriesInfoHelper::get() ); - } + return comphelper::containerToSequence( aProperties ); + }(); + return oHelper; }; void lcl_SetParent( @@ -127,24 +126,22 @@ namespace chart { DataSeries::DataSeries() : - ::property::OPropertySet( m_aMutex ), - m_xModifyEventForwarder( ModifyListenerHelper::createModifyEventForwarder()) + m_xModifyEventForwarder( new ModifyEventForwarder() ) { } DataSeries::DataSeries( const DataSeries & rOther ) : impl::DataSeries_Base(rOther), - ::property::OPropertySet( rOther, m_aMutex ), - m_xModifyEventForwarder( ModifyListenerHelper::createModifyEventForwarder()) + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) { if( ! rOther.m_aDataSequences.empty()) { - CloneHelper::CloneRefVector<css::chart2::data::XLabeledDataSequence>( - rOther.m_aDataSequences, m_aDataSequences ); + CloneHelper::CloneRefVector(rOther.m_aDataSequences, m_aDataSequences ); ModifyListenerHelper::addListenerToAllElements( m_aDataSequences, m_xModifyEventForwarder ); } - CloneHelper::CloneRefVector< chart2::XRegressionCurve >( rOther.m_aRegressionCurves, m_aRegressionCurves ); + CloneHelper::CloneRefVector( rOther.m_aRegressionCurves, m_aRegressionCurves ); ModifyListenerHelper::addListenerToAllElements( m_aRegressionCurves, m_xModifyEventForwarder ); // add as listener to XPropertySet properties @@ -165,9 +162,6 @@ DataSeries::DataSeries( const DataSeries & rOther ) : // late initialization to call after copy-constructing void DataSeries::Init( const DataSeries & rOther ) { - if( ! rOther.m_aDataSequences.empty()) - EventListenerHelper::addListenerToAllElements( m_aDataSequences, this ); - Reference< uno::XInterface > xThisInterface( static_cast< ::cppu::OWeakObject * >( this )); if( ! rOther.m_aAttributedDataPoints.empty()) { @@ -230,25 +224,28 @@ uno::Reference< util::XCloneable > SAL_CALL DataSeries::createClone() } // ____ OPropertySet ____ -uno::Any DataSeries::GetDefaultValue( sal_Int32 nHandle ) const +void DataSeries::GetDefaultValue( sal_Int32 nHandle, uno::Any& rDest ) const { - const tPropertyValueMap& rStaticDefaults = StaticDataSeriesDefaults::get(); + const tPropertyValueMap& rStaticDefaults = StaticDataSeriesDefaults(); tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); if( aFound == rStaticDefaults.end() ) - return uno::Any(); - return (*aFound).second; + rDest.clear(); + else + rDest = (*aFound).second; } // ____ OPropertySet ____ ::cppu::IPropertyArrayHelper & SAL_CALL DataSeries::getInfoHelper() { - return StaticDataSeriesInfoHelper::get(); + return StaticDataSeriesInfoHelper(); } // ____ XPropertySet ____ uno::Reference< beans::XPropertySetInfo > SAL_CALL DataSeries::getPropertySetInfo() { - return StaticDataSeriesInfo::get(); + static uno::Reference< beans::XPropertySetInfo > xPropSetInfo = + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDataSeriesInfoHelper() ); + return xPropSetInfo; } void SAL_CALL DataSeries::getFastPropertyValue @@ -299,13 +296,13 @@ Reference< beans::XPropertySet > { Reference< beans::XPropertySet > xResult; - Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences; + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences; { MutexGuard aGuard( m_aMutex ); - aSequences = comphelper::containerToSequence( m_aDataSequences ); + aSequences = m_aDataSequences; } - std::vector< Reference< chart2::data::XLabeledDataSequence > > aValuesSeries( + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aValuesSeries( DataSeriesHelper::getAllDataSequencesByRole( aSequences , "values" ) ); if (aValuesSeries.empty()) @@ -387,18 +384,34 @@ void SAL_CALL DataSeries::setData( const uno::Sequence< Reference< chart2::data: tDataSequenceContainer aOldDataSequences; tDataSequenceContainer aNewDataSequences; Reference< util::XModifyListener > xModifyEventForwarder; - Reference< lang::XEventListener > xListener; { MutexGuard aGuard( m_aMutex ); xModifyEventForwarder = m_xModifyEventForwarder; - xListener = this; std::swap( aOldDataSequences, m_aDataSequences ); - aNewDataSequences = comphelper::sequenceToContainer<tDataSequenceContainer>( aData ); + for (const auto & i : aData) + { + aNewDataSequences.push_back(i); + } + m_aDataSequences = aNewDataSequences; + } + ModifyListenerHelper::removeListenerFromAllElements( aOldDataSequences, xModifyEventForwarder ); + ModifyListenerHelper::addListenerToAllElements( aNewDataSequences, xModifyEventForwarder ); + fireModifyEvent(); +} + +void DataSeries::setData( const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > >& aData ) +{ + tDataSequenceContainer aOldDataSequences; + tDataSequenceContainer aNewDataSequences; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + std::swap( aOldDataSequences, m_aDataSequences ); + aNewDataSequences = aData; m_aDataSequences = aNewDataSequences; } ModifyListenerHelper::removeListenerFromAllElements( aOldDataSequences, xModifyEventForwarder ); - EventListenerHelper::removeListenerFromAllElements( aOldDataSequences, xListener ); - EventListenerHelper::addListenerToAllElements( aNewDataSequences, xListener ); ModifyListenerHelper::addListenerToAllElements( aNewDataSequences, xModifyEventForwarder ); fireModifyEvent(); } @@ -407,23 +420,25 @@ void SAL_CALL DataSeries::setData( const uno::Sequence< Reference< chart2::data: Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL DataSeries::getDataSequences() { MutexGuard aGuard( m_aMutex ); - return comphelper::containerToSequence( m_aDataSequences ); + return comphelper::containerToSequence<Reference< chart2::data::XLabeledDataSequence >>( m_aDataSequences ); } // ____ XRegressionCurveContainer ____ void SAL_CALL DataSeries::addRegressionCurve( const uno::Reference< chart2::XRegressionCurve >& xRegressionCurve ) { + auto pRegressionCurve = dynamic_cast<RegressionCurveModel*>(xRegressionCurve.get()); + assert(pRegressionCurve); Reference< util::XModifyListener > xModifyEventForwarder; { MutexGuard aGuard( m_aMutex ); xModifyEventForwarder = m_xModifyEventForwarder; - if( std::find( m_aRegressionCurves.begin(), m_aRegressionCurves.end(), xRegressionCurve ) + if( std::find( m_aRegressionCurves.begin(), m_aRegressionCurves.end(), pRegressionCurve ) != m_aRegressionCurves.end()) throw lang::IllegalArgumentException("curve not found", static_cast<cppu::OWeakObject*>(this), 1); - m_aRegressionCurves.push_back( xRegressionCurve ); + m_aRegressionCurves.push_back( pRegressionCurve ); } - ModifyListenerHelper::addListener( xRegressionCurve, xModifyEventForwarder ); + ModifyListenerHelper::addListener( rtl::Reference<RegressionCurveModel>(pRegressionCurve), xModifyEventForwarder ); fireModifyEvent(); } @@ -432,13 +447,15 @@ void SAL_CALL DataSeries::removeRegressionCurve( { if( !xRegressionCurve.is() ) throw container::NoSuchElementException(); + auto pRegressionCurve = dynamic_cast<RegressionCurveModel*>(xRegressionCurve.get()); + assert(pRegressionCurve); Reference< util::XModifyListener > xModifyEventForwarder; { MutexGuard aGuard( m_aMutex ); xModifyEventForwarder = m_xModifyEventForwarder; tRegressionCurveContainerType::iterator aIt( - std::find( m_aRegressionCurves.begin(), m_aRegressionCurves.end(), xRegressionCurve ) ); + std::find( m_aRegressionCurves.begin(), m_aRegressionCurves.end(), pRegressionCurve ) ); if( aIt == m_aRegressionCurves.end()) throw container::NoSuchElementException( "The given regression curve is no element of this series", @@ -446,21 +463,27 @@ void SAL_CALL DataSeries::removeRegressionCurve( m_aRegressionCurves.erase( aIt ); } - ModifyListenerHelper::removeListener( xRegressionCurve, xModifyEventForwarder ); + ModifyListenerHelper::removeListener( rtl::Reference<RegressionCurveModel>(pRegressionCurve), xModifyEventForwarder ); fireModifyEvent(); } uno::Sequence< uno::Reference< chart2::XRegressionCurve > > SAL_CALL DataSeries::getRegressionCurves() { MutexGuard aGuard( m_aMutex ); - return comphelper::containerToSequence( m_aRegressionCurves ); + return comphelper::containerToSequence<uno::Reference< chart2::XRegressionCurve >>( m_aRegressionCurves ); } void SAL_CALL DataSeries::setRegressionCurves( const Sequence< Reference< chart2::XRegressionCurve > >& aRegressionCurves ) { tRegressionCurveContainerType aOldCurves; - auto aNewCurves( comphelper::sequenceToContainer<tRegressionCurveContainerType>( aRegressionCurves ) ); + tRegressionCurveContainerType aNewCurves; + for (const auto & i : aRegressionCurves) + { + auto pRegressionCurve = dynamic_cast<RegressionCurveModel*>(i.get()); + assert(pRegressionCurve); + aNewCurves.push_back(pRegressionCurve); + } Reference< util::XModifyListener > xModifyEventForwarder; { MutexGuard aGuard( m_aMutex ); @@ -476,28 +499,12 @@ void SAL_CALL DataSeries::setRegressionCurves( // ____ XModifyBroadcaster ____ void SAL_CALL DataSeries::addModifyListener( const Reference< util::XModifyListener >& aListener ) { - try - { - Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW ); - xBroadcaster->addModifyListener( aListener ); - } - catch( const uno::Exception & ) - { - DBG_UNHANDLED_EXCEPTION("chart2"); - } + m_xModifyEventForwarder->addModifyListener( aListener ); } void SAL_CALL DataSeries::removeModifyListener( const Reference< util::XModifyListener >& aListener ) { - try - { - Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW ); - xBroadcaster->removeModifyListener( aListener ); - } - catch( const uno::Exception & ) - { - DBG_UNHANDLED_EXCEPTION("chart2"); - } + m_xModifyEventForwarder->removeModifyListener( aListener ); } // ____ XModifyListener ____ @@ -507,13 +514,8 @@ void SAL_CALL DataSeries::modified( const lang::EventObject& aEvent ) } // ____ XEventListener (base of XModifyListener) ____ -void SAL_CALL DataSeries::disposing( const lang::EventObject& rEventObject ) +void SAL_CALL DataSeries::disposing( const lang::EventObject& ) { - // forget disposed data sequences - tDataSequenceContainer::iterator aIt( - std::find( m_aDataSequences.begin(), m_aDataSequences.end(), rEventObject.Source )); - if( aIt != m_aDataSequences.end()) - m_aDataSequences.erase( aIt ); } // ____ OPropertySet ____ @@ -552,6 +554,173 @@ css::uno::Sequence< OUString > SAL_CALL DataSeries::getSupportedServiceNames() "com.sun.star.beans.PropertySet" }; } +static Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & rDataSequences ) +{ + Reference< chart2::data::XLabeledDataSequence > xResult; + + for( auto const & labeledData : rDataSequences ) + { + OSL_ENSURE( labeledData.is(), "empty LabeledDataSequence" ); + // no values are set but a label exists + if( labeledData.is() && + ( ! labeledData->getValues().is() && + labeledData->getLabel().is())) + { + xResult.set( labeledData ); + break; + } + } + + return xResult; +} + +static 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; + OUStringBuffer aBuf; + + for( sal_Int32 i = 0; i <= nMax; ++i ) + { + aBuf.append( aSeq[i] ); + if( i < nMax ) + aBuf.append( ' '); + } + 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( ' '); + } + else if( aSeq[ i ] >>= fNum ) + { + aBuf.append( fNum ); + if( i < nMax ) + aBuf.append( ' '); + } + } + aResult = aBuf.makeStringAndClear(); + } + + return aResult; +} + +static 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.isEmpty() ) + { + // 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.hasElements() ) + 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 DataSeries::getLabelForRole( const OUString & rLabelSequenceRole ) +{ + OUString aResult; + + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + ::chart::DataSeriesHelper::getDataSequenceByRole( this, 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( getDataSequences() )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getLabel()); + if( xSeq.is()) + aResult = lcl_getDataSequenceLabel( xSeq ); + } + } + + return aResult; +} + +static 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( "HiddenValues" ) >>= aHiddenValues; + if( !aHiddenValues.hasElements() ) + return true; + } + catch( const uno::Exception& ) + { + return true; + } + } + return xDataSequence->getData().hasElements(); +} + +bool DataSeries::hasUnhiddenData() +{ + MutexGuard aGuard( m_aMutex ); + + for(uno::Reference< chart2::data::XLabeledDataSequence > const & rDataSequence : m_aDataSequences) + { + if( !rDataSequence.is() ) + continue; + if( lcl_SequenceHasUnhiddenData( rDataSequence->getValues() ) ) + return true; + } + return false; +} + + } // namespace chart extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * |