diff options
Diffstat (limited to 'chart2/source/model/main')
25 files changed, 10045 insertions, 0 deletions
diff --git a/chart2/source/model/main/Axis.cxx b/chart2/source/model/main/Axis.cxx new file mode 100644 index 0000000000..26a6d48368 --- /dev/null +++ b/chart2/source/model/main/Axis.cxx @@ -0,0 +1,601 @@ +/* -*- 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 <Axis.hxx> +#include <GridProperties.hxx> +#include <CharacterProperties.hxx> +#include <LinePropertiesHelper.hxx> +#include <UserDefinedProperties.hxx> +#include <PropertyHelper.hxx> +#include <CloneHelper.hxx> +#include <AxisHelper.hxx> +#include <EventListenerHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <Title.hxx> +#include <unonames.hxx> + +#include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp> +#include <com/sun/star/chart/ChartAxisLabelPosition.hpp> +#include <com/sun/star/chart/ChartAxisMarkPosition.hpp> +#include <com/sun/star/chart/ChartAxisPosition.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <rtl/ref.hxx> + +#include <vector> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans::PropertyAttribute; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; + +namespace +{ + +enum +{ + PROP_AXIS_SHOW, + PROP_AXIS_CROSSOVER_POSITION, + PROP_AXIS_CROSSOVER_VALUE, + PROP_AXIS_DISPLAY_LABELS, + PROP_AXIS_NUMBERFORMAT, + PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, + PROP_AXIS_LABEL_POSITION, + PROP_AXIS_TEXT_ROTATION, + PROP_AXIS_TEXT_BREAK, + PROP_AXIS_TEXT_OVERLAP, + PROP_AXIS_TEXT_STACKED, + PROP_AXIS_TEXT_ARRANGE_ORDER, + PROP_AXIS_REFERENCE_DIAGRAM_SIZE, + + PROP_AXIS_MAJOR_TICKMARKS, + PROP_AXIS_MINOR_TICKMARKS, + PROP_AXIS_MARK_POSITION, + + PROP_AXIS_DISPLAY_UNITS, + PROP_AXIS_BUILTINUNIT, + + PROP_AXIS_TRY_STAGGERING_FIRST, + PROP_AXIS_MAJOR_ORIGIN +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Show", + PROP_AXIS_SHOW, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "CrossoverPosition", + PROP_AXIS_CROSSOVER_POSITION, + cppu::UnoType<css::chart::ChartAxisPosition>::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "CrossoverValue", + PROP_AXIS_CROSSOVER_VALUE, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "DisplayLabels", + PROP_AXIS_DISPLAY_LABELS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_NUMFMT, + PROP_AXIS_NUMBERFORMAT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LINK_TO_SRC_NUMFMT, + PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LabelPosition", + PROP_AXIS_LABEL_POSITION, + cppu::UnoType<css::chart::ChartAxisLabelPosition>::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextRotation", + PROP_AXIS_TEXT_ROTATION, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextBreak", + PROP_AXIS_TEXT_BREAK, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextOverlap", + PROP_AXIS_TEXT_OVERLAP, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "StackCharacters", + PROP_AXIS_TEXT_STACKED, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ArrangeOrder", + PROP_AXIS_TEXT_ARRANGE_ORDER, + cppu::UnoType<css::chart::ChartAxisArrangeOrderType>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_AXIS_REFERENCE_DIAGRAM_SIZE, + cppu::UnoType<awt::Size>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "MajorTickmarks", + PROP_AXIS_MAJOR_TICKMARKS, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MinorTickmarks", + PROP_AXIS_MINOR_TICKMARKS, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MarkPosition", + PROP_AXIS_MARK_POSITION, + cppu::UnoType<css::chart::ChartAxisMarkPosition>::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for display units: + rOutProperties.emplace_back( "DisplayUnits", + PROP_AXIS_DISPLAY_UNITS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for labels: + rOutProperties.emplace_back( "BuiltInUnit", + PROP_AXIS_BUILTINUNIT, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + rOutProperties.emplace_back( "TryStaggeringFirst", + PROP_AXIS_TRY_STAGGERING_FIRST, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MajorOrigin", + PROP_AXIS_MAJOR_ORIGIN, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + +} +} // namespace + +namespace chart +{ +const ::chart::tPropertyValueMap & StaticAxisDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aMap; + ::chart::CharacterProperties::AddDefaultsToMap( aMap ); + ::chart::LinePropertiesHelper::AddDefaultsToMap( aMap ); + + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_SHOW, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_CROSSOVER_POSITION, css::chart::ChartAxisPosition_ZERO ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_DISPLAY_LABELS, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_LABEL_POSITION, css::chart::ChartAxisLabelPosition_NEAR_AXIS ); + ::chart::PropertyHelper::setPropertyValueDefault< double >( aMap, PROP_AXIS_TEXT_ROTATION, 0.0 ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_TEXT_BREAK, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_TEXT_OVERLAP, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_TEXT_STACKED, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_TEXT_ARRANGE_ORDER, css::chart::ChartAxisArrangeOrderType_AUTO ); + + 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 ); + + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_AXIS_MAJOR_TICKMARKS, 2 /* CHAXIS_MARK_OUTER */ ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_AXIS_MINOR_TICKMARKS, 0 /* CHAXIS_MARK_NONE */ ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_MARK_POSITION, css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_DISPLAY_UNITS, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_AXIS_TRY_STAGGERING_FIRST, false ); + return aMap; + }(); + return aStaticDefaults; +}; +} // namespace chart + +namespace +{ +::cppu::OPropertyArrayHelper& StaticAxisInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +std::vector< rtl::Reference< ::chart::GridProperties > > lcl_CloneSubGrids( + const std::vector< rtl::Reference< ::chart::GridProperties > > & rSource ) +{ + std::vector< rtl::Reference< ::chart::GridProperties > > aDestination; + aDestination.reserve( rSource.size()); + for( rtl::Reference< ::chart::GridProperties > const & i : rSource ) + { + aDestination.push_back(new ::chart::GridProperties(*i)); + } + return aDestination; +} + +} // anonymous namespace + +namespace chart +{ + +Axis::Axis() : + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_aScaleData( AxisHelper::createDefaultScale() ), + m_xGrid( new GridProperties() ) +{ + osl_atomic_increment(&m_refCount); + setFastPropertyValue_NoBroadcast( + ::chart::LinePropertiesHelper::PROP_LINE_COLOR, uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30 + + if( m_xGrid.is()) + ModifyListenerHelper::addListener( m_xGrid, m_xModifyEventForwarder ); + if( m_aScaleData.Categories.is()) + ModifyListenerHelper::addListener( m_aScaleData.Categories, m_xModifyEventForwarder ); + + AllocateSubGrids(); + osl_atomic_decrement(&m_refCount); +} + +Axis::Axis( const Axis & rOther ) : + impl::Axis_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_aScaleData( rOther.m_aScaleData ) +{ + if (rOther.m_xGrid) + m_xGrid = new ::chart::GridProperties(*rOther.m_xGrid); + if( m_xGrid.is()) + ModifyListenerHelper::addListener( m_xGrid, m_xModifyEventForwarder ); + + if( m_aScaleData.Categories.is()) + ModifyListenerHelper::addListener( m_aScaleData.Categories, m_xModifyEventForwarder ); + + if( !rOther.m_aSubGridProperties.empty() ) + m_aSubGridProperties = lcl_CloneSubGrids( rOther.m_aSubGridProperties ); + ModifyListenerHelper::addListenerToAllElements( m_aSubGridProperties, m_xModifyEventForwarder ); + + if ( rOther.m_xTitle ) + m_xTitle = new Title( *rOther.m_xTitle ); + if( m_xTitle.is()) + ModifyListenerHelper::addListener( m_xTitle, m_xModifyEventForwarder ); +} + +// late initialization to call after copy-constructing +void Axis::Init() +{ + if( m_aScaleData.Categories.is()) + EventListenerHelper::addListener( m_aScaleData.Categories, this ); +} + +Axis::~Axis() +{ + try + { + ModifyListenerHelper::removeListener( m_xGrid, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListenerFromAllElements( m_aSubGridProperties, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListener( m_xTitle, m_xModifyEventForwarder ); + if( m_aScaleData.Categories.is()) + { + ModifyListenerHelper::removeListener( m_aScaleData.Categories, m_xModifyEventForwarder ); + m_aScaleData.Categories.clear(); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + m_aSubGridProperties.clear(); + m_xGrid = nullptr; + m_xTitle = nullptr; +} + +void Axis::AllocateSubGrids() +{ + Reference< util::XModifyListener > xModifyEventForwarder; + Reference< lang::XEventListener > xEventListener; + std::vector< rtl::Reference< GridProperties > > aOldBroadcasters; + std::vector< rtl::Reference< GridProperties > > aNewBroadcasters; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + xEventListener = this; + + sal_Int32 nNewSubIncCount = m_aScaleData.IncrementData.SubIncrements.getLength(); + sal_Int32 nOldSubIncCount = m_aSubGridProperties.size(); + + if( nOldSubIncCount > nNewSubIncCount ) + { + // remove superfluous entries + for( sal_Int32 i = nNewSubIncCount; i < nOldSubIncCount; ++i ) + aOldBroadcasters.push_back( m_aSubGridProperties[ i ] ); + m_aSubGridProperties.resize( nNewSubIncCount ); + } + else if( nOldSubIncCount < nNewSubIncCount ) + { + m_aSubGridProperties.resize( nNewSubIncCount ); + + // allocate new entries + for( sal_Int32 i = nOldSubIncCount; i < nNewSubIncCount; ++i ) + { + m_aSubGridProperties[ i ] = new GridProperties(); + LinePropertiesHelper::SetLineInvisible( m_aSubGridProperties[ i ] ); + LinePropertiesHelper::SetLineColor( m_aSubGridProperties[ i ], static_cast<sal_Int32>(0xdddddd) ); //gray2 + aNewBroadcasters.push_back( m_aSubGridProperties[ i ] ); + } + } + } + //don't keep the mutex locked while calling out + for (auto const& oldBroadcaster : aOldBroadcasters) + ModifyListenerHelper::removeListener(oldBroadcaster, xModifyEventForwarder ); + for (auto const& newBroadcaster : aNewBroadcasters) + ModifyListenerHelper::addListener( newBroadcaster, xModifyEventForwarder ); +} + +// ____ XAxis ____ +void SAL_CALL Axis::setScaleData( const chart2::ScaleData& rScaleData ) +{ + Reference< util::XModifyListener > xModifyEventForwarder; + Reference< lang::XEventListener > xEventListener; + Reference< chart2::data::XLabeledDataSequence > xOldCategories; + Reference< chart2::data::XLabeledDataSequence > xNewCategories = rScaleData.Categories; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + xEventListener = this; + xOldCategories = m_aScaleData.Categories; + m_aScaleData = rScaleData; + } + AllocateSubGrids(); + + //don't keep the mutex locked while calling out + if( xOldCategories.is() && xOldCategories != xNewCategories ) + { + ModifyListenerHelper::removeListener( xOldCategories, xModifyEventForwarder ); + EventListenerHelper::removeListener( xOldCategories, xEventListener ); + } + if( xNewCategories.is() && xOldCategories != xNewCategories ) + { + ModifyListenerHelper::addListener( xNewCategories, m_xModifyEventForwarder ); + EventListenerHelper::addListener( xNewCategories, xEventListener ); + } + fireModifyEvent(); +} + +chart2::ScaleData SAL_CALL Axis::getScaleData() +{ + MutexGuard aGuard( m_aMutex ); + return m_aScaleData; +} + +Reference< beans::XPropertySet > SAL_CALL Axis::getGridProperties() +{ + MutexGuard aGuard( m_aMutex ); + return m_xGrid; +} +rtl::Reference< ::chart::GridProperties > Axis::getGridProperties2() +{ + MutexGuard aGuard( m_aMutex ); + return m_xGrid; +} +Sequence< Reference< beans::XPropertySet > > SAL_CALL Axis::getSubGridProperties() +{ + MutexGuard aGuard( m_aMutex ); + return comphelper::containerToSequence<Reference< beans::XPropertySet >>(m_aSubGridProperties); +} + +std::vector< rtl::Reference< GridProperties > > Axis::getSubGridProperties2() +{ + MutexGuard aGuard( m_aMutex ); + return m_aSubGridProperties; +} + +Sequence< Reference< beans::XPropertySet > > SAL_CALL Axis::getSubTickProperties() +{ + OSL_FAIL( "Not implemented yet" ); + return Sequence< Reference< beans::XPropertySet > >(); +} + +// ____ XTitled ____ +Reference< chart2::XTitle > SAL_CALL Axis::getTitleObject() +{ + MutexGuard aGuard( m_aMutex ); + return m_xTitle; +} + +rtl::Reference< Title > Axis::getTitleObject2() const +{ + MutexGuard aGuard( m_aMutex ); + return m_xTitle; +} + +void SAL_CALL Axis::setTitleObject( const Reference< chart2::XTitle >& xNewTitle ) +{ + rtl::Reference<Title> xTitle = dynamic_cast<Title*>(xNewTitle.get()); + assert(!xNewTitle || xTitle); + setTitleObject(xTitle); +} + +void Axis::setTitleObject( const rtl::Reference< Title >& xNewTitle ) +{ + Reference< util::XModifyListener > xModifyEventForwarder; + rtl::Reference< Title > xOldTitle; + { + MutexGuard aGuard( m_aMutex ); + xOldTitle = m_xTitle; + xModifyEventForwarder = m_xModifyEventForwarder; + m_xTitle = xNewTitle; + } + + //don't keep the mutex locked while calling out + if( xOldTitle.is() && xOldTitle != xNewTitle ) + ModifyListenerHelper::removeListener( xOldTitle, xModifyEventForwarder ); + if( xNewTitle.is() && xOldTitle != xNewTitle ) + ModifyListenerHelper::addListener( xNewTitle, xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL Axis::createClone() +{ + rtl::Reference<Axis> pNewAxis( new Axis( *this )); + // do initialization that uses uno references to the clone + pNewAxis->Init(); + return pNewAxis; +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Axis::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Axis::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Axis::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Axis::disposing( const lang::EventObject& Source ) +{ + if( Source.Source == m_aScaleData.Categories ) + m_aScaleData.Categories = nullptr; +} + +// ____ OPropertySet ____ +void Axis::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void Axis::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void Axis::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticAxisDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL Axis::getInfoHelper() +{ + return StaticAxisInfoHelper(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL Axis::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticAxisInfoHelper() ) ); + return xPropertySetInfo; +} + +using impl::Axis_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Axis, Axis_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( Axis, Axis_Base, ::property::OPropertySet ) + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL Axis::getImplementationName() +{ + return "com.sun.star.comp.chart2.Axis"; +} + +sal_Bool SAL_CALL Axis::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL Axis::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.Axis", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_Axis_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::Axis); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/BaseCoordinateSystem.cxx b/chart2/source/model/main/BaseCoordinateSystem.cxx new file mode 100644 index 0000000000..8af32fa096 --- /dev/null +++ b/chart2/source/model/main/BaseCoordinateSystem.cxx @@ -0,0 +1,387 @@ +/* -*- 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 <BaseCoordinateSystem.hxx> +#include <PropertyHelper.hxx> +#include <UserDefinedProperties.hxx> +#include <CloneHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <Axis.hxx> +#include <ChartType.hxx> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <o3tl/safeint.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <algorithm> + +#include <com/sun/star/beans/PropertyAttribute.hpp> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ +enum +{ + PROP_COORDINATESYSTEM_SWAPXANDYAXIS +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "SwapXAndYAxis", + PROP_COORDINATESYSTEM_SWAPXANDYAXIS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +const ::chart::tPropertyValueMap & StaticCooSysDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aMap; + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_COORDINATESYSTEM_SWAPXANDYAXIS, false ); + return aMap; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& StaticCooSysInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ + +BaseCoordinateSystem::BaseCoordinateSystem( + sal_Int32 nDimensionCount /* = 2 */ ) : + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_nDimensionCount( nDimensionCount ) + { + m_aAllAxis.resize( m_nDimensionCount ); + for( sal_Int32 nN=0; nN<m_nDimensionCount; nN++ ) + { + m_aAllAxis[nN].resize( 1 ); + rtl::Reference< Axis > xAxis( new Axis ); + m_aAllAxis[nN][0] = xAxis; + + ModifyListenerHelper::addListenerToAllElements( m_aAllAxis[nN], m_xModifyEventForwarder ); + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + if(nN==0) + { + aScaleData.AxisType = chart2::AxisType::CATEGORY; + } + else if( nN==1) + { + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + } + else if( nN==2) + { + aScaleData.AxisType = chart2::AxisType::SERIES; + } + xAxis->setScaleData( aScaleData ); + } + + setFastPropertyValue_NoBroadcast( PROP_COORDINATESYSTEM_SWAPXANDYAXIS, uno::Any( false )); +} + +// explicit +BaseCoordinateSystem::BaseCoordinateSystem( + const BaseCoordinateSystem & rSource ) : + impl::BaseCoordinateSystem_Base(rSource), + ::property::OPropertySet( rSource ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_nDimensionCount( rSource.m_nDimensionCount ) +{ + m_aAllAxis.resize(rSource.m_aAllAxis.size()); + tAxisVecVecType::size_type nN=0; + for( nN=0; nN<m_aAllAxis.size(); nN++ ) + CloneHelper::CloneRefVector( rSource.m_aAllAxis[nN], m_aAllAxis[nN] ); + for (const auto & rxChartType : rSource.m_aChartTypes) + m_aChartTypes.push_back(rxChartType->cloneChartType()); + + for( nN=0; nN<m_aAllAxis.size(); nN++ ) + ModifyListenerHelper::addListenerToAllElements( m_aAllAxis[nN], m_xModifyEventForwarder ); + for (const auto & rxChartType : m_aChartTypes) + rxChartType->addModifyListener( m_xModifyEventForwarder ); +} + +BaseCoordinateSystem::~BaseCoordinateSystem() +{ + try + { + for(const tAxisVecVecType::value_type & i : m_aAllAxis) + ModifyListenerHelper::removeListenerFromAllElements( i, m_xModifyEventForwarder ); + for (const auto & rxChartType : m_aChartTypes) + rxChartType->removeModifyListener( m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +// ____ XCoordinateSystem ____ +sal_Int32 SAL_CALL BaseCoordinateSystem::getDimension() +{ + return m_nDimensionCount; +} + +void SAL_CALL BaseCoordinateSystem::setAxisByDimension( + sal_Int32 nDimensionIndex, + const Reference< chart2::XAxis >& xAxis, + sal_Int32 nIndex ) +{ + if( nDimensionIndex < 0 || nDimensionIndex >= getDimension() ) + throw lang::IndexOutOfBoundsException(); + + if( nIndex < 0 ) + throw lang::IndexOutOfBoundsException(); + + assert(!xAxis || dynamic_cast<Axis*>(xAxis.get())); + + if( m_aAllAxis[ nDimensionIndex ].size() < o3tl::make_unsigned( nIndex+1 )) + { + m_aAllAxis[ nDimensionIndex ].resize( nIndex+1 ); + m_aAllAxis[ nDimensionIndex ][nIndex] = nullptr; + } + + rtl::Reference< Axis > xOldAxis( m_aAllAxis[ nDimensionIndex ][nIndex] ); + if( xOldAxis.is()) + ModifyListenerHelper::removeListener( xOldAxis, m_xModifyEventForwarder ); + m_aAllAxis[ nDimensionIndex ][nIndex] = dynamic_cast<Axis*>(xAxis.get()); + if( xAxis.is()) + ModifyListenerHelper::addListener( xAxis, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +void BaseCoordinateSystem::setAxisByDimension( + sal_Int32 nDimensionIndex, + const rtl::Reference< Axis >& xAxis, + sal_Int32 nIndex ) +{ + if( nDimensionIndex < 0 || nDimensionIndex >= getDimension() ) + throw lang::IndexOutOfBoundsException(); + + if( nIndex < 0 ) + throw lang::IndexOutOfBoundsException(); + + if( m_aAllAxis[ nDimensionIndex ].size() < o3tl::make_unsigned( nIndex+1 )) + { + m_aAllAxis[ nDimensionIndex ].resize( nIndex+1 ); + m_aAllAxis[ nDimensionIndex ][nIndex] = nullptr; + } + + rtl::Reference< Axis > xOldAxis( m_aAllAxis[ nDimensionIndex ][nIndex] ); + if( xOldAxis.is()) + ModifyListenerHelper::removeListener( xOldAxis, m_xModifyEventForwarder ); + m_aAllAxis[ nDimensionIndex ][nIndex] = xAxis; + if( xAxis.is()) + ModifyListenerHelper::addListener( xAxis, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +Reference< chart2::XAxis > SAL_CALL BaseCoordinateSystem::getAxisByDimension( + sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + if( nDimensionIndex < 0 || nDimensionIndex >= getDimension() ) + throw lang::IndexOutOfBoundsException(); + + OSL_ASSERT( m_aAllAxis.size() == static_cast< size_t >( getDimension())); + + if( nAxisIndex < 0 || nAxisIndex > getMaximumAxisIndexByDimension(nDimensionIndex) ) + throw lang::IndexOutOfBoundsException(); + + return m_aAllAxis[ nDimensionIndex ][nAxisIndex]; +} + +const rtl::Reference< Axis > & BaseCoordinateSystem::getAxisByDimension2( + sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + if( nDimensionIndex < 0 || nDimensionIndex >= m_nDimensionCount ) + throw lang::IndexOutOfBoundsException(); + + OSL_ASSERT( m_aAllAxis.size() == static_cast< size_t >( m_nDimensionCount)); + + if( nAxisIndex < 0 || o3tl::make_unsigned(nAxisIndex) > m_aAllAxis[ nDimensionIndex ].size() ) + throw lang::IndexOutOfBoundsException(); + + return m_aAllAxis[ nDimensionIndex ][nAxisIndex]; +} + +sal_Int32 SAL_CALL BaseCoordinateSystem::getMaximumAxisIndexByDimension( sal_Int32 nDimensionIndex ) +{ + if( nDimensionIndex < 0 || nDimensionIndex >= getDimension() ) + throw lang::IndexOutOfBoundsException(); + + OSL_ASSERT( m_aAllAxis.size() == static_cast< size_t >( getDimension())); + + sal_Int32 nRet = m_aAllAxis[ nDimensionIndex ].size(); + if(nRet) + nRet-=1; + + return nRet; +} + +// ____ XChartTypeContainer ____ +void SAL_CALL BaseCoordinateSystem::addChartType( const Reference< chart2::XChartType >& aChartType ) +{ + auto pChartType = dynamic_cast<ChartType*>(aChartType.get()); + assert(pChartType); + + if( std::find( m_aChartTypes.begin(), m_aChartTypes.end(), pChartType ) + != m_aChartTypes.end()) + throw lang::IllegalArgumentException("type not found", static_cast<cppu::OWeakObject*>(this), 1); + + m_aChartTypes.push_back( pChartType ); + ModifyListenerHelper::addListener( aChartType, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +void SAL_CALL BaseCoordinateSystem::removeChartType( const Reference< chart2::XChartType >& aChartType ) +{ + auto pChartType = dynamic_cast<ChartType*>(aChartType.get()); + assert(pChartType); + auto aIt( std::find( m_aChartTypes.begin(), m_aChartTypes.end(), pChartType )); + if( aIt == m_aChartTypes.end()) + throw container::NoSuchElementException( + "The given chart type is no element of the container", + static_cast< uno::XWeak * >( this )); + + m_aChartTypes.erase( aIt ); + ModifyListenerHelper::removeListener( aChartType, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +Sequence< Reference< chart2::XChartType > > SAL_CALL BaseCoordinateSystem::getChartTypes() +{ + return comphelper::containerToSequence< Reference< chart2::XChartType > >( m_aChartTypes ); +} + +void SAL_CALL BaseCoordinateSystem::setChartTypes( const Sequence< Reference< chart2::XChartType > >& aChartTypes ) +{ + for (auto const & aChartType : m_aChartTypes) + aChartType->removeModifyListener( m_xModifyEventForwarder ); + m_aChartTypes.clear(); + for (auto const & aChartType : aChartTypes) + { + auto pChartType = dynamic_cast<ChartType*>(aChartType.get()); + assert(pChartType); + m_aChartTypes.push_back(pChartType); + pChartType->addModifyListener( m_xModifyEventForwarder ); + } + fireModifyEvent(); +} + +void BaseCoordinateSystem::setChartTypes( const std::vector< rtl::Reference< ChartType > >& aChartTypes ) +{ + for (auto const & aChartType : m_aChartTypes) + aChartType->removeModifyListener( m_xModifyEventForwarder ); + m_aChartTypes = aChartTypes; + for (auto const & aChartType : m_aChartTypes) + aChartType->addModifyListener( m_xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL BaseCoordinateSystem::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL BaseCoordinateSystem::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL BaseCoordinateSystem::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL BaseCoordinateSystem::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void BaseCoordinateSystem::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void BaseCoordinateSystem::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void BaseCoordinateSystem::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticCooSysDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL BaseCoordinateSystem::getInfoHelper() +{ + return StaticCooSysInfoHelper(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL BaseCoordinateSystem::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticCooSysInfoHelper() ) ); + return xPropertySetInfo; +} + +using impl::BaseCoordinateSystem_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( BaseCoordinateSystem, BaseCoordinateSystem_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( BaseCoordinateSystem, BaseCoordinateSystem_Base, ::property::OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/CartesianCoordinateSystem.cxx b/chart2/source/model/main/CartesianCoordinateSystem.cxx new file mode 100644 index 0000000000..1f1320d8ae --- /dev/null +++ b/chart2/source/model/main/CartesianCoordinateSystem.cxx @@ -0,0 +1,160 @@ +/* -*- 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 <CartesianCoordinateSystem.hxx> +#include <servicenames_coosystems.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace com::sun::star::uno { class XComponentContext; } + +namespace +{ + +constexpr OUString CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME = u"com.sun.star.chart2.CoordinateSystems.Cartesian"_ustr; + +} + +namespace chart +{ + +// explicit +CartesianCoordinateSystem::CartesianCoordinateSystem( + sal_Int32 nDimensionCount /* = 2 */ ) : + BaseCoordinateSystem( nDimensionCount ) +{} + +CartesianCoordinateSystem::CartesianCoordinateSystem( + const CartesianCoordinateSystem & rSource ) : + BaseCoordinateSystem( rSource ) +{} + +CartesianCoordinateSystem::~CartesianCoordinateSystem() +{} + +// ____ XCoordinateSystem ____ +OUString SAL_CALL CartesianCoordinateSystem::getCoordinateSystemType() +{ + return CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME; +} + +OUString SAL_CALL CartesianCoordinateSystem::getViewServiceName() +{ + return CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME; +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL CartesianCoordinateSystem::createClone() +{ + return Reference< util::XCloneable >( new CartesianCoordinateSystem( *this )); +} + +// ____ XServiceInfo ____ +OUString SAL_CALL CartesianCoordinateSystem::getImplementationName() +{ + return "com.sun.star.comp.chart.CartesianCoordinateSystem"; +} + +sal_Bool SAL_CALL CartesianCoordinateSystem::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CartesianCoordinateSystem::getSupportedServiceNames() +{ + return { CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME }; +} + +// ==== CartesianCoordinateSystem2d ==== + +CartesianCoordinateSystem2d::CartesianCoordinateSystem2d() : + CartesianCoordinateSystem( 2 ) +{} + +CartesianCoordinateSystem2d::~CartesianCoordinateSystem2d() +{} + +// ____ XServiceInfo ____ +OUString SAL_CALL CartesianCoordinateSystem2d::getImplementationName() +{ + return "com.sun.star.comp.chart2.CartesianCoordinateSystem2d"; +} + +sal_Bool SAL_CALL CartesianCoordinateSystem2d::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CartesianCoordinateSystem2d::getSupportedServiceNames() +{ + return { + CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME, + "com.sun.star.chart2.CartesianCoordinateSystem2d" + }; +} + +// ==== CartesianCoordinateSystem3d ==== + +CartesianCoordinateSystem3d::CartesianCoordinateSystem3d() : + CartesianCoordinateSystem( 3 ) +{} + +CartesianCoordinateSystem3d::~CartesianCoordinateSystem3d() +{} + +// ____ XServiceInfo ____ +OUString SAL_CALL CartesianCoordinateSystem3d::getImplementationName() +{ + return "com.sun.star.comp.chart2.CartesianCoordinateSystem3d"; +} + +sal_Bool SAL_CALL CartesianCoordinateSystem3d::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CartesianCoordinateSystem3d::getSupportedServiceNames() +{ + return { + CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME, + "com.sun.star.chart2.CartesianCoordinateSystem3d" + }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_CartesianCoordinateSystem2d_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::CartesianCoordinateSystem2d); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_CartesianCoordinateSystem3d_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::CartesianCoordinateSystem3d); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/ChartModel.cxx b/chart2/source/model/main/ChartModel.cxx new file mode 100644 index 0000000000..19fccff373 --- /dev/null +++ b/chart2/source/model/main/ChartModel.cxx @@ -0,0 +1,1339 @@ +/* -*- 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 <ChartModel.hxx> +#include <ChartTypeManager.hxx> +#include <ChartTypeTemplate.hxx> +#include <servicenames.hxx> +#include <DataSource.hxx> +#include <DataSourceHelper.hxx> +#include <ChartModelHelper.hxx> +#include <DisposeHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <InternalDataProvider.hxx> +#include <ObjectIdentifier.hxx> +#include "PageBackground.hxx" +#include <CloneHelper.hxx> +#include <NameContainer.hxx> +#include "UndoManager.hxx" +#include <ChartView.hxx> +#include <PopupRequest.hxx> +#include <ModifyListenerHelper.hxx> +#include <RangeHighlighter.hxx> +#include <Diagram.hxx> +#include <comphelper/dumpxmltostring.hxx> + +#include <com/sun/star/chart/ChartDataRowSource.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> + +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <svl/numformat.hxx> +#include <svl/numuno.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/embed/EmbedMapUnits.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/document/DocumentProperties.hpp> +#include <com/sun/star/util/CloseVetoException.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> + +#include <sal/log.hxx> +#include <utility> +#include <comphelper/diagnose_ex.hxx> +#include <libxml/xmlwriter.h> + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::osl::MutexGuard; + +using namespace ::com::sun::star; +using namespace ::apphelper; +using namespace ::chart::CloneHelper; + +namespace +{ +constexpr OUString lcl_aGDIMetaFileMIMEType( + u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr); +constexpr OUString lcl_aGDIMetaFileMIMETypeHighContrast( + u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr); + +} // anonymous namespace + +// ChartModel Constructor and Destructor + +namespace chart +{ + +ChartModel::ChartModel(uno::Reference<uno::XComponentContext > xContext) + : m_aLifeTimeManager( this, this ) + , m_bReadOnly( false ) + , m_bModified( false ) + , m_nInLoad(0) + , m_bUpdateNotificationsPending(false) + , mbTimeBased(false) + , m_aControllers( m_aModelMutex ) + , m_nControllerLockCount(0) + , m_xContext(std::move( xContext )) + , m_aVisualAreaSize( ChartModelHelper::getDefaultPageSize() ) + , m_xPageBackground( new PageBackground ) + , m_xXMLNamespaceMap( new NameContainer() ) + , mnStart(0) + , mnEnd(0) +{ + osl_atomic_increment(&m_refCount); + { + m_xOldModelAgg.set( + m_xContext->getServiceManager()->createInstanceWithContext( + CHART_CHARTAPIWRAPPER_SERVICE_NAME, + m_xContext ), uno::UNO_QUERY_THROW ); + m_xOldModelAgg->setDelegator( *this ); + } + + { + m_xPageBackground->addModifyListener( this ); + m_xChartTypeManager = new ::chart::ChartTypeManager( m_xContext ); + } + osl_atomic_decrement(&m_refCount); +} + +ChartModel::ChartModel( const ChartModel & rOther ) + : impl::ChartModel_Base(rOther) + , m_aLifeTimeManager( this, this ) + , m_bReadOnly( rOther.m_bReadOnly ) + , m_bModified( rOther.m_bModified ) + , m_nInLoad(0) + , m_bUpdateNotificationsPending(false) + , mbTimeBased(rOther.mbTimeBased) + , m_aResource( rOther.m_aResource ) + , m_aMediaDescriptor( rOther.m_aMediaDescriptor ) + , m_aControllers( m_aModelMutex ) + , m_nControllerLockCount(0) + , m_xContext( rOther.m_xContext ) + // @note: the old model aggregate must not be shared with other models if it + // is, you get mutex deadlocks + //, m_xOldModelAgg( nullptr ) //rOther.m_xOldModelAgg ) + // m_xStorage( nullptr ) //rOther.m_xStorage ) + , m_aVisualAreaSize( rOther.m_aVisualAreaSize ) + , m_aGraphicObjectVector( rOther.m_aGraphicObjectVector ) + , m_xDataProvider( rOther.m_xDataProvider ) + , m_xInternalDataProvider( rOther.m_xInternalDataProvider ) + , mnStart(rOther.mnStart) + , mnEnd(rOther.mnEnd) +{ + osl_atomic_increment(&m_refCount); + { + m_xOldModelAgg.set( + m_xContext->getServiceManager()->createInstanceWithContext( + CHART_CHARTAPIWRAPPER_SERVICE_NAME, + m_xContext ), uno::UNO_QUERY_THROW ); + m_xOldModelAgg->setDelegator( *this ); + + Reference< util::XModifyListener > xListener; + rtl::Reference< Title > xNewTitle; + if ( rOther.m_xTitle ) + xNewTitle = new Title(*rOther.m_xTitle); + rtl::Reference< ::chart::Diagram > xNewDiagram; + if (rOther.m_xDiagram.is()) + xNewDiagram = new ::chart::Diagram( *rOther.m_xDiagram ); + rtl::Reference< ::chart::PageBackground > xNewPageBackground = new PageBackground( *rOther.m_xPageBackground ); + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager; // does not implement XCloneable + rtl::Reference< ::chart::NameContainer > xXMLNamespaceMap = new NameContainer( *rOther.m_xXMLNamespaceMap ); + + { + MutexGuard aGuard( m_aModelMutex ); + xListener = this; + m_xTitle = xNewTitle; + m_xDiagram = xNewDiagram; + m_xPageBackground = xNewPageBackground; + m_xChartTypeManager = xChartTypeManager; + m_xXMLNamespaceMap = xXMLNamespaceMap; + } + + ModifyListenerHelper::addListener( xNewTitle, xListener ); + if( xNewDiagram && xListener) + xNewDiagram->addModifyListener( xListener ); + if( xNewPageBackground && xListener) + xNewPageBackground->addModifyListener( xListener ); + xListener.clear(); + } + osl_atomic_decrement(&m_refCount); +} + +ChartModel::~ChartModel() +{ + if( m_xOldModelAgg.is()) + m_xOldModelAgg->setDelegator( nullptr ); +} + +void SAL_CALL ChartModel::initialize( const Sequence< Any >& /*rArguments*/ ) +{ + //#i113722# avoid duplicate creation + + //maybe additional todo?: + //support argument "EmbeddedObject"? + //support argument "EmbeddedScriptSupport"? + //support argument "DocumentRecoverySupport"? +} + +ChartView* ChartModel::getChartView() const +{ + return mxChartView.get(); +} + +// private methods + +OUString ChartModel::impl_g_getLocation() +{ + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return OUString(); //behave passive if already disposed or closed or throw exception @todo? + //mutex is acquired + return m_aResource; +} + +bool ChartModel::impl_isControllerConnected( const uno::Reference< frame::XController >& xController ) +{ + try + { + std::vector< uno::Reference<uno::XInterface> > aSeq = m_aControllers.getElements(); + for( const auto & r : aSeq ) + { + if( r == xController ) + return true; + } + } + catch (const uno::Exception&) + { + } + return false; +} + +uno::Reference< frame::XController > ChartModel::impl_getCurrentController() +{ + //@todo? hold only weak references to controllers + + // get the last active controller of this model + if( m_xCurrentController.is() ) + return m_xCurrentController; + + // get the first controller of this model + if( m_aControllers.getLength() ) + { + uno::Reference<uno::XInterface> xI = m_aControllers.getInterface(0); + return uno::Reference<frame::XController>( xI, uno::UNO_QUERY ); + } + + //return nothing if no controllers are connected at all + return uno::Reference< frame::XController > (); +} + +void ChartModel::impl_notifyCloseListeners() +{ + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + if( m_aLifeTimeManager.m_aCloseListeners.getLength(aGuard) ) + { + lang::EventObject aEvent( static_cast< lang::XComponent*>(this) ); + m_aLifeTimeManager.m_aCloseListeners.notifyEach(aGuard, &util::XCloseListener::notifyClosing, aEvent); + } +} + +void ChartModel::impl_adjustAdditionalShapesPositionAndSize( const awt::Size& aVisualAreaSize ) +{ + uno::Reference< beans::XPropertySet > xProperties( static_cast< ::cppu::OWeakObject* >( this ), uno::UNO_QUERY ); + if ( !xProperties.is() ) + return; + + uno::Reference< drawing::XShapes > xShapes; + xProperties->getPropertyValue( "AdditionalShapes" ) >>= xShapes; + if ( !xShapes.is() ) + return; + + sal_Int32 nCount = xShapes->getCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< drawing::XShape > xShape; + if ( xShapes->getByIndex( i ) >>= xShape ) + { + if ( xShape.is() ) + { + awt::Point aPos( xShape->getPosition() ); + awt::Size aSize( xShape->getSize() ); + + double fWidth = static_cast< double >( aVisualAreaSize.Width ) / m_aVisualAreaSize.Width; + double fHeight = static_cast< double >( aVisualAreaSize.Height ) / m_aVisualAreaSize.Height; + + aPos.X = static_cast< tools::Long >( aPos.X * fWidth ); + aPos.Y = static_cast< tools::Long >( aPos.Y * fHeight ); + aSize.Width = static_cast< tools::Long >( aSize.Width * fWidth ); + aSize.Height = static_cast< tools::Long >( aSize.Height * fHeight ); + + xShape->setPosition( aPos ); + xShape->setSize( aSize ); + } + } + } +} + +// lang::XServiceInfo + +OUString SAL_CALL ChartModel::getImplementationName() +{ + return CHART_MODEL_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartModel::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartModel::getSupportedServiceNames() +{ + return { + CHART_MODEL_SERVICE_NAME, + "com.sun.star.document.OfficeDocument", + "com.sun.star.chart.ChartDocument" + }; +} + +// frame::XModel (required interface) + +sal_Bool SAL_CALL ChartModel::attachResource( const OUString& rURL + , const uno::Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + /* + The method attachResource() is used by the frame loader implementations + to inform the model about its URL and MediaDescriptor. + */ + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return false; //behave passive if already disposed or closed or throw exception @todo? + //mutex is acquired + + if(!m_aResource.isEmpty())//we have a resource already //@todo? or is setting a new resource allowed? + return false; + m_aResource = rURL; + m_aMediaDescriptor = rMediaDescriptor; + + //@todo ? check rURL ?? + //@todo ? evaluate m_aMediaDescriptor; + //@todo ? ... ??? --> nothing, this method is only for setting information + + return true; +} + +OUString SAL_CALL ChartModel::getURL() +{ + return impl_g_getLocation(); +} + +uno::Sequence< beans::PropertyValue > SAL_CALL ChartModel::getArgs() +{ + /* + The method getArgs() returns a sequence of property values + that report the resource description according to com.sun.star.document.MediaDescriptor, + specified on loading or saving with storeAsURL. + */ + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return uno::Sequence< beans::PropertyValue >(); //behave passive if already disposed or closed or throw exception @todo? + //mutex is acquired + + return m_aMediaDescriptor; +} + +void SAL_CALL ChartModel::connectController( const uno::Reference< frame::XController >& xController ) +{ + //@todo? this method is declared as oneway -> ...? + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return ; //behave passive if already disposed or closed + //mutex is acquired + + //--add controller + m_aControllers.addInterface(xController); +} + +void SAL_CALL ChartModel::disconnectController( const uno::Reference< frame::XController >& xController ) +{ + //@todo? this method is declared as oneway -> ...? + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return; //behave passive if already disposed or closed + + //--remove controller + m_aControllers.removeInterface(xController); + + //case: current controller is disconnected: + if( m_xCurrentController == xController ) + m_xCurrentController.clear(); + + if (m_xRangeHighlighter) + { + m_xRangeHighlighter->dispose(); + m_xRangeHighlighter.clear(); + } + DisposeHelper::DisposeAndClear(m_xPopupRequest); +} + +void SAL_CALL ChartModel::lockControllers() +{ + /* + suspends some notifications to the controllers which are used for display updates. + + The calls to lockControllers() and unlockControllers() may be nested + and even overlapping, but they must be in pairs. While there is at least one lock + remaining, some notifications for display updates are not broadcasted. + */ + + //@todo? this method is declared as oneway -> ...? + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return; //behave passive if already disposed or closed or throw exception @todo? + ++m_nControllerLockCount; +} + +void SAL_CALL ChartModel::unlockControllers() +{ + /* + resumes the notifications which were suspended by lockControllers() . + + The calls to lockControllers() and unlockControllers() may be nested + and even overlapping, but they must be in pairs. While there is at least one lock + remaining, some notifications for display updates are not broadcasted. + */ + + //@todo? this method is declared as oneway -> ...? + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return; //behave passive if already disposed or closed or throw exception @todo? + if( m_nControllerLockCount == 0 ) + { + SAL_WARN("chart2", "ChartModel: unlockControllers called with m_nControllerLockCount == 0" ); + return; + } + --m_nControllerLockCount; + if( m_nControllerLockCount == 0 && m_bUpdateNotificationsPending ) + { + aGuard.clear(); + impl_notifyModifiedListeners(); + } +} + +sal_Bool SAL_CALL ChartModel::hasControllersLocked() +{ + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return false; //behave passive if already disposed or closed or throw exception @todo? + return ( m_nControllerLockCount != 0 ) ; +} + +uno::Reference< frame::XController > SAL_CALL ChartModel::getCurrentController() +{ + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + throw lang::DisposedException( + "getCurrentController was called on an already disposed or closed model", + static_cast< ::cppu::OWeakObject* >(this) ); + + return impl_getCurrentController(); +} + +void SAL_CALL ChartModel::setCurrentController( const uno::Reference< frame::XController >& xController ) +{ + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + throw lang::DisposedException( + "setCurrentController was called on an already disposed or closed model", + static_cast< ::cppu::OWeakObject* >(this) ); + + //OSL_ENSURE( impl_isControllerConnected(xController), "setCurrentController is called with a Controller which is not connected" ); + if(!impl_isControllerConnected(xController)) + throw container::NoSuchElementException( + "setCurrentController is called with a Controller which is not connected", + static_cast< ::cppu::OWeakObject* >(this) ); + + m_xCurrentController = xController; + + if (m_xRangeHighlighter) + { + m_xRangeHighlighter->dispose(); + m_xRangeHighlighter.clear(); + } + DisposeHelper::DisposeAndClear(m_xPopupRequest); +} + +uno::Reference< uno::XInterface > SAL_CALL ChartModel::getCurrentSelection() +{ + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + throw lang::DisposedException( + "getCurrentSelection was called on an already disposed or closed model", + static_cast< ::cppu::OWeakObject* >(this) ); + + uno::Reference< uno::XInterface > xReturn; + uno::Reference< frame::XController > xController = impl_getCurrentController(); + + aGuard.clear(); + if( xController.is() ) + { + uno::Reference< view::XSelectionSupplier > xSelectionSupl( xController, uno::UNO_QUERY ); + if ( xSelectionSupl.is() ) + { + uno::Any aSel = xSelectionSupl->getSelection(); + OUString aObjectCID; + if( aSel >>= aObjectCID ) + xReturn.set( ObjectIdentifier::getObjectPropertySet( aObjectCID, this)); + } + } + return xReturn; +} + +// lang::XComponent (base of XModel) +void SAL_CALL ChartModel::dispose() +{ + Reference< XInterface > xKeepAlive( *this ); + + //This object should release all resources and references in the + //easiest possible manner + //This object must notify all registered listeners using the method + //<member>XEventListener::disposing</member> + + //hold no mutex + if( !m_aLifeTimeManager.dispose() ) + return; + + //--release all resources and references + //// @todo + + if ( m_xDiagram.is() ) + m_xDiagram->removeModifyListener( this ); + + if ( m_xDataProvider.is() ) + { + Reference<util::XModifyBroadcaster> xModifyBroadcaster( m_xDataProvider, uno::UNO_QUERY ); + if ( xModifyBroadcaster.is() ) + xModifyBroadcaster->removeModifyListener( this ); + } + + m_xDataProvider.clear(); + m_xInternalDataProvider.clear(); + m_xNumberFormatsSupplier.clear(); + m_xOwnNumberFormatsSupplier.clear(); + m_xChartTypeManager.clear(); + m_xDiagram.clear(); + m_xTitle.clear(); + m_xPageBackground.clear(); + m_xXMLNamespaceMap.clear(); + + m_xStorage.clear(); + // just clear, don't dispose - we're not the owner + + if ( m_pUndoManager.is() ) + m_pUndoManager->disposing(); + m_pUndoManager.clear(); + // that's important, since the UndoManager implementation delegates its ref counting to ourself. + + if( m_xOldModelAgg.is()) // #i120828#, to release cyclic reference to ChartModel object + m_xOldModelAgg->setDelegator( nullptr ); + + m_aControllers.disposeAndClear( lang::EventObject( static_cast< cppu::OWeakObject * >( this ))); + m_xCurrentController.clear(); + + if (m_xRangeHighlighter) + { + m_xRangeHighlighter->dispose(); + m_xRangeHighlighter.clear(); + } + DisposeHelper::DisposeAndClear(m_xPopupRequest); + + if( m_xOldModelAgg.is()) + m_xOldModelAgg->setDelegator( nullptr ); +} + +void SAL_CALL ChartModel::addEventListener( const uno::Reference< lang::XEventListener > & xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed() ) + return; //behave passive if already disposed or closed + + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + m_aLifeTimeManager.m_aEventListeners.addInterface( aGuard, xListener ); +} + +void SAL_CALL ChartModel::removeEventListener( const uno::Reference< lang::XEventListener > & xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) + return; //behave passive if already disposed or closed + + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + m_aLifeTimeManager.m_aEventListeners.removeInterface( aGuard, xListener ); +} + +// util::XCloseBroadcaster (base of XCloseable) +void SAL_CALL ChartModel::addCloseListener( const uno::Reference< util::XCloseListener > & xListener ) +{ + m_aLifeTimeManager.g_addCloseListener( xListener ); +} + +void SAL_CALL ChartModel::removeCloseListener( const uno::Reference< util::XCloseListener > & xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) + return; //behave passive if already disposed or closed + + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + m_aLifeTimeManager.m_aCloseListeners.removeInterface( aGuard, xListener ); +} + +// util::XCloseable +void SAL_CALL ChartModel::close( sal_Bool bDeliverOwnership ) +{ + //hold no mutex + + if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) ) + return; + //no mutex is acquired + + // At the end of this method may we must dispose ourself ... + // and may nobody from outside hold a reference to us ... + // then it's a good idea to do that by ourself. + uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) ); + + //the listeners have had no veto + //check whether we self can close + { + util::CloseVetoException aVetoException( + "the model itself could not be closed", + static_cast< ::cppu::OWeakObject* >(this) ); + + m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ); + } + m_aLifeTimeManager.g_close_endTryClose_doClose(); + + // BM @todo: is it ok to call the listeners here? + impl_notifyCloseListeners(); +} + +// lang::XTypeProvider +uno::Sequence< uno::Type > SAL_CALL ChartModel::getTypes() +{ + uno::Reference< lang::XTypeProvider > xAggTypeProvider; + if( (m_xOldModelAgg->queryAggregation( cppu::UnoType<decltype(xAggTypeProvider)>::get()) >>= xAggTypeProvider) + && xAggTypeProvider.is()) + { + return comphelper::concatSequences( + impl::ChartModel_Base::getTypes(), + xAggTypeProvider->getTypes()); + } + + return impl::ChartModel_Base::getTypes(); +} + +// document::XDocumentPropertiesSupplier +uno::Reference< document::XDocumentProperties > SAL_CALL + ChartModel::getDocumentProperties() +{ + ::osl::MutexGuard aGuard( m_aModelMutex ); + if ( !m_xDocumentProperties.is() ) + { + m_xDocumentProperties.set( document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) ); + } + return m_xDocumentProperties; +} + +// document::XDocumentPropertiesSupplier +Reference< document::XUndoManager > SAL_CALL ChartModel::getUndoManager( ) +{ + ::osl::MutexGuard aGuard( m_aModelMutex ); + if ( !m_pUndoManager.is() ) + m_pUndoManager.set( new UndoManager( *this, m_aModelMutex ) ); + return m_pUndoManager; +} + +// chart2::XChartDocument + +uno::Reference< chart2::XDiagram > SAL_CALL ChartModel::getFirstDiagram() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xDiagram; +} + +void SAL_CALL ChartModel::setFirstDiagram( const uno::Reference< chart2::XDiagram >& xDiagram ) +{ + rtl::Reference< ::chart::Diagram > xOldDiagram; + Reference< util::XModifyListener > xListener; + { + MutexGuard aGuard( m_aModelMutex ); + if( xDiagram.get() == m_xDiagram.get() ) + return; + xOldDiagram = m_xDiagram; + assert(!xDiagram || dynamic_cast<::chart::Diagram*>(xDiagram.get())); + m_xDiagram = dynamic_cast<::chart::Diagram*>(xDiagram.get()); + xListener = this; + } + //don't keep the mutex locked while calling out + if( xOldDiagram && xListener ) + xOldDiagram->removeModifyListener( xListener ); + ModifyListenerHelper::addListener( xDiagram, xListener ); + setModified( true ); +} + +Reference< chart2::data::XDataSource > ChartModel::impl_createDefaultData() +{ + Reference< chart2::data::XDataSource > xDataSource; + if( hasInternalDataProvider() ) + { + //init internal dataprovider + { + beans::NamedValue aParam( "CreateDefaultData" ,uno::Any(true) ); + uno::Sequence< uno::Any > aArgs{ uno::Any(aParam) }; + m_xInternalDataProvider->initialize(aArgs); + } + //create data + uno::Sequence<beans::PropertyValue> aArgs( comphelper::InitPropertySequence({ + { "CellRangeRepresentation", uno::Any( OUString("all") ) }, + { "HasCategories", uno::Any( true ) }, + { "FirstCellAsLabel", uno::Any( true ) }, + { "DataRowSource", uno::Any( css::chart::ChartDataRowSource_COLUMNS ) } + })); + xDataSource = m_xInternalDataProvider->createDataSource( aArgs ); + } + return xDataSource; +} + +void SAL_CALL ChartModel::createInternalDataProvider( sal_Bool bCloneExistingData ) +{ + // don't lock the mutex, because this call calls out to code that tries to + // lock the solar mutex. On the other hand, a paint locks the solar mutex + // and calls to the model lock the model's mutex => deadlock + // @todo: lock a separate mutex in the InternalData class + if( !hasInternalDataProvider() ) + { + if( bCloneExistingData ) + m_xInternalDataProvider = ChartModelHelper::createInternalDataProvider( this, true ); + else + m_xInternalDataProvider = ChartModelHelper::createInternalDataProvider( nullptr, true ); + m_xDataProvider.set( m_xInternalDataProvider ); + } + setModified( true ); +} + +void ChartModel::removeDataProviders() +{ + if (m_xInternalDataProvider.is()) + m_xInternalDataProvider.clear(); + if (m_xDataProvider.is()) + m_xDataProvider.clear(); +} + +void ChartModel::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ChartModel")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + + if (mxChartView.is()) + { + mxChartView->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + +sal_Bool SAL_CALL ChartModel::hasInternalDataProvider() +{ + return m_xDataProvider.is() && m_xInternalDataProvider.is(); +} + +uno::Reference< chart2::data::XDataProvider > SAL_CALL ChartModel::getDataProvider() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xDataProvider; +} + +// ____ XDataReceiver ____ + +void SAL_CALL ChartModel::attachDataProvider( const uno::Reference< chart2::data::XDataProvider >& xDataProvider ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + uno::Reference< beans::XPropertySet > xProp( xDataProvider, uno::UNO_QUERY ); + if( xProp.is() ) + { + try + { + bool bIncludeHiddenCells = ChartModelHelper::isIncludeHiddenCells( this ); + xProp->setPropertyValue("IncludeHiddenCells", uno::Any(bIncludeHiddenCells)); + } + catch (const beans::UnknownPropertyException&) + { + } + } + + uno::Reference<util::XModifyBroadcaster> xModifyBroadcaster(xDataProvider, uno::UNO_QUERY); + if (xModifyBroadcaster.is()) + { + xModifyBroadcaster->addModifyListener(this); + } + + m_xDataProvider.set( xDataProvider ); + m_xInternalDataProvider.clear(); + + //the numberformatter is kept independent of the data provider! + } + setModified( true ); +} + +void SAL_CALL ChartModel::attachNumberFormatsSupplier( const uno::Reference< util::XNumberFormatsSupplier >& xNewSupplier ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + if( xNewSupplier == m_xNumberFormatsSupplier ) + return; + if( xNewSupplier == uno::Reference<XNumberFormatsSupplier>(m_xOwnNumberFormatsSupplier) ) + return; + if( m_xOwnNumberFormatsSupplier.is() && xNewSupplier.is() ) + { + //@todo + //merge missing numberformats from own to new formatter + } + else if( !xNewSupplier.is() ) + { + if( m_xNumberFormatsSupplier.is() ) + { + //@todo + //merge missing numberformats from old numberformatter to own numberformatter + //create own numberformatter if necessary + } + } + + m_xNumberFormatsSupplier.set( xNewSupplier ); + m_xOwnNumberFormatsSupplier.clear(); + } + setModified( true ); +} + +void SAL_CALL ChartModel::setArguments( const Sequence< beans::PropertyValue >& aArguments ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + if( !m_xDataProvider.is() ) + return; + lockControllers(); + + try + { + Reference< chart2::data::XDataSource > xDataSource( m_xDataProvider->createDataSource( aArguments ) ); + if( xDataSource.is() ) + { + rtl::Reference< Diagram > xDia = getFirstChartDiagram(); + if( !xDia.is() ) + { + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() ); + if( xTemplate.is()) + setFirstDiagram( xTemplate->createDiagramByDataSource( xDataSource, aArguments ) ); + } + else + xDia->setDiagramData( xDataSource, aArguments ); + } + } + catch (const lang::IllegalArgumentException&) + { + throw; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + unlockControllers(); + } + setModified( true ); +} + +Sequence< OUString > SAL_CALL ChartModel::getUsedRangeRepresentations() +{ + return DataSourceHelper::getUsedDataRanges( this ); +} + +Reference< chart2::data::XDataSource > SAL_CALL ChartModel::getUsedData() +{ + return DataSourceHelper::getUsedData( *this ); +} + +Reference< chart2::data::XRangeHighlighter > SAL_CALL ChartModel::getRangeHighlighter() +{ + if( ! m_xRangeHighlighter.is()) + m_xRangeHighlighter = new RangeHighlighter( this ); + return m_xRangeHighlighter; +} + +Reference<awt::XRequestCallback> SAL_CALL ChartModel::getPopupRequest() +{ + if (!m_xPopupRequest.is()) + m_xPopupRequest.set(new PopupRequest); + return m_xPopupRequest; +} + +rtl::Reference< ::chart::ChartTypeTemplate > ChartModel::impl_createDefaultChartTypeTemplate() +{ + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + if( m_xChartTypeManager.is() ) + xTemplate = m_xChartTypeManager->createTemplate( "com.sun.star.chart2.template.Column" ); + return xTemplate; +} + +void SAL_CALL ChartModel::setChartTypeManager( const uno::Reference< chart2::XChartTypeManager >& xNewManager ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + m_xChartTypeManager = dynamic_cast<::chart::ChartTypeManager*>(xNewManager.get()); + assert(!xNewManager || m_xChartTypeManager); + } + setModified( true ); +} + +uno::Reference< chart2::XChartTypeManager > SAL_CALL ChartModel::getChartTypeManager() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xChartTypeManager; +} + +uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getPageBackground() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xPageBackground; +} + +void SAL_CALL ChartModel::createDefaultChart() +{ + insertDefaultChart(); +} + +// ____ XTitled ____ +uno::Reference< chart2::XTitle > SAL_CALL ChartModel::getTitleObject() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xTitle; +} + +rtl::Reference< Title > ChartModel::getTitleObject2() const +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xTitle; +} + +void SAL_CALL ChartModel::setTitleObject( const uno::Reference< chart2::XTitle >& xNewTitle ) +{ + rtl::Reference<Title> xTitle = dynamic_cast<Title*>(xNewTitle.get()); + assert(!xNewTitle || xTitle); + setTitleObject(xTitle); +} + +void ChartModel::setTitleObject( const rtl::Reference< Title >& xTitle ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + if( m_xTitle.is() ) + ModifyListenerHelper::removeListener( m_xTitle, this ); + m_xTitle = xTitle; + ModifyListenerHelper::addListener( m_xTitle, this ); + } + setModified( true ); +} + +// ____ XInterface (for old API wrapper) ____ +uno::Any SAL_CALL ChartModel::queryInterface( const uno::Type& aType ) +{ + uno::Any aResult( impl::ChartModel_Base::queryInterface( aType )); + + if( ! aResult.hasValue()) + { + // try old API wrapper + try + { + if( m_xOldModelAgg.is()) + aResult = m_xOldModelAgg->queryAggregation( aType ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL ChartModel::createClone() +{ + return Reference< util::XCloneable >( new ChartModel( *this )); +} + +// ____ XVisualObject ____ +void SAL_CALL ChartModel::setVisualAreaSize( ::sal_Int64 nAspect, const awt::Size& aSize ) +{ + if( nAspect == embed::Aspects::MSOLE_CONTENT ) + { + ControllerLockGuard aLockGuard( *this ); + bool bChanged = + (m_aVisualAreaSize.Width != aSize.Width || + m_aVisualAreaSize.Height != aSize.Height); + + // #i12587# support for shapes in chart + if ( bChanged ) + { + impl_adjustAdditionalShapesPositionAndSize( aSize ); + } + + m_aVisualAreaSize = aSize; + if( bChanged ) + setModified( true ); + } + else + { + OSL_FAIL( "setVisualAreaSize: Aspect not implemented yet."); + } +} + +awt::Size SAL_CALL ChartModel::getVisualAreaSize( ::sal_Int64 nAspect ) +{ + OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, + "No aspects other than content are supported" ); + // other possible aspects are MSOLE_THUMBNAIL, MSOLE_ICON and MSOLE_DOCPRINT + + return m_aVisualAreaSize; +} + +embed::VisualRepresentation SAL_CALL ChartModel::getPreferredVisualRepresentation( ::sal_Int64 nAspect ) +{ + OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, + "No aspects other than content are supported" ); + + embed::VisualRepresentation aResult; + + try + { + Sequence< sal_Int8 > aMetafile; + + //get view from old api wrapper + Reference< datatransfer::XTransferable > xTransferable( + createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY ); + if( xTransferable.is() ) + { + datatransfer::DataFlavor aDataFlavor( lcl_aGDIMetaFileMIMEType, + "GDIMetaFile", + cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); + + uno::Any aData( xTransferable->getTransferData( aDataFlavor ) ); + aData >>= aMetafile; + } + + aResult.Flavor.MimeType = lcl_aGDIMetaFileMIMEType; + aResult.Flavor.DataType = cppu::UnoType<decltype(aMetafile)>::get(); + + aResult.Data <<= aMetafile; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +::sal_Int32 SAL_CALL ChartModel::getMapUnit( ::sal_Int64 nAspect ) +{ + OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, + "No aspects other than content are supported" ); + return embed::EmbedMapUnits::ONE_100TH_MM; +} + +// ____ datatransfer::XTransferable ____ +uno::Any SAL_CALL ChartModel::getTransferData( const datatransfer::DataFlavor& aFlavor ) +{ + uno::Any aResult; + if( !isDataFlavorSupported( aFlavor ) ) + throw datatransfer::UnsupportedFlavorException( + aFlavor.MimeType, static_cast< ::cppu::OWeakObject* >( this )); + + try + { + //get view from old api wrapper + Reference< datatransfer::XTransferable > xTransferable( + createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY ); + if( xTransferable.is() && + xTransferable->isDataFlavorSupported( aFlavor )) + { + aResult = xTransferable->getTransferData( aFlavor ); + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +Sequence< datatransfer::DataFlavor > SAL_CALL ChartModel::getTransferDataFlavors() +{ + return { datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast, + "GDIMetaFile", + cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) }; +} + +sal_Bool SAL_CALL ChartModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor ) +{ + return aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast; +} + +namespace +{ +enum eServiceType +{ + SERVICE_DASH_TABLE, + SERVICE_GRADIENT_TABLE, + SERVICE_HATCH_TABLE, + SERVICE_BITMAP_TABLE, + SERVICE_TRANSP_GRADIENT_TABLE, + SERVICE_MARKER_TABLE, + SERVICE_NAMESPACE_MAP +}; + +typedef std::map< OUString, enum eServiceType > tServiceNameMap; + +tServiceNameMap & lcl_getStaticServiceNameMap() +{ + static tServiceNameMap aServiceNameMap{ + {"com.sun.star.drawing.DashTable", SERVICE_DASH_TABLE}, + {"com.sun.star.drawing.GradientTable", SERVICE_GRADIENT_TABLE}, + {"com.sun.star.drawing.HatchTable", SERVICE_HATCH_TABLE}, + {"com.sun.star.drawing.BitmapTable", SERVICE_BITMAP_TABLE}, + {"com.sun.star.drawing.TransparencyGradientTable", SERVICE_TRANSP_GRADIENT_TABLE}, + {"com.sun.star.drawing.MarkerTable", SERVICE_MARKER_TABLE}, + {"com.sun.star.xml.NamespaceMap", SERVICE_NAMESPACE_MAP}}; + return aServiceNameMap; +} +} +// ____ XMultiServiceFactory ____ +Reference< uno::XInterface > SAL_CALL ChartModel::createInstance( const OUString& rServiceSpecifier ) +{ + tServiceNameMap & rMap = lcl_getStaticServiceNameMap(); + + tServiceNameMap::const_iterator aIt( rMap.find( rServiceSpecifier )); + if( aIt != rMap.end()) + { + switch( (*aIt).second ) + { + case SERVICE_DASH_TABLE: + case SERVICE_GRADIENT_TABLE: + case SERVICE_HATCH_TABLE: + case SERVICE_BITMAP_TABLE: + case SERVICE_TRANSP_GRADIENT_TABLE: + case SERVICE_MARKER_TABLE: + { + if(!mxChartView.is()) + { + mxChartView = new ChartView( m_xContext, *this); + } + return mxChartView->createInstance( rServiceSpecifier ); + } + break; + case SERVICE_NAMESPACE_MAP: + return static_cast<cppu::OWeakObject*>(m_xXMLNamespaceMap.get()); + } + } + else if(rServiceSpecifier == CHART_VIEW_SERVICE_NAME) + { + if(!mxChartView.is()) + { + mxChartView = new ChartView( m_xContext, *this); + } + + return static_cast< ::cppu::OWeakObject* >( mxChartView.get() ); + } + else + { + if( m_xOldModelAgg.is() ) + { + Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get()); + uno::Reference< lang::XMultiServiceFactory > xOldModelFactory; + if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() ) + { + return xOldModelFactory->createInstance( rServiceSpecifier ); + } + } + } + return nullptr; +} + +Reference< uno::XInterface > SAL_CALL ChartModel::createInstanceWithArguments( + const OUString& rServiceSpecifier , const Sequence< Any >& Arguments ) +{ + OSL_ENSURE( Arguments.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" ); + return createInstance( rServiceSpecifier ); +} + +Sequence< OUString > SAL_CALL ChartModel::getAvailableServiceNames() +{ + uno::Sequence< OUString > aResult; + + if( m_xOldModelAgg.is()) + { + Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get()); + uno::Reference< lang::XMultiServiceFactory > xOldModelFactory; + if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() ) + { + return xOldModelFactory->getAvailableServiceNames(); + } + } + return aResult; +} + +Reference< util::XNumberFormatsSupplier > const & ChartModel::getNumberFormatsSupplier() +{ + if( !m_xNumberFormatsSupplier.is() ) + { + if( !m_xOwnNumberFormatsSupplier.is() ) + { + m_apSvNumberFormatter.reset( new SvNumberFormatter( m_xContext, LANGUAGE_SYSTEM ) ); + m_xOwnNumberFormatsSupplier = new SvNumberFormatsSupplierObj( m_apSvNumberFormatter.get() ); + //pOwnNumberFormatter->ChangeStandardPrec( 15 ); todo? + } + m_xNumberFormatsSupplier = m_xOwnNumberFormatsSupplier; + } + return m_xNumberFormatsSupplier; +} + +// ____ XUnoTunnel ___ +::sal_Int64 SAL_CALL ChartModel::getSomething( const Sequence< ::sal_Int8 >& aIdentifier ) +{ + if( comphelper::isUnoTunnelId<SvNumberFormatsSupplierObj>(aIdentifier) ) + { + Reference< lang::XUnoTunnel > xTunnel( getNumberFormatsSupplier(), uno::UNO_QUERY ); + if( xTunnel.is() ) + return xTunnel->getSomething( aIdentifier ); + } + return 0; +} + +// ____ XNumberFormatsSupplier ____ +uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getNumberFormatSettings() +{ + Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() ); + if( xSupplier.is() ) + return xSupplier->getNumberFormatSettings(); + return uno::Reference< beans::XPropertySet >(); +} + +uno::Reference< util::XNumberFormats > SAL_CALL ChartModel::getNumberFormats() +{ + Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() ); + if( xSupplier.is() ) + return xSupplier->getNumberFormats(); + return uno::Reference< util::XNumberFormats >(); +} + +// ____ XChild ____ +Reference< uno::XInterface > SAL_CALL ChartModel::getParent() +{ + return Reference< uno::XInterface >(m_xParent,uno::UNO_QUERY); +} + +void SAL_CALL ChartModel::setParent( const Reference< uno::XInterface >& Parent ) +{ + if( Parent != m_xParent ) + m_xParent.set( Parent, uno::UNO_QUERY ); +} + +// ____ XDataSource ____ +uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL ChartModel::getDataSequences() +{ + rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *this ); + if( xSource.is()) + return xSource->getDataSequences(); + + return uno::Sequence< Reference< chart2::data::XLabeledDataSequence > >(); +} + +//XDumper +OUString SAL_CALL ChartModel::dump(OUString const & kind) +{ + if (kind.isEmpty()) { + return comphelper::dumpXmlToString([this](auto writer) { return dumpAsXml(writer); }); + } + + // kind == "shapes": + uno::Reference< qa::XDumper > xDumper( + createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY ); + if (xDumper.is()) + return xDumper->dump(kind); + + return OUString(); +} + +void ChartModel::setTimeBasedRange(sal_Int32 nStart, sal_Int32 nEnd) +{ + mnStart = nStart; + mnEnd = nEnd; + mbTimeBased = true; +} + +void ChartModel::update() +{ + if(!mxChartView.is()) + { + mxChartView = new ChartView( m_xContext, *this); + } + mxChartView->setViewDirty(); + mxChartView->update(); +} + +bool ChartModel::isDataFromSpreadsheet() +{ + return !isDataFromPivotTable() && !hasInternalDataProvider(); +} + +bool ChartModel::isDataFromPivotTable() const +{ + uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(m_xDataProvider, uno::UNO_QUERY); + return xPivotTableDataProvider.is(); +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartModel_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::ChartModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/ChartModel_Persistence.cxx b/chart2/source/model/main/ChartModel_Persistence.cxx new file mode 100644 index 0000000000..03824aab5c --- /dev/null +++ b/chart2/source/model/main/ChartModel_Persistence.cxx @@ -0,0 +1,802 @@ +/* -*- 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 <memory> +#include <ChartModel.hxx> +#include <MediaDescriptorHelper.hxx> +#include <ChartViewHelper.hxx> +#include <ChartModelHelper.hxx> +#include <ChartTypeManager.hxx> +#include <ChartTypeTemplate.hxx> +#include <DataSourceHelper.hxx> +#include <AxisHelper.hxx> +#include <ThreeDHelper.hxx> +#include <Diagram.hxx> +#include <DiagramHelper.hxx> +#include <BaseCoordinateSystem.hxx> +#include <Legend.hxx> +#include <XMLFilter.hxx> + +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/XImporter.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/ProjectionMode.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/StorageFactory.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/io/TempFile.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <com/sun/star/ucb/ContentCreationException.hpp> + +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> + +#include <ucbhelper/content.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/tempfile.hxx> +#include <utility> +#include <vcl/cvtgrf.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/storagehelper.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <sal/log.hxx> +#include <sfx2/objsh.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::osl::MutexGuard; + +namespace +{ +struct lcl_PropNameEquals +{ + explicit lcl_PropNameEquals( OUString aStrToCompareWith ) : + m_aStr(std::move( aStrToCompareWith )) + {} + bool operator() ( const beans::PropertyValue & rProp ) + { + return rProp.Name == m_aStr; + } +private: + OUString m_aStr; +}; + +template< typename T > +T lcl_getProperty( + const Sequence< beans::PropertyValue > & rMediaDescriptor, + const OUString & rPropName ) +{ + T aResult; + if( rMediaDescriptor.hasElements()) + { + const beans::PropertyValue * pIt = rMediaDescriptor.getConstArray(); + const beans::PropertyValue * pEndIt = pIt + + rMediaDescriptor.getLength(); + pIt = std::find_if( pIt, pEndIt, lcl_PropNameEquals( rPropName )); + if( pIt != pEndIt ) + (*pIt).Value >>= aResult; + } + return aResult; +} + +void lcl_addStorageToMediaDescriptor( + Sequence< beans::PropertyValue > & rOutMD, + const Reference< embed::XStorage > & xStorage ) +{ + rOutMD.realloc( rOutMD.getLength() + 1 ); + rOutMD.getArray()[rOutMD.getLength() - 1] = beans::PropertyValue( + "Storage", -1, uno::Any( xStorage ), beans::PropertyState_DIRECT_VALUE ); +} + +Reference< embed::XStorage > lcl_createStorage( + const OUString & rURL, + const Reference< uno::XComponentContext > & xContext, + const Sequence< beans::PropertyValue > & rMediaDescriptor ) +{ + // create new storage + Reference< embed::XStorage > xStorage; + if( !xContext.is()) + return xStorage; + + try + { + Reference< io::XStream > xStream( + ::ucbhelper::Content( rURL, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext()).openStream(), + uno::UNO_QUERY ); + + Reference< lang::XSingleServiceFactory > xStorageFact( embed::StorageFactory::create( xContext ) ); + Sequence< uno::Any > aStorageArgs{ uno::Any(xStream), + uno::Any(embed::ElementModes::READWRITE), + uno::Any(rMediaDescriptor) }; + xStorage.set( + xStorageFact->createInstanceWithArguments( aStorageArgs ), uno::UNO_QUERY_THROW ); + } + catch(const css::ucb::ContentCreationException&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + catch(const css::ucb::CommandFailedException&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xStorage; +} + +} // anonymous namespace + +namespace chart +{ + +Reference< document::XFilter > ChartModel::impl_createFilter( + const Sequence< beans::PropertyValue > & rMediaDescriptor ) +{ + Reference< document::XFilter > xFilter; + + // find FilterName in MediaDescriptor + OUString aFilterName( + lcl_getProperty< OUString >( rMediaDescriptor, "FilterName" ) ); + + // if FilterName was found, get Filter from factory + if( !aFilterName.isEmpty() ) + { + try + { + Reference< container::XNameAccess > xFilterFact( + m_xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.document.FilterFactory", m_xContext ), + uno::UNO_QUERY_THROW ); + uno::Any aFilterProps( xFilterFact->getByName( aFilterName )); + Sequence< beans::PropertyValue > aProps; + + if( aFilterProps.hasValue() && + (aFilterProps >>= aProps)) + { + OUString aFilterServiceName( + lcl_getProperty< OUString >( aProps, "FilterService" ) ); + + if( !aFilterServiceName.isEmpty()) + { + xFilter.set( + m_xContext->getServiceManager()->createInstanceWithContext( + aFilterServiceName, m_xContext ), uno::UNO_QUERY_THROW ); + SAL_INFO("chart2", "Filter found for service " << aFilterServiceName ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + OSL_ENSURE( xFilter.is(), "Filter not found via factory" ); + } + + // fall-back: create XML-Filter + if( ! xFilter.is()) + { + SAL_WARN("chart2", "No FilterName passed in MediaDescriptor" ); + xFilter = new XMLFilter(m_xContext); + } + + return xFilter; +} + +// frame::XStorable2 + +void SAL_CALL ChartModel::storeSelf( const Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + // only some parameters are allowed (see also SfxBaseModel) + // "VersionComment", "Author", "InteractionHandler", "StatusIndicator" + // However, they are ignored here. They would become interesting when + // charts support a standalone format again. + impl_store( rMediaDescriptor, m_xStorage ); +} + +// frame::XStorable (base of XStorable2) +sal_Bool SAL_CALL ChartModel::hasLocation() +{ + //@todo guard + return !m_aResource.isEmpty(); +} + +OUString SAL_CALL ChartModel::getLocation() +{ + return impl_g_getLocation(); +} + +sal_Bool SAL_CALL ChartModel::isReadonly() +{ + //@todo guard + return m_bReadOnly; +} + +void SAL_CALL ChartModel::store() +{ + apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall(true)) //start LongLastingCall + return; //behave passive if already disposed or closed or throw exception @todo? + + OUString aLocation = m_aResource; + + if( aLocation.isEmpty() ) + throw io::IOException( "no location specified", static_cast< ::cppu::OWeakObject* >(this)); + //@todo check whether aLocation is something like private:factory... + if( m_bReadOnly ) + throw io::IOException( "document is read only", static_cast< ::cppu::OWeakObject* >(this)); + + aGuard.clear(); + + // store + impl_store( m_aMediaDescriptor, m_xStorage ); +} + +void SAL_CALL ChartModel::storeAsURL( + const OUString& rURL, + const uno::Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall(true)) //start LongLastingCall + return; //behave passive if already disposed or closed or throw exception @todo? + + apphelper::MediaDescriptorHelper aMediaDescriptorHelper(rMediaDescriptor); + uno::Sequence< beans::PropertyValue > aReducedMediaDescriptor( + aMediaDescriptorHelper.getReducedForModel() ); + + m_bReadOnly = false; + aGuard.clear(); + + // create new storage + Reference< embed::XStorage > xStorage( lcl_createStorage( rURL, m_xContext, aReducedMediaDescriptor )); + + if( xStorage.is()) + { + impl_store( aReducedMediaDescriptor, xStorage ); + attachResource( rURL, aReducedMediaDescriptor ); + } +} + +void SAL_CALL ChartModel::storeToURL( + const OUString& rURL, + const uno::Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall(true)) //start LongLastingCall + return; //behave passive if already disposed or closed or throw exception @todo? + //do not change the internal state of the document here + + aGuard.clear(); + + apphelper::MediaDescriptorHelper aMediaDescriptorHelper(rMediaDescriptor); + uno::Sequence< beans::PropertyValue > aReducedMediaDescriptor( + aMediaDescriptorHelper.getReducedForModel() ); + + if ( rURL == "private:stream" ) + { + try + { + if( m_xContext.is() && aMediaDescriptorHelper.ISSET_OutputStream ) + { + rtl::Reference< utl::TempFileFastService > xStream = new utl::TempFileFastService; + Reference< io::XInputStream > xInputStream( xStream->getInputStream()); + + Reference< embed::XStorage > xStorage( + ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE, m_xContext )); + if( xStorage.is()) + { + impl_store( aReducedMediaDescriptor, xStorage ); + + xStream->seek( 0 ); + ::comphelper::OStorageHelper::CopyInputToOutput( xInputStream, aMediaDescriptorHelper.OutputStream ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + // create new storage + Reference< embed::XStorage > xStorage( lcl_createStorage( rURL, m_xContext, aReducedMediaDescriptor )); + + if( xStorage.is()) + impl_store( aReducedMediaDescriptor, xStorage ); + } +} + +void ChartModel::impl_store( + const Sequence< beans::PropertyValue >& rMediaDescriptor, + const Reference< embed::XStorage > & xStorage ) +{ + Reference< document::XFilter > xFilter( impl_createFilter( rMediaDescriptor)); + if( xFilter.is() && xStorage.is()) + { + Sequence< beans::PropertyValue > aMD( rMediaDescriptor ); + lcl_addStorageToMediaDescriptor( aMD, xStorage ); + try + { + Reference< document::XExporter > xExporter( xFilter, uno::UNO_QUERY_THROW ); + xExporter->setSourceDocument( Reference< lang::XComponent >( this )); + xFilter->filter( aMD ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + OSL_FAIL( "No filter" ); + } + + setModified( false ); + + //#i66865# + //for data change notification during chart is not loaded: + //notify parent data provider after saving thus the parent document can store + //the ranges for which a load and update of the chart will be necessary + Reference< beans::XPropertySet > xPropSet( m_xParent, uno::UNO_QUERY ); + if ( hasInternalDataProvider() || !xPropSet.is() ) + return; + + apphelper::MediaDescriptorHelper aMDHelper(rMediaDescriptor); + try + { + xPropSet->setPropertyValue( + "SavedObject", + uno::Any( aMDHelper.HierarchicalDocumentName ) ); + } + catch ( const uno::Exception& ) + { + } +} + +void ChartModel::insertDefaultChart() +{ + lockControllers(); + createInternalDataProvider( false ); + try + { + // create default chart + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() ); + if( xTemplate.is()) + { + try + { + Reference< chart2::data::XDataSource > xDataSource( impl_createDefaultData() ); + Sequence< beans::PropertyValue > aParam; + + bool bSupportsCategories = xTemplate->supportsCategories(); + if( bSupportsCategories ) + { + aParam = { beans::PropertyValue( "HasCategories", -1, uno::Any( true ), + beans::PropertyState_DIRECT_VALUE ) }; + } + + rtl::Reference< Diagram > xDiagram( xTemplate->createDiagramByDataSource2( xDataSource, aParam ) ); + + setFirstDiagram( xDiagram ); + + bool bIsRTL = AllSettings::GetMathLayoutRTL(); + //reverse x axis for rtl charts + if( bIsRTL ) + AxisHelper::setRTLAxisLayout( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ) ); + + // create and attach legend + rtl::Reference< Legend > xLegend = new Legend(); + xLegend->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_NONE )); + xLegend->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE )); + xLegend->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) )); // gray30 + xLegend->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xe6e6e6 ) ) ); // gray10 + + if( bIsRTL ) + xLegend->setPropertyValue( "AnchorPosition", uno::Any( chart2::LegendPosition_LINE_START )); + if(xDiagram.is()) + xDiagram->setLegend( xLegend ); + + // set simple 3D look + if( xDiagram.is() ) + { + xDiagram->setPropertyValue( "RightAngledAxes", uno::Any( true )); + xDiagram->setPropertyValue( "D3DScenePerspective", uno::Any( drawing::ProjectionMode_PARALLEL )); + xDiagram->setScheme( ThreeDLookScheme::ThreeDLookScheme_Realistic ); + } + + //set some new 'defaults' for wall and floor + if( xDiagram.is() ) + { + Reference< beans::XPropertySet > xWall( xDiagram->getWall() ); + if( xWall.is() ) + { + xWall->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID ) ); + xWall->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_NONE ) ); + xWall->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30 + xWall->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xe6e6e6 ) ) ); // gray10 + } + Reference< beans::XPropertySet > xFloor( xDiagram->getFloor() ); + if( xFloor.is() ) + { + xFloor->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE ) ); + xFloor->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_SOLID ) ); + xFloor->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30 + xFloor->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xcccccc ) ) ); // gray20 + } + + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + ChartModelHelper::setIncludeHiddenCells( false, *this ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + setModified( false ); + unlockControllers(); +} + +// frame::XLoadable +void SAL_CALL ChartModel::initNew() +{ +} + +void SAL_CALL ChartModel::load( + const Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + Reference< embed::XStorage > xStorage; + OUString aURL; + try + { + apphelper::MediaDescriptorHelper aMDHelper( rMediaDescriptor ); + if( aMDHelper.ISSET_Storage ) + { + xStorage = aMDHelper.Storage; + } + else if( aMDHelper.ISSET_Stream || + aMDHelper.ISSET_InputStream ) + { + if( aMDHelper.ISSET_FilterName && + (aMDHelper.FilterName == "StarChart 5.0" || + aMDHelper.FilterName == "StarChart 4.0" || + aMDHelper.FilterName == "StarChart 3.0" )) + { + attachResource( aMDHelper.URL, rMediaDescriptor ); + impl_load( rMediaDescriptor, nullptr ); // cannot create a storage from binary streams, but I do not need the storage here anyhow + m_bReadOnly = true; + return; + } + + Reference< lang::XSingleServiceFactory > xStorageFact( embed::StorageFactory::create(m_xContext) ); + + if( aMDHelper.ISSET_Stream ) + { + // convert XStream to XStorage via the storage factory + Sequence< uno::Any > aStorageArgs{ uno::Any(aMDHelper.Stream), + // todo: check if stream is read-only + uno::Any(embed::ElementModes::READ) }; //WRITE | embed::ElementModes::NOCREATE); + + xStorage.set( xStorageFact->createInstanceWithArguments( aStorageArgs ), + uno::UNO_QUERY_THROW ); + } + else + { + OSL_ASSERT( aMDHelper.ISSET_InputStream ); + // convert XInputStream to XStorage via the storage factory + Sequence< uno::Any > aStorageArgs{ uno::Any(aMDHelper.InputStream), + uno::Any(embed::ElementModes::READ) }; + + xStorage.set( xStorageFact->createInstanceWithArguments( aStorageArgs ), + uno::UNO_QUERY_THROW ); + } + } + + if( aMDHelper.ISSET_URL ) + aURL = aMDHelper.URL; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if( xStorage.is()) + { + attachResource( aURL, rMediaDescriptor ); + impl_load( rMediaDescriptor, xStorage ); + } +} + +void ChartModel::impl_load( + const Sequence< beans::PropertyValue >& rMediaDescriptor, + const Reference< embed::XStorage >& xStorage ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + m_nInLoad++; + } + + Reference< document::XFilter > xFilter( impl_createFilter( rMediaDescriptor )); + + if( xFilter.is()) + { + Reference< document::XImporter > xImporter( xFilter, uno::UNO_QUERY_THROW ); + xImporter->setTargetDocument( this ); + Sequence< beans::PropertyValue > aMD( rMediaDescriptor ); + lcl_addStorageToMediaDescriptor( aMD, xStorage ); + + xFilter->filter( aMD ); + xFilter.clear(); + } + else + { + OSL_FAIL( "loadFromStorage cannot create filter" ); + } + + if( xStorage.is() ) + impl_loadGraphics( xStorage ); + + setModified( false ); + + // switchToStorage without notifying listeners (which shouldn't exist at + // this time, anyway) + m_xStorage = xStorage; + + { + MutexGuard aGuard( m_aModelMutex ); + m_nInLoad--; + } +} + +void ChartModel::impl_loadGraphics( + const Reference< embed::XStorage >& xStorage ) +{ + try + { + const Reference< embed::XStorage >& xGraphicsStorage( + xStorage->openStorageElement( "Pictures", + embed::ElementModes::READ ) ); + + if( xGraphicsStorage.is() ) + { + const uno::Sequence< OUString > aElementNames( + xGraphicsStorage->getElementNames() ); + + for( OUString const & streamName : aElementNames ) + { + if( xGraphicsStorage->isStreamElement( streamName ) ) + { + uno::Reference< io::XStream > xElementStream( + xGraphicsStorage->openStreamElement( + streamName, + embed::ElementModes::READ ) ); + + if( xElementStream.is() ) + { + std::unique_ptr< SvStream > apIStm( + ::utl::UcbStreamHelper::CreateStream( + xElementStream, true ) ); + + if (apIStm) + { + SolarMutexGuard aGuard; + Graphic aGraphic; + if (!GraphicConverter::Import(*apIStm, aGraphic)) + { + m_aGraphicObjectVector.emplace_back(aGraphic ); + } + } + } + } + } + } + } + catch ( const uno::Exception& ) + { + } +} + +// util::XModifiable +void ChartModel::impl_notifyModifiedListeners() +{ + { + MutexGuard aGuard( m_aModelMutex ); + m_bUpdateNotificationsPending = false; + } + + //always notify the view first! + ChartViewHelper::setViewToDirtyState( this ); + + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + if( m_aLifeTimeManager.m_aModifyListeners.getLength(aGuard) ) + { + lang::EventObject aEvent( static_cast< lang::XComponent*>(this) ); + m_aLifeTimeManager.m_aModifyListeners.notifyEach(aGuard, &util::XModifyListener::modified, aEvent); + } +} + +sal_Bool SAL_CALL ChartModel::isModified() +{ + //@todo guard + return m_bModified; +} + +void SAL_CALL ChartModel::setModified( sal_Bool bModified ) +{ + // tdf#141914: allow to set *unmodified* when parent does not allow to set modified + if (bModified) + { + // tdf#77007: honor parent's IsEnableSetModified + // Check it before LifeTimeGuard, to avoid deadlocking solar mutex and this guard + if (auto pParentShell = SfxObjectShell::GetShellFromComponent(getParent()); + pParentShell && !pParentShell->IsEnableSetModified()) + return; + } + + apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall())//@todo ? is this a long lasting call?? + return; //behave passive if already disposed or closed or throw exception @todo? + m_bModified = bModified; + + if( m_nControllerLockCount > 0 ) + { + if (bModified) + m_bUpdateNotificationsPending = true; // Maybe !bModified should reset it? + return;//don't call listeners if controllers are locked + } + aGuard.clear(); + + if(bModified) + impl_notifyModifiedListeners(); +} + +// util::XModifyBroadcaster (base of XModifiable) +void SAL_CALL ChartModel::addModifyListener( + const uno::Reference< util::XModifyListener >& xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed() ) + return; //behave passive if already disposed or closed + + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + m_aLifeTimeManager.m_aModifyListeners.addInterface( aGuard, xListener ); +} + +void SAL_CALL ChartModel::removeModifyListener( + const uno::Reference< util::XModifyListener >& xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) + return; //behave passive if already disposed or closed + + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + m_aLifeTimeManager.m_aModifyListeners.removeInterface( aGuard, xListener ); +} + +// util::XModifyListener +void SAL_CALL ChartModel::modified( const lang::EventObject& rEvenObject) +{ + uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rEvenObject.Source, uno::UNO_QUERY); + if (xPivotTableDataProvider.is()) + { + lockControllers(); + uno::Reference<chart2::data::XDataProvider> xDataProvider(xPivotTableDataProvider, uno::UNO_QUERY); + try + { + uno::Sequence<beans::PropertyValue> aArguments = + DataSourceHelper::createArguments("PivotChart", uno::Sequence<sal_Int32>(), true, true, true); + + Reference<chart2::data::XDataSource> xDataSource(xDataProvider->createDataSource(aArguments)); + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = getTypeManager(); + rtl::Reference<Diagram> xDiagram(getFirstChartDiagram()); + + Diagram::tTemplateWithServiceName aTemplateAndService = xDiagram->getTemplate(xChartTypeManager); + aTemplateAndService.xChartTypeTemplate->changeDiagramData(xDiagram, xDataSource, aArguments); + } + catch (const uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + unlockControllers(); + } + + if (m_nInLoad == 0) + setModified(true); +} + +// lang::XEventListener (base of util::XModifyListener) +void SAL_CALL ChartModel::disposing( const lang::EventObject& ) +{ + // child was disposed -- should not happen from outside +} + +// document::XStorageBasedDocument +void SAL_CALL ChartModel::loadFromStorage( + const Reference< embed::XStorage >& xStorage, + const Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + attachResource( OUString(), rMediaDescriptor ); + impl_load( rMediaDescriptor, xStorage ); +} + +void SAL_CALL ChartModel::storeToStorage( + const Reference< embed::XStorage >& xStorage, + const Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + impl_store( rMediaDescriptor, xStorage ); +} + +void SAL_CALL ChartModel::switchToStorage( const Reference< embed::XStorage >& xStorage ) +{ + m_xStorage = xStorage; + impl_notifyStorageChangeListeners(); +} + +Reference< embed::XStorage > SAL_CALL ChartModel::getDocumentStorage() +{ + return m_xStorage; +} + +void ChartModel::impl_notifyStorageChangeListeners() +{ + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + if( m_aLifeTimeManager.m_aStorageChangeListeners.getLength(aGuard) ) + { + m_aLifeTimeManager.m_aStorageChangeListeners.forEach(aGuard, + [this](const uno::Reference<document::XStorageChangeListener>& l) + { + l->notifyStorageChange( static_cast< ::cppu::OWeakObject* >( this ), m_xStorage ); + }); + } +} + +void SAL_CALL ChartModel::addStorageChangeListener( const Reference< document::XStorageChangeListener >& xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed() ) + return; //behave passive if already disposed or closed + + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + m_aLifeTimeManager.m_aStorageChangeListeners.addInterface( aGuard, xListener ); +} + +void SAL_CALL ChartModel::removeStorageChangeListener( const Reference< document::XStorageChangeListener >& xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) + return; //behave passive if already disposed or closed + + std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); + m_aLifeTimeManager.m_aStorageChangeListeners.removeInterface(aGuard, xListener ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataPoint.cxx b/chart2/source/model/main/DataPoint.cxx new file mode 100644 index 0000000000..d6c8a9e2ac --- /dev/null +++ b/chart2/source/model/main/DataPoint.cxx @@ -0,0 +1,255 @@ +/* -*- 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 "DataPoint.hxx" +#include "DataPointProperties.hxx" +#include <CharacterProperties.hxx> +#include <UserDefinedProperties.hxx> +#include <PropertyHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +::cppu::OPropertyArrayHelper& StaticDataPointInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + ::chart::DataPointProperties::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ + +DataPoint::DataPoint( const uno::Reference< beans::XPropertySet > & rParentProperties ) : + m_xParentProperties( rParentProperties ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_bNoParentPropAllowed( false ) +{ + SetNewValuesExplicitlyEvenIfTheyEqualDefault(); +} + +DataPoint::DataPoint( const DataPoint & rOther ) : + impl::DataPoint_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_bNoParentPropAllowed( true ) +{ + SetNewValuesExplicitlyEvenIfTheyEqualDefault(); + + // m_xParentProperties has to be set from outside, like in the method + // DataSeries::createClone + + // add as listener to XPropertySet properties + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); + + m_bNoParentPropAllowed = false; +} + +DataPoint::~DataPoint() +{ + try + { + // remove listener from XPropertySet properties + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL DataPoint::createClone() +{ + return uno::Reference< util::XCloneable >( new DataPoint( *this )); +} + +// ____ XChild ____ +Reference< uno::XInterface > SAL_CALL DataPoint::getParent() +{ + return Reference< uno::XInterface >( m_xParentProperties.get(), uno::UNO_QUERY ); +} + +void SAL_CALL DataPoint::setParent( + const Reference< uno::XInterface >& Parent ) +{ + m_xParentProperties = Reference< beans::XPropertySet >( Parent, uno::UNO_QUERY ); +} + +// ____ OPropertySet ____ +void DataPoint::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + // the value set at the data series is the default + uno::Reference< beans::XFastPropertySet > xFast( m_xParentProperties.get(), uno::UNO_QUERY ); + if( !xFast.is()) + { + OSL_ENSURE( m_bNoParentPropAllowed, "data point needs a parent property set to provide values correctly" ); + rAny.clear(); + return; + } + + rAny = xFast->getFastPropertyValue( nHandle ); +} + +void SAL_CALL DataPoint::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, const uno::Any& rValue ) +{ + if( nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y + || nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ) + { + uno::Any aOldValue; + Reference< util::XModifyBroadcaster > xBroadcaster; + getFastPropertyValue( aOldValue, nHandle ); + if( aOldValue.hasValue() && + (aOldValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::removeListener( xBroadcaster, m_xModifyEventForwarder ); + } + + OSL_ASSERT( rValue.getValueType().getTypeClass() == uno::TypeClass_INTERFACE ); + if( rValue.hasValue() && + (rValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::addListener( xBroadcaster, m_xModifyEventForwarder ); + } + } + + ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue ); +} + +::cppu::IPropertyArrayHelper & SAL_CALL DataPoint::getInfoHelper() +{ + return StaticDataPointInfoHelper(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL DataPoint::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDataPointInfoHelper() ) ); + return xPropertySetInfo; +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL DataPoint::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL DataPoint::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL DataPoint::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL DataPoint::disposing( const lang::EventObject& ) +{ + // nothing +} + +// ____ OPropertySet ____ +void DataPoint::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// needed by MSC compiler +using impl::DataPoint_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( DataPoint, DataPoint_Base, ::property::OPropertySet ) + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL DataPoint::getImplementationName() +{ + return "com.sun.star.comp.chart.DataPoint" ; +} + +sal_Bool SAL_CALL DataPoint::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DataPoint::getSupportedServiceNames() +{ + return { + "com.sun.star.drawing.FillProperties", + "com.sun.star.chart2.DataPoint", + "com.sun.star.chart2.DataPointProperties", + "com.sun.star.beans.PropertySet" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataPoint.hxx b/chart2/source/model/main/DataPoint.hxx new file mode 100644 index 0000000000..ba94449fff --- /dev/null +++ b/chart2/source/model/main/DataPoint.hxx @@ -0,0 +1,109 @@ +/* -*- 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 . + */ +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/weakref.hxx> +#include <comphelper/uno3.hxx> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <OPropertySet.hxx> +#include <ModifyListenerHelper.hxx> + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::container::XChild, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener, + css::lang::XServiceInfo > + DataPoint_Base; +} + +class DataPoint final : + public impl::DataPoint_Base, + public ::property::OPropertySet +{ +public: + explicit DataPoint( const css::uno::Reference< css::beans::XPropertySet > & rParentProperties ); + virtual ~DataPoint() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +private: + explicit DataPoint( const DataPoint & rOther ); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast + ( sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + // Note: m_xParentProperties are not cloned! + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XChild ____ + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent() override; + virtual void SAL_CALL setParent( + const css::uno::Reference< css::uno::XInterface >& Parent ) override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + css::uno::WeakReference< css::beans::XPropertySet > m_xParentProperties; + + rtl::Reference<ModifyEventForwarder> m_xModifyEventForwarder; + bool m_bNoParentPropAllowed; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataPointProperties.cxx b/chart2/source/model/main/DataPointProperties.cxx new file mode 100644 index 0000000000..819336edd9 --- /dev/null +++ b/chart2/source/model/main/DataPointProperties.cxx @@ -0,0 +1,544 @@ +/* -*- 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 "DataPointProperties.hxx" +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <unonames.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/LineDash.hpp> +#include <com/sun/star/drawing/LineCap.hpp> +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <com/sun/star/drawing/RectanglePoint.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp> +#include <com/sun/star/chart2/DataPointGeometry3D.hpp> +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <com/sun/star/chart2/Symbol.hpp> + +#include <tools/color.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +void DataPointProperties::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + // DataPointProperties + + // Common + + rOutProperties.emplace_back( "Color", + PROP_DATAPOINT_COLOR, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillColor", + PROP_DATAPOINT_COLOR, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Transparency", + PROP_DATAPOINT_TRANSPARENCY, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillTransparence", + PROP_DATAPOINT_TRANSPARENCY, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // Fill Properties + rOutProperties.emplace_back( "FillStyle", + PROP_DATAPOINT_FILL_STYLE, + cppu::UnoType<drawing::FillStyle>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TransparencyGradientName", + PROP_DATAPOINT_TRANSPARENCY_GRADIENT_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillTransparenceGradientName", + PROP_DATAPOINT_TRANSPARENCY_GRADIENT_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "GradientName", + PROP_DATAPOINT_GRADIENT_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillGradientName", + PROP_DATAPOINT_GRADIENT_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "GradientStepCount", + PROP_DATAPOINT_GRADIENT_STEPCOUNT, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillGradientStepCount", + PROP_DATAPOINT_GRADIENT_STEPCOUNT, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "HatchName", + PROP_DATAPOINT_HATCH_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillHatchName", + PROP_DATAPOINT_HATCH_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillBitmapName", + PROP_DATAPOINT_FILL_BITMAP_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillBackground", + PROP_DATAPOINT_FILL_BACKGROUND, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + // border for filled objects + rOutProperties.emplace_back( "BorderColor", + PROP_DATAPOINT_BORDER_COLOR, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "BorderStyle", + PROP_DATAPOINT_BORDER_STYLE, + cppu::UnoType<drawing::LineStyle>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "BorderWidth", + PROP_DATAPOINT_BORDER_WIDTH, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "BorderDashName", + PROP_DATAPOINT_BORDER_DASH_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "BorderTransparency", + PROP_DATAPOINT_BORDER_TRANSPARENCY, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + // Line Properties + + rOutProperties.emplace_back( "LineColor", + PROP_DATAPOINT_BORDER_COLOR, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineStyle", + LinePropertiesHelper::PROP_LINE_STYLE, + cppu::UnoType<drawing::LineStyle>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineWidth", + LinePropertiesHelper::PROP_LINE_WIDTH, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineDash", + LinePropertiesHelper::PROP_LINE_DASH, + cppu::UnoType<drawing::LineDash>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LineDashName", + LinePropertiesHelper::PROP_LINE_DASH_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LineTransparence", + PROP_DATAPOINT_BORDER_TRANSPARENCY, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LineCap", + ::chart::LinePropertiesHelper::PROP_LINE_CAP, + cppu::UnoType<drawing::LineCap>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // FillProperties + // bitmap properties + rOutProperties.emplace_back( "FillBitmapOffsetX", + FillProperties::PROP_FILL_BITMAP_OFFSETX, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapOffsetY", + FillProperties::PROP_FILL_BITMAP_OFFSETY, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapPositionOffsetX", + FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETX, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapPositionOffsetY", + FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETY, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapRectanglePoint", + FillProperties::PROP_FILL_BITMAP_RECTANGLEPOINT, + cppu::UnoType<drawing::RectanglePoint>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapLogicalSize", + FillProperties::PROP_FILL_BITMAP_LOGICALSIZE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapSizeX", + FillProperties::PROP_FILL_BITMAP_SIZEX, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapSizeY", + FillProperties::PROP_FILL_BITMAP_SIZEY, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapMode", + FillProperties::PROP_FILL_BITMAP_MODE, + cppu::UnoType<drawing::BitmapMode>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // others + rOutProperties.emplace_back( "Symbol", + PROP_DATAPOINT_SYMBOL_PROP, + cppu::UnoType<chart2::Symbol>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Offset", + PROP_DATAPOINT_OFFSET, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Geometry3D", + PROP_DATAPOINT_GEOMETRY3D, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_NUMFMT, + PROP_DATAPOINT_NUMBER_FORMAT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LINK_TO_SRC_NUMFMT, + PROP_DATAPOINT_LINK_NUMBERFORMAT_TO_SOURCE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //additional 'PercentageNumberFormat' + rOutProperties.emplace_back( "PercentageNumberFormat", + PROP_DATAPOINT_PERCENTAGE_NUMBER_FORMAT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LabelPlacement", + PROP_DATAPOINT_LABEL_PLACEMENT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_DATAPOINT_REFERENCE_DIAGRAM_SIZE, + cppu::UnoType<awt::Size>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "TextRotation", + PROP_DATAPOINT_TEXT_ROTATION, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // statistics + rOutProperties.emplace_back( CHART_UNONAME_ERRORBAR_X, + PROP_DATAPOINT_ERROR_BAR_X, + // XPropertySet supporting service ErrorBar + cppu::UnoType<beans::XPropertySet>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_ERRORBAR_Y, + PROP_DATAPOINT_ERROR_BAR_Y, + // XPropertySet supporting service ErrorBar + cppu::UnoType<beans::XPropertySet>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "ShowErrorBox", + PROP_DATAPOINT_SHOW_ERROR_BOX, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "PercentDiagonal", + PROP_DATAPOINT_PERCENT_DIAGONAL, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + // Properties specific to data label. + + rOutProperties.emplace_back( CHART_UNONAME_LABEL, + PROP_DATAPOINT_LABEL, + cppu::UnoType<chart2::DataPointLabel>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextWordWrap", + PROP_DATAPOINT_TEXT_WORD_WRAP, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_SEP, + PROP_DATAPOINT_LABEL_SEPARATOR, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_STYLE, + PROP_DATAPOINT_LABEL_BORDER_STYLE, + cppu::UnoType<drawing::LineStyle>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_COLOR, + PROP_DATAPOINT_LABEL_BORDER_COLOR, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_STYLE, + PROP_DATAPOINT_LABEL_FILL_STYLE, + cppu::UnoType<drawing::FillStyle>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_COLOR, + PROP_DATAPOINT_LABEL_FILL_COLOR, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_BACKGROUND, + PROP_DATAPOINT_LABEL_FILL_BACKGROUND, + cppu::UnoType<sal_Bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_HATCH_NAME, + PROP_DATAPOINT_LABEL_FILL_HATCH_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_WIDTH, + PROP_DATAPOINT_LABEL_BORDER_WIDTH, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_DASH, + PROP_DATAPOINT_LABEL_BORDER_DASH, + cppu::UnoType<drawing::LineDash>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_DASHNAME, + PROP_DATAPOINT_LABEL_BORDER_DASH_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_TRANS, + PROP_DATAPOINT_LABEL_BORDER_TRANS, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_CUSTOM_LABEL_FIELDS, + PROP_DATAPOINT_CUSTOM_LABEL_FIELDS, + cppu::UnoType<uno::Sequence<uno::Reference<chart2::XDataPointCustomLabelField>>>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT); + + rOutProperties.emplace_back( "CustomLabelPosition", + PROP_DATAPOINT_LABEL_CUSTOM_POS, + cppu::UnoType<chart2::RelativePosition>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +void DataPointProperties::AddDefaultsToMap( + ::chart::tPropertyValueMap & rOutMap ) +{ + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_COLOR, Color(0x99, 0xcc, 0xff) ); // blue 8 + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_TRANSPARENCY, sal_Int16(0) ); + + //fill + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_FILL_STYLE, drawing::FillStyle_SOLID ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_TRANSPARENCY_GRADIENT_NAME ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_GRADIENT_NAME ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_HATCH_NAME ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_FILL_BITMAP_NAME ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_FILL_BACKGROUND, false ); + + //border + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_BORDER_COLOR, COL_BLACK ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_BORDER_STYLE, drawing::LineStyle_SOLID ); // drawing::LineStyle_NONE + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_BORDER_WIDTH, sal_Int32(0) ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_BORDER_DASH_NAME ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_BORDER_TRANSPARENCY, sal_Int16(0) ); + + //line + PropertyHelper::setPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_SOLID ); + PropertyHelper::setPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_WIDTH, sal_Int32(0) ); + PropertyHelper::setPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_DASH, drawing::LineDash()); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_DASH_NAME ); + PropertyHelper::setPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_CAP, drawing::LineCap_BUTT); + + //fill bitmap + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_OFFSETX, sal_Int16(0) ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_OFFSETY, sal_Int16(0) ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETX, sal_Int16(0) ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETY, sal_Int16(0) ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_RECTANGLEPOINT, drawing::RectanglePoint_MIDDLE_MIDDLE ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_LOGICALSIZE, true ); + + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_SIZEX, sal_Int32(0) ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_SIZEY, sal_Int32(0) ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_MODE, drawing::BitmapMode_REPEAT ); + + //others + chart2::Symbol aSymbProp; + aSymbProp.Style = chart2::SymbolStyle_NONE; + aSymbProp.StandardSymbol = 0; + aSymbProp.Size = awt::Size( 250, 250 ); // ca. 7pt x 7pt (7pt=246.94) + aSymbProp.BorderColor = sal_Int32(COL_BLACK); + aSymbProp.FillColor = 0xee4000; // OrangeRed2 + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_SYMBOL_PROP, aSymbProp ); + + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_OFFSET, 0.0 ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_GEOMETRY3D, chart2::DataPointGeometry3D::CUBOID ); + + //@todo maybe choose a different one here -> should be dynamically that of the attached axis + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_ERROR_BAR_X, uno::Reference< beans::XPropertySet >()); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_ERROR_BAR_Y, uno::Reference< beans::XPropertySet >()); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_PERCENT_DIAGONAL, sal_Int16(0) ); + + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_TEXT_ROTATION, 0.0 ); + + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LINK_NUMBERFORMAT_TO_SOURCE, true); + + // data label + PropertyHelper::setPropertyValueDefault( + rOutMap, PROP_DATAPOINT_LABEL, + chart2::DataPointLabel( + false, // ShowNumber + false, // ShowNumberInPercent + false, // ShowCategoryName + false, // ShowLegendSymbol + false, // ShowCustomLabel + false // ShowSeriesName + )); + + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_TEXT_WORD_WRAP, false ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_LABEL_SEPARATOR, OUString(" ") ); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_STYLE, drawing::LineStyle_NONE); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_COLOR); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_FILL_STYLE); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_FILL_COLOR); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_FILL_BACKGROUND); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_FILL_HATCH_NAME); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_WIDTH, sal_Int32(0)); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_DASH, drawing::LineDash()); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_DASH_NAME); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_TRANS, sal_Int16(0)); + + uno::Sequence<uno::Reference<chart2::XDataPointCustomLabelField>> aFields(0); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_CUSTOM_LABEL_FIELDS, aFields); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataPointProperties.hxx b/chart2/source/model/main/DataPointProperties.hxx new file mode 100644 index 0000000000..ada7907b88 --- /dev/null +++ b/chart2/source/model/main/DataPointProperties.hxx @@ -0,0 +1,103 @@ +/* -*- 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 . + */ +#pragma once + +#include <PropertyHelper.hxx> +#include <FastPropertyIdRanges.hxx> + +#include <vector> + +namespace com::sun::star::beans { struct Property; } + +namespace chart +{ + +// implements service DataPointProperties +namespace DataPointProperties +{ + // FastProperty Ids for properties + enum + { + PROP_DATAPOINT_LABEL_FILL_STYLE, + PROP_DATAPOINT_LABEL_FILL_COLOR, + PROP_DATAPOINT_LABEL_FILL_BACKGROUND, + PROP_DATAPOINT_LABEL_FILL_HATCH_NAME, + + // common + PROP_DATAPOINT_COLOR = FAST_PROPERTY_ID_START_DATA_POINT, + PROP_DATAPOINT_TRANSPARENCY, + + // fill + PROP_DATAPOINT_FILL_STYLE, + PROP_DATAPOINT_TRANSPARENCY_GRADIENT_NAME, + PROP_DATAPOINT_GRADIENT_NAME, + PROP_DATAPOINT_GRADIENT_STEPCOUNT, + PROP_DATAPOINT_HATCH_NAME, + PROP_DATAPOINT_FILL_BITMAP_NAME, + PROP_DATAPOINT_FILL_BACKGROUND, + + // border (of filled objects) + PROP_DATAPOINT_BORDER_COLOR, + PROP_DATAPOINT_BORDER_STYLE, + PROP_DATAPOINT_BORDER_WIDTH, + PROP_DATAPOINT_BORDER_DASH_NAME, + PROP_DATAPOINT_BORDER_TRANSPARENCY, + + // others + PROP_DATAPOINT_SYMBOL_PROP, + PROP_DATAPOINT_OFFSET, + PROP_DATAPOINT_GEOMETRY3D, + PROP_DATAPOINT_NUMBER_FORMAT, + PROP_DATAPOINT_LINK_NUMBERFORMAT_TO_SOURCE, + PROP_DATAPOINT_PERCENTAGE_NUMBER_FORMAT, + PROP_DATAPOINT_LABEL_PLACEMENT, + PROP_DATAPOINT_REFERENCE_DIAGRAM_SIZE, + PROP_DATAPOINT_TEXT_ROTATION, + + // statistics + PROP_DATAPOINT_ERROR_BAR_X, + PROP_DATAPOINT_ERROR_BAR_Y, + PROP_DATAPOINT_SHOW_ERROR_BOX, + PROP_DATAPOINT_PERCENT_DIAGONAL, + + // label + PROP_DATAPOINT_LABEL, + PROP_DATAPOINT_LABEL_SEPARATOR, + PROP_DATAPOINT_TEXT_WORD_WRAP, + PROP_DATAPOINT_LABEL_BORDER_STYLE, + PROP_DATAPOINT_LABEL_BORDER_COLOR, + PROP_DATAPOINT_LABEL_BORDER_WIDTH, + PROP_DATAPOINT_LABEL_BORDER_DASH, + PROP_DATAPOINT_LABEL_BORDER_DASH_NAME, + PROP_DATAPOINT_LABEL_BORDER_TRANS, + PROP_DATAPOINT_CUSTOM_LABEL_FIELDS, + PROP_DATAPOINT_LABEL_CUSTOM_POS + + // additionally some properties from ::chart::LineProperties + }; + + void AddPropertiesToVector( + std::vector< css::beans::Property > & rOutProperties ); + + void AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataSeries.cxx b/chart2/source/model/main/DataSeries.cxx new file mode 100644 index 0000000000..38f2c474b4 --- /dev/null +++ b/chart2/source/model/main/DataSeries.cxx @@ -0,0 +1,733 @@ +/* -*- 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 <DataSeries.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 <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 <comphelper/diagnose_ex.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> + +#include <algorithm> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::osl::MutexGuard; + +namespace chart +{ +const ::chart::tPropertyValueMap & StaticDataSeriesDefaults() +{ + 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 + +namespace +{ + +::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 ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return oHelper; +}; + +void lcl_SetParent( + const uno::Reference< uno::XInterface > & xChildInterface, + const uno::Reference< uno::XInterface > & xParentInterface ) +{ + uno::Reference< container::XChild > xChild( xChildInterface, uno::UNO_QUERY ); + if( xChild.is()) + xChild->setParent( xParentInterface ); +} + +typedef std::map< sal_Int32, css::uno::Reference< css::beans::XPropertySet > > + lcl_tDataPointMap; + +void lcl_CloneAttributedDataPoints( + const lcl_tDataPointMap & rSource, lcl_tDataPointMap & rDestination, + const uno::Reference< uno::XInterface > & xSeries ) +{ + for (auto const& elem : rSource) + { + Reference< beans::XPropertySet > xPoint( elem.second ); + if( xPoint.is()) + { + Reference< util::XCloneable > xCloneable( xPoint, uno::UNO_QUERY ); + if( xCloneable.is()) + { + xPoint.set( xCloneable->createClone(), uno::UNO_QUERY ); + if( xPoint.is()) + { + lcl_SetParent( xPoint, xSeries ); + rDestination.emplace( elem.first, xPoint ); + } + } + } + } +} + +} // anonymous namespace + +namespace chart +{ + +DataSeries::DataSeries() : + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ +} + +DataSeries::DataSeries( const DataSeries & rOther ) : + impl::DataSeries_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + if( ! rOther.m_aDataSequences.empty()) + { + CloneHelper::CloneRefVector(rOther.m_aDataSequences, m_aDataSequences ); + ModifyListenerHelper::addListenerToAllElements( m_aDataSequences, m_xModifyEventForwarder ); + } + + CloneHelper::CloneRefVector( rOther.m_aRegressionCurves, m_aRegressionCurves ); + ModifyListenerHelper::addListenerToAllElements( m_aRegressionCurves, m_xModifyEventForwarder ); + + // add as listener to XPropertySet properties + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); +} + +// late initialization to call after copy-constructing +void DataSeries::Init( const DataSeries & rOther ) +{ + Reference< uno::XInterface > xThisInterface( static_cast< ::cppu::OWeakObject * >( this )); + if( ! rOther.m_aAttributedDataPoints.empty()) + { + lcl_CloneAttributedDataPoints( + rOther.m_aAttributedDataPoints, m_aAttributedDataPoints, xThisInterface ); + ModifyListenerHelper::addListenerToAllMapElements( m_aAttributedDataPoints, m_xModifyEventForwarder ); + } + + // add as parent to error bars + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + lcl_SetParent( xPropertySet, xThisInterface ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + lcl_SetParent( xPropertySet, xThisInterface ); +} + +DataSeries::~DataSeries() +{ + try + { + ModifyListenerHelper::removeListenerFromAllMapElements( m_aAttributedDataPoints, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListenerFromAllElements( m_aRegressionCurves, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListenerFromAllElements( m_aDataSequences, m_xModifyEventForwarder ); + + // remove listener from XPropertySet properties + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL DataSeries::createClone() +{ + rtl::Reference<DataSeries> pNewSeries( new DataSeries( *this )); + // do initialization that uses uno references to the clone + pNewSeries->Init( *this ); + + return pNewSeries; +} + +// ____ OPropertySet ____ +void DataSeries::GetDefaultValue( sal_Int32 nHandle, uno::Any& rDest ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticDataSeriesDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rDest.clear(); + else + rDest = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL DataSeries::getInfoHelper() +{ + return StaticDataSeriesInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL DataSeries::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropSetInfo = + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDataSeriesInfoHelper() ); + return xPropSetInfo; +} + +void SAL_CALL DataSeries::getFastPropertyValue + ( uno::Any& rValue, + sal_Int32 nHandle ) const +{ + // special handling for get. set is not possible for this property + if( nHandle == DataSeriesProperties::PROP_DATASERIES_ATTRIBUTED_DATA_POINTS ) + { + // TODO: only add those property sets that are really modified + + rValue <<= comphelper::mapKeysToSequence(m_aAttributedDataPoints); + } + else + OPropertySet::getFastPropertyValue( rValue, nHandle ); +} + +void SAL_CALL DataSeries::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, const uno::Any& rValue ) +{ + if( nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y + || nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ) + { + uno::Any aOldValue; + Reference< util::XModifyBroadcaster > xBroadcaster; + getFastPropertyValue( aOldValue, nHandle ); + if( aOldValue.hasValue() && + (aOldValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::removeListener( xBroadcaster, m_xModifyEventForwarder ); + } + + OSL_ASSERT( rValue.getValueType().getTypeClass() == uno::TypeClass_INTERFACE ); + if( rValue.hasValue() && + (rValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::addListener( xBroadcaster, m_xModifyEventForwarder ); + } + } + + ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue ); +} + +Reference< beans::XPropertySet > + SAL_CALL DataSeries::getDataPointByIndex( sal_Int32 nIndex ) +{ + Reference< beans::XPropertySet > xResult; + + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences; + { + MutexGuard aGuard( m_aMutex ); + aSequences = m_aDataSequences; + } + + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aValuesSeries( + DataSeriesHelper::getAllDataSequencesByRole( aSequences , "values" ) ); + + if (aValuesSeries.empty()) + throw lang::IndexOutOfBoundsException(); + + Reference< chart2::data::XDataSequence > xSeq( aValuesSeries.front()->getValues() ); + if( 0 <= nIndex && nIndex < xSeq->getData().getLength() ) + { + { + MutexGuard aGuard( m_aMutex ); + tDataPointAttributeContainer::iterator aIt( m_aAttributedDataPoints.find( nIndex ) ); + if( aIt != m_aAttributedDataPoints.end() ) + xResult = (*aIt).second; + } + if( !xResult.is() ) + { + Reference< beans::XPropertySet > xParentProperties; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xParentProperties = this; + xModifyEventForwarder = m_xModifyEventForwarder; + } + + // create a new XPropertySet for this data point + xResult.set( new DataPoint( xParentProperties ) ); + { + MutexGuard aGuard( m_aMutex ); + m_aAttributedDataPoints[ nIndex ] = xResult; + } + ModifyListenerHelper::addListener( xResult, xModifyEventForwarder ); + } + } + + return xResult; +} + +void SAL_CALL DataSeries::resetDataPoint( sal_Int32 nIndex ) +{ + Reference< beans::XPropertySet > xDataPointProp; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + tDataPointAttributeContainer::iterator aIt( m_aAttributedDataPoints.find( nIndex )); + if( aIt != m_aAttributedDataPoints.end()) + { + xDataPointProp = (*aIt).second; + m_aAttributedDataPoints.erase(aIt); + } + + } + if( xDataPointProp.is() ) + { + Reference< util::XModifyBroadcaster > xBroadcaster( xDataPointProp, uno::UNO_QUERY ); + if( xBroadcaster.is() && xModifyEventForwarder.is()) + xBroadcaster->removeModifyListener( xModifyEventForwarder ); + fireModifyEvent(); + } +} + +void SAL_CALL DataSeries::resetAllDataPoints() +{ + tDataPointAttributeContainer aOldAttributedDataPoints; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + std::swap( aOldAttributedDataPoints, m_aAttributedDataPoints ); + } + ModifyListenerHelper::removeListenerFromAllMapElements( aOldAttributedDataPoints, xModifyEventForwarder ); + aOldAttributedDataPoints.clear(); + fireModifyEvent(); +} + +// ____ XDataSink ____ +void SAL_CALL DataSeries::setData( const uno::Sequence< 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 ); + 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 ); + ModifyListenerHelper::addListenerToAllElements( aNewDataSequences, xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ XDataSource ____ +Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL DataSeries::getDataSequences() +{ + MutexGuard aGuard( m_aMutex ); + 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(), pRegressionCurve ) + != m_aRegressionCurves.end()) + throw lang::IllegalArgumentException("curve not found", static_cast<cppu::OWeakObject*>(this), 1); + m_aRegressionCurves.push_back( pRegressionCurve ); + } + ModifyListenerHelper::addListener( rtl::Reference<RegressionCurveModel>(pRegressionCurve), xModifyEventForwarder ); + fireModifyEvent(); +} + +void SAL_CALL DataSeries::removeRegressionCurve( + const uno::Reference< chart2::XRegressionCurve >& xRegressionCurve ) +{ + 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(), pRegressionCurve ) ); + if( aIt == m_aRegressionCurves.end()) + throw container::NoSuchElementException( + "The given regression curve is no element of this series", + static_cast< uno::XWeak * >( this )); + m_aRegressionCurves.erase( aIt ); + } + + 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<uno::Reference< chart2::XRegressionCurve >>( m_aRegressionCurves ); +} + +void SAL_CALL DataSeries::setRegressionCurves( + const Sequence< Reference< chart2::XRegressionCurve > >& aRegressionCurves ) +{ + tRegressionCurveContainerType aOldCurves; + 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 ); + xModifyEventForwarder = m_xModifyEventForwarder; + std::swap( aOldCurves, m_aRegressionCurves ); + m_aRegressionCurves = aNewCurves; + } + ModifyListenerHelper::removeListenerFromAllElements( aOldCurves, xModifyEventForwarder ); + ModifyListenerHelper::addListenerToAllElements( aNewCurves, xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL DataSeries::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL DataSeries::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL DataSeries::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL DataSeries::disposing( const lang::EventObject& ) +{ +} + +// ____ OPropertySet ____ +void DataSeries::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void DataSeries::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +using impl::DataSeries_Base; +using ::property::OPropertySet; + +IMPLEMENT_FORWARD_XINTERFACE2( DataSeries, DataSeries_Base, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( DataSeries, DataSeries_Base, OPropertySet ) + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL DataSeries::getImplementationName() +{ + return "com.sun.star.comp.chart.DataSeries"; +} + +sal_Bool SAL_CALL DataSeries::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DataSeries::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.DataSeries", + "com.sun.star.chart2.DataPointProperties", + "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 * +com_sun_star_comp_chart_DataSeries_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::DataSeries ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataSeriesProperties.cxx b/chart2/source/model/main/DataSeriesProperties.cxx new file mode 100644 index 0000000000..e6d40feb5a --- /dev/null +++ b/chart2/source/model/main/DataSeriesProperties.cxx @@ -0,0 +1,99 @@ +/* -*- 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 <DataSeriesProperties.hxx> +#include "DataPointProperties.hxx" +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/chart2/StackingDirection.hpp> + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +void DataSeriesProperties::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "AttributedDataPoints", + PROP_DATASERIES_ATTRIBUTED_DATA_POINTS, + cppu::UnoType<uno::Sequence< sal_Int32 >>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "StackingDirection", + PROP_DATASERIES_STACKING_DIRECTION, + cppu::UnoType<chart2::StackingDirection>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "VaryColorsByPoint", + PROP_DATASERIES_VARY_COLORS_BY_POINT, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AttachedAxisIndex", + PROP_DATASERIES_ATTACHED_AXIS_INDEX, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ShowLegendEntry", + PROP_DATASERIES_SHOW_LEGEND_ENTRY, + cppu::UnoType<sal_Bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "DeletedLegendEntries", + PROP_DATASERIES_DELETED_LEGEND_ENTRIES, + cppu::UnoType<uno::Sequence<sal_Int32>>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ShowCustomLeaderLines", + PROP_DATASERIES_SHOW_CUSTOM_LEADERLINES, + cppu::UnoType<sal_Bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // add properties of service DataPointProperties + DataPointProperties::AddPropertiesToVector( rOutProperties ); +} + +void DataSeriesProperties::AddDefaultsToMap( + tPropertyValueMap & rOutMap ) +{ + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_STACKING_DIRECTION, chart2::StackingDirection_NO_STACKING ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_VARY_COLORS_BY_POINT, false ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_ATTACHED_AXIS_INDEX, sal_Int32(0) ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_SHOW_LEGEND_ENTRY, true ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_SHOW_CUSTOM_LEADERLINES, true ); + + // PROP_DATASERIES_ATTRIBUTED_DATA_POINTS has no default + + // add properties of service DataPointProperties + DataPointProperties::AddDefaultsToMap( rOutMap ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataTable.cxx b/chart2/source/model/main/DataTable.cxx new file mode 100644 index 0000000000..6cec190615 --- /dev/null +++ b/chart2/source/model/main/DataTable.cxx @@ -0,0 +1,209 @@ +/* -*- 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/. + */ + +#include <DataTable.hxx> + +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <CharacterProperties.hxx> +#include <ModifyListenerHelper.hxx> +#include <PropertyHelper.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> + +#include <algorithm> + +using namespace css; + +namespace +{ +/** DataTable Properties */ +enum +{ + DataTableProperty_HorizontalBorder, + DataTableProperty_VerticalBorder, + DataTableProperty_Outilne, + DataTableProperty_Keys, +}; + +void lcl_AddPropertiesToVector(std::vector<beans::Property>& rProps) +{ + auto const nBound = beans::PropertyAttribute::BOUND; + auto const nMaybeDefault = beans::PropertyAttribute::MAYBEDEFAULT; + + rProps.emplace_back("HBorder", DataTableProperty_HorizontalBorder, cppu::UnoType<bool>::get(), + nBound | nMaybeDefault); + rProps.emplace_back("VBorder", DataTableProperty_VerticalBorder, cppu::UnoType<bool>::get(), + nBound | nMaybeDefault); + rProps.emplace_back("Outline", DataTableProperty_Outilne, cppu::UnoType<bool>::get(), + nBound | nMaybeDefault); + rProps.emplace_back("Keys", DataTableProperty_Keys, cppu::UnoType<bool>::get(), + nBound | nMaybeDefault); +} + +const ::chart::tPropertyValueMap& StaticDataTableDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() { + ::chart::tPropertyValueMap aMap; + ::chart::LinePropertiesHelper::AddDefaultsToMap(aMap); + ::chart::FillProperties::AddDefaultsToMap(aMap); + ::chart::CharacterProperties::AddDefaultsToMap(aMap); + + ::chart::PropertyHelper::setPropertyValueDefault(aMap, DataTableProperty_HorizontalBorder, + false); + ::chart::PropertyHelper::setPropertyValueDefault(aMap, DataTableProperty_VerticalBorder, + false); + ::chart::PropertyHelper::setPropertyValueDefault(aMap, DataTableProperty_Outilne, false); + ::chart::PropertyHelper::setPropertyValueDefault(aMap, DataTableProperty_Keys, false); + + ::chart::PropertyHelper::setPropertyValue( + aMap, ::chart::LinePropertiesHelper::PROP_LINE_WIDTH, uno::Any(sal_Int32(1))); + + ::chart::PropertyHelper::setPropertyValueDefault( + aMap, ::chart::FillProperties::PROP_FILL_STYLE, drawing::FillStyle_NONE); + + 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; +}; + +cppu::OPropertyArrayHelper& StaticDataTableInfoHelper() +{ + static cppu::OPropertyArrayHelper aPropHelper = []() { + std::vector<beans::Property> aProperties; + lcl_AddPropertiesToVector(aProperties); + ::chart::LinePropertiesHelper::AddPropertiesToVector(aProperties); + ::chart::FillProperties::AddPropertiesToVector(aProperties); + ::chart::CharacterProperties::AddPropertiesToVector(aProperties); + std::sort(aProperties.begin(), aProperties.end(), ::chart::PropertyNameLess()); + + return comphelper::containerToSequence(aProperties); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ +DataTable::DataTable() + : m_xModifyEventForwarder(new ModifyEventForwarder()) +{ +} + +DataTable::DataTable(const DataTable& rOther) + : DataTable_Base(rOther) + , ::property::OPropertySet(rOther) + , m_xModifyEventForwarder(new ModifyEventForwarder()) +{ +} + +DataTable::~DataTable() = default; + +// ____ XCloneable ____ +uno::Reference<util::XCloneable> SAL_CALL DataTable::createClone() +{ + return uno::Reference<util::XCloneable>(new DataTable(*this)); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL DataTable::addModifyListener(const uno::Reference<util::XModifyListener>& aListener) +{ + m_xModifyEventForwarder->addModifyListener(aListener); +} + +void SAL_CALL +DataTable::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener) +{ + m_xModifyEventForwarder->removeModifyListener(aListener); +} + +// ____ XModifyListener ____ +void SAL_CALL DataTable::modified(const lang::EventObject& aEvent) +{ + m_xModifyEventForwarder->modified(aEvent); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL DataTable::disposing(const lang::EventObject& /* Source */) +{ + // nothing +} + +// ____ OPropertySet ____ +void DataTable::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified(lang::EventObject(static_cast<uno::XWeak*>(this))); +} + +// ____ OPropertySet ____ +void DataTable::GetDefaultValue(sal_Int32 nHandle, uno::Any& rAny) const +{ + const tPropertyValueMap& rStaticDefaults = StaticDataTableDefaults(); + auto aFound = rStaticDefaults.find(nHandle); + if (aFound == rStaticDefaults.end()) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper& SAL_CALL DataTable::getInfoHelper() +{ + return StaticDataTableInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference<beans::XPropertySetInfo> SAL_CALL DataTable::getPropertySetInfo() +{ + static uno::Reference<beans::XPropertySetInfo> xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDataTableInfoHelper())); + return xPropertySetInfo; +} + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL DataTable::getImplementationName() +{ + return "com.sun.star.comp.chart2.DataTable"; +} + +sal_Bool SAL_CALL DataTable::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> SAL_CALL DataTable::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.DataTable", "com.sun.star.beans.PropertySet", + "com.sun.star.drawing.FillProperties", "com.sun.star.drawing.LineProperties", + "com.sun.star.style.CharacterProperties" }; +} + +IMPLEMENT_FORWARD_XINTERFACE2(DataTable, DataTable_Base, ::property::OPropertySet) +IMPLEMENT_FORWARD_XTYPEPROVIDER2(DataTable, DataTable_Base, ::property::OPropertySet) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_chart2_DataTable_get_implementation( + css::uno::XComponentContext* /*pComponentContext*/, uno::Sequence<uno::Any> const& /*rAny*/) +{ + return cppu::acquire(new ::chart::DataTable); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Diagram.cxx b/chart2/source/model/main/Diagram.cxx new file mode 100644 index 0000000000..db7be686b0 --- /dev/null +++ b/chart2/source/model/main/Diagram.cxx @@ -0,0 +1,2288 @@ +/* -*- 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 <Diagram.hxx> +#include <AxisHelper.hxx> +#include <BaseGFXHelper.hxx> +#include <ChartTypeHelper.hxx> +#include <ChartTypeManager.hxx> +#include <ChartTypeTemplate.hxx> +#include <ChartType.hxx> +#include <DataSeriesHelper.hxx> +#include <PropertyHelper.hxx> +#include <RegressionCurveHelper.hxx> +#include <RegressionCurveModel.hxx> +#include "Wall.hxx" +#include <ModifyListenerHelper.hxx> +#include <UserDefinedProperties.hxx> +#include <ConfigColorScheme.hxx> +#include <DiagramHelper.hxx> +#include <ThreeDHelper.hxx> +#include <CloneHelper.hxx> +#include <SceneProperties.hxx> +#include <unonames.hxx> +#include <BaseCoordinateSystem.hxx> +#include <Legend.hxx> +#include <Axis.hxx> +#include <DataTable.hxx> +#include <servicenames_charttypes.hxx> +#include <defines.hxx> + +#include <basegfx/numeric/ftools.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/DataPointGeometry3D.hpp> +#include <com/sun/star/chart2/StackingDirection.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/RelativeSize.hpp> +#include <com/sun/star/chart/MissingValueTreatment.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/CloseVetoException.hpp> + +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <editeng/unoprnms.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/math.hxx> +#include <tools/helpers.hxx> + +#include <algorithm> +#include <utility> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans::PropertyAttribute; +using namespace ::chart::SceneProperties; + +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 +{ + +enum +{ + PROP_DIAGRAM_REL_POS, + PROP_DIAGRAM_REL_SIZE, + PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS, + PROP_DIAGRAM_SORT_BY_X_VALUES, + PROP_DIAGRAM_CONNECT_BARS, + PROP_DIAGRAM_GROUP_BARS_PER_AXIS, + PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, + PROP_DIAGRAM_STARTING_ANGLE, + PROP_DIAGRAM_RIGHT_ANGLED_AXES, + PROP_DIAGRAM_PERSPECTIVE, + PROP_DIAGRAM_ROTATION_HORIZONTAL, + PROP_DIAGRAM_ROTATION_VERTICAL, + PROP_DIAGRAM_MISSING_VALUE_TREATMENT, + PROP_DIAGRAM_3DRELATIVEHEIGHT, + PROP_DIAGRAM_DATATABLEHBORDER, + PROP_DIAGRAM_DATATABLEVBORDER, + PROP_DIAGRAM_DATATABLEOUTLINE, + PROP_DIAGRAM_EXTERNALDATA +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "RelativePosition", + PROP_DIAGRAM_REL_POS, + cppu::UnoType<chart2::RelativePosition>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RelativeSize", + PROP_DIAGRAM_REL_SIZE, + cppu::UnoType<chart2::RelativeSize>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "PosSizeExcludeAxes", + PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_SORT_BY_XVALUES, + PROP_DIAGRAM_SORT_BY_X_VALUES, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ConnectBars", + PROP_DIAGRAM_CONNECT_BARS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "GroupBarsPerAxis", + PROP_DIAGRAM_GROUP_BARS_PER_AXIS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "IncludeHiddenCells", + PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "StartingAngle", + PROP_DIAGRAM_STARTING_ANGLE, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "RightAngledAxes", + PROP_DIAGRAM_RIGHT_ANGLED_AXES, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Perspective", + PROP_DIAGRAM_PERSPECTIVE, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RotationHorizontal", + PROP_DIAGRAM_ROTATION_HORIZONTAL, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RotationVertical", + PROP_DIAGRAM_ROTATION_VERTICAL, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "MissingValueTreatment", + PROP_DIAGRAM_MISSING_VALUE_TREATMENT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "3DRelativeHeight", + PROP_DIAGRAM_3DRELATIVEHEIGHT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "ExternalData", + PROP_DIAGRAM_EXTERNALDATA, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::MAYBEVOID ); +} + +const ::chart::tPropertyValueMap& StaticDiagramDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aMap; + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_SORT_BY_X_VALUES, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_CONNECT_BARS, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_GROUP_BARS_PER_AXIS, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_RIGHT_ANGLED_AXES, false ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_DIAGRAM_STARTING_ANGLE, 90 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_DIAGRAM_3DRELATIVEHEIGHT, 100 ); + ::chart::SceneProperties::AddDefaultsToMap( aMap ); + return aMap; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& StaticDiagramInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::SceneProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return ::cppu::OPropertyArrayHelper( aProperties.data(), aProperties.size() ); + }(); + return aPropHelper; +}; + +const uno::Reference< beans::XPropertySetInfo >& StaticDiagramInfo() +{ + static const uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDiagramInfoHelper() ) ); + return xPropertySetInfo; +}; + +void lcl_CloneCoordinateSystems( + const ::chart::Diagram::tCoordinateSystemContainerType & rSource, + ::chart::Diagram::tCoordinateSystemContainerType & rDestination ) +{ + for( rtl::Reference< ::chart::BaseCoordinateSystem > const & i : rSource ) + { + auto xClone = i->createClone(); + ::chart::BaseCoordinateSystem* pClone = dynamic_cast<::chart::BaseCoordinateSystem*>(xClone.get()); + assert(pClone); + rDestination.push_back( pClone ); + } +} + +} // anonymous namespace + +namespace chart +{ + +Diagram::Diagram( uno::Reference< uno::XComponentContext > xContext ) : + m_xContext(std::move( xContext )), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + // Set camera position to a default position (that should be set hard, so + // that it will be exported. The property default is a camera looking + // straight ono the scene). These defaults have been acquired from the old + // chart implementation. + setFastPropertyValue_NoBroadcast( + PROP_SCENE_CAMERA_GEOMETRY, uno::Any( + ThreeDHelper::getDefaultCameraGeometry())); +} + +Diagram::Diagram( const Diagram & rOther ) : + impl::Diagram_Base(rOther), + ::property::OPropertySet( rOther ), + m_xContext( rOther.m_xContext ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + lcl_CloneCoordinateSystems( rOther.m_aCoordSystems, m_aCoordSystems ); + for (auto & xSystem : m_aCoordSystems) + xSystem->addModifyListener(m_xModifyEventForwarder); + + if ( rOther.m_xWall ) + m_xWall = new Wall( *rOther.m_xWall ); + if ( rOther.m_xFloor ) + m_xFloor = new Wall( *rOther.m_xFloor ); + m_xTitle.set( CloneHelper::CreateRefClone< chart2::XTitle >()( rOther.m_xTitle )); + if (rOther.m_xLegend) + m_xLegend = new Legend(*rOther.m_xLegend); + if (rOther.m_xDataTable) + m_xDataTable = new DataTable(*rOther.m_xDataTable); + + if ( m_xWall ) + m_xWall->addModifyListener( m_xModifyEventForwarder ); + if ( m_xFloor ) + m_xFloor->addModifyListener( m_xModifyEventForwarder ); + ModifyListenerHelper::addListener( m_xTitle, m_xModifyEventForwarder ); + ModifyListenerHelper::addListener( m_xLegend, m_xModifyEventForwarder ); +} + +Diagram::~Diagram() +{ + try + { + for (auto & xSystem : m_aCoordSystems) + xSystem->removeModifyListener(m_xModifyEventForwarder); + + if ( m_xWall ) + m_xWall->removeModifyListener( m_xModifyEventForwarder ); + if ( m_xFloor ) + m_xFloor->removeModifyListener( m_xModifyEventForwarder ); + ModifyListenerHelper::removeListener( m_xTitle, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListener( m_xLegend, m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XDiagram ____ +uno::Reference< beans::XPropertySet > SAL_CALL Diagram::getWall() +{ + rtl::Reference< Wall > xRet; + bool bAddListener = false; + { + MutexGuard aGuard( m_aMutex ); + if( !m_xWall.is() ) + { + m_xWall.set( new Wall() ); + bAddListener = true; + } + xRet = m_xWall; + } + if(bAddListener) + xRet->addModifyListener( m_xModifyEventForwarder ); + return xRet; +} + +uno::Reference< beans::XPropertySet > SAL_CALL Diagram::getFloor() +{ + rtl::Reference< Wall > xRet; + bool bAddListener = false; + { + MutexGuard aGuard( m_aMutex ); + if( !m_xFloor.is() ) + { + m_xFloor.set( new Wall() ); + bAddListener = true; + } + xRet = m_xFloor; + } + if(bAddListener) + xRet->addModifyListener( m_xModifyEventForwarder ); + return xRet; +} + +uno::Reference< chart2::XLegend > SAL_CALL Diagram::getLegend() +{ + MutexGuard aGuard( m_aMutex ); + return m_xLegend; +} + +rtl::Reference< ::chart::Legend > Diagram::getLegend2() const +{ + MutexGuard aGuard( m_aMutex ); + return m_xLegend; +} + +void SAL_CALL Diagram::setLegend( const uno::Reference< chart2::XLegend >& xNewLegend ) +{ + auto pLegend = dynamic_cast<Legend*>(xNewLegend.get()); + assert(!xNewLegend || pLegend); + setLegend(rtl::Reference< Legend >(pLegend)); +} + +void Diagram::setLegend( const rtl::Reference< Legend >& xNewLegend ) +{ + rtl::Reference< Legend > xOldLegend; + { + MutexGuard aGuard( m_aMutex ); + if( m_xLegend == xNewLegend ) + return; + xOldLegend = m_xLegend; + m_xLegend = xNewLegend; + } + if( xOldLegend.is()) + ModifyListenerHelper::removeListener( xOldLegend, m_xModifyEventForwarder ); + if( xNewLegend.is()) + ModifyListenerHelper::addListener( xNewLegend, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +Reference< chart2::XColorScheme > SAL_CALL Diagram::getDefaultColorScheme() +{ + Reference< chart2::XColorScheme > xRet; + { + MutexGuard aGuard( m_aMutex ); + xRet = m_xColorScheme; + } + + if( !xRet.is()) + { + xRet.set( createConfigColorScheme( m_xContext )); + MutexGuard aGuard( m_aMutex ); + m_xColorScheme = xRet; + } + return xRet; +} + +void SAL_CALL Diagram::setDefaultColorScheme( const Reference< chart2::XColorScheme >& xColorScheme ) +{ + { + MutexGuard aGuard( m_aMutex ); + m_xColorScheme.set( xColorScheme ); + } + fireModifyEvent(); +} + +void SAL_CALL Diagram::setDiagramData( + const Reference< chart2::data::XDataSource >& xDataSource, + const Sequence< beans::PropertyValue >& aArguments ) +{ + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = new ::chart::ChartTypeManager( m_xContext ); + Diagram::tTemplateWithServiceName aTemplateAndService = getTemplate( xChartTypeManager ); + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( aTemplateAndService.xChartTypeTemplate ); + if( !xTemplate.is() ) + xTemplate = xChartTypeManager->createTemplate( "com.sun.star.chart2.template.Column" ); + if(!xTemplate.is()) + return; + xTemplate->changeDiagramData( rtl::Reference< ::chart::Diagram >(this), xDataSource, aArguments ); +} + +// ____ XTitled ____ +uno::Reference< chart2::XTitle > SAL_CALL Diagram::getTitleObject() +{ + MutexGuard aGuard( m_aMutex ); + return m_xTitle; +} + +void SAL_CALL Diagram::setTitleObject( const uno::Reference< chart2::XTitle >& xNewTitle ) +{ + Reference< chart2::XTitle > xOldTitle; + { + MutexGuard aGuard( m_aMutex ); + if( m_xTitle == xNewTitle ) + return; + xOldTitle = m_xTitle; + m_xTitle = xNewTitle; + } + if( xOldTitle.is()) + ModifyListenerHelper::removeListener( xOldTitle, m_xModifyEventForwarder ); + if( xNewTitle.is()) + ModifyListenerHelper::addListener( xNewTitle, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ X3DDefaultSetter ____ +void SAL_CALL Diagram::set3DSettingsToDefault() +{ + setPropertyToDefault( "D3DSceneDistance"); + setPropertyToDefault( "D3DSceneFocalLength"); + setDefaultRotation(); + setDefaultIllumination(); +} + +void SAL_CALL Diagram::setDefaultRotation() +{ + bool bPieOrDonut( isPieOrDonutChart() ); + setDefaultRotation( bPieOrDonut ); +} + +static ::basegfx::B3DHomMatrix lcl_getCompleteRotationMatrix( Diagram& rDiagram ) +{ + ::basegfx::B3DHomMatrix aCompleteRotation; + double fXAngleRad=0.0; + double fYAngleRad=0.0; + double fZAngleRad=0.0; + rDiagram.getRotationAngle( fXAngleRad, fYAngleRad, fZAngleRad ); + aCompleteRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); + return aCompleteRotation; +} +static void lcl_RotateLightSource( Diagram& rDiagram + , int nLightSourceDirectionProp + , int nLightSourceOnProp + , const ::basegfx::B3DHomMatrix& rRotationMatrix ) +{ + bool bLightOn = false; + if( !(rDiagram.getFastPropertyValue( nLightSourceOnProp ) >>= bLightOn) ) + return; + + if( bLightOn ) + { + drawing::Direction3D aLight; + if( rDiagram.getFastPropertyValue( nLightSourceDirectionProp ) >>= aLight ) + { + ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aLight ) ); + aLightVector = rRotationMatrix*aLightVector; + + rDiagram.setFastPropertyValue( nLightSourceDirectionProp + , uno::Any( BaseGFXHelper::B3DVectorToDirection3D( aLightVector ) ) ); + } + } +} + +static void lcl_setLightsForScheme( Diagram& rDiagram, const ThreeDLookScheme& rScheme ) +{ + if( rScheme == ThreeDLookScheme::ThreeDLookScheme_Unknown) + return; + + // "D3DSceneLightOn2" / UNO_NAME_3D_SCENE_LIGHTON_2 + rDiagram.setFastPropertyValue( PROP_SCENE_LIGHT_ON_2, uno::Any( true ) ); + + rtl::Reference< ChartType > xChartType( rDiagram.getChartTypeByIndex( 0 ) ); + uno::Any aADirection( rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple + ? ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) + : ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) ); + + // "D3DSceneLightDirection2" / UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 + rDiagram.setFastPropertyValue( PROP_SCENE_LIGHT_DIRECTION_2, aADirection ); + //rotate light direction when right angled axes are off but supported + { + bool bRightAngledAxes = false; + rDiagram.getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bRightAngledAxes; // "RightAngledAxes" + if(!bRightAngledAxes) + { + if( ChartTypeHelper::isSupportingRightAngledAxes( xChartType ) ) + { + ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( rDiagram ) ); + BaseGFXHelper::ReduceToRotationMatrix( aRotation ); + // "D3DSceneLightDirection2", "D3DSceneLightOn2" + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_2, PROP_SCENE_LIGHT_ON_2, aRotation ); + } + } + } + + sal_Int32 nColor = ::chart::ChartTypeHelper::getDefaultDirectLightColor( + rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple, xChartType); + // "D3DSceneLightColor2" / UNO_NAME_3D_SCENE_LIGHTCOLOR_2 + rDiagram.setFastPropertyValue( PROP_SCENE_LIGHT_COLOR_2, uno::Any( nColor ) ); + + sal_Int32 nAmbientColor = ::chart::ChartTypeHelper::getDefaultAmbientLightColor( + rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple, xChartType); + // "D3DSceneAmbientColor" / UNO_NAME_3D_SCENE_AMBIENTCOLOR + rDiagram.setFastPropertyValue( PROP_SCENE_AMBIENT_COLOR, uno::Any( nAmbientColor ) ); +} + +void SAL_CALL Diagram::setDefaultIllumination() +{ + drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH ); + try + { + // "D3DSceneShadeMode" + getFastPropertyValue( PROP_SCENE_SHADE_MODE )>>= aShadeMode; + // "D3DSceneLightOn1" / UNO_NAME_3D_SCENE_LIGHTON_1 + setFastPropertyValue( PROP_SCENE_LIGHT_ON_1, uno::Any( false ) ); + setFastPropertyValue( PROP_SCENE_LIGHT_ON_3, uno::Any( false ) ); + setFastPropertyValue( PROP_SCENE_LIGHT_ON_4, uno::Any( false ) ); + setFastPropertyValue( PROP_SCENE_LIGHT_ON_5, uno::Any( false ) ); + setFastPropertyValue( PROP_SCENE_LIGHT_ON_6, uno::Any( false ) ); + setFastPropertyValue( PROP_SCENE_LIGHT_ON_7, uno::Any( false ) ); + setFastPropertyValue( PROP_SCENE_LIGHT_ON_8, uno::Any( false ) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + ThreeDLookScheme aScheme = (aShadeMode == drawing::ShadeMode_FLAT) + ? ThreeDLookScheme::ThreeDLookScheme_Simple + : ThreeDLookScheme::ThreeDLookScheme_Realistic; + lcl_setLightsForScheme( *this, aScheme ); +} + +// ____ XCoordinateSystemContainer ____ +void SAL_CALL Diagram::addCoordinateSystem( + const uno::Reference< chart2::XCoordinateSystem >& aCoordSys ) +{ + ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordSys.get()); + assert(pCoordSys); + { + MutexGuard aGuard( m_aMutex ); + if( std::find( m_aCoordSystems.begin(), m_aCoordSystems.end(), pCoordSys ) + != m_aCoordSystems.end()) + throw lang::IllegalArgumentException("coordsys not found", static_cast<cppu::OWeakObject*>(this), 1); + + if( !m_aCoordSystems.empty() ) + { + OSL_FAIL( "more than one coordinatesystem is not supported yet by the fileformat" ); + return; + } + m_aCoordSystems.push_back( pCoordSys ); + } + ModifyListenerHelper::addListener( aCoordSys, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +void SAL_CALL Diagram::removeCoordinateSystem( + const uno::Reference< chart2::XCoordinateSystem >& aCoordSys ) +{ + ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordSys.get()); + assert(pCoordSys); + { + MutexGuard aGuard( m_aMutex ); + auto aIt = std::find( m_aCoordSystems.begin(), m_aCoordSystems.end(), pCoordSys ); + if( aIt == m_aCoordSystems.end()) + throw container::NoSuchElementException( + "The given coordinate-system is no element of the container", + static_cast< uno::XWeak * >( this )); + m_aCoordSystems.erase( aIt ); + } + ModifyListenerHelper::removeListener( aCoordSys, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > SAL_CALL Diagram::getCoordinateSystems() +{ + MutexGuard aGuard( m_aMutex ); + return comphelper::containerToSequence<uno::Reference< chart2::XCoordinateSystem >>( m_aCoordSystems ); +} + +Diagram::tCoordinateSystemContainerType Diagram::getBaseCoordinateSystems() const +{ + MutexGuard aGuard( m_aMutex ); + return m_aCoordSystems; +} + +void SAL_CALL Diagram::setCoordinateSystems( + const Sequence< Reference< chart2::XCoordinateSystem > >& aCoordinateSystems ) +{ + tCoordinateSystemContainerType aNew; + tCoordinateSystemContainerType aOld; + if( aCoordinateSystems.hasElements() ) + { + OSL_ENSURE( aCoordinateSystems.getLength()<=1, "more than one coordinatesystem is not supported yet by the fileformat" ); + ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordinateSystems[0].get()); + assert(pCoordSys); + aNew.push_back( pCoordSys ); + } + { + MutexGuard aGuard( m_aMutex ); + std::swap( aOld, m_aCoordSystems ); + m_aCoordSystems = aNew; + } + for (auto & xSystem : aOld) + xSystem->removeModifyListener(m_xModifyEventForwarder); + for (auto & xSystem : aNew) + xSystem->addModifyListener(m_xModifyEventForwarder); + fireModifyEvent(); +} + +void Diagram::setCoordinateSystems( + const std::vector< rtl::Reference< BaseCoordinateSystem > >& aCoordinateSystems ) +{ + tCoordinateSystemContainerType aNew; + tCoordinateSystemContainerType aOld; + if( !aCoordinateSystems.empty() ) + { + OSL_ENSURE( aCoordinateSystems.size()<=1, "more than one coordinatesystem is not supported yet by the fileformat" ); + aNew.push_back( aCoordinateSystems[0] ); + } + { + MutexGuard aGuard( m_aMutex ); + std::swap( aOld, m_aCoordSystems ); + m_aCoordSystems = aNew; + } + for (auto & xSystem : aOld) + xSystem->removeModifyListener(m_xModifyEventForwarder); + for (auto & xSystem : aNew) + xSystem->addModifyListener(m_xModifyEventForwarder); + fireModifyEvent(); +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL Diagram::createClone() +{ + MutexGuard aGuard( m_aMutex ); + return Reference< util::XCloneable >( new Diagram( *this )); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Diagram::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Diagram::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Diagram::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Diagram::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void Diagram::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void Diagram::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void Diagram::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticDiagramDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL Diagram::getInfoHelper() +{ + return StaticDiagramInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL Diagram::getPropertySetInfo() +{ + return StaticDiagramInfo(); +} + +// ____ XFastPropertySet ____ +void SAL_CALL Diagram::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) +{ + //special treatment for some 3D properties + if( nHandle == PROP_DIAGRAM_PERSPECTIVE ) + { + sal_Int32 fPerspective = 20; + if( rValue >>=fPerspective ) + setCameraDistance( ThreeDHelper::PerspectiveToCameraDistance( fPerspective ) ); + } + else if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL + || nHandle == PROP_DIAGRAM_ROTATION_VERTICAL ) + { + sal_Int32 nNewAngleDegree = 0; + if( rValue >>=nNewAngleDegree ) + { + sal_Int32 nHorizontal, nVertical; + getRotation( nHorizontal, nVertical ); + if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL ) + nHorizontal = nNewAngleDegree; + else + nVertical = nNewAngleDegree; + setRotation( nHorizontal, nVertical ); + } + } + else + ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue ); +} + +void SAL_CALL Diagram::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + //special treatment for some 3D properties + if( nHandle == PROP_DIAGRAM_PERSPECTIVE ) + { + sal_Int32 nPerspective = ::basegfx::fround( ThreeDHelper::CameraDistanceToPerspective( + const_cast< Diagram* >( this )->getCameraDistance() ) ); + rValue <<= nPerspective; + } + else if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL + || nHandle == PROP_DIAGRAM_ROTATION_VERTICAL ) + { + sal_Int32 nHorizontal, nVertical; + const_cast< Diagram* >( this )->getRotation( nHorizontal, nVertical ); + sal_Int32 nAngleDegree = 0; + if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL ) + nAngleDegree = nHorizontal; + else + nAngleDegree = nVertical; + rValue <<= nAngleDegree; + } + else + ::property::OPropertySet::getFastPropertyValue( rValue,nHandle ); +} + +uno::Reference<chart2::XDataTable> SAL_CALL Diagram::getDataTable() +{ + MutexGuard aGuard( m_aMutex ); + return m_xDataTable; +} + +rtl::Reference<::chart::DataTable> Diagram::getDataTableRef() const +{ + MutexGuard aGuard( m_aMutex ); + return m_xDataTable; +} + +void SAL_CALL Diagram::setDataTable(const uno::Reference<chart2::XDataTable>& xDataTable) +{ + auto* pDataTable = dynamic_cast<DataTable*>(xDataTable.get()); + assert(!xDataTable || pDataTable); + setDataTable(rtl::Reference<DataTable>(pDataTable)); +} + +void Diagram::setDataTable(const rtl::Reference<DataTable>& xNewDataTable) +{ + rtl::Reference<DataTable> xOldDataTable; + { + MutexGuard aGuard(m_aMutex); + if (m_xDataTable == xNewDataTable) + return; + xOldDataTable = m_xDataTable; + m_xDataTable = xNewDataTable; + } + if (xOldDataTable.is()) + ModifyListenerHelper::removeListener(xOldDataTable, m_xModifyEventForwarder); + if (xNewDataTable.is()) + ModifyListenerHelper::addListener(xNewDataTable, m_xModifyEventForwarder); + fireModifyEvent(); +} + +using impl::Diagram_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Diagram, Diagram_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( Diagram, Diagram_Base, ::property::OPropertySet ) + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL Diagram::getImplementationName() +{ + return "com.sun.star.comp.chart2.Diagram"; +} + +sal_Bool SAL_CALL Diagram::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL Diagram::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.Diagram", + "com.sun.star.layout.LayoutElement", + "com.sun.star.beans.PropertySet" }; +} + +DiagramPositioningMode Diagram::getDiagramPositioningMode() +{ + DiagramPositioningMode eMode = DiagramPositioningMode::Auto; + chart2::RelativePosition aRelPos; + chart2::RelativeSize aRelSize; + if( (getFastPropertyValue(PROP_DIAGRAM_REL_POS) >>= aRelPos ) && + (getFastPropertyValue(PROP_DIAGRAM_REL_SIZE) >>= aRelSize ) ) + { + bool bPosSizeExcludeAxes=false; + getFastPropertyValue(PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS) >>= bPosSizeExcludeAxes; + if( bPosSizeExcludeAxes ) + eMode = DiagramPositioningMode::Excluding; + else + eMode = DiagramPositioningMode::Including; + } + return eMode; +} + + +sal_Int32 Diagram::getCorrectedMissingValueTreatment( + const rtl::Reference< ChartType >& xChartType ) +{ + sal_Int32 nResult = css::chart::MissingValueTreatment::LEAVE_GAP; + const uno::Sequence < sal_Int32 > aAvailableMissingValueTreatments( + ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) ); + + if( getFastPropertyValue( PROP_DIAGRAM_MISSING_VALUE_TREATMENT ) >>= nResult ) + { + //ensure that the set value is supported by this charttype + for( sal_Int32 n : aAvailableMissingValueTreatments ) + if( n == nResult ) + return nResult; //ok + } + + //otherwise use the first supported one + if( aAvailableMissingValueTreatments.hasElements() ) + { + nResult = aAvailableMissingValueTreatments[0]; + return nResult; + } + + return nResult; +} + +void Diagram::setGeometry3D( sal_Int32 nNewGeometry ) +{ + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + getDataSeries(); + + for (auto const& series : aSeriesVec) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( + series, "Geometry3D", uno::Any( nNewGeometry )); + } +} + +sal_Int32 Diagram::getGeometry3D( bool& rbFound, bool& rbAmbiguous ) +{ + sal_Int32 nCommonGeom( css::chart2::DataPointGeometry3D::CUBOID ); + rbFound = false; + rbAmbiguous = false; + + std::vector< rtl::Reference< DataSeries > > aSeriesVec = getDataSeries(); + + if( aSeriesVec.empty()) + rbAmbiguous = true; + + for (auto const& series : aSeriesVec) + { + try + { + sal_Int32 nGeom = 0; + if( series->getPropertyValue( "Geometry3D") >>= nGeom ) + { + if( ! rbFound ) + { + // first series + nCommonGeom = nGeom; + rbFound = true; + } + // further series: compare for uniqueness + else if( nCommonGeom != nGeom ) + { + rbAmbiguous = true; + break; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return nCommonGeom; +} + +bool Diagram::isPieOrDonutChart() +{ + rtl::Reference< ChartType > xChartType = getChartTypeByIndex( 0 ); + + if( xChartType .is() ) + { + OUString aChartType = xChartType->getChartType(); + if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + return true; + } + return false; +} + +bool Diagram::isSupportingFloorAndWall() +{ + //pies and donuts currently do not support this because of wrong files from older versions + //todo: allow this in future again, if fileversion is available for OLE objects (metastream) + //thus the wrong bottom can be removed on import + + const std::vector< rtl::Reference< ChartType > > aTypes = getChartTypes(); + for( rtl::Reference< ChartType > const & xType : aTypes ) + { + OUString sChartType = xType->getChartType(); + if( sChartType.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return false; + if( sChartType.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + return false; + if( sChartType.match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + return false; + } + return true; +} + + /** + * This method implements the logic of checking if a series can be moved + * forward/backward. Depending on the "bDoMove" parameter the series will + * be moved (bDoMove = true) or the function just will test if the + * series can be moved without doing the move (bDoMove = false). + * + * @param xDiagram + * Reference to the diagram that contains the series. + * + * @param xGivenDataSeries + * Reference to the series that should moved or tested for moving. + * + * @param bForward + * Direction in which the series should be moved or tested for moving. + * + * @param bDoMove + * Should this function really move the series (true) or just test if it is + * possible (false). + * + * + * @returns + * in case of bDoMove == true + * - True : if the move was done + * - False : the move failed + * in case of bDoMove == false + * - True : the series can be moved + * - False : the series can not be moved + * + */ +static bool lcl_moveSeriesOrCheckIfMoveIsAllowed( + Diagram& rDiagram, + const rtl::Reference< DataSeries >& xGivenDataSeries, + bool bForward, + bool bDoMove ) +{ + bool bMovedOrMoveAllowed = false; + + try + { + if( !xGivenDataSeries.is() ) + return false; + + //find position of series. + bool bFound = false; + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList( rDiagram.getBaseCoordinateSystems() ); + + for( std::size_t nCS = 0; !bFound && nCS < aCooSysList.size(); ++nCS ) + { + const rtl::Reference< BaseCoordinateSystem > & xCooSys( aCooSysList[nCS] ); + + //iterate through all chart types in the current coordinate system + std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() ); + rtl::Reference< ChartType > xFormerChartType; + + for( std::size_t nT = 0; !bFound && nT < aChartTypeList.size(); ++nT ) + { + rtl::Reference< ChartType > xCurrentChartType( aChartTypeList[nT] ); + + //iterate through all series in this chart type + + std::vector< rtl::Reference< DataSeries > > aSeriesList = xCurrentChartType->getDataSeries2(); + + for( std::size_t nS = 0; !bFound && nS < aSeriesList.size(); ++nS ) + { + + // We found the series we are interested in! + if( xGivenDataSeries==aSeriesList[nS] ) + { + std::size_t nOldSeriesIndex = nS; + bFound = true; + + try + { + sal_Int32 nNewSeriesIndex = nS; + + // tdf#34517 Bringing forward means increasing, backwards means decreasing series position + if( !bForward ) + nNewSeriesIndex--; + else + nNewSeriesIndex++; + + if( nNewSeriesIndex >= 0 && o3tl::make_unsigned(nNewSeriesIndex) < aSeriesList.size() ) + { + //move series in the same charttype + bMovedOrMoveAllowed = true; + if( bDoMove ) + { + aSeriesList[ nOldSeriesIndex ] = aSeriesList[ nNewSeriesIndex ]; + aSeriesList[ nNewSeriesIndex ] = xGivenDataSeries; + xCurrentChartType->setDataSeries( aSeriesList ); + } + } + else if( nNewSeriesIndex<0 ) + { + //exchange series with former charttype + if( xFormerChartType.is() && DiagramHelper::areChartTypesCompatible( xFormerChartType, xCurrentChartType ) ) + { + bMovedOrMoveAllowed = true; + if( bDoMove ) + { + std::vector< rtl::Reference< DataSeries > > aOtherSeriesList = xFormerChartType->getDataSeries2(); + sal_Int32 nOtherSeriesIndex = aOtherSeriesList.size()-1; + if( nOtherSeriesIndex >= 0 && o3tl::make_unsigned(nOtherSeriesIndex) < aOtherSeriesList.size() ) + { + rtl::Reference< DataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] ); + aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries; + xFormerChartType->setDataSeries(aOtherSeriesList); + + aSeriesList[nOldSeriesIndex]=xExchangeSeries; + xCurrentChartType->setDataSeries(aSeriesList); + } + } + } + } + else if( nT+1 < aChartTypeList.size() ) + { + //exchange series with next charttype + rtl::Reference< ChartType > xOtherChartType( aChartTypeList[nT+1] ); + if( xOtherChartType.is() && DiagramHelper::areChartTypesCompatible( xOtherChartType, xCurrentChartType ) ) + { + bMovedOrMoveAllowed = true; + if( bDoMove ) + { + std::vector< rtl::Reference< DataSeries > > aOtherSeriesList = xOtherChartType->getDataSeries2(); + if( !aOtherSeriesList.empty() ) + { + rtl::Reference< DataSeries > xExchangeSeries( aOtherSeriesList[0] ); + aOtherSeriesList[0] = xGivenDataSeries; + xOtherChartType->setDataSeries(aOtherSeriesList); + + aSeriesList[nOldSeriesIndex]=xExchangeSeries; + xCurrentChartType->setDataSeries(aSeriesList); + } + } + } + } + } + catch( const util::CloseVetoException& ) + { + } + catch( const uno::RuntimeException& ) + { + } + } + } + xFormerChartType = xCurrentChartType; + } + } + } + catch( const util::CloseVetoException& ) + { + } + catch( const uno::RuntimeException& ) + { + } + return bMovedOrMoveAllowed; +} + +bool Diagram::isSeriesMoveable( + const rtl::Reference< DataSeries >& xGivenDataSeries, + bool bForward ) +{ + const bool bDoMove = false; + + bool bIsMoveable = lcl_moveSeriesOrCheckIfMoveIsAllowed( + *this, xGivenDataSeries, bForward, bDoMove ); + + return bIsMoveable; +} + +bool Diagram::moveSeries( const rtl::Reference< DataSeries >& xGivenDataSeries, bool bForward ) +{ + const bool bDoMove = true; + + bool bMoved = lcl_moveSeriesOrCheckIfMoveIsAllowed( + *this, xGivenDataSeries, bForward, bDoMove ); + + return bMoved; +} + +std::vector< rtl::Reference< ChartType > > Diagram::getChartTypes() +{ + std::vector< rtl::Reference< ChartType > > aResult; + try + { + for( rtl::Reference< BaseCoordinateSystem > const & coords : getBaseCoordinateSystems() ) + { + const std::vector< rtl::Reference< ChartType > > & aChartTypeSeq( coords->getChartTypes2()); + aResult.insert( aResult.end(), aChartTypeSeq.begin(), aChartTypeSeq.end() ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +rtl::Reference< ChartType > Diagram::getChartTypeByIndex( sal_Int32 nIndex ) +{ + rtl::Reference< ChartType > xChartType; + + //iterate through all coordinate systems + sal_Int32 nTypesSoFar = 0; + for( rtl::Reference< BaseCoordinateSystem > const & coords : getBaseCoordinateSystems() ) + { + const std::vector< rtl::Reference< ChartType > > & aChartTypeList( coords->getChartTypes2() ); + if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < nTypesSoFar + aChartTypeList.size() ) + { + xChartType = aChartTypeList[nIndex - nTypesSoFar]; + break; + } + nTypesSoFar += aChartTypeList.size(); + } + + return xChartType; +} + +bool Diagram::isSupportingDateAxis() +{ + return ::chart::ChartTypeHelper::isSupportingDateAxis( getChartTypeByIndex( 0 ), 0 ); +} + +static std::vector< rtl::Reference< Axis > > lcl_getAxisHoldingCategoriesFromDiagram( + Diagram& rDiagram ) +{ + std::vector< rtl::Reference< Axis > > aRet; + + // return first x-axis as fall-back + rtl::Reference< Axis > xFallBack; + try + { + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : rDiagram.getBaseCoordinateSystems() ) + { + OSL_ASSERT( xCooSys.is()); + for( sal_Int32 nN = xCooSys->getDimension(); nN--; ) + { + const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN); + for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nN,nI ); + OSL_ASSERT( xAxis.is()); + if( xAxis.is()) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + if( aScaleData.Categories.is() || (aScaleData.AxisType == chart2::AxisType::CATEGORY) ) + { + aRet.push_back(xAxis); + } + if( (nN == 0) && !xFallBack.is()) + xFallBack = xAxis; + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } + + if( aRet.empty() ) + aRet.push_back(xFallBack); + + return aRet; +} + +uno::Reference< chart2::data::XLabeledDataSequence > Diagram::getCategories() +{ + uno::Reference< chart2::data::XLabeledDataSequence > xResult; + + try + { + std::vector< rtl::Reference< Axis > > aCatAxes( + lcl_getAxisHoldingCategoriesFromDiagram( *this )); + //search for first categories + if (aCatAxes.empty()) + return xResult; + + rtl::Reference< Axis > xCatAxis(aCatAxes[0]); + if( !xCatAxis.is()) + return xResult; + + chart2::ScaleData aScaleData( xCatAxis->getScaleData()); + if( !aScaleData.Categories.is() ) + return xResult; + + xResult = aScaleData.Categories; + uno::Reference<beans::XPropertySet> xProp(xResult->getValues(), uno::UNO_QUERY ); + if( xProp.is() ) + { + try + { + xProp->setPropertyValue( "Role", uno::Any( OUString("categories") ) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +void Diagram::setCategories( + const uno::Reference< chart2::data::XLabeledDataSequence >& xCategories, + bool bSetAxisType /* = false */, + bool bCategoryAxis /* = true */ ) +{ + std::vector< rtl::Reference< Axis > > aCatAxes( + lcl_getAxisHoldingCategoriesFromDiagram( *this )); + + for (const rtl::Reference< Axis >& xCatAxis : aCatAxes) + { + if( xCatAxis.is()) + { + chart2::ScaleData aScaleData( xCatAxis->getScaleData()); + aScaleData.Categories = xCategories; + if( bSetAxisType ) + { + if( bCategoryAxis ) + aScaleData.AxisType = chart2::AxisType::CATEGORY; + else if( aScaleData.AxisType == chart2::AxisType::CATEGORY || aScaleData.AxisType == chart2::AxisType::DATE ) + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + } + xCatAxis->setScaleData( aScaleData ); + } + } +} + +bool Diagram::isCategory() +{ + try + { + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() ) + { + for( sal_Int32 nN = xCooSys->getDimension(); nN--; ) + { + const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN); + for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nN,nI ); + OSL_ASSERT( xAxis.is()); + if( xAxis.is()) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + if( aScaleData.AxisType == chart2::AxisType::CATEGORY || aScaleData.AxisType == chart2::AxisType::DATE ) + return true; + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return false; +} + +std::vector< std::vector< rtl::Reference< DataSeries > > > +Diagram::getDataSeriesGroups() +{ + std::vector< std::vector< rtl::Reference< DataSeries > > > aResult; + + //iterate through all coordinate systems + for( rtl::Reference< BaseCoordinateSystem > const & coords : getBaseCoordinateSystems() ) + { + //iterate through all chart types in the current coordinate system + for( rtl::Reference< ChartType > const & chartType : coords->getChartTypes2() ) + { + aResult.push_back( chartType->getDataSeries2() ); + } + } + return aResult; +} + +std::vector< rtl::Reference< ::chart::DataSeries > > + Diagram::getDataSeries() +{ + std::vector< rtl::Reference< DataSeries > > aResult; + try + { + for( rtl::Reference< BaseCoordinateSystem > const & coords : getBaseCoordinateSystems() ) + { + for( rtl::Reference< ChartType> const & chartType : coords->getChartTypes2() ) + { + const std::vector< rtl::Reference< DataSeries > > aSeriesSeq( chartType->getDataSeries2() ); + aResult.insert( aResult.end(), aSeriesSeq.begin(), aSeriesSeq.end() ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +rtl::Reference< ChartType > Diagram::getChartTypeOfSeries( + const rtl::Reference< DataSeries >& xGivenDataSeries ) +{ + if( !xGivenDataSeries.is() ) + return nullptr; + + //iterate through the model to find the given xSeries + //the found parent indicates the charttype + + //iterate through all coordinate systems + + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() ) + { + //iterate through all chart types in the current coordinate system + const std::vector< rtl::Reference< ChartType > > & aChartTypeList( xCooSys->getChartTypes2() ); + for( rtl::Reference< ChartType > const & xChartType : aChartTypeList ) + { + //iterate through all series in this chart type + for( rtl::Reference< DataSeries > const & dataSeries : xChartType->getDataSeries2() ) + { + if( xGivenDataSeries==dataSeries ) + return xChartType; + } + } + } + return nullptr; +} + +rtl::Reference< Axis > Diagram::getAttachedAxis( + const rtl::Reference< DataSeries >& xSeries ) +{ + return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), this ); +} + +bool Diagram::attachSeriesToAxis( bool bAttachToMainAxis + , const rtl::Reference< DataSeries >& xDataSeries + , const uno::Reference< uno::XComponentContext > & xContext + , bool bAdaptAxes ) +{ + bool bChanged = false; + + //set property at axis + + sal_Int32 nNewAxisIndex = bAttachToMainAxis ? 0 : 1; + sal_Int32 nOldAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + rtl::Reference< Axis > xOldAxis = getAttachedAxis( xDataSeries ); + + if( nOldAxisIndex != nNewAxisIndex ) + { + try + { + xDataSeries->setPropertyValue( "AttachedAxisIndex", uno::Any( nNewAxisIndex ) ); + bChanged = true; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if( bChanged ) + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 1, bAttachToMainAxis, this ); + if(!xAxis.is()) //create an axis if necessary + xAxis = AxisHelper::createAxis( 1, bAttachToMainAxis, this, xContext ); + if( bAdaptAxes ) + { + AxisHelper::makeAxisVisible( xAxis ); + AxisHelper::hideAxisIfNoDataIsAttached( xOldAxis, this ); + } + } + + return bChanged; +} + +void Diagram::replaceCoordinateSystem( + const rtl::Reference< BaseCoordinateSystem > & xCooSysToReplace, + const rtl::Reference< BaseCoordinateSystem > & xReplacement ) +{ + // update the coordinate-system container + try + { + uno::Reference< chart2::data::XLabeledDataSequence > xCategories = getCategories(); + + // move chart types of xCooSysToReplace to xReplacement + xReplacement->setChartTypes( xCooSysToReplace->getChartTypes()); + + removeCoordinateSystem( xCooSysToReplace ); + addCoordinateSystem( xReplacement ); + + if( xCategories.is() ) + setCategories( xCategories ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +sal_Int32 Diagram::getDimension() +{ + // -1: not yet set + sal_Int32 nResult = -1; + + try + { + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() ) + { + if(xCooSys.is()) + { + nResult = xCooSys->getDimension(); + break; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return nResult; +} + +void Diagram::setDimension( sal_Int32 nNewDimensionCount ) +{ + if( getDimension() == nNewDimensionCount ) + return; + + try + { + bool rbFound = false; + bool rbAmbiguous = true; + StackMode eStackMode = getStackMode( rbFound, rbAmbiguous ); + bool bIsSupportingOnlyDeepStackingFor3D=false; + + //change all coordinate systems: + auto aCoordSystems = getBaseCoordinateSystems(); + for( rtl::Reference<BaseCoordinateSystem> const & xOldCooSys : aCoordSystems ) + { + rtl::Reference< BaseCoordinateSystem > xNewCooSys; + + const std::vector< rtl::Reference< ChartType > > aChartTypeList( xOldCooSys->getChartTypes2() ); + for( rtl::Reference< ChartType > const & xChartType : aChartTypeList ) + { + bIsSupportingOnlyDeepStackingFor3D = ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( xChartType ); + if(!xNewCooSys.is()) + { + xNewCooSys = dynamic_cast<BaseCoordinateSystem*>(xChartType->createCoordinateSystem( nNewDimensionCount ).get()); + assert(xNewCooSys); + break; + } + //@todo make sure that all following charttypes are also capable of the new dimension + //otherwise separate them in a different group + //BM: might be done in replaceCoordinateSystem() + } + + // replace the old coordinate system at all places where it was used + replaceCoordinateSystem( xOldCooSys, xNewCooSys ); + } + + //correct stack mode if necessary + if( nNewDimensionCount==3 && eStackMode != StackMode::ZStacked && bIsSupportingOnlyDeepStackingFor3D ) + setStackMode( StackMode::ZStacked ); + else if( nNewDimensionCount==2 && eStackMode == StackMode::ZStacked ) + setStackMode( StackMode::NONE ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void Diagram::setStackMode( StackMode eStackMode ) +{ + try + { + bool bValueFound = false; + bool bIsAmbiguous = false; + StackMode eOldStackMode = getStackMode( bValueFound, bIsAmbiguous ); + + if( eStackMode == eOldStackMode && !bIsAmbiguous ) + return; + + chart2::StackingDirection eNewDirection = chart2::StackingDirection_NO_STACKING; + if( eStackMode == StackMode::YStacked || eStackMode == StackMode::YStackedPercent ) + eNewDirection = chart2::StackingDirection_Y_STACKING; + else if( eStackMode == StackMode::ZStacked ) + eNewDirection = chart2::StackingDirection_Z_STACKING; + + uno::Any aNewDirection( eNewDirection ); + + bool bPercent = false; + if( eStackMode == StackMode::YStackedPercent ) + bPercent = true; + + //iterate through all coordinate systems + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() ) + { + //set correct percent stacking + const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(1); + for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( 1,nI ); + if( xAxis.is()) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + if( (aScaleData.AxisType==chart2::AxisType::PERCENT) != bPercent ) + { + if( bPercent ) + aScaleData.AxisType = chart2::AxisType::PERCENT; + else + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + xAxis->setScaleData( aScaleData ); + } + } + } + //iterate through all chart types in the current coordinate system + const std::vector< rtl::Reference< ChartType > > & aChartTypeList( xCooSys->getChartTypes2() ); + if (aChartTypeList.empty()) + continue; + + rtl::Reference< ChartType > xChartType( aChartTypeList[0] ); + + //iterate through all series in this chart type + for( rtl::Reference< DataSeries > const & dataSeries : xChartType->getDataSeries2() ) + { + dataSeries->setPropertyValue( "StackingDirection", aNewDirection ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +StackMode Diagram::getStackMode( bool& rbFound, bool& rbAmbiguous ) +{ + rbFound=false; + rbAmbiguous=false; + + StackMode eGlobalStackMode = StackMode::NONE; + + //iterate through all coordinate systems + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() ) + { + //iterate through all chart types in the current coordinate system + std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() ); + for( std::size_t nT = 0; nT < aChartTypeList.size(); ++nT ) + { + rtl::Reference< ChartType > xChartType( aChartTypeList[nT] ); + + StackMode eLocalStackMode = DiagramHelper::getStackModeFromChartType( + xChartType, rbFound, rbAmbiguous, xCooSys ); + + if( rbFound && eLocalStackMode != eGlobalStackMode && nT>0 ) + { + rbAmbiguous = true; + return eGlobalStackMode; + } + + eGlobalStackMode = eLocalStackMode; + } + } + + return eGlobalStackMode; +} + +void Diagram::setVertical( bool bVertical /* = true */ ) +{ + try + { + uno::Any aValue; + aValue <<= bVertical; + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() ) + { + bool bChanged = false; + bool bOldSwap = false; + if( !(xCooSys->getPropertyValue("SwapXAndYAxis") >>= bOldSwap) + || bVertical != bOldSwap ) + bChanged = true; + + if( bChanged ) + xCooSys->setPropertyValue("SwapXAndYAxis", aValue); + + const sal_Int32 nDimensionCount = xCooSys->getDimension(); + sal_Int32 nDimIndex = 0; + for (nDimIndex=0; nDimIndex < nDimensionCount; ++nDimIndex) + { + const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex); + for (sal_Int32 nI = 0; nI <= nMaximumScaleIndex; ++nI) + { + rtl::Reference<Axis> xAxis = xCooSys->getAxisByDimension2(nDimIndex,nI); + if (!xAxis.is()) + continue; + + //adapt title rotation only when axis swapping has changed + if (!bChanged) + continue; + + Reference< beans::XPropertySet > xTitleProps( xAxis->getTitleObject(), uno::UNO_QUERY ); + if (!xTitleProps.is()) + continue; + + double fAngleDegree = 0.0; + xTitleProps->getPropertyValue("TextRotation") >>= fAngleDegree; + if (fAngleDegree != 0.0 && + !rtl::math::approxEqual(fAngleDegree, 90.0)) + continue; + + double fNewAngleDegree = 0.0; + if( !bVertical && nDimIndex == 1 ) + fNewAngleDegree = 90.0; + else if( bVertical && nDimIndex == 0 ) + fNewAngleDegree = 90.0; + + xTitleProps->setPropertyValue("TextRotation", uno::Any(fNewAngleDegree)); + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool Diagram::getVertical( bool& rbFound, bool& rbAmbiguous ) +{ + bool bValue = false; + rbFound = false; + rbAmbiguous = false; + + for (rtl::Reference<BaseCoordinateSystem> const & coords : getBaseCoordinateSystems()) + { + bool bCurrent = false; + if (coords->getPropertyValue("SwapXAndYAxis") >>= bCurrent) + { + if (!rbFound) + { + bValue = bCurrent; + rbFound = true; + } + else if (bCurrent != bValue) + { + // ambiguous -> choose always first found + rbAmbiguous = true; + } + } + } + return bValue; +} + +Diagram::tTemplateWithServiceName + Diagram::getTemplate( + const rtl::Reference< ::chart::ChartTypeManager > & xChartTypeManager ) +{ + tTemplateWithServiceName aResult; + + if( !xChartTypeManager ) + return aResult; + + Sequence< OUString > aServiceNames( xChartTypeManager->getAvailableServiceNames()); + const sal_Int32 nLength = aServiceNames.getLength(); + + bool bTemplateFound = false; + + for( sal_Int32 i = 0; ! bTemplateFound && i < nLength; ++i ) + { + try + { + rtl::Reference< ::chart::ChartTypeTemplate > xTempl = + xChartTypeManager->createTemplate( aServiceNames[ i ] ); + + if (xTempl.is() && xTempl->matchesTemplate2(this, true)) + { + aResult.xChartTypeTemplate = xTempl; + aResult.sServiceName = aServiceNames[ i ]; + bTemplateFound = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +std::vector< rtl::Reference< RegressionCurveModel > > + Diagram::getAllRegressionCurvesNotMeanValueLine() +{ + std::vector< rtl::Reference< RegressionCurveModel > > aResult; + std::vector< rtl::Reference< DataSeries > > aSeries( getDataSeries()); + for (auto const& elem : aSeries) + { + for( rtl::Reference< RegressionCurveModel > const & curve : elem->getRegressionCurves2() ) + { + if( ! RegressionCurveHelper::isMeanValueLine( curve )) + aResult.push_back( curve ); + } + } + + return aResult; +} + +double Diagram::getCameraDistance() +{ + double fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME; + + try + { + drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); + getFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY ) >>= aCG; + ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) ); + fCameraDistance = aVRP.getLength(); + + ThreeDHelper::ensureCameraDistanceRange( fCameraDistance ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return fCameraDistance; +} + +void Diagram::setCameraDistance(double fCameraDistance ) +{ + try + { + if( fCameraDistance <= 0 ) + fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME; + + drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); + getFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY ) >>= aCG; + ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) ); + if( ::basegfx::fTools::equalZero( aVRP.getLength() ) ) + aVRP = ::basegfx::B3DVector(0,0,1); + aVRP.setLength(fCameraDistance); + aCG.vrp = BaseGFXHelper::B3DVectorToPosition3D( aVRP ); + + setFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY, uno::Any( aCG )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +static bool lcl_isRightAngledAxesSetAndSupported( Diagram& rDiagram ) +{ + bool bRightAngledAxes = false; + rDiagram.getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bRightAngledAxes; // "RightAngledAxes" + if(bRightAngledAxes) + { + if( ChartTypeHelper::isSupportingRightAngledAxes( + rDiagram.getChartTypeByIndex( 0 ) ) ) + { + return true; + } + } + return false; +} + +void Diagram::getRotation( sal_Int32& rnHorizontalAngleDegree, sal_Int32& rnVerticalAngleDegree ) +{ + double fXAngle, fYAngle, fZAngle; + getRotationAngle( fXAngle, fYAngle, fZAngle ); + + if( !lcl_isRightAngledAxesSetAndSupported( *this ) ) + { + ThreeDHelper::convertXYZAngleRadToElevationRotationDeg( + rnHorizontalAngleDegree, rnVerticalAngleDegree, fXAngle, fYAngle, fZAngle); + rnVerticalAngleDegree*=-1; + } + else + { + rnHorizontalAngleDegree = basegfx::fround(basegfx::rad2deg(fXAngle)); + rnVerticalAngleDegree = basegfx::fround(-1.0 * basegfx::rad2deg(fYAngle)); + // nZRotation = basegfx::fround(-1.0 * basegfx::rad2deg(fZAngle)); + } + + rnHorizontalAngleDegree = NormAngle180(rnHorizontalAngleDegree); + rnVerticalAngleDegree = NormAngle180(rnVerticalAngleDegree); +} + +void Diagram::setRotation( sal_Int32 nHorizontalAngleDegree, sal_Int32 nVerticalYAngleDegree ) +{ + //todo: x and y is not equal to horz and vert in case of RightAngledAxes==false + double fXAngle = basegfx::deg2rad(nHorizontalAngleDegree); + double fYAngle = basegfx::deg2rad(-1 * nVerticalYAngleDegree); + double fZAngle = 0.0; + + if( !lcl_isRightAngledAxesSetAndSupported( *this ) ) + ThreeDHelper::convertElevationRotationDegToXYZAngleRad( + nHorizontalAngleDegree, -1*nVerticalYAngleDegree, fXAngle, fYAngle, fZAngle ); + + setRotationAngle( fXAngle, fYAngle, fZAngle ); +} + +static ::basegfx::B3DHomMatrix lcl_getCameraMatrix( Diagram& rDiagram ) +{ + drawing::HomogenMatrix aCameraMatrix; + + drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); + rDiagram.getFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY ) >>= aCG; // "D3DCameraGeometry" + + ::basegfx::B3DVector aVPN( BaseGFXHelper::Direction3DToB3DVector( aCG.vpn ) ); + ::basegfx::B3DVector aVUP( BaseGFXHelper::Direction3DToB3DVector( aCG.vup ) ); + + //normalize vectors: + aVPN.normalize(); + aVUP.normalize(); + + ::basegfx::B3DVector aCross = ::basegfx::cross( aVUP, aVPN ); + + //first line is VUP x VPN + aCameraMatrix.Line1.Column1 = aCross[0]; + aCameraMatrix.Line1.Column2 = aCross[1]; + aCameraMatrix.Line1.Column3 = aCross[2]; + aCameraMatrix.Line1.Column4 = 0.0; + + //second line is VUP + aCameraMatrix.Line2.Column1 = aVUP[0]; + aCameraMatrix.Line2.Column2 = aVUP[1]; + aCameraMatrix.Line2.Column3 = aVUP[2]; + aCameraMatrix.Line2.Column4 = 0.0; + + //third line is VPN + aCameraMatrix.Line3.Column1 = aVPN[0]; + aCameraMatrix.Line3.Column2 = aVPN[1]; + aCameraMatrix.Line3.Column3 = aVPN[2]; + aCameraMatrix.Line3.Column4 = 0.0; + + //fourth line is 0 0 0 1 + aCameraMatrix.Line4.Column1 = 0.0; + aCameraMatrix.Line4.Column2 = 0.0; + aCameraMatrix.Line4.Column3 = 0.0; + aCameraMatrix.Line4.Column4 = 1.0; + + return BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aCameraMatrix ); +} + +static double lcl_shiftAngleToIntervalMinusPiToPi( double fAngleRad ) +{ + //valid range: ]-Pi,Pi] + while( fAngleRad<=-M_PI ) + fAngleRad+=(2*M_PI); + while( fAngleRad>M_PI ) + fAngleRad-=(2*M_PI); + return fAngleRad; +} + +void Diagram::getRotationAngle( double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad ) +{ + //takes the camera and the transformation matrix into account + + rfXAngleRad = rfYAngleRad = rfZAngleRad = 0.0; + + //get camera rotation + ::basegfx::B3DHomMatrix aFixCameraRotationMatrix( lcl_getCameraMatrix( *this ) ); + BaseGFXHelper::ReduceToRotationMatrix( aFixCameraRotationMatrix ); + + //get scene rotation + ::basegfx::B3DHomMatrix aSceneRotation; + { + drawing::HomogenMatrix aHomMatrix; + // "D3DTransformMatrix" + if( getFastPropertyValue( PROP_SCENE_TRANSF_MATRIX ) >>= aHomMatrix ) + { + aSceneRotation = BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHomMatrix ); + BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation ); + } + } + + ::basegfx::B3DHomMatrix aResultRotation = aFixCameraRotationMatrix * aSceneRotation; + ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( aResultRotation ) ); + + rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getX()); + rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getY()); + rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getZ()); + + if(rfZAngleRad<-M_PI_2 || rfZAngleRad>M_PI_2) + { + rfZAngleRad-=M_PI; + rfXAngleRad-=M_PI; + rfYAngleRad=(M_PI-rfYAngleRad); + + rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfXAngleRad); + rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfYAngleRad); + rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfZAngleRad); + } +} + +static ::basegfx::B3DHomMatrix lcl_getInverseRotationMatrix( Diagram& rDiagram ) +{ + ::basegfx::B3DHomMatrix aInverseRotation; + double fXAngleRad=0.0; + double fYAngleRad=0.0; + double fZAngleRad=0.0; + rDiagram.getRotationAngle( fXAngleRad, fYAngleRad, fZAngleRad ); + aInverseRotation.rotate( 0.0, 0.0, -fZAngleRad ); + aInverseRotation.rotate( 0.0, -fYAngleRad, 0.0 ); + aInverseRotation.rotate( -fXAngleRad, 0.0, 0.0 ); + return aInverseRotation; +} + +static void lcl_rotateLights( const ::basegfx::B3DHomMatrix& rLightRotation, Diagram& rDiagram ) +{ + ::basegfx::B3DHomMatrix aLightRotation( rLightRotation ); + BaseGFXHelper::ReduceToRotationMatrix( aLightRotation ); + + // "D3DSceneLightDirection1","D3DSceneLightOn1", + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_1, PROP_SCENE_LIGHT_ON_1, aLightRotation ); + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_2, PROP_SCENE_LIGHT_ON_2, aLightRotation ); + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_3, PROP_SCENE_LIGHT_ON_3, aLightRotation ); + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_4, PROP_SCENE_LIGHT_ON_4, aLightRotation ); + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_5, PROP_SCENE_LIGHT_ON_5, aLightRotation ); + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_6, PROP_SCENE_LIGHT_ON_6, aLightRotation ); + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_7, PROP_SCENE_LIGHT_ON_7, aLightRotation ); + lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_8, PROP_SCENE_LIGHT_ON_8, aLightRotation ); +} + +void Diagram::setRotationAngle( + double fXAngleRad, double fYAngleRad, double fZAngleRad ) +{ + //the rotation of the camera is not touched but taken into account + //the rotation difference is applied to the transformation matrix + + //the light sources will be adapted also + + try + { + //remind old rotation for adaptation of light directions + ::basegfx::B3DHomMatrix aInverseOldRotation( lcl_getInverseRotationMatrix( *this ) ); + + ::basegfx::B3DHomMatrix aInverseCameraRotation; + { + ::basegfx::B3DTuple aR( BaseGFXHelper::GetRotationFromMatrix( + lcl_getCameraMatrix( *this ) ) ); + aInverseCameraRotation.rotate( 0.0, 0.0, -aR.getZ() ); + aInverseCameraRotation.rotate( 0.0, -aR.getY(), 0.0 ); + aInverseCameraRotation.rotate( -aR.getX(), 0.0, 0.0 ); + } + + ::basegfx::B3DHomMatrix aCumulatedRotation; + aCumulatedRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); + + //calculate new scene matrix + ::basegfx::B3DHomMatrix aSceneRotation = aInverseCameraRotation*aCumulatedRotation; + BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation ); + + //set new rotation to transformation matrix ("D3DTransformMatrix") + setFastPropertyValue( + PROP_SCENE_TRANSF_MATRIX, uno::Any( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation ))); + + //rotate lights if RightAngledAxes are not set or not supported + bool bRightAngledAxes = false; + getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bRightAngledAxes; + if(!bRightAngledAxes || !ChartTypeHelper::isSupportingRightAngledAxes( + getChartTypeByIndex( 0 ) ) ) + { + ::basegfx::B3DHomMatrix aNewRotation; + aNewRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); + lcl_rotateLights( aNewRotation*aInverseOldRotation, *this ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +static bool lcl_isEqual( const drawing::Direction3D& rA, const drawing::Direction3D& rB ) +{ + return ::rtl::math::approxEqual(rA.DirectionX, rB.DirectionX) + && ::rtl::math::approxEqual(rA.DirectionY, rB.DirectionY) + && ::rtl::math::approxEqual(rA.DirectionZ, rB.DirectionZ); +} +static bool lcl_isSimpleScheme( drawing::ShadeMode aShadeMode + , sal_Int32 nRoundedEdges + , sal_Int32 nObjectLines + , const rtl::Reference< Diagram >& xDiagram ) +{ + if(aShadeMode!=drawing::ShadeMode_FLAT) + return false; + if(nRoundedEdges!=0) + return false; + if(nObjectLines==0) + { + rtl::Reference< ChartType > xChartType( xDiagram->getChartTypeByIndex( 0 ) ); + return ChartTypeHelper::noBordersForSimpleScheme( xChartType ); + } + if(nObjectLines!=1) + return false; + return true; +} +static bool lcl_isRealisticScheme( drawing::ShadeMode aShadeMode + , sal_Int32 nRoundedEdges + , sal_Int32 nObjectLines ) +{ + if(aShadeMode!=drawing::ShadeMode_SMOOTH) + return false; + if(nRoundedEdges!=5) + return false; + if(nObjectLines!=0) + return false; + return true; +} +static bool lcl_isLightScheme( Diagram& rDiagram, bool bRealistic ) +{ + bool bIsOn = false; + // "D3DSceneLightOn2" / UNO_NAME_3D_SCENE_LIGHTON_2 + rDiagram.getFastPropertyValue( PROP_SCENE_LIGHT_ON_2 ) >>= bIsOn; + if(!bIsOn) + return false; + + rtl::Reference< ChartType > xChartType( rDiagram.getChartTypeByIndex( 0 ) ); + + sal_Int32 nColor = 0; + // "D3DSceneLightColor2" / UNO_NAME_3D_SCENE_LIGHTCOLOR_2 + rDiagram.getFastPropertyValue( PROP_SCENE_LIGHT_COLOR_2 ) >>= nColor; + if( nColor != ::chart::ChartTypeHelper::getDefaultDirectLightColor( !bRealistic, xChartType ) ) + return false; + + sal_Int32 nAmbientColor = 0; + // "D3DSceneAmbientColor" / UNO_NAME_3D_SCENE_AMBIENTCOLOR + rDiagram.getFastPropertyValue( PROP_SCENE_AMBIENT_COLOR ) >>= nAmbientColor; + if( nAmbientColor != ::chart::ChartTypeHelper::getDefaultAmbientLightColor( !bRealistic, xChartType ) ) + return false; + + drawing::Direction3D aDirection(0,0,0); + // "D3DSceneLightDirection2" / UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 + rDiagram.getFastPropertyValue( PROP_SCENE_LIGHT_DIRECTION_2 ) >>= aDirection; + + drawing::Direction3D aDefaultDirection( bRealistic + ? ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) + : ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) ); + + //rotate default light direction when right angled axes are off but supported + { + bool bRightAngledAxes = false; + rDiagram.getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bRightAngledAxes; // "RightAngledAxes" + if(!bRightAngledAxes) + { + if( ChartTypeHelper::isSupportingRightAngledAxes( + rDiagram.getChartTypeByIndex( 0 ) ) ) + { + ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( rDiagram ) ); + BaseGFXHelper::ReduceToRotationMatrix( aRotation ); + ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aDefaultDirection ) ); + aLightVector = aRotation*aLightVector; + aDefaultDirection = BaseGFXHelper::B3DVectorToDirection3D( aLightVector ); + } + } + } + + return lcl_isEqual( aDirection, aDefaultDirection ); +} +static bool lcl_isRealisticLightScheme( Diagram& rDiagram ) +{ + return lcl_isLightScheme( rDiagram, true /*bRealistic*/ ); +} +static bool lcl_isSimpleLightScheme( Diagram& rDiagram ) +{ + return lcl_isLightScheme( rDiagram, false /*bRealistic*/ ); +} + +ThreeDLookScheme Diagram::detectScheme() +{ + ThreeDLookScheme aScheme = ThreeDLookScheme::ThreeDLookScheme_Unknown; + + sal_Int32 nRoundedEdges; + sal_Int32 nObjectLines; + ThreeDHelper::getRoundedEdgesAndObjectLines( this, nRoundedEdges, nObjectLines ); + + //get shade mode and light settings: + drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH ); + try + { + getFastPropertyValue( PROP_SCENE_SHADE_MODE )>>= aShadeMode; // "D3DSceneShadeMode" + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if( lcl_isSimpleScheme( aShadeMode, nRoundedEdges, nObjectLines, this ) ) + { + if( lcl_isSimpleLightScheme(*this) ) + aScheme = ThreeDLookScheme::ThreeDLookScheme_Simple; + } + else if( lcl_isRealisticScheme( aShadeMode, nRoundedEdges, nObjectLines ) ) + { + if( lcl_isRealisticLightScheme(*this) ) + aScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + } + + return aScheme; +} + +static void lcl_setRealisticScheme( drawing::ShadeMode& rShadeMode + , sal_Int32& rnRoundedEdges + , sal_Int32& rnObjectLines ) +{ + rShadeMode = drawing::ShadeMode_SMOOTH; + rnRoundedEdges = 5; + rnObjectLines = 0; +} + +static void lcl_setSimpleScheme( drawing::ShadeMode& rShadeMode + , sal_Int32& rnRoundedEdges + , sal_Int32& rnObjectLines + , const rtl::Reference< Diagram >& xDiagram ) +{ + rShadeMode = drawing::ShadeMode_FLAT; + rnRoundedEdges = 0; + + rtl::Reference< ChartType > xChartType( xDiagram->getChartTypeByIndex( 0 ) ); + rnObjectLines = ChartTypeHelper::noBordersForSimpleScheme( xChartType ) ? 0 : 1; +} +void Diagram::setScheme( ThreeDLookScheme aScheme ) +{ + if( aScheme == ThreeDLookScheme::ThreeDLookScheme_Unknown ) + return; + + drawing::ShadeMode aShadeMode; + sal_Int32 nRoundedEdges; + sal_Int32 nObjectLines; + + if( aScheme == ThreeDLookScheme::ThreeDLookScheme_Simple ) + lcl_setSimpleScheme(aShadeMode,nRoundedEdges,nObjectLines,this); + else + lcl_setRealisticScheme(aShadeMode,nRoundedEdges,nObjectLines); + + try + { + ThreeDHelper::setRoundedEdgesAndObjectLines( this, nRoundedEdges, nObjectLines ); + + drawing::ShadeMode aOldShadeMode; + if( ! (getFastPropertyValue( PROP_SCENE_SHADE_MODE)>>=aOldShadeMode) || + aOldShadeMode != aShadeMode ) + { + setFastPropertyValue( PROP_SCENE_SHADE_MODE, uno::Any( aShadeMode )); // "D3DSceneShadeMode" + } + + lcl_setLightsForScheme( *this, aScheme ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + +} + +void Diagram::setDefaultRotation( bool bPieOrDonut ) +{ + drawing::CameraGeometry aCameraGeo( ThreeDHelper::getDefaultCameraGeometry( bPieOrDonut ) ); + // "D3DCameraGeometry" + setFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY, uno::Any( aCameraGeo )); + + ::basegfx::B3DHomMatrix aSceneRotation; + if( bPieOrDonut ) + aSceneRotation.rotate( -M_PI/3.0, 0, 0 ); + // "D3DTransformMatrix" + setFastPropertyValue( PROP_SCENE_TRANSF_MATRIX, + uno::Any( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation ))); +} + +void Diagram::switchRightAngledAxes( bool bRightAngledAxes ) +{ + try + { + bool bOldRightAngledAxes = false; + getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bOldRightAngledAxes; // "RightAngledAxes" + if( bOldRightAngledAxes!=bRightAngledAxes) + { + setFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES, uno::Any( bRightAngledAxes )); + if(bRightAngledAxes) + { + ::basegfx::B3DHomMatrix aInverseRotation( lcl_getInverseRotationMatrix( *this ) ); + lcl_rotateLights( aInverseRotation, *this ); + } + else + { + ::basegfx::B3DHomMatrix aCompleteRotation( lcl_getCompleteRotationMatrix( *this ) ); + lcl_rotateLights( aCompleteRotation, *this ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_Diagram_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::Diagram(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/FormattedString.cxx b/chart2/source/model/main/FormattedString.cxx new file mode 100644 index 0000000000..dbd5876b97 --- /dev/null +++ b/chart2/source/model/main/FormattedString.cxx @@ -0,0 +1,276 @@ +/* -*- 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 <FormattedString.hxx> + +#include <CharacterProperties.hxx> +#include <PropertyHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <cppuhelper/supportsservice.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::osl::MutexGuard; + +namespace chart +{ +const ::chart::tPropertyValueMap & StaticFormattedStringDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = [] + { + ::chart::tPropertyValueMap aMap; + ::chart::CharacterProperties::AddDefaultsToMap( aMap ); + return aMap; + }(); + return aStaticDefaults; +}; +} // namespace chart + +namespace +{ + +::cppu::OPropertyArrayHelper& StaticFormattedStringInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ + +FormattedString::FormattedString() : + m_aType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT), + m_bDataLabelsRange(false), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +FormattedString::FormattedString( const FormattedString & rOther ) : + impl::FormattedString_Base(rOther), + ::property::OPropertySet( rOther ), + m_aString( rOther.m_aString ), + m_aType(rOther.m_aType), + m_aGuid(rOther.m_aGuid), + m_bDataLabelsRange(rOther.m_bDataLabelsRange), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +FormattedString::~FormattedString() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL FormattedString::createClone() +{ + return uno::Reference< util::XCloneable >( new FormattedString( *this )); +} + +// ____ XFormattedString ____ +OUString SAL_CALL FormattedString::getString() +{ + MutexGuard aGuard( m_aMutex); + return m_aString; +} + +void SAL_CALL FormattedString::setString( const OUString& String ) +{ + { + MutexGuard aGuard( m_aMutex); + m_aString = String; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); + +} + +// ____ XDataPointCustomLabelField ____ +css::chart2::DataPointCustomLabelFieldType SAL_CALL FormattedString::getFieldType() +{ + MutexGuard aGuard(m_aMutex); + return m_aType; +} + +void SAL_CALL +FormattedString::setFieldType(const css::chart2::DataPointCustomLabelFieldType Type) +{ + { + MutexGuard aGuard(m_aMutex); + m_aType = Type; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); +} + +OUString SAL_CALL FormattedString::getGuid() +{ + MutexGuard aGuard( m_aMutex); + return m_aGuid; +} + +void SAL_CALL FormattedString::setGuid( const OUString& guid ) +{ + { + MutexGuard aGuard( m_aMutex); + m_aGuid= guid; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); + +} + +sal_Bool SAL_CALL FormattedString::getDataLabelsRange() +{ + MutexGuard aGuard( m_aMutex); + return m_bDataLabelsRange; +} + +void SAL_CALL FormattedString::setDataLabelsRange( sal_Bool dataLabelsRange ) +{ + { + MutexGuard aGuard( m_aMutex); + m_bDataLabelsRange = dataLabelsRange; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); +} + +OUString SAL_CALL FormattedString::getCellRange() +{ + MutexGuard aGuard( m_aMutex); + return m_aCellRange; +} + +void SAL_CALL FormattedString::setCellRange( const OUString& cellRange ) +{ + { + MutexGuard aGuard( m_aMutex); + m_aCellRange = cellRange; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL FormattedString::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL FormattedString::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL FormattedString::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL FormattedString::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void FormattedString::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void FormattedString::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void FormattedString::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticFormattedStringDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL FormattedString::getInfoHelper() +{ + return StaticFormattedStringInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL FormattedString::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticFormattedStringInfoHelper() ) ); + return xPropertySetInfo; +} + +using impl::FormattedString_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( FormattedString, FormattedString_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( FormattedString, FormattedString_Base, ::property::OPropertySet ) + +// do this in derived classes! + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL FormattedString::getImplementationName() +{ + return "com.sun.star.comp.chart.FormattedString"; +} + +sal_Bool SAL_CALL FormattedString::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL FormattedString::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.DataPointCustomLabelField", + "com.sun.star.chart2.FormattedString", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_FormattedString_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::FormattedString); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/GridProperties.cxx b/chart2/source/model/main/GridProperties.cxx new file mode 100644 index 0000000000..a495f631f7 --- /dev/null +++ b/chart2/source/model/main/GridProperties.cxx @@ -0,0 +1,201 @@ +/* -*- 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 <GridProperties.hxx> +#include <LinePropertiesHelper.hxx> +#include <UserDefinedProperties.hxx> +#include <PropertyHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <cppuhelper/supportsservice.hxx> + +namespace com::sun::star::beans { class XPropertySetInfo; } +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_GRID_SHOW +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Show", + PROP_GRID_SHOW, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +const ::chart::tPropertyValueMap & StaticGridDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aTmp; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aTmp ); + + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_GRID_SHOW, false ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue< sal_Int32 >( + aTmp, ::chart::LinePropertiesHelper::PROP_LINE_COLOR, 0xb3b3b3 ); // gray30 + return aTmp; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& StaticGridInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ + +GridProperties::GridProperties() : + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +GridProperties::GridProperties( const GridProperties & rOther ) : + impl::GridProperties_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ +} + +GridProperties::~GridProperties() +{} + +// ____ OPropertySet ____ +void GridProperties::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticGridDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL GridProperties::getInfoHelper() +{ + return StaticGridInfoHelper(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL GridProperties::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticGridInfoHelper() ) ); + return xPropertySetInfo; +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL GridProperties::createClone() +{ + return uno::Reference< util::XCloneable >( new GridProperties( *this )); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL GridProperties::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL GridProperties::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL GridProperties::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL GridProperties::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void GridProperties::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL GridProperties::getImplementationName() +{ + return "com.sun.star.comp.chart2.GridProperties"; +} + +sal_Bool SAL_CALL GridProperties::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL GridProperties::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.GridProperties", + "com.sun.star.beans.PropertySet" }; +} + +// needed by MSC compiler +using impl::GridProperties_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( GridProperties, GridProperties_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( GridProperties, GridProperties_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_GridProperties_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::GridProperties); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Legend.cxx b/chart2/source/model/main/Legend.cxx new file mode 100644 index 0000000000..f72868b58c --- /dev/null +++ b/chart2/source/model/main/Legend.cxx @@ -0,0 +1,275 @@ +/* -*- 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 <Legend.hxx> +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <CharacterProperties.hxx> +#include <UserDefinedProperties.hxx> +#include <ModifyListenerHelper.hxx> +#include <PropertyHelper.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart/ChartLegendExpansion.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/RelativeSize.hpp> +#include <cppuhelper/supportsservice.hxx> + +#include <algorithm> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans::PropertyAttribute; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_LEGEND_ANCHOR_POSITION, + PROP_LEGEND_EXPANSION, + PROP_LEGEND_SHOW, + PROP_LEGEND_OVERLAY, + PROP_LEGEND_REF_PAGE_SIZE, + PROP_LEGEND_REL_POS, + PROP_LEGEND_REL_SIZE +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "AnchorPosition", + PROP_LEGEND_ANCHOR_POSITION, + cppu::UnoType<chart2::LegendPosition>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Expansion", + PROP_LEGEND_EXPANSION, + cppu::UnoType<css::chart::ChartLegendExpansion>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Show", + PROP_LEGEND_SHOW, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Overlay", + PROP_LEGEND_OVERLAY, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_LEGEND_REF_PAGE_SIZE, + cppu::UnoType<awt::Size>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RelativePosition", + PROP_LEGEND_REL_POS, + cppu::UnoType<chart2::RelativePosition>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RelativeSize", + PROP_LEGEND_REL_SIZE, + cppu::UnoType<chart2::RelativeSize>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + +} + +} // namespace + +namespace chart +{ +const ::chart::tPropertyValueMap& StaticLegendDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aTmp; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aTmp ); + ::chart::FillProperties::AddDefaultsToMap( aTmp ); + ::chart::CharacterProperties::AddDefaultsToMap( aTmp ); + + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_LEGEND_ANCHOR_POSITION, chart2::LegendPosition_LINE_END ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_LEGEND_EXPANSION, css::chart::ChartLegendExpansion_HIGH ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_LEGEND_SHOW, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_LEGEND_OVERLAY, false ); + + float fDefaultCharHeight = 10.0; + ::chart::PropertyHelper::setPropertyValue( aTmp, ::chart::CharacterProperties::PROP_CHAR_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( aTmp, ::chart::CharacterProperties::PROP_CHAR_ASIAN_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( aTmp, ::chart::CharacterProperties::PROP_CHAR_COMPLEX_CHAR_HEIGHT, fDefaultCharHeight ); + return aTmp; + }(); + return aStaticDefaults; +}; +} // namespace chart + +namespace +{ +::cppu::OPropertyArrayHelper& StaticLegendInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ + +Legend::Legend() : + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ +} + +Legend::Legend( const Legend & rOther ) : + impl::Legend_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ +} + +Legend::~Legend() +{ +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL Legend::createClone() +{ + return Reference< util::XCloneable >( new Legend( *this )); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Legend::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Legend::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Legend::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Legend::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void Legend::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void Legend::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticLegendDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL Legend::getInfoHelper() +{ + return StaticLegendInfoHelper(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL Legend::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticLegendInfoHelper() ) ); + return xPropertySetInfo; +} + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL Legend::getImplementationName() +{ + return "com.sun.star.comp.chart2.Legend"; +} + +sal_Bool SAL_CALL Legend::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL Legend::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.Legend", + "com.sun.star.beans.PropertySet", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties", + "com.sun.star.style.CharacterProperties", + "com.sun.star.layout.LayoutElement" + }; +} + +// needed by MSC compiler +using impl::Legend_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Legend, Legend_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( Legend, Legend_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_Legend_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::Legend); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/PageBackground.cxx b/chart2/source/model/main/PageBackground.cxx new file mode 100644 index 0000000000..c866bdbb3f --- /dev/null +++ b/chart2/source/model/main/PageBackground.cxx @@ -0,0 +1,198 @@ +/* -*- 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 "PageBackground.hxx" +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <UserDefinedProperties.hxx> +#include <PropertyHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <svtools/colorcfg.hxx> +#include <sfx2/viewsh.hxx> + +#include <com/sun/star/drawing/LineStyle.hpp> +#include <cppuhelper/supportsservice.hxx> + +#include <vector> +#include <algorithm> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace +{ + +const ::chart::tPropertyValueMap& StaticPageBackgroundDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aTmp; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aTmp ); + ::chart::FillProperties::AddDefaultsToMap( aTmp ); + + // override other defaults + Color aDocColor = COL_WHITE; + if (SfxViewShell::Current()) { + aDocColor = SfxViewShell::Current()->GetColorConfigColor(svtools::DOCCOLOR); + } else { + SAL_WARN("chart2", "SfxViewShell::Current() returned nullptr"); + } + ::chart::PropertyHelper::setPropertyValue( aTmp, ::chart::FillProperties::PROP_FILL_COLOR, aDocColor ); + ::chart::PropertyHelper::setPropertyValue( aTmp, ::chart::LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_NONE ); + return aTmp; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& StaticPageBackgroundInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ + +PageBackground::PageBackground() : + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +PageBackground::PageBackground( const PageBackground & rOther ) : + impl::PageBackground_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +PageBackground::~PageBackground() +{} + +// ____ XTypeProvider ____ +uno::Sequence< css::uno::Type > SAL_CALL PageBackground::getTypes() +{ + return ::comphelper::concatSequences( + impl::PageBackground_Base::getTypes(), + ::property::OPropertySet::getTypes()); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL PageBackground::createClone() +{ + return uno::Reference< util::XCloneable >( new PageBackground( *this )); +} + +// ____ OPropertySet ____ +void PageBackground::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticPageBackgroundDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL PageBackground::getInfoHelper() +{ + return StaticPageBackgroundInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL PageBackground::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticPageBackgroundInfoHelper() ) ); + return xPropertySetInfo; +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL PageBackground::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL PageBackground::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL PageBackground::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL PageBackground::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void PageBackground::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +OUString SAL_CALL PageBackground::getImplementationName() +{ + return "com.sun.star.comp.chart2.PageBackground"; +} + +sal_Bool SAL_CALL PageBackground::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PageBackground::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.PageBackground", + "com.sun.star.beans.PropertySet" }; +} + +using impl::PageBackground_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( PageBackground, PageBackground_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_PageBackground_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::PageBackground ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/PageBackground.hxx b/chart2/source/model/main/PageBackground.hxx new file mode 100644 index 0000000000..2aef8bd45e --- /dev/null +++ b/chart2/source/model/main/PageBackground.hxx @@ -0,0 +1,100 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <OPropertySet.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/uno3.hxx> +#include <ModifyListenerHelper.hxx> + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener, + css::lang::XServiceInfo > + PageBackground_Base; +} + +class PageBackground final : + public impl::PageBackground_Base, + public ::property::OPropertySet +{ +public: + explicit PageBackground(); + virtual ~PageBackground() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + + explicit PageBackground( const PageBackground & rOther ); + + // ____ XTypeProvider ____ + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + +private: + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + rtl::Reference<ModifyEventForwarder> m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/PolarCoordinateSystem.cxx b/chart2/source/model/main/PolarCoordinateSystem.cxx new file mode 100644 index 0000000000..0807415dac --- /dev/null +++ b/chart2/source/model/main/PolarCoordinateSystem.cxx @@ -0,0 +1,158 @@ +/* -*- 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 <PolarCoordinateSystem.hxx> +#include <servicenames_coosystems.hxx> +#include <cppuhelper/supportsservice.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +constexpr OUString CHART2_COOSYSTEM_POLAR_SERVICE_NAME + = u"com.sun.star.chart2.CoordinateSystems.Polar"_ustr; + +} + +namespace chart +{ + +// explicit +PolarCoordinateSystem::PolarCoordinateSystem( sal_Int32 nDimensionCount /* = 2 */ ) : + BaseCoordinateSystem( nDimensionCount ) +{} + +PolarCoordinateSystem::PolarCoordinateSystem( + const PolarCoordinateSystem & rSource ) : + BaseCoordinateSystem( rSource ) +{} + +PolarCoordinateSystem::~PolarCoordinateSystem() +{} + +// ____ XCoordinateSystem ____ +OUString SAL_CALL PolarCoordinateSystem::getCoordinateSystemType() +{ + return CHART2_COOSYSTEM_POLAR_SERVICE_NAME; +} + +OUString SAL_CALL PolarCoordinateSystem::getViewServiceName() +{ + return CHART2_COOSYSTEM_POLAR_VIEW_SERVICE_NAME; +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL PolarCoordinateSystem::createClone() +{ + return Reference< util::XCloneable >( new PolarCoordinateSystem( *this )); +} + +// ____ XServiceInfo ____ +OUString SAL_CALL PolarCoordinateSystem::getImplementationName() +{ + return "com.sun.star.comp.chart.PolarCoordinateSystem"; +} + +sal_Bool SAL_CALL PolarCoordinateSystem::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PolarCoordinateSystem::getSupportedServiceNames() +{ + return { CHART2_COOSYSTEM_POLAR_SERVICE_NAME }; +} + +// ==== PolarCoordinateSystem2d ==== + +PolarCoordinateSystem2d::PolarCoordinateSystem2d() : + PolarCoordinateSystem( 2 ) +{} + +PolarCoordinateSystem2d::~PolarCoordinateSystem2d() +{} + +// ____ XServiceInfo ____ +OUString SAL_CALL PolarCoordinateSystem2d::getImplementationName() +{ + return "com.sun.star.comp.chart2.PolarCoordinateSystem2d" ; +} + +sal_Bool SAL_CALL PolarCoordinateSystem2d::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PolarCoordinateSystem2d::getSupportedServiceNames() +{ + return { + CHART2_COOSYSTEM_POLAR_SERVICE_NAME, + "com.sun.star.chart2.PolarCoordinateSystem2d" }; +} + +// ==== PolarCoordinateSystem3d ==== + +PolarCoordinateSystem3d::PolarCoordinateSystem3d() : + PolarCoordinateSystem( 3 ) +{} + +PolarCoordinateSystem3d::~PolarCoordinateSystem3d() +{} + +// ____ XServiceInfo ____ +OUString SAL_CALL PolarCoordinateSystem3d::getImplementationName() +{ + return "com.sun.star.comp.chart2.PolarCoordinateSystem3d"; +} + +sal_Bool SAL_CALL PolarCoordinateSystem3d::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PolarCoordinateSystem3d::getSupportedServiceNames() +{ + return { + CHART2_COOSYSTEM_POLAR_SERVICE_NAME, + "com.sun.star.chart2.PolarCoordinateSystem3d" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_PolarCoordinateSystem2d_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::PolarCoordinateSystem2d); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_PolarCoordinateSystem3d_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::PolarCoordinateSystem3d); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/StockBar.cxx b/chart2/source/model/main/StockBar.cxx new file mode 100644 index 0000000000..e8c72059bc --- /dev/null +++ b/chart2/source/model/main/StockBar.cxx @@ -0,0 +1,173 @@ +/* -*- 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 <StockBar.hxx> +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <UserDefinedProperties.hxx> +#include <PropertyHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <algorithm> + +namespace com::sun::star::beans { class XPropertySetInfo; } + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace +{ + +::cppu::OPropertyArrayHelper& StaticStockBarInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +const ::chart::tPropertyValueMap & StaticStockBarDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aTmp; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aTmp ); + ::chart::FillProperties::AddDefaultsToMap( aTmp ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue< sal_Int32 >( aTmp, ::chart::FillProperties::PROP_FILL_COLOR, 0xffffff ); // white + return aTmp; + }(); + return aStaticDefaults; +}; + +} // anonymous namespace + +namespace chart +{ + +StockBar::StockBar( bool bRisingCourse ) : + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + if( ! bRisingCourse ) + { + setFastPropertyValue_NoBroadcast( + ::chart::FillProperties::PROP_FILL_COLOR, + uno::Any( sal_Int32( 0x000000 ))); // black + setFastPropertyValue_NoBroadcast( + ::chart::LinePropertiesHelper::PROP_LINE_COLOR, + uno::Any( sal_Int32( 0xb3b3b3 ))); // gray30 + } +} + +StockBar::StockBar( const StockBar & rOther ) : + impl::StockBar_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +StockBar::~StockBar() +{} + +// ____ XTypeProvider ____ +uno::Sequence< css::uno::Type > SAL_CALL StockBar::getTypes() +{ + return ::comphelper::concatSequences( + impl::StockBar_Base::getTypes(), + ::property::OPropertySet::getTypes()); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL StockBar::createClone() +{ + return uno::Reference< util::XCloneable >( new StockBar( *this )); +} + +// ____ OPropertySet ____ +void StockBar::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticStockBarDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL StockBar::getInfoHelper() +{ + return StaticStockBarInfoHelper(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL StockBar::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticStockBarInfoHelper() ) ); + return xPropertySetInfo; +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL StockBar::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL StockBar::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL StockBar::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL StockBar::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void StockBar::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +using impl::StockBar_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( StockBar, StockBar_Base, ::property::OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Title.cxx b/chart2/source/model/main/Title.cxx new file mode 100644 index 0000000000..6833684e9b --- /dev/null +++ b/chart2/source/model/main/Title.cxx @@ -0,0 +1,343 @@ +/* -*- 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 <Title.hxx> +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <CloneHelper.hxx> +#include <PropertyHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/style/ParagraphAdjust.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <cppuhelper/supportsservice.hxx> + +#include <vector> +#include <algorithm> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans::PropertyAttribute; + +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; + +namespace +{ + +enum +{ + PROP_TITLE_PARA_ADJUST, + PROP_TITLE_PARA_LAST_LINE_ADJUST, + PROP_TITLE_PARA_LEFT_MARGIN, + PROP_TITLE_PARA_RIGHT_MARGIN, + PROP_TITLE_PARA_TOP_MARGIN, + PROP_TITLE_PARA_BOTTOM_MARGIN, + PROP_TITLE_PARA_IS_HYPHENATION, + PROP_TITLE_VISIBLE, + + PROP_TITLE_TEXT_ROTATION, + PROP_TITLE_TEXT_STACKED, + PROP_TITLE_REL_POS, + + PROP_TITLE_REF_PAGE_SIZE +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "ParaAdjust", + PROP_TITLE_PARA_ADJUST, + cppu::UnoType<css::style::ParagraphAdjust>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaLastLineAdjust", + PROP_TITLE_PARA_LAST_LINE_ADJUST, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaLeftMargin", + PROP_TITLE_PARA_LEFT_MARGIN, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaRightMargin", + PROP_TITLE_PARA_RIGHT_MARGIN, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaTopMargin", + PROP_TITLE_PARA_TOP_MARGIN, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaBottomMargin", + PROP_TITLE_PARA_BOTTOM_MARGIN, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaIsHyphenation", + PROP_TITLE_PARA_IS_HYPHENATION, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + + rOutProperties.emplace_back( "Visible", + PROP_TITLE_VISIBLE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextRotation", + PROP_TITLE_TEXT_ROTATION, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "StackCharacters", + PROP_TITLE_TEXT_STACKED, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "RelativePosition", + PROP_TITLE_REL_POS, + cppu::UnoType<chart2::RelativePosition>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_TITLE_REF_PAGE_SIZE, + cppu::UnoType<awt::Size>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +const ::chart::tPropertyValueMap& StaticTitleDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aTmp; + + ::chart::LinePropertiesHelper::AddDefaultsToMap( aTmp ); + ::chart::FillProperties::AddDefaultsToMap( aTmp ); + + // ParagraphProperties + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_TITLE_PARA_ADJUST, + css::style::ParagraphAdjust_CENTER ); + // PROP_TITLE_PARA_LAST_LINE_ADJUST + + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aTmp, PROP_TITLE_PARA_LEFT_MARGIN, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aTmp, PROP_TITLE_PARA_RIGHT_MARGIN, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aTmp, PROP_TITLE_PARA_TOP_MARGIN, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aTmp, PROP_TITLE_PARA_BOTTOM_MARGIN, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_TITLE_PARA_IS_HYPHENATION, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_TITLE_VISIBLE, true ); + + // own properties + ::chart::PropertyHelper::setPropertyValueDefault< double >( aTmp, PROP_TITLE_TEXT_ROTATION, 0.0 ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_TITLE_TEXT_STACKED, false ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue( aTmp, ::chart::FillProperties::PROP_FILL_STYLE, drawing::FillStyle_NONE ); + ::chart::PropertyHelper::setPropertyValue( aTmp, ::chart::LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_NONE ); + return aTmp; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& StaticTitleInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ + +Title::Title() : + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +Title::Title( const Title & rOther ) : + impl::Title_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + CloneHelper::CloneRefSequence<chart2::XFormattedString>( + rOther.m_aStrings, m_aStrings ); + ModifyListenerHelper::addListenerToAllElements( + comphelper::sequenceToContainer<std::vector<uno::Reference< chart2::XFormattedString > > >( m_aStrings ), + m_xModifyEventForwarder ); +} + +Title::~Title() +{ + ModifyListenerHelper::removeListenerFromAllElements( + comphelper::sequenceToContainer<std::vector<uno::Reference< chart2::XFormattedString > > >( m_aStrings ), + m_xModifyEventForwarder ); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL Title::createClone() +{ + return uno::Reference< util::XCloneable >( new Title( *this )); +} + +// ____ XTitle ____ +uno::Sequence< uno::Reference< chart2::XFormattedString > > SAL_CALL Title::getText() +{ + MutexGuard aGuard( m_aMutex ); + return m_aStrings; +} + +void SAL_CALL Title::setText( const uno::Sequence< uno::Reference< chart2::XFormattedString > >& rNewStrings ) +{ + uno::Sequence< uno::Reference< chart2::XFormattedString > > aOldStrings; + { + MutexGuard aGuard( m_aMutex ); + std::swap( m_aStrings, aOldStrings ); + m_aStrings = rNewStrings; + } + //don't keep the mutex locked while calling out + ModifyListenerHelper::removeListenerFromAllElements( + comphelper::sequenceToContainer<std::vector<uno::Reference< chart2::XFormattedString > > >( aOldStrings ), + m_xModifyEventForwarder ); + ModifyListenerHelper::addListenerToAllElements( + comphelper::sequenceToContainer<std::vector<uno::Reference< chart2::XFormattedString > > >( rNewStrings ), + m_xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ OPropertySet ____ +void Title::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticTitleDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL Title::getInfoHelper() +{ + return StaticTitleInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL Title::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticTitleInfoHelper() ) ); + return xPropertySetInfo; +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Title::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Title::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Title::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Title::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void Title::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void Title::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +OUString SAL_CALL Title::getImplementationName() +{ + return "com.sun.star.comp.chart2.Title"; +} + +sal_Bool SAL_CALL Title::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL Title::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.Title", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.beans.PropertySet", + "com.sun.star.layout.LayoutElement" }; +} + +// needed by MSC compiler +using impl::Title_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Title, Title_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( Title, Title_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_Title_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::Title); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/UndoManager.cxx b/chart2/source/model/main/UndoManager.cxx new file mode 100644 index 0000000000..a756e7440a --- /dev/null +++ b/chart2/source/model/main/UndoManager.cxx @@ -0,0 +1,350 @@ +/* -*- 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 "UndoManager.hxx" +#include <ChartModel.hxx> +#include <ChartViewHelper.hxx> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <framework/undomanagerhelper.hxx> +#include <framework/imutex.hxx> +#include <officecfg/Office/Common.hxx> +#include <svl/undo.hxx> + +namespace chart +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::document::XUndoManager; + using ::com::sun::star::document::XUndoAction; + using ::com::sun::star::document::XUndoManagerListener; + using ::com::sun::star::lang::NoSupportException; + using ::com::sun::star::util::XModifyListener; + using ::com::sun::star::frame::XModel; + + namespace impl + { + class UndoManager_Impl : public ::framework::IUndoManagerImplementation + { + public: + UndoManager_Impl( UndoManager& i_antiImpl, ::chart::ChartModel& i_parent, ::osl::Mutex& i_mutex ) + :m_rAntiImpl( i_antiImpl ) + ,m_rParent( i_parent ) + ,m_rMutex( i_mutex ) + ,m_bDisposed( false ) + ,m_aUndoHelper( *this ) + { + m_aUndoManager.SetMaxUndoActionCount( + officecfg::Office::Common::Undo::Steps::get()); + } + + virtual ~UndoManager_Impl() + { + } + + ::osl::Mutex& getMutex(); + // IUndoManagerImplementation + virtual SfxUndoManager& getImplUndoManager() override; + virtual Reference< XUndoManager > getThis() override; + + // attribute access + ::chart::ChartModel& getParent() { return m_rParent; } + ::framework::UndoManagerHelper& getUndoHelper() { return m_aUndoHelper; } + + // public interface + + /// is called when the owner of the UndoManager is being disposed + void disposing(); + + /// checks whether we're already disposed, throws a DisposedException if so + void checkDisposed_lck(); + + private: + UndoManager& m_rAntiImpl; + ::chart::ChartModel& m_rParent; + ::osl::Mutex& m_rMutex; + bool m_bDisposed; + + SfxUndoManager m_aUndoManager; + ::framework::UndoManagerHelper m_aUndoHelper; + }; + + ::osl::Mutex& UndoManager_Impl::getMutex() + { + return m_rMutex; + } + + SfxUndoManager& UndoManager_Impl::getImplUndoManager() + { + return m_aUndoManager; + } + + Reference< XUndoManager > UndoManager_Impl::getThis() + { + return &m_rAntiImpl; + } + + void UndoManager_Impl::disposing() + { + { + ::osl::MutexGuard aGuard( m_rMutex ); + m_bDisposed = true; + } + m_aUndoHelper.disposing(); + } + + void UndoManager_Impl::checkDisposed_lck() + { + if ( m_bDisposed ) + throw DisposedException( OUString(), getThis() ); + } + + namespace { + + /** guard for public UNO methods of the UndoManager + + The only purpose of this guard is to check for the instance being disposed already. Everything else, + in particular the IMutexGuard functionality required by the UndoManagerHelper class, is a dummy only, + as all involved classes (means we ourselves, the UndoManagerHelper, the SfxUndoManager, and the Undo actions + we create) are inherently thread-safe, thus need no external lock (in particular no SolarMutex!). + */ + class UndoManagerMethodGuard : public ::framework::IMutexGuard + { + public: + explicit UndoManagerMethodGuard( UndoManager_Impl& i_impl ) + { + ::osl::MutexGuard aGuard( i_impl.getMutex() ); + // throw if the instance is already disposed + i_impl.checkDisposed_lck(); + } + virtual ~UndoManagerMethodGuard() + { + } + + // IMutexGuard + virtual void clear() override; + virtual ::framework::IMutex& getGuardedMutex() override; + }; + + class DummyMutex : public ::framework::IMutex + { + public: + virtual ~DummyMutex() {} + virtual void acquire() override { } + virtual void release() override { } + }; + + } + + ::framework::IMutex& UndoManagerMethodGuard::getGuardedMutex() + { + static DummyMutex s_aDummyMutex; + return s_aDummyMutex; + } + + void UndoManagerMethodGuard::clear() + { + // nothing to do. This interface implementation is a dummy. + } + } + + using impl::UndoManagerMethodGuard; + + UndoManager::UndoManager( ::chart::ChartModel& i_parent, ::osl::Mutex& i_mutex ) + :m_pImpl( new impl::UndoManager_Impl( *this, i_parent, i_mutex ) ) + { + } + + UndoManager::~UndoManager() + { + } + + void SAL_CALL UndoManager::acquire() noexcept + { + m_pImpl->getParent().acquire(); + } + + void SAL_CALL UndoManager::release() noexcept + { + m_pImpl->getParent().release(); + } + + void UndoManager::disposing() + { + m_pImpl->disposing(); + } + + void SAL_CALL UndoManager::enterUndoContext( const OUString& i_title ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().enterUndoContext( i_title, aGuard ); + } + + void SAL_CALL UndoManager::enterHiddenUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().enterHiddenUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::leaveUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().leaveUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::addUndoAction( const Reference< XUndoAction >& i_action ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().addUndoAction( i_action, aGuard ); + } + + void SAL_CALL UndoManager::undo( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().undo( aGuard ); + + ChartViewHelper::setViewToDirtyState( &m_pImpl->getParent() ); + } + + void SAL_CALL UndoManager::redo( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().redo( aGuard ); + + ChartViewHelper::setViewToDirtyState( &m_pImpl->getParent() ); + } + + sal_Bool SAL_CALL UndoManager::isUndoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().isUndoPossible(); + } + + sal_Bool SAL_CALL UndoManager::isRedoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().isRedoPossible(); + } + + OUString SAL_CALL UndoManager::getCurrentUndoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().getCurrentUndoActionTitle(); + } + + OUString SAL_CALL UndoManager::getCurrentRedoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().getCurrentRedoActionTitle(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllUndoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().getAllUndoActionTitles(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllRedoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().getAllRedoActionTitles(); + } + + void SAL_CALL UndoManager::clear( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().clear( aGuard ); + } + + void SAL_CALL UndoManager::clearRedo( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().clearRedo( aGuard ); + } + + void SAL_CALL UndoManager::reset( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().reset( aGuard ); + } + + void SAL_CALL UndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().addUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().removeUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::lock( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().lock(); + } + + void SAL_CALL UndoManager::unlock( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().unlock(); + } + + sal_Bool SAL_CALL UndoManager::isLocked( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().isLocked(); + } + + Reference< XInterface > SAL_CALL UndoManager::getParent( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getParent(); + } + + void SAL_CALL UndoManager::setParent( const Reference< XInterface >& ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + throw NoSupportException( OUString(), m_pImpl->getThis() ); + } + + void SAL_CALL UndoManager::addModifyListener( const Reference< XModifyListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().addModifyListener( i_listener ); + } + + void SAL_CALL UndoManager::removeModifyListener( const Reference< XModifyListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().removeModifyListener( i_listener ); + } + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/UndoManager.hxx b/chart2/source/model/main/UndoManager.hxx new file mode 100644 index 0000000000..c20dcef664 --- /dev/null +++ b/chart2/source/model/main/UndoManager.hxx @@ -0,0 +1,92 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/document/XUndoManager.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> + +#include <cppuhelper/implbase2.hxx> + +#include <memory> + +namespace chart +{ +class ChartModel; + + namespace impl + { + class UndoManager_Impl; + typedef ::cppu::ImplHelper2 < css::document::XUndoManager + , css::util::XModifyBroadcaster + > UndoManager_Base; + } + + class UndoManager : public impl::UndoManager_Base + { + public: + UndoManager( ::chart::ChartModel& i_parent, ::osl::Mutex& i_mutex ); + virtual ~UndoManager(); + + // XInterface + virtual void SAL_CALL acquire( ) noexcept override; + virtual void SAL_CALL release( ) noexcept override; + + // XComponent equivalents + void disposing(); + + // XUndoManager + virtual void SAL_CALL enterUndoContext( const OUString& i_title ) override; + virtual void SAL_CALL enterHiddenUndoContext( ) override; + virtual void SAL_CALL leaveUndoContext( ) override; + virtual void SAL_CALL addUndoAction( const css::uno::Reference< css::document::XUndoAction >& i_action ) override; + virtual void SAL_CALL undo( ) override; + virtual void SAL_CALL redo( ) override; + virtual sal_Bool SAL_CALL isUndoPossible( ) override; + virtual sal_Bool SAL_CALL isRedoPossible( ) override; + virtual OUString SAL_CALL getCurrentUndoActionTitle( ) override; + virtual OUString SAL_CALL getCurrentRedoActionTitle( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getAllUndoActionTitles( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getAllRedoActionTitles( ) override; + virtual void SAL_CALL clear( ) override; + virtual void SAL_CALL clearRedo( ) override; + virtual void SAL_CALL reset( ) override; + virtual void SAL_CALL addUndoManagerListener( const css::uno::Reference< css::document::XUndoManagerListener >& i_listener ) override; + virtual void SAL_CALL removeUndoManagerListener( const css::uno::Reference< css::document::XUndoManagerListener >& i_listener ) override; + + // XLockable (base of XUndoManager) + virtual void SAL_CALL lock( ) override; + virtual void SAL_CALL unlock( ) override; + virtual sal_Bool SAL_CALL isLocked( ) override; + + // XChild (base of XUndoManager) + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override; + virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override; + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + private: + std::unique_ptr< impl::UndoManager_Impl > m_pImpl; + }; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Wall.cxx b/chart2/source/model/main/Wall.cxx new file mode 100644 index 0000000000..1bbe133de9 --- /dev/null +++ b/chart2/source/model/main/Wall.cxx @@ -0,0 +1,155 @@ +/* -*- 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 "Wall.hxx" +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <UserDefinedProperties.hxx> +#include <PropertyHelper.hxx> +#include <ModifyListenerHelper.hxx> +#include <com/sun/star/drawing/LineStyle.hpp> + +#include <vector> +#include <algorithm> + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace +{ + +::cppu::OPropertyArrayHelper& StaticWallInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +} // anonymous namespace + +namespace chart +{ + +Wall::Wall() : + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +Wall::Wall( const Wall & rOther ) : + impl::Wall_Base(rOther), + ::property::OPropertySet( rOther ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +Wall::~Wall() +{} + +// ____ XTypeProvider ____ +uno::Sequence< css::uno::Type > SAL_CALL Wall::getTypes() +{ + return ::comphelper::concatSequences( + impl::Wall_Base::getTypes(), + ::property::OPropertySet::getTypes()); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL Wall::createClone() +{ + return uno::Reference< util::XCloneable >( new Wall( *this )); +} + +// ____ OPropertySet ____ +void Wall::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aTmp; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aTmp ); + ::chart::FillProperties::AddDefaultsToMap( aTmp ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue( aTmp, ::chart::LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_NONE ); + return aTmp; + }(); + tPropertyValueMap::const_iterator aFound( aStaticDefaults.find( nHandle ) ); + if( aFound == aStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL Wall::getInfoHelper() +{ + return StaticWallInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL Wall::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticWallInfoHelper() ) ); + return xPropertySetInfo; +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Wall::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Wall::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Wall::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Wall::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void Wall::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +using impl::Wall_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Wall, Wall_Base, ::property::OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Wall.hxx b/chart2/source/model/main/Wall.hxx new file mode 100644 index 0000000000..6cae798959 --- /dev/null +++ b/chart2/source/model/main/Wall.hxx @@ -0,0 +1,95 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/util/XCloneable.hpp> +#include <OPropertySet.hxx> + +#include <cppuhelper/implbase.hxx> +#include <comphelper/uno3.hxx> +#include <ModifyListenerHelper.hxx> + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + Wall_Base; +} + +class Wall final : + public impl::Wall_Base, + public ::property::OPropertySet +{ +public: + Wall(); + virtual ~Wall() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + + explicit Wall( const Wall & rOther ); + + // ____ XTypeProvider ____ + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + +private: + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + +private: + + rtl::Reference<ModifyEventForwarder> m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |