/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include <ErrorBar.hxx> #include <EventListenerHelper.hxx> #include <CloneHelper.hxx> #include <ModifyListenerHelper.hxx> #include <comphelper/sequence.hxx> #include <cppuhelper/supportsservice.hxx> #include <svl/itemprop.hxx> #include <vcl/svapp.hxx> #include <com/sun/star/chart/ErrorBarStyle.hpp> #include <com/sun/star/drawing/LineStyle.hpp> #include <com/sun/star/util/Color.hpp> #include <com/sun/star/drawing/LineJoint.hpp> #include <tools/diagnose_ex.h> #include <sal/log.hxx> using namespace ::com::sun::star; namespace { static const char lcl_aServiceName[] = "com.sun.star.comp.chart2.ErrorBar"; bool lcl_isInternalData( const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq ) { uno::Reference< lang::XServiceInfo > xServiceInfo( xLSeq, uno::UNO_QUERY ); return ( xServiceInfo.is() && xServiceInfo->getImplementationName() == "com.sun.star.comp.chart2.LabeledDataSequence" ); } const SfxItemPropertySet* GetErrorBarPropertySet() { static const SfxItemPropertyMapEntry aErrorBarPropertyMap_Impl[] = { {OUString("ShowPositiveError"),0,cppu::UnoType<bool>::get(), 0, 0}, {OUString("ShowNegativeError"),1,cppu::UnoType<bool>::get(), 0, 0}, {OUString("PositiveError"),2,cppu::UnoType<double>::get(),0,0}, {OUString("NegativeError"),3,cppu::UnoType<double>::get(), 0, 0}, {OUString("PercentageError"),4,cppu::UnoType<double>::get(), 0, 0}, {OUString("ErrorBarStyle"),5,cppu::UnoType<sal_Int32>::get(),0,0}, {OUString("ErrorBarRangePositive"),6,cppu::UnoType<OUString>::get(),0,0}, // read-only for export {OUString("ErrorBarRangeNegative"),7,cppu::UnoType<OUString>::get(),0,0}, // read-only for export {OUString("Weight"),8,cppu::UnoType<double>::get(),0,0}, {OUString("LineStyle"),9,cppu::UnoType<css::drawing::LineStyle>::get(),0,0}, {OUString("LineDash"),10,cppu::UnoType<drawing::LineDash>::get(),0,0}, {OUString("LineWidth"),11,cppu::UnoType<sal_Int32>::get(),0,0}, {OUString("LineColor"),12,cppu::UnoType<css::util::Color>::get(),0,0}, {OUString("LineTransparence"),13,cppu::UnoType<sal_Int16>::get(),0,0}, {OUString("LineJoint"),14,cppu::UnoType<css::drawing::LineJoint>::get(),0,0}, { OUString(), 0, css::uno::Type(), 0, 0 } }; static SfxItemPropertySet aPropSet( aErrorBarPropertyMap_Impl ); return &aPropSet; } } // anonymous namespace namespace chart { ErrorBar::ErrorBar() : mnLineWidth(0), meLineStyle(drawing::LineStyle_SOLID), maLineColor(0), mnLineTransparence(0), meLineJoint(drawing::LineJoint_ROUND), mbShowPositiveError(true), mbShowNegativeError(true), mfPositiveError(0), mfNegativeError(0), mfWeight(1), meStyle(css::chart::ErrorBarStyle::NONE), m_xModifyEventForwarder( ModifyListenerHelper::createModifyEventForwarder()) {} ErrorBar::ErrorBar( const ErrorBar & rOther ) : impl::ErrorBar_Base(rOther), maDashName(rOther.maDashName), maLineDash(rOther.maLineDash), mnLineWidth(rOther.mnLineWidth), meLineStyle(rOther.meLineStyle), maLineColor(rOther.maLineColor), mnLineTransparence(rOther.mnLineTransparence), meLineJoint(rOther.meLineJoint), mbShowPositiveError(rOther.mbShowPositiveError), mbShowNegativeError(rOther.mbShowNegativeError), mfPositiveError(rOther.mfPositiveError), mfNegativeError(rOther.mfNegativeError), mfWeight(rOther.mfWeight), meStyle(rOther.meStyle), m_xModifyEventForwarder( ModifyListenerHelper::createModifyEventForwarder()) { if( ! rOther.m_aDataSequences.empty()) { if( lcl_isInternalData( rOther.m_aDataSequences.front())) CloneHelper::CloneRefVector< css::chart2::data::XLabeledDataSequence >( rOther.m_aDataSequences, m_aDataSequences ); else m_aDataSequences = rOther.m_aDataSequences; ModifyListenerHelper::addListenerToAllElements( m_aDataSequences, m_xModifyEventForwarder ); } } ErrorBar::~ErrorBar() {} uno::Reference< util::XCloneable > SAL_CALL ErrorBar::createClone() { return uno::Reference< util::XCloneable >( new ErrorBar( *this )); } // ____ XPropertySet ____ uno::Reference< beans::XPropertySetInfo > SAL_CALL ErrorBar::getPropertySetInfo() { static uno::Reference< beans::XPropertySetInfo > aRef ( new SfxItemPropertySetInfo( GetErrorBarPropertySet()->getPropertyMap() ) ); return aRef; } void ErrorBar::setPropertyValue( const OUString& rPropName, const uno::Any& rAny ) { SolarMutexGuard aGuard; if(rPropName == "ErrorBarStyle") rAny >>= meStyle; else if(rPropName == "PositiveError") rAny >>= mfPositiveError; else if(rPropName == "PercentageError") { rAny >>= mfPositiveError; rAny >>= mfNegativeError; } else if(rPropName == "Weight") { rAny >>= mfWeight; } else if(rPropName == "NegativeError") rAny >>= mfNegativeError; else if(rPropName == "ShowPositiveError") rAny >>= mbShowPositiveError; else if(rPropName == "ShowNegativeError") rAny >>= mbShowNegativeError; else if(rPropName == "ErrorBarRangePositive" || rPropName == "ErrorBarRangeNegative") throw beans::UnknownPropertyException("read-only property", static_cast< uno::XWeak*>(this)); else if(rPropName == "LineDashName") rAny >>= maDashName; else if(rPropName == "LineDash") rAny >>= maLineDash; else if(rPropName == "LineWidth") rAny >>= mnLineWidth; else if(rPropName == "LineStyle") rAny >>= meLineStyle; else if(rPropName == "LineColor") rAny >>= maLineColor; else if(rPropName == "LineTransparence") rAny >>= mnLineTransparence; else if(rPropName == "LineJoint") rAny >>= meLineJoint; m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); } namespace { OUString getSourceRangeStrFromLabeledSequences( const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aSequences, bool bPositive ) { OUString aDirection; if(bPositive) aDirection = "positive"; else aDirection = "negative"; for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledData : aSequences ) { try { if( labeledData.is()) { uno::Reference< chart2::data::XDataSequence > xSequence( labeledData->getValues()); uno::Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW ); OUString aRole; if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) && aRole.match( "error-bars" ) && aRole.indexOf(aDirection) >= 0 ) { return xSequence->getSourceRangeRepresentation(); } } } catch (uno::Exception const &) { // we can't be sure that this is 100% safe and we don't want to kill the export // we should at least check why the exception is thrown TOOLS_WARN_EXCEPTION("chart2", "unexpected exception"); } catch (...) { // we can't be sure that this is 100% safe and we don't want to kill the export // we should at least check why the exception is thrown SAL_WARN("chart2", "unexpected exception! "); } } return OUString(); } } uno::Any ErrorBar::getPropertyValue(const OUString& rPropName) { SolarMutexGuard aGuard; uno::Any aRet; if(rPropName == "ErrorBarStyle") aRet <<= meStyle; else if(rPropName == "PositiveError") aRet <<= mfPositiveError; else if(rPropName == "NegativeError") aRet <<= mfNegativeError; else if(rPropName == "PercentageError") aRet <<= mfPositiveError; else if(rPropName == "ShowPositiveError") aRet <<= mbShowPositiveError; else if(rPropName == "ShowNegativeError") aRet <<= mbShowNegativeError; else if(rPropName == "Weight") aRet <<= mfWeight; else if(rPropName == "ErrorBarRangePositive") { OUString aRange; if(meStyle == css::chart::ErrorBarStyle::FROM_DATA) { uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences = getDataSequences(); aRange = getSourceRangeStrFromLabeledSequences( aSequences, true ); } aRet <<= aRange; } else if(rPropName == "ErrorBarRangeNegative") { OUString aRange; if(meStyle == css::chart::ErrorBarStyle::FROM_DATA) { uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences = getDataSequences(); aRange = getSourceRangeStrFromLabeledSequences( aSequences, false ); } aRet <<= aRange; } else if(rPropName == "LineDashName") aRet <<= maDashName; else if(rPropName == "LineDash") aRet <<= maLineDash; else if(rPropName == "LineWidth") aRet <<= mnLineWidth; else if(rPropName == "LineStyle") aRet <<= meLineStyle; else if(rPropName == "LineColor") aRet <<= maLineColor; else if(rPropName == "LineTransparence") aRet <<= mnLineTransparence; else if(rPropName == "LineJoint") aRet <<= meLineJoint; SAL_WARN_IF(!aRet.hasValue(), "chart2", "asked for property value: " << rPropName); return aRet; } beans::PropertyState ErrorBar::getPropertyState( const OUString& rPropName ) { if(rPropName == "ErrorBarStyle") { if(meStyle == css::chart::ErrorBarStyle::NONE) return beans::PropertyState_DEFAULT_VALUE; return beans::PropertyState_DIRECT_VALUE; } else if(rPropName == "PositiveError") { if(mbShowPositiveError) { switch(meStyle) { case css::chart::ErrorBarStyle::ABSOLUTE: case css::chart::ErrorBarStyle::ERROR_MARGIN: return beans::PropertyState_DIRECT_VALUE; default: break; } } return beans::PropertyState_DEFAULT_VALUE; } else if(rPropName == "NegativeError") { if(mbShowNegativeError) { switch(meStyle) { case css::chart::ErrorBarStyle::ABSOLUTE: case css::chart::ErrorBarStyle::ERROR_MARGIN: return beans::PropertyState_DIRECT_VALUE; default: break; } } return beans::PropertyState_DEFAULT_VALUE; } else if(rPropName == "PercentageError") { if(meStyle != css::chart::ErrorBarStyle::RELATIVE) return beans::PropertyState_DEFAULT_VALUE; return beans::PropertyState_DIRECT_VALUE; } else if(rPropName == "ShowPositiveError") { // this value should be never default return beans::PropertyState_DIRECT_VALUE; } else if(rPropName == "ShowNegativeError") { // this value should be never default return beans::PropertyState_DIRECT_VALUE; } else if(rPropName == "ErrorBarRangePositive") { if(meStyle == css::chart::ErrorBarStyle::FROM_DATA && mbShowPositiveError) return beans::PropertyState_DIRECT_VALUE; return beans::PropertyState_DEFAULT_VALUE; } else if(rPropName == "ErrorBarRangeNegative") { if(meStyle == css::chart::ErrorBarStyle::FROM_DATA && mbShowNegativeError) return beans::PropertyState_DIRECT_VALUE; return beans::PropertyState_DEFAULT_VALUE; } else return beans::PropertyState_DIRECT_VALUE; } uno::Sequence< beans::PropertyState > ErrorBar::getPropertyStates( const uno::Sequence< OUString >& rPropNames ) { uno::Sequence< beans::PropertyState > aRet( rPropNames.getLength() ); for(sal_Int32 i = 0; i < rPropNames.getLength(); ++i) { aRet[i] = getPropertyState(rPropNames[i]); } return aRet; } void ErrorBar::setPropertyToDefault( const OUString& ) { //keep them unimplemented for now } uno::Any ErrorBar::getPropertyDefault( const OUString& ) { //keep them unimplemented for now return uno::Any(); } void ErrorBar::addPropertyChangeListener( const OUString&, const css::uno::Reference< css::beans::XPropertyChangeListener >& ) { } void ErrorBar::removePropertyChangeListener( const OUString&, const css::uno::Reference< css::beans::XPropertyChangeListener >& ) { } void ErrorBar::addVetoableChangeListener( const OUString&, const css::uno::Reference< css::beans::XVetoableChangeListener >& ) { } void ErrorBar::removeVetoableChangeListener( const OUString&, const css::uno::Reference< css::beans::XVetoableChangeListener >& ) { } // ____ XModifyBroadcaster ____ void SAL_CALL ErrorBar::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) { try { uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW ); xBroadcaster->addModifyListener( aListener ); } catch( const uno::Exception & ) { DBG_UNHANDLED_EXCEPTION("chart2"); } } void SAL_CALL ErrorBar::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) { try { uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW ); xBroadcaster->removeModifyListener( aListener ); } catch( const uno::Exception & ) { DBG_UNHANDLED_EXCEPTION("chart2"); } } // ____ XModifyListener ____ void SAL_CALL ErrorBar::modified( const lang::EventObject& aEvent ) { m_xModifyEventForwarder->modified( aEvent ); } // ____ XEventListener (base of XModifyListener) ____ void SAL_CALL ErrorBar::disposing( const lang::EventObject& /* Source */ ) { // nothing } // ____ XDataSink ____ void SAL_CALL ErrorBar::setData( const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aData ) { ModifyListenerHelper::removeListenerFromAllElements( m_aDataSequences, m_xModifyEventForwarder ); EventListenerHelper::removeListenerFromAllElements( m_aDataSequences, this ); m_aDataSequences = comphelper::sequenceToContainer<tDataSequenceContainer>( aData ); EventListenerHelper::addListenerToAllElements( m_aDataSequences, this ); ModifyListenerHelper::addListenerToAllElements( m_aDataSequences, m_xModifyEventForwarder ); } // ____ XDataSource ____ uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > SAL_CALL ErrorBar::getDataSequences() { return comphelper::containerToSequence( m_aDataSequences ); } OUString SAL_CALL ErrorBar::getImplementationName() { return lcl_aServiceName; } sal_Bool SAL_CALL ErrorBar::supportsService( const OUString& rServiceName ) { return cppu::supportsService(this, rServiceName); } css::uno::Sequence< OUString > SAL_CALL ErrorBar::getSupportedServiceNames() { return { lcl_aServiceName, "com.sun.star.chart2.ErrorBar" }; } // needed by MSC compiler using impl::ErrorBar_Base; } // namespace chart extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_chart2_ErrorBar_get_implementation(css::uno::XComponentContext *, css::uno::Sequence<css::uno::Any> const &) { return cppu::acquire(new ::chart::ErrorBar); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */