diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /chart2/source/controller | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'chart2/source/controller')
299 files changed, 67981 insertions, 0 deletions
diff --git a/chart2/source/controller/accessibility/AccessibleBase.cxx b/chart2/source/controller/accessibility/AccessibleBase.cxx new file mode 100644 index 000000000..4e8b20574 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleBase.cxx @@ -0,0 +1,854 @@ +/* -*- 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 <AccessibleBase.hxx> +#include "AccessibleChartShape.hxx" +#include <ObjectHierarchy.hxx> +#include <ObjectIdentifier.hxx> +#include <chartview/ExplicitValueProvider.hxx> + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleEventObject.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <sal/log.hxx> +#include <vcl/svapp.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/window.hxx> +#include <vcl/settings.hxx> +#include <o3tl/functional.hxx> +#include <o3tl/safeint.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/accessiblestatesethelper.hxx> + +#include <algorithm> +#include <iterator> + +#include "ChartElementFactory.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::Reference; +using ::osl::MutexGuard; +using ::osl::ClearableMutexGuard; +using ::com::sun::star::uno::Any; + +namespace chart +{ + +/** @param bMayHaveChildren is false per default + */ +AccessibleBase::AccessibleBase( + const AccessibleElementInfo & rAccInfo, + bool bMayHaveChildren, + bool bAlwaysTransparent /* default: false */ ) : + impl::AccessibleBase_Base( m_aMutex ), + m_bIsDisposed( false ), + m_bMayHaveChildren( bMayHaveChildren ), + m_bChildrenInitialized( false ), + m_nEventNotifierId(0), + m_xStateSetHelper( new ::utl::AccessibleStateSetHelper() ), + m_aAccInfo( rAccInfo ), + m_bAlwaysTransparent( bAlwaysTransparent ), + m_bStateSetInitialized( false ) +{ + // initialize some states + OSL_ASSERT( m_xStateSetHelper.is() ); + m_xStateSetHelper->AddState( AccessibleStateType::ENABLED ); + m_xStateSetHelper->AddState( AccessibleStateType::SHOWING ); + m_xStateSetHelper->AddState( AccessibleStateType::VISIBLE ); + m_xStateSetHelper->AddState( AccessibleStateType::SELECTABLE ); + m_xStateSetHelper->AddState( AccessibleStateType::FOCUSABLE ); +} + +AccessibleBase::~AccessibleBase() +{ + OSL_ASSERT( m_bIsDisposed ); +} + +bool AccessibleBase::CheckDisposeState( bool bThrowException /* default: true */ ) const +{ + if( bThrowException && + m_bIsDisposed ) + { + throw lang::DisposedException("component has state DEFUNC", + static_cast< uno::XWeak * >( const_cast< AccessibleBase * >( this ))); + } + return m_bIsDisposed; +} + +bool AccessibleBase::NotifyEvent( EventType eEventType, const AccessibleUniqueId & rId ) +{ + if( GetId() == rId ) + { + // event is addressed to this object + + css::uno::Any aEmpty; + css::uno::Any aSelected; + aSelected <<= AccessibleStateType::SELECTED; + switch( eEventType ) + { + case EventType::GOT_SELECTION: + { + AddState( AccessibleStateType::SELECTED ); + BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aSelected, aEmpty ); + + AddState( AccessibleStateType::FOCUSED ); + aSelected <<= AccessibleStateType::FOCUSED; + BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aSelected, aEmpty ); + + SAL_INFO("chart2.accessibility", "Selection acquired by: " << getAccessibleName()); + } + break; + + case EventType::LOST_SELECTION: + { + RemoveState( AccessibleStateType::SELECTED ); + BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aEmpty, aSelected ); + + AddState( AccessibleStateType::FOCUSED ); + aSelected <<= AccessibleStateType::FOCUSED; + BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aEmpty, aSelected ); + SAL_INFO("chart2.accessibility", "Selection lost by: " << getAccessibleName()); + } + break; + } + return true; + } + else if( m_bMayHaveChildren ) + { + bool bStop = false; + + ClearableMutexGuard aGuard( m_aMutex ); + // make local copy for notification + ChildListVectorType aLocalChildList( m_aChildList ); + aGuard.clear(); + + for (auto const& localChild : aLocalChildList) + { + // Note: at this place we must be sure to have an AccessibleBase + // object in the UNO reference to XAccessible ! + bStop = (*static_cast< AccessibleBase * > + ( localChild.get() )).NotifyEvent( eEventType, rId ); + if (bStop) + break; + } + return bStop; + } + + return false; +} + +void AccessibleBase::AddState( sal_Int16 aState ) +{ + CheckDisposeState(); + OSL_ASSERT( m_xStateSetHelper.is() ); + m_xStateSetHelper->AddState( aState ); +} + +void AccessibleBase::RemoveState( sal_Int16 aState ) +{ + CheckDisposeState(); + OSL_ASSERT( m_xStateSetHelper.is() ); + m_xStateSetHelper->RemoveState( aState ); +} + +bool AccessibleBase::UpdateChildren() +{ + bool bMustUpdateChildren = false; + { + MutexGuard aGuard( m_aMutex ); + if( ! m_bMayHaveChildren || + m_bIsDisposed ) + return false; + + bMustUpdateChildren = ( m_bMayHaveChildren && + ! m_bChildrenInitialized ); + } + + // update unguarded + if( bMustUpdateChildren ) + m_bChildrenInitialized = ImplUpdateChildren(); + + return m_bChildrenInitialized; +} + +bool AccessibleBase::ImplUpdateChildren() +{ + bool bResult = false; + + if( m_aAccInfo.m_spObjectHierarchy ) + { + ObjectHierarchy::tChildContainer aModelChildren( + m_aAccInfo.m_spObjectHierarchy->getChildren( GetId() )); + std::vector< ChildOIDMap::key_type > aAccChildren; + aAccChildren.reserve( aModelChildren.size()); + std::transform( m_aChildOIDMap.begin(), m_aChildOIDMap.end(), + std::back_inserter( aAccChildren ), + ::o3tl::select1st< ChildOIDMap::value_type >() ); + + std::sort( aModelChildren.begin(), aModelChildren.end()); + + std::vector< ObjectIdentifier > aChildrenToRemove, aChildrenToAdd; + std::set_difference( aModelChildren.begin(), aModelChildren.end(), + aAccChildren.begin(), aAccChildren.end(), + std::back_inserter( aChildrenToAdd )); + std::set_difference( aAccChildren.begin(), aAccChildren.end(), + aModelChildren.begin(), aModelChildren.end(), + std::back_inserter( aChildrenToRemove )); + + for (auto const& childToRemove : aChildrenToRemove) + { + RemoveChildByOId(childToRemove); + } + + AccessibleElementInfo aAccInfo( GetInfo()); + aAccInfo.m_pParent = this; + + for (auto const& childToAdd : aChildrenToAdd) + { + aAccInfo.m_aOID = childToAdd; + if ( childToAdd.isAutoGeneratedObject() ) + { + AddChild( ChartElementFactory::CreateChartElement( aAccInfo ).get() ); + } + else if ( childToAdd.isAdditionalShape() ) + { + AddChild( new AccessibleChartShape( aAccInfo ) ); + } + } + bResult = true; + } + + return bResult; +} + +void AccessibleBase::AddChild( AccessibleBase * pChild ) +{ + OSL_ENSURE( pChild != nullptr, "Invalid Child" ); + if( !pChild ) + return; + + ClearableMutexGuard aGuard( m_aMutex ); + + Reference< XAccessible > xChild( pChild ); + m_aChildList.push_back( xChild ); + + m_aChildOIDMap[ pChild->GetId() ] = xChild; + + // inform listeners of new child + if( m_bChildrenInitialized ) + { + Any aEmpty, aNew; + aNew <<= xChild; + + aGuard.clear(); + BroadcastAccEvent( AccessibleEventId::CHILD, aNew, aEmpty ); + } +} + +/** in this method we imply that the Reference< XAccessible > elements in the + vector are AccessibleBase objects ! + */ +void AccessibleBase::RemoveChildByOId( const ObjectIdentifier& rOId ) +{ + ClearableMutexGuard aGuard( m_aMutex ); + + ChildOIDMap::iterator aIt( m_aChildOIDMap.find( rOId )); + if( aIt == m_aChildOIDMap.end()) + return; + + Reference< XAccessible > xChild( aIt->second ); + + // remove from map + m_aChildOIDMap.erase( aIt ); + + // search child in vector + ChildListVectorType::iterator aVecIter = + std::find( m_aChildList.begin(), m_aChildList.end(), xChild ); + + OSL_ENSURE( aVecIter != m_aChildList.end(), + "Inconsistent ChildMap" ); + + // remove child from vector + m_aChildList.erase( aVecIter ); + bool bInitialized = m_bChildrenInitialized; + + // call listeners unguarded + aGuard.clear(); + + // inform listeners of removed child + if( bInitialized ) + { + Any aEmpty, aOld; + aOld <<= xChild; + + BroadcastAccEvent( AccessibleEventId::CHILD, aEmpty, aOld ); + } + + // dispose the child + Reference< lang::XComponent > xComp( xChild, UNO_QUERY ); + if( xComp.is()) + xComp->dispose(); +} + +awt::Point AccessibleBase::GetUpperLeftOnScreen() const +{ + awt::Point aResult; + if( m_aAccInfo.m_pParent ) + { + ClearableMutexGuard aGuard( m_aMutex ); + AccessibleBase * pParent = m_aAccInfo.m_pParent; + aGuard.clear(); + + if( pParent ) + { + aResult = pParent->GetUpperLeftOnScreen(); + } + else + OSL_FAIL( "Default position used is probably incorrect." ); + } + + return aResult; +} + +void AccessibleBase::BroadcastAccEvent( + sal_Int16 nId, + const Any & rNew, + const Any & rOld ) const +{ + ClearableMutexGuard aGuard( m_aMutex ); + + if ( !m_nEventNotifierId ) + return; + // if we don't have a client id for the notifier, then we don't have listeners, then + // we don't need to notify anything + + // the const cast is needed, because UNO parameters are never const + const AccessibleEventObject aEvent( + const_cast< uno::XWeak * >( static_cast< const uno::XWeak * >( this )), + nId, rNew, rOld ); + + // let the notifier handle this event + ::comphelper::AccessibleEventNotifier::addEvent( m_nEventNotifierId, aEvent ); + + aGuard.clear(); +} + +void AccessibleBase::KillAllChildren() +{ + ClearableMutexGuard aGuard( m_aMutex ); + + // make local copy for notification, and remove all children + ChildListVectorType aLocalChildList; + aLocalChildList.swap( m_aChildList ); + m_aChildOIDMap.clear(); + + aGuard.clear(); + + // call dispose for all children + // and notify listeners + Reference< lang::XComponent > xComp; + Any aEmpty, aOld; + for (auto const& localChild : aLocalChildList) + { + aOld <<= localChild; + BroadcastAccEvent( AccessibleEventId::CHILD, aEmpty, aOld ); + + xComp.set(localChild, UNO_QUERY); + if( xComp.is()) + xComp->dispose(); + } + m_bChildrenInitialized = false; +} + +void AccessibleBase::SetInfo( const AccessibleElementInfo & rNewInfo ) +{ + m_aAccInfo = rNewInfo; + if( m_bMayHaveChildren ) + { + KillAllChildren(); + } + BroadcastAccEvent( AccessibleEventId::INVALIDATE_ALL_CHILDREN, uno::Any(), uno::Any()); +} + +// ________ (XComponent::dispose) ________ +void SAL_CALL AccessibleBase::disposing() +{ + { + MutexGuard aGuard(m_aMutex); + OSL_ENSURE(!m_bIsDisposed, "dispose() called twice"); + + // notify disposing to all AccessibleEvent listeners asynchronous + if (m_nEventNotifierId) + { + ::comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(m_nEventNotifierId, + *this); + m_nEventNotifierId = 0; + } + + // reset pointers + m_aAccInfo.m_pParent = nullptr; + + // attach new empty state set helper to member reference + rtl::Reference<::utl::AccessibleStateSetHelper> pHelper = new ::utl::AccessibleStateSetHelper(); + pHelper->AddState(AccessibleStateType::DEFUNC); + // release old helper and attach new one + m_xStateSetHelper = pHelper; + + m_bIsDisposed = true; + + } + // call listeners unguarded + + if( m_bMayHaveChildren ) + { + KillAllChildren(); + } + else + OSL_ENSURE( m_aChildList.empty(), "Child list should be empty" ); +} + +// ________ XAccessible ________ +Reference< XAccessibleContext > SAL_CALL AccessibleBase::getAccessibleContext() +{ + return this; +} + +// ________ AccessibleBase::XAccessibleContext ________ +sal_Int32 SAL_CALL AccessibleBase::getAccessibleChildCount() +{ + ClearableMutexGuard aGuard( m_aMutex ); + if( ! m_bMayHaveChildren || + m_bIsDisposed ) + return 0; + + bool bMustUpdateChildren = ( m_bMayHaveChildren && + ! m_bChildrenInitialized ); + + aGuard.clear(); + + // update unguarded + if( bMustUpdateChildren ) + UpdateChildren(); + + return ImplGetAccessibleChildCount(); +} + +sal_Int32 AccessibleBase::ImplGetAccessibleChildCount() const +{ + return m_aChildList.size(); +} + +Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleChild( sal_Int32 i ) +{ + CheckDisposeState(); + Reference< XAccessible > xResult; + + ClearableMutexGuard aGuard( m_aMutex ); + bool bMustUpdateChildren = ( m_bMayHaveChildren && + ! m_bChildrenInitialized ); + + aGuard.clear(); + + if( bMustUpdateChildren ) + UpdateChildren(); + + xResult.set( ImplGetAccessibleChildById( i )); + + return xResult; +} + +Reference< XAccessible > AccessibleBase::ImplGetAccessibleChildById( sal_Int32 i ) const +{ + Reference< XAccessible > xResult; + + MutexGuard aGuard( m_aMutex); + if( ! m_bMayHaveChildren || + i < 0 || + o3tl::make_unsigned( i ) >= m_aChildList.size() ) + { + OUString aBuf = "Index " + OUString::number( i ) + " is invalid for range [ 0, " + + OUString::number( m_aChildList.size() - 1 ) + + " ]"; + lang::IndexOutOfBoundsException aEx( aBuf, + const_cast< ::cppu::OWeakObject * >( + static_cast< const ::cppu::OWeakObject * >( this ))); + throw aEx; + } + else + xResult.set( m_aChildList[ i ] ); + + return xResult; +} + +Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleParent() +{ + CheckDisposeState(); + Reference< XAccessible > aResult; + if( m_aAccInfo.m_pParent ) + aResult.set( m_aAccInfo.m_pParent ); + + return aResult; +} + +sal_Int32 SAL_CALL AccessibleBase::getAccessibleIndexInParent() +{ + CheckDisposeState(); + + if( m_aAccInfo.m_spObjectHierarchy ) + return m_aAccInfo.m_spObjectHierarchy->getIndexInParent( GetId() ); + return -1; +} + +sal_Int16 SAL_CALL AccessibleBase::getAccessibleRole() +{ + return AccessibleRole::SHAPE; +} + +Reference< XAccessibleRelationSet > SAL_CALL AccessibleBase::getAccessibleRelationSet() +{ + Reference< XAccessibleRelationSet > aResult; + return aResult; +} + +Reference< XAccessibleStateSet > SAL_CALL AccessibleBase::getAccessibleStateSet() +{ + if( ! m_bStateSetInitialized ) + { + Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier ); + if ( xSelSupp.is() ) + { + ObjectIdentifier aOID( xSelSupp->getSelection() ); + if ( aOID.isValid() && GetId() == aOID ) + { + AddState( AccessibleStateType::SELECTED ); + AddState( AccessibleStateType::FOCUSED ); + } + } + m_bStateSetInitialized = true; + } + + return m_xStateSetHelper; +} + +lang::Locale SAL_CALL AccessibleBase::getLocale() +{ + CheckDisposeState(); + + return Application::GetSettings().GetLanguageTag().getLocale(); +} + +// ________ AccessibleBase::XAccessibleComponent ________ +sal_Bool SAL_CALL AccessibleBase::containsPoint( const awt::Point& aPoint ) +{ + awt::Rectangle aRect( getBounds() ); + + // contains() works with relative coordinates + aRect.X = 0; + aRect.Y = 0; + + return ( aPoint.X >= aRect.X && + aPoint.Y >= aRect.Y && + aPoint.X < (aRect.X + aRect.Width) && + aPoint.Y < (aRect.Y + aRect.Height) ); +} + +Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleAtPoint( const awt::Point& aPoint ) +{ + CheckDisposeState(); + Reference< XAccessible > aResult; + awt::Rectangle aRect( getBounds()); + + // children are positioned relative to this object, so translate bound rect + aRect.X = 0; + aRect.Y = 0; + + // children must be inside the own bound rect + if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) && + ( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height))) + { + ClearableMutexGuard aGuard( m_aMutex ); + ChildListVectorType aLocalChildList( m_aChildList ); + aGuard.clear(); + + Reference< XAccessibleComponent > aComp; + for (auto const& localChild : aLocalChildList) + { + aComp.set(localChild, UNO_QUERY); + if( aComp.is()) + { + aRect = aComp->getBounds(); + if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) && + ( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height))) + { + aResult = localChild; + break; + } + } + } + } + + return aResult; +} + +awt::Rectangle SAL_CALL AccessibleBase::getBounds() +{ + ExplicitValueProvider *pExplicitValueProvider( + comphelper::getFromUnoTunnel<ExplicitValueProvider>( m_aAccInfo.m_xView )); + if( pExplicitValueProvider ) + { + VclPtr<vcl::Window> pWindow( VCLUnoHelper::GetWindow( m_aAccInfo.m_xWindow )); + awt::Rectangle aLogicRect( pExplicitValueProvider->getRectangleOfObject( m_aAccInfo.m_aOID.getObjectCID() )); + if( pWindow ) + { + tools::Rectangle aRect( aLogicRect.X, aLogicRect.Y, + aLogicRect.X + aLogicRect.Width, + aLogicRect.Y + aLogicRect.Height ); + SolarMutexGuard aSolarGuard; + aRect = pWindow->LogicToPixel( aRect ); + + // aLogicRect is relative to the page, but we need a value relative + // to the parent object + awt::Point aParentLocOnScreen; + uno::Reference< XAccessibleComponent > xParent( getAccessibleParent(), uno::UNO_QUERY ); + if( xParent.is() ) + aParentLocOnScreen = xParent->getLocationOnScreen(); + + awt::Point aULOnScreen = GetUpperLeftOnScreen(); + awt::Point aOffset( aParentLocOnScreen.X - aULOnScreen.X, + aParentLocOnScreen.Y - aULOnScreen.Y ); + + return awt::Rectangle( aRect.Left() - aOffset.X, aRect.Top() - aOffset.Y, + aRect.getWidth(), aRect.getHeight()); + } + } + + return awt::Rectangle(); +} + +awt::Point SAL_CALL AccessibleBase::getLocation() +{ + CheckDisposeState(); + awt::Rectangle aBBox( getBounds() ); + return awt::Point( aBBox.X, aBBox.Y ); +} + +awt::Point SAL_CALL AccessibleBase::getLocationOnScreen() +{ + CheckDisposeState(); + + if (AccessibleBase* pParent = m_aAccInfo.m_pParent) + { + awt::Point aLocThisRel( getLocation()); + awt::Point aUpperLeft(pParent->getLocationOnScreen()); + + return awt::Point( aUpperLeft.X + aLocThisRel.X, + aUpperLeft.Y + aLocThisRel.Y ); + } + else + return getLocation(); +} + +awt::Size SAL_CALL AccessibleBase::getSize() +{ + CheckDisposeState(); + awt::Rectangle aBBox( getBounds() ); + return awt::Size( aBBox.Width, aBBox.Height ); +} + +void SAL_CALL AccessibleBase::grabFocus() +{ + CheckDisposeState(); + + Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier ); + if ( xSelSupp.is() ) + { + xSelSupp->select( GetId().getAny() ); + } +} + +sal_Int32 SAL_CALL AccessibleBase::getForeground() +{ + return sal_Int32(getColor( ACC_BASE_FOREGROUND )); +} + +sal_Int32 SAL_CALL AccessibleBase::getBackground() +{ + return sal_Int32(getColor( ACC_BASE_BACKGROUND )); +} + +Color AccessibleBase::getColor( eColorType eColType ) +{ + Color nResult = COL_TRANSPARENT; + if( m_bAlwaysTransparent ) + return nResult; + + ObjectIdentifier aOID( m_aAccInfo.m_aOID ); + ObjectType eType( aOID.getObjectType() ); + Reference< beans::XPropertySet > xObjProp; + OUString aObjectCID = aOID.getObjectCID(); + if( eType == OBJECTTYPE_LEGEND_ENTRY ) + { + // for colors get the data series/point properties + std::u16string_view aParentParticle( ObjectIdentifier::getFullParentParticle( aObjectCID )); + aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle ); + } + + xObjProp = + ObjectIdentifier::getObjectPropertySet( + aObjectCID, m_aAccInfo.m_xChartDocument ); + if( xObjProp.is()) + { + try + { + OUString aPropName; + OUString aStylePropName; + + switch( eType ) + { + case OBJECTTYPE_LEGEND_ENTRY: + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_DATA_POINT: + if( eColType == ACC_BASE_FOREGROUND ) + { + aPropName = "BorderColor"; + aStylePropName = "BorderTransparency"; + } + else + { + aPropName = "Color"; + aStylePropName = "Transparency"; + } + break; + default: + if( eColType == ACC_BASE_FOREGROUND ) + { + aPropName = "LineColor"; + aStylePropName = "LineTransparence"; + } + else + { + aPropName = "FillColor"; + aStylePropName = "FillTransparence"; + } + break; + } + + bool bTransparent = m_bAlwaysTransparent; + Reference< beans::XPropertySetInfo > xInfo = xObjProp->getPropertySetInfo(); + if( xInfo.is() && + xInfo->hasPropertyByName( aStylePropName )) + { + if( eColType == ACC_BASE_FOREGROUND ) + { + drawing::LineStyle aLStyle; + if( xObjProp->getPropertyValue( aStylePropName ) >>= aLStyle ) + bTransparent = (aLStyle == drawing::LineStyle_NONE); + } + else + { + drawing::FillStyle aFStyle; + if( xObjProp->getPropertyValue( aStylePropName ) >>= aFStyle ) + bTransparent = (aFStyle == drawing::FillStyle_NONE); + } + } + + if( !bTransparent && + xInfo.is() && + xInfo->hasPropertyByName( aPropName )) + { + xObjProp->getPropertyValue( aPropName ) >>= nResult; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return nResult; +} + +// ________ AccessibleBase::XServiceInfo ________ +OUString SAL_CALL AccessibleBase::getImplementationName() +{ + return "AccessibleBase"; +} + +sal_Bool SAL_CALL AccessibleBase::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +uno::Sequence< OUString > SAL_CALL AccessibleBase::getSupportedServiceNames() +{ + return { + "com.sun.star.accessibility.Accessible", + "com.sun.star.accessibility.AccessibleContext" + }; +} + +// ________ AccessibleBase::XEventListener ________ +void SAL_CALL AccessibleBase::disposing( const lang::EventObject& /*Source*/ ) +{ +} + +// ________ XAccessibleEventBroadcasters ________ +void SAL_CALL AccessibleBase::addAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener ) +{ + MutexGuard aGuard( m_aMutex ); + + if ( xListener.is() ) + { + if ( !m_nEventNotifierId ) + m_nEventNotifierId = ::comphelper::AccessibleEventNotifier::registerClient(); + + ::comphelper::AccessibleEventNotifier::addEventListener( m_nEventNotifierId, xListener ); + } +} + +void SAL_CALL AccessibleBase::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener ) +{ + MutexGuard aGuard( m_aMutex ); + + if ( xListener.is() && m_nEventNotifierId) + { + sal_Int32 nListenerCount = ::comphelper::AccessibleEventNotifier::removeEventListener( m_nEventNotifierId, xListener ); + if ( !nListenerCount ) + { + // no listeners anymore + ::comphelper::AccessibleEventNotifier::revokeClient( m_nEventNotifierId ); + m_nEventNotifierId = 0; + } + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartElement.cxx b/chart2/source/controller/accessibility/AccessibleChartElement.cxx new file mode 100644 index 000000000..d89a5d027 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartElement.cxx @@ -0,0 +1,243 @@ +/* -*- 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 "AccessibleChartElement.hxx" +#include <CharacterProperties.hxx> +#include <ChartModel.hxx> +#include <ObjectIdentifier.hxx> +#include <ObjectNameProvider.hxx> +#include <servicenames.hxx> + +#include <com/sun/star/awt/XDevice.hpp> +#include <com/sun/star/chart2/XTitle.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> + +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +AccessibleChartElement::AccessibleChartElement( + const AccessibleElementInfo & rAccInfo, + bool bMayHaveChildren ) : + impl::AccessibleChartElement_Base( rAccInfo, bMayHaveChildren, false/*bAlwaysTransparent*/ ), + m_bHasText( false ) +{ + AddState( AccessibleStateType::TRANSIENT ); +} + +AccessibleChartElement::~AccessibleChartElement() +{ + OSL_ASSERT( CheckDisposeState( false /* don't throw exceptions */ ) ); +} + +// ________ protected ________ + +bool AccessibleChartElement::ImplUpdateChildren() +{ + bool bResult = false; + Reference< chart2::XTitle > xTitle( + ObjectIdentifier::getObjectPropertySet( + GetInfo().m_aOID.getObjectCID(), GetInfo().m_xChartDocument ), + uno::UNO_QUERY ); + m_bHasText = xTitle.is(); + + if( m_bHasText ) + { + InitTextEdit(); + bResult = true; + } + else + bResult = AccessibleBase::ImplUpdateChildren(); + + return bResult; +} + +void AccessibleChartElement::InitTextEdit() +{ + if( ! m_xTextHelper.is()) + { + // get hard reference + Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier ); + // get factory from selection supplier (controller) + Reference< lang::XMultiServiceFactory > xFact( xSelSupp, uno::UNO_QUERY ); + if( xFact.is()) + { + m_xTextHelper.set( + xFact->createInstance( CHART_ACCESSIBLE_TEXT_SERVICE_NAME ), uno::UNO_QUERY ); + } + } + + if( !m_xTextHelper.is()) + return; + + try + { + Reference< lang::XInitialization > xInit( m_xTextHelper, uno::UNO_QUERY_THROW ); + Sequence< uno::Any > aArgs{ uno::Any(GetInfo().m_aOID.getObjectCID()), + uno::Any(Reference< XAccessible >( this )), + uno::Any(Reference< awt::XWindow >( GetInfo().m_xWindow )) }; + xInit->initialize( aArgs ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// Interfaces + +// ________ AccessibleBase::XAccessibleContext ________ +Reference< XAccessible > AccessibleChartElement::ImplGetAccessibleChildById( sal_Int32 i ) const +{ + Reference< XAccessible > xResult; + + if( m_bHasText ) + xResult.set( m_xTextHelper->getAccessibleChild( i )); + else + xResult.set( AccessibleBase::ImplGetAccessibleChildById( i )); + + return xResult; +} + +sal_Int32 AccessibleChartElement::ImplGetAccessibleChildCount() const +{ + if( m_bHasText ) + { + if( m_xTextHelper.is()) + return m_xTextHelper->getAccessibleChildCount(); + return 0; + } + + return AccessibleBase::ImplGetAccessibleChildCount(); +} + +// ________ XServiceInfo ________ +OUString SAL_CALL AccessibleChartElement::getImplementationName() +{ + return "AccessibleChartElement"; +} + +// ________ AccessibleChartElement::XAccessibleContext (override) ________ +OUString SAL_CALL AccessibleChartElement::getAccessibleName() +{ + return ObjectNameProvider::getNameForCID( + GetInfo().m_aOID.getObjectCID(), GetInfo().m_xChartDocument ); +} + +// ________ AccessibleChartElement::XAccessibleContext (override) ________ +OUString SAL_CALL AccessibleChartElement::getAccessibleDescription() +{ + return getToolTipText(); +} + +// ________ AccessibleChartElement::XAccessibleExtendedComponent ________ +Reference< awt::XFont > SAL_CALL AccessibleChartElement::getFont() +{ + CheckDisposeState(); + + Reference< awt::XFont > xFont; + Reference< awt::XDevice > xDevice( Reference< awt::XWindow >( GetInfo().m_xWindow ), uno::UNO_QUERY ); + + if( xDevice.is()) + { + Reference< beans::XMultiPropertySet > xObjProp( + ObjectIdentifier::getObjectPropertySet( + GetInfo().m_aOID.getObjectCID(), GetInfo().m_xChartDocument ), uno::UNO_QUERY ); + awt::FontDescriptor aDescr( + CharacterProperties::createFontDescriptorFromPropertySet( xObjProp )); + xFont = xDevice->getFont( aDescr ); + } + + return xFont; +} + +OUString SAL_CALL AccessibleChartElement::getTitledBorderText() +{ + return OUString(); +} + +OUString SAL_CALL AccessibleChartElement::getToolTipText() +{ + CheckDisposeState(); + + return ObjectNameProvider::getHelpText( + GetInfo().m_aOID.getObjectCID(), GetInfo().m_xChartDocument ); +} + +// ________ XAccessibleComponent ________ +sal_Bool SAL_CALL AccessibleChartElement::containsPoint( const awt::Point& aPoint ) +{ + return AccessibleBase::containsPoint( aPoint ); +} + +Reference< XAccessible > SAL_CALL AccessibleChartElement::getAccessibleAtPoint( const awt::Point& aPoint ) +{ + return AccessibleBase::getAccessibleAtPoint( aPoint ); +} + +awt::Rectangle SAL_CALL AccessibleChartElement::getBounds() +{ + return AccessibleBase::getBounds(); +} + +awt::Point SAL_CALL AccessibleChartElement::getLocation() +{ + return AccessibleBase::getLocation(); +} + +awt::Point SAL_CALL AccessibleChartElement::getLocationOnScreen() +{ + return AccessibleBase::getLocationOnScreen(); +} + +awt::Size SAL_CALL AccessibleChartElement::getSize() +{ + return AccessibleBase::getSize(); +} + +void SAL_CALL AccessibleChartElement::grabFocus() +{ + return AccessibleBase::grabFocus(); +} + +sal_Int32 SAL_CALL AccessibleChartElement::getForeground() +{ + return AccessibleBase::getForeground(); +} + +sal_Int32 SAL_CALL AccessibleChartElement::getBackground() +{ + return AccessibleBase::getBackground(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartElement.hxx b/chart2/source/controller/accessibility/AccessibleChartElement.hxx new file mode 100644 index 000000000..12982db8f --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartElement.hxx @@ -0,0 +1,104 @@ +/* -*- 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 <AccessibleBase.hxx> +#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp> + +namespace com::sun::star::accessibility { class XAccessible; } +namespace com::sun::star::accessibility { class XAccessibleContext; } +namespace com::sun::star::awt { class XFont; } + +namespace chart +{ + +/** Base class for all Chart Accessibility objects except the root node (see AccessibleChartView) + + This class contains a reference to the ChartModel, thus, components can easily access all core functionality. + + Usage Instructions: + + <ul> + <li>define the getAccessibleName() method of XAccessibleContext</li> + <li>set the ChartModel using SetChartModel() for the first node before + creating any children</li> + <li>override UpdateChildren()</li> + </ul> + */ + +namespace impl +{ +typedef ::cppu::ImplInheritanceHelper< + AccessibleBase, + css::accessibility::XAccessibleExtendedComponent + > AccessibleChartElement_Base; +} + +class AccessibleChartElement : + public impl::AccessibleChartElement_Base +{ +public: + AccessibleChartElement( const AccessibleElementInfo & rAccInfo, + bool bMayHaveChildren ); + virtual ~AccessibleChartElement() override; + + // ________ AccessibleBase ________ + virtual bool ImplUpdateChildren() override; + virtual css::uno::Reference< css::accessibility::XAccessible > + ImplGetAccessibleChildById( sal_Int32 i ) const override; + virtual sal_Int32 ImplGetAccessibleChildCount() const override; + + // ________ XAccessibleContext ________ + virtual OUString SAL_CALL getAccessibleName() override; + virtual OUString SAL_CALL getAccessibleDescription() override; + + // ________ XAccessibleExtendedComponent ________ + virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override; + virtual OUString SAL_CALL getTitledBorderText() override; + virtual OUString SAL_CALL getToolTipText() override; + + // the following interface is implemented in AccessibleBase, however it is + // also a (non-virtual) base class of XAccessibleExtendedComponent Thus + // these methods have to be overridden and forward to AccessibleBase + + // ________ XAccessibleComponent ________ + virtual sal_Bool SAL_CALL containsPoint( const css::awt::Point& aPoint ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + virtual css::awt::Rectangle SAL_CALL getBounds() override; + virtual css::awt::Point SAL_CALL getLocation() override; + virtual css::awt::Point SAL_CALL getLocationOnScreen() override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL grabFocus() override; + virtual sal_Int32 SAL_CALL getForeground() override; + virtual sal_Int32 SAL_CALL getBackground() override; + + // ________ XServiceInfo ________ + virtual OUString SAL_CALL getImplementationName() override; + +private: + bool m_bHasText; + css::uno::Reference< css::accessibility::XAccessibleContext > + m_xTextHelper; + + void InitTextEdit(); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartShape.cxx b/chart2/source/controller/accessibility/AccessibleChartShape.cxx new file mode 100644 index 000000000..73ff2e9c0 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartShape.cxx @@ -0,0 +1,250 @@ +/* -*- 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 "AccessibleChartShape.hxx" + +#include <com/sun/star/awt/XWindow.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <svx/ShapeTypeHandler.hxx> +#include <svx/AccessibleShape.hxx> +#include <svx/AccessibleShapeInfo.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +AccessibleChartShape::AccessibleChartShape( + const AccessibleElementInfo& rAccInfo ) + :impl::AccessibleChartShape_Base( rAccInfo, true/*bMayHaveChildren*/, false/*bAlwaysTransparent*/ ) +{ + if ( !rAccInfo.m_aOID.isAdditionalShape() ) + return; + + Reference< drawing::XShape > xShape( rAccInfo.m_aOID.getAdditionalShape() ); + Reference< XAccessible > xParent; + if ( rAccInfo.m_pParent ) + { + xParent.set( rAccInfo.m_pParent ); + } + ::accessibility::AccessibleShapeInfo aShapeInfo( xShape, xParent ); + + m_aShapeTreeInfo.SetSdrView( rAccInfo.m_pSdrView ); + m_aShapeTreeInfo.SetController( nullptr ); + m_aShapeTreeInfo.SetWindow( VCLUnoHelper::GetWindow( rAccInfo.m_xWindow ) ); + m_aShapeTreeInfo.SetViewForwarder( rAccInfo.m_pViewForwarder ); + + ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance(); + m_pAccShape = rShapeHandler.CreateAccessibleObject( aShapeInfo, m_aShapeTreeInfo ); + if ( m_pAccShape.is() ) + { + m_pAccShape->Init(); + } +} + +AccessibleChartShape::~AccessibleChartShape() +{ + OSL_ASSERT( CheckDisposeState( false /* don't throw exceptions */ ) ); + + if ( m_pAccShape.is() ) + { + m_pAccShape->dispose(); + } +} + +// ________ XServiceInfo ________ +OUString AccessibleChartShape::getImplementationName() +{ + return "AccessibleChartShape"; +} + +// ________ XAccessibleContext ________ +sal_Int32 AccessibleChartShape::getAccessibleChildCount() +{ + sal_Int32 nCount(0); + if ( m_pAccShape.is() ) + { + nCount = m_pAccShape->getAccessibleChildCount(); + } + return nCount; +} + +Reference< XAccessible > AccessibleChartShape::getAccessibleChild( sal_Int32 i ) +{ + Reference< XAccessible > xChild; + if ( m_pAccShape.is() ) + { + xChild = m_pAccShape->getAccessibleChild( i ); + } + return xChild; +} + +sal_Int16 AccessibleChartShape::getAccessibleRole() +{ + sal_Int16 nRole(0); + if ( m_pAccShape.is() ) + { + nRole = m_pAccShape->getAccessibleRole(); + } + return nRole; +} + +OUString AccessibleChartShape::getAccessibleDescription() +{ + OUString aDescription; + if ( m_pAccShape.is() ) + { + aDescription = m_pAccShape->getAccessibleDescription(); + } + return aDescription; +} + +OUString AccessibleChartShape::getAccessibleName() +{ + OUString aName; + if ( m_pAccShape.is() ) + { + aName = m_pAccShape->getAccessibleName(); + } + return aName; +} + +// ________ XAccessibleComponent ________ +sal_Bool AccessibleChartShape::containsPoint( const awt::Point& aPoint ) +{ + bool bReturn = false; + if ( m_pAccShape.is() ) + { + bReturn = m_pAccShape->containsPoint( aPoint ); + } + return bReturn; +} + +Reference< XAccessible > AccessibleChartShape::getAccessibleAtPoint( const awt::Point& aPoint ) +{ + Reference< XAccessible > xResult; + if ( m_pAccShape.is() ) + { + xResult.set( m_pAccShape->getAccessibleAtPoint( aPoint ) ); + } + return xResult; +} + +awt::Rectangle AccessibleChartShape::getBounds() +{ + awt::Rectangle aBounds; + if ( m_pAccShape.is() ) + { + aBounds = m_pAccShape->getBounds(); + } + return aBounds; +} + +awt::Point AccessibleChartShape::getLocation() +{ + awt::Point aLocation; + if ( m_pAccShape.is() ) + { + aLocation = m_pAccShape->getLocation(); + } + return aLocation; +} + +awt::Point AccessibleChartShape::getLocationOnScreen() +{ + awt::Point aLocation; + if ( m_pAccShape.is() ) + { + aLocation = m_pAccShape->getLocationOnScreen(); + } + return aLocation; +} + +awt::Size AccessibleChartShape::getSize() +{ + awt::Size aSize; + if ( m_pAccShape.is() ) + { + aSize = m_pAccShape->getSize(); + } + return aSize; +} + +void AccessibleChartShape::grabFocus() +{ + return AccessibleBase::grabFocus(); +} + +sal_Int32 AccessibleChartShape::getForeground() +{ + sal_Int32 nColor(0); + if ( m_pAccShape.is() ) + { + nColor = m_pAccShape->getForeground(); + } + return nColor; +} + +sal_Int32 AccessibleChartShape::getBackground() +{ + sal_Int32 nColor(0); + if ( m_pAccShape.is() ) + { + nColor = m_pAccShape->getBackground(); + } + return nColor; +} + +// ________ XAccessibleExtendedComponent ________ +Reference< awt::XFont > AccessibleChartShape::getFont() +{ + Reference< awt::XFont > xFont; + if ( m_pAccShape.is() ) + { + xFont.set( m_pAccShape->getFont() ); + } + return xFont; +} + +OUString AccessibleChartShape::getTitledBorderText() +{ + OUString aText; + if ( m_pAccShape.is() ) + { + aText = m_pAccShape->getTitledBorderText(); + } + return aText; +} + +OUString AccessibleChartShape::getToolTipText() +{ + OUString aText; + if ( m_pAccShape.is() ) + { + aText = m_pAccShape->getToolTipText(); + } + return aText; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartShape.hxx b/chart2/source/controller/accessibility/AccessibleChartShape.hxx new file mode 100644 index 000000000..4377929fa --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartShape.hxx @@ -0,0 +1,83 @@ +/* -*- 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 <AccessibleBase.hxx> + +#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp> +#include <cppuhelper/implbase.hxx> +#include <svx/AccessibleShapeTreeInfo.hxx> + +namespace accessibility +{ +class AccessibleShape; +} + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::ImplInheritanceHelper< + AccessibleBase, + css::accessibility::XAccessibleExtendedComponent > AccessibleChartShape_Base; +} + +class AccessibleChartShape : + public impl::AccessibleChartShape_Base +{ +public: + explicit AccessibleChartShape( const AccessibleElementInfo& rAccInfo ); + virtual ~AccessibleChartShape() override; + + // ________ XServiceInfo ________ + virtual OUString SAL_CALL getImplementationName() override; + + // ________ XAccessibleContext ________ + virtual sal_Int32 SAL_CALL getAccessibleChildCount() override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL + getAccessibleChild( sal_Int32 i ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole() override; + virtual OUString SAL_CALL getAccessibleDescription() override; + virtual OUString SAL_CALL getAccessibleName() override; + + // ________ XAccessibleComponent ________ + virtual sal_Bool SAL_CALL containsPoint( const css::awt::Point& aPoint ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + virtual css::awt::Rectangle SAL_CALL getBounds() override; + virtual css::awt::Point SAL_CALL getLocation() override; + virtual css::awt::Point SAL_CALL getLocationOnScreen() override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL grabFocus() override; + virtual sal_Int32 SAL_CALL getForeground() override; + virtual sal_Int32 SAL_CALL getBackground() override; + + // ________ XAccessibleExtendedComponent ________ + virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override; + virtual OUString SAL_CALL getTitledBorderText() override; + virtual OUString SAL_CALL getToolTipText() override; + +private: + rtl::Reference<accessibility::AccessibleShape> m_pAccShape; + ::accessibility::AccessibleShapeTreeInfo m_aShapeTreeInfo; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartView.cxx b/chart2/source/controller/accessibility/AccessibleChartView.cxx new file mode 100644 index 000000000..6f9dad562 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartView.cxx @@ -0,0 +1,358 @@ +/* -*- 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 <AccessibleChartView.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <ObjectHierarchy.hxx> +#include <ObjectIdentifier.hxx> +#include <ResId.hxx> +#include <strings.hrc> +#include "AccessibleViewForwarder.hxx" +#include <ChartModel.hxx> + +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> + +#include <comphelper/servicehelper.hxx> + +#include <rtl/ustring.hxx> +#include <vcl/window.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::WeakReference; +using ::com::sun::star::uno::Any; +using osl::MutexGuard; + +namespace chart +{ + +AccessibleChartView::AccessibleChartView(SdrView* pView ) : + impl::AccessibleChartView_Base( + AccessibleElementInfo(), // empty for now + true, // has children + true // always transparent + ), + m_pSdrView( pView ) +{ + AddState( AccessibleStateType::OPAQUE ); +} + +AccessibleChartView::~AccessibleChartView() +{ +} + +awt::Rectangle AccessibleChartView::GetWindowPosSize() const +{ + Reference< awt::XWindow > xWindow( GetInfo().m_xWindow ); + if( ! xWindow.is()) + return awt::Rectangle(); + + awt::Rectangle aBBox( xWindow->getPosSize() ); + + VclPtr<vcl::Window> pWindow( VCLUnoHelper::GetWindow( GetInfo().m_xWindow )); + if( pWindow ) + { + SolarMutexGuard aSolarGuard; + Point aVCLPoint( pWindow->OutputToAbsoluteScreenPixel( Point( 0, 0 ) )); + aBBox.X = aVCLPoint.getX(); + aBBox.Y = aVCLPoint.getY(); + } + + return aBBox; +} + +awt::Point AccessibleChartView::GetUpperLeftOnScreen() const +{ + awt::Point aParentPosition; + + awt::Rectangle aBBox( GetWindowPosSize() ); + aParentPosition.X = aBBox.X; + aParentPosition.Y = aBBox.Y; + + return aParentPosition; +} + +// ________ XAccessibleContext ________ +OUString SAL_CALL AccessibleChartView::getAccessibleName() +{ + return SchResId(STR_OBJECT_DIAGRAM); +} + +OUString SAL_CALL AccessibleChartView::getAccessibleDescription() +{ + return getAccessibleName(); +} + +Reference< XAccessible > SAL_CALL AccessibleChartView::getAccessibleParent() +{ + return Reference< XAccessible >( m_xParent ); +} + +sal_Int32 SAL_CALL AccessibleChartView::getAccessibleIndexInParent() +{ + // the document is always the only child of the window + return 0; +} + +sal_Int16 SAL_CALL AccessibleChartView::getAccessibleRole() +{ + return AccessibleRole::DOCUMENT; +} + +// ________ XAccessibleComponent ________ +awt::Rectangle SAL_CALL AccessibleChartView::getBounds() +{ + awt::Rectangle aResult( GetWindowPosSize()); + Reference< XAccessible > xParent( m_xParent ); + if( xParent.is()) + { + Reference< XAccessibleComponent > xContext( xParent->getAccessibleContext(), uno::UNO_QUERY ); + if( xContext.is()) + { + awt::Point aParentPosition = xContext->getLocationOnScreen(); + aResult.X -= aParentPosition.X; + aResult.Y -= aParentPosition.Y; + } + } + return aResult; +} + +awt::Point SAL_CALL AccessibleChartView::getLocationOnScreen() +{ + awt::Rectangle aBounds( getBounds()); + awt::Point aResult; + Reference< XAccessible > xParent( m_xParent ); + if( xParent.is()) + { + Reference< XAccessibleComponent > xAccComp( + xParent->getAccessibleContext(), uno::UNO_QUERY ); + aResult = xAccComp->getLocationOnScreen(); + aResult.X += aBounds.X; + aResult.Y += aBounds.Y; + } + return aResult; +} + +// lang::XInitialization + +void SAL_CALL AccessibleChartView::initialize( const Sequence< Any >& rArguments ) +{ + //0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself + //1: frame::XModel representing the chart model - offers access to object data + //2: lang::XInterface representing the normal chart view - offers access to some extra object data + + //all arguments are only valid until next initialization + bool bChanged = false; + bool bOldInvalid = false; + bool bNewInvalid = false; + + Reference< view::XSelectionSupplier > xSelectionSupplier; + rtl::Reference<::chart::ChartModel> xChartModel; + Reference< uno::XInterface > xChartView; + Reference< XAccessible > xParent; + Reference< awt::XWindow > xWindow; + { + MutexGuard aGuard( m_aMutex); + xSelectionSupplier.set( m_xSelectionSupplier ); + xChartModel = m_xChartModel; + xChartView.set( m_xChartView ); + xParent.set( m_xParent ); + xWindow.set( m_xWindow ); + } + + if( !xSelectionSupplier.is() || !xChartModel.is() || !xChartView.is() ) + { + bOldInvalid = true; + } + + if( rArguments.getLength() > 1 ) + { + Reference< frame::XModel > xNewChartModel; + rArguments[1] >>= xNewChartModel; + assert(!xNewChartModel || dynamic_cast<::chart::ChartModel*>(xNewChartModel.get())); + ::chart::ChartModel* pNewChartModel = dynamic_cast<::chart::ChartModel*>(xNewChartModel.get()); + if( pNewChartModel != xChartModel.get() ) + { + xChartModel = pNewChartModel; + bChanged = true; + } + } + else if( xChartModel.is() ) + { + bChanged = true; + xChartModel = nullptr; + } + + if( rArguments.getLength() > 2 ) + { + Reference< uno::XInterface > xNewChartView; + rArguments[2] >>= xNewChartView; + if( xNewChartView != xChartView ) + { + xChartView = xNewChartView; + bChanged = true; + } + } + else if( xChartView.is() ) + { + bChanged = true; + xChartView = nullptr; + } + + if( rArguments.getLength() > 3 ) + { + Reference< XAccessible > xNewParent; + rArguments[3] >>= xNewParent; + if( xNewParent != xParent ) + { + xParent = xNewParent; + bChanged = true; + } + } + + if( rArguments.getLength() > 4 ) + { + Reference< awt::XWindow > xNewWindow; + rArguments[4] >>= xNewWindow; + if( xNewWindow != xWindow ) + { + xWindow.set( xNewWindow ); + bChanged = true; + } + } + + if( rArguments.hasElements() && xChartModel.is() && xChartView.is() ) + { + Reference< view::XSelectionSupplier > xNewSelectionSupplier; + rArguments[0] >>= xNewSelectionSupplier; + if(xSelectionSupplier!=xNewSelectionSupplier) + { + bChanged = true; + if(xSelectionSupplier.is()) + xSelectionSupplier->removeSelectionChangeListener(this); + if(xNewSelectionSupplier.is()) + xNewSelectionSupplier->addSelectionChangeListener(this); + xSelectionSupplier = xNewSelectionSupplier; + } + } + else if( xSelectionSupplier.is() ) + { + bChanged = true; + xSelectionSupplier->removeSelectionChangeListener(this); + xSelectionSupplier = nullptr; + } + + if( !xSelectionSupplier.is() || !xChartModel.is() || !xChartView.is() ) + { + if(xSelectionSupplier.is()) + xSelectionSupplier->removeSelectionChangeListener(this); + xSelectionSupplier = nullptr; + xChartModel.clear(); + xChartView.clear(); + xParent.clear(); + xWindow.clear(); + + bNewInvalid = true; + } + + { + MutexGuard aGuard( m_aMutex); + m_xSelectionSupplier = WeakReference< view::XSelectionSupplier >(xSelectionSupplier); + m_xChartModel = xChartModel.get(); + m_xChartView = WeakReference< uno::XInterface >(xChartView); + m_xParent = WeakReference< XAccessible >(xParent); + m_xWindow = WeakReference< awt::XWindow >(xWindow); + } + + if( bOldInvalid && bNewInvalid ) + bChanged = false; + + if( !bChanged ) + return; + + { + //before notification we prepare for creation of new context + //the old context will be deleted after notification than + MutexGuard aGuard( m_aMutex); + if( xChartModel.is()) + m_spObjectHierarchy = + std::make_shared<ObjectHierarchy>( xChartModel, comphelper::getFromUnoTunnel<ExplicitValueProvider>(m_xChartView) ); + else + m_spObjectHierarchy.reset(); + } + + { + AccessibleElementInfo aAccInfo; + aAccInfo.m_aOID = ObjectIdentifier("ROOT"); + aAccInfo.m_xChartDocument = m_xChartModel; + aAccInfo.m_xSelectionSupplier = m_xSelectionSupplier; + aAccInfo.m_xView = m_xChartView; + aAccInfo.m_xWindow = m_xWindow; + aAccInfo.m_pParent = nullptr; + aAccInfo.m_spObjectHierarchy = m_spObjectHierarchy; + aAccInfo.m_pSdrView = m_pSdrView; + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( m_xWindow ); + m_pViewForwarder.reset( new AccessibleViewForwarder( this, pWindow ) ); + aAccInfo.m_pViewForwarder = m_pViewForwarder.get(); + // broadcasts an INVALIDATE_ALL_CHILDREN event globally + SetInfo( aAccInfo ); + } +} + +// view::XSelectionChangeListener + +void SAL_CALL AccessibleChartView::selectionChanged( const lang::EventObject& /*rEvent*/ ) +{ + Reference< view::XSelectionSupplier > xSelectionSupplier; + { + MutexGuard aGuard( m_aMutex); + xSelectionSupplier.set(m_xSelectionSupplier); + } + + if( !xSelectionSupplier.is() ) + return; + + ObjectIdentifier aSelectedOID( xSelectionSupplier->getSelection() ); + if ( m_aCurrentSelectionOID.isValid() ) + { + NotifyEvent( EventType::LOST_SELECTION, m_aCurrentSelectionOID ); + } + if( aSelectedOID.isValid() ) + { + NotifyEvent( EventType::GOT_SELECTION, aSelectedOID ); + } + m_aCurrentSelectionOID = aSelectedOID; +} + +// XEventListener +void SAL_CALL AccessibleChartView::disposing( const lang::EventObject& /*Source*/ ) +{ +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleTextHelper.cxx b/chart2/source/controller/accessibility/AccessibleTextHelper.cxx new file mode 100644 index 000000000..2a58d9484 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleTextHelper.cxx @@ -0,0 +1,168 @@ +/* -*- 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 <sal/config.h> + +#include <memory> + +#include <AccessibleTextHelper.hxx> +#include <DrawViewWrapper.hxx> + +#include <vcl/svapp.hxx> + +#include <svx/AccessibleTextHelper.hxx> +#include <svx/unoshtxt.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/window.hxx> + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <osl/diagnose.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +AccessibleTextHelper::AccessibleTextHelper( + DrawViewWrapper * pDrawViewWrapper ) : + m_pDrawViewWrapper( pDrawViewWrapper ) +{} + +AccessibleTextHelper::~AccessibleTextHelper() +{ +} + +// ____ XInitialization ____ +void SAL_CALL AccessibleTextHelper::initialize( const Sequence< uno::Any >& aArguments ) +{ + OUString aCID; + Reference< XAccessible > xEventSource; + Reference< awt::XWindow > xWindow; + + if( aArguments.getLength() >= 3 ) + { + aArguments[0] >>= aCID; + aArguments[1] >>= xEventSource; + aArguments[2] >>= xWindow; + } + OSL_ENSURE( !aCID.isEmpty(), "Empty CID" ); + OSL_ENSURE( xEventSource.is(), "Empty Event Source" ); + OSL_ENSURE( xWindow.is(), "Empty Window" ); + if( !xEventSource.is() || aCID.isEmpty() ) + return; + + SolarMutexGuard aSolarGuard; + + m_pTextHelper.reset(); + + VclPtr<vcl::Window> pWindow( VCLUnoHelper::GetWindow( xWindow )); + if( pWindow ) + { + SdrView * pView = m_pDrawViewWrapper; + if( pView ) + { + SdrObject * pTextObj = m_pDrawViewWrapper->getNamedSdrObject( aCID ); + if( pTextObj ) + { + m_pTextHelper.reset( new ::accessibility::AccessibleTextHelper(std::make_unique<SvxTextEditSource>(*pTextObj, nullptr, *pView, *pWindow->GetOutDev())) ); + m_pTextHelper->SetEventSource( xEventSource ); + } + } + } + + OSL_ENSURE( m_pTextHelper, "Couldn't create text helper" ); +} + +// ____ XAccessibleContext ____ +::sal_Int32 SAL_CALL AccessibleTextHelper::getAccessibleChildCount() +{ + if( m_pTextHelper ) + { + SolarMutexGuard aSolarGuard; + return m_pTextHelper->GetChildCount(); + } + return 0; +} + +Reference< XAccessible > SAL_CALL AccessibleTextHelper::getAccessibleChild( ::sal_Int32 i ) +{ + if( m_pTextHelper ) + { + SolarMutexGuard aSolarGuard; + return m_pTextHelper->GetChild( i ); + } + return Reference< XAccessible >(); +} + +Reference< XAccessible > SAL_CALL AccessibleTextHelper::getAccessibleParent() +{ + OSL_FAIL( "Not implemented in this helper" ); + return Reference< XAccessible >(); +} + +::sal_Int32 SAL_CALL AccessibleTextHelper::getAccessibleIndexInParent() +{ + OSL_FAIL( "Not implemented in this helper" ); + return -1; +} + +::sal_Int16 SAL_CALL AccessibleTextHelper::getAccessibleRole() +{ + OSL_FAIL( "Not implemented in this helper" ); + return AccessibleRole::UNKNOWN; +} + +OUString SAL_CALL AccessibleTextHelper::getAccessibleDescription() +{ + OSL_FAIL( "Not implemented in this helper" ); + return OUString(); +} + +OUString SAL_CALL AccessibleTextHelper::getAccessibleName() +{ + OSL_FAIL( "Not implemented in this helper" ); + return OUString(); +} + +Reference< XAccessibleRelationSet > SAL_CALL AccessibleTextHelper::getAccessibleRelationSet() +{ + OSL_FAIL( "Not implemented in this helper" ); + return Reference< XAccessibleRelationSet >(); +} + +Reference< XAccessibleStateSet > SAL_CALL AccessibleTextHelper::getAccessibleStateSet() +{ + OSL_FAIL( "Not implemented in this helper" ); + return Reference< XAccessibleStateSet >(); +} + +lang::Locale SAL_CALL AccessibleTextHelper::getLocale() +{ + OSL_FAIL( "Not implemented in this helper" ); + return lang::Locale(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleViewForwarder.cxx b/chart2/source/controller/accessibility/AccessibleViewForwarder.cxx new file mode 100644 index 000000000..31395f118 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleViewForwarder.cxx @@ -0,0 +1,79 @@ +/* -*- 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 "AccessibleViewForwarder.hxx" +#include <AccessibleChartView.hxx> + +#include <vcl/window.hxx> + +using namespace ::com::sun::star; + +namespace chart +{ + +AccessibleViewForwarder::AccessibleViewForwarder( AccessibleChartView* pAccChartView, vcl::Window* pWindow ) + :m_pAccChartView( pAccChartView ) + ,m_pWindow( pWindow ) + ,m_aMapMode( MapUnit::Map100thMM ) +{ +} + +AccessibleViewForwarder::~AccessibleViewForwarder() +{ +} + +// ________ IAccessibleViewforwarder ________ + +tools::Rectangle AccessibleViewForwarder::GetVisibleArea() const +{ + tools::Rectangle aVisibleArea; + if ( m_pWindow ) + { + aVisibleArea.SetPos( Point( 0, 0 ) ); + aVisibleArea.SetSize( m_pWindow->GetOutputSizePixel() ); + aVisibleArea = m_pWindow->PixelToLogic( aVisibleArea, m_aMapMode ); + } + return aVisibleArea; +} + +Point AccessibleViewForwarder::LogicToPixel( const Point& rPoint ) const +{ + Point aPoint; + if ( m_pAccChartView && m_pWindow ) + { + awt::Point aLocation = m_pAccChartView->getLocationOnScreen(); + Point aTopLeft( aLocation.X, aLocation.Y ); + aPoint = m_pWindow->LogicToPixel( rPoint, m_aMapMode ) + aTopLeft; + } + return aPoint; +} + +Size AccessibleViewForwarder::LogicToPixel( const Size& rSize ) const +{ + Size aSize; + if ( m_pWindow ) + { + aSize = m_pWindow->LogicToPixel( rSize, m_aMapMode ); + } + return aSize; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleViewForwarder.hxx b/chart2/source/controller/accessibility/AccessibleViewForwarder.hxx new file mode 100644 index 000000000..5bfbd06ad --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleViewForwarder.hxx @@ -0,0 +1,56 @@ +/* -*- 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 <vcl/mapmod.hxx> +#include <vcl/vclptr.hxx> +#include <svx/IAccessibleViewForwarder.hxx> + +namespace vcl +{ +class Window; +} + +namespace chart +{ +class AccessibleChartView; + +class AccessibleViewForwarder : public ::accessibility::IAccessibleViewForwarder +{ +public: + AccessibleViewForwarder(AccessibleChartView* pAccChartView, vcl::Window* pWindow); + virtual ~AccessibleViewForwarder() override; + + // ________ IAccessibleViewforwarder ________ + virtual tools::Rectangle GetVisibleArea() const override; + virtual Point LogicToPixel(const Point& rPoint) const override; + virtual Size LogicToPixel(const Size& rSize) const override; + +private: + AccessibleViewForwarder(AccessibleViewForwarder const&) = delete; + AccessibleViewForwarder& operator=(AccessibleViewForwarder const&) = delete; + + AccessibleChartView* m_pAccChartView; + VclPtr<vcl::Window> m_pWindow; + MapMode m_aMapMode; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/ChartElementFactory.cxx b/chart2/source/controller/accessibility/ChartElementFactory.cxx new file mode 100644 index 000000000..a173ac0f4 --- /dev/null +++ b/chart2/source/controller/accessibility/ChartElementFactory.cxx @@ -0,0 +1,71 @@ +/* -*- 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 "ChartElementFactory.hxx" +#include <ObjectIdentifier.hxx> +#include "AccessibleChartElement.hxx" + +namespace chart +{ +rtl::Reference<AccessibleBase> +ChartElementFactory::CreateChartElement(const AccessibleElementInfo& rAccInfo) +{ + ObjectIdentifier aOID(rAccInfo.m_aOID); + ObjectType eType(aOID.getObjectType()); + + switch (eType) + { + case OBJECTTYPE_DATA_POINT: + case OBJECTTYPE_LEGEND_ENTRY: + return new AccessibleChartElement(rAccInfo, false); + case OBJECTTYPE_PAGE: + case OBJECTTYPE_TITLE: + case OBJECTTYPE_LEGEND: + case OBJECTTYPE_DIAGRAM: + case OBJECTTYPE_DIAGRAM_WALL: + case OBJECTTYPE_DIAGRAM_FLOOR: + case OBJECTTYPE_AXIS: + case OBJECTTYPE_AXIS_UNITLABEL: + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + case OBJECTTYPE_DATA_CURVE: // e.g. a statistical method printed as line + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_STOCK_RANGE: + case OBJECTTYPE_DATA_STOCK_LOSS: + case OBJECTTYPE_DATA_STOCK_GAIN: + case OBJECTTYPE_DATA_CURVE_EQUATION: + return new AccessibleChartElement(rAccInfo, true); + case OBJECTTYPE_UNKNOWN: + break; + default: + break; + } + + return nullptr; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/ChartElementFactory.hxx b/chart2/source/controller/accessibility/ChartElementFactory.hxx new file mode 100644 index 000000000..08ae64598 --- /dev/null +++ b/chart2/source/controller/accessibility/ChartElementFactory.hxx @@ -0,0 +1,39 @@ +/* -*- 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 <rtl/ref.hxx> + +namespace chart +{ +class AccessibleBase; +struct AccessibleElementInfo; + +class ChartElementFactory +{ +public: + /** @return a newly created object (using the new operator) that corresponds + to the given unique id + */ + static rtl::Reference<AccessibleBase> CreateChartElement(const AccessibleElementInfo& rAccInfo); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/AreaWrapper.cxx b/chart2/source/controller/chartapiwrapper/AreaWrapper.cxx new file mode 100644 index 000000000..10cd00e29 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/AreaWrapper.cxx @@ -0,0 +1,176 @@ +/* -*- 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 "AreaWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include <WrappedDirectStateProperty.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <UserDefinedProperties.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +struct StaticAreaWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + 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 ); + } +}; + +struct StaticAreaWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticAreaWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +AreaWrapper::AreaWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) +{ +} + +AreaWrapper::~AreaWrapper() +{} + +// ____ XShape ____ +awt::Point SAL_CALL AreaWrapper::getPosition() +{ + return awt::Point(0,0); +} + +void SAL_CALL AreaWrapper::setPosition( const awt::Point& /*aPosition*/ ) +{ + OSL_FAIL( "trying to set position of chart area" ); +} + +awt::Size SAL_CALL AreaWrapper::getSize() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +void SAL_CALL AreaWrapper::setSize( const awt::Size& /*aSize*/ ) +{ + OSL_FAIL( "trying to set size of chart area" ); +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL AreaWrapper::getShapeType() +{ + return "com.sun.star.chart.ChartArea"; +} + +// ____ XComponent ____ +void SAL_CALL AreaWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + MutexGuard aGuard( m_aMutex); + clearWrappedPropertySet(); +} + +void SAL_CALL AreaWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL AreaWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// WrappedPropertySet +Reference< beans::XPropertySet > AreaWrapper::getInnerPropertySet() +{ + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( xChartDoc.is() ) + return xChartDoc->getPageBackground(); + OSL_FAIL("AreaWrapper::getInnerPropertySet() is NULL"); + return nullptr; +} + +const Sequence< beans::Property >& AreaWrapper::getPropertySequence() +{ + return *StaticAreaWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > AreaWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("LineStyle","LineStyle") ); + + return aWrappedProperties; +} + +OUString SAL_CALL AreaWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Area"; +} + +sal_Bool SAL_CALL AreaWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL AreaWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.beans.PropertySet", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties" }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/AreaWrapper.hxx b/chart2/source/controller/chartapiwrapper/AreaWrapper.hxx new file mode 100644 index 000000000..3de57f421 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/AreaWrapper.hxx @@ -0,0 +1,80 @@ +/* -*- 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 <WrappedPropertySet.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <memory> + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class AreaWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::drawing::XShape + , css::lang::XComponent + , css::lang::XServiceInfo + > +{ +public: + explicit AreaWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~AreaWrapper() 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; + + // ____ XShape ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/AxisWrapper.cxx b/chart2/source/controller/chartapiwrapper/AxisWrapper.cxx new file mode 100644 index 000000000..02306d2c1 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/AxisWrapper.cxx @@ -0,0 +1,672 @@ +/* -*- 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 "AxisWrapper.hxx" +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <TitleHelper.hxx> +#include "Chart2ModelContact.hxx" +#include <WrappedDirectStateProperty.hxx> +#include "GridWrapper.hxx" +#include "TitleWrapper.hxx" +#include <DisposeHelper.hxx> +#include <unonames.hxx> + +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp> +#include <com/sun/star/chart/ChartAxisPosition.hpp> +#include <com/sun/star/chart/ChartAxisLabelPosition.hpp> +#include <com/sun/star/chart/ChartAxisMarkPosition.hpp> +#include <com/sun/star/chart2/XAxis.hpp> + +#include <CharacterProperties.hxx> +#include <LinePropertiesHelper.hxx> +#include <UserDefinedProperties.hxx> +#include "WrappedCharacterHeightProperty.hxx" +#include "WrappedTextRotationProperty.hxx" +#include "WrappedGapwidthProperty.hxx" +#include "WrappedScaleProperty.hxx" +#include "WrappedNumberFormatProperty.hxx" +#include "WrappedScaleTextProperties.hxx" + +#include <algorithm> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace +{ + +enum +{ + PROP_AXIS_MAX, + PROP_AXIS_MIN, + PROP_AXIS_STEPMAIN, + PROP_AXIS_STEPHELP, //deprecated property use 'StepHelpCount' instead + PROP_AXIS_STEPHELP_COUNT, + PROP_AXIS_AUTO_MAX, + PROP_AXIS_AUTO_MIN, + PROP_AXIS_AUTO_STEPMAIN, + PROP_AXIS_AUTO_STEPHELP, + PROP_AXIS_TYPE, + PROP_AXIS_TIME_INCREMENT, + PROP_AXIS_EXPLICIT_TIME_INCREMENT, + PROP_AXIS_LOGARITHMIC, + PROP_AXIS_REVERSEDIRECTION, + PROP_AXIS_VISIBLE, + PROP_AXIS_CROSSOVER_POSITION, + PROP_AXIS_CROSSOVER_VALUE, + PROP_AXIS_ORIGIN, + PROP_AXIS_AUTO_ORIGIN, + PROP_AXIS_MARKS, + PROP_AXIS_HELPMARKS, + PROP_AXIS_MARK_POSITION, + PROP_AXIS_DISPLAY_LABELS, + PROP_AXIS_NUMBERFORMAT, + PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, + PROP_AXIS_LABEL_POSITION, + PROP_AXIS_TEXT_ROTATION, + PROP_AXIS_ARRANGE_ORDER, + PROP_AXIS_TEXTBREAK, + PROP_AXIS_CAN_OVERLAP, + PROP_AXIS_STACKEDTEXT, + PROP_AXIS_OVERLAP, + PROP_AXIS_GAP_WIDTH, + PROP_AXIS_DISPLAY_UNITS, + PROP_AXIS_BUILTINUNIT, + PROP_AXIS_TRY_STAGGERING_FIRST, + PROP_AXIS_MAJOR_ORIGIN +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + //Properties for scaling: + rOutProperties.emplace_back( "Max", + PROP_AXIS_MAX, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "Min", + PROP_AXIS_MIN, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "StepMain", + PROP_AXIS_STEPMAIN, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "StepHelpCount", + PROP_AXIS_STEPHELP_COUNT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + //deprecated property use 'StepHelpCount' instead + rOutProperties.emplace_back( "StepHelp", + PROP_AXIS_STEPHELP, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "AutoMax", + PROP_AXIS_AUTO_MAX, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AutoMin", + PROP_AXIS_AUTO_MIN, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AutoStepMain", + PROP_AXIS_AUTO_STEPMAIN, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AutoStepHelp", + PROP_AXIS_AUTO_STEPHELP, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AxisType", + PROP_AXIS_TYPE, + cppu::UnoType<sal_Int32>::get(), //type css::chart::ChartAxisType + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TimeIncrement", + PROP_AXIS_TIME_INCREMENT, + cppu::UnoType<css::chart::TimeIncrement>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ExplicitTimeIncrement", + PROP_AXIS_EXPLICIT_TIME_INCREMENT, + cppu::UnoType<css::chart::TimeIncrement>::get(), + beans::PropertyAttribute::READONLY | + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "Logarithmic", + PROP_AXIS_LOGARITHMIC, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ReverseDirection", + PROP_AXIS_REVERSEDIRECTION, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + //todo: this property is missing in the API + rOutProperties.emplace_back( "Visible", + PROP_AXIS_VISIBLE, + 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( "Origin", + PROP_AXIS_ORIGIN, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "AutoOrigin", + PROP_AXIS_AUTO_ORIGIN, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for interval marks: + rOutProperties.emplace_back( "Marks", + PROP_AXIS_MARKS, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "HelpMarks", + PROP_AXIS_HELPMARKS, + 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 labels: + 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<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ArrangeOrder", + PROP_AXIS_ARRANGE_ORDER, + cppu::UnoType<css::chart::ChartAxisArrangeOrderType>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextBreak", + PROP_AXIS_TEXTBREAK, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextCanOverlap", + PROP_AXIS_CAN_OVERLAP, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "StackedText", + PROP_AXIS_STACKEDTEXT, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // Properties related to bar charts: + rOutProperties.emplace_back( "Overlap", + PROP_AXIS_OVERLAP, + cppu::UnoType<sal_Int32>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "GapWidth", + PROP_AXIS_GAP_WIDTH, + cppu::UnoType<sal_Int32>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + 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 ); +} + +struct StaticAxisWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::wrapper::WrappedScaleTextProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticAxisWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticAxisWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +AxisWrapper::AxisWrapper( + tAxisType eType, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) : + m_spChart2ModelContact( spChart2ModelContact ), + m_aEventListenerContainer( m_aMutex ), + m_eType( eType ) +{ +} + +AxisWrapper::~AxisWrapper() +{ +} + +// ____ chart::XAxis ____ +Reference< beans::XPropertySet > SAL_CALL AxisWrapper::getAxisTitle() +{ + if( !m_xAxisTitle.is() ) + { + TitleHelper::eTitleType eTitleType( TitleHelper::X_AXIS_TITLE ); + switch( m_eType ) + { + case X_AXIS: + eTitleType = TitleHelper::X_AXIS_TITLE; + break; + case Y_AXIS: + eTitleType = TitleHelper::Y_AXIS_TITLE; + break; + case Z_AXIS: + eTitleType = TitleHelper::Z_AXIS_TITLE; + break; + case SECOND_X_AXIS: + eTitleType = TitleHelper::SECONDARY_X_AXIS_TITLE; + break; + case SECOND_Y_AXIS: + eTitleType = TitleHelper::SECONDARY_Y_AXIS_TITLE; + break; + default: + return nullptr; + } + m_xAxisTitle = new TitleWrapper( eTitleType, m_spChart2ModelContact ); + } + return m_xAxisTitle; +} +Reference< beans::XPropertySet > SAL_CALL AxisWrapper::getMajorGrid() +{ + if( !m_xMajorGrid.is() ) + { + GridWrapper::tGridType eGridType( GridWrapper::X_MAJOR_GRID ); + switch( m_eType ) + { + case X_AXIS: + eGridType = GridWrapper::X_MAJOR_GRID; + break; + case Y_AXIS: + eGridType = GridWrapper::Y_MAJOR_GRID; + break; + case Z_AXIS: + eGridType = GridWrapper::Z_MAJOR_GRID; + break; + default: + return nullptr; + } + m_xMajorGrid = new GridWrapper( eGridType, m_spChart2ModelContact ); + } + return m_xMajorGrid; +} +Reference< beans::XPropertySet > SAL_CALL AxisWrapper::getMinorGrid() +{ + if( !m_xMinorGrid.is() ) + { + GridWrapper::tGridType eGridType( GridWrapper::X_MAJOR_GRID ); + switch( m_eType ) + { + case X_AXIS: + eGridType = GridWrapper::X_MINOR_GRID; + break; + case Y_AXIS: + eGridType = GridWrapper::Y_MINOR_GRID; + break; + case Z_AXIS: + eGridType = GridWrapper::Z_MINOR_GRID; + break; + default: + return nullptr; + } + m_xMinorGrid = new GridWrapper( eGridType, m_spChart2ModelContact ); + } + return m_xMinorGrid; +} + +// ____ XShape ____ +awt::Point SAL_CALL AxisWrapper::getPosition() +{ + awt::Point aResult( m_spChart2ModelContact->GetAxisPosition( getAxis() ) ); + return aResult; +} + +void SAL_CALL AxisWrapper::setPosition( const awt::Point& /*aPosition*/ ) +{ + OSL_FAIL( "trying to set position of Axis" ); +} + +awt::Size SAL_CALL AxisWrapper::getSize() +{ + awt::Size aSize( m_spChart2ModelContact->GetAxisSize( getAxis() ) ); + return aSize; +} + +void SAL_CALL AxisWrapper::setSize( const awt::Size& /*aSize*/ ) +{ + OSL_FAIL( "trying to set size of Axis" ); +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL AxisWrapper::getShapeType() +{ + return "com.sun.star.chart.ChartAxis"; +} + +// ____ XNumberFormatsSupplier ____ +uno::Reference< beans::XPropertySet > SAL_CALL AxisWrapper::getNumberFormatSettings() +{ + rtl::Reference<ChartModel> xChartModel( m_spChart2ModelContact->getDocumentModel() ); + if( xChartModel ) + return xChartModel->getNumberFormatSettings(); + + return uno::Reference< beans::XPropertySet >(); +} + +uno::Reference< util::XNumberFormats > SAL_CALL AxisWrapper::getNumberFormats() +{ + rtl::Reference<ChartModel> xChartModel( m_spChart2ModelContact->getDocumentModel() ); + if( xChartModel ) + return xChartModel->getNumberFormats(); + + return uno::Reference< util::XNumberFormats >(); +} + +void AxisWrapper::getDimensionAndMainAxisBool( tAxisType eType, sal_Int32& rnDimensionIndex, bool& rbMainAxis ) +{ + switch( eType ) + { + case X_AXIS: + rnDimensionIndex = 0; rbMainAxis = true; break; + case Y_AXIS: + rnDimensionIndex = 1; rbMainAxis = true; break; + case Z_AXIS: + rnDimensionIndex = 2; rbMainAxis = true; break; + case SECOND_X_AXIS: + rnDimensionIndex = 0; rbMainAxis = false; break; + case SECOND_Y_AXIS: + rnDimensionIndex = 1; rbMainAxis = false; break; + } +} + +// ____ XComponent ____ +void SAL_CALL AxisWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + DisposeHelper::DisposeAndClear( m_xAxisTitle ); + DisposeHelper::DisposeAndClear( m_xMajorGrid ); + DisposeHelper::DisposeAndClear( m_xMinorGrid ); + + clearWrappedPropertySet(); +} + +void SAL_CALL AxisWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL AxisWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +//ReferenceSizePropertyProvider +void AxisWrapper::updateReferenceSize() +{ + Reference< beans::XPropertySet > xProp( getAxis(), uno::UNO_QUERY ); + if( xProp.is() ) + { + if( xProp->getPropertyValue("ReferencePageSize").hasValue() ) + xProp->setPropertyValue("ReferencePageSize", uno::Any( + m_spChart2ModelContact->GetPageSize() )); + } +} +Any AxisWrapper::getReferenceSize() +{ + Any aRet; + Reference< beans::XPropertySet > xProp( getAxis(), uno::UNO_QUERY ); + if( xProp.is() ) + aRet = xProp->getPropertyValue("ReferencePageSize"); + return aRet; +} +awt::Size AxisWrapper::getCurrentSizeForReference() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +Reference< chart2::XAxis > AxisWrapper::getAxis() +{ + rtl::Reference< Axis > xAxis; + try + { + sal_Int32 nDimensionIndex = 0; + bool bMainAxis = true; + AxisWrapper::getDimensionAndMainAxisBool( m_eType, nDimensionIndex, bMainAxis ); + + rtl::Reference< Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ); + if( !xAxis.is() ) + { + xAxis = AxisHelper::createAxis( nDimensionIndex, bMainAxis, xDiagram, m_spChart2ModelContact->m_xContext ); + if( xAxis.is() ) + xAxis->setPropertyValue("Show", uno::Any( false ) ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xAxis; +} + +// WrappedPropertySet +Reference< beans::XPropertySet > AxisWrapper::getInnerPropertySet() +{ + return Reference< beans::XPropertySet >( getAxis(), uno::UNO_QUERY ); +} + +const Sequence< beans::Property >& AxisWrapper::getPropertySequence() +{ + return *StaticAxisWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > AxisWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedTextRotationProperty() ); + aWrappedProperties.emplace_back( new WrappedProperty("Marks","MajorTickmarks") ); + aWrappedProperties.emplace_back( new WrappedProperty("HelpMarks","MinorTickmarks") ); + aWrappedProperties.emplace_back( new WrappedProperty("TextCanOverlap","TextOverlap") ); + aWrappedProperties.emplace_back( new WrappedProperty("ArrangeOrder","ArrangeOrder") ); + aWrappedProperties.emplace_back( new WrappedProperty("Visible","Show") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("DisplayLabels","DisplayLabels") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("TryStaggeringFirst","TryStaggeringFirst") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("TextBreak","TextBreak") ); + aWrappedProperties.emplace_back( new WrappedNumberFormatProperty(m_spChart2ModelContact) ); + aWrappedProperties.emplace_back( new WrappedLinkNumberFormatProperty ); + aWrappedProperties.emplace_back( new WrappedProperty("StackedText","StackCharacters") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("CrossoverPosition","CrossoverPosition") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("MajorOrigin","MajorOrigin") ); + { + WrappedGapwidthProperty* pWrappedGapwidthProperty( new WrappedGapwidthProperty( m_spChart2ModelContact ) ); + WrappedBarOverlapProperty* pWrappedBarOverlapProperty( new WrappedBarOverlapProperty( m_spChart2ModelContact ) ); + sal_Int32 nDimensionIndex = 0; + bool bMainAxis = true; + sal_Int32 nAxisIndex = 0; + AxisWrapper::getDimensionAndMainAxisBool( m_eType, nDimensionIndex, bMainAxis ); + if( !bMainAxis ) + nAxisIndex = 1; + pWrappedGapwidthProperty->setDimensionAndAxisIndex( nDimensionIndex, nAxisIndex ); + pWrappedBarOverlapProperty->setDimensionAndAxisIndex( nDimensionIndex, nAxisIndex ); + aWrappedProperties.emplace_back( pWrappedGapwidthProperty ); + aWrappedProperties.emplace_back( pWrappedBarOverlapProperty ); + } + + WrappedScaleProperty::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); + WrappedScaleTextProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + return aWrappedProperties; +} + +OUString SAL_CALL AxisWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Axis"; +} + +sal_Bool SAL_CALL AxisWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL AxisWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartAxis", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.style.CharacterProperties" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/AxisWrapper.hxx b/chart2/source/controller/chartapiwrapper/AxisWrapper.hxx new file mode 100644 index 000000000..b421ab331 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/AxisWrapper.hxx @@ -0,0 +1,123 @@ +/* -*- 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 <WrappedPropertySet.hxx> +#include "ReferenceSizePropertyProvider.hxx" +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/chart/XAxis.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> + +#include <memory> + +namespace com::sun::star::chart2 { class XAxis; } + +namespace chart::wrapper +{ +class Chart2ModelContact; + +class AxisWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::chart::XAxis + , css::drawing::XShape + , css::lang::XComponent + , css::lang::XServiceInfo + , css::util::XNumberFormatsSupplier + > + , public ReferenceSizePropertyProvider +{ +public: + enum tAxisType + { + X_AXIS, + Y_AXIS, + Z_AXIS, + SECOND_X_AXIS, + SECOND_Y_AXIS + }; + + AxisWrapper(tAxisType eType, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~AxisWrapper() override; + + static void getDimensionAndMainAxisBool( tAxisType eType, sal_Int32& rnDimensionIndex, bool& rbMainAxis ); + + /// 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; + + //ReferenceSizePropertyProvider + virtual void updateReferenceSize() override; + virtual css::uno::Any getReferenceSize() override; + virtual css::awt::Size getCurrentSizeForReference() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + + // ____ chart::XAxis ____ + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getAxisTitle( ) override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getMajorGrid( ) override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getMinorGrid( ) override; + + // ____ XShape ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XNumberFormatsSupplier ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getNumberFormatSettings() override; + virtual css::uno::Reference< + css::util::XNumberFormats > SAL_CALL getNumberFormats() override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: //methods + css::uno::Reference< css::chart2::XAxis > getAxis(); + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; + + tAxisType m_eType; + + css::uno::Reference< css::beans::XPropertySet > m_xAxisTitle; + css::uno::Reference< css::beans::XPropertySet > m_xMajorGrid; + css::uno::Reference< css::beans::XPropertySet > m_xMinorGrid; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/Chart2ModelContact.cxx b/chart2/source/controller/chartapiwrapper/Chart2ModelContact.cxx new file mode 100644 index 000000000..e65d78915 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/Chart2ModelContact.cxx @@ -0,0 +1,302 @@ +/* -*- 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 "Chart2ModelContact.hxx" +#include <ChartModelHelper.hxx> +#include <Legend.hxx> +#include <LegendHelper.hxx> +#include <CommonConverters.hxx> +#include <servicenames.hxx> +#include <ObjectIdentifier.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <AxisHelper.hxx> +#include <ChartView.hxx> +#include <DiagramHelper.hxx> +#include <BaseCoordinateSystem.hxx> + +#include <ChartModel.hxx> + +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; + +namespace chart::wrapper +{ + +Chart2ModelContact::Chart2ModelContact( + const Reference< uno::XComponentContext > & xContext ) : + m_xContext( xContext ), + m_xChartModel( nullptr ) +{ +} + +Chart2ModelContact::~Chart2ModelContact() +{ + clear(); +} + +void Chart2ModelContact::setDocumentModel( ChartModel* pChartModel ) +{ + clear(); + m_xChartModel = pChartModel; + if( !pChartModel ) + return; + + uno::Reference< container::XNameContainer > xDashTable( pChartModel->createInstance("com.sun.star.drawing.DashTable"), uno::UNO_QUERY ); + uno::Reference< container::XNameContainer > xGradientTable( pChartModel->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY ); + uno::Reference< container::XNameContainer > xHatchTable( pChartModel->createInstance("com.sun.star.drawing.HatchTable"), uno::UNO_QUERY ); + uno::Reference< container::XNameContainer > xBitmapTable( pChartModel->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY ); + uno::Reference< container::XNameContainer > xTransparencyGradientTable( pChartModel->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY ); + m_aTableMap["LineDashName"] = xDashTable; + m_aTableMap["FillGradientName"] = xGradientTable; + m_aTableMap["FillHatchName"] = xHatchTable; + m_aTableMap["FillBitmapName"] = xBitmapTable; + m_aTableMap["FillTransparenceGradientName"] = xTransparencyGradientTable; +} + +void Chart2ModelContact::clear() +{ + m_xChartModel.clear(); + m_xChartView.clear(); +} + +rtl::Reference< ChartModel > Chart2ModelContact::getDocumentModel() const +{ + return m_xChartModel; +} + +rtl::Reference< ::chart::Diagram > Chart2ModelContact::getDiagram() const +{ + try + { + rtl::Reference<ChartModel> xChartModel = getDocumentModel(); + if( xChartModel) + return xChartModel->getFirstChartDiagram(); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nullptr; +} + +rtl::Reference< ::chart::ChartView > const & Chart2ModelContact::getChartView() const +{ + if(!m_xChartView.is()) + { + // get the chart view + rtl::Reference<ChartModel> xChartModel( m_xChartModel ); + if( xChartModel ) + { + auto xInstance = xChartModel->createInstance( CHART_VIEW_SERVICE_NAME ); + auto pChartView = dynamic_cast<ChartView*>(xInstance.get()); + assert(!xInstance || pChartView); + m_xChartView = pChartView; + } + } + return m_xChartView; +} + +ExplicitValueProvider* Chart2ModelContact::getExplicitValueProvider() const +{ + getChartView(); + + //obtain the ExplicitValueProvider from the chart view + return m_xChartView.get(); +} + +rtl::Reference<SvxDrawPage> Chart2ModelContact::getDrawPage() const +{ + rtl::Reference<SvxDrawPage> xResult; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + { + xResult = pProvider->getDrawModelWrapper()->getMainDrawPage(); + } + return xResult; +} + +void Chart2ModelContact::getExplicitValuesForAxis( + const Reference< XAxis > & xAxis, + ExplicitScaleData & rOutExplicitScale, + ExplicitIncrementData & rOutExplicitIncrement ) +{ + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + { + pProvider->getExplicitValuesForAxis( + xAxis, rOutExplicitScale, rOutExplicitIncrement ); + } +} + +sal_Int32 Chart2ModelContact::getExplicitNumberFormatKeyForAxis( + const Reference< chart2::XAxis >& xAxis ) +{ + rtl::Reference< BaseCoordinateSystem > xCooSys( + AxisHelper::getCoordinateSystemOfAxis( + xAxis, ChartModelHelper::findDiagram( m_xChartModel ) ) ); + + return ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( xAxis, xCooSys + , m_xChartModel.get() ); +} + +sal_Int32 Chart2ModelContact::getExplicitNumberFormatKeyForSeries( + const Reference< chart2::XDataSeries >& xSeries ) +{ + return ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( + uno::Reference< beans::XPropertySet >( xSeries, uno::UNO_QUERY )); +} + +awt::Size Chart2ModelContact::GetPageSize() const +{ + return ChartModelHelper::getPageSize(m_xChartModel.get()); +} + +awt::Rectangle Chart2ModelContact::SubstractAxisTitleSizes( const awt::Rectangle& rPositionRect ) +{ + awt::Rectangle aRect = ExplicitValueProvider::AddSubtractAxisTitleSizes( + *m_xChartModel.get(), getChartView().get(), rPositionRect, true ); + return aRect; +} + +awt::Rectangle Chart2ModelContact::GetDiagramRectangleIncludingTitle() const +{ + awt::Rectangle aRect( GetDiagramRectangleIncludingAxes() ); + + //add axis title sizes to the diagram size + aRect = ExplicitValueProvider::AddSubtractAxisTitleSizes( + *m_xChartModel.get(), getChartView().get(), aRect, false ); + + return aRect; +} + +awt::Rectangle Chart2ModelContact::GetDiagramRectangleIncludingAxes() const +{ + awt::Rectangle aRect(0,0,0,0); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartModel ); + + if( DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_INCLUDING ) + aRect = DiagramHelper::getDiagramRectangleFromModel(m_xChartModel.get()); + else + { + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + aRect = pProvider->getRectangleOfObject("PlotAreaIncludingAxes"); + } + return aRect; +} + +awt::Rectangle Chart2ModelContact::GetDiagramRectangleExcludingAxes() const +{ + awt::Rectangle aRect(0,0,0,0); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartModel ); + + if( DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_EXCLUDING ) + aRect = DiagramHelper::getDiagramRectangleFromModel(m_xChartModel.get()); + else + { + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + aRect = pProvider->getDiagramRectangleExcludingAxes(); + } + return aRect; +} + +awt::Size Chart2ModelContact::GetLegendSize() const +{ + awt::Size aSize; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + { + rtl::Reference< Legend > xLegend = LegendHelper::getLegend( *m_xChartModel.get() ); + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xLegend, m_xChartModel ) ); + aSize = ToSize( pProvider->getRectangleOfObject( aCID ) ); + } + return aSize; +} + +awt::Point Chart2ModelContact::GetLegendPosition() const +{ + awt::Point aPoint; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + { + rtl::Reference< Legend > xLegend = LegendHelper::getLegend( *m_xChartModel.get() ); + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xLegend, m_xChartModel ) ); + aPoint = ToPoint( pProvider->getRectangleOfObject( aCID ) ); + } + return aPoint; +} + +awt::Size Chart2ModelContact::GetTitleSize( const uno::Reference< css::chart2::XTitle > & xTitle ) const +{ + awt::Size aSize; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider && xTitle.is() ) + { + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, m_xChartModel ) ); + aSize = ToSize( pProvider->getRectangleOfObject( aCID ) ); + } + return aSize; +} + +awt::Point Chart2ModelContact::GetTitlePosition( const uno::Reference< css::chart2::XTitle > & xTitle ) const +{ + awt::Point aPoint; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider && xTitle.is() ) + { + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, m_xChartModel.get() ) ); + aPoint = ToPoint( pProvider->getRectangleOfObject( aCID ) ); + } + return aPoint; +} + +awt::Size Chart2ModelContact::GetAxisSize( const uno::Reference< css::chart2::XAxis > & xAxis ) const +{ + awt::Size aSize; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider && xAxis.is() ) + { + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, m_xChartModel.get() ) ); + aSize = ToSize( pProvider->getRectangleOfObject( aCID ) ); + } + return aSize; +} + +awt::Point Chart2ModelContact::GetAxisPosition( const uno::Reference< css::chart2::XAxis > & xAxis ) const +{ + awt::Point aPoint; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider && xAxis.is() ) + { + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, m_xChartModel.get() ) ); + aPoint = ToPoint( pProvider->getRectangleOfObject( aCID ) ); + } + return aPoint; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/Chart2ModelContact.hxx b/chart2/source/controller/chartapiwrapper/Chart2ModelContact.hxx new file mode 100644 index 000000000..7a89fb7dd --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/Chart2ModelContact.hxx @@ -0,0 +1,149 @@ +/* -*- 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/awt/Size.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <rtl/ref.hxx> +#include <svx/unopage.hxx> +#include <unotools/weakref.hxx> +#include <ChartModel.hxx> +#include <Diagram.hxx> +#include <map> + +namespace chart { struct ExplicitIncrementData; } +namespace chart { struct ExplicitScaleData; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2 { class XTitle; } +namespace com::sun::star::container { class XNameContainer; } +namespace com::sun::star::drawing { class XDrawPage; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::lang { class XUnoTunnel; } +namespace com::sun::star::uno { class XComponentContext; } + + +namespace chart +{ +class ExplicitValueProvider; +class ChartModel; + +namespace wrapper +{ + +class Chart2ModelContact final +{ +public: + explicit Chart2ModelContact( const css::uno::Reference< css::uno::XComponentContext >& xContext ); + ~Chart2ModelContact(); + +public: + void setDocumentModel( ChartModel* pChartModel ); + void clear(); + + rtl::Reference<ChartModel> getDocumentModel() const; + + rtl::Reference< ::chart::Diagram > getDiagram() const; + + rtl::Reference<SvxDrawPage> getDrawPage() const; + + /** get the current values calculated for an axis in the current view in + case properties are 'auto'. + */ + void getExplicitValuesForAxis( + const css::uno::Reference< css::chart2::XAxis > & xAxis, + ExplicitScaleData & rOutExplicitScale, + ExplicitIncrementData & rOutExplicitIncrement ); + + sal_Int32 getExplicitNumberFormatKeyForAxis( + const css::uno::Reference< css::chart2::XAxis >& xAxis ); + + static sal_Int32 getExplicitNumberFormatKeyForSeries( + const css::uno::Reference< css::chart2::XDataSeries >& xSeries ); + + /** Returns the size of the page in logic coordinates. This value is used + for setting an appropriate "ReferencePageSize" for FontHeights. + */ + css::awt::Size GetPageSize() const; + + /** calculates the current axes title sizes and subtract that space them from the given rectangle + */ + css::awt::Rectangle SubstractAxisTitleSizes( const css::awt::Rectangle& rPositionRect ); + + /** Returns the position and size of the diagram in logic coordinates (100th mm) including + the space used for axes including axes titles. + */ + css::awt::Rectangle GetDiagramRectangleIncludingTitle() const; + + /** Returns the position and size of the diagram in logic coordinates (100th mm) including + the space used for axes excluding axes titles. + */ + css::awt::Rectangle GetDiagramRectangleIncludingAxes() const; + + /** Returns the position and size of the diagram in logic coordinates (100th mm) excluding + the space used for axes (inner plot area). + */ + css::awt::Rectangle GetDiagramRectangleExcludingAxes() const; + + /** Returns the size of the object in logic coordinates. + */ + css::awt::Size GetLegendSize() const; + + /** Returns the position of the object in logic coordinates. + */ + css::awt::Point GetLegendPosition() const; + + /** Returns the size of the object in logic coordinates. + */ + css::awt::Size GetTitleSize( const css::uno::Reference< css::chart2::XTitle > & xTitle ) const; + + /** Returns the position of the object in logic coordinates. + */ + css::awt::Point GetTitlePosition( const css::uno::Reference< css::chart2::XTitle > & xTitle ) const; + + /** Returns the size of the object in logic coordinates. + */ + css::awt::Size GetAxisSize( const css::uno::Reference< css::chart2::XAxis > & xAxis ) const; + + /** Returns the position of the object in logic coordinates. + */ + css::awt::Point GetAxisPosition( const css::uno::Reference< css::chart2::XAxis > & xAxis ) const; + +private: //methods + ExplicitValueProvider* getExplicitValueProvider() const; + rtl::Reference< ChartView > const & getChartView() const; + +public: //member + css::uno::Reference< css::uno::XComponentContext > m_xContext; + +private: //member + unotools::WeakReference< ChartModel > m_xChartModel; + + mutable rtl::Reference< ChartView > m_xChartView; + + std::map< OUString, css::uno::Reference< css::container::XNameContainer > > m_aTableMap; +}; + +} // namespace wrapper +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/ChartDataWrapper.cxx b/chart2/source/controller/chartapiwrapper/ChartDataWrapper.cxx new file mode 100644 index 000000000..787c9ba1b --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/ChartDataWrapper.cxx @@ -0,0 +1,695 @@ +/* -*- 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 "ChartDataWrapper.hxx" +#include <DiagramHelper.hxx> +#include <DataSourceHelper.hxx> +#include <ChartModelHelper.hxx> +#include <InternalDataProvider.hxx> +#include <ControllerLockGuard.hxx> +#include "Chart2ModelContact.hxx" +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/chart/XChartDocument.hpp> + +#include <float.h> +#include <cmath> +#include <limits> +#include <osl/diagnose.h> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::chart2::XAnyDescriptionAccess; +using ::com::sun::star::chart::XComplexDescriptionAccess; +using ::com::sun::star::chart::XChartData; +using ::com::sun::star::chart::XChartDataArray; +using ::com::sun::star::chart::XDateCategories; + +namespace +{ + +uno::Sequence< uno::Sequence< double > > lcl_getNANInsteadDBL_MIN( const uno::Sequence< uno::Sequence< double > >& rData ) +{ + uno::Sequence< uno::Sequence< double > > aRet; + const sal_Int32 nOuterSize = rData.getLength(); + aRet.realloc( nOuterSize ); + auto pRet = aRet.getArray(); + for( sal_Int32 nOuter=0; nOuter<nOuterSize; ++nOuter ) + { + sal_Int32 nInnerSize = rData[nOuter].getLength(); + pRet[nOuter].realloc( nInnerSize ); + auto pRet_nOuter = pRet[nOuter].getArray(); + for( sal_Int32 nInner=0; nInner<nInnerSize; ++nInner ) + { + pRet_nOuter[nInner] = rData[nOuter][nInner]; + double& rValue = pRet_nOuter[nInner]; + if( rValue == DBL_MIN ) + rValue = std::numeric_limits<double>::quiet_NaN(); + } + } + return aRet; +} + +uno::Sequence< uno::Sequence< double > > lcl_getDBL_MINInsteadNAN( const uno::Sequence< uno::Sequence< double > >& rData ) +{ + uno::Sequence< uno::Sequence< double > > aRet; + const sal_Int32 nOuterSize = rData.getLength(); + aRet.realloc( nOuterSize ); + auto pRet = aRet.getArray(); + for( sal_Int32 nOuter=0; nOuter<nOuterSize; ++nOuter ) + { + sal_Int32 nInnerSize = rData[nOuter].getLength(); + pRet[nOuter].realloc( nInnerSize ); + auto pRet_nOuter = pRet[nOuter].getArray(); + for( sal_Int32 nInner=0; nInner<nInnerSize; ++nInner ) + { + pRet_nOuter[nInner] = rData[nOuter][nInner]; + double& rValue = pRet_nOuter[nInner]; + if( std::isnan( rValue ) ) + rValue = DBL_MIN; + } + } + return aRet; +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +struct lcl_Operator +{ + lcl_Operator() + { + } + virtual ~lcl_Operator() + { + } + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) = 0; + + virtual bool setsCategories( bool /*bDataInColumns*/ ) + { + return false; + } +}; + +namespace { + +struct lcl_AllOperator : public lcl_Operator +{ + explicit lcl_AllOperator( const Reference< XChartData >& xDataToApply ) + : m_xDataToApply( xDataToApply ) + { + } + + virtual bool setsCategories( bool /*bDataInColumns*/ ) override + { + return true; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( !xDataAccess.is() ) + return; + + Reference< XAnyDescriptionAccess > xNewAny( m_xDataToApply, uno::UNO_QUERY ); + Reference< XComplexDescriptionAccess > xNewComplex( m_xDataToApply, uno::UNO_QUERY ); + if( xNewAny.is() ) + { + xDataAccess->setData( xNewAny->getData() ); + xDataAccess->setComplexRowDescriptions( xNewAny->getComplexRowDescriptions() ); + xDataAccess->setComplexColumnDescriptions( xNewAny->getComplexColumnDescriptions() ); + } + else if( xNewComplex.is() ) + { + xDataAccess->setData( xNewComplex->getData() ); + xDataAccess->setComplexRowDescriptions( xNewComplex->getComplexRowDescriptions() ); + xDataAccess->setComplexColumnDescriptions( xNewComplex->getComplexColumnDescriptions() ); + } + else + { + Reference< XChartDataArray > xNew( m_xDataToApply, uno::UNO_QUERY ); + if( xNew.is() ) + { + xDataAccess->setData( xNew->getData() ); + xDataAccess->setRowDescriptions( xNew->getRowDescriptions() ); + xDataAccess->setColumnDescriptions( xNew->getColumnDescriptions() ); + } + } + } + + Reference< XChartData > m_xDataToApply; +}; + +struct lcl_DataOperator : public lcl_Operator +{ + explicit lcl_DataOperator( const Sequence< Sequence< double > >& rData ) + : m_rData( rData ) + { + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + xDataAccess->setData( lcl_getNANInsteadDBL_MIN( m_rData ) ); + } + + const Sequence< Sequence< double > >& m_rData; +}; + +struct lcl_RowDescriptionsOperator : public lcl_Operator +{ + lcl_RowDescriptionsOperator( const Sequence< OUString >& rRowDescriptions + , const rtl::Reference<::chart::ChartModel>& xChartDoc ) + : m_rRowDescriptions( rRowDescriptions ) + , m_xChartDoc(xChartDoc) + , m_bDataInColumns(true) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + m_bDataInColumns = bDataInColumns; + return bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + { + xDataAccess->setRowDescriptions( m_rRowDescriptions ); + if( m_bDataInColumns ) + DiagramHelper::switchToTextCategories( m_xChartDoc ); + } + } + + const Sequence< OUString >& m_rRowDescriptions; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bDataInColumns; +}; + +struct lcl_ComplexRowDescriptionsOperator : public lcl_Operator +{ + lcl_ComplexRowDescriptionsOperator( const Sequence< Sequence< OUString > >& rComplexRowDescriptions + , const rtl::Reference<::chart::ChartModel>& xChartDoc ) + : m_rComplexRowDescriptions( rComplexRowDescriptions ) + , m_xChartDoc(xChartDoc) + , m_bDataInColumns(true) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + m_bDataInColumns = bDataInColumns; + return bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + { + xDataAccess->setComplexRowDescriptions( m_rComplexRowDescriptions ); + if( m_bDataInColumns ) + DiagramHelper::switchToTextCategories( m_xChartDoc ); + } + } + + const Sequence< Sequence< OUString > >& m_rComplexRowDescriptions; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bDataInColumns; +}; + +struct lcl_AnyRowDescriptionsOperator : public lcl_Operator +{ + explicit lcl_AnyRowDescriptionsOperator( const Sequence< Sequence< uno::Any > >& rAnyRowDescriptions ) + : m_rAnyRowDescriptions( rAnyRowDescriptions ) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + return bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + xDataAccess->setAnyRowDescriptions( m_rAnyRowDescriptions ); + } + + const Sequence< Sequence< uno::Any > >& m_rAnyRowDescriptions; +}; + +struct lcl_ColumnDescriptionsOperator : public lcl_Operator +{ + lcl_ColumnDescriptionsOperator( const Sequence< OUString >& rColumnDescriptions + , const rtl::Reference<::chart::ChartModel>& xChartDoc ) + : m_rColumnDescriptions( rColumnDescriptions ) + , m_xChartDoc(xChartDoc) + , m_bDataInColumns(true) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + m_bDataInColumns = bDataInColumns; + return !bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + { + xDataAccess->setColumnDescriptions( m_rColumnDescriptions ); + if( !m_bDataInColumns ) + DiagramHelper::switchToTextCategories( m_xChartDoc ); + } + } + + const Sequence< OUString >& m_rColumnDescriptions; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bDataInColumns; +}; + +struct lcl_ComplexColumnDescriptionsOperator : public lcl_Operator +{ + lcl_ComplexColumnDescriptionsOperator( const Sequence< Sequence< OUString > >& rComplexColumnDescriptions + , const rtl::Reference<::chart::ChartModel>& xChartDoc ) + : m_rComplexColumnDescriptions( rComplexColumnDescriptions ) + , m_xChartDoc(xChartDoc) + , m_bDataInColumns(true) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + m_bDataInColumns = bDataInColumns; + return !bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + { + xDataAccess->setComplexColumnDescriptions( m_rComplexColumnDescriptions ); + if( !m_bDataInColumns ) + DiagramHelper::switchToTextCategories( m_xChartDoc ); + } + } + + const Sequence< Sequence< OUString > >& m_rComplexColumnDescriptions; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bDataInColumns; +}; + +struct lcl_AnyColumnDescriptionsOperator : public lcl_Operator +{ + explicit lcl_AnyColumnDescriptionsOperator( const Sequence< Sequence< uno::Any > >& rAnyColumnDescriptions ) + : m_rAnyColumnDescriptions( rAnyColumnDescriptions ) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + return bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + xDataAccess->setAnyColumnDescriptions( m_rAnyColumnDescriptions ); + } + + const Sequence< Sequence< uno::Any > >& m_rAnyColumnDescriptions; +}; + +struct lcl_DateCategoriesOperator : public lcl_Operator +{ + explicit lcl_DateCategoriesOperator( const Sequence< double >& rDates ) + : m_rDates( rDates ) + { + } + + virtual bool setsCategories( bool /*bDataInColumns*/ ) override + { + return true; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + Reference< XDateCategories > xDateCategories( xDataAccess, uno::UNO_QUERY ); + if( xDateCategories.is() ) + xDateCategories->setDateCategories( m_rDates ); + } + + const Sequence< double >& m_rDates; +}; + +} + +ChartDataWrapper::ChartDataWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) +{ + osl_atomic_increment( &m_refCount ); + initDataAccess(); + osl_atomic_decrement( &m_refCount ); +} + +ChartDataWrapper::ChartDataWrapper( const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + const Reference< XChartData >& xNewData ) : + m_spChart2ModelContact( spChart2ModelContact ), + m_aEventListenerContainer( m_aMutex ) +{ + osl_atomic_increment( &m_refCount ); + lcl_AllOperator aOperator( xNewData ); + applyData( aOperator ); + osl_atomic_decrement( &m_refCount ); +} + +ChartDataWrapper::~ChartDataWrapper() +{ + // @todo: implement XComponent and call this in dispose(). In the DTOR the + // ref-count is 0, thus creating a stack reference to this calls the DTOR at + // the end of the block recursively +// uno::Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); +// m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); +} + +// ____ XChartDataArray (read)____ +Sequence< Sequence< double > > SAL_CALL ChartDataWrapper::getData() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return lcl_getDBL_MINInsteadNAN( m_xDataAccess->getData() ); + return Sequence< Sequence< double > >(); +} +Sequence< OUString > SAL_CALL ChartDataWrapper::getRowDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getRowDescriptions(); + return Sequence< OUString >(); +} +Sequence< OUString > SAL_CALL ChartDataWrapper::getColumnDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getColumnDescriptions(); + return Sequence< OUString > (); +} + +// ____ XComplexDescriptionAccess (read) ____ +Sequence< Sequence< OUString > > SAL_CALL ChartDataWrapper::getComplexRowDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getComplexRowDescriptions(); + return Sequence< Sequence< OUString > >(); +} +Sequence< Sequence< OUString > > SAL_CALL ChartDataWrapper::getComplexColumnDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getComplexColumnDescriptions(); + return Sequence< Sequence< OUString > >(); +} + +// ____ XAnyDescriptionAccess (read) ____ +Sequence< Sequence< uno::Any > > SAL_CALL ChartDataWrapper::getAnyRowDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getAnyRowDescriptions(); + return Sequence< Sequence< uno::Any > >(); +} +Sequence< Sequence< uno::Any > > SAL_CALL ChartDataWrapper::getAnyColumnDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getAnyColumnDescriptions(); + return Sequence< Sequence< uno::Any > >(); +} + +// ____ XDateCategories (read) ____ +Sequence< double > SAL_CALL ChartDataWrapper::getDateCategories() +{ + initDataAccess(); + Reference< XDateCategories > xDateCategories( m_xDataAccess, uno::UNO_QUERY ); + if( xDateCategories.is() ) + return xDateCategories->getDateCategories(); + return Sequence< double >(); +} + +// ____ XChartDataArray (write)____ +void SAL_CALL ChartDataWrapper::setData( const Sequence< Sequence< double > >& rData ) +{ + lcl_DataOperator aOperator( rData ); + applyData( aOperator ); +} +void SAL_CALL ChartDataWrapper::setRowDescriptions( const Sequence< OUString >& rRowDescriptions ) +{ + lcl_RowDescriptionsOperator aOperator( rRowDescriptions, m_spChart2ModelContact->getDocumentModel() ); + applyData( aOperator ); +} +void SAL_CALL ChartDataWrapper::setColumnDescriptions( const Sequence< OUString >& rColumnDescriptions ) +{ + lcl_ColumnDescriptionsOperator aOperator( rColumnDescriptions, m_spChart2ModelContact->getDocumentModel() ); + applyData( aOperator ); +} + +// ____ XComplexDescriptionAccess (write) ____ +void SAL_CALL ChartDataWrapper::setComplexRowDescriptions( const Sequence< Sequence< OUString > >& rRowDescriptions ) +{ + lcl_ComplexRowDescriptionsOperator aOperator( rRowDescriptions, m_spChart2ModelContact->getDocumentModel() ); + applyData( aOperator ); +} +void SAL_CALL ChartDataWrapper::setComplexColumnDescriptions( const Sequence< Sequence< OUString > >& rColumnDescriptions ) +{ + lcl_ComplexColumnDescriptionsOperator aOperator( rColumnDescriptions, m_spChart2ModelContact->getDocumentModel() ); + applyData( aOperator ); +} + +// ____ XAnyDescriptionAccess (write) ____ +void SAL_CALL ChartDataWrapper::setAnyRowDescriptions( const Sequence< Sequence< uno::Any > >& rRowDescriptions ) +{ + lcl_AnyRowDescriptionsOperator aOperator( rRowDescriptions ); + applyData( aOperator ); +} +void SAL_CALL ChartDataWrapper::setAnyColumnDescriptions( const Sequence< Sequence< uno::Any > >& rColumnDescriptions ) +{ + lcl_AnyColumnDescriptionsOperator aOperator( rColumnDescriptions ); + applyData( aOperator ); +} + +// ____ XDateCategories (write) ____ +void SAL_CALL ChartDataWrapper::setDateCategories( const Sequence< double >& rDates ) +{ + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + lcl_DateCategoriesOperator aOperator( rDates ); + applyData( aOperator ); + DiagramHelper::switchToDateCategories( xChartDoc ); +} + +// ____ XChartData (base of XChartDataArray) ____ +void SAL_CALL ChartDataWrapper::addChartDataChangeEventListener( + const uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) +{ + m_aEventListenerContainer.addInterface( aListener ); +} + +void SAL_CALL ChartDataWrapper::removeChartDataChangeEventListener( + const uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +double SAL_CALL ChartDataWrapper::getNotANumber() +{ + return DBL_MIN; +} + +sal_Bool SAL_CALL ChartDataWrapper::isNotANumber( double nNumber ) +{ + return nNumber == DBL_MIN + || std::isnan( nNumber ) + || std::isinf( nNumber ); +} + +// ____ XComponent ____ +void SAL_CALL ChartDataWrapper::dispose() +{ + m_aEventListenerContainer.disposeAndClear( lang::EventObject( static_cast< ::cppu::OWeakObject* >( this ))); + m_xDataAccess=nullptr; +} + +void SAL_CALL ChartDataWrapper::addEventListener( + const uno::Reference< lang::XEventListener > & xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL ChartDataWrapper::removeEventListener( + const uno::Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// ____ XEventListener ____ +void SAL_CALL ChartDataWrapper::disposing( const lang::EventObject& /* Source */ ) +{ +} + +void ChartDataWrapper::fireChartDataChangeEvent( css::chart::ChartDataChangeEvent& aEvent ) +{ + if( ! m_aEventListenerContainer.getLength() ) + return; + + uno::Reference< uno::XInterface > xSrc( static_cast< cppu::OWeakObject* >( this )); + OSL_ASSERT( xSrc.is()); + if( xSrc.is() ) + aEvent.Source = xSrc; + + m_aEventListenerContainer.notifyEach( &css::chart::XChartDataChangeEventListener::chartDataChanged, aEvent ); +} + +void ChartDataWrapper::switchToInternalDataProvider() +{ + //create an internal data provider that is connected to the model + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( xChartDoc.is() ) + xChartDoc->createInternalDataProvider( true /*bCloneExistingData*/ ); + m_xDataAccess.clear(); + initDataAccess(); +} + +void ChartDataWrapper::initDataAccess() +{ + if (m_xDataAccess) + return; + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( !xChartDoc.is() ) + return; + if( xChartDoc->hasInternalDataProvider() ) + m_xDataAccess.set( xChartDoc->getDataProvider(), uno::UNO_QUERY_THROW ); + else + { + //create a separate "internal data provider" that is not connected to the model + auto xInternal = ChartModelHelper::createInternalDataProvider( + xChartDoc, false /*bConnectToModel*/ ); + m_xDataAccess.set( static_cast<cppu::OWeakObject*>(xInternal.get()), uno::UNO_QUERY_THROW ); + } +} + +void ChartDataWrapper::applyData( lcl_Operator& rDataOperator ) +{ + //bool bSetValues, bool bSetRowDescriptions, bool bSetColumnDescriptions + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( !xChartDoc.is() ) + return; + + // remember some diagram properties to reset later + bool bStacked = false; + bool bPercent = false; + bool bDeep = false; + uno::Reference< css::chart::XChartDocument > xOldDoc( static_cast<cppu::OWeakObject*>(xChartDoc.get()), uno::UNO_QUERY ); + OSL_ASSERT( xOldDoc.is()); + uno::Reference< beans::XPropertySet > xDiaProp( xOldDoc->getDiagram(), uno::UNO_QUERY ); + if( xDiaProp.is()) + { + xDiaProp->getPropertyValue("Stacked") >>= bStacked; + xDiaProp->getPropertyValue("Percent") >>= bPercent; + xDiaProp->getPropertyValue("Deep") >>= bDeep; + } + + //detect arguments for the new data source + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + (void)DataSourceHelper::detectRangeSegmentation( + xChartDoc, + aRangeString, aSequenceMapping, bUseColumns, bFirstCellAsLabel, bHasCategories ); + + if( !bHasCategories && rDataOperator.setsCategories( bUseColumns ) ) + bHasCategories = true; + + aRangeString = "all"; + uno::Sequence< beans::PropertyValue > aArguments( DataSourceHelper::createArguments( + aRangeString, aSequenceMapping, bUseColumns, bFirstCellAsLabel, bHasCategories ) ); + + // -- locked controllers + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + + // create and attach new data source + switchToInternalDataProvider(); + rDataOperator.apply(m_xDataAccess); + uno::Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + OSL_ASSERT( xDataProvider.is() ); + if( !xDataProvider.is() ) + return; + uno::Reference< chart2::data::XDataSource > xSource( xDataProvider->createDataSource( aArguments ) ); + + rtl::Reference< Diagram > xDia( xChartDoc->getFirstChartDiagram() ); + if( xDia.is() ) + xDia->setDiagramData( xSource, aArguments ); + + //correct stacking mode + if( bStacked || bPercent || bDeep ) + { + StackMode eStackMode = StackMode::YStacked; + if( bDeep ) + eStackMode = StackMode::ZStacked; + else if( bPercent ) + eStackMode = StackMode::YStackedPercent; + DiagramHelper::setStackMode( xDia, eStackMode ); + } + + // notify listeners + css::chart::ChartDataChangeEvent aEvent( + static_cast< ::cppu::OWeakObject* >( this ), + css::chart::ChartDataChangeType_ALL, 0, 0, 0, 0 ); + fireChartDataChangeEvent( aEvent ); + // \-- locked controllers +} + +OUString SAL_CALL ChartDataWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.ChartData"; +} + +sal_Bool SAL_CALL ChartDataWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartDataWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartDataArray", + "com.sun.star.chart.ChartData" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/ChartDataWrapper.hxx b/chart2/source/controller/chartapiwrapper/ChartDataWrapper.hxx new file mode 100644 index 000000000..dcf7c50ad --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/ChartDataWrapper.hxx @@ -0,0 +1,118 @@ +/* -*- 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/basemutex.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer2.hxx> +#include <com/sun/star/chart2/XAnyDescriptionAccess.hpp> +#include <com/sun/star/chart/XDateCategories.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/EventObject.hpp> + +#include <memory> + +namespace chart::wrapper +{ + +class Chart2ModelContact; +struct lcl_Operator; + +class ChartDataWrapper final : public cppu::BaseMutex, public + ::cppu::WeakImplHelper< + css::chart2::XAnyDescriptionAccess, + css::chart::XDateCategories, + css::lang::XServiceInfo, + css::lang::XEventListener, + css::lang::XComponent > +{ +public: + explicit ChartDataWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + ChartDataWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact + , const css::uno::Reference< css::chart::XChartData >& xNewData ); + virtual ~ChartDataWrapper() 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; + +private: + // ____ XDateCategories ____ + virtual css::uno::Sequence< double > SAL_CALL getDateCategories() override; + virtual void SAL_CALL setDateCategories( const css::uno::Sequence< double >& rDates ) override; + + // ____ XAnyDescriptionAccess ____ + virtual css::uno::Sequence< css::uno::Sequence< css::uno::Any > > SAL_CALL + getAnyRowDescriptions() override; + virtual void SAL_CALL setAnyRowDescriptions( + const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& aRowDescriptions ) override; + virtual css::uno::Sequence< css::uno::Sequence< css::uno::Any > > SAL_CALL + getAnyColumnDescriptions() override; + virtual void SAL_CALL setAnyColumnDescriptions( + const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& aColumnDescriptions ) override; + + // ____ XComplexDescriptionAccess (base of XAnyDescriptionAccess) ____ + virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL + getComplexRowDescriptions() override; + virtual void SAL_CALL setComplexRowDescriptions( + const css::uno::Sequence< css::uno::Sequence< OUString > >& aRowDescriptions ) override; + virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL + getComplexColumnDescriptions() override; + virtual void SAL_CALL setComplexColumnDescriptions( + const css::uno::Sequence< css::uno::Sequence< OUString > >& aColumnDescriptions ) override; + + // ____ XChartDataArray (base of XComplexDescriptionAccess) ____ + virtual css::uno::Sequence< css::uno::Sequence< double > > SAL_CALL getData() override; + virtual void SAL_CALL setData( const css::uno::Sequence< css::uno::Sequence< double > >& aData ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getRowDescriptions() override; + virtual void SAL_CALL setRowDescriptions( const css::uno::Sequence< OUString >& aRowDescriptions ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getColumnDescriptions() override; + virtual void SAL_CALL setColumnDescriptions( const css::uno::Sequence< OUString >& aColumnDescriptions ) override; + + // ____ XChartData (base of XChartDataArray) ____ + virtual void SAL_CALL addChartDataChangeEventListener( const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override; + virtual void SAL_CALL removeChartDataChangeEventListener( const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override; + virtual double SAL_CALL getNotANumber() override; + virtual sal_Bool SAL_CALL isNotANumber( double nNumber ) override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // ____ XEventListener ____ + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + void fireChartDataChangeEvent( css::chart::ChartDataChangeEvent& aEvent ); + + void switchToInternalDataProvider(); + void initDataAccess(); + void applyData( lcl_Operator& rDataOperator ); + + css::uno::Reference< css::chart2::XAnyDescriptionAccess > m_xDataAccess; + + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper2 m_aEventListenerContainer; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/ChartDocumentWrapper.cxx b/chart2/source/controller/chartapiwrapper/ChartDocumentWrapper.cxx new file mode 100644 index 000000000..d8acdefe7 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/ChartDocumentWrapper.cxx @@ -0,0 +1,1437 @@ +/* -*- 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 <ChartDocumentWrapper.hxx> +#include <ChartView.hxx> +#include <ChartTypeManager.hxx> +#include <ChartTypeTemplate.hxx> +#include <servicenames.hxx> +#include <PropertyHelper.hxx> +#include <TitleHelper.hxx> +#include <Legend.hxx> +#include <LegendHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <DisposeHelper.hxx> +#include "DataSeriesPointWrapper.hxx" +#include <chartview/ExplicitValueProvider.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include "Chart2ModelContact.hxx" +#include <BaseCoordinateSystem.hxx> + +#include <ChartModel.hxx> + +#include <DiagramHelper.hxx> +#include <DataSourceHelper.hxx> +#include <ChartModelHelper.hxx> +#include <AxisHelper.hxx> +#include <ThreeDHelper.hxx> + +#include "TitleWrapper.hxx" +#include "ChartDataWrapper.hxx" +#include "DiagramWrapper.hxx" +#include "LegendWrapper.hxx" +#include "AreaWrapper.hxx" +#include "WrappedAddInProperty.hxx" +#include <WrappedIgnoreProperty.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <vcl/settings.hxx> + +#include <com/sun/star/drawing/ShapeCollection.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <tools/diagnose_ex.h> + +#include <algorithm> +#include <map> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ +enum eServiceType +{ + SERVICE_NAME_AREA_DIAGRAM = 0, + SERVICE_NAME_BAR_DIAGRAM, + SERVICE_NAME_DONUT_DIAGRAM, + SERVICE_NAME_LINE_DIAGRAM, + SERVICE_NAME_NET_DIAGRAM, + SERVICE_NAME_FILLED_NET_DIAGRAM, + SERVICE_NAME_PIE_DIAGRAM, + SERVICE_NAME_STOCK_DIAGRAM, + SERVICE_NAME_XY_DIAGRAM, + SERVICE_NAME_BUBBLE_DIAGRAM, + + SERVICE_NAME_DASH_TABLE, + SERVICE_NAME_GRADIENT_TABLE, + SERVICE_NAME_HATCH_TABLE, + SERVICE_NAME_BITMAP_TABLE, + SERVICE_NAME_TRANSP_GRADIENT_TABLE, + SERVICE_NAME_MARKER_TABLE, + + SERVICE_NAME_NAMESPACE_MAP, + SERVICE_NAME_EXPORT_GRAPHIC_STORAGE_RESOLVER, + SERVICE_NAME_IMPORT_GRAPHIC_STORAGE_RESOLVER +}; + +typedef std::map< OUString, enum eServiceType > tServiceNameMap; + +tServiceNameMap & lcl_getStaticServiceNameMap() +{ + static tServiceNameMap aServiceNameMap { + {"com.sun.star.chart.AreaDiagram", SERVICE_NAME_AREA_DIAGRAM}, + {"com.sun.star.chart.BarDiagram", SERVICE_NAME_BAR_DIAGRAM}, + {"com.sun.star.chart.DonutDiagram", SERVICE_NAME_DONUT_DIAGRAM}, + {"com.sun.star.chart.LineDiagram", SERVICE_NAME_LINE_DIAGRAM}, + {"com.sun.star.chart.NetDiagram", SERVICE_NAME_NET_DIAGRAM}, + {"com.sun.star.chart.FilledNetDiagram", SERVICE_NAME_FILLED_NET_DIAGRAM}, + {"com.sun.star.chart.PieDiagram", SERVICE_NAME_PIE_DIAGRAM}, + {"com.sun.star.chart.StockDiagram", SERVICE_NAME_STOCK_DIAGRAM}, + {"com.sun.star.chart.XYDiagram", SERVICE_NAME_XY_DIAGRAM}, + {"com.sun.star.chart.BubbleDiagram", SERVICE_NAME_BUBBLE_DIAGRAM}, + + {"com.sun.star.drawing.DashTable", SERVICE_NAME_DASH_TABLE}, + {"com.sun.star.drawing.GradientTable", SERVICE_NAME_GRADIENT_TABLE}, + {"com.sun.star.drawing.HatchTable", SERVICE_NAME_HATCH_TABLE}, + {"com.sun.star.drawing.BitmapTable", SERVICE_NAME_BITMAP_TABLE}, + {"com.sun.star.drawing.TransparencyGradientTable", SERVICE_NAME_TRANSP_GRADIENT_TABLE}, + {"com.sun.star.drawing.MarkerTable", SERVICE_NAME_MARKER_TABLE}, + + {"com.sun.star.xml.NamespaceMap", SERVICE_NAME_NAMESPACE_MAP}, + {"com.sun.star.document.ExportGraphicStorageHandler", SERVICE_NAME_EXPORT_GRAPHIC_STORAGE_RESOLVER}, + {"com.sun.star.document.ImportGraphicStorageHandler", SERVICE_NAME_IMPORT_GRAPHIC_STORAGE_RESOLVER} + }; + + return aServiceNameMap; +} + +enum +{ + PROP_DOCUMENT_HAS_MAIN_TITLE, + PROP_DOCUMENT_HAS_SUB_TITLE, + PROP_DOCUMENT_HAS_LEGEND, + PROP_DOCUMENT_LABELS_IN_FIRST_ROW, + PROP_DOCUMENT_LABELS_IN_FIRST_COLUMN, + PROP_DOCUMENT_ADDIN, + PROP_DOCUMENT_BASEDIAGRAM, + PROP_DOCUMENT_ADDITIONAL_SHAPES, + PROP_DOCUMENT_UPDATE_ADDIN, + PROP_DOCUMENT_NULL_DATE, + PROP_DOCUMENT_ENABLE_COMPLEX_CHARTTYPES, + PROP_DOCUMENT_ENABLE_DATATABLE_DIALOG +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "HasMainTitle", + PROP_DOCUMENT_HAS_MAIN_TITLE, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasSubTitle", + PROP_DOCUMENT_HAS_SUB_TITLE, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasLegend", + PROP_DOCUMENT_HAS_LEGEND, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + // really needed? + rOutProperties.emplace_back( "DataSourceLabelsInFirstRow", + PROP_DOCUMENT_LABELS_IN_FIRST_ROW, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataSourceLabelsInFirstColumn", + PROP_DOCUMENT_LABELS_IN_FIRST_COLUMN, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + //add-in + rOutProperties.emplace_back( "AddIn", + PROP_DOCUMENT_ADDIN, + cppu::UnoType<util::XRefreshable>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "BaseDiagram", + PROP_DOCUMENT_BASEDIAGRAM, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "AdditionalShapes", + PROP_DOCUMENT_ADDITIONAL_SHAPES, + cppu::UnoType<drawing::XShapes>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::READONLY ); + rOutProperties.emplace_back( "RefreshAddInAllowed", + PROP_DOCUMENT_UPDATE_ADDIN, + cppu::UnoType<bool>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::TRANSIENT ); + + // table:null-date // i99104 + rOutProperties.emplace_back( "NullDate", + PROP_DOCUMENT_NULL_DATE, + ::cppu::UnoType<css::util::DateTime>::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "EnableComplexChartTypes", + PROP_DOCUMENT_ENABLE_COMPLEX_CHARTTYPES, + cppu::UnoType<bool>::get(), + //#i112666# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "EnableDataTableDialog", + PROP_DOCUMENT_ENABLE_DATATABLE_DIALOG, + cppu::UnoType<bool>::get(), + //#i112666# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticChartDocumentWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticChartDocumentWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticChartDocumentWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +namespace { + +//PROP_DOCUMENT_LABELS_IN_FIRST_ROW +class WrappedDataSourceLabelsInFirstRowProperty : public WrappedProperty +{ +public: + explicit WrappedDataSourceLabelsInFirstRowProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedDataSourceLabelsInFirstRowProperty::WrappedDataSourceLabelsInFirstRowProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("DataSourceLabelsInFirstRow",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedDataSourceLabelsInFirstRowProperty::getPropertyDefault( nullptr ); +} + +void WrappedDataSourceLabelsInFirstRowProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bLabelsInFirstRow = true; + if( ! (rOuterValue >>= bLabelsInFirstRow) ) + throw lang::IllegalArgumentException("Property DataSourceLabelsInFirstRow requires value of type boolean", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + bool bNewValue = bLabelsInFirstRow; + + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( !DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + return; + + if( bUseColumns && bNewValue != bFirstCellAsLabel ) + { + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bUseColumns ,bNewValue, bHasCategories ); + } + else if( !bUseColumns && bNewValue != bHasCategories ) + { + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bUseColumns , bFirstCellAsLabel, bNewValue ); + } +} + +Any WrappedDataSourceLabelsInFirstRowProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + { + bool bLabelsInFirstRow = true; + if( bUseColumns ) + bLabelsInFirstRow = bFirstCellAsLabel; + else + bLabelsInFirstRow = bHasCategories; + + m_aOuterValue <<= bLabelsInFirstRow; + } + return m_aOuterValue; +} + +Any WrappedDataSourceLabelsInFirstRowProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= true; + return aRet; +} + +namespace { + +//PROP_DOCUMENT_LABELS_IN_FIRST_COLUMN +class WrappedDataSourceLabelsInFirstColumnProperty : public WrappedProperty +{ +public: + explicit WrappedDataSourceLabelsInFirstColumnProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedDataSourceLabelsInFirstColumnProperty::WrappedDataSourceLabelsInFirstColumnProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("DataSourceLabelsInFirstColumn",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedDataSourceLabelsInFirstColumnProperty::getPropertyDefault( nullptr ); +} + +void WrappedDataSourceLabelsInFirstColumnProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bLabelsInFirstRow = true; + if( ! (rOuterValue >>= bLabelsInFirstRow) ) + throw lang::IllegalArgumentException("Property DataSourceLabelsInFirstRow requires value of type boolean", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + bool bNewValue = bLabelsInFirstRow; + + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( !DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + return; + + if( bUseColumns && bNewValue != bHasCategories ) + { + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bUseColumns, bFirstCellAsLabel, bNewValue ); + } + else if( !bUseColumns && bNewValue != bFirstCellAsLabel ) + { + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bUseColumns , bNewValue, bHasCategories ); + } +} + +Any WrappedDataSourceLabelsInFirstColumnProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + { + bool bLabelsInFirstColumn = true; + if( bUseColumns ) + bLabelsInFirstColumn = bHasCategories; + else + bLabelsInFirstColumn = bFirstCellAsLabel; + + m_aOuterValue <<= bLabelsInFirstColumn; + } + return m_aOuterValue; +} + +Any WrappedDataSourceLabelsInFirstColumnProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= true; + return aRet; +} + +namespace { + +//PROP_DOCUMENT_HAS_LEGEND +class WrappedHasLegendProperty : public WrappedProperty +{ +public: + explicit WrappedHasLegendProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedHasLegendProperty::WrappedHasLegendProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("HasLegend",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedHasLegendProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException("Property HasLegend requires value of type boolean", nullptr, 0 ); + + try + { + rtl::Reference< Legend > xLegend = LegendHelper::getLegend( *m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext,bNewValue ); + if(xLegend.is()) + { + bool bOldValue = true; + Any aAOld = xLegend->getPropertyValue("Show"); + aAOld >>= bOldValue; + if( bOldValue != bNewValue ) + xLegend->setPropertyValue("Show", uno::Any( bNewValue )); + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedHasLegendProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + try + { + rtl::Reference< Legend > xLegend = + LegendHelper::getLegend( *m_spChart2ModelContact->getDocumentModel() ); + if( xLegend.is()) + aRet = xLegend->getPropertyValue("Show"); + else + aRet <<= false; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aRet; +} + +Any WrappedHasLegendProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DOCUMENT_HAS_MAIN_TITLE +class WrappedHasMainTitleProperty : public WrappedProperty +{ +public: + explicit WrappedHasMainTitleProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedHasMainTitleProperty::WrappedHasMainTitleProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("HasMainTitle",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedHasMainTitleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException("Property HasMainTitle requires value of type boolean", nullptr, 0 ); + + try + { + if( bNewValue ) + TitleHelper::createTitle( TitleHelper::MAIN_TITLE, "main-title", m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext ); + else + TitleHelper::removeTitle( TitleHelper::MAIN_TITLE, m_spChart2ModelContact->getDocumentModel() ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedHasMainTitleProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + try + { + aRet <<= TitleHelper::getTitle( TitleHelper::MAIN_TITLE, m_spChart2ModelContact->getDocumentModel() ).is(); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aRet; +} + +Any WrappedHasMainTitleProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DOCUMENT_HAS_SUB_TITLE +class WrappedHasSubTitleProperty : public WrappedProperty +{ +public: + explicit WrappedHasSubTitleProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedHasSubTitleProperty::WrappedHasSubTitleProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("HasSubTitle",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedHasSubTitleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException("Property HasSubTitle requires value of type boolean", nullptr, 0 ); + + try + { + if( bNewValue ) + TitleHelper::createTitle( TitleHelper::SUB_TITLE, "", m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext ); + else + TitleHelper::removeTitle( TitleHelper::SUB_TITLE, m_spChart2ModelContact->getDocumentModel() ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedHasSubTitleProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + try + { + aRet <<= TitleHelper::getTitle( TitleHelper::SUB_TITLE, m_spChart2ModelContact->getDocumentModel() ).is(); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aRet; +} + +Any WrappedHasSubTitleProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +ChartDocumentWrapper::ChartDocumentWrapper( + const Reference< uno::XComponentContext > & xContext ) : + m_spChart2ModelContact( std::make_shared<Chart2ModelContact>( xContext ) ), + m_bUpdateAddIn( true ), + m_bIsDisposed( false ) +{ +} + +ChartDocumentWrapper::~ChartDocumentWrapper() +{ + stopAllComponentListening(); +} + +// ____ XInterface (for new interfaces) ____ +uno::Any SAL_CALL ChartDocumentWrapper::queryInterface( const uno::Type& aType ) +{ + if( m_xDelegator.is()) + // calls queryAggregation if the delegator doesn't know aType + return m_xDelegator->queryInterface( aType ); + else + return queryAggregation( aType ); +} + +// ____ chart::XChartDocument (old API wrapper) ____ +Reference< drawing::XShape > SAL_CALL ChartDocumentWrapper::getTitle() +{ + if( !m_xTitle.is() ) + { + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + m_xTitle = new TitleWrapper( TitleHelper::MAIN_TITLE, m_spChart2ModelContact ); + } + return m_xTitle; +} + +Reference< drawing::XShape > SAL_CALL ChartDocumentWrapper::getSubTitle() +{ + if( !m_xSubTitle.is() ) + { + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + m_xSubTitle = new TitleWrapper( TitleHelper::SUB_TITLE, m_spChart2ModelContact ); + } + return m_xSubTitle; +} + +Reference< drawing::XShape > SAL_CALL ChartDocumentWrapper::getLegend() +{ + if( ! m_xLegend.is()) + { + m_xLegend = new LegendWrapper( m_spChart2ModelContact ); + } + + return m_xLegend; +} + +Reference< beans::XPropertySet > SAL_CALL ChartDocumentWrapper::getArea() +{ + if( ! m_xArea.is()) + { + m_xArea.set( new AreaWrapper( m_spChart2ModelContact ) ); + } + + return m_xArea; +} + +Reference< XDiagram > SAL_CALL ChartDocumentWrapper::getDiagram() +{ + if( !m_xDiagram.is() ) + { + try + { + m_xDiagram = new DiagramWrapper( m_spChart2ModelContact ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return m_xDiagram; +} + +void SAL_CALL ChartDocumentWrapper::setDiagram( const Reference< XDiagram >& xDiagram ) +{ + uno::Reference< util::XRefreshable > xAddIn( xDiagram, uno::UNO_QUERY ); + if( xAddIn.is() ) + { + setAddIn( xAddIn ); + } + else if( xDiagram.is() && xDiagram != m_xDiagram ) + { + // set new wrapped diagram at new chart. This requires the old + // diagram given as parameter to implement the new interface. If + // this is not possible throw an exception + Reference< chart2::XDiagramProvider > xNewDiaProvider( xDiagram, uno::UNO_QUERY_THROW ); + Reference< chart2::XDiagram > xNewDia( xNewDiaProvider->getDiagram()); + + try + { + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( xChartDoc.is() ) + { + // set the new diagram + xChartDoc->setFirstDiagram( xNewDia ); + m_xDiagram = xDiagram; + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +Reference< XChartData > SAL_CALL ChartDocumentWrapper::getData() +{ + if( !m_xChartData.is() ) + { + m_xChartData.set( new ChartDataWrapper( m_spChart2ModelContact ) ); + } + //@todo: check hasInternalDataProvider also in else? + + return m_xChartData; +} + +void SAL_CALL ChartDocumentWrapper::attachData( const Reference< XChartData >& xNewData ) +{ + if( !xNewData.is() ) + return; + + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + m_xChartData.set( new ChartDataWrapper( m_spChart2ModelContact, xNewData ) ); +} + +// ____ XModel ____ +sal_Bool SAL_CALL ChartDocumentWrapper::attachResource( + const OUString& URL, + const Sequence< beans::PropertyValue >& Arguments ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->attachResource( URL, Arguments ); + return false; +} + +OUString SAL_CALL ChartDocumentWrapper::getURL() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->getURL(); + return OUString(); +} + +Sequence< beans::PropertyValue > SAL_CALL ChartDocumentWrapper::getArgs() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->getArgs(); + return Sequence< beans::PropertyValue >(); +} + +void SAL_CALL ChartDocumentWrapper::connectController( const Reference< frame::XController >& Controller ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->connectController( Controller ); +} + +void SAL_CALL ChartDocumentWrapper::disconnectController( + const Reference< frame::XController >& Controller ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->disconnectController( Controller ); +} + +void SAL_CALL ChartDocumentWrapper::lockControllers() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->lockControllers(); +} + +void SAL_CALL ChartDocumentWrapper::unlockControllers() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->unlockControllers(); +} + +sal_Bool SAL_CALL ChartDocumentWrapper::hasControllersLocked() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->hasControllersLocked(); + return false; +} + +Reference< frame::XController > SAL_CALL ChartDocumentWrapper::getCurrentController() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->getCurrentController(); + return nullptr; +} + +void SAL_CALL ChartDocumentWrapper::setCurrentController( + const Reference< frame::XController >& Controller ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->setCurrentController( Controller ); +} + +Reference< uno::XInterface > SAL_CALL ChartDocumentWrapper::getCurrentSelection() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->getCurrentSelection(); + return nullptr; +} + +// ____ XComponent ____ +void SAL_CALL ChartDocumentWrapper::dispose() +{ + if( m_bIsDisposed ) + throw lang::DisposedException("ChartDocumentWrapper is disposed", + static_cast< ::cppu::OWeakObject* >( this )); + + m_bIsDisposed = true; + + try + { + Reference< lang::XComponent > xFormerDelegator( m_xDelegator, uno::UNO_QUERY ); + DisposeHelper::DisposeAndClear( m_xTitle ); + DisposeHelper::DisposeAndClear( m_xSubTitle ); + DisposeHelper::DisposeAndClear( m_xLegend ); + DisposeHelper::DisposeAndClear( m_xChartData ); + DisposeHelper::DisposeAndClear( m_xDiagram ); + DisposeHelper::DisposeAndClear( m_xArea ); + m_xChartView.set( nullptr ); + m_xShapeFactory.set( nullptr ); + m_xDelegator.set( nullptr ); + + clearWrappedPropertySet(); + m_spChart2ModelContact->clear(); + impl_resetAddIn(); + + stopAllComponentListening(); + + try + { + if( xFormerDelegator.is()) + xFormerDelegator->dispose(); + } + catch (const lang::DisposedException&) + { + // this is ok, don't panic + } + } + catch (const uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartDocumentWrapper::impl_resetAddIn() +{ + Reference< util::XRefreshable > xAddIn( m_xAddIn ); + m_xAddIn.set( nullptr ); + + if( !xAddIn.is() ) + return; + + try + { + //make sure that the add-in does not hold a references to us anymore: + Reference< lang::XComponent > xComp( xAddIn, uno::UNO_QUERY ); + if( xComp.is()) + xComp->dispose(); + else + { + uno::Reference< lang::XInitialization > xInit( xAddIn, uno::UNO_QUERY ); + if( xInit.is() ) + { + uno::Any aParam; + uno::Reference< css::chart::XChartDocument > xDoc; + aParam <<= xDoc; + uno::Sequence< uno::Any > aSeq( &aParam, 1 ); + xInit->initialize( aSeq ); + } + } + } + catch (const uno::RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartDocumentWrapper::setBaseDiagram( const OUString& rBaseDiagram ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + m_aBaseDiagram = rBaseDiagram; + + uno::Reference< XDiagram > xDiagram( ChartDocumentWrapper::createInstance( rBaseDiagram ), uno::UNO_QUERY ); + if( xDiagram.is() ) + setDiagram( xDiagram ); +} + +void ChartDocumentWrapper::setAddIn( const Reference< util::XRefreshable >& xAddIn ) +{ + if( m_xAddIn == xAddIn ) + return; + + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + impl_resetAddIn(); + m_xAddIn = xAddIn; + // initialize AddIn with this as chart document + uno::Reference< lang::XInitialization > xInit( m_xAddIn, uno::UNO_QUERY ); + if( xInit.is() ) + { + uno::Any aParam; + uno::Reference< XChartDocument > xDoc(this); + aParam <<= xDoc; + uno::Sequence< uno::Any > aSeq( &aParam, 1 ); + xInit->initialize( aSeq ); + } +} + +void ChartDocumentWrapper::setUpdateAddIn( bool bUpdateAddIn ) +{ + m_bUpdateAddIn = bUpdateAddIn; +} + +Reference< drawing::XShapes > ChartDocumentWrapper::getAdditionalShapes() const +{ + // get additional non-chart shapes for XML export + uno::Reference< drawing::XShapes > xFoundShapes; + rtl::Reference<SvxDrawPage> xDrawPage( impl_getDrawPage() ); + + if( !xDrawPage.is() ) + return xFoundShapes; + + uno::Reference<drawing::XShapes> xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); + + // iterate 'flat' over all top-level objects + // and determine all that are no chart objects + std::vector< uno::Reference< drawing::XShape > > aShapeVector; + sal_Int32 nSubCount = xDrawPage->getCount(); + uno::Reference< drawing::XShape > xShape; + for( sal_Int32 nS = 0; nS < nSubCount; nS++ ) + { + if( xDrawPage->getByIndex( nS ) >>= xShape ) + { + if( xShape.is() && xChartRoot!=xShape ) + aShapeVector.push_back( xShape ); + } + } + + if( !aShapeVector.empty() ) + { + // create a shape collection + xFoundShapes = drawing::ShapeCollection::create( + comphelper::getProcessComponentContext()); + + OSL_ENSURE( xFoundShapes.is(), "Couldn't create a shape collection!" ); + if( xFoundShapes.is()) + { + for (auto const& shape : aShapeVector) + xFoundShapes->add(shape); + } + } + + return xFoundShapes; +} + +void SAL_CALL ChartDocumentWrapper::addEventListener( const Reference< lang::XEventListener >& xListener ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->addEventListener( xListener ); +} + +void SAL_CALL ChartDocumentWrapper::removeEventListener( const Reference< lang::XEventListener >& aListener ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->removeEventListener( aListener ); +} + +// ____ XDrawPageSupplier ____ +uno::Reference< drawing::XDrawPage > SAL_CALL ChartDocumentWrapper::getDrawPage() +{ + return impl_getDrawPage(); +} + +rtl::Reference<SvxDrawPage> ChartDocumentWrapper::impl_getDrawPage() const +{ + return m_spChart2ModelContact->getDrawPage(); +} + +namespace { + +uno::Reference< lang::XMultiServiceFactory > getShapeFactory(const uno::Reference<uno::XInterface>& xChartView) +{ + auto pProvider = comphelper::getFromUnoTunnel<ExplicitValueProvider>(xChartView); + if( pProvider ) + return pProvider->getDrawModelWrapper()->getShapeFactory(); + + return uno::Reference< lang::XMultiServiceFactory >(); +} + +} + +// ____ XMultiServiceFactory ____ +uno::Reference< uno::XInterface > SAL_CALL ChartDocumentWrapper::createInstance( + const OUString& aServiceSpecifier ) +{ + uno::Reference< uno::XInterface > xResult; + + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( !xChartDoc.is() ) + return xResult; + + bool bServiceFound = false; + tServiceNameMap & rMap = lcl_getStaticServiceNameMap(); + + tServiceNameMap::const_iterator aIt( rMap.find( aServiceSpecifier )); + if( aIt != rMap.end()) + { + bool bCreateDiagram = false; + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = + xChartDoc->getTypeManager(); + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + + switch( (*aIt).second ) + { + case SERVICE_NAME_AREA_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Area"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_BAR_DIAGRAM: + if( xChartTypeManager.is()) + { + // this is for bar and column (the latter is the default if + // no "Vertical=false" property was set) + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Column"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_DONUT_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Donut"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_LINE_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Line"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_NET_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Net"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_FILLED_NET_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.FilledNet"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_PIE_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Pie"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_STOCK_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.StockLowHighClose"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_XY_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.ScatterLineSymbol"); + bCreateDiagram = true; + } + break; + + case SERVICE_NAME_BUBBLE_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Bubble"); + bCreateDiagram = true; + } + break; + + case SERVICE_NAME_DASH_TABLE: + case SERVICE_NAME_GRADIENT_TABLE: + case SERVICE_NAME_HATCH_TABLE: + case SERVICE_NAME_BITMAP_TABLE: + case SERVICE_NAME_TRANSP_GRADIENT_TABLE: + case SERVICE_NAME_MARKER_TABLE: + xResult.set( xChartDoc->createInstance( aIt->first ), uno::UNO_QUERY ); + break; + + case SERVICE_NAME_NAMESPACE_MAP: + break; + case SERVICE_NAME_EXPORT_GRAPHIC_STORAGE_RESOLVER: + break; + case SERVICE_NAME_IMPORT_GRAPHIC_STORAGE_RESOLVER: + break; + } + + if( bCreateDiagram && xTemplate.is() ) + { + try + { + uno::Reference< chart2::XDiagram > xDia( xChartDoc->getFirstDiagram()); + if( xDia.is()) + { + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartDoc ); + ThreeDLookScheme e3DScheme = ThreeDHelper::detectScheme( xDiagram ); + rtl::Reference< ::chart::ChartTypeManager > xTemplateManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateWithService( + DiagramHelper::getTemplateForDiagram( xDiagram, xTemplateManager )); + if( aTemplateWithService.xChartTypeTemplate.is()) + aTemplateWithService.xChartTypeTemplate->resetStyles2( xDiagram );//#i109371# + xTemplate->changeDiagram( xDiagram ); + if( AllSettings::GetMathLayoutRTL() ) + AxisHelper::setRTLAxisLayout( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ) ); + ThreeDHelper::setScheme( xDiagram, e3DScheme ); + } + else + { + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + xDia.set( xTemplate->createDiagramByDataSource( + uno::Reference< chart2::data::XDataSource >(), + uno::Sequence< beans::PropertyValue >())); + xChartDoc->setFirstDiagram( xDia ); + } + + xResult = static_cast< ::cppu::OWeakObject* >( new DiagramWrapper( m_spChart2ModelContact )); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + bServiceFound = true; + } + else if( aServiceSpecifier == "com.sun.star.comp.chart2.DataSeriesWrapper" ) + { + Reference< beans::XPropertySet > xDataSeries( new DataSeriesPointWrapper( m_spChart2ModelContact ) ); + xResult.set( xDataSeries ); + bServiceFound = true; + } + else if( aServiceSpecifier == CHART_VIEW_SERVICE_NAME ) + { + if( !m_xChartView.is() ) + { + rtl::Reference<::chart::ChartModel> pChartModel = new ::chart::ChartModel(m_spChart2ModelContact->m_xContext); + rtl::Reference<ChartView> xChartView = new ::chart::ChartView(m_spChart2ModelContact->m_xContext, *pChartModel); + + try + { + m_xChartView = xChartView; + + Sequence< Any > aArguments{ Any(Reference<frame::XModel>(this)), + Any(true) }; // bRefreshAddIn + xChartView->initialize(aArguments); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + xResult.set( static_cast<cppu::OWeakObject*>(m_xChartView.get()) ); + bServiceFound = true; + } + else + { + // try to create a shape + try + { + if( !m_xShapeFactory.is() && m_xChartView.is() ) + { + m_xShapeFactory = getShapeFactory( static_cast<cppu::OWeakObject*>(m_xChartView.get()) ); + } + else + { + rtl::Reference<ChartModel> pModel = m_spChart2ModelContact->getDocumentModel(); + if(pModel) + { + m_xChartView = pModel->getChartView(); + m_xShapeFactory = getShapeFactory( static_cast<cppu::OWeakObject*>(m_xChartView.get()) ); + } + } + + if( m_xShapeFactory.is() ) + { + xResult = m_xShapeFactory->createInstance( aServiceSpecifier ); + bServiceFound = true; + } + } + catch (const uno::Exception&) + { + // couldn't create shape + } + } + + // finally, try to create an addin + if( !bServiceFound ) + { + try + { + Reference< lang::XMultiServiceFactory > xFact( + m_spChart2ModelContact->m_xContext->getServiceManager(), uno::UNO_QUERY_THROW ); + uno::Reference< util::XRefreshable > xAddIn( + xFact->createInstance( aServiceSpecifier ), uno::UNO_QUERY ); + if( xAddIn.is() ) + { + xResult = xAddIn; + } + } + catch (const uno::Exception&) + { + // couldn't create service + } + } + + return xResult; +} + +uno::Reference< uno::XInterface > SAL_CALL ChartDocumentWrapper::createInstanceWithArguments( + const OUString& ServiceSpecifier, + const uno::Sequence< uno::Any >& Arguments ) +{ + OSL_ENSURE( Arguments.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" ); + + return createInstance( ServiceSpecifier ); +} + +uno::Sequence< OUString > SAL_CALL ChartDocumentWrapper::getAvailableServiceNames() +{ + return comphelper::mapKeysToSequence( lcl_getStaticServiceNameMap() ); +} + +// ____ XAggregation ____ +void SAL_CALL ChartDocumentWrapper::setDelegator( + const uno::Reference< uno::XInterface >& rDelegator ) +{ + if( m_bIsDisposed ) + { + if( rDelegator.is() ) + throw lang::DisposedException("ChartDocumentWrapper is disposed", + static_cast< ::cppu::OWeakObject* >( this )); + return; + } + + if( rDelegator.is()) + { + m_xDelegator = rDelegator; + ChartModel* pChartModel = dynamic_cast<ChartModel*>(rDelegator.get()); + assert(pChartModel); + m_spChart2ModelContact->setDocumentModel( pChartModel ); + } + else + { + // this is a sort of dispose() from the new model,so release resources here + try + { + dispose(); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +uno::Any SAL_CALL ChartDocumentWrapper::queryAggregation( const uno::Type& rType ) +{ + return ChartDocumentWrapper_Base::queryInterface( rType ); +} + +// ____ ::utl::OEventListenerAdapter ____ +void ChartDocumentWrapper::_disposing( const lang::EventObject& rSource ) +{ + if( rSource.Source == m_xTitle ) + m_xTitle.set( nullptr ); + else if( rSource.Source == m_xSubTitle ) + m_xSubTitle.set( nullptr ); + else if( rSource.Source == m_xLegend ) + m_xLegend.set( nullptr ); + else if( rSource.Source == m_xChartData ) + m_xChartData.set( nullptr ); + else if( rSource.Source == m_xDiagram ) + m_xDiagram.set( nullptr ); + else if( rSource.Source == m_xArea ) + m_xArea.set( nullptr ); + else if( rSource.Source == m_xAddIn ) + m_xAddIn.set( nullptr ); + else if( rSource.Source == static_cast<cppu::OWeakObject*>(m_xChartView.get()) ) + m_xChartView.set( nullptr ); +} + +// WrappedPropertySet +Reference< beans::XPropertySet > ChartDocumentWrapper::getInnerPropertySet() +{ + return nullptr; +} +const Sequence< beans::Property >& ChartDocumentWrapper::getPropertySequence() +{ + return *StaticChartDocumentWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > ChartDocumentWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + aWrappedProperties.emplace_back( new WrappedDataSourceLabelsInFirstRowProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedDataSourceLabelsInFirstColumnProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedHasLegendProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedHasMainTitleProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedHasSubTitleProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedAddInProperty( *this ) ); + aWrappedProperties.emplace_back( new WrappedBaseDiagramProperty( *this ) ); + aWrappedProperties.emplace_back( new WrappedAdditionalShapesProperty( *this ) ); + aWrappedProperties.emplace_back( new WrappedRefreshAddInAllowedProperty( *this ) ); + aWrappedProperties.emplace_back( new WrappedIgnoreProperty("NullDate",Any() ) ); // i99104 + aWrappedProperties.emplace_back( new WrappedIgnoreProperty("EnableComplexChartTypes", uno::Any(true) ) ); + aWrappedProperties.emplace_back( new WrappedIgnoreProperty("EnableDataTableDialog", uno::Any(true) ) ); + + return aWrappedProperties; +} + +OUString SAL_CALL ChartDocumentWrapper::getImplementationName() +{ + return CHART_CHARTAPIWRAPPER_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartDocumentWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartDocumentWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartDocument", + CHART_CHARTAPIWRAPPER_SERVICE_NAME, + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.beans.PropertySet" + }; +} + +} // namespace chart::wrapper + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartDocumentWrapper_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::wrapper::ChartDocumentWrapper(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.cxx b/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.cxx new file mode 100644 index 000000000..40e4df69c --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.cxx @@ -0,0 +1,899 @@ +/* -*- 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 "DataSeriesPointWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <DiagramHelper.hxx> +#include <DataSeries.hxx> +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <CharacterProperties.hxx> +#include <UserDefinedProperties.hxx> +#include "WrappedCharacterHeightProperty.hxx" +#include <WrappedProperty.hxx> +#include <WrappedIgnoreProperty.hxx> +#include "WrappedStatisticProperties.hxx" +#include "WrappedSymbolProperties.hxx" +#include "WrappedDataCaptionProperties.hxx" +#include "WrappedSeriesAreaOrLineProperty.hxx" +#include "WrappedScaleTextProperties.hxx" +#include "WrappedNumberFormatProperty.hxx" +#include "WrappedTextRotationProperty.hxx" +#include <unonames.hxx> + +#include <o3tl/safeint.hxx> +#include <rtl/math.hxx> + +#include <algorithm> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/chart/ChartAxisAssign.hpp> +#include <com/sun/star/chart/ChartErrorCategory.hpp> +#include <com/sun/star/chart/ChartSymbolType.hpp> +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <com/sun/star/drawing/LineJoint.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <comphelper/sequence.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/propshlp.hxx> + +using namespace ::com::sun::star; +using namespace ::chart::wrapper; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Any; + +namespace +{ + +enum +{ + //data point properties + PROP_SERIES_DATAPOINT_SOLIDTYPE, + PROP_SERIES_DATAPOINT_SEGMENT_OFFSET, + PROP_SERIES_DATAPOINT_PERCENT_DIAGONAL, + PROP_SERIES_DATAPOINT_LABEL_SEPARATOR, + PROP_SERIES_NUMBERFORMAT, + PROP_SERIES_LINK_NUMBERFORMAT_TO_SOURCE, + PROP_SERIES_PERCENTAGE_NUMBERFORMAT, + PROP_SERIES_DATAPOINT_TEXT_WORD_WRAP, + PROP_SERIES_DATAPOINT_LABEL_PLACEMENT, + //other series properties + PROP_SERIES_ATTACHED_AXIS, + PROP_SERIES_SHOW_CUSTOM_LEADERLINES, + PROP_SERIES_DATAPOINT_TEXT_ROTATION, + PROP_SERIES_DATAPOINT_LABEL_BORDER_STYLE, + PROP_SERIES_DATAPOINT_LABEL_BORDER_WIDTH, + PROP_SERIES_DATAPOINT_LABEL_BORDER_COLOR, + PROP_SERIES_DATAPOINT_LABEL_BORDER_TRANS, + PROP_SERIES_DATAPOINT_LABEL_FILL_STYLE, + PROP_SERIES_DATAPOINT_LABEL_FILL_COLOR, + PROP_SERIES_DATAPOINT_LABEL_FILL_BACKGROUND, + PROP_SERIES_DATAPOINT_LABEL_FILL_HATCH_NAME +}; + +void lcl_AddPropertiesToVector_PointProperties( + std::vector< Property > & rOutProperties ) +{ + //service chart::Chart3DBarProperties + rOutProperties.emplace_back( "SolidType", + PROP_SERIES_DATAPOINT_SOLIDTYPE, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "SegmentOffset", + PROP_SERIES_DATAPOINT_SEGMENT_OFFSET, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "D3DPercentDiagonal", + PROP_SERIES_DATAPOINT_PERCENT_DIAGONAL, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LabelSeparator", + PROP_SERIES_DATAPOINT_LABEL_SEPARATOR, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_NUMFMT, + PROP_SERIES_NUMBERFORMAT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( CHART_UNONAME_LINK_TO_SRC_NUMFMT, + PROP_SERIES_LINK_NUMBERFORMAT_TO_SOURCE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "PercentageNumberFormat", + PROP_SERIES_PERCENTAGE_NUMBERFORMAT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "TextWordWrap", + PROP_SERIES_DATAPOINT_TEXT_WORD_WRAP, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LabelPlacement", + PROP_SERIES_DATAPOINT_LABEL_PLACEMENT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "TextRotation", + PROP_SERIES_DATAPOINT_TEXT_ROTATION, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_STYLE, + PROP_SERIES_DATAPOINT_LABEL_BORDER_STYLE, + cppu::UnoType<drawing::LineStyle>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_STYLE, + PROP_SERIES_DATAPOINT_LABEL_FILL_STYLE, + cppu::UnoType<drawing::FillStyle>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_COLOR, + PROP_SERIES_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_SERIES_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_SERIES_DATAPOINT_LABEL_FILL_HATCH_NAME, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_WIDTH, + PROP_SERIES_DATAPOINT_LABEL_BORDER_WIDTH, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_COLOR, + PROP_SERIES_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_BORDER_TRANS, + PROP_SERIES_DATAPOINT_LABEL_BORDER_TRANS, + cppu::UnoType<sal_Int16>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void lcl_AddPropertiesToVector_SeriesOnly( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Axis", + PROP_SERIES_ATTACHED_AXIS, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ShowCustomLeaderLines", + PROP_SERIES_SHOW_CUSTOM_LEADERLINES, + cppu::UnoType<sal_Bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +uno::Sequence< Property > lcl_GetPropertySequence( DataSeriesPointWrapper::eType _eType ) +{ + std::vector< css::beans::Property > aProperties; + + lcl_AddPropertiesToVector_PointProperties( aProperties ); + if( _eType == DataSeriesPointWrapper::DATA_SERIES ) + { + lcl_AddPropertiesToVector_SeriesOnly( aProperties ); + WrappedStatisticProperties::addProperties( aProperties ); + } + WrappedSymbolProperties::addProperties( aProperties ); //for series and points + WrappedDataCaptionProperties::addProperties( aProperties ); //for series and points + + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::wrapper::WrappedScaleTextProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); +} + +struct StaticSeriesWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence( DataSeriesPointWrapper::DATA_SERIES ) ); + return &aPropSeq; + } +}; + +struct StaticSeriesWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticSeriesWrapperPropertyArray_Initializer > +{ +}; + +struct StaticPointWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence( DataSeriesPointWrapper::DATA_POINT ) ); + return &aPropSeq; + } +}; + +struct StaticPointWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticPointWrapperPropertyArray_Initializer > +{ +}; + +//PROP_SERIES_ATTACHED_AXIS +class WrappedAttachedAxisProperty : public ::chart::WrappedProperty +{ +public: + explicit WrappedAttachedAxisProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +WrappedAttachedAxisProperty::WrappedAttachedAxisProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) + : WrappedProperty("Axis",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +Any WrappedAttachedAxisProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= css::chart::ChartAxisAssign::PRIMARY_Y; + return aRet; +} + +Any WrappedAttachedAxisProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet; + + uno::Reference< chart2::XDataSeries > xDataSeries( xInnerPropertySet, uno::UNO_QUERY ); + bool bAttachedToMainAxis = ::chart::DiagramHelper::isSeriesAttachedToMainAxis( xDataSeries ); + if( bAttachedToMainAxis ) + aRet <<= css::chart::ChartAxisAssign::PRIMARY_Y; + else + aRet <<= css::chart::ChartAxisAssign::SECONDARY_Y; + return aRet; +} + +void WrappedAttachedAxisProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + uno::Reference< chart2::XDataSeries > xDataSeries( xInnerPropertySet, uno::UNO_QUERY ); + + sal_Int32 nChartAxisAssign = css::chart::ChartAxisAssign::PRIMARY_Y; + if( ! (rOuterValue >>= nChartAxisAssign) ) + throw lang::IllegalArgumentException("Property Axis requires value of type sal_Int32", nullptr, 0 ); + + bool bNewAttachedToMainAxis = nChartAxisAssign == css::chart::ChartAxisAssign::PRIMARY_Y; + bool bOldAttachedToMainAxis = ::chart::DiagramHelper::isSeriesAttachedToMainAxis( xDataSeries ); + + if( bNewAttachedToMainAxis != bOldAttachedToMainAxis) + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + ::chart::DiagramHelper::attachSeriesToAxis( bNewAttachedToMainAxis, xDataSeries, xDiagram, m_spChart2ModelContact->m_xContext, false ); + } +} + +class WrappedSegmentOffsetProperty : public ::chart::WrappedProperty +{ +public: + WrappedSegmentOffsetProperty(); + +protected: + virtual Any convertInnerToOuterValue( const Any& rInnerValue ) const override; + virtual Any convertOuterToInnerValue( const Any& rOuterValue ) const override; +}; + +WrappedSegmentOffsetProperty::WrappedSegmentOffsetProperty() : + WrappedProperty("SegmentOffset","Offset") +{} + +Any WrappedSegmentOffsetProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + // convert new double offset to former integer segment-offset + double fOffset = 0; + Any aResult( rInnerValue ); + + if( rInnerValue >>= fOffset ) + aResult <<= static_cast< sal_Int32 >( ::rtl::math::round( fOffset * 100.0 )); + + return aResult; +} + +Any WrappedSegmentOffsetProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + // convert former integer segment-offset to new double offset + sal_Int32 nOffset = 0; + Any aResult( rOuterValue ); + + if( rOuterValue >>= nOffset ) + aResult <<= static_cast< double >( nOffset ) / 100.0; + + return aResult; +} + +class WrappedLineColorProperty : public WrappedSeriesAreaOrLineProperty +{ +public: + explicit WrappedLineColorProperty( DataSeriesPointWrapper* pDataSeriesPointWrapper ); + + virtual void setPropertyValue( const Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual void setPropertyToDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + DataSeriesPointWrapper* m_pDataSeriesPointWrapper; + mutable Any m_aDefaultValue; +}; + +WrappedLineColorProperty::WrappedLineColorProperty( + DataSeriesPointWrapper* pDataSeriesPointWrapper ) + : WrappedSeriesAreaOrLineProperty("LineColor","BorderColor","Color", pDataSeriesPointWrapper ) + , m_pDataSeriesPointWrapper( pDataSeriesPointWrapper ) + , m_aDefaultValue(uno::Any(sal_Int32( 0x0099ccff ))) // blue 8 +{ +} + +void WrappedLineColorProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !m_pDataSeriesPointWrapper || !m_pDataSeriesPointWrapper->isLinesForbidden() ) + WrappedSeriesAreaOrLineProperty::setPropertyValue( rOuterValue, xInnerPropertySet ); +} + +void WrappedLineColorProperty::setPropertyToDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( !m_pDataSeriesPointWrapper || !m_pDataSeriesPointWrapper->isLinesForbidden() ) + WrappedSeriesAreaOrLineProperty::setPropertyToDefault( xInnerPropertyState ); +} + +Any WrappedLineColorProperty::getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( m_pDataSeriesPointWrapper && !m_pDataSeriesPointWrapper->isSupportingAreaProperties() ) + return m_aDefaultValue; + else + return WrappedSeriesAreaOrLineProperty::getPropertyDefault( xInnerPropertyState ); +} + +class WrappedLineStyleProperty : public WrappedSeriesAreaOrLineProperty +{ +public: + explicit WrappedLineStyleProperty( DataSeriesPointWrapper* pDataSeriesPointWrapper ); + + virtual void setPropertyValue( const Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual void setPropertyToDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + DataSeriesPointWrapper* m_pDataSeriesPointWrapper; +}; + +WrappedLineStyleProperty::WrappedLineStyleProperty( + DataSeriesPointWrapper* pDataSeriesPointWrapper ) + : WrappedSeriesAreaOrLineProperty("LineStyle","BorderStyle", "LineStyle", pDataSeriesPointWrapper ) + , m_pDataSeriesPointWrapper( pDataSeriesPointWrapper ) +{ +} + +void WrappedLineStyleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aNewValue(rOuterValue); + if( m_pDataSeriesPointWrapper && m_pDataSeriesPointWrapper->isLinesForbidden() ) + { + aNewValue <<= drawing::LineStyle_NONE; + } + WrappedSeriesAreaOrLineProperty::setPropertyValue( aNewValue, xInnerPropertySet ); +} + +void WrappedLineStyleProperty::setPropertyToDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( !m_pDataSeriesPointWrapper || !m_pDataSeriesPointWrapper->isLinesForbidden() ) + WrappedSeriesAreaOrLineProperty::setPropertyToDefault( xInnerPropertyState ); +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +DataSeriesPointWrapper::DataSeriesPointWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact( spChart2ModelContact ) + , m_aEventListenerContainer( m_aMutex ) + , m_eType( DATA_SERIES ) + , m_nSeriesIndexInNewAPI( -1 ) + , m_nPointIndex( -1 ) + , m_bLinesAllowed(true) +{ + //need initialize call afterwards +} + +void SAL_CALL DataSeriesPointWrapper::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + OSL_PRECOND(aArguments.hasElements(),"need at least 1 argument to initialize the DataSeriesPointWrapper: series reference + optional datapoint index"); + + m_nSeriesIndexInNewAPI = -1;//ignored in this case + m_nPointIndex = -1; + if( aArguments.hasElements() ) + { + uno::Reference<chart2::XDataSeries> xTmp; + aArguments[0] >>= xTmp; + auto p = dynamic_cast<DataSeries*>(xTmp.get()); + assert(p); + m_xDataSeries = p; + if( aArguments.getLength() >= 2 ) + aArguments[1] >>= m_nPointIndex; + } + + if( !m_xDataSeries.is() ) + throw uno::Exception( + "DataSeries index invalid", static_cast< ::cppu::OWeakObject * >( this )); + + //todo: check upper border of point index + + if( m_nPointIndex >= 0 ) + m_eType = DATA_POINT; + else + m_eType = DATA_SERIES; +} + +DataSeriesPointWrapper::DataSeriesPointWrapper(eType _eType, + sal_Int32 nSeriesIndexInNewAPI , + sal_Int32 nPointIndex, //ignored for series + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact( spChart2ModelContact ) + , m_aEventListenerContainer( m_aMutex ) + , m_eType( _eType ) + , m_nSeriesIndexInNewAPI( nSeriesIndexInNewAPI ) + , m_nPointIndex( (_eType == DATA_POINT) ? nPointIndex : -1 ) + , m_bLinesAllowed( false ) +{ +} + +DataSeriesPointWrapper::~DataSeriesPointWrapper() +{ +} + +// ____ XComponent ____ +void SAL_CALL DataSeriesPointWrapper::dispose() +{ + uno::Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + m_xDataSeries.clear(); + clearWrappedPropertySet(); +} + +void SAL_CALL DataSeriesPointWrapper::addEventListener( + const uno::Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL DataSeriesPointWrapper::removeEventListener( + const uno::Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// ____ XEventListener ____ +void SAL_CALL DataSeriesPointWrapper::disposing( const lang::EventObject& /*Source*/ ) +{ +} + +bool DataSeriesPointWrapper::isSupportingAreaProperties() +{ + rtl::Reference< DataSeries > xSeries( getDataSeries() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< ::chart::ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) ); + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + + return ChartTypeHelper::isSupportingAreaProperties( xChartType, nDimensionCount ); +} + +rtl::Reference< DataSeries > DataSeriesPointWrapper::getDataSeries() +{ + rtl::Reference< DataSeries > xSeries = m_xDataSeries; + if( !xSeries.is() ) + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + std::vector< rtl::Reference< DataSeries > > aSeriesList = + ::chart::DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + if( m_nSeriesIndexInNewAPI >= 0 && o3tl::make_unsigned(m_nSeriesIndexInNewAPI) < aSeriesList.size() ) + xSeries = aSeriesList[m_nSeriesIndexInNewAPI]; + } + + return xSeries; +} + +Reference< beans::XPropertySet > DataSeriesPointWrapper::getDataPointProperties() +{ + Reference< beans::XPropertySet > xPointProp; + + rtl::Reference< DataSeries > xSeries( getDataSeries() ); + + // may throw an IllegalArgumentException + if( xSeries.is() ) + xPointProp = xSeries->getDataPointByIndex( m_nPointIndex ); + + return xPointProp; +} + +//ReferenceSizePropertyProvider +void DataSeriesPointWrapper::updateReferenceSize() +{ + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); + if( xProp.is() ) + { + if( xProp->getPropertyValue("ReferencePageSize").hasValue() ) + xProp->setPropertyValue("ReferencePageSize", uno::Any( + m_spChart2ModelContact->GetPageSize() )); + } +} +Any DataSeriesPointWrapper::getReferenceSize() +{ + Any aRet; + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); + if( xProp.is() ) + aRet = xProp->getPropertyValue("ReferencePageSize"); + return aRet; +} +awt::Size DataSeriesPointWrapper::getCurrentSizeForReference() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +// WrappedPropertySet + +//XPropertyState +beans::PropertyState SAL_CALL DataSeriesPointWrapper::getPropertyState( const OUString& rPropertyName ) +{ + beans::PropertyState aState( beans::PropertyState_DIRECT_VALUE ); + try + { + if (rPropertyName == "SymbolBitmap" || rPropertyName == "SymbolBitmapURL") + { + uno::Any aAny = WrappedPropertySet::getPropertyValue("SymbolType"); + sal_Int32 nVal = css::chart::ChartSymbolType::NONE; + if (aAny >>= nVal) + { + if (nVal != css::chart::ChartSymbolType::BITMAPURL) + return beans::PropertyState::PropertyState_DEFAULT_VALUE; + } + } + + if( m_eType == DATA_SERIES ) + aState = WrappedPropertySet::getPropertyState( rPropertyName ); + else + { + if( rPropertyName == "FillColor") + { + rtl::Reference< DataSeries > xSeriesProp = getDataSeries(); + bool bVaryColorsByPoint = false; + if( xSeriesProp.is() && (xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint) + && bVaryColorsByPoint ) + return beans::PropertyState_DIRECT_VALUE; + } + else if( rPropertyName == "Lines" + || rPropertyName == "SymbolType" + || rPropertyName == "SymbolSize" ) + return WrappedPropertySet::getPropertyState( rPropertyName ); + + uno::Any aDefault( getPropertyDefault( rPropertyName ) ); + uno::Any aValue( getPropertyValue( rPropertyName ) ); + if( aDefault==aValue ) + aState = beans::PropertyState_DEFAULT_VALUE; + } + } + catch( const beans::UnknownPropertyException& ) + { + throw; + } + catch( const uno::RuntimeException& ) + { + throw; + } + catch( const lang::WrappedTargetException& e ) + { + css::uno::Any a(e.TargetException); + throw css::lang::WrappedTargetRuntimeException( + "wrapped Exception " + e.Message, + css::uno::Reference<css::uno::XInterface>(), a); + } + catch( const uno::Exception& e ) + { + css::uno::Any a(cppu::getCaughtException()); + throw css::lang::WrappedTargetRuntimeException( + "wrapped Exception " + e.Message, + css::uno::Reference<css::uno::XInterface>(), a); + } + return aState; +} + +void SAL_CALL DataSeriesPointWrapper::setPropertyToDefault( const OUString& rPropertyName ) +{ + if( m_eType == DATA_SERIES ) + WrappedPropertySet::setPropertyToDefault( rPropertyName ); + else + { + //for data points the default is given by the series + setPropertyValue( rPropertyName, getPropertyDefault( rPropertyName ) ); + } +} +Any SAL_CALL DataSeriesPointWrapper::getPropertyDefault( const OUString& rPropertyName ) +{ + Any aRet; + try + { + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( nHandle > 0 ) + { + //always take the series current value as default for points + rtl::Reference< DataSeries > xInnerPropertySet = getDataSeries(); + if( xInnerPropertySet.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + aRet = pWrappedProperty->getPropertyValue(xInnerPropertySet); + else + aRet = xInnerPropertySet->getPropertyValue( rPropertyName ); + } + } + } + catch( const beans::UnknownPropertyException& ) + { + aRet = WrappedPropertySet::getPropertyDefault( rPropertyName ); + } + return aRet; +} + +Reference< beans::XPropertySet > DataSeriesPointWrapper::getInnerPropertySet() +{ + if( m_eType == DATA_SERIES ) + return getDataSeries(); + return getDataPointProperties(); +} + +const Sequence< beans::Property >& DataSeriesPointWrapper::getPropertySequence() +{ + if( m_eType == DATA_SERIES ) + return *StaticSeriesWrapperPropertyArray::get(); + else + return *StaticPointWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > DataSeriesPointWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + + WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); + + if( m_eType == DATA_SERIES ) + { + WrappedStatisticProperties::addWrappedPropertiesForSeries( aWrappedProperties, m_spChart2ModelContact ); + aWrappedProperties.emplace_back( new WrappedAttachedAxisProperty( m_spChart2ModelContact ) ); + + aWrappedProperties.emplace_back( new WrappedNumberFormatProperty(m_spChart2ModelContact) ); + aWrappedProperties.emplace_back( new WrappedLinkNumberFormatProperty ); + } + + WrappedSymbolProperties::addWrappedPropertiesForSeries( aWrappedProperties, m_spChart2ModelContact ); + WrappedDataCaptionProperties::addWrappedPropertiesForSeries( aWrappedProperties, m_spChart2ModelContact ); + WrappedScaleTextProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + //add unnamed line properties (different inner names here) + + aWrappedProperties.emplace_back( new WrappedProperty("FillColor","Color") ); + aWrappedProperties.emplace_back( new WrappedLineStyleProperty( this ) ); + aWrappedProperties.emplace_back( new WrappedLineColorProperty( this ) ); + aWrappedProperties.emplace_back( new WrappedSeriesAreaOrLineProperty("LineDashName","BorderDashName","LineDashName", this ) ); + aWrappedProperties.emplace_back( new WrappedSeriesAreaOrLineProperty("LineTransparence","BorderTransparency","Transparency", this ) ); + aWrappedProperties.emplace_back( new WrappedSeriesAreaOrLineProperty("LineWidth","BorderWidth","LineWidth", this ) ); + aWrappedProperties.emplace_back( new WrappedSeriesAreaOrLineProperty("LineCap","LineCap","LineCap", this ) ); + aWrappedProperties.emplace_back( new WrappedProperty("FillStyle","FillStyle" ) ); + aWrappedProperties.emplace_back( new WrappedProperty("FillTransparence","Transparency") ); + + aWrappedProperties.emplace_back( new WrappedIgnoreProperty("LineJoint", uno::Any( drawing::LineJoint_ROUND ) ) ); + aWrappedProperties.emplace_back( new WrappedProperty("FillTransparenceGradientName","TransparencyGradientName") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillGradientName","GradientName") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillGradientStepCount","GradientStepCount") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillHatchName","HatchName") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapName","FillBitmapName") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBackground","FillBackground") ); + + //bitmap properties + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapMode","FillBitmapMode") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapSizeX","FillBitmapSizeX") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapSizeY","FillBitmapSizeY") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapLogicalSize","FillBitmapLogicalSize") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapOffsetX","FillBitmapOffsetX") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapOffsetY","FillBitmapOffsetY") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapRectanglePoint","FillBitmapRectanglePoint") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapPositionOffsetX","FillBitmapPositionOffsetX") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapPositionOffsetY","FillBitmapPositionOffsetY") ); + + aWrappedProperties.emplace_back( new WrappedProperty("SolidType","Geometry3D") ); + aWrappedProperties.emplace_back( new WrappedSegmentOffsetProperty() ); + aWrappedProperties.emplace_back( new WrappedProperty("D3DPercentDiagonal","PercentDiagonal") ); + + aWrappedProperties.emplace_back( new WrappedTextRotationProperty() ); + + return aWrappedProperties; +} + +void SAL_CALL DataSeriesPointWrapper::setPropertyValue( const OUString& rPropertyName, const Any& rValue ) +{ + if(rPropertyName == "Lines") + { + if( ! (rValue >>= m_bLinesAllowed) ) + throw lang::IllegalArgumentException("Property Lines requires value of type sal_Bool", nullptr, 0 ); + } + + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + static const sal_Int32 nErrorCategoryHandle = getInfoHelper().getHandleByName("ErrorCategory"); + if( nErrorCategoryHandle == nHandle ) + { + css::chart::ChartErrorCategory aNewValue = css::chart::ChartErrorCategory_NONE; + rValue >>= aNewValue; + Any aLow, aHigh; + bool bSetHighAndLowValues = false; + switch(aNewValue) + { + case css::chart::ChartErrorCategory_CONSTANT_VALUE: + aHigh = getPropertyValue("ConstantErrorHigh"); + aLow = getPropertyValue("ConstantErrorLow"); + bSetHighAndLowValues = true; + break; + case css::chart::ChartErrorCategory_PERCENT: + aHigh = aLow = getPropertyValue("PercentageError"); + bSetHighAndLowValues = true; + break; + case css::chart::ChartErrorCategory_ERROR_MARGIN: + aHigh = aLow = getPropertyValue("ErrorMargin"); + bSetHighAndLowValues = true; + break; + default: + break; + } + + WrappedPropertySet::setPropertyValue( rPropertyName, rValue ); + + if(bSetHighAndLowValues) + { + switch(aNewValue) + { + case css::chart::ChartErrorCategory_CONSTANT_VALUE: + setPropertyValue("ConstantErrorHigh",aHigh); + setPropertyValue("ConstantErrorLow",aLow); + break; + case css::chart::ChartErrorCategory_PERCENT: + setPropertyValue("PercentageError",aHigh); + break; + case css::chart::ChartErrorCategory_ERROR_MARGIN: + setPropertyValue("ErrorMargin",aHigh); + break; + default: + break; + } + } + } + else + WrappedPropertySet::setPropertyValue( rPropertyName, rValue ); +} + +Any SAL_CALL DataSeriesPointWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + if( m_eType == DATA_POINT ) + { + if( rPropertyName == "FillColor" ) + { + rtl::Reference< DataSeries > xSeriesProp = getDataSeries(); + bool bVaryColorsByPoint = false; + if( xSeriesProp.is() && (xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint) + && bVaryColorsByPoint ) + { + uno::Reference< beans::XPropertyState > xPointState( DataSeriesPointWrapper::getDataPointProperties(), uno::UNO_QUERY ); + if( xPointState.is() && xPointState->getPropertyState("Color") == beans::PropertyState_DEFAULT_VALUE ) + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + Reference< chart2::XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme() ); + if( xColorScheme.is() ) + return uno::Any( xColorScheme->getColorByIndex( m_nPointIndex ) ); + } + } + } + } + } + return WrappedPropertySet::getPropertyValue( rPropertyName ); +} + +OUString SAL_CALL DataSeriesPointWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.DataSeries"; +} + +sal_Bool SAL_CALL DataSeriesPointWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DataSeriesPointWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartDataRowProperties", + "com.sun.star.chart.ChartDataPointProperties", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.beans.PropertySet", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties", + "com.sun.star.style.CharacterProperties" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.hxx b/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.hxx new file mode 100644 index 000000000..8936ec418 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.hxx @@ -0,0 +1,124 @@ +/* -*- 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 <WrappedPropertySet.hxx> +#include "ReferenceSizePropertyProvider.hxx" +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <rtl/ref.hxx> +#include <memory> + +namespace com::sun::star::chart2 { class XDataSeries; } +namespace chart { class DataSeries; } + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class DataSeriesPointWrapper final : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::lang::XServiceInfo + , css::lang::XInitialization + , css::lang::XComponent + , css::lang::XEventListener + > + , public ReferenceSizePropertyProvider + +{ +public: + enum eType + { + DATA_SERIES, + DATA_POINT + }; + + //this constructor needs an initialize call afterwards + explicit DataSeriesPointWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + DataSeriesPointWrapper(eType eType + , sal_Int32 nSeriesIndexInNewAPI + , sal_Int32 nPointIndex //ignored for series + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual ~DataSeriesPointWrapper() override; + + bool isSupportingAreaProperties(); + bool isLinesForbidden() const { return !m_bLinesAllowed;} + + /// 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; + + // ___lang::XInitialization___ + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + //ReferenceSizePropertyProvider + virtual void updateReferenceSize() override; + virtual css::uno::Any getReferenceSize() override; + virtual css::awt::Size getCurrentSizeForReference() override; + +private: + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // ____ XEventListener ____ + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + //own methods + rtl::Reference< ::chart::DataSeries > getDataSeries(); + css::uno::Reference< css::beans::XPropertySet > getDataPointProperties(); + + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; + + eType m_eType; + sal_Int32 m_nSeriesIndexInNewAPI; + sal_Int32 m_nPointIndex; + + bool m_bLinesAllowed; + + //this should only be used, if the DataSeriesPointWrapper is initialized via the XInitialize interface + //because a big change in the chartmodel may lead to a dataseriespointer that is not connected to the model anymore + //with the indices instead we can always get the new dataseries + rtl::Reference< ::chart::DataSeries > m_xDataSeries; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx b/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx new file mode 100644 index 000000000..85df10b87 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx @@ -0,0 +1,1918 @@ +/* -*- 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 "DiagramWrapper.hxx" +#include <servicenames_charttypes.hxx> +#include "DataSeriesPointWrapper.hxx" +#include "AxisWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include "WallFloorWrapper.hxx" +#include "MinMaxLineWrapper.hxx" +#include "UpDownBarWrapper.hxx" +#include <Diagram.hxx> +#include <DiagramHelper.hxx> +#include <DataSourceHelper.hxx> +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <DataSeries.hxx> +#include <WrappedIgnoreProperty.hxx> +#include "WrappedAxisAndGridExistenceProperties.hxx" +#include "WrappedStatisticProperties.hxx" +#include "WrappedSymbolProperties.hxx" +#include "WrappedDataCaptionProperties.hxx" +#include "WrappedSplineProperties.hxx" +#include "WrappedStockProperties.hxx" +#include "WrappedSceneProperty.hxx" +#include <ControllerLockGuard.hxx> +#include <DisposeHelper.hxx> +#include "WrappedAutomaticPositionProperties.hxx" +#include <CommonConverters.hxx> +#include <unonames.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <ChartTypeManager.hxx> +#include <ChartTypeTemplate.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/chart/ChartDataRowSource.hpp> +#include <com/sun/star/chart2/RelativeSize.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart/ChartSolidType.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> + +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <UserDefinedProperties.hxx> +#include <SceneProperties.hxx> + +#include <algorithm> +#include <map> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <tools/diagnose_ex.h> +#include <o3tl/string_view.hxx> + +using namespace ::com::sun::star; +using namespace ::chart::wrapper; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; +using ::com::sun::star::chart::XAxis; +using ::osl::MutexGuard; + +namespace +{ + +enum +{ + PROP_DIAGRAM_ATTRIBUTED_DATA_POINTS, + PROP_DIAGRAM_PERCENT_STACKED, + PROP_DIAGRAM_STACKED, + PROP_DIAGRAM_THREE_D, + PROP_DIAGRAM_SOLIDTYPE, + PROP_DIAGRAM_DEEP, + PROP_DIAGRAM_VERTICAL, + PROP_DIAGRAM_NUMBER_OF_LINES, + PROP_DIAGRAM_STACKED_BARS_CONNECTED, + PROP_DIAGRAM_DATAROW_SOURCE, + + PROP_DIAGRAM_GROUP_BARS_PER_AXIS, + PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, + + PROP_DIAGRAM_SORT_BY_X_VALUES, + + 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_HAS_X_AXIS, + PROP_DIAGRAM_HAS_X_AXIS_DESCR, + PROP_DIAGRAM_HAS_X_AXIS_TITLE, + PROP_DIAGRAM_HAS_X_AXIS_GRID, + PROP_DIAGRAM_HAS_X_AXIS_HELP_GRID, + + PROP_DIAGRAM_HAS_Y_AXIS, + PROP_DIAGRAM_HAS_Y_AXIS_DESCR, + PROP_DIAGRAM_HAS_Y_AXIS_TITLE, + PROP_DIAGRAM_HAS_Y_AXIS_GRID, + PROP_DIAGRAM_HAS_Y_AXIS_HELP_GRID, + + PROP_DIAGRAM_HAS_Z_AXIS, + PROP_DIAGRAM_HAS_Z_AXIS_DESCR, + PROP_DIAGRAM_HAS_Z_AXIS_TITLE, + PROP_DIAGRAM_HAS_Z_AXIS_GRID, + PROP_DIAGRAM_HAS_Z_AXIS_HELP_GRID, + + PROP_DIAGRAM_HAS_SECOND_X_AXIS, + PROP_DIAGRAM_HAS_SECOND_X_AXIS_DESCR, + + PROP_DIAGRAM_HAS_SECOND_Y_AXIS, + PROP_DIAGRAM_HAS_SECOND_Y_AXIS_DESCR, + + PROP_DIAGRAM_HAS_SECOND_X_AXIS_TITLE, + PROP_DIAGRAM_HAS_SECOND_Y_AXIS_TITLE, + + PROP_DIAGRAM_AUTOMATIC_SIZE, + PROP_DIAGRAM_DATATABLEHBORDER, + PROP_DIAGRAM_DATATABLEVBORDER, + PROP_DIAGRAM_DATATABLEOUTLINE, + PROP_DIAGRAM_EXTERNALDATA +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "AttributedDataPoints", + PROP_DIAGRAM_ATTRIBUTED_DATA_POINTS, + cppu::UnoType<uno::Sequence< uno::Sequence< sal_Int32 > >>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + // see com.sun.star.chart.StackableDiagram + rOutProperties.emplace_back( "Percent", + PROP_DIAGRAM_PERCENT_STACKED, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Stacked", + PROP_DIAGRAM_STACKED, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Dim3D", + PROP_DIAGRAM_THREE_D, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // see com.sun.star.chart.Chart3DBarProperties + rOutProperties.emplace_back( "SolidType", + PROP_DIAGRAM_SOLIDTYPE, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // see com.sun.star.chart.BarDiagram + rOutProperties.emplace_back( "Deep", + PROP_DIAGRAM_DEEP, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Vertical", + PROP_DIAGRAM_VERTICAL, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "NumberOfLines", + PROP_DIAGRAM_NUMBER_OF_LINES, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "StackedBarsConnected", + PROP_DIAGRAM_STACKED_BARS_CONNECTED, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "DataRowSource", + PROP_DIAGRAM_DATAROW_SOURCE, + cppu::UnoType<css::chart::ChartDataRowSource>::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 ); + + //new for XY charts + rOutProperties.emplace_back( CHART_UNONAME_SORT_BY_XVALUES, + PROP_DIAGRAM_SORT_BY_X_VALUES, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //for pie and donut charts + rOutProperties.emplace_back( "StartingAngle", + PROP_DIAGRAM_STARTING_ANGLE, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //new for 3D charts + 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 ); + + // XAxisXSupplier + rOutProperties.emplace_back( "HasXAxis", + PROP_DIAGRAM_HAS_X_AXIS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasXAxisDescription", + PROP_DIAGRAM_HAS_X_AXIS_DESCR, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasXAxisTitle", + PROP_DIAGRAM_HAS_X_AXIS_TITLE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasXAxisGrid", + PROP_DIAGRAM_HAS_X_AXIS_GRID, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasXAxisHelpGrid", + PROP_DIAGRAM_HAS_X_AXIS_HELP_GRID, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XAxisYSupplier + rOutProperties.emplace_back( "HasYAxis", + PROP_DIAGRAM_HAS_Y_AXIS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasYAxisDescription", + PROP_DIAGRAM_HAS_Y_AXIS_DESCR, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasYAxisTitle", + PROP_DIAGRAM_HAS_Y_AXIS_TITLE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasYAxisGrid", + PROP_DIAGRAM_HAS_Y_AXIS_GRID, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasYAxisHelpGrid", + PROP_DIAGRAM_HAS_Y_AXIS_HELP_GRID, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XAxisZSupplier + rOutProperties.emplace_back( "HasZAxis", + PROP_DIAGRAM_HAS_Z_AXIS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasZAxisDescription", + PROP_DIAGRAM_HAS_Z_AXIS_DESCR, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasZAxisTitle", + PROP_DIAGRAM_HAS_Z_AXIS_TITLE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasZAxisGrid", + PROP_DIAGRAM_HAS_Z_AXIS_GRID, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasZAxisHelpGrid", + PROP_DIAGRAM_HAS_Z_AXIS_HELP_GRID, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XTwoAxisXSupplier + rOutProperties.emplace_back( "HasSecondaryXAxis", + PROP_DIAGRAM_HAS_SECOND_X_AXIS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasSecondaryXAxisDescription", + PROP_DIAGRAM_HAS_SECOND_X_AXIS_DESCR, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XTwoAxisYSupplier + rOutProperties.emplace_back( "HasSecondaryYAxis", + PROP_DIAGRAM_HAS_SECOND_Y_AXIS, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasSecondaryYAxisDescription", + PROP_DIAGRAM_HAS_SECOND_Y_AXIS_DESCR, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XSecondAxisTitleSupplier + rOutProperties.emplace_back( "HasSecondaryXAxisTitle", + PROP_DIAGRAM_HAS_SECOND_X_AXIS_TITLE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasSecondaryYAxisTitle", + PROP_DIAGRAM_HAS_SECOND_Y_AXIS_TITLE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MissingValueTreatment", + PROP_DIAGRAM_MISSING_VALUE_TREATMENT, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "AutomaticSize", + PROP_DIAGRAM_AUTOMATIC_SIZE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataTableHBorder", + PROP_DIAGRAM_DATATABLEHBORDER, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataTableVBorder", + PROP_DIAGRAM_DATATABLEVBORDER, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataTableOutline", + PROP_DIAGRAM_DATATABLEOUTLINE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ExternalData", + PROP_DIAGRAM_EXTERNALDATA, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +struct StaticDiagramWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::SceneProperties::AddPropertiesToVector( aProperties ); + WrappedStatisticProperties::addProperties( aProperties ); + WrappedSymbolProperties::addProperties( aProperties ); + WrappedDataCaptionProperties::addProperties( aProperties ); + WrappedSplineProperties::addProperties( aProperties ); + WrappedStockProperties::addProperties( aProperties ); + WrappedAutomaticPositionProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticDiagramWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticDiagramWrapperPropertyArray_Initializer > +{ +}; + +bool lcl_isXYChart( const rtl::Reference< ::chart::Diagram >& rDiagram ) +{ + bool bRet = false; + rtl::Reference< ::chart::ChartType > xChartType( ::chart::DiagramHelper::getChartTypeByIndex( rDiagram, 0 ) ); + if( xChartType.is() ) + { + OUString aChartType( xChartType->getChartType() ); + if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) ) + bRet = true; + } + return bRet; +} + +sal_Int32 lcl_getNewAPIIndexForOldAPIIndex( + sal_Int32 nOldAPIIndex + , const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + sal_Int32 nNewAPIIndex = nOldAPIIndex; + + if( lcl_isXYChart( xDiagram ) ) + { + if( nNewAPIIndex >= 1 ) + nNewAPIIndex -= 1; + } + + std::vector< rtl::Reference< ::chart::DataSeries > > aSeriesList = + ::chart::DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + if( nNewAPIIndex >= static_cast<sal_Int32>(aSeriesList.size()) ) + nNewAPIIndex = -1; + + return nNewAPIIndex; +} + +OUString lcl_getDiagramType( std::u16string_view rTemplateServiceName ) +{ + static const OUStringLiteral aPrefix(u"com.sun.star.chart2.template."); + + if( o3tl::starts_with(rTemplateServiceName, aPrefix) ) + { + const std::u16string_view aName( rTemplateServiceName.substr( aPrefix.getLength())); + + // "Area" "StackedArea" "PercentStackedArea" "ThreeDArea" + // "StackedThreeDArea" "PercentStackedThreeDArea" + if( aName.find( u"Area" ) != std::u16string_view::npos ) + return "com.sun.star.chart.AreaDiagram"; + + // "Pie" "PieAllExploded" "ThreeDPie" "ThreeDPieAllExploded" + if( aName.find( u"Pie" ) != std::u16string_view::npos ) + return "com.sun.star.chart.PieDiagram"; + + // "Column" "StackedColumn" "PercentStackedColumn" "ThreeDColumnDeep" + // "ThreeDColumnFlat" "StackedThreeDColumnFlat" + // "PercentStackedThreeDColumnFlat" "Bar" "StackedBar" + // "PercentStackedBar" "ThreeDBarDeep" "ThreeDBarFlat" + // "StackedThreeDBarFlat" "PercentStackedThreeDBarFlat" "ColumnWithLine" + // "StackedColumnWithLine" + if( aName.find( u"Column" ) != std::u16string_view::npos || aName.find( u"Bar" ) != std::u16string_view::npos ) + return "com.sun.star.chart.BarDiagram"; + + // "Donut" "DonutAllExploded" "ThreeDDonut" "ThreeDDonutAllExploded" + if( aName.find( u"Donut" ) != std::u16string_view::npos ) + return "com.sun.star.chart.DonutDiagram"; + + // "ScatterLineSymbol" "ScatterLine" "ScatterSymbol" "ThreeDScatter" + if( aName.find( u"Scatter" ) != std::u16string_view::npos ) + return "com.sun.star.chart.XYDiagram"; + + // "FilledNet" "StackedFilledNet" "PercentStackedFilledNet" + if( aName.find( u"FilledNet" ) != std::u16string_view::npos ) + return "com.sun.star.chart.FilledNetDiagram"; + + // "Net" "NetSymbol" "NetLine" "StackedNet" "StackedNetSymbol" + // "StackedNetLine" "PercentStackedNet" "PercentStackedNetSymbol" + // "PercentStackedNetLine" + if( aName.find( u"Net" ) != std::u16string_view::npos ) + return "com.sun.star.chart.NetDiagram"; + + // "StockLowHighClose" "StockOpenLowHighClose" "StockVolumeLowHighClose" + // "StockVolumeOpenLowHighClose" + if( aName.find( u"Stock" ) != std::u16string_view::npos ) + return "com.sun.star.chart.StockDiagram"; + + if( aName.find( u"Bubble" ) != std::u16string_view::npos ) + return "com.sun.star.chart.BubbleDiagram"; + + // Note: this must be checked after Bar, Net and Scatter + + // "Symbol" "StackedSymbol" "PercentStackedSymbol" "Line" "StackedLine" + // "PercentStackedLine" "LineSymbol" "StackedLineSymbol" + // "PercentStackedLineSymbol" "ThreeDLine" "StackedThreeDLine" + // "PercentStackedThreeDLine" "ThreeDLineDeep" + if( aName.find( u"Line" ) != std::u16string_view::npos || aName.find( u"Symbol" ) != std::u16string_view::npos ) + return "com.sun.star.chart.LineDiagram"; + + OSL_FAIL( "unknown template" ); + } + + return OUString(); +} + +typedef std::map< OUString, OUString > tMakeStringStringMap; + +const tMakeStringStringMap& lcl_getChartTypeNameMap() +{ + static tMakeStringStringMap g_aChartTypeNameMap{ + {"com.sun.star.chart2.LineChartType", "com.sun.star.chart.LineDiagram"}, + {"com.sun.star.chart2.AreaChartType", "com.sun.star.chart.AreaDiagram"}, + {"com.sun.star.chart2.ColumnChartType", "com.sun.star.chart.BarDiagram"}, + {"com.sun.star.chart2.PieChartType", "com.sun.star.chart.PieDiagram"}, + {"com.sun.star.chart2.DonutChartType", "com.sun.star.chart.DonutDiagram"}, + {"com.sun.star.chart2.ScatterChartType", "com.sun.star.chart.XYDiagram"}, + {"com.sun.star.chart2.FilledNetChartType", "com.sun.star.chart.FilledNetDiagram"}, + {"com.sun.star.chart2.NetChartType", "com.sun.star.chart.NetDiagram"}, + {"com.sun.star.chart2.CandleStickChartType", "com.sun.star.chart.StockDiagram"}, + {"com.sun.star.chart2.BubbleChartType", "com.sun.star.chart.BubbleDiagram"} + }; + return g_aChartTypeNameMap; +} + +OUString lcl_getOldChartTypeName( const OUString & rNewChartTypeName ) +{ + OUString aOld(rNewChartTypeName); + + const tMakeStringStringMap& rMap = lcl_getChartTypeNameMap(); + tMakeStringStringMap::const_iterator aIt( rMap.find( rNewChartTypeName )); + if( aIt != rMap.end()) + { + aOld = aIt->second; + } + return aOld; +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +DiagramWrapper::DiagramWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) +{ +} + +DiagramWrapper::~DiagramWrapper() +{} + +// ____ XDiagram ____ +OUString SAL_CALL DiagramWrapper::getDiagramType() +{ + OUString aRet; + + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xChartDoc.is() && xDiagram.is() ) + { + Reference< beans::XPropertySet > xChartDocProp( static_cast<cppu::OWeakObject*>(xChartDoc.get()), uno::UNO_QUERY ); + if( xChartDocProp.is() ) + { + uno::Reference< util::XRefreshable > xAddIn; + if( xChartDocProp->getPropertyValue( "AddIn" ) >>= xAddIn ) + { + uno::Reference< lang::XServiceName > xServiceName( xAddIn, uno::UNO_QUERY ); + if( xServiceName.is()) + return xServiceName->getServiceName(); + } + } + + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + aRet = lcl_getDiagramType( aTemplateAndService.sServiceName ); + } + + if( aRet.isEmpty()) + { + // none of the standard templates matched + // use first chart type + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + if( xChartType.is() ) + { + aRet = xChartType->getChartType(); + if( !aRet.isEmpty() ) + aRet = lcl_getOldChartTypeName( aRet ); + } + if( aRet.isEmpty()) + aRet = "com.sun.star.chart.BarDiagram"; + } + + return aRet; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getDataRowProperties( sal_Int32 nRow ) +{ + if( nRow < 0 ) + throw lang::IndexOutOfBoundsException("DataSeries index invalid", + static_cast< ::cppu::OWeakObject * >( this )); + + sal_Int32 nNewAPIIndex = lcl_getNewAPIIndexForOldAPIIndex( nRow, m_spChart2ModelContact->getDiagram() ); + if( nNewAPIIndex < 0 ) + throw lang::IndexOutOfBoundsException("DataSeries index invalid", + static_cast< ::cppu::OWeakObject * >( this )); + + Reference< beans::XPropertySet > xRet( new DataSeriesPointWrapper( + DataSeriesPointWrapper::DATA_SERIES, nNewAPIIndex, 0, m_spChart2ModelContact ) ); + return xRet; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getDataPointProperties( sal_Int32 nCol, sal_Int32 nRow ) +{ + if( nCol < 0 || nRow < 0 ) + throw lang::IndexOutOfBoundsException("DataSeries index invalid", + static_cast< ::cppu::OWeakObject * >( this )); + + sal_Int32 nNewAPIIndex = lcl_getNewAPIIndexForOldAPIIndex( nRow, m_spChart2ModelContact->getDiagram() ); + if( nNewAPIIndex < 0 ) + throw lang::IndexOutOfBoundsException("DataSeries index invalid", + static_cast< ::cppu::OWeakObject * >( this )); + + //todo: check borders of point index + + Reference< beans::XPropertySet > xRet( new DataSeriesPointWrapper( + DataSeriesPointWrapper::DATA_POINT, nNewAPIIndex, nCol, m_spChart2ModelContact ) ); + + return xRet; +} + +// ____ XShape (base of XDiagram) ____ +awt::Point SAL_CALL DiagramWrapper::getPosition() +{ + awt::Point aPosition = ToPoint( m_spChart2ModelContact->GetDiagramRectangleIncludingAxes() ); + return aPosition; +} + +void SAL_CALL DiagramWrapper::setPosition( const awt::Point& aPosition ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + Reference< beans::XPropertySet > xProp( getInnerPropertySet() ); + if( !xProp.is() ) + return; + + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT; + aRelativePosition.Primary = double(aPosition.X)/double(aPageSize.Width); + aRelativePosition.Secondary = double(aPosition.Y)/double(aPageSize.Height); + if( aRelativePosition.Primary < 0 || aRelativePosition.Secondary < 0 || aRelativePosition.Primary > 1 || aRelativePosition.Secondary > 1 ) + { + OSL_FAIL("DiagramWrapper::setPosition called with a position out of range -> automatic values are taken instead" ); + uno::Any aEmpty; + xProp->setPropertyValue( "RelativePosition", aEmpty ); + return; + } + xProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + xProp->setPropertyValue( "PosSizeExcludeAxes", uno::Any(false) ); +} + +awt::Size SAL_CALL DiagramWrapper::getSize() +{ + awt::Size aSize = ToSize( m_spChart2ModelContact->GetDiagramRectangleIncludingAxes() ); + return aSize; +} + +void SAL_CALL DiagramWrapper::setSize( const awt::Size& aSize ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + Reference< beans::XPropertySet > xProp( getInnerPropertySet() ); + if( !xProp.is() ) + return; + + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + + chart2::RelativeSize aRelativeSize; + aRelativeSize.Primary = double(aSize.Width)/double(aPageSize.Width); + aRelativeSize.Secondary = double(aSize.Height)/double(aPageSize.Height); + + if( aRelativeSize.Primary > 1 || aRelativeSize.Secondary > 1 ) + { + OSL_FAIL("DiagramWrapper::setSize called with sizes bigger than page -> automatic values are taken instead" ); + uno::Any aEmpty; + xProp->setPropertyValue( "RelativeSize", aEmpty ); + return; + } + + xProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) ); + xProp->setPropertyValue( "PosSizeExcludeAxes", uno::Any(false) ); +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL DiagramWrapper::getShapeType() +{ + return "com.sun.star.chart.Diagram"; +} + +// ____ XDiagramPositioning ____ + +void SAL_CALL DiagramWrapper::setAutomaticDiagramPositioning() +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + { + xDiaProps->setPropertyValue( "RelativeSize", Any() ); + xDiaProps->setPropertyValue( "RelativePosition", Any() ); + } +} +sal_Bool SAL_CALL DiagramWrapper::isAutomaticDiagramPositioning( ) +{ + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + { + Any aRelativeSize( xDiaProps->getPropertyValue( "RelativeSize" ) ); + Any aRelativePosition( xDiaProps->getPropertyValue( "RelativePosition" ) ); + if( aRelativeSize.hasValue() && aRelativePosition.hasValue() ) + return false; + } + return true; +} +void SAL_CALL DiagramWrapper::setDiagramPositionExcludingAxes( const awt::Rectangle& rPositionRect ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + DiagramHelper::setDiagramPositioning( m_spChart2ModelContact->getDocumentModel(), rPositionRect ); + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + xDiaProps->setPropertyValue("PosSizeExcludeAxes", uno::Any(true) ); +} +sal_Bool SAL_CALL DiagramWrapper::isExcludingDiagramPositioning() +{ + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + { + Any aRelativeSize( xDiaProps->getPropertyValue( "RelativeSize" ) ); + Any aRelativePosition( xDiaProps->getPropertyValue( "RelativePosition" ) ); + if( aRelativeSize.hasValue() && aRelativePosition.hasValue() ) + { + bool bPosSizeExcludeAxes = false; + xDiaProps->getPropertyValue( "PosSizeExcludeAxes" ) >>= bPosSizeExcludeAxes; + return bPosSizeExcludeAxes; + } + } + return false; +} +awt::Rectangle SAL_CALL DiagramWrapper::calculateDiagramPositionExcludingAxes( ) +{ + return m_spChart2ModelContact->GetDiagramRectangleExcludingAxes(); +} +void SAL_CALL DiagramWrapper::setDiagramPositionIncludingAxes( const awt::Rectangle& rPositionRect ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + DiagramHelper::setDiagramPositioning( m_spChart2ModelContact->getDocumentModel(), rPositionRect ); + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + xDiaProps->setPropertyValue("PosSizeExcludeAxes", uno::Any(false) ); +} +awt::Rectangle SAL_CALL DiagramWrapper::calculateDiagramPositionIncludingAxes( ) +{ + return m_spChart2ModelContact->GetDiagramRectangleIncludingAxes(); +} +void SAL_CALL DiagramWrapper::setDiagramPositionIncludingAxesAndAxisTitles( const awt::Rectangle& rPositionRect ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + awt::Rectangle aRect( m_spChart2ModelContact->SubstractAxisTitleSizes(rPositionRect) ); + DiagramWrapper::setDiagramPositionIncludingAxes( aRect ); +} +css::awt::Rectangle SAL_CALL DiagramWrapper::calculateDiagramPositionIncludingAxesAndAxisTitles( ) +{ + return m_spChart2ModelContact->GetDiagramRectangleIncludingTitle(); +} + +// ____ XAxisSupplier ____ +Reference< XAxis > SAL_CALL DiagramWrapper::getAxis( sal_Int32 nDimensionIndex ) +{ + Reference< XAxis > xAxis; + if(!nDimensionIndex) + { + if( !m_xXAxis.is() ) + m_xXAxis = new AxisWrapper( AxisWrapper::X_AXIS, m_spChart2ModelContact ); + xAxis = m_xXAxis; + } + else if(nDimensionIndex==1) + { + if( !m_xYAxis.is() ) + m_xYAxis = new AxisWrapper( AxisWrapper::Y_AXIS, m_spChart2ModelContact ); + xAxis = m_xYAxis; + } + else if(nDimensionIndex==2) + { + if( !m_xZAxis.is() ) + m_xZAxis = new AxisWrapper( AxisWrapper::Z_AXIS, m_spChart2ModelContact ); + xAxis = m_xZAxis; + } + return xAxis; +} + +Reference< XAxis > SAL_CALL DiagramWrapper::getSecondaryAxis( sal_Int32 nDimensionIndex ) +{ + Reference< XAxis > xAxis; + if(!nDimensionIndex) + { + if( !m_xSecondXAxis.is() ) + m_xSecondXAxis = new AxisWrapper( AxisWrapper::SECOND_X_AXIS, m_spChart2ModelContact ); + xAxis = m_xSecondXAxis; + } + else if(nDimensionIndex==1) + { + if( !m_xSecondYAxis.is() ) + m_xSecondYAxis = new AxisWrapper( AxisWrapper::SECOND_Y_AXIS, m_spChart2ModelContact ); + xAxis = m_xSecondYAxis; + } + return xAxis; +} + +// ____ XAxisZSupplier ____ +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getZAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getAxis(2) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getZMainGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(2) ); + if( xAxis.is() ) + xRet = xAxis->getMajorGrid(); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getZHelpGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(2) ); + if( xAxis.is() ) + xRet = xAxis->getMinorGrid(); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getZAxis() +{ + if( ! m_xZAxis.is()) + m_xZAxis = new AxisWrapper( AxisWrapper::Z_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xZAxis, uno::UNO_QUERY ); +} + +// ____ XTwoAxisXSupplier ____ +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getSecondaryXAxis() +{ + if( ! m_xSecondXAxis.is()) + m_xSecondXAxis = new AxisWrapper( AxisWrapper::SECOND_X_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xSecondXAxis, uno::UNO_QUERY ); +} + +// ____ XAxisXSupplier (base of XTwoAxisXSupplier) ____ +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getXAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getAxis(0) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getXAxis() +{ + if( ! m_xXAxis.is()) + m_xXAxis = new AxisWrapper( AxisWrapper::X_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xXAxis, uno::UNO_QUERY ); +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getXMainGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(0) ); + if( xAxis.is() ) + xRet = xAxis->getMajorGrid(); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getXHelpGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(0) ); + if( xAxis.is() ) + xRet = xAxis->getMinorGrid(); + return xRet; +} + +// ____ XTwoAxisYSupplier ____ +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getSecondaryYAxis() +{ + if( ! m_xSecondYAxis.is()) + m_xSecondYAxis = new AxisWrapper( AxisWrapper::SECOND_Y_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xSecondYAxis, uno::UNO_QUERY ); +} + +// ____ XAxisYSupplier (base of XTwoAxisYSupplier) ____ +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getYAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getAxis(1) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getYAxis() +{ + if( ! m_xYAxis.is()) + m_xYAxis = new AxisWrapper( AxisWrapper::Y_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xYAxis, uno::UNO_QUERY ); +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getYMainGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(1) ); + if( xAxis.is() ) + xRet = xAxis->getMajorGrid(); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getYHelpGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(1) ); + if( xAxis.is() ) + xRet = xAxis->getMinorGrid(); + return xRet; +} + +// ____ XSecondAxisTitleSupplier ____ +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getSecondXAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getSecondaryAxis(0) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getSecondYAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getSecondaryAxis(1) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +// ____ XStatisticDisplay ____ +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getUpBar() +{ + if( !m_xUpBarWrapper.is() ) + { + m_xUpBarWrapper = new UpDownBarWrapper( true, m_spChart2ModelContact ); + } + return m_xUpBarWrapper; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getDownBar() +{ + if( !m_xDownBarWrapper.is() ) + { + m_xDownBarWrapper = new UpDownBarWrapper( false, m_spChart2ModelContact ); + } + return m_xDownBarWrapper; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getMinMaxLine() +{ + if( !m_xMinMaxLineWrapper.is() ) + { + m_xMinMaxLineWrapper = new MinMaxLineWrapper( m_spChart2ModelContact ); + } + return m_xMinMaxLineWrapper; +} + +// ____ X3DDisplay ____ +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getWall() +{ + if( !m_xWall.is() ) + { + m_xWall = new WallFloorWrapper( true, m_spChart2ModelContact ); + } + return m_xWall; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getFloor() +{ + if( !m_xFloor.is() ) + { + m_xFloor = new WallFloorWrapper( false, m_spChart2ModelContact ); + } + return m_xFloor; +} + +// ____ X3DDefaultSetter ____ +void SAL_CALL DiagramWrapper::set3DSettingsToDefault() +{ + rtl::Reference< ::chart::Diagram > x3DDefaultSetter( m_spChart2ModelContact->getDiagram() ); + if( x3DDefaultSetter.is() ) + x3DDefaultSetter->set3DSettingsToDefault(); +} + +void SAL_CALL DiagramWrapper::setDefaultRotation() +{ + rtl::Reference< ::chart::Diagram > x3DDefaultSetter( m_spChart2ModelContact->getDiagram() ); + if( x3DDefaultSetter.is() ) + x3DDefaultSetter->setDefaultRotation(); +} + +void SAL_CALL DiagramWrapper::setDefaultIllumination() +{ + rtl::Reference< ::chart::Diagram > x3DDefaultSetter( m_spChart2ModelContact->getDiagram() ); + if( x3DDefaultSetter.is() ) + x3DDefaultSetter->setDefaultIllumination(); +} + +// ____ XComponent ____ +void SAL_CALL DiagramWrapper::dispose() +{ + m_aEventListenerContainer.disposeAndClear( lang::EventObject( static_cast< ::cppu::OWeakObject* >( this ))); + + MutexGuard aGuard( m_aMutex); + + DisposeHelper::DisposeAndClear( m_xXAxis ); + DisposeHelper::DisposeAndClear( m_xYAxis ); + DisposeHelper::DisposeAndClear( m_xZAxis ); + DisposeHelper::DisposeAndClear( m_xSecondXAxis ); + DisposeHelper::DisposeAndClear( m_xSecondYAxis ); + DisposeHelper::DisposeAndClear( m_xWall ); + DisposeHelper::DisposeAndClear( m_xFloor ); + DisposeHelper::DisposeAndClear( m_xMinMaxLineWrapper ); + DisposeHelper::DisposeAndClear( m_xUpBarWrapper ); + DisposeHelper::DisposeAndClear( m_xDownBarWrapper ); + + clearWrappedPropertySet(); +} + +void SAL_CALL DiagramWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL DiagramWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +namespace { + +//PROP_DIAGRAM_DATAROW_SOURCE +class WrappedDataRowSourceProperty : public WrappedProperty +{ +public: + explicit WrappedDataRowSourceProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedDataRowSourceProperty::WrappedDataRowSourceProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("DataRowSource",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedDataRowSourceProperty::getPropertyDefault( nullptr ); +} + +void WrappedDataRowSourceProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + css::chart::ChartDataRowSource eChartDataRowSource = css::chart::ChartDataRowSource_ROWS; + if( ! (rOuterValue >>= eChartDataRowSource) ) + { + sal_Int32 nNew = sal_Int32(css::chart::ChartDataRowSource_ROWS); + if( !(rOuterValue >>= nNew) ) + throw lang::IllegalArgumentException( "Property DataRowSource requires css::chart::ChartDataRowSource value", nullptr, 0 ); + eChartDataRowSource = css::chart::ChartDataRowSource(nNew); + } + + m_aOuterValue = rOuterValue; + + bool bNewUseColumns = eChartDataRowSource == css::chart::ChartDataRowSource_COLUMNS; + + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + { + if( bUseColumns != bNewUseColumns ) + { + aSequenceMapping.realloc(0); + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bNewUseColumns , bFirstCellAsLabel , bHasCategories); + } + } +} + +Any WrappedDataRowSourceProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + { + css::chart::ChartDataRowSource eChartDataRowSource = css::chart::ChartDataRowSource_ROWS; + if(bUseColumns) + eChartDataRowSource = css::chart::ChartDataRowSource_COLUMNS; + + m_aOuterValue <<= eChartDataRowSource; + } + + return m_aOuterValue; +} + +Any WrappedDataRowSourceProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= css::chart::ChartDataRowSource_COLUMNS; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_STACKED +//PROP_DIAGRAM_DEEP +//PROP_DIAGRAM_PERCENT_STACKED +class WrappedStackingProperty : public WrappedProperty +{ +public: + WrappedStackingProperty(StackMode eStackMode, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: //methods + bool detectInnerValue( StackMode& eInnerStackMode ) const; + +private: //member +std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + const StackMode m_eStackMode; + mutable Any m_aOuterValue; +}; + +} + +WrappedStackingProperty::WrappedStackingProperty(StackMode eStackMode, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_eStackMode( eStackMode ) +{ + switch( m_eStackMode ) + { + case StackMode::YStacked: + m_aOuterName = "Stacked"; + break; + case StackMode::YStackedPercent: + m_aOuterName = "Percent"; + break; + case StackMode::ZStacked: + m_aOuterName = "Deep"; + break; + default: + OSL_FAIL( "unexpected stack mode" ); + break; + } +} + +bool WrappedStackingProperty::detectInnerValue( StackMode& eStackMode ) const +{ + bool bHasDetectableInnerValue = false; + bool bIsAmbiguous = false; + eStackMode = DiagramHelper::getStackMode( m_spChart2ModelContact->getDiagram() + , bHasDetectableInnerValue, bIsAmbiguous ); + return bHasDetectableInnerValue; +} + +void WrappedStackingProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Stacking Properties require boolean values", nullptr, 0 ); + + StackMode eInnerStackMode; + bool bHasDetectableInnerValue = detectInnerValue( eInnerStackMode ); + + if( !bHasDetectableInnerValue ) + { + m_aOuterValue = rOuterValue; + return; + } + + if( bNewValue && eInnerStackMode == m_eStackMode ) + return; + if( !bNewValue && eInnerStackMode != m_eStackMode ) + return; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + StackMode eNewStackMode = bNewValue ? m_eStackMode : StackMode::NONE; + DiagramHelper::setStackMode( xDiagram, eNewStackMode ); + } +} + +Any WrappedStackingProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + StackMode eInnerStackMode; + if( detectInnerValue( eInnerStackMode ) ) + { + bool bValue = (eInnerStackMode == m_eStackMode); + return Any(bValue); + } + return m_aOuterValue; +} + +Any WrappedStackingProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_THREE_D +class WrappedDim3DProperty : public WrappedProperty +{ +public: + explicit WrappedDim3DProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedDim3DProperty::WrappedDim3DProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("Dim3D",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedDim3DProperty::getPropertyDefault( nullptr ); +} + +void WrappedDim3DProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNew3D = false; + if( ! (rOuterValue >>= bNew3D) ) + throw lang::IllegalArgumentException( "Property Dim3D requires boolean value", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( !xDiagram.is() ) + return; + + bool bOld3D = DiagramHelper::getDimension( xDiagram ) == 3; + if( bOld3D != bNew3D ) + DiagramHelper::setDimension( xDiagram, bNew3D ? 3 : 2 ); +} + +Any WrappedDim3DProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + bool b3D = DiagramHelper::getDimension( xDiagram ) == 3; + m_aOuterValue <<= b3D; + } + return m_aOuterValue; +} + +Any WrappedDim3DProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_VERTICAL +class WrappedVerticalProperty : public WrappedProperty +{ +public: + explicit WrappedVerticalProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedVerticalProperty::WrappedVerticalProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("Vertical",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedVerticalProperty::getPropertyDefault( nullptr ); +} + +void WrappedVerticalProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewVertical = false; + if( ! (rOuterValue >>= bNewVertical) ) + throw lang::IllegalArgumentException( "Property Vertical requires boolean value", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( !xDiagram.is() ) + return; + + bool bFound = false; + bool bAmbiguous = false; + bool bOldVertical = DiagramHelper::getVertical( xDiagram, bFound, bAmbiguous ); + if( bFound && ( bOldVertical != bNewVertical || bAmbiguous ) ) + DiagramHelper::setVertical( xDiagram, bNewVertical ); +} + +Any WrappedVerticalProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + bool bFound = false; + bool bAmbiguous = false; + bool bVertical = DiagramHelper::getVertical( xDiagram, bFound, bAmbiguous ); + if( bFound ) + m_aOuterValue <<= bVertical; + } + return m_aOuterValue; +} + +Any WrappedVerticalProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_NUMBER_OF_LINES +class WrappedNumberOfLinesProperty : public WrappedProperty +{ +public: + explicit WrappedNumberOfLinesProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: //methods + bool detectInnerValue( uno::Any& rInnerValue ) const; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedNumberOfLinesProperty::WrappedNumberOfLinesProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("NumberOfLines",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_aOuterValue( getPropertyDefault(nullptr) ) +{ +} + +bool WrappedNumberOfLinesProperty::detectInnerValue( uno::Any& rInnerValue ) const +{ + sal_Int32 nNumberOfLines = 0; + bool bHasDetectableInnerValue = false; + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( xDiagram.is() && xChartDoc.is() ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + if( !aSeriesVector.empty() ) + { + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.ColumnWithLine" ) + { + try + { + uno::Reference< beans::XPropertySet > xProp( static_cast<cppu::OWeakObject*>(aTemplateAndService.xChartTypeTemplate.get()), uno::UNO_QUERY ); + xProp->getPropertyValue( m_aOuterName ) >>= nNumberOfLines; + bHasDetectableInnerValue = true; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + if(bHasDetectableInnerValue) + rInnerValue <<= nNumberOfLines; + return bHasDetectableInnerValue; +} + +void WrappedNumberOfLinesProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + sal_Int32 nNewValue; + if( ! (rOuterValue >>= nNewValue) ) + throw lang::IllegalArgumentException( "property NumberOfLines requires sal_Int32 value", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + sal_Int32 nDimension = ::chart::DiagramHelper::getDimension( xDiagram ); + if( !(xChartDoc.is() && xDiagram.is() && nDimension == 2) ) + return; + + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + rtl::Reference< ChartTypeTemplate > xTemplate; + if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.ColumnWithLine" ) + { + if( nNewValue != 0 ) + { + xTemplate = aTemplateAndService.xChartTypeTemplate; + try + { + sal_Int32 nOldValue = 0; + uno::Reference< beans::XPropertySet > xProp( static_cast<cppu::OWeakObject*>(xTemplate.get()), uno::UNO_QUERY ); + xProp->getPropertyValue( m_aOuterName ) >>= nOldValue; + if( nOldValue == nNewValue ) + return; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + xTemplate = xChartTypeManager->createTemplate("com.sun.star.chart2.template.Column"); + } + } + else if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.Column" ) + { + if( nNewValue == 0 ) + return; + xTemplate = xChartTypeManager->createTemplate( "com.sun.star.chart2.template.ColumnWithLine" ); + } + + if(!xTemplate.is()) + return; + + try + { + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + uno::Reference< beans::XPropertySet > xProp( static_cast<cppu::OWeakObject*>(xTemplate.get()), uno::UNO_QUERY ); + xProp->setPropertyValue( "NumberOfLines", uno::Any(nNewValue) ); + xTemplate->changeDiagram( xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedNumberOfLinesProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + if( !detectInnerValue( aRet ) ) + aRet = m_aOuterValue; + return aRet; +} + +Any WrappedNumberOfLinesProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= sal_Int32( 0 ); + return aRet; +} + +namespace { + +//PROP_DIAGRAM_ATTRIBUTED_DATA_POINTS +class WrappedAttributedDataPointsProperty : public WrappedProperty +{ +public: + explicit WrappedAttributedDataPointsProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedAttributedDataPointsProperty::WrappedAttributedDataPointsProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("AttributedDataPoints",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedAttributedDataPointsProperty::getPropertyDefault( nullptr ); +} + +void WrappedAttributedDataPointsProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + uno::Sequence< uno::Sequence< sal_Int32 > > aNewValue; + if( ! (rOuterValue >>= aNewValue) ) + throw lang::IllegalArgumentException( "Property AttributedDataPoints requires value of type uno::Sequence< uno::Sequence< sal_Int32 > >", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + + if( !xDiagram ) + return; + + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + ::chart::DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + sal_Int32 i = 0; + for (auto const& series : aSeriesVector) + { + uno::Any aVal; + if( i < aNewValue.getLength() ) + aVal <<= aNewValue[i]; + else + { + //set empty sequence + uno::Sequence< sal_Int32 > aSeq; + aVal <<= aSeq; + } + series->setPropertyValue( "AttributedDataPoints", aVal ); + ++i; + } +} + +Any WrappedAttributedDataPointsProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + + if( xDiagram ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + ::chart::DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + uno::Sequence< uno::Sequence< sal_Int32 > > aResult( aSeriesVector.size() ); + auto aResultRange = asNonConstRange(aResult); + sal_Int32 i = 0; + for (auto const& series : aSeriesVector) + { + uno::Any aVal( + series->getPropertyValue("AttributedDataPoints")); + uno::Sequence< sal_Int32 > aSeq; + if( aVal >>= aSeq ) + aResultRange[ i ] = aSeq; + ++i; + } + m_aOuterValue <<= aResult; + } + return m_aOuterValue; +} + +Any WrappedAttributedDataPointsProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + uno::Sequence< uno::Sequence< sal_Int32 > > aSeq; + aRet <<= aSeq; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_SOLIDTYPE +class WrappedSolidTypeProperty : public WrappedProperty +{ +public: + explicit WrappedSolidTypeProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedSolidTypeProperty::WrappedSolidTypeProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty( "SolidType", OUString() ) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedSolidTypeProperty::getPropertyDefault( nullptr ); +} + +void WrappedSolidTypeProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + sal_Int32 nNewSolidType = css::chart::ChartSolidType::RECTANGULAR_SOLID; + if( ! (rOuterValue >>= nNewSolidType) ) + throw lang::IllegalArgumentException( "Property SolidType requires integer value", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( !xDiagram.is() ) + return; + + bool bFound = false; + bool bAmbiguous = false; + sal_Int32 nOldSolidType = DiagramHelper::getGeometry3D( xDiagram, bFound, bAmbiguous ); + if( bFound && ( nOldSolidType != nNewSolidType || bAmbiguous ) ) + DiagramHelper::setGeometry3D( xDiagram, nNewSolidType ); +} + +Any WrappedSolidTypeProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + bool bFound = false; + bool bAmbiguous = false; + sal_Int32 nGeometry = DiagramHelper::getGeometry3D( xDiagram, bFound, bAmbiguous ); + if( bFound ) + m_aOuterValue <<= nGeometry; + } + return m_aOuterValue; +} + +Any WrappedSolidTypeProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any( css::chart::ChartSolidType::RECTANGULAR_SOLID ); +} + +namespace { + +class WrappedAutomaticSizeProperty : public WrappedProperty +{ +public: + WrappedAutomaticSizeProperty(); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; +}; + +} + +WrappedAutomaticSizeProperty::WrappedAutomaticSizeProperty() + : WrappedProperty( "AutomaticSize", OUString() ) +{ +} + +void WrappedAutomaticSizeProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + return; + + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Property AutomaticSize requires value of type boolean", nullptr, 0 ); + + try + { + if( bNewValue ) + { + Any aRelativeSize( xInnerPropertySet->getPropertyValue( "RelativeSize" ) ); + if( aRelativeSize.hasValue() ) + xInnerPropertySet->setPropertyValue( "RelativeSize", Any() ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedAutomaticSizeProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( getPropertyDefault( Reference< beans::XPropertyState >( xInnerPropertySet, uno::UNO_QUERY ) ) ); + if( xInnerPropertySet.is() ) + { + Any aRelativeSize( xInnerPropertySet->getPropertyValue( "RelativeSize" ) ); + if( !aRelativeSize.hasValue() ) + aRet <<= true; + } + return aRet; +} + +Any WrappedAutomaticSizeProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS +class WrappedIncludeHiddenCellsProperty : public WrappedProperty +{ +public: + explicit WrappedIncludeHiddenCellsProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue(const Reference<beans::XPropertySet>& xInnerPropertySet) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedIncludeHiddenCellsProperty::WrappedIncludeHiddenCellsProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty("IncludeHiddenCells","IncludeHiddenCells") + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedIncludeHiddenCellsProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Property IncludeHiddenCells requires boolean value", nullptr, 0 ); + + ChartModelHelper::setIncludeHiddenCells( bNewValue, *m_spChart2ModelContact->getDocumentModel() ); +} + +Any WrappedIncludeHiddenCellsProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bValue = ChartModelHelper::isIncludeHiddenCells( m_spChart2ModelContact->getDocumentModel() ); + return uno::Any(bValue); +} + +// ____ XDiagramProvider ____ +Reference< chart2::XDiagram > SAL_CALL DiagramWrapper::getDiagram() +{ + return m_spChart2ModelContact->getDiagram(); +} + +void SAL_CALL DiagramWrapper::setDiagram( + const Reference< chart2::XDiagram >& /*xDiagram*/ ) +{ + //@todo: remove this method from interface + OSL_FAIL("DiagramWrapper::setDiagram is not implemented, should be removed and not be called" ); +} + +Reference< beans::XPropertySet > DiagramWrapper::getInnerPropertySet() +{ + return m_spChart2ModelContact->getDiagram(); +} + +const Sequence< beans::Property >& DiagramWrapper::getPropertySequence() +{ + return *StaticDiagramWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > DiagramWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + + WrappedAxisAndGridExistenceProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedAxisTitleExistenceProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedAxisLabelExistenceProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedSceneProperty::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedIgnoreProperties::addIgnoreFillProperties( aWrappedProperties ); + WrappedIgnoreProperties::addIgnoreLineProperties( aWrappedProperties ); + WrappedStatisticProperties::addWrappedPropertiesForDiagram( aWrappedProperties, m_spChart2ModelContact ); + WrappedSymbolProperties::addWrappedPropertiesForDiagram( aWrappedProperties, m_spChart2ModelContact ); + WrappedDataCaptionProperties::addWrappedPropertiesForDiagram( aWrappedProperties, m_spChart2ModelContact ); + WrappedSplineProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedStockProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedAutomaticPositionProperties::addWrappedProperties( aWrappedProperties ); + + aWrappedProperties.emplace_back( new WrappedDataRowSourceProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedStackingProperty( StackMode::YStacked,m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedStackingProperty( StackMode::YStackedPercent, m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedStackingProperty( StackMode::ZStacked, m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedDim3DProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedVerticalProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedNumberOfLinesProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedAttributedDataPointsProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedProperty( "StackedBarsConnected", "ConnectBars" ) ); + aWrappedProperties.emplace_back( new WrappedSolidTypeProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedAutomaticSizeProperty() ); + aWrappedProperties.emplace_back( new WrappedIncludeHiddenCellsProperty( m_spChart2ModelContact ) ); + + return aWrappedProperties; +} + +OUString SAL_CALL DiagramWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Diagram"; +} + +sal_Bool SAL_CALL DiagramWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DiagramWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.Diagram", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.chart.StackableDiagram", + "com.sun.star.chart.ChartAxisXSupplier", + "com.sun.star.chart.ChartAxisYSupplier", + "com.sun.star.chart.ChartAxisZSupplier", + "com.sun.star.chart.ChartTwoAxisXSupplier", + "com.sun.star.chart.ChartTwoAxisYSupplier" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/DiagramWrapper.hxx b/chart2/source/controller/chartapiwrapper/DiagramWrapper.hxx new file mode 100644 index 000000000..bef53a739 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/DiagramWrapper.hxx @@ -0,0 +1,217 @@ +/* -*- 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 <WrappedPropertySet.hxx> + +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/chart/XDiagramPositioning.hpp> +#include <com/sun/star/chart2/XDiagramProvider.hpp> +#include <com/sun/star/chart/XDiagram.hpp> +#include <com/sun/star/chart/XAxisSupplier.hpp> +#include <com/sun/star/chart/XAxisZSupplier.hpp> +#include <com/sun/star/chart/XTwoAxisXSupplier.hpp> +#include <com/sun/star/chart/XTwoAxisYSupplier.hpp> +#include <com/sun/star/chart/XStatisticDisplay.hpp> +#include <com/sun/star/chart/X3DDisplay.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp> + +#include <com/sun/star/chart/X3DDefaultSetter.hpp> +#include <memory> + +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::lang { class XEventListener; } + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class DiagramWrapper : public cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::chart::XDiagram + , css::chart::XAxisSupplier + , css::chart::XAxisZSupplier + , css::chart::XTwoAxisXSupplier // : XAxisXSupplier + , css::chart::XTwoAxisYSupplier // : XAxisYSupplier + , css::chart::XStatisticDisplay + , css::chart::X3DDisplay + , css::chart::X3DDefaultSetter + , css::lang::XServiceInfo + , css::lang::XComponent + , css::chart::XDiagramPositioning + , css::chart2::XDiagramProvider + , css::chart::XSecondAxisTitleSupplier + > +{ +public: + explicit DiagramWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~DiagramWrapper() 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; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + + // ____ XDiagram ____ + virtual OUString SAL_CALL getDiagramType() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getDataRowProperties( sal_Int32 nRow ) override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getDataPointProperties( sal_Int32 nCol, sal_Int32 nRow ) override; + + // ____ XShape (base of XDiagram) ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XAxisSupplier ____ + virtual css::uno::Reference< + css::chart::XAxis > SAL_CALL getAxis( sal_Int32 nDimensionIndex ) override; + virtual css::uno::Reference< + css::chart::XAxis > SAL_CALL getSecondaryAxis( sal_Int32 nDimensionIndex ) override; + + // ____ XAxisZSupplier ____ + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getZAxisTitle() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getZMainGrid() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getZHelpGrid() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getZAxis() override; + + // ____ XTwoAxisXSupplier ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getSecondaryXAxis() override; + + // ____ XAxisXSupplier (base of XTwoAxisXSupplier) ____ + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getXAxisTitle() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getXAxis() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getXMainGrid() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getXHelpGrid() override; + + // ____ XTwoAxisYSupplier ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getSecondaryYAxis() override; + + // ____ XAxisYSupplier (base of XTwoAxisYSupplier) ____ + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getYAxisTitle() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getYAxis() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getYHelpGrid() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getYMainGrid() override; + + // ____ XSecondAxisTitleSupplier ____ + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getSecondXAxisTitle() override; + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getSecondYAxisTitle() override; + + // ____ XStatisticDisplay ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getUpBar() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getDownBar() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getMinMaxLine() override; + + // ____ X3DDisplay ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getWall() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getFloor() override; + + // ____ X3DDefaultSetter ____ + virtual void SAL_CALL set3DSettingsToDefault() override; + virtual void SAL_CALL setDefaultRotation() override; + virtual void SAL_CALL setDefaultIllumination() override; + + // ____ XDiagramPositioning ____ + virtual void SAL_CALL setAutomaticDiagramPositioning( ) override; + virtual sal_Bool SAL_CALL isAutomaticDiagramPositioning( ) override; + virtual void SAL_CALL setDiagramPositionExcludingAxes( const css::awt::Rectangle& PositionRect ) override; + virtual sal_Bool SAL_CALL isExcludingDiagramPositioning( ) override; + virtual css::awt::Rectangle SAL_CALL calculateDiagramPositionExcludingAxes( ) override; + virtual void SAL_CALL setDiagramPositionIncludingAxes( const css::awt::Rectangle& PositionRect ) override; + virtual css::awt::Rectangle SAL_CALL calculateDiagramPositionIncludingAxes( ) override; + virtual void SAL_CALL setDiagramPositionIncludingAxesAndAxisTitles( const css::awt::Rectangle& PositionRect ) override; + virtual css::awt::Rectangle SAL_CALL calculateDiagramPositionIncludingAxesAndAxisTitles( ) override; + + // ____ XDiagramProvider ____ + virtual css::uno::Reference< css::chart2::XDiagram > SAL_CALL getDiagram() override; + virtual void SAL_CALL setDiagram( const css::uno::Reference< css::chart2::XDiagram >& xDiagram ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; + + css::uno::Reference< + css::chart::XAxis > m_xXAxis; + css::uno::Reference< + css::chart::XAxis > m_xYAxis; + css::uno::Reference< + css::chart::XAxis > m_xZAxis; + css::uno::Reference< + css::chart::XAxis > m_xSecondXAxis; + css::uno::Reference< + css::chart::XAxis > m_xSecondYAxis; + + css::uno::Reference< + css::beans::XPropertySet > m_xWall; + css::uno::Reference< + css::beans::XPropertySet > m_xFloor; + + css::uno::Reference< + css::beans::XPropertySet > m_xMinMaxLineWrapper; + css::uno::Reference< + css::beans::XPropertySet > m_xUpBarWrapper; + css::uno::Reference< + css::beans::XPropertySet > m_xDownBarWrapper; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/GridWrapper.cxx b/chart2/source/controller/chartapiwrapper/GridWrapper.cxx new file mode 100644 index 000000000..b2474e236 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/GridWrapper.cxx @@ -0,0 +1,188 @@ +/* -*- 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 "GridWrapper.hxx" +#include <AxisHelper.hxx> +#include "Chart2ModelContact.hxx" +#include <AxisIndexDefines.hxx> +#include <BaseCoordinateSystem.hxx> + +#include <LinePropertiesHelper.hxx> +#include <UserDefinedProperties.hxx> +#include <WrappedDefaultProperty.hxx> + +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <algorithm> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +struct StaticGridWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticGridWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticGridWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +GridWrapper::GridWrapper(tGridType eType, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) + , m_eType(eType) +{ +} + +GridWrapper::~GridWrapper() +{} + +void GridWrapper::getDimensionAndSubGridBool( tGridType eType, sal_Int32& rnDimensionIndex, bool& rbSubGrid ) +{ + rnDimensionIndex = 1; + rbSubGrid = false; + + switch( eType ) + { + case X_MAJOR_GRID: + rnDimensionIndex = 0; rbSubGrid = false; break; + case Y_MAJOR_GRID: + rnDimensionIndex = 1; rbSubGrid = false; break; + case Z_MAJOR_GRID: + rnDimensionIndex = 2; rbSubGrid = false; break; + case X_MINOR_GRID: + rnDimensionIndex = 0; rbSubGrid = true; break; + case Y_MINOR_GRID: + rnDimensionIndex = 1; rbSubGrid = true; break; + case Z_MINOR_GRID: + rnDimensionIndex = 2; rbSubGrid = true; break; + } +} + +// ____ XComponent ____ +void SAL_CALL GridWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + clearWrappedPropertySet(); +} + +void SAL_CALL GridWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL GridWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// WrappedPropertySet + +Reference< beans::XPropertySet > GridWrapper::getInnerPropertySet() +{ + Reference< beans::XPropertySet > xRet; + try + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 /*nCooSysIndex*/ ) ); + + sal_Int32 nDimensionIndex = 1; + bool bSubGrid = false; + getDimensionAndSubGridBool( m_eType, nDimensionIndex, bSubGrid ); + + sal_Int32 nSubGridIndex = bSubGrid ? 0 : -1; + xRet.set( AxisHelper::getGridProperties( xCooSys , nDimensionIndex, MAIN_AXIS_INDEX, nSubGridIndex ) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xRet; +} + +const Sequence< beans::Property >& GridWrapper::getPropertySequence() +{ + return *StaticGridWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > GridWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedDefaultProperty( "LineColor", "LineColor", uno::Any( sal_Int32( 0x000000) ) ) ); // black + + return aWrappedProperties; +} + +OUString SAL_CALL GridWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Grid"; +} + +sal_Bool SAL_CALL GridWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL GridWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartGrid", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.drawing.LineProperties", + "com.sun.star.beans.PropertySet" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/GridWrapper.hxx b/chart2/source/controller/chartapiwrapper/GridWrapper.hxx new file mode 100644 index 000000000..0a16368e9 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/GridWrapper.hxx @@ -0,0 +1,81 @@ +/* -*- 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 <WrappedPropertySet.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <memory> + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class GridWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::lang::XComponent + , css::lang::XServiceInfo + > +{ +public: + enum tGridType + { + X_MAJOR_GRID, + Y_MAJOR_GRID, + Z_MAJOR_GRID, + X_MINOR_GRID, + Y_MINOR_GRID, + Z_MINOR_GRID + }; + + GridWrapper(tGridType eType, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~GridWrapper() override; + + static void getDimensionAndSubGridBool( tGridType eType, sal_Int32& rnDimensionIndex, bool& rbSubGrid ); + + /// 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; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; + + tGridType m_eType; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx b/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx new file mode 100644 index 000000000..e91416821 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx @@ -0,0 +1,422 @@ +/* -*- 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 "LegendWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/chart/ChartLegendPosition.hpp> +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart/ChartLegendExpansion.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> + +#include <CharacterProperties.hxx> +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <UserDefinedProperties.hxx> +#include "WrappedCharacterHeightProperty.hxx" +#include <PositionAndSizeHelper.hxx> +#include <WrappedDirectStateProperty.hxx> +#include "WrappedAutomaticPositionProperties.hxx" +#include "WrappedScaleTextProperties.hxx" + +#include <algorithm> + +using namespace ::com::sun::star; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ +namespace { + +class WrappedLegendAlignmentProperty : public WrappedProperty +{ +public: + WrappedLegendAlignmentProperty(); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + +protected: + virtual Any convertInnerToOuterValue( const Any& rInnerValue ) const override; + virtual Any convertOuterToInnerValue( const Any& rOuterValue ) const override; +}; + +} + +WrappedLegendAlignmentProperty::WrappedLegendAlignmentProperty() + : ::chart::WrappedProperty( "Alignment", "AnchorPosition" ) +{ +} + +Any WrappedLegendAlignmentProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet; + if( xInnerPropertySet.is() ) + { + bool bShowLegend = true; + xInnerPropertySet->getPropertyValue( "Show" ) >>= bShowLegend; + if(!bShowLegend) + { + aRet <<= css::chart::ChartLegendPosition_NONE; + } + else + { + aRet = xInnerPropertySet->getPropertyValue( m_aInnerName ); + aRet = convertInnerToOuterValue( aRet ); + } + } + return aRet; +} + +void WrappedLegendAlignmentProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if(!xInnerPropertySet.is()) + return; + + bool bNewShowLegend = true; + bool bOldShowLegend = true; + { + css::chart::ChartLegendPosition eOuterPos(css::chart::ChartLegendPosition_NONE); + if( (rOuterValue >>= eOuterPos) && eOuterPos == css::chart::ChartLegendPosition_NONE ) + bNewShowLegend = false; + xInnerPropertySet->getPropertyValue( "Show" ) >>= bOldShowLegend; + } + if(bNewShowLegend!=bOldShowLegend) + { + xInnerPropertySet->setPropertyValue( "Show", uno::Any(bNewShowLegend) ); + } + if(!bNewShowLegend) + return; + + //set corresponding LegendPosition + Any aInnerValue = convertOuterToInnerValue( rOuterValue ); + xInnerPropertySet->setPropertyValue( m_aInnerName, aInnerValue ); + + //correct LegendExpansion + chart2::LegendPosition eNewInnerPos(chart2::LegendPosition_LINE_END); + if( aInnerValue >>= eNewInnerPos ) + { + css::chart::ChartLegendExpansion eNewExpansion = + ( eNewInnerPos == chart2::LegendPosition_LINE_END || + eNewInnerPos == chart2::LegendPosition_LINE_START ) + ? css::chart::ChartLegendExpansion_HIGH + : css::chart::ChartLegendExpansion_WIDE; + + css::chart::ChartLegendExpansion eOldExpansion( css::chart::ChartLegendExpansion_HIGH ); + bool bExpansionWasSet( + xInnerPropertySet->getPropertyValue( "Expansion" ) >>= eOldExpansion ); + + if( !bExpansionWasSet || (eOldExpansion != eNewExpansion)) + xInnerPropertySet->setPropertyValue( "Expansion", uno::Any( eNewExpansion )); + } + + //correct RelativePosition + Any aRelativePosition( xInnerPropertySet->getPropertyValue("RelativePosition") ); + if(aRelativePosition.hasValue()) + { + xInnerPropertySet->setPropertyValue( "RelativePosition", Any() ); + } +} + +Any WrappedLegendAlignmentProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + css::chart::ChartLegendPosition ePos = css::chart::ChartLegendPosition_NONE; + + chart2::LegendPosition eNewPos; + if( rInnerValue >>= eNewPos ) + { + switch( eNewPos ) + { + case chart2::LegendPosition_LINE_START: + ePos = css::chart::ChartLegendPosition_LEFT; + break; + case chart2::LegendPosition_LINE_END: + ePos = css::chart::ChartLegendPosition_RIGHT; + break; + case chart2::LegendPosition_PAGE_START: + ePos = css::chart::ChartLegendPosition_TOP; + break; + case chart2::LegendPosition_PAGE_END: + ePos = css::chart::ChartLegendPosition_BOTTOM; + break; + + default: + ePos = css::chart::ChartLegendPosition_NONE; + break; + } + } + return uno::Any( ePos ); +} +Any WrappedLegendAlignmentProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + chart2::LegendPosition eNewPos = chart2::LegendPosition_LINE_END; + + css::chart::ChartLegendPosition ePos; + if( rOuterValue >>= ePos ) + { + switch( ePos ) + { + case css::chart::ChartLegendPosition_LEFT: + eNewPos = chart2::LegendPosition_LINE_START; + break; + case css::chart::ChartLegendPosition_RIGHT: + eNewPos = chart2::LegendPosition_LINE_END; + break; + case css::chart::ChartLegendPosition_TOP: + eNewPos = chart2::LegendPosition_PAGE_START; + break; + case css::chart::ChartLegendPosition_BOTTOM: + eNewPos = chart2::LegendPosition_PAGE_END; + break; + default: // NONE + break; + } + } + + return uno::Any( eNewPos ); +} +} + +namespace +{ + +enum +{ + PROP_LEGEND_ALIGNMENT, + PROP_LEGEND_EXPANSION +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Alignment", + PROP_LEGEND_ALIGNMENT, + cppu::UnoType<css::chart::ChartLegendPosition>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Expansion", + PROP_LEGEND_EXPANSION, + cppu::UnoType<css::chart::ChartLegendExpansion>::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticLegendWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::wrapper::WrappedAutomaticPositionProperties::addProperties( aProperties ); + ::chart::wrapper::WrappedScaleTextProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticLegendWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticLegendWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +LegendWrapper::LegendWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) +{ +} + +LegendWrapper::~LegendWrapper() +{ +} + +// ____ XShape ____ +awt::Point SAL_CALL LegendWrapper::getPosition() +{ + return m_spChart2ModelContact->GetLegendPosition(); +} + +void SAL_CALL LegendWrapper::setPosition( const awt::Point& aPosition ) +{ + Reference< beans::XPropertySet > xProp( getInnerPropertySet() ); + if( xProp.is() ) + { + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT; + aRelativePosition.Primary = aPageSize.Width == 0 ? 0 : double(aPosition.X)/double(aPageSize.Width); + aRelativePosition.Secondary = aPageSize.Height == 0 ? 0 : double(aPosition.Y)/double(aPageSize.Height); + xProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + } +} + +awt::Size SAL_CALL LegendWrapper::getSize() +{ + return m_spChart2ModelContact->GetLegendSize(); +} + +void SAL_CALL LegendWrapper::setSize( const awt::Size& aSize ) +{ + Reference< beans::XPropertySet > xProp( getInnerPropertySet() ); + if( xProp.is() ) + { + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + awt::Rectangle aPageRectangle( 0,0,aPageSize.Width,aPageSize.Height); + + awt::Point aPos( getPosition() ); + awt::Rectangle aNewPositionAndSize(aPos.X,aPos.Y,aSize.Width,aSize.Height); + + PositionAndSizeHelper::moveObject( OBJECTTYPE_LEGEND + , xProp, aNewPositionAndSize, awt::Rectangle(), aPageRectangle ); + } +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL LegendWrapper::getShapeType() +{ + return "com.sun.star.chart.ChartLegend"; +} + +// ____ XComponent ____ +void SAL_CALL LegendWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + MutexGuard aGuard( m_aMutex); + clearWrappedPropertySet(); +} + +void SAL_CALL LegendWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL LegendWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +//ReferenceSizePropertyProvider +void LegendWrapper::updateReferenceSize() +{ + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); + if( xProp.is() ) + { + if( xProp->getPropertyValue( "ReferencePageSize" ).hasValue() ) + xProp->setPropertyValue( "ReferencePageSize", uno::Any( + m_spChart2ModelContact->GetPageSize() )); + } +} +Any LegendWrapper::getReferenceSize() +{ + Any aRet; + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); + if( xProp.is() ) + aRet = xProp->getPropertyValue( "ReferencePageSize" ); + + return aRet; +} +awt::Size LegendWrapper::getCurrentSizeForReference() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +// WrappedPropertySet +Reference< beans::XPropertySet > LegendWrapper::getInnerPropertySet() +{ + Reference< beans::XPropertySet > xRet; + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + xRet.set( xDiagram->getLegend(), uno::UNO_QUERY ); + OSL_ENSURE(xRet.is(),"LegendWrapper::getInnerPropertySet() is NULL"); + return xRet; +} + +const Sequence< beans::Property >& LegendWrapper::getPropertySequence() +{ + return *StaticLegendWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > LegendWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedLegendAlignmentProperty() ); + aWrappedProperties.emplace_back( new WrappedProperty( "Expansion", "Expansion")); + WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); + //same problem as for wall: the defaults in the old chart are different for different charttypes, so we need to export explicitly + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("FillStyle", "FillStyle")); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("FillColor", "FillColor")); + WrappedAutomaticPositionProperties::addWrappedProperties( aWrappedProperties ); + WrappedScaleTextProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + return aWrappedProperties; +} + +OUString SAL_CALL LegendWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Legend"; +} + +sal_Bool SAL_CALL LegendWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL LegendWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartLegend", + "com.sun.star.drawing.Shape", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.style.CharacterProperties" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/LegendWrapper.hxx b/chart2/source/controller/chartapiwrapper/LegendWrapper.hxx new file mode 100644 index 000000000..128c5fbcf --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/LegendWrapper.hxx @@ -0,0 +1,87 @@ +/* -*- 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 <WrappedPropertySet.hxx> +#include "ReferenceSizePropertyProvider.hxx" +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <memory> + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class LegendWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::drawing::XShape + , css::lang::XComponent + , css::lang::XServiceInfo + > + , public ReferenceSizePropertyProvider +{ +public: + explicit LegendWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~LegendWrapper() 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; + + //ReferenceSizePropertyProvider + virtual void updateReferenceSize() override; + virtual css::uno::Any getReferenceSize() override; + virtual css::awt::Size getCurrentSizeForReference() override; + + // ____ XShape ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.cxx b/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.cxx new file mode 100644 index 000000000..3520dacb5 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.cxx @@ -0,0 +1,384 @@ +/* -*- 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 "MinMaxLineWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include <ChartType.hxx> +#include <DiagramHelper.hxx> +#include <servicenames_charttypes.hxx> +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/drawing/LineJoint.hpp> +#include <comphelper/sequence.hxx> +#include <DataSeries.hxx> +#include <LinePropertiesHelper.hxx> +#include <UserDefinedProperties.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace +{ + +struct StaticMinMaxLineWrapperDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +}; + +struct StaticMinMaxLineWrapperDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticMinMaxLineWrapperDefaults_Initializer > +{ +}; + +struct StaticMinMaxLineWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticMinMaxLineWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticMinMaxLineWrapperPropertyArray_Initializer > +{ +}; + +struct StaticMinMaxLineWrapperInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( *StaticMinMaxLineWrapperPropertyArray::get() ); + return &aPropHelper; + } +}; + +struct StaticMinMaxLineWrapperInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticMinMaxLineWrapperInfoHelper_Initializer > +{ +}; + +struct StaticMinMaxLineWrapperInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticMinMaxLineWrapperInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticMinMaxLineWrapperInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticMinMaxLineWrapperInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +MinMaxLineWrapper::MinMaxLineWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact( spChart2ModelContact ) + , m_aEventListenerContainer( m_aMutex ) + , m_aWrappedLineJointProperty( "LineJoint", uno::Any( drawing::LineJoint_NONE )) +{ +} + +MinMaxLineWrapper::~MinMaxLineWrapper() +{ +} + +// ____ XComponent ____ +void SAL_CALL MinMaxLineWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); +} + +void SAL_CALL MinMaxLineWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL MinMaxLineWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +//XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL MinMaxLineWrapper::getPropertySetInfo() +{ + return *StaticMinMaxLineWrapperInfo::get(); +} + +void SAL_CALL MinMaxLineWrapper::setPropertyValue( const OUString& rPropertyName, const uno::Any& rValue ) +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + const std::vector< rtl::Reference< ChartType > > & aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( rtl::Reference< ChartType > const & xType : aTypes ) + { + if( xType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + const std::vector< rtl::Reference< DataSeries > > & aSeriesSeq( xType->getDataSeries2() ); + if(!aSeriesSeq.empty()) + { + if(aSeriesSeq[0].is()) + { + if( rPropertyName == "LineColor" ) + aSeriesSeq[0]->setPropertyValue( "Color", rValue ); + else if( rPropertyName == "LineTransparence" ) + aSeriesSeq[0]->setPropertyValue( "Transparency", rValue ); + else if( rPropertyName == m_aWrappedLineJointProperty.getOuterName() ) + m_aWrappedLineJointProperty.setPropertyValue( rValue, aSeriesSeq[0] ); + else + aSeriesSeq[0]->setPropertyValue( rPropertyName, rValue ); + return; + } + } + } + } +} +uno::Any SAL_CALL MinMaxLineWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + Any aRet; + + rtl::Reference< DataSeries > xPropSet; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + const std::vector< rtl::Reference< ChartType > > aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( rtl::Reference< ChartType > const & xType : aTypes ) + { + if( xType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + const std::vector< rtl::Reference< DataSeries > > & aSeriesSeq( xType->getDataSeries2() ); + if(!aSeriesSeq.empty()) + { + xPropSet = aSeriesSeq[0]; + break; + } + } + } + if(xPropSet.is()) + { + if( rPropertyName == "LineColor" ) + aRet = xPropSet->getPropertyValue( "Color" ); + else if( rPropertyName == "LineTransparence" ) + aRet = xPropSet->getPropertyValue( "Transparency" ); + else if( rPropertyName == m_aWrappedLineJointProperty.getOuterName() ) + aRet = m_aWrappedLineJointProperty.getPropertyValue( xPropSet ); + else + aRet = xPropSet->getPropertyValue( rPropertyName ); + + } + return aRet; +} + +void SAL_CALL MinMaxLineWrapper::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} + +//XMultiPropertySet +//getPropertySetInfo() already declared in XPropertySet +void SAL_CALL MinMaxLineWrapper::setPropertyValues( const uno::Sequence< OUString >& rNameSeq, const uno::Sequence< uno::Any >& rValueSeq ) +{ + sal_Int32 nMinCount = std::min( rValueSeq.getLength(), rNameSeq.getLength() ); + for(sal_Int32 nN=0; nN<nMinCount; nN++) + { + OUString aPropertyName( rNameSeq[nN] ); + try + { + setPropertyValue( aPropertyName, rValueSeq[nN] ); + } + catch( const beans::UnknownPropertyException& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + //todo: store unknown properties elsewhere +} +uno::Sequence< uno::Any > SAL_CALL MinMaxLineWrapper::getPropertyValues( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN<rNameSeq.getLength(); nN++) + { + OUString aPropertyName( rNameSeq[nN] ); + pRetSeq[nN] = getPropertyValue( aPropertyName ); + } + } + return aRetSeq; +} +void SAL_CALL MinMaxLineWrapper::addPropertiesChangeListener( + const uno::Sequence< OUString >& /* aPropertyNames */, + const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::removePropertiesChangeListener( + const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::firePropertiesChangeEvent( + const uno::Sequence< OUString >& /* aPropertyNames */, + const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} + +//XPropertyState +beans::PropertyState SAL_CALL MinMaxLineWrapper::getPropertyState( const OUString& rPropertyName ) +{ + if( rPropertyName == m_aWrappedLineJointProperty.getOuterName() ) + return beans::PropertyState_DEFAULT_VALUE; + + uno::Any aDefault( getPropertyDefault( rPropertyName ) ); + uno::Any aValue( getPropertyValue( rPropertyName ) ); + + if( aDefault == aValue ) + return beans::PropertyState_DEFAULT_VALUE; + + return beans::PropertyState_DIRECT_VALUE; +} +uno::Sequence< beans::PropertyState > SAL_CALL MinMaxLineWrapper::getPropertyStates( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< beans::PropertyState > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN<rNameSeq.getLength(); nN++) + { + OUString aPropertyName( rNameSeq[nN] ); + pRetSeq[nN] = getPropertyState( aPropertyName ); + } + } + return aRetSeq; +} +void SAL_CALL MinMaxLineWrapper::setPropertyToDefault( const OUString& rPropertyName ) +{ + setPropertyValue( rPropertyName, getPropertyDefault(rPropertyName) ); +} + +uno::Any SAL_CALL MinMaxLineWrapper::getPropertyDefault( const OUString& rPropertyName ) +{ + const tPropertyValueMap& rStaticDefaults = *StaticMinMaxLineWrapperDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( StaticMinMaxLineWrapperInfoHelper::get()->getHandleByName( rPropertyName ) ) ); + if( aFound == rStaticDefaults.end() ) + return uno::Any(); + return (*aFound).second; +} + +//XMultiPropertyStates +//getPropertyStates() already declared in XPropertyState +void SAL_CALL MinMaxLineWrapper::setAllPropertiesToDefault( ) +{ + const Sequence< beans::Property >& rPropSeq = *StaticMinMaxLineWrapperPropertyArray::get(); + for(beans::Property const & prop : rPropSeq) + { + setPropertyToDefault( prop.Name ); + } +} +void SAL_CALL MinMaxLineWrapper::setPropertiesToDefault( const uno::Sequence< OUString >& rNameSeq ) +{ + for(OUString const & s : rNameSeq) + { + setPropertyToDefault( s ); + } +} +uno::Sequence< uno::Any > SAL_CALL MinMaxLineWrapper::getPropertyDefaults( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN<rNameSeq.getLength(); nN++) + { + OUString aPropertyName( rNameSeq[nN] ); + pRetSeq[nN] = getPropertyDefault( aPropertyName ); + } + } + return aRetSeq; +} + +OUString SAL_CALL MinMaxLineWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.ChartLine"; +} + +sal_Bool SAL_CALL MinMaxLineWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL MinMaxLineWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartLine", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.drawing.LineProperties" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.hxx b/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.hxx new file mode 100644 index 000000000..33cabe174 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.hxx @@ -0,0 +1,104 @@ +/* -*- 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 <WrappedIgnoreProperty.hxx> +#include <comphelper/interfacecontainer3.hxx> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertyStates.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <memory> + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class MinMaxLineWrapper : public cppu::BaseMutex + , public ::cppu::WeakImplHelper + < css::lang::XComponent + , css::lang::XServiceInfo + , css::beans::XPropertySet + , css::beans::XMultiPropertySet + , css::beans::XPropertyState + , css::beans::XMultiPropertyStates + > +{ +public: + explicit MinMaxLineWrapper(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~MinMaxLineWrapper() 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; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + //XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + //XMultiPropertySet + //getPropertySetInfo() already declared in XPropertySet + virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + + //XPropertyState + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + //XMultiPropertyStates + //getPropertyStates() already declared in XPropertyState + virtual void SAL_CALL setAllPropertiesToDefault( ) override; + virtual void SAL_CALL setPropertiesToDefault( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyDefaults( const css::uno::Sequence< OUString >& aPropertyNames ) override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; + + WrappedIgnoreProperty m_aWrappedLineJointProperty; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/ReferenceSizePropertyProvider.hxx b/chart2/source/controller/chartapiwrapper/ReferenceSizePropertyProvider.hxx new file mode 100644 index 000000000..4451c3cce --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/ReferenceSizePropertyProvider.hxx @@ -0,0 +1,38 @@ +/* -*- 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/awt/Size.hpp> + +namespace chart::wrapper +{ +class ReferenceSizePropertyProvider +{ +public: + virtual void updateReferenceSize() = 0; + virtual css::uno::Any getReferenceSize() = 0; + virtual css::awt::Size getCurrentSizeForReference() = 0; + +protected: + ~ReferenceSizePropertyProvider() {} +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx new file mode 100644 index 000000000..d9039d879 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx @@ -0,0 +1,510 @@ +/* -*- 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 "TitleWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include <ControllerLockGuard.hxx> + +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/XTitle.hpp> + +#include <CharacterProperties.hxx> +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <UserDefinedProperties.hxx> +#include "WrappedCharacterHeightProperty.hxx" +#include "WrappedTextRotationProperty.hxx" +#include "WrappedAutomaticPositionProperties.hxx" +#include "WrappedScaleTextProperties.hxx" + +#include <algorithm> +#include <rtl/ustrbuf.hxx> +#include <cppuhelper/propshlp.hxx> + +using namespace ::com::sun::star; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ +namespace { + +class WrappedTitleStringProperty : public WrappedProperty +{ +public: + explicit WrappedTitleStringProperty( const Reference< uno::XComponentContext >& xContext ); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + Reference< uno::XComponentContext > m_xContext; +}; + +} + +WrappedTitleStringProperty::WrappedTitleStringProperty( const Reference< uno::XComponentContext >& xContext ) + : ::chart::WrappedProperty( "String", OUString() ) + , m_xContext( xContext ) +{ +} + +void WrappedTitleStringProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Reference< chart2::XTitle > xTitle(xInnerPropertySet,uno::UNO_QUERY); + if(xTitle.is()) + { + OUString aString; + rOuterValue >>= aString; + TitleHelper::setCompleteString( aString, xTitle, m_xContext ); + } +} +Any WrappedTitleStringProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( getPropertyDefault( Reference< beans::XPropertyState >( xInnerPropertySet, uno::UNO_QUERY ) ) ); + Reference< chart2::XTitle > xTitle(xInnerPropertySet,uno::UNO_QUERY); + if(xTitle.is()) + { + const Sequence< Reference< chart2::XFormattedString > > aStrings( xTitle->getText()); + + OUStringBuffer aBuf; + for( Reference< chart2::XFormattedString > const & formattedStr : aStrings ) + { + aBuf.append( formattedStr->getString()); + } + aRet <<= aBuf.makeStringAndClear(); + } + return aRet; +} +Any WrappedTitleStringProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any( OUString() );//default title is an empty String +} + +namespace { + +class WrappedStackedTextProperty : public WrappedProperty +{ +public: + WrappedStackedTextProperty(); +}; + +} + +WrappedStackedTextProperty::WrappedStackedTextProperty() + : ::chart::WrappedProperty( "StackedText", "StackCharacters" ) +{ +} + +}// end namespace chart + +namespace +{ + +enum +{ + PROP_TITLE_STRING, + PROP_TITLE_TEXT_ROTATION, + PROP_TITLE_TEXT_STACKED +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "String", + PROP_TITLE_STRING, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "TextRotation", + PROP_TITLE_TEXT_ROTATION, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "StackedText", + PROP_TITLE_TEXT_STACKED, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticTitleWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::wrapper::WrappedAutomaticPositionProperties::addProperties( aProperties ); + ::chart::wrapper::WrappedScaleTextProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticTitleWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticTitleWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +TitleWrapper::TitleWrapper( ::chart::TitleHelper::eTitleType eTitleType, + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) : + m_spChart2ModelContact( spChart2ModelContact ), + m_aEventListenerContainer( m_aMutex ), + m_eTitleType(eTitleType) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + if( !getTitleObject().is() ) //#i83831# create an empty title at the model, thus references to properties can be mapped correctly + TitleHelper::createTitle( m_eTitleType, OUString(), m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext ); +} + +TitleWrapper::~TitleWrapper() +{ +} + +// ____ XShape ____ +awt::Point SAL_CALL TitleWrapper::getPosition() +{ + return m_spChart2ModelContact->GetTitlePosition( getTitleObject() ); +} + +void SAL_CALL TitleWrapper::setPosition( const awt::Point& aPosition ) +{ + Reference< beans::XPropertySet > xPropertySet( getInnerPropertySet() ); + if(xPropertySet.is()) + { + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT; + aRelativePosition.Primary = double(aPosition.X)/double(aPageSize.Width); + aRelativePosition.Secondary = double(aPosition.Y)/double(aPageSize.Height); + xPropertySet->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + } +} + +awt::Size SAL_CALL TitleWrapper::getSize() +{ + return m_spChart2ModelContact->GetTitleSize( getTitleObject() ); +} + +void SAL_CALL TitleWrapper::setSize( const awt::Size& /*aSize*/ ) +{ + OSL_FAIL( "trying to set size of title" ); +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL TitleWrapper::getShapeType() +{ + return "com.sun.star.chart.ChartTitle"; +} + +// ____ XComponent ____ +void SAL_CALL TitleWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + MutexGuard aGuard( m_aMutex); + clearWrappedPropertySet(); +} + +void SAL_CALL TitleWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL TitleWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +Reference< beans::XPropertySet > TitleWrapper::getFirstCharacterPropertySet() +{ + Reference< beans::XPropertySet > xProp; + + Reference< chart2::XTitle > xTitle( getTitleObject() ); + if( xTitle.is()) + { + Sequence< Reference< chart2::XFormattedString > > aStrings( xTitle->getText()); + if( aStrings.hasElements() ) + xProp.set( aStrings[0], uno::UNO_QUERY ); + } + + return xProp; +} + +void TitleWrapper::getFastCharacterPropertyValue( sal_Int32 nHandle, Any& rValue ) +{ + OSL_ASSERT( FAST_PROPERTY_ID_START_CHAR_PROP <= nHandle && + nHandle < CharacterProperties::FAST_PROPERTY_ID_END_CHAR_PROP ); + + Reference< beans::XPropertySet > xProp = getFirstCharacterPropertySet(); + Reference< beans::XFastPropertySet > xFastProp( xProp, uno::UNO_QUERY ); + if(xProp.is()) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( nHandle ); + if( pWrappedProperty ) + { + rValue = pWrappedProperty->getPropertyValue( xProp ); + } + else if( xFastProp.is() ) + { + rValue = xFastProp->getFastPropertyValue( nHandle ); + } + } + +} + +void TitleWrapper::setFastCharacterPropertyValue( + sal_Int32 nHandle, const Any& rValue ) +{ + OSL_ASSERT( FAST_PROPERTY_ID_START_CHAR_PROP <= nHandle && + nHandle < CharacterProperties::FAST_PROPERTY_ID_END_CHAR_PROP ); + + Reference< chart2::XTitle > xTitle( getTitleObject() ); + if( !xTitle.is()) + return; + + const Sequence< Reference< chart2::XFormattedString > > aStrings( xTitle->getText()); + const WrappedProperty* pWrappedProperty = getWrappedProperty( nHandle ); + + for( Reference< chart2::XFormattedString > const & formattedStr : aStrings ) + { + Reference< beans::XFastPropertySet > xFastPropertySet( formattedStr, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xPropSet( xFastPropertySet, uno::UNO_QUERY ); + + if( pWrappedProperty ) + pWrappedProperty->setPropertyValue( rValue, xPropSet ); + else if( xFastPropertySet.is() ) + xFastPropertySet->setFastPropertyValue( nHandle, rValue ); + } +} + +// WrappedPropertySet + +void SAL_CALL TitleWrapper::setPropertyValue( const OUString& rPropertyName, const Any& rValue ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + setFastCharacterPropertyValue( nHandle, rValue ); + } + else + WrappedPropertySet::setPropertyValue( rPropertyName, rValue ); +} + +Any SAL_CALL TitleWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + Any aRet; + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + getFastCharacterPropertyValue( nHandle, aRet ); + else + aRet = WrappedPropertySet::getPropertyValue( rPropertyName ); + return aRet; +} + +beans::PropertyState SAL_CALL TitleWrapper::getPropertyState( const OUString& rPropertyName ) +{ + beans::PropertyState aState( beans::PropertyState_DIRECT_VALUE ); + + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Reference< beans::XPropertyState > xPropState( getFirstCharacterPropertySet(), uno::UNO_QUERY ); + if( xPropState.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + aState = pWrappedProperty->getPropertyState( xPropState ); + else + aState = xPropState->getPropertyState( rPropertyName ); + } + } + else + aState = WrappedPropertySet::getPropertyState( rPropertyName ); + + return aState; +} +void SAL_CALL TitleWrapper::setPropertyToDefault( const OUString& rPropertyName ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Any aDefault = getPropertyDefault( rPropertyName ); + setFastCharacterPropertyValue( nHandle, aDefault ); + } + else + WrappedPropertySet::setPropertyToDefault( rPropertyName ); +} +Any SAL_CALL TitleWrapper::getPropertyDefault( const OUString& rPropertyName ) +{ + Any aRet; + + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Reference< beans::XPropertyState > xPropState( getFirstCharacterPropertySet(), uno::UNO_QUERY ); + if( xPropState.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + aRet = pWrappedProperty->getPropertyDefault(xPropState); + else + aRet = xPropState->getPropertyDefault( rPropertyName ); + } + } + else + aRet = WrappedPropertySet::getPropertyDefault( rPropertyName ); + + return aRet; +} + +void SAL_CALL TitleWrapper::addPropertyChangeListener( const OUString& rPropertyName, const Reference< beans::XPropertyChangeListener >& xListener ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Reference< beans::XPropertySet > xPropSet = getFirstCharacterPropertySet(); + if( xPropSet.is() ) + xPropSet->addPropertyChangeListener( rPropertyName, xListener ); + } + else + WrappedPropertySet::addPropertyChangeListener( rPropertyName, xListener ); +} +void SAL_CALL TitleWrapper::removePropertyChangeListener( const OUString& rPropertyName, const Reference< beans::XPropertyChangeListener >& xListener ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Reference< beans::XPropertySet > xPropSet = getFirstCharacterPropertySet(); + if( xPropSet.is() ) + xPropSet->removePropertyChangeListener( rPropertyName, xListener ); + } + else + WrappedPropertySet::removePropertyChangeListener( rPropertyName, xListener ); +} + +//ReferenceSizePropertyProvider +void TitleWrapper::updateReferenceSize() +{ + Reference< beans::XPropertySet > xProp( getTitleObject(), uno::UNO_QUERY ); + if( xProp.is() ) + { + if( xProp->getPropertyValue( "ReferencePageSize" ).hasValue() ) + xProp->setPropertyValue( "ReferencePageSize", uno::Any( + m_spChart2ModelContact->GetPageSize() )); + } +} +Any TitleWrapper::getReferenceSize() +{ + Any aRet; + Reference< beans::XPropertySet > xProp( getTitleObject(), uno::UNO_QUERY ); + if( xProp.is() ) + aRet = xProp->getPropertyValue( "ReferencePageSize" ); + + return aRet; +} +awt::Size TitleWrapper::getCurrentSizeForReference() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +Reference< chart2::XTitle > TitleWrapper::getTitleObject() +{ + return TitleHelper::getTitle( m_eTitleType, m_spChart2ModelContact->getDocumentModel() ); +} + +// WrappedPropertySet + +Reference< beans::XPropertySet > TitleWrapper::getInnerPropertySet() +{ + return Reference< beans::XPropertySet >( getTitleObject(), uno::UNO_QUERY ); +} + +const Sequence< beans::Property >& TitleWrapper::getPropertySequence() +{ + return *StaticTitleWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > TitleWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedTitleStringProperty( m_spChart2ModelContact->m_xContext ) ); + aWrappedProperties.emplace_back( new WrappedTextRotationProperty( true ) ); + aWrappedProperties.emplace_back( new WrappedStackedTextProperty() ); + WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); + WrappedAutomaticPositionProperties::addWrappedProperties( aWrappedProperties ); + WrappedScaleTextProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + return aWrappedProperties; +} + +OUString SAL_CALL TitleWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Title"; +} + +sal_Bool SAL_CALL TitleWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL TitleWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartTitle", + "com.sun.star.drawing.Shape", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.style.CharacterProperties" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/TitleWrapper.hxx b/chart2/source/controller/chartapiwrapper/TitleWrapper.hxx new file mode 100644 index 000000000..5cc3ed477 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/TitleWrapper.hxx @@ -0,0 +1,110 @@ +/* -*- 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 <WrappedPropertySet.hxx> +#include "ReferenceSizePropertyProvider.hxx" +#include <TitleHelper.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <memory> + +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::chart2 { class XTitle; } + +namespace chart::wrapper +{ + +class TitleWrapper final : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::drawing::XShape + , css::lang::XComponent + , css::lang::XServiceInfo + > + , public ReferenceSizePropertyProvider +{ +public: + TitleWrapper( ::chart::TitleHelper::eTitleType eTitleType, + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ); + virtual ~TitleWrapper() 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; + + //ReferenceSizePropertyProvider + virtual void updateReferenceSize() override; + virtual css::uno::Any getReferenceSize() override; + virtual css::awt::Size getCurrentSizeForReference() override; + +private: + // ____ XShape ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // character properties have to be handled differently (via the XFormattedString elements) + void getFastCharacterPropertyValue( sal_Int32 nHandle, css::uno::Any& rValue ); + /// @throws css::uno::Exception + void setFastCharacterPropertyValue( sal_Int32 nHandle, const css::uno::Any& rValue ); + + // ____ WrappedPropertySet ____ + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + + css::uno::Reference< css::beans::XPropertySet > getFirstCharacterPropertySet(); + + css::uno::Reference< css::chart2::XTitle > getTitleObject(); + + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; + + ::chart::TitleHelper::eTitleType m_eTitleType; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.cxx b/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.cxx new file mode 100644 index 000000000..c1bde1473 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.cxx @@ -0,0 +1,356 @@ +/* -*- 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 "UpDownBarWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include <ChartType.hxx> +#include <DiagramHelper.hxx> +#include <servicenames_charttypes.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/propshlp.hxx> +#include <comphelper/sequence.hxx> + +#include <LinePropertiesHelper.hxx> +#include <FillProperties.hxx> +#include <UserDefinedProperties.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace +{ + +struct StaticUpDownBarWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + 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 ); + } +}; + +struct StaticUpDownBarWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticUpDownBarWrapperPropertyArray_Initializer > +{ +}; + +struct StaticUpDownBarWrapperInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( *StaticUpDownBarWrapperPropertyArray::get() ); + return &aPropHelper; + } +}; + +struct StaticUpDownBarWrapperInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticUpDownBarWrapperInfoHelper_Initializer > +{ +}; + +struct StaticUpDownBarWrapperInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticUpDownBarWrapperInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticUpDownBarWrapperInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticUpDownBarWrapperInfo_Initializer > +{ +}; + +struct StaticUpDownBarWrapperDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + ::chart::FillProperties::AddDefaultsToMap( rOutMap ); + } +}; + +struct StaticUpDownBarWrapperDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticUpDownBarWrapperDefaults_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +UpDownBarWrapper::UpDownBarWrapper( + bool bUp, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : m_spChart2ModelContact( spChart2ModelContact ) + , m_aEventListenerContainer( m_aMutex ) + , m_aPropertySetName( bUp ? OUString( "WhiteDay" ) : OUString( "BlackDay" )) +{ +} + +UpDownBarWrapper::~UpDownBarWrapper() +{ +} + +// ____ XComponent ____ +void SAL_CALL UpDownBarWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); +} + +void SAL_CALL UpDownBarWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL UpDownBarWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +//XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL UpDownBarWrapper::getPropertySetInfo() +{ + return *StaticUpDownBarWrapperInfo::get(); +} +void SAL_CALL UpDownBarWrapper::setPropertyValue( const OUString& rPropertyName, const uno::Any& rValue ) +{ + Reference< beans::XPropertySet > xPropSet; + + const std::vector< rtl::Reference< ChartType > > aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( m_spChart2ModelContact->getDiagram() ) ); + for( rtl::Reference< ChartType > const & xType : aTypes ) + { + if( xType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + xType->getPropertyValue( m_aPropertySetName ) >>= xPropSet; + } + } + if(xPropSet.is()) + xPropSet->setPropertyValue( rPropertyName, rValue ); +} +uno::Any SAL_CALL UpDownBarWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + Any aRet; + + Reference< beans::XPropertySet > xPropSet; + + const std::vector< rtl::Reference< ChartType > > aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( m_spChart2ModelContact->getDiagram() ) ); + for( rtl::Reference<ChartType > const & xType : aTypes ) + { + if( xType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + xType->getPropertyValue( m_aPropertySetName ) >>= xPropSet; + } + } + if(xPropSet.is()) + aRet = xPropSet->getPropertyValue( rPropertyName ); + return aRet; +} + +void SAL_CALL UpDownBarWrapper::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} + +//XMultiPropertySet +//getPropertySetInfo() already declared in XPropertySet +void SAL_CALL UpDownBarWrapper::setPropertyValues( const uno::Sequence< OUString >& rNameSeq, const uno::Sequence< uno::Any >& rValueSeq ) +{ + sal_Int32 nMinCount = std::min( rValueSeq.getLength(), rNameSeq.getLength() ); + for(sal_Int32 nN=0; nN<nMinCount; nN++) + { + OUString aPropertyName( rNameSeq[nN] ); + try + { + setPropertyValue( aPropertyName, rValueSeq[nN] ); + } + catch( const beans::UnknownPropertyException& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + //todo: store unknown properties elsewhere +} +uno::Sequence< uno::Any > SAL_CALL UpDownBarWrapper::getPropertyValues( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN<rNameSeq.getLength(); nN++) + { + OUString aPropertyName( rNameSeq[nN] ); + pRetSeq[nN] = getPropertyValue( aPropertyName ); + } + } + return aRetSeq; +} +void SAL_CALL UpDownBarWrapper::addPropertiesChangeListener( const uno::Sequence< OUString >& /* aPropertyNames */, const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::firePropertiesChangeEvent( const uno::Sequence< OUString >& /* aPropertyNames */, const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} + +//XPropertyState +beans::PropertyState SAL_CALL UpDownBarWrapper::getPropertyState( const OUString& rPropertyName ) +{ + uno::Any aDefault( getPropertyDefault( rPropertyName ) ); + uno::Any aValue( getPropertyValue( rPropertyName ) ); + + if( aDefault == aValue ) + return beans::PropertyState_DEFAULT_VALUE; + + return beans::PropertyState_DIRECT_VALUE; +} +uno::Sequence< beans::PropertyState > SAL_CALL UpDownBarWrapper::getPropertyStates( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< beans::PropertyState > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN<rNameSeq.getLength(); nN++) + { + OUString aPropertyName( rNameSeq[nN] ); + pRetSeq[nN] = getPropertyState( aPropertyName ); + } + } + return aRetSeq; +} +void SAL_CALL UpDownBarWrapper::setPropertyToDefault( const OUString& rPropertyName ) +{ + setPropertyValue( rPropertyName, getPropertyDefault(rPropertyName) ); +} + +uno::Any SAL_CALL UpDownBarWrapper::getPropertyDefault( const OUString& rPropertyName ) +{ + const tPropertyValueMap& rStaticDefaults = *StaticUpDownBarWrapperDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( StaticUpDownBarWrapperInfoHelper::get()->getHandleByName( rPropertyName ) ) ); + if( aFound == rStaticDefaults.end() ) + return uno::Any(); + return (*aFound).second; +} + +//XMultiPropertyStates +//getPropertyStates() already declared in XPropertyState +void SAL_CALL UpDownBarWrapper::setAllPropertiesToDefault( ) +{ + const Sequence< beans::Property >& rPropSeq = *StaticUpDownBarWrapperPropertyArray::get(); + for(beans::Property const & prop : rPropSeq) + { + setPropertyToDefault( prop.Name ); + } +} +void SAL_CALL UpDownBarWrapper::setPropertiesToDefault( const uno::Sequence< OUString >& rNameSeq ) +{ + for(OUString const & s : rNameSeq) + { + setPropertyToDefault( s ); + } +} +uno::Sequence< uno::Any > SAL_CALL UpDownBarWrapper::getPropertyDefaults( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN<rNameSeq.getLength(); nN++) + { + OUString aPropertyName( rNameSeq[nN] ); + pRetSeq[nN] = getPropertyDefault( aPropertyName ); + } + } + return aRetSeq; +} + +OUString SAL_CALL UpDownBarWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.ChartArea"; +} + +sal_Bool SAL_CALL UpDownBarWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL UpDownBarWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartArea", + "com.sun.star.drawing.LineProperties", + "com.sun.star.drawing.FillProperties", + "com.sun.star.xml.UserDefinedAttributesSupplier" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.hxx b/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.hxx new file mode 100644 index 000000000..63e1c44db --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.hxx @@ -0,0 +1,105 @@ +/* -*- 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 <comphelper/interfacecontainer3.hxx> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertyStates.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <memory> + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class UpDownBarWrapper : public cppu::BaseMutex + , public ::cppu::WeakImplHelper + < css::lang::XComponent + , css::lang::XServiceInfo + , css::beans::XPropertySet + , css::beans::XMultiPropertySet + , css::beans::XPropertyState + , css::beans::XMultiPropertyStates + > +{ +public: + UpDownBarWrapper(bool bUp, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~UpDownBarWrapper() 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; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + + //XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + //XMultiPropertySet + //getPropertySetInfo() already declared in XPropertySet + virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + + //XPropertyState + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + //XMultiPropertyStates + //getPropertyStates() already declared in XPropertyState + virtual void SAL_CALL setAllPropertiesToDefault( ) override; + virtual void SAL_CALL setPropertiesToDefault( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyDefaults( const css::uno::Sequence< OUString >& aPropertyNames ) override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; + + OUString m_aPropertySetName; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WallFloorWrapper.cxx b/chart2/source/controller/chartapiwrapper/WallFloorWrapper.cxx new file mode 100644 index 000000000..9131bec9b --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WallFloorWrapper.cxx @@ -0,0 +1,168 @@ +/* -*- 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 "WallFloorWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <FillProperties.hxx> +#include <LinePropertiesHelper.hxx> +#include <UserDefinedProperties.hxx> +#include <WrappedDirectStateProperty.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +struct StaticWallFloorWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticWallFloorWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticWallFloorWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +WallFloorWrapper::WallFloorWrapper( bool bWall, + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) : + m_spChart2ModelContact( spChart2ModelContact ), + m_aEventListenerContainer( m_aMutex ), + m_bWall( bWall ) + +{ +} + +WallFloorWrapper::~WallFloorWrapper() +{ +} + +// ____ XComponent ____ +void SAL_CALL WallFloorWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + MutexGuard aGuard( m_aMutex); + clearWrappedPropertySet(); +} + +void SAL_CALL WallFloorWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL WallFloorWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// WrappedPropertySet +Reference< beans::XPropertySet > WallFloorWrapper::getInnerPropertySet() +{ + Reference< beans::XPropertySet > xRet; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + if( m_bWall ) + xRet.set( xDiagram->getWall() ); + else + xRet.set( xDiagram->getFloor() ); + } + + return xRet; +} + +const Sequence< beans::Property >& WallFloorWrapper::getPropertySequence() +{ + return *StaticWallFloorWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr<WrappedProperty> > WallFloorWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; + + // use direct state always, so that in XML the value is always + // exported. Because in the old chart the defaults is as follows: + // Floor: SOLID (new and old model default), Wall: NONE, except for some chart types (line, scatter) + if( m_bWall ) + aWrappedProperties.emplace_back( new WrappedDirectStateProperty( "FillStyle", "FillStyle" )); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty( "FillColor", "FillColor" )); + + return aWrappedProperties; +} + +OUString SAL_CALL WallFloorWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.WallOrFloor"; +} + +sal_Bool SAL_CALL WallFloorWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL WallFloorWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties", + "com.sun.star.beans.PropertySet" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WallFloorWrapper.hxx b/chart2/source/controller/chartapiwrapper/WallFloorWrapper.hxx new file mode 100644 index 000000000..3df4a9f1a --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WallFloorWrapper.hxx @@ -0,0 +1,69 @@ +/* -*- 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 <WrappedPropertySet.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <memory> + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class WallFloorWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::lang::XComponent + , css::lang::XServiceInfo + > +{ +public: + WallFloorWrapper(bool bWall, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~WallFloorWrapper() 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; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aEventListenerContainer; + + bool m_bWall; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.cxx new file mode 100644 index 000000000..24a6dfb78 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.cxx @@ -0,0 +1,121 @@ +/* -*- 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 "WrappedAddInProperty.hxx" +#include <ChartDocumentWrapper.hxx> +#include <com/sun/star/util/XRefreshable.hpp> + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using namespace ::com::sun::star; + +namespace chart::wrapper +{ + +WrappedAddInProperty::WrappedAddInProperty( ChartDocumentWrapper& rChartDocumentWrapper ) + : ::chart::WrappedProperty( "AddIn", OUString() ) + , m_rChartDocumentWrapper( rChartDocumentWrapper ) +{ +} +WrappedAddInProperty::~WrappedAddInProperty() +{ +} + +void WrappedAddInProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Reference< util::XRefreshable > xAddIn; + if( ! (rOuterValue >>= xAddIn) ) + throw lang::IllegalArgumentException( "AddIn properties require type XRefreshable", nullptr, 0 ); + + m_rChartDocumentWrapper.setAddIn( xAddIn ); +} + +Any WrappedAddInProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + return uno::Any( m_rChartDocumentWrapper.getAddIn() ); +} + +WrappedBaseDiagramProperty::WrappedBaseDiagramProperty( ChartDocumentWrapper& rChartDocumentWrapper ) + : ::chart::WrappedProperty( "BaseDiagram" , OUString() ) + , m_rChartDocumentWrapper( rChartDocumentWrapper ) +{ +} +WrappedBaseDiagramProperty::~WrappedBaseDiagramProperty() +{ +} + +void WrappedBaseDiagramProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + OUString aBaseDiagram; + if( ! (rOuterValue >>= aBaseDiagram) ) + throw lang::IllegalArgumentException( "BaseDiagram properties require type OUString", nullptr, 0 ); + + m_rChartDocumentWrapper.setBaseDiagram( aBaseDiagram ); +} + +Any WrappedBaseDiagramProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + return uno::Any( m_rChartDocumentWrapper.getBaseDiagram() ); +} + +WrappedAdditionalShapesProperty::WrappedAdditionalShapesProperty( ChartDocumentWrapper& rChartDocumentWrapper ) + : ::chart::WrappedProperty( "AdditionalShapes" , OUString() ) + , m_rChartDocumentWrapper( rChartDocumentWrapper ) +{ +} +WrappedAdditionalShapesProperty::~WrappedAdditionalShapesProperty() +{ +} + +void WrappedAdditionalShapesProperty::setPropertyValue( const Any& /*rOuterValue*/, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + throw lang::IllegalArgumentException( "AdditionalShapes is a read only property", nullptr, 0 ); +} + +Any WrappedAdditionalShapesProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + return uno::Any( m_rChartDocumentWrapper.getAdditionalShapes() ); +} + +WrappedRefreshAddInAllowedProperty::WrappedRefreshAddInAllowedProperty( ChartDocumentWrapper& rChartDocumentWrapper ) + : ::chart::WrappedProperty( "RefreshAddInAllowed" , OUString() ) + , m_rChartDocumentWrapper( rChartDocumentWrapper ) +{ +} +WrappedRefreshAddInAllowedProperty::~WrappedRefreshAddInAllowedProperty() +{ +} + +void WrappedRefreshAddInAllowedProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /* xInnerPropertySet */ ) const +{ + bool bUpdateAddIn = true; + if( ! (rOuterValue >>= bUpdateAddIn) ) + throw lang::IllegalArgumentException( "The property RefreshAddInAllowed requires type boolean", nullptr, 0 ); + + m_rChartDocumentWrapper.setUpdateAddIn( bUpdateAddIn ); +} + +Any WrappedRefreshAddInAllowedProperty::getPropertyValue( const Reference< beans::XPropertySet >& /* xInnerPropertySet */ ) const +{ + return uno::Any( m_rChartDocumentWrapper.getUpdateAddIn() ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.hxx new file mode 100644 index 000000000..b87ab15d7 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.hxx @@ -0,0 +1,87 @@ +/* -*- 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 <WrappedProperty.hxx> + +namespace chart::wrapper { class ChartDocumentWrapper; } + +namespace chart::wrapper +{ + +class WrappedAddInProperty : public WrappedProperty +{ +public: + explicit WrappedAddInProperty( ChartDocumentWrapper& rChartDocumentWrapper ); + virtual ~WrappedAddInProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + ChartDocumentWrapper& m_rChartDocumentWrapper; +}; + +class WrappedBaseDiagramProperty : public WrappedProperty +{ +public: + explicit WrappedBaseDiagramProperty( ChartDocumentWrapper& rChartDocumentWrapper ); + virtual ~WrappedBaseDiagramProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + ChartDocumentWrapper& m_rChartDocumentWrapper; +}; + +class WrappedAdditionalShapesProperty : public WrappedProperty +{ +public: + explicit WrappedAdditionalShapesProperty( ChartDocumentWrapper& rChartDocumentWrapper ); + virtual ~WrappedAdditionalShapesProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + ChartDocumentWrapper& m_rChartDocumentWrapper; +}; + +class WrappedRefreshAddInAllowedProperty : public WrappedProperty +{ +public: + explicit WrappedRefreshAddInAllowedProperty( ChartDocumentWrapper& rChartDocumentWrapper ); + virtual ~WrappedRefreshAddInAllowedProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + ChartDocumentWrapper& m_rChartDocumentWrapper; +}; + + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.cxx new file mode 100644 index 000000000..2bfb5ed42 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.cxx @@ -0,0 +1,123 @@ +/* -*- 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 "WrappedAutomaticPositionProperties.hxx" +#include <FastPropertyIdRanges.hxx> +#include <WrappedProperty.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace { + +class WrappedAutomaticPositionProperty : public WrappedProperty +{ +public: + WrappedAutomaticPositionProperty(); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; +}; + +} + +WrappedAutomaticPositionProperty::WrappedAutomaticPositionProperty() + : ::chart::WrappedProperty( "AutomaticPosition" , OUString() ) +{ +} + +void WrappedAutomaticPositionProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + return; + + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Property AutomaticPosition requires value of type boolean", nullptr, 0 ); + + try + { + if( bNewValue ) + { + Any aRelativePosition( xInnerPropertySet->getPropertyValue( "RelativePosition" ) ); + if( aRelativePosition.hasValue() ) + xInnerPropertySet->setPropertyValue( "RelativePosition", Any() ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedAutomaticPositionProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( getPropertyDefault( Reference< beans::XPropertyState >( xInnerPropertySet, uno::UNO_QUERY ) ) ); + if( xInnerPropertySet.is() ) + { + Any aRelativePosition( xInnerPropertySet->getPropertyValue( "RelativePosition" ) ); + if( !aRelativePosition.hasValue() ) + aRet <<= true; + } + return aRet; +} + +Any WrappedAutomaticPositionProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace +{ +enum +{ + PROP_CHART_AUTOMATIC_POSITION = FAST_PROPERTY_ID_START_CHART_AUTOPOSITION_PROP +}; + +}//anonymous namespace + +void WrappedAutomaticPositionProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "AutomaticPosition", + PROP_CHART_AUTOMATIC_POSITION, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void WrappedAutomaticPositionProperties::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList ) +{ + rList.emplace_back( new WrappedAutomaticPositionProperty() ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.hxx new file mode 100644 index 000000000..a98a0aa72 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.hxx @@ -0,0 +1,46 @@ +/* -*- 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 <sal/types.h> +#include <memory> +#include <vector> + +namespace chart +{ +class WrappedProperty; +} +namespace com::sun::star::beans +{ +struct Property; +} + +namespace chart::wrapper +{ +class WrappedAutomaticPositionProperties +{ +public: + static void addProperties(std::vector<css::beans::Property>& rOutProperties); + static void addWrappedProperties(std::vector<std::unique_ptr<WrappedProperty>>& rList); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.cxx new file mode 100644 index 000000000..4280fc4c0 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.cxx @@ -0,0 +1,406 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include "WrappedAxisAndGridExistenceProperties.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <WrappedProperty.hxx> +#include "Chart2ModelContact.hxx" +#include <TitleHelper.hxx> +#include <osl/diagnose.h> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + +namespace chart::wrapper +{ + +namespace { + +class WrappedAxisAndGridExistenceProperty : public WrappedProperty +{ +public: + WrappedAxisAndGridExistenceProperty( bool bAxis, bool bMain, sal_Int32 nDimensionIndex + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + bool m_bAxis; + bool m_bMain; + sal_Int32 m_nDimensionIndex; +}; + +} + +void WrappedAxisAndGridExistenceProperties::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, true, 0, spChart2ModelContact ) );//x axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, false, 0, spChart2ModelContact ) );//x secondary axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, true, 0, spChart2ModelContact ) );//x grid + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, false, 0, spChart2ModelContact ) );//x help grid + + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, true, 1, spChart2ModelContact ) );//y axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, false, 1, spChart2ModelContact ) );//y secondary axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, true, 1, spChart2ModelContact ) );//y grid + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, false, 1, spChart2ModelContact ) );//y help grid + + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, true, 2, spChart2ModelContact ) );//z axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, true, 2, spChart2ModelContact ) );//z grid + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, false, 2, spChart2ModelContact ) );//z help grid +} + +WrappedAxisAndGridExistenceProperty::WrappedAxisAndGridExistenceProperty( bool bAxis, bool bMain, sal_Int32 nDimensionIndex + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_bAxis( bAxis ) + , m_bMain( bMain ) + , m_nDimensionIndex( nDimensionIndex ) +{ + switch( m_nDimensionIndex ) + { + case 0: + { + if( m_bAxis ) + { + if( m_bMain ) + m_aOuterName = "HasXAxis"; + else + m_aOuterName = "HasSecondaryXAxis"; + } + else + { + if( m_bMain ) + m_aOuterName = "HasXAxisGrid"; + else + m_aOuterName = "HasXAxisHelpGrid"; + } + } + break; + case 2: + { + if( m_bAxis ) + { + OSL_ENSURE(m_bMain,"there is no secondary z axis at the old api"); + m_bMain = true; + m_aOuterName = "HasZAxis"; + } + else + { + if( m_bMain ) + m_aOuterName = "HasZAxisGrid"; + else + m_aOuterName = "HasZAxisHelpGrid"; + } + } + break; + default: + { + if( m_bAxis ) + { + if( m_bMain ) + m_aOuterName = "HasYAxis"; + else + m_aOuterName = "HasSecondaryYAxis"; + } + else + { + if( m_bMain ) + m_aOuterName = "HasYAxisGrid"; + else + m_aOuterName = "HasYAxisHelpGrid"; + } + } + break; + } +} + +void WrappedAxisAndGridExistenceProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Has axis or grid properties require boolean values", nullptr, 0 ); + + bool bOldValue = false; + getPropertyValue( xInnerPropertySet ) >>= bOldValue; + + if( bOldValue == bNewValue ) + return; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( bNewValue ) + { + if( m_bAxis ) + AxisHelper::showAxis( m_nDimensionIndex, m_bMain, xDiagram, m_spChart2ModelContact->m_xContext ); + else + AxisHelper::showGrid( m_nDimensionIndex, 0, m_bMain, xDiagram ); + } + else + { + if( m_bAxis ) + AxisHelper::hideAxis( m_nDimensionIndex, m_bMain, xDiagram ); + else + AxisHelper::hideGrid( m_nDimensionIndex, 0, m_bMain, xDiagram ); + } +} + +Any WrappedAxisAndGridExistenceProperty::getPropertyValue( const Reference< beans::XPropertySet >& /* xInnerPropertySet */ ) const +{ + Any aRet; + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if(m_bAxis) + { + bool bShown = AxisHelper::isAxisShown( m_nDimensionIndex, m_bMain, xDiagram ); + aRet <<= bShown; + } + else + { + bool bShown = AxisHelper::isGridShown( m_nDimensionIndex, 0, m_bMain, xDiagram ); + aRet <<= bShown; + } + return aRet; +} + +Any WrappedAxisAndGridExistenceProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +class WrappedAxisTitleExistenceProperty : public WrappedProperty +{ +public: + WrappedAxisTitleExistenceProperty( sal_Int32 nTitleIndex + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + TitleHelper::eTitleType m_eTitleType; +}; + +} + +void WrappedAxisTitleExistenceProperties::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 0, spChart2ModelContact ) );//x axis title + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 1, spChart2ModelContact ) );//y axis title + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 2, spChart2ModelContact ) );//z axis title + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 3, spChart2ModelContact ) );//secondary x axis title + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 4, spChart2ModelContact ) );//secondary y axis title +} + +WrappedAxisTitleExistenceProperty::WrappedAxisTitleExistenceProperty(sal_Int32 nTitleIndex + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_eTitleType( TitleHelper::Y_AXIS_TITLE ) +{ + switch( nTitleIndex ) + { + case 0: + m_aOuterName = "HasXAxisTitle"; + m_eTitleType = TitleHelper::X_AXIS_TITLE; + break; + case 2: + m_aOuterName = "HasZAxisTitle"; + m_eTitleType = TitleHelper::Z_AXIS_TITLE; + break; + case 3: + m_aOuterName = "HasSecondaryXAxisTitle"; + m_eTitleType = TitleHelper::SECONDARY_X_AXIS_TITLE; + break; + case 4: + m_aOuterName = "HasSecondaryYAxisTitle"; + m_eTitleType = TitleHelper::SECONDARY_Y_AXIS_TITLE; + break; + default: + m_aOuterName = "HasYAxisTitle"; + m_eTitleType = TitleHelper::Y_AXIS_TITLE; + break; + } +} + +void WrappedAxisTitleExistenceProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Has axis or grid properties require boolean values", nullptr, 0 ); + + bool bOldValue = false; + getPropertyValue( xInnerPropertySet ) >>= bOldValue; + + if( bOldValue == bNewValue ) + return; + + if( bNewValue ) + { + TitleHelper::createTitle( m_eTitleType, OUString() + , m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext ); + } + else + { + TitleHelper::removeTitle( m_eTitleType, m_spChart2ModelContact->getDocumentModel() ); + } +} + +Any WrappedAxisTitleExistenceProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bHasTitle = false; + + Reference< chart2::XTitle > xTitle( TitleHelper::getTitle( m_eTitleType, m_spChart2ModelContact->getDocumentModel() ) ); + if( xTitle.is() && !TitleHelper::getCompleteString( xTitle ).isEmpty() ) + bHasTitle = true; + + Any aRet; + aRet <<= bHasTitle; + return aRet; + +} + +Any WrappedAxisTitleExistenceProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +class WrappedAxisLabelExistenceProperty : public WrappedProperty +{ +public: + WrappedAxisLabelExistenceProperty( bool bMain, sal_Int32 nDimensionIndex + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + bool m_bMain; + sal_Int32 m_nDimensionIndex; +}; + +} + +void WrappedAxisLabelExistenceProperties::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedAxisLabelExistenceProperty( true, 0, spChart2ModelContact ) );//x axis + rList.emplace_back( new WrappedAxisLabelExistenceProperty( true, 1, spChart2ModelContact ) );//y axis + rList.emplace_back( new WrappedAxisLabelExistenceProperty( true, 2, spChart2ModelContact ) );//z axis + rList.emplace_back( new WrappedAxisLabelExistenceProperty( false, 0, spChart2ModelContact ) );//secondary x axis + rList.emplace_back( new WrappedAxisLabelExistenceProperty( false, 1, spChart2ModelContact ) );//secondary y axis +} + +WrappedAxisLabelExistenceProperty::WrappedAxisLabelExistenceProperty(bool bMain, sal_Int32 nDimensionIndex + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_bMain( bMain ) + , m_nDimensionIndex( nDimensionIndex ) +{ + switch( m_nDimensionIndex ) + { + case 0: + m_aOuterName = m_bMain ? std::u16string_view(u"HasXAxisDescription") : std::u16string_view(u"HasSecondaryXAxisDescription"); + break; + case 2: + OSL_ENSURE(m_bMain,"there is no description available for a secondary z axis"); + m_aOuterName = "HasZAxisDescription"; + break; + default: + m_aOuterName = m_bMain ? std::u16string_view(u"HasYAxisDescription") : std::u16string_view(u"HasSecondaryYAxisDescription"); + break; + } +} + +void WrappedAxisLabelExistenceProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Has axis or grid properties require boolean values", nullptr, 0 ); + + bool bOldValue = false; + getPropertyValue( xInnerPropertySet ) >>= bOldValue; + + if( bOldValue == bNewValue ) + return; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< Axis > xProp = AxisHelper::getAxis( m_nDimensionIndex, m_bMain, xDiagram ); + if( !xProp.is() && bNewValue ) + { + //create axis if needed + xProp = AxisHelper::createAxis( m_nDimensionIndex, m_bMain, xDiagram, m_spChart2ModelContact->m_xContext ); + if( xProp.is() ) + xProp->setPropertyValue( "Show", uno::Any( false ) ); + } + if( xProp.is() ) + xProp->setPropertyValue( "DisplayLabels", rOuterValue ); +} + +Any WrappedAxisLabelExistenceProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< Axis > xProp = AxisHelper::getAxis( m_nDimensionIndex, m_bMain, xDiagram ); + if( xProp.is() ) + aRet = xProp->getPropertyValue( "DisplayLabels" ); + else + aRet <<= false; + return aRet; +} + +Any WrappedAxisLabelExistenceProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= true; + return aRet; +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.hxx new file mode 100644 index 000000000..c15bee711 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.hxx @@ -0,0 +1,54 @@ +/* -*- 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 <memory> +#include <vector> + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + +class WrappedAxisAndGridExistenceProperties +{ +public: + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +class WrappedAxisTitleExistenceProperties +{ +public: + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +class WrappedAxisLabelExistenceProperties +{ +public: + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.cxx new file mode 100644 index 000000000..67ea51b0e --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.cxx @@ -0,0 +1,138 @@ +/* -*- 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 "WrappedCharacterHeightProperty.hxx" +#include <RelativeSizeHelper.hxx> +#include "ReferenceSizePropertyProvider.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <osl/diagnose.h> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +namespace chart::wrapper +{ +WrappedCharacterHeightProperty_Base::WrappedCharacterHeightProperty_Base( + const OUString& rOuterEqualsInnerName + , ReferenceSizePropertyProvider* pRefSizePropProvider ) + : WrappedProperty( rOuterEqualsInnerName, rOuterEqualsInnerName ) + , m_pRefSizePropProvider( pRefSizePropProvider ) +{ +} +WrappedCharacterHeightProperty_Base::~WrappedCharacterHeightProperty_Base() +{ +} + +void WrappedCharacterHeightProperty::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , ReferenceSizePropertyProvider* pRefSizePropProvider ) +{ + rList.emplace_back( new WrappedCharacterHeightProperty( pRefSizePropProvider ) ); + rList.emplace_back( new WrappedAsianCharacterHeightProperty( pRefSizePropProvider ) ); + rList.emplace_back( new WrappedComplexCharacterHeightProperty( pRefSizePropProvider ) ); +} + +void WrappedCharacterHeightProperty_Base::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if(xInnerPropertySet.is()) + { + if( m_pRefSizePropProvider ) + m_pRefSizePropProvider->updateReferenceSize(); + xInnerPropertySet->setPropertyValue( m_aInnerName, rOuterValue ); + } +} + +Any WrappedCharacterHeightProperty_Base::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet; + if( xInnerPropertySet.is() ) + { + aRet = xInnerPropertySet->getPropertyValue( m_aInnerName ); + float fHeight = 0; + if( aRet >>= fHeight ) + { + if( m_pRefSizePropProvider ) + { + awt::Size aReferenceSize; + if( m_pRefSizePropProvider->getReferenceSize() >>= aReferenceSize ) + { + awt::Size aCurrentSize = m_pRefSizePropProvider->getCurrentSizeForReference(); + aRet <<= static_cast< float >( + RelativeSizeHelper::calculate( fHeight, aReferenceSize, aCurrentSize )); + } + } + } + } + return aRet; +} + +Any WrappedCharacterHeightProperty_Base::getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + Any aRet; + if( xInnerPropertyState.is() ) + { + aRet = xInnerPropertyState->getPropertyDefault( m_aInnerName ); + } + return aRet; +} + +beans::PropertyState WrappedCharacterHeightProperty_Base::getPropertyState( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return beans::PropertyState_DIRECT_VALUE; +} + +Any WrappedCharacterHeightProperty_Base::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + OSL_FAIL("should not be used: WrappedCharacterHeightProperty_Base::convertInnerToOuterValue - check if you miss data"); + return rInnerValue; +} +Any WrappedCharacterHeightProperty_Base::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + OSL_FAIL("should not be used: WrappedCharacterHeightProperty_Base::convertOuterToInnerValue - check if you miss data"); + return rOuterValue; +} + +WrappedCharacterHeightProperty::WrappedCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ) + : WrappedCharacterHeightProperty_Base( "CharHeight", pRefSizePropProvider ) +{ +} +WrappedCharacterHeightProperty::~WrappedCharacterHeightProperty() +{ +} + +WrappedAsianCharacterHeightProperty::WrappedAsianCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ) + : WrappedCharacterHeightProperty_Base( "CharHeightAsian", pRefSizePropProvider ) +{ +} +WrappedAsianCharacterHeightProperty::~WrappedAsianCharacterHeightProperty() +{ +} + +WrappedComplexCharacterHeightProperty::WrappedComplexCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ) + : WrappedCharacterHeightProperty_Base( "CharHeightComplex", pRefSizePropProvider ) +{ +} +WrappedComplexCharacterHeightProperty::~WrappedComplexCharacterHeightProperty() +{ +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.hxx new file mode 100644 index 000000000..7eee90a2c --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.hxx @@ -0,0 +1,77 @@ +/* -*- 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 <WrappedProperty.hxx> + +#include <vector> + +namespace chart::wrapper +{ + +class ReferenceSizePropertyProvider; + +class WrappedCharacterHeightProperty_Base : public WrappedProperty +{ +public: + WrappedCharacterHeightProperty_Base( const OUString& rOuterEqualsInnerName, ReferenceSizePropertyProvider* pRefSizePropProvider ); + virtual ~WrappedCharacterHeightProperty_Base() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + virtual css::beans::PropertyState getPropertyState( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + virtual css::uno::Any convertInnerToOuterValue( const css::uno::Any& rInnerValue ) const override; + virtual css::uno::Any convertOuterToInnerValue( const css::uno::Any& rOuterValue ) const override; + +protected: + ReferenceSizePropertyProvider* m_pRefSizePropProvider; +}; + +class WrappedCharacterHeightProperty : public WrappedCharacterHeightProperty_Base +{ +public: + explicit WrappedCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ); + virtual ~WrappedCharacterHeightProperty() override; + + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList, ReferenceSizePropertyProvider* pRefSizePropProvider ); +}; + +class WrappedAsianCharacterHeightProperty : public WrappedCharacterHeightProperty_Base +{ +public: + explicit WrappedAsianCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ); + virtual ~WrappedAsianCharacterHeightProperty() override; +}; + +class WrappedComplexCharacterHeightProperty : public WrappedCharacterHeightProperty_Base +{ +public: + explicit WrappedComplexCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ); + virtual ~WrappedComplexCharacterHeightProperty() override; +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.cxx new file mode 100644 index 000000000..d317210c3 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.cxx @@ -0,0 +1,156 @@ +/* -*- 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 "WrappedDataCaptionProperties.hxx" +#include "WrappedSeriesOrDiagramProperty.hxx" +#include <FastPropertyIdRanges.hxx> +#include <unonames.hxx> + +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <com/sun/star/chart/ChartDataCaption.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace +{ + +class WrappedDataCaptionProperty : public WrappedSeriesOrDiagramProperty< sal_Int32 > +{ +public: + virtual sal_Int32 getValueFromSeries( const css::uno::Reference< css::beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const css::uno::Reference< css::beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& aNewValue ) const override; + + explicit WrappedDataCaptionProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +enum +{ + //data caption properties + PROP_CHART_DATAPOINT_DATA_CAPTION = FAST_PROPERTY_ID_START_CHART_DATACAPTION_PROP +}; + +sal_Int32 lcl_LabelToCaption( const chart2::DataPointLabel& rLabel ) +{ + sal_Int32 nCaption=0; + + if( rLabel.ShowNumber ) + nCaption |= css::chart::ChartDataCaption::VALUE; + if( rLabel.ShowNumberInPercent ) + nCaption |= css::chart::ChartDataCaption::PERCENT; + if( rLabel.ShowCategoryName ) + nCaption |= css::chart::ChartDataCaption::TEXT; + if( rLabel.ShowLegendSymbol ) + nCaption |= css::chart::ChartDataCaption::SYMBOL; + if (rLabel.ShowSeriesName) + nCaption |= css::chart::ChartDataCaption::DATA_SERIES; + + return nCaption; +} + +chart2::DataPointLabel lcl_CaptionToLabel( sal_Int32 nCaption ) +{ + chart2::DataPointLabel aLabel(false,false,false,false,false,false); + + if( nCaption & css::chart::ChartDataCaption::VALUE ) + aLabel.ShowNumber = true; + if( nCaption & css::chart::ChartDataCaption::PERCENT ) + aLabel.ShowNumberInPercent = true; + if( nCaption & css::chart::ChartDataCaption::TEXT ) + aLabel.ShowCategoryName = true; + if( nCaption & css::chart::ChartDataCaption::SYMBOL ) + aLabel.ShowLegendSymbol = true; + if( nCaption & css::chart::ChartDataCaption::CUSTOM ) + aLabel.ShowCustomLabel = true; + if( nCaption & css::chart::ChartDataCaption::DATA_SERIES ) + aLabel.ShowSeriesName = true; + + return aLabel; +} + +void lcl_addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) +{ + //if !spChart2ModelContact.get() is then the created properties do belong to a single series or single datapoint + //otherwise they do belong to the whole diagram + + rList.emplace_back( new WrappedDataCaptionProperty( spChart2ModelContact, ePropertyType ) ); +} + +}//anonymous namespace + +void WrappedDataCaptionProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "DataCaption", + PROP_CHART_DATAPOINT_DATA_CAPTION, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void WrappedDataCaptionProperties::addWrappedPropertiesForSeries( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DATA_SERIES ); +} + +void WrappedDataCaptionProperties::addWrappedPropertiesForDiagram( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DIAGRAM ); +} + +WrappedDataCaptionProperty::WrappedDataCaptionProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty< sal_Int32 >( "DataCaption" + , uno::Any( sal_Int32(0) ), spChart2ModelContact, ePropertyType ) +{ +} + +sal_Int32 WrappedDataCaptionProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + sal_Int32 aRet = 0; + m_aDefaultValue >>= aRet; + chart2::DataPointLabel aLabel; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel ) ) + aRet = lcl_LabelToCaption( aLabel ); + return aRet; +} + +void WrappedDataCaptionProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& nCaption ) const +{ + if(!xSeriesPropertySet.is()) + return; + + chart2::DataPointLabel aLabel = lcl_CaptionToLabel( nCaption ); + xSeriesPropertySet->setPropertyValue( CHART_UNONAME_LABEL, uno::Any( aLabel ) ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.hxx new file mode 100644 index 000000000..a2bcaa302 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.hxx @@ -0,0 +1,44 @@ +/* -*- 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 <sal/types.h> +#include <memory> +#include <vector> + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedDataCaptionProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedPropertiesForSeries( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); + static void addWrappedPropertiesForDiagram( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.cxx new file mode 100644 index 000000000..8ad57070a --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.cxx @@ -0,0 +1,168 @@ +/* -*- 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 <sal/config.h> + +#include <cstddef> + +#include "WrappedGapwidthProperty.hxx" +#include "Chart2ModelContact.hxx" +#include <ChartType.hxx> +#include <DiagramHelper.hxx> +#include <tools/long.hxx> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace chart::wrapper +{ + +const sal_Int32 DEFAULT_GAPWIDTH = 100; +const sal_Int32 DEFAULT_OVERLAP = 0; + +WrappedBarPositionProperty_Base::WrappedBarPositionProperty_Base( + const OUString& rOuterName + , const OUString& rInnerSequencePropertyName + , sal_Int32 nDefaultValue + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) + : WrappedDefaultProperty( rOuterName, OUString(), uno::Any( nDefaultValue ) ) + , m_nDimensionIndex(0) + , m_nAxisIndex(0) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_nDefaultValue( nDefaultValue ) + , m_InnerSequencePropertyName( rInnerSequencePropertyName ) +{ +} + +void WrappedBarPositionProperty_Base::setDimensionAndAxisIndex( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + m_nDimensionIndex = nDimensionIndex; + m_nAxisIndex = nAxisIndex; +} + +WrappedBarPositionProperty_Base::~WrappedBarPositionProperty_Base() +{ +} + +void WrappedBarPositionProperty_Base::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + sal_Int32 nNewValue = 0; + if( ! (rOuterValue >>= nNewValue) ) + throw lang::IllegalArgumentException( "GapWidth and Overlap property require value of type sal_Int32", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( !xDiagram.is() ) + return; + + if( m_nDimensionIndex!=1 ) + return; + + const std::vector< rtl::Reference< ChartType > > aChartTypeList( DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( rtl::Reference< ChartType > const & chartType : aChartTypeList ) + { + try + { + Sequence< sal_Int32 > aBarPositionSequence; + chartType->getPropertyValue( m_InnerSequencePropertyName ) >>= aBarPositionSequence; + + tools::Long nOldLength = aBarPositionSequence.getLength(); + if( nOldLength <= m_nAxisIndex ) + aBarPositionSequence.realloc( m_nAxisIndex+1 ); + auto pBarPositionSequence = aBarPositionSequence.getArray(); + for( sal_Int32 i=nOldLength; i<m_nAxisIndex; i++ ) + { + pBarPositionSequence[i] = m_nDefaultValue; + } + pBarPositionSequence[m_nAxisIndex] = nNewValue; + + chartType->setPropertyValue( m_InnerSequencePropertyName, uno::Any( aBarPositionSequence ) ); + } + catch( uno::Exception& e ) + { + //the above properties are not supported by all charttypes (only by column and bar) + //in that cases this exception is ok + e.Context.is();//to have debug information without compilation warnings + } + } +} + +Any WrappedBarPositionProperty_Base::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + bool bInnerValueDetected = false; + sal_Int32 nInnerValue = m_nDefaultValue; + + if( m_nDimensionIndex==1 ) + { + std::vector< rtl::Reference< ChartType > > aChartTypeList( DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( std::size_t nN = 0; nN < aChartTypeList.size() && !bInnerValueDetected; nN++ ) + { + try + { + Sequence< sal_Int32 > aBarPositionSequence; + aChartTypeList[nN]->getPropertyValue( m_InnerSequencePropertyName ) >>= aBarPositionSequence; + if( m_nAxisIndex < aBarPositionSequence.getLength() ) + { + nInnerValue = aBarPositionSequence[m_nAxisIndex]; + bInnerValueDetected = true; + } + } + catch( uno::Exception& e ) + { + //the above properties are not supported by all charttypes (only by column and bar) + //in that cases this exception is ok + e.Context.is();//to have debug information without compilation warnings + } + } + } + if( bInnerValueDetected ) + { + m_aOuterValue <<= nInnerValue; + } + } + return m_aOuterValue; +} + +WrappedGapwidthProperty::WrappedGapwidthProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedBarPositionProperty_Base( "GapWidth", "GapwidthSequence", DEFAULT_GAPWIDTH, spChart2ModelContact ) +{ +} +WrappedGapwidthProperty::~WrappedGapwidthProperty() +{ +} + +WrappedBarOverlapProperty::WrappedBarOverlapProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) + : WrappedBarPositionProperty_Base( "Overlap", "OverlapSequence", DEFAULT_OVERLAP, spChart2ModelContact ) +{ +} +WrappedBarOverlapProperty::~WrappedBarOverlapProperty() +{ +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.hxx new file mode 100644 index 000000000..550b0ce6a --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.hxx @@ -0,0 +1,73 @@ +/* -*- 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 <WrappedDefaultProperty.hxx> + +#include <memory> + +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + +class WrappedBarPositionProperty_Base : public WrappedDefaultProperty +{ +public: + WrappedBarPositionProperty_Base( + const OUString& rOuterName + , const OUString& rInnerSequencePropertyName + , sal_Int32 nDefaultValue + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ); + virtual ~WrappedBarPositionProperty_Base() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + void setDimensionAndAxisIndex( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + +protected: + sal_Int32 m_nDimensionIndex; + sal_Int32 m_nAxisIndex; + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + + sal_Int32 m_nDefaultValue; + OUString m_InnerSequencePropertyName; + + mutable css::uno::Any m_aOuterValue; +}; + +class WrappedGapwidthProperty : public WrappedBarPositionProperty_Base +{ +public: + explicit WrappedGapwidthProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~WrappedGapwidthProperty() override; +}; + +class WrappedBarOverlapProperty : public WrappedBarPositionProperty_Base +{ +public: + explicit WrappedBarOverlapProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~WrappedBarOverlapProperty() override; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.cxx new file mode 100644 index 000000000..1ce277c32 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.cxx @@ -0,0 +1,121 @@ +/* -*- 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 "WrappedNumberFormatProperty.hxx" +#include "Chart2ModelContact.hxx" +#include <com/sun/star/chart2/XAxis.hpp> +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <unonames.hxx> +#include <osl/diagnose.h> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +namespace chart::wrapper +{ + +WrappedNumberFormatProperty::WrappedNumberFormatProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedDirectStateProperty( CHART_UNONAME_NUMFMT, CHART_UNONAME_NUMFMT ) + , m_spChart2ModelContact(spChart2ModelContact) +{ +} + +WrappedNumberFormatProperty::~WrappedNumberFormatProperty() +{ +} + +void WrappedNumberFormatProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + sal_Int32 nFormat = 0; + if( ! (rOuterValue >>= nFormat) ) + throw lang::IllegalArgumentException( "Property 'NumberFormat' requires value of type sal_Int32", nullptr, 0 ); + + if(xInnerPropertySet.is()) + xInnerPropertySet->setPropertyValue(getInnerName(), convertOuterToInnerValue(rOuterValue)); +} + +Any WrappedNumberFormatProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + { + OSL_FAIL("missing xInnerPropertySet in WrappedNumberFormatProperty::getPropertyValue"); + return Any(); + } + Any aRet( xInnerPropertySet->getPropertyValue(getInnerName())); + if( !aRet.hasValue() ) + { + sal_Int32 nKey = 0; + Reference< chart2::XDataSeries > xSeries( xInnerPropertySet, uno::UNO_QUERY ); + if( xSeries.is() ) + nKey = Chart2ModelContact::getExplicitNumberFormatKeyForSeries( xSeries ); + else + { + Reference< chart2::XAxis > xAxis( xInnerPropertySet, uno::UNO_QUERY ); + nKey = m_spChart2ModelContact->getExplicitNumberFormatKeyForAxis( xAxis ); + } + aRet <<= nKey; + } + return aRet; +} + +Any WrappedNumberFormatProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any( sal_Int32( 0 ) ); +} + +WrappedLinkNumberFormatProperty::WrappedLinkNumberFormatProperty() : + WrappedDirectStateProperty(CHART_UNONAME_LINK_TO_SRC_NUMFMT, CHART_UNONAME_LINK_TO_SRC_NUMFMT) +{ +} + +WrappedLinkNumberFormatProperty::~WrappedLinkNumberFormatProperty() +{ +} + +void WrappedLinkNumberFormatProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + { + OSL_FAIL("missing xInnerPropertySet in WrappedNumberFormatProperty::setPropertyValue"); + return; + } + + xInnerPropertySet->setPropertyValue(getInnerName(), rOuterValue); +} + +Any WrappedLinkNumberFormatProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + { + OSL_FAIL("missing xInnerPropertySet in WrappedNumberFormatProperty::getPropertyValue"); + return getPropertyDefault(nullptr); + } + + return xInnerPropertySet->getPropertyValue(getInnerName()); +} + +Any WrappedLinkNumberFormatProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any( true ); // bLink +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.hxx new file mode 100644 index 000000000..fa4042cea --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.hxx @@ -0,0 +1,64 @@ +/* -*- 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 <WrappedDirectStateProperty.hxx> + +#include <memory> + +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + + +class WrappedNumberFormatProperty : public WrappedDirectStateProperty +{ +public: + explicit WrappedNumberFormatProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~WrappedNumberFormatProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + friend class WrappedLinkNumberFormatProperty; +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +class WrappedLinkNumberFormatProperty : public WrappedDirectStateProperty +{ +public: + explicit WrappedLinkNumberFormatProperty(); + virtual ~WrappedLinkNumberFormatProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.cxx new file mode 100644 index 000000000..27e07256e --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.cxx @@ -0,0 +1,587 @@ +/* -*- 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 "WrappedScaleProperty.hxx" +#include "Chart2ModelContact.hxx" +#include <CommonConverters.hxx> +#include <AxisHelper.hxx> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/XAxis.hpp> +#include <com/sun/star/chart/ChartAxisType.hpp> +#include <chartview/ExplicitScaleValues.hxx> +#include <osl/diagnose.h> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::chart::TimeIncrement; + +namespace chart::wrapper +{ + +WrappedScaleProperty::WrappedScaleProperty(tScaleProperty eScaleProperty + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_eScaleProperty( eScaleProperty ) +{ + switch( m_eScaleProperty ) + { + case SCALE_PROP_MAX: + m_aOuterName = "Max"; + break; + case SCALE_PROP_MIN: + m_aOuterName = "Min"; + break; + case SCALE_PROP_ORIGIN: + m_aOuterName = "Origin"; + break; + case SCALE_PROP_STEPMAIN: + m_aOuterName = "StepMain"; + break; + case SCALE_PROP_STEPHELP: + m_aOuterName = "StepHelp"; + break; + case SCALE_PROP_STEPHELP_COUNT: + m_aOuterName = "StepHelpCount"; + break; + case SCALE_PROP_AUTO_MAX: + m_aOuterName = "AutoMax"; + break; + case SCALE_PROP_AUTO_MIN: + m_aOuterName = "AutoMin"; + break; + case SCALE_PROP_AUTO_ORIGIN: + m_aOuterName = "AutoOrigin"; + break; + case SCALE_PROP_AUTO_STEPMAIN: + m_aOuterName = "AutoStepMain"; + break; + case SCALE_PROP_AUTO_STEPHELP: + m_aOuterName = "AutoStepHelp"; + break; + case SCALE_PROP_AXIS_TYPE: + m_aOuterName = "AxisType"; + break; + case SCALE_PROP_DATE_INCREMENT: + m_aOuterName = "TimeIncrement"; + break; + case SCALE_PROP_EXPLICIT_DATE_INCREMENT: + m_aOuterName = "ExplicitTimeIncrement"; + break; + case SCALE_PROP_LOGARITHMIC: + m_aOuterName = "Logarithmic"; + break; + case SCALE_PROP_REVERSEDIRECTION: + m_aOuterName = "ReverseDirection"; + break; + default: + OSL_FAIL("unknown scale property"); + break; + } +} + +WrappedScaleProperty::~WrappedScaleProperty() +{ +} + +void WrappedScaleProperty::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_MAX, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_MIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_ORIGIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_STEPMAIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_STEPHELP, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_STEPHELP_COUNT, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_MAX, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_MIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_ORIGIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_STEPMAIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_STEPHELP, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AXIS_TYPE, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_DATE_INCREMENT, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_EXPLICIT_DATE_INCREMENT, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_LOGARITHMIC, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_REVERSEDIRECTION, spChart2ModelContact ) ); +} + +void WrappedScaleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + setPropertyValue( m_eScaleProperty, rOuterValue, xInnerPropertySet ); +} + +Any WrappedScaleProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + return getPropertyValue( m_eScaleProperty, xInnerPropertySet ); +} + +void WrappedScaleProperty::setPropertyValue( tScaleProperty eScaleProperty, const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + m_aOuterValue = rOuterValue; + + Reference< chart2::XAxis > xAxis( xInnerPropertySet, uno::UNO_QUERY ); + OSL_ENSURE(xAxis.is(),"need an XAxis"); + if(!xAxis.is()) + return; + + bool bSetScaleData = false; + + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + + bool bBool = false; + switch( eScaleProperty ) + { + case SCALE_PROP_MAX: + { + aScaleData.Maximum = rOuterValue; + bSetScaleData = true; + break; + } + case SCALE_PROP_MIN: + { + aScaleData.Minimum = rOuterValue; + bSetScaleData = true; + break; + } + case SCALE_PROP_STEPMAIN: + { + aScaleData.IncrementData.Distance = rOuterValue; + bSetScaleData = true; + break; + } + case SCALE_PROP_STEPHELP: + { + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( !rSubIncrements.hasElements() ) + rSubIncrements.realloc( 1 ); + auto pSubIncrements = rSubIncrements.getArray(); + + double fStepHelp = 0; + if( rOuterValue >>= fStepHelp ) + { + double fStepMain = 0; + if( AxisHelper::isLogarithmic(aScaleData.Scaling) ) + { + sal_Int32 nIntervalCount = static_cast< sal_Int32 >(fStepHelp); + pSubIncrements[ 0 ].IntervalCount <<= nIntervalCount; + } + else if( (fStepHelp != 0.0) && + (aScaleData.IncrementData.Distance >>= fStepMain) ) + { + // approximate interval count + sal_Int32 nIntervalCount = static_cast< sal_Int32 >(fStepMain / fStepHelp);//cppcheck-suppress zerodiv + pSubIncrements[ 0 ].IntervalCount <<= nIntervalCount; + } + } + bSetScaleData = true; + break; + } + case SCALE_PROP_STEPHELP_COUNT: + { + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( !rSubIncrements.hasElements() ) + rSubIncrements.realloc( 1 ); + auto pSubIncrements = rSubIncrements.getArray(); + sal_Int32 nIntervalCount=0; + if( rOuterValue>>=nIntervalCount ) + pSubIncrements[ 0 ].IntervalCount <<= nIntervalCount; + else + pSubIncrements[ 0 ].IntervalCount = Any(); + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_MAX: + { + if( (rOuterValue >>= bBool) && bBool ) + aScaleData.Maximum = Any(); + else + aScaleData.Maximum = getPropertyValue( SCALE_PROP_MAX, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_MIN: + { + if( (rOuterValue >>= bBool) && bBool ) + aScaleData.Minimum = Any(); + else + aScaleData.Minimum = getPropertyValue( SCALE_PROP_MIN, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_STEPMAIN: + { + if( (rOuterValue >>= bBool) && bBool ) + aScaleData.IncrementData.Distance = Any(); + else + aScaleData.IncrementData.Distance = getPropertyValue( SCALE_PROP_STEPMAIN, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_STEPHELP: + { + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( !rSubIncrements.hasElements() ) + rSubIncrements.realloc( 1 ); + auto pSubIncrements = rSubIncrements.getArray(); + + if( (rOuterValue >>= bBool) && bBool ) + pSubIncrements[ 0 ].IntervalCount = Any(); + else + pSubIncrements[ 0 ].IntervalCount = getPropertyValue( SCALE_PROP_STEPHELP_COUNT, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_ORIGIN: + { + aScaleData.Origin = rOuterValue; + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_ORIGIN: + { + if( (rOuterValue >>= bBool) && bBool ) + aScaleData.Origin = Any(); + else + aScaleData.Origin = getPropertyValue( SCALE_PROP_ORIGIN, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_AXIS_TYPE: + { + sal_Int32 nType = 0; + if( rOuterValue >>= nType ) + { + if( nType == css::chart::ChartAxisType::AUTOMATIC ) + { + aScaleData.AutoDateAxis = true; + if( aScaleData.AxisType == AxisType::DATE ) + aScaleData.AxisType = AxisType::CATEGORY; + } + else if( nType == css::chart::ChartAxisType::CATEGORY ) + { + aScaleData.AutoDateAxis = false; + if( aScaleData.AxisType == AxisType::DATE ) + aScaleData.AxisType = AxisType::CATEGORY; + } + else if( nType == css::chart::ChartAxisType::DATE ) + { + if( aScaleData.AxisType == AxisType::CATEGORY ) + aScaleData.AxisType = AxisType::DATE; + } + bSetScaleData = true; + } + break; + } + case SCALE_PROP_DATE_INCREMENT: + { + TimeIncrement aTimeIncrement; + rOuterValue >>= aTimeIncrement; + aScaleData.TimeIncrement = aTimeIncrement; + bSetScaleData = true; + break; + } + case SCALE_PROP_EXPLICIT_DATE_INCREMENT: + //read only property + break; + case SCALE_PROP_LOGARITHMIC: + { + if( rOuterValue >>= bBool ) + { + bool bWasLogarithm = AxisHelper::isLogarithmic( aScaleData.Scaling ); + + // safe comparison between sal_Bool and bool + if( (!bBool) != (!bWasLogarithm) ) + { + if( bBool ) + aScaleData.Scaling = AxisHelper::createLogarithmicScaling( 10.0 ); + else + aScaleData.Scaling = nullptr; + bSetScaleData = true; + } + } + break; + } + case SCALE_PROP_REVERSEDIRECTION: + { + if( rOuterValue >>= bBool ) + { + bool bWasReverse = ( aScaleData.Orientation == AxisOrientation_REVERSE ); + if( (!bBool) != (!bWasReverse) ) // safe comparison between sal_Bool and bool + { + aScaleData.Orientation = bBool ? AxisOrientation_REVERSE : AxisOrientation_MATHEMATICAL; + bSetScaleData = true; + } + } + break; + } + default: + { + OSL_FAIL("unknown scale property"); + break; + } + } + + if( bSetScaleData ) + xAxis->setScaleData( aScaleData ); +} + +Any WrappedScaleProperty::getPropertyValue( tScaleProperty eScaleProperty, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( m_aOuterValue ); + + Reference< chart2::XAxis > xAxis( xInnerPropertySet, uno::UNO_QUERY ); + OSL_ENSURE(xAxis.is(),"need an XAxis"); + if(!xAxis.is()) + return aRet; + + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + + switch( eScaleProperty ) + { + case SCALE_PROP_MAX: + { + aRet = aScaleData.Maximum; + if( !aRet.hasValue() ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + aRet <<= aExplicitScale.Maximum; + } + break; + } + case SCALE_PROP_MIN: + { + aRet = aScaleData.Minimum; + if( !aRet.hasValue() ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + aRet <<= aExplicitScale.Minimum; + } + break; + } + + case SCALE_PROP_STEPMAIN: + { + aRet = aScaleData.IncrementData.Distance; + if( !aRet.hasValue() ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + aRet <<= aExplicitIncrement.Distance; + } + break; + } + case SCALE_PROP_STEPHELP: + { + // todo: evaluate PostEquidistant + bool bNeedToCalculateExplicitValues = true; + + bool bLogarithmic( AxisHelper::isLogarithmic(aScaleData.Scaling) ); + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( bLogarithmic ) + { + if( rSubIncrements.hasElements() ) + { + sal_Int32 nIntervalCount = 0; + rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount; + aRet <<= double(nIntervalCount); + bNeedToCalculateExplicitValues = false; + } + } + else if( aScaleData.IncrementData.Distance.hasValue() ) + { + if( rSubIncrements.hasElements() ) + { + double fStepMain = 0; + sal_Int32 nIntervalCount = 0; + if( (aScaleData.IncrementData.Distance >>= fStepMain) && + (rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount) && + nIntervalCount > 0 ) + { + aRet <<= fStepMain / static_cast< double >( nIntervalCount ); + bNeedToCalculateExplicitValues = false; + } + } + else + { + aRet = aScaleData.IncrementData.Distance; + bNeedToCalculateExplicitValues = false; + } + } + + if( bNeedToCalculateExplicitValues ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + + if( !aExplicitIncrement.SubIncrements.empty() && + aExplicitIncrement.SubIncrements[ 0 ].IntervalCount > 0 ) + { + if( bLogarithmic ) + { + if( rSubIncrements.hasElements() ) + { + sal_Int32 nIntervalCount = aExplicitIncrement.SubIncrements[ 0 ].IntervalCount; + aRet <<= double(nIntervalCount); + } + } + else + aRet <<= aExplicitIncrement.Distance / + static_cast< double >( + aExplicitIncrement.SubIncrements[ 0 ].IntervalCount ); + } + else + { + if( bLogarithmic ) + aRet <<= 5.0; + else + aRet <<= aExplicitIncrement.Distance; + } + } + break; + } + case SCALE_PROP_STEPHELP_COUNT: + { + sal_Int32 nIntervalCount = 0; + bool bNeedToCalculateExplicitValues = true; + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( rSubIncrements.hasElements() ) + { + if( (rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount) && (nIntervalCount > 0) ) + bNeedToCalculateExplicitValues = false; + } + if( bNeedToCalculateExplicitValues ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( xAxis, aExplicitScale, aExplicitIncrement ); + if( !aExplicitIncrement.SubIncrements.empty() ) + nIntervalCount = aExplicitIncrement.SubIncrements[ 0 ].IntervalCount; + } + aRet <<= nIntervalCount; + break; + } + case SCALE_PROP_AUTO_MAX: + { + aRet <<= !aScaleData.Maximum.hasValue(); + break; + } + case SCALE_PROP_AUTO_MIN: + { + aRet <<= !aScaleData.Minimum.hasValue(); + break; + } + case SCALE_PROP_AUTO_STEPMAIN: + { + aRet <<= !aScaleData.IncrementData.Distance.hasValue(); + break; + } + case SCALE_PROP_AUTO_STEPHELP: + { + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( rSubIncrements.hasElements() ) + aRet <<= !rSubIncrements[ 0 ].IntervalCount.hasValue(); + else + aRet <<= true; + break; + } + case SCALE_PROP_ORIGIN: + { + aRet = aScaleData.Origin; + if( !aRet.hasValue() ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + aRet <<= aExplicitScale.Origin; + } + break; + } + case SCALE_PROP_AUTO_ORIGIN: + { + aRet <<= !hasDoubleValue(aScaleData.Origin); + break; + } + case SCALE_PROP_AXIS_TYPE: + { + sal_Int32 nType = css::chart::ChartAxisType::AUTOMATIC; + if( aScaleData.AxisType == AxisType::DATE ) + { + nType = css::chart::ChartAxisType::DATE; + } + else if( aScaleData.AxisType == AxisType::CATEGORY ) + { + if( !aScaleData.AutoDateAxis ) + nType = css::chart::ChartAxisType::CATEGORY; + } + aRet <<= nType; + break; + } + case SCALE_PROP_DATE_INCREMENT: + { + if( aScaleData.AxisType == AxisType::DATE || aScaleData.AutoDateAxis ) + aRet <<= aScaleData.TimeIncrement; + break; + } + case SCALE_PROP_EXPLICIT_DATE_INCREMENT: + { + if( aScaleData.AxisType == AxisType::DATE || aScaleData.AutoDateAxis ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( xAxis, aExplicitScale, aExplicitIncrement ); + if( aExplicitScale.AxisType == AxisType::DATE ) + { + TimeIncrement aTimeIncrement; + aTimeIncrement.MajorTimeInterval <<= aExplicitIncrement.MajorTimeInterval; + aTimeIncrement.MinorTimeInterval <<= aExplicitIncrement.MinorTimeInterval; + aTimeIncrement.TimeResolution <<= aExplicitScale.TimeResolution; + aRet <<= aTimeIncrement; + } + else + aRet <<= aScaleData.TimeIncrement; + } + + break; + } + case SCALE_PROP_LOGARITHMIC: + { + aRet <<= AxisHelper::isLogarithmic(aScaleData.Scaling); + break; + } + case SCALE_PROP_REVERSEDIRECTION: + { + aRet <<= aScaleData.Orientation == AxisOrientation_REVERSE; + break; + } + default: + { + OSL_FAIL("unknown scale property"); + break; + } + } + + return aRet; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.hxx new file mode 100644 index 000000000..64e8071b5 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.hxx @@ -0,0 +1,83 @@ +/* -*- 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 <WrappedProperty.hxx> + +#include <memory> +#include <vector> + +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + +class WrappedScaleProperty final : public WrappedProperty +{ +public: + enum tScaleProperty + { + SCALE_PROP_MAX + , SCALE_PROP_MIN + , SCALE_PROP_ORIGIN + , SCALE_PROP_STEPMAIN + , SCALE_PROP_STEPHELP //deprecated property + , SCALE_PROP_STEPHELP_COUNT + , SCALE_PROP_AUTO_MAX + , SCALE_PROP_AUTO_MIN + , SCALE_PROP_AUTO_ORIGIN + , SCALE_PROP_AUTO_STEPMAIN + , SCALE_PROP_AUTO_STEPHELP + , SCALE_PROP_AXIS_TYPE + , SCALE_PROP_DATE_INCREMENT + , SCALE_PROP_EXPLICIT_DATE_INCREMENT + , SCALE_PROP_LOGARITHMIC + , SCALE_PROP_REVERSEDIRECTION + }; + + WrappedScaleProperty(tScaleProperty eScaleProperty, const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~WrappedScaleProperty() override; + + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList, const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + /// @throws css::beans::UnknownPropertyException + /// @throws css::beans::PropertyVetoException + /// @throws css::lang::IllegalArgumentException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + void setPropertyValue( tScaleProperty eScaleProperty, const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const; + /// @throws css::beans::UnknownPropertyException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + css::uno::Any getPropertyValue( tScaleProperty eScaleProperty, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const; + + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + tScaleProperty m_eScaleProperty; + + mutable css::uno::Any m_aOuterValue; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.cxx new file mode 100644 index 000000000..8551915d9 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.cxx @@ -0,0 +1,138 @@ +/* -*- 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 "WrappedScaleTextProperties.hxx" +#include "Chart2ModelContact.hxx" +#include <FastPropertyIdRanges.hxx> +#include <WrappedProperty.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace { + +class WrappedScaleTextProperty : public WrappedProperty +{ +public: + explicit WrappedScaleTextProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedScaleTextProperty::WrappedScaleTextProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : ::chart::WrappedProperty( "ScaleText" , OUString() ) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedScaleTextProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + static constexpr OUStringLiteral aRefSizeName = u"ReferencePageSize"; + + if( !xInnerPropertySet.is() ) + return; + + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + { + if( rOuterValue.hasValue() ) + throw lang::IllegalArgumentException( "Property ScaleText requires value of type boolean", nullptr, 0 ); + } + + try + { + if( bNewValue ) + { + awt::Size aRefSize( m_spChart2ModelContact->GetPageSize() ); + xInnerPropertySet->setPropertyValue( aRefSizeName, uno::Any( aRefSize ) ); + } + else + xInnerPropertySet->setPropertyValue( aRefSizeName, Any() ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedScaleTextProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( getPropertyDefault( Reference< beans::XPropertyState >( xInnerPropertySet, uno::UNO_QUERY ) ) ); + if( xInnerPropertySet.is() ) + { + if( xInnerPropertySet->getPropertyValue( "ReferencePageSize" ).hasValue() ) + aRet <<= true; + else + aRet <<= false; + } + + return aRet; +} + +Any WrappedScaleTextProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace +{ +enum +{ + PROP_CHART_SCALE_TEXT = FAST_PROPERTY_ID_START_SCALE_TEXT_PROP +}; + +}//anonymous namespace + +void WrappedScaleTextProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "ScaleText", + PROP_CHART_SCALE_TEXT, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void WrappedScaleTextProperties::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedScaleTextProperty( spChart2ModelContact ) ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.hxx new file mode 100644 index 000000000..958b5f55d --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.hxx @@ -0,0 +1,43 @@ +/* -*- 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 <sal/types.h> +#include <memory> +#include <vector> + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedScaleTextProperties +{ +public: + static void addProperties( std::vector< css::beans::Property >& rOutProperties ); + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.cxx new file mode 100644 index 000000000..2430dcba7 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.cxx @@ -0,0 +1,101 @@ +/* -*- 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 "WrappedSceneProperty.hxx" +#include "Chart2ModelContact.hxx" +#include <DiagramHelper.hxx> +#include <BaseGFXHelper.hxx> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + +namespace chart::wrapper +{ + +void WrappedSceneProperty::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedD3DTransformMatrixProperty( spChart2ModelContact ) ); +} + +WrappedD3DTransformMatrixProperty::WrappedD3DTransformMatrixProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) + : WrappedProperty("D3DTransformMatrix","D3DTransformMatrix") + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +WrappedD3DTransformMatrixProperty::~WrappedD3DTransformMatrixProperty() +{ +} + +void WrappedD3DTransformMatrixProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( DiagramHelper::isPieOrDonutChart( m_spChart2ModelContact->getDiagram() ) ) + { + drawing::HomogenMatrix aHM; + if( rOuterValue >>= aHM ) + { + ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( + BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHM ) ) ); + + ::basegfx::B3DHomMatrix aMatrix; + aMatrix.rotate( aRotation.getX(), aRotation.getY(), aRotation.getZ() ); + ::basegfx::B3DHomMatrix aObjectMatrix; + ::basegfx::B3DHomMatrix aNewMatrix = aMatrix*aObjectMatrix; + + aHM = BaseGFXHelper::B3DHomMatrixToHomogenMatrix(aNewMatrix); + + WrappedProperty::setPropertyValue( uno::Any(aHM), xInnerPropertySet ); + return; + } + } + + WrappedProperty::setPropertyValue( rOuterValue, xInnerPropertySet ); +} + +Any WrappedD3DTransformMatrixProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( DiagramHelper::isPieOrDonutChart( m_spChart2ModelContact->getDiagram() ) ) + { + uno::Any aAMatrix( WrappedProperty::getPropertyValue( xInnerPropertySet ) ); + drawing::HomogenMatrix aHM; + if( aAMatrix >>= aHM ) + { + ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( + BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHM ) ) ); + + ::basegfx::B3DHomMatrix aMatrix; + aMatrix.rotate( aRotation.getX(), aRotation.getY(), aRotation.getZ() ); + ::basegfx::B3DHomMatrix aObjectMatrix; + ::basegfx::B3DHomMatrix aNewMatrix = aMatrix*aObjectMatrix; + + aHM = BaseGFXHelper::B3DHomMatrixToHomogenMatrix(aNewMatrix); + + return uno::Any(aHM); + } + } + + return WrappedProperty::getPropertyValue( xInnerPropertySet ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.hxx new file mode 100644 index 000000000..7e6679016 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.hxx @@ -0,0 +1,55 @@ +/* -*- 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 <WrappedProperty.hxx> + +#include <memory> +#include <vector> + +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + +class WrappedSceneProperty +{ +public: + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +class WrappedD3DTransformMatrixProperty : public WrappedProperty +{ +public: + explicit WrappedD3DTransformMatrixProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + virtual ~WrappedD3DTransformMatrixProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.cxx new file mode 100644 index 000000000..88fa72696 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.cxx @@ -0,0 +1,51 @@ +/* -*- 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 "WrappedSeriesAreaOrLineProperty.hxx" +#include "DataSeriesPointWrapper.hxx" + +namespace chart::wrapper +{ + +WrappedSeriesAreaOrLineProperty::WrappedSeriesAreaOrLineProperty( + const OUString& rOuterName + , const OUString& rInnerAreaTypeName + , const OUString& rInnerLineTypeName + , DataSeriesPointWrapper* pDataSeriesPointWrapper ) + : WrappedProperty( rOuterName, OUString() ) + , m_pDataSeriesPointWrapper( pDataSeriesPointWrapper ) + , m_aInnerAreaTypeName( rInnerAreaTypeName ) + , m_aInnerLineTypeName( rInnerLineTypeName ) +{ +} +WrappedSeriesAreaOrLineProperty::~WrappedSeriesAreaOrLineProperty() +{ +} + +//virtual +OUString WrappedSeriesAreaOrLineProperty::getInnerName() const +{ + if( m_pDataSeriesPointWrapper && !m_pDataSeriesPointWrapper->isSupportingAreaProperties() ) + return m_aInnerLineTypeName; + return m_aInnerAreaTypeName; +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.hxx new file mode 100644 index 000000000..ba77b6939 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.hxx @@ -0,0 +1,45 @@ +/* -*- 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 <WrappedProperty.hxx> + +namespace chart::wrapper +{ + +class DataSeriesPointWrapper; +class WrappedSeriesAreaOrLineProperty : public WrappedProperty +{ +public: + WrappedSeriesAreaOrLineProperty( const OUString& rOuterName + , const OUString& rInnerAreaTypeName, const OUString& rInnerLineTypeName + , DataSeriesPointWrapper* pDataSeriesPointWrapper ); + virtual ~WrappedSeriesAreaOrLineProperty() override; + + virtual OUString getInnerName() const override; + +private: + DataSeriesPointWrapper* m_pDataSeriesPointWrapper; + OUString m_aInnerAreaTypeName; + OUString m_aInnerLineTypeName; +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSeriesOrDiagramProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedSeriesOrDiagramProperty.hxx new file mode 100644 index 000000000..db9a07b45 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSeriesOrDiagramProperty.hxx @@ -0,0 +1,163 @@ +/* -*- 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 <WrappedProperty.hxx> +#include "Chart2ModelContact.hxx" +#include <DiagramHelper.hxx> +#include <DataSeries.hxx> + +#include <memory> +#include <vector> + +namespace com::sun::star::chart2 { class XDataSeries; } + +namespace chart::wrapper +{ + +enum tSeriesOrDiagramPropertyType +{ + DATA_SERIES, + DIAGRAM +}; + +//PROPERTYTYPE is the type of the outer property + +template< typename PROPERTYTYPE > +class WrappedSeriesOrDiagramProperty : public WrappedProperty +{ +public: + virtual PROPERTYTYPE getValueFromSeries( const css::uno::Reference< css::beans::XPropertySet >& xSeriesPropertySet ) const =0; + virtual void setValueToSeries( const css::uno::Reference< css::beans::XPropertySet >& xSeriesPropertySet, const PROPERTYTYPE & aNewValue ) const =0; + + explicit WrappedSeriesOrDiagramProperty( const OUString& rName, const css::uno::Any& rDefaulValue + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedProperty(rName,OUString()) + , m_spChart2ModelContact(spChart2ModelContact) + , m_aOuterValue(rDefaulValue) + , m_aDefaultValue(rDefaulValue) + , m_ePropertyType( ePropertyType ) + { + } + + bool detectInnerValue( PROPERTYTYPE& rValue, bool& rHasAmbiguousValue ) const + { + bool bHasDetectableInnerValue = false; + rHasAmbiguousValue = false; + if( m_ePropertyType == DIAGRAM && + m_spChart2ModelContact ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + ::chart::DiagramHelper::getDataSeriesFromDiagram( m_spChart2ModelContact->getDiagram() ); + for (auto const& series : aSeriesVector) + { + PROPERTYTYPE aCurValue = getValueFromSeries( series ); + if( !bHasDetectableInnerValue ) + rValue = aCurValue; + else + { + if( rValue != aCurValue ) + { + rHasAmbiguousValue = true; + break; + } + else + rValue = aCurValue; + } + bHasDetectableInnerValue = true; + } + } + return bHasDetectableInnerValue; + } + void setInnerValue( PROPERTYTYPE aNewValue ) const + { + if( m_ePropertyType == DIAGRAM && + m_spChart2ModelContact ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + ::chart::DiagramHelper::getDataSeriesFromDiagram( m_spChart2ModelContact->getDiagram() ); + for (auto const& series : aSeriesVector) + { + setValueToSeries( series, aNewValue ); + } + } + } + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override + { + PROPERTYTYPE aNewValue = PROPERTYTYPE(); + if( ! (rOuterValue >>= aNewValue) ) + throw css::lang::IllegalArgumentException( "statistic property requires different type", nullptr, 0 ); + + if( m_ePropertyType == DIAGRAM ) + { + m_aOuterValue = rOuterValue; + + bool bHasAmbiguousValue = false; + PROPERTYTYPE aOldValue = PROPERTYTYPE(); + if( detectInnerValue( aOldValue, bHasAmbiguousValue ) ) + { + if( bHasAmbiguousValue || aNewValue != aOldValue ) + setInnerValue( aNewValue ); + } + } + else + { + setValueToSeries( xInnerPropertySet, aNewValue ); + } + } + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override + { + if( m_ePropertyType == DIAGRAM ) + { + bool bHasAmbiguousValue = false; + PROPERTYTYPE aValue = PROPERTYTYPE(); + if( detectInnerValue( aValue, bHasAmbiguousValue ) ) + { + if(bHasAmbiguousValue) + m_aOuterValue = m_aDefaultValue; + else + m_aOuterValue <<= aValue; + } + return m_aOuterValue; + } + else + { + css::uno::Any aRet( m_aDefaultValue ); + aRet <<= getValueFromSeries( xInnerPropertySet ); + return aRet; + } + } + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& /* xInnerPropertyState */ ) const override + { + return m_aDefaultValue; + } + +protected: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable css::uno::Any m_aOuterValue; + css::uno::Any m_aDefaultValue; + tSeriesOrDiagramPropertyType m_ePropertyType; +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx new file mode 100644 index 000000000..102acfb02 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx @@ -0,0 +1,284 @@ +/* -*- 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 "WrappedSplineProperties.hxx" +#include "Chart2ModelContact.hxx" +#include <FastPropertyIdRanges.hxx> +#include <ChartType.hxx> +#include <DiagramHelper.hxx> +#include <WrappedProperty.hxx> +#include <unonames.hxx> + +#include <sal/log.hxx> + +#include <com/sun/star/chart2/CurveStyle.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace +{ + +//PROPERTYTYPE is the type of the outer property + +template< typename PROPERTYTYPE > +class WrappedSplineProperty : public WrappedProperty +{ +public: + explicit WrappedSplineProperty( const OUString& rOuterName, const OUString& rInnerName + , const css::uno::Any& rDefaulValue + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) + : WrappedProperty(rOuterName,OUString()) + , m_spChart2ModelContact(spChart2ModelContact) + , m_aOuterValue(rDefaulValue) + , m_aDefaultValue(rDefaulValue) + , m_aOwnInnerName(rInnerName) + { + } + + bool detectInnerValue( PROPERTYTYPE& rValue, bool& rHasAmbiguousValue ) const + { + bool bHasDetectableInnerValue = false; + rHasAmbiguousValue = false; + std::vector< rtl::Reference< ChartType > > aChartTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( m_spChart2ModelContact->getDiagram() ) ); + for( sal_Int32 nN = aChartTypes.size(); nN--; ) + { + try + { + Any aSingleValue = convertInnerToOuterValue( aChartTypes[nN]->getPropertyValue(m_aOwnInnerName) ); + PROPERTYTYPE aCurValue = PROPERTYTYPE(); + aSingleValue >>= aCurValue; + if( !bHasDetectableInnerValue ) + rValue = aCurValue; + else + { + if( rValue != aCurValue ) + { + rHasAmbiguousValue = true; + break; + } + else + rValue = aCurValue; + } + bHasDetectableInnerValue = true; + } + catch( uno::Exception & ex ) + { + //spline properties are not supported by all charttypes + //in that cases this exception is ok + ex.Context.is();//to have debug information without compilation warnings + } + } + return bHasDetectableInnerValue; + } + void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const override + { + PROPERTYTYPE aNewValue; + if( ! (rOuterValue >>= aNewValue) ) + throw css::lang::IllegalArgumentException( "spline property requires different type", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + bool bHasAmbiguousValue = false; + PROPERTYTYPE aOldValue = PROPERTYTYPE(); + if( !detectInnerValue( aOldValue, bHasAmbiguousValue ) ) + return; + + if( !(bHasAmbiguousValue || aNewValue != aOldValue) ) + return; + + std::vector< rtl::Reference< ChartType > > aChartTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( m_spChart2ModelContact->getDiagram() ) ); + for( sal_Int32 nN = aChartTypes.size(); nN--; ) + { + try + { + aChartTypes[nN]->setPropertyValue(m_aOwnInnerName,convertOuterToInnerValue(uno::Any(aNewValue))); + } + catch( uno::Exception & ex ) + { + //spline properties are not supported by all charttypes + //in that cases this exception is ok + ex.Context.is();//to have debug information without compilation warnings + } + } + } + + css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const override + { + bool bHasAmbiguousValue = false; + PROPERTYTYPE aValue; + if( detectInnerValue( aValue, bHasAmbiguousValue ) ) + { + m_aOuterValue <<= aValue; + } + return m_aOuterValue; + } + + css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& /*xInnerPropertyState*/ ) const override + { + return m_aDefaultValue; + } + +protected: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable css::uno::Any m_aOuterValue; + css::uno::Any m_aDefaultValue; + // this inner name is not set as inner name at the base class + const OUString m_aOwnInnerName; +}; + +class WrappedSplineTypeProperty : public WrappedSplineProperty< sal_Int32 > +{ +public: + explicit WrappedSplineTypeProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + virtual css::uno::Any convertInnerToOuterValue( const css::uno::Any& rInnerValue ) const override; + virtual css::uno::Any convertOuterToInnerValue( const css::uno::Any& rOuterValue ) const override; +}; + +enum +{ + //spline properties + PROP_CHART_SPLINE_TYPE = FAST_PROPERTY_ID_START_CHART_SPLINE_PROP + , PROP_CHART_SPLINE_ORDER + , PROP_CHART_SPLINE_RESOLUTION +}; + +}//anonymous namespace + +void WrappedSplineProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( CHART_UNONAME_SPLINE_TYPE, + PROP_CHART_SPLINE_TYPE, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_SPLINE_ORDER, + PROP_CHART_SPLINE_ORDER, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_SPLINE_RESOLUTION, + PROP_CHART_SPLINE_RESOLUTION, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); +} + +void WrappedSplineProperties::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedSplineTypeProperty( spChart2ModelContact ) ); + rList.emplace_back( + new WrappedSplineProperty<sal_Int32>( + CHART_UNONAME_SPLINE_ORDER, CHART_UNONAME_SPLINE_ORDER, + uno::Any(sal_Int32(3)), spChart2ModelContact)); + rList.emplace_back( + new WrappedSplineProperty<sal_Int32>( + CHART_UNONAME_SPLINE_RESOLUTION, CHART_UNONAME_CURVE_RESOLUTION, + uno::Any(sal_Int32(20)), spChart2ModelContact)); +} + +WrappedSplineTypeProperty::WrappedSplineTypeProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedSplineProperty<sal_Int32>(CHART_UNONAME_SPLINE_TYPE, CHART_UNONAME_CURVE_STYLE, uno::Any(sal_Int32(0)), spChart2ModelContact ) +{ +} + +Any WrappedSplineTypeProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + chart2::CurveStyle aInnerValue = chart2::CurveStyle_LINES; + rInnerValue >>= aInnerValue; + + sal_Int32 nOuterValue; + switch (aInnerValue) + { + case chart2::CurveStyle_CUBIC_SPLINES: + nOuterValue = 1; + break; + case chart2::CurveStyle_B_SPLINES: + nOuterValue = 2; + break; + case chart2::CurveStyle_STEP_START: + nOuterValue = 3; + break; + case chart2::CurveStyle_STEP_END: + nOuterValue = 4; + break; + case chart2::CurveStyle_STEP_CENTER_X: + nOuterValue = 5; + break; + case chart2::CurveStyle_STEP_CENTER_Y: + nOuterValue = 6; + break; + default: + nOuterValue = 0; + } + + return uno::Any(nOuterValue); +} +Any WrappedSplineTypeProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + sal_Int32 nOuterValue=0; + rOuterValue >>= nOuterValue; + + chart2::CurveStyle aInnerValue; + + switch (nOuterValue) + { + case 1: + aInnerValue = chart2::CurveStyle_CUBIC_SPLINES; + break; + case 2: + aInnerValue = chart2::CurveStyle_B_SPLINES; + break; + case 3: + aInnerValue = chart2::CurveStyle_STEP_START; + break; + case 4: + aInnerValue = chart2::CurveStyle_STEP_END; + break; + case 5: + aInnerValue = chart2::CurveStyle_STEP_CENTER_X; + break; + case 6: + aInnerValue = chart2::CurveStyle_STEP_CENTER_Y; + break; + default: + SAL_WARN_IF(nOuterValue != 0, "chart2", "Unknown line style"); + aInnerValue = chart2::CurveStyle_LINES; + } + + return uno::Any(aInnerValue); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.hxx new file mode 100644 index 000000000..686a69297 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.hxx @@ -0,0 +1,42 @@ +/* -*- 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 <sal/types.h> +#include <memory> +#include <vector> + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedSplineProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx new file mode 100644 index 000000000..2de01cc8b --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx @@ -0,0 +1,1072 @@ +/* -*- 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 "WrappedStatisticProperties.hxx" +#include "WrappedSeriesOrDiagramProperty.hxx" +#include <FastPropertyIdRanges.hxx> +#include <RegressionCurveHelper.hxx> +#include <RegressionCurveModel.hxx> +#include <ErrorBar.hxx> +#include <StatisticsHelper.hxx> +#include <unonames.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart/ChartErrorCategory.hpp> +#include <com/sun/star/chart/ErrorBarStyle.hpp> +#include <com/sun/star/chart/ChartErrorIndicatorType.hpp> +#include <com/sun/star/chart/ChartRegressionCurveType.hpp> +#include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> +#include <com/sun/star/chart2/XRegressionCurveContainer.hpp> +#include <utility> + +namespace com::sun::star::chart2::data { class XDataProvider; } + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace +{ + +Any lcl_getRegressionDefault() +{ + Any aRet; + aRet <<= css::chart::ChartRegressionCurveType_NONE; + return aRet; +} + +css::chart::ChartRegressionCurveType lcl_getRegressionCurveType(SvxChartRegress eRegressionType) +{ + css::chart::ChartRegressionCurveType eRet = css::chart::ChartRegressionCurveType_NONE; + switch(eRegressionType) + { + case SvxChartRegress::Linear: + eRet = css::chart::ChartRegressionCurveType_LINEAR; + break; + case SvxChartRegress::Log: + eRet = css::chart::ChartRegressionCurveType_LOGARITHM; + break; + case SvxChartRegress::Exp: + eRet = css::chart::ChartRegressionCurveType_EXPONENTIAL; + break; + case SvxChartRegress::Power: + eRet = css::chart::ChartRegressionCurveType_POWER; + break; + case SvxChartRegress::Polynomial: + eRet = css::chart::ChartRegressionCurveType_POLYNOMIAL; + break; + /*case SvxChartRegress::MovingAverage: + eRet = css::chart::ChartRegressionCurveType_MOVING_AVERAGE; + break;*/ + default: + eRet = css::chart::ChartRegressionCurveType_NONE; + break; + } + return eRet; +} + +SvxChartRegress lcl_getRegressionType( css::chart::ChartRegressionCurveType eRegressionCurveType ) +{ + SvxChartRegress eRet; + switch (eRegressionCurveType) + { + case css::chart::ChartRegressionCurveType_LINEAR: + eRet = SvxChartRegress::Linear; + break; + case css::chart::ChartRegressionCurveType_LOGARITHM: + eRet = SvxChartRegress::Log; + break; + case css::chart::ChartRegressionCurveType_EXPONENTIAL: + eRet = SvxChartRegress::Exp; + break; + case css::chart::ChartRegressionCurveType_POLYNOMIAL: + //case css::chart::ChartRegressionCurveType_MOVING_AVERAGE: + case css::chart::ChartRegressionCurveType_POWER: + eRet = SvxChartRegress::Power; + break; + default: + eRet = SvxChartRegress::NONE; + break; + } + return eRet; +} + +sal_Int32 lcl_getErrorBarStyle( const uno::Reference< beans::XPropertySet >& xErrorBarProperties ) +{ + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + if(xErrorBarProperties.is()) + xErrorBarProperties->getPropertyValue( "ErrorBarStyle" ) >>= nStyle; + return nStyle; +} + +uno::Reference< chart2::data::XDataProvider > lcl_getDataProviderFromContact( + const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + uno::Reference< chart2::data::XDataProvider > xResult; + if( spChart2ModelContact) + { + rtl::Reference< ChartModel > xChartDoc( + spChart2ModelContact->getDocumentModel()); + if( xChartDoc.is()) + xResult.set( xChartDoc->getDataProvider()); + } + return xResult; +} + +void lcl_ConvertRangeFromXML( + OUString & rInOutRange, + const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + if( !rInOutRange.isEmpty()) + { + uno::Reference< chart2::data::XRangeXMLConversion > xConverter( + lcl_getDataProviderFromContact( spChart2ModelContact ), uno::UNO_QUERY ); + if( xConverter.is()) + { + OUString aResult = xConverter->convertRangeFromXML( rInOutRange ); + rInOutRange = aResult; + } + } +} + +void lcl_ConvertRangeToXML( + OUString & rInOutRange, + const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + if( !rInOutRange.isEmpty()) + { + uno::Reference< chart2::data::XRangeXMLConversion > xConverter( + lcl_getDataProviderFromContact( spChart2ModelContact ), uno::UNO_QUERY ); + if( xConverter.is()) + { + OUString aResult = xConverter->convertRangeToXML( rInOutRange ); + rInOutRange = aResult; + } + } +} + +template< typename PROPERTYTYPE > +class WrappedStatisticProperty : public WrappedSeriesOrDiagramProperty< PROPERTYTYPE > +{ +public: + explicit WrappedStatisticProperty( + const OUString& rName, const Any& rDefaulValue, + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType) + : WrappedSeriesOrDiagramProperty<PROPERTYTYPE>(rName, rDefaulValue, spChart2ModelContact, + ePropertyType) + {} + +protected: + static uno::Reference< beans::XPropertySet > getOrCreateErrorBarProperties( const Reference< beans::XPropertySet >& xSeriesPropertySet ) + { + if(!xSeriesPropertySet.is()) + return nullptr; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties; + if( !xErrorBarProperties.is() ) + { + xErrorBarProperties = new ::chart::ErrorBar; + //default in new and old api are different + xErrorBarProperties->setPropertyValue( "ShowPositiveError" , uno::Any(false) ); + xErrorBarProperties->setPropertyValue( "ShowNegativeError" , uno::Any(false) ); + xErrorBarProperties->setPropertyValue( "ErrorBarStyle" , uno::Any(css::chart::ErrorBarStyle::NONE) ); + xSeriesPropertySet->setPropertyValue( CHART_UNONAME_ERRORBAR_Y , uno::Any( xErrorBarProperties ) ); + } + return xErrorBarProperties; + } + +}; + +//PROP_CHART_STATISTIC_CONST_ERROR_LOW +class WrappedConstantErrorLowProperty : public WrappedStatisticProperty< double > +{ +public: + virtual double getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const override; + + explicit WrappedConstantErrorLowProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + mutable Any m_aOuterValue; +}; + +}//anonymous namespace + +WrappedConstantErrorLowProperty::WrappedConstantErrorLowProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< double >( "ConstantErrorLow" + , uno::Any( 0.0 ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +double WrappedConstantErrorLowProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + double aRet = 0.0; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ABSOLUTE ) + xErrorBarProperties->getPropertyValue( "NegativeError" ) >>= aRet; + else + m_aOuterValue >>= aRet; + } + return aRet; +} + +void WrappedConstantErrorLowProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + m_aOuterValue <<= aNewValue; + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ABSOLUTE ) + { + xErrorBarProperties->setPropertyValue( "NegativeError", m_aOuterValue ); + } + } +} + +namespace { + +//PROP_CHART_STATISTIC_CONST_ERROR_HIGH +class WrappedConstantErrorHighProperty : public WrappedStatisticProperty< double > +{ +public: + virtual double getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const override; + + explicit WrappedConstantErrorHighProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + mutable Any m_aOuterValue; +}; + +} + +WrappedConstantErrorHighProperty::WrappedConstantErrorHighProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< double >( "ConstantErrorHigh" + , uno::Any( 0.0 ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +double WrappedConstantErrorHighProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + double aRet = 0.0; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ABSOLUTE ) + xErrorBarProperties->getPropertyValue( "PositiveError" ) >>= aRet; + else + m_aOuterValue >>= aRet; + } + return aRet; +} + +void WrappedConstantErrorHighProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + m_aOuterValue <<= aNewValue; + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ABSOLUTE ) + { + xErrorBarProperties->setPropertyValue( "PositiveError" , m_aOuterValue ); + } + } +} + +namespace { + +//PROP_CHART_STATISTIC_MEAN_VALUE +class WrappedMeanValueProperty : public WrappedStatisticProperty< bool > +{ +public: + virtual bool getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const bool& aNewValue ) const override; + + explicit WrappedMeanValueProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedMeanValueProperty::WrappedMeanValueProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< bool >( "MeanValue", uno::Any( false ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +bool WrappedMeanValueProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + bool bRet = false; + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropertySet, uno::UNO_QUERY ); + if( xRegCnt.is() ) + bRet = RegressionCurveHelper::hasMeanValueLine( xRegCnt ); + return bRet; +} + +void WrappedMeanValueProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const bool& aNewValue ) const +{ + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropertySet, uno::UNO_QUERY ); + if( xRegCnt.is() ) + { + if(aNewValue) + RegressionCurveHelper::addMeanValueLine( xRegCnt, nullptr ); + else + RegressionCurveHelper::removeMeanValueLine( xRegCnt ); + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_CATEGORY +// deprecated, replaced by ErrorBarStyle +class WrappedErrorCategoryProperty : public WrappedStatisticProperty< css::chart::ChartErrorCategory > +{ +public: + virtual css::chart::ChartErrorCategory getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartErrorCategory& aNewValue ) const override; + + explicit WrappedErrorCategoryProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorCategoryProperty::WrappedErrorCategoryProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< css::chart::ChartErrorCategory >( "ErrorCategory" + , uno::Any( css::chart::ChartErrorCategory_NONE ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +css::chart::ChartErrorCategory WrappedErrorCategoryProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + css::chart::ChartErrorCategory aRet = css::chart::ChartErrorCategory_NONE; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + xErrorBarProperties->getPropertyValue( "ErrorBarStyle" ) >>= nStyle; + switch(nStyle) + { + case css::chart::ErrorBarStyle::NONE: + aRet = css::chart::ChartErrorCategory_NONE; + break; + case css::chart::ErrorBarStyle::VARIANCE: + aRet = css::chart::ChartErrorCategory_VARIANCE; + break; + case css::chart::ErrorBarStyle::STANDARD_DEVIATION: + aRet = css::chart::ChartErrorCategory_STANDARD_DEVIATION; + break; + case css::chart::ErrorBarStyle::ABSOLUTE: + aRet = css::chart::ChartErrorCategory_CONSTANT_VALUE; + break; + case css::chart::ErrorBarStyle::RELATIVE: + aRet = css::chart::ChartErrorCategory_PERCENT; + break; + case css::chart::ErrorBarStyle::ERROR_MARGIN: + aRet = css::chart::ChartErrorCategory_ERROR_MARGIN; + break; + case css::chart::ErrorBarStyle::STANDARD_ERROR: + break; + case css::chart::ErrorBarStyle::FROM_DATA: + break; + default: + break; + } + } + return aRet; +} +void WrappedErrorCategoryProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartErrorCategory& aNewValue ) const +{ + if( !xSeriesPropertySet.is() ) + return; + + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( !xErrorBarProperties.is() ) + return; + + sal_Int32 nNewStyle = css::chart::ErrorBarStyle::NONE; + switch(aNewValue) + { + case css::chart::ChartErrorCategory_NONE: + nNewStyle = css::chart::ErrorBarStyle::NONE; + break; + case css::chart::ChartErrorCategory_VARIANCE: + nNewStyle = css::chart::ErrorBarStyle::VARIANCE; + break; + case css::chart::ChartErrorCategory_STANDARD_DEVIATION: + nNewStyle = css::chart::ErrorBarStyle::STANDARD_DEVIATION; + break; + case css::chart::ChartErrorCategory_CONSTANT_VALUE: + nNewStyle = css::chart::ErrorBarStyle::ABSOLUTE; + break; + case css::chart::ChartErrorCategory_PERCENT: + nNewStyle = css::chart::ErrorBarStyle::RELATIVE; + break; + case css::chart::ChartErrorCategory_ERROR_MARGIN: + nNewStyle = css::chart::ErrorBarStyle::ERROR_MARGIN; + break; + default: + break; + } + xErrorBarProperties->setPropertyValue( "ErrorBarStyle" , uno::Any(nNewStyle) ); +} + +namespace { + +//PROP_CHART_STATISTIC_PERCENT_ERROR +class WrappedPercentageErrorProperty : public WrappedStatisticProperty< double > +{ +public: + virtual double getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const override; + + explicit WrappedPercentageErrorProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + mutable Any m_aOuterValue; +}; + +} + +WrappedPercentageErrorProperty::WrappedPercentageErrorProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< double >( "PercentageError" + , uno::Any( 0.0 ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +double WrappedPercentageErrorProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + double aRet = 0.0; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::RELATIVE ) + xErrorBarProperties->getPropertyValue( "PositiveError" ) >>= aRet; + else + m_aOuterValue >>= aRet; + } + return aRet; +} +void WrappedPercentageErrorProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + m_aOuterValue <<= aNewValue; + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::RELATIVE ) + { + xErrorBarProperties->setPropertyValue( "PositiveError" , m_aOuterValue ); + xErrorBarProperties->setPropertyValue( "NegativeError" , m_aOuterValue ); + } + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_MARGIN +class WrappedErrorMarginProperty : public WrappedStatisticProperty< double > +{ +public: + virtual double getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const override; + + explicit WrappedErrorMarginProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + mutable Any m_aOuterValue; +}; + +} + +WrappedErrorMarginProperty::WrappedErrorMarginProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< double >( "ErrorMargin" + , uno::Any( 0.0 ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +double WrappedErrorMarginProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + double aRet = 0.0; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ERROR_MARGIN ) + xErrorBarProperties->getPropertyValue( "PositiveError" ) >>= aRet; + else + m_aOuterValue >>= aRet; + } + return aRet; +} +void WrappedErrorMarginProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + m_aOuterValue <<= aNewValue; + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ERROR_MARGIN ) + { + xErrorBarProperties->setPropertyValue( "PositiveError" , m_aOuterValue ); + xErrorBarProperties->setPropertyValue( "NegativeError" , m_aOuterValue ); + } + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_INDICATOR +class WrappedErrorIndicatorProperty : public WrappedStatisticProperty< css::chart::ChartErrorIndicatorType > +{ +public: + virtual css::chart::ChartErrorIndicatorType getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartErrorIndicatorType& aNewValue ) const override; + + explicit WrappedErrorIndicatorProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorIndicatorProperty::WrappedErrorIndicatorProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< css::chart::ChartErrorIndicatorType >( "ErrorIndicator" + , uno::Any( css::chart::ChartErrorIndicatorType_NONE ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +css::chart::ChartErrorIndicatorType WrappedErrorIndicatorProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + css::chart::ChartErrorIndicatorType aRet = css::chart::ChartErrorIndicatorType_NONE; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + bool bPositive = false; + bool bNegative = false; + xErrorBarProperties->getPropertyValue( "ShowPositiveError" ) >>= bPositive; + xErrorBarProperties->getPropertyValue( "ShowNegativeError" ) >>= bNegative; + + if( bPositive && bNegative ) + aRet = css::chart::ChartErrorIndicatorType_TOP_AND_BOTTOM; + else if( bPositive && !bNegative ) + aRet = css::chart::ChartErrorIndicatorType_UPPER; + else if( !bPositive && bNegative ) + aRet = css::chart::ChartErrorIndicatorType_LOWER; + } + return aRet; +} +void WrappedErrorIndicatorProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartErrorIndicatorType& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( !xErrorBarProperties.is() ) + return; + + bool bPositive = false; + bool bNegative = false; + switch( aNewValue ) + { + case css::chart::ChartErrorIndicatorType_TOP_AND_BOTTOM: + bPositive = true; + bNegative = true; + break; + case css::chart::ChartErrorIndicatorType_UPPER: + bPositive = true; + break; + case css::chart::ChartErrorIndicatorType_LOWER: + bNegative = true; + break; + default: + break; + } + + xErrorBarProperties->setPropertyValue( "ShowPositiveError" , uno::Any(bPositive) ); + xErrorBarProperties->setPropertyValue( "ShowNegativeError" , uno::Any(bNegative) ); +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_BAR_STYLE +// this is the new constant group that replaces the deprecated enum ChartErrorCategory +class WrappedErrorBarStyleProperty : public WrappedStatisticProperty< sal_Int32 > +{ +public: + virtual sal_Int32 getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& nNewValue ) const override; + + explicit WrappedErrorBarStyleProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact1, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorBarStyleProperty::WrappedErrorBarStyleProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< sal_Int32 >( "ErrorBarStyle" + , uno::Any( css::chart::ErrorBarStyle::NONE ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +sal_Int32 WrappedErrorBarStyleProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + sal_Int32 nRet = css::chart::ErrorBarStyle::NONE; + m_aDefaultValue >>= nRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + xErrorBarProperties->getPropertyValue( "ErrorBarStyle" ) >>= nRet; + } + return nRet; +} +void WrappedErrorBarStyleProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& nNewValue ) const +{ + if( !xSeriesPropertySet.is() ) + return; + + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + xErrorBarProperties->setPropertyValue( "ErrorBarStyle" , uno::Any( nNewValue )); + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_RANGE_POSITIVE +class WrappedErrorBarRangePositiveProperty : public WrappedStatisticProperty< OUString > +{ +public: + virtual OUString getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const OUString& aNewValue ) const override; + + explicit WrappedErrorBarRangePositiveProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorBarRangePositiveProperty::WrappedErrorBarRangePositiveProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< OUString >( "ErrorBarRangePositive" + , uno::Any( OUString() ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +OUString WrappedErrorBarRangePositiveProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + OUString aRet; + m_aDefaultValue >>= aRet; + uno::Reference< chart2::data::XDataSource > xErrorBarDataSource; + if( xSeriesPropertySet.is() && + ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarDataSource ) && + xErrorBarDataSource.is()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarDataSource, true /* positive */ )); + if( xSeq.is()) + aRet = xSeq->getSourceRangeRepresentation(); + else + m_aOuterValue >>= aRet; + } + lcl_ConvertRangeToXML( aRet, m_spChart2ModelContact ); + return aRet; +} + +void WrappedErrorBarRangePositiveProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const OUString& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( !xErrorBarProperties.is() ) + return; + + uno::Reference< chart2::data::XDataProvider > xDataProvider( + lcl_getDataProviderFromContact( m_spChart2ModelContact )); + uno::Reference< chart2::data::XDataSource > xDataSource( xErrorBarProperties, uno::UNO_QUERY ); + if( xDataSource.is() && xDataProvider.is()) + { + OUString aTmp( aNewValue ); + OUString aXMLRange( aNewValue ); + lcl_ConvertRangeFromXML( aTmp, m_spChart2ModelContact ); + StatisticsHelper::setErrorDataSequence( + xDataSource, xDataProvider, aTmp, true /* positive */, true /* y-error */, &aXMLRange ); + m_aOuterValue <<= aTmp; + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_RANGE_NEGATIVE +class WrappedErrorBarRangeNegativeProperty : public WrappedStatisticProperty< OUString > +{ +public: + virtual OUString getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const OUString& aNewValue ) const override; + + explicit WrappedErrorBarRangeNegativeProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorBarRangeNegativeProperty::WrappedErrorBarRangeNegativeProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< OUString >( "ErrorBarRangeNegative" + , uno::Any( OUString() ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +OUString WrappedErrorBarRangeNegativeProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + OUString aRet; + m_aDefaultValue >>= aRet; + uno::Reference< chart2::data::XDataSource > xErrorBarDataSource; + if( xSeriesPropertySet.is() && + ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarDataSource ) && + xErrorBarDataSource.is()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarDataSource, false /* positive */ )); + if( xSeq.is()) + aRet = xSeq->getSourceRangeRepresentation(); + else + m_aOuterValue >>= aRet; + } + lcl_ConvertRangeToXML( aRet, m_spChart2ModelContact ); + return aRet; +} + +void WrappedErrorBarRangeNegativeProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const OUString& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( !xErrorBarProperties.is() ) + return; + + uno::Reference< chart2::data::XDataProvider > xDataProvider( + lcl_getDataProviderFromContact( m_spChart2ModelContact )); + uno::Reference< chart2::data::XDataSource > xDataSource( xErrorBarProperties, uno::UNO_QUERY ); + if( xDataSource.is() && xDataProvider.is()) + { + OUString aTmp( aNewValue ); + OUString aXMLRange( aNewValue ); + lcl_ConvertRangeFromXML( aTmp, m_spChart2ModelContact ); + StatisticsHelper::setErrorDataSequence( + xDataSource, xDataProvider, aTmp, false /* positive */, true /* y-error */, &aXMLRange ); + m_aOuterValue <<= aTmp; + } +} + +namespace { + +//PROP_CHART_STATISTIC_REGRESSION_CURVES +class WrappedRegressionCurvesProperty : public WrappedStatisticProperty< css::chart::ChartRegressionCurveType > +{ +public: + virtual css::chart::ChartRegressionCurveType getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartRegressionCurveType & aNewValue ) const override; + + explicit WrappedRegressionCurvesProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedRegressionCurvesProperty::WrappedRegressionCurvesProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< css::chart::ChartRegressionCurveType >( "RegressionCurves" + , lcl_getRegressionDefault(), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +css::chart::ChartRegressionCurveType WrappedRegressionCurvesProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + css::chart::ChartRegressionCurveType aRet; + m_aDefaultValue >>= aRet; + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropertySet, uno::UNO_QUERY ); + if( xRegCnt.is() ) + { + aRet = lcl_getRegressionCurveType( + RegressionCurveHelper::getFirstRegressTypeNotMeanValueLine( xRegCnt ) ); + } + return aRet; +} +void WrappedRegressionCurvesProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartRegressionCurveType& aNewValue ) const +{ + uno::Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeriesPropertySet, uno::UNO_QUERY ); + uno::Reference< chart2::XRegressionCurve > xRegressionCurve( xSeriesPropertySet, uno::UNO_QUERY ); + + if( xRegressionCurveContainer.is() && xRegressionCurve.is() ) + { + SvxChartRegress eNewRegressionType = lcl_getRegressionType( aNewValue ); + + RegressionCurveHelper::changeRegressionCurveType( + eNewRegressionType, + xRegressionCurveContainer, + xRegressionCurve); + } +} + +namespace { + +//PROP_CHART_STATISTIC_REGRESSION_PROPERTIES +//PROP_CHART_STATISTIC_ERROR_PROPERTIES +//PROP_CHART_STATISTIC_MEAN_VALUE_PROPERTIES +class WrappedStatisticPropertySetProperty : public WrappedStatisticProperty< Reference< beans::XPropertySet > > +{ +public: + virtual Reference< beans::XPropertySet > getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + // properties are read-only, so this method should never be called + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const Reference< beans::XPropertySet > & xNewValue ) const override; + + enum PropertySetType + { + PROPERTY_SET_TYPE_REGRESSION, + PROPERTY_SET_TYPE_ERROR_BAR, + PROPERTY_SET_TYPE_MEAN_VALUE + }; + + explicit WrappedStatisticPropertySetProperty( + PropertySetType ePropertySetType, std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + PropertySetType m_eType; +}; + +} + +WrappedStatisticPropertySetProperty::WrappedStatisticPropertySetProperty( + PropertySetType ePropertySetType + , std::shared_ptr< Chart2ModelContact > spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< Reference< beans::XPropertySet > >( + (ePropertySetType == PROPERTY_SET_TYPE_REGRESSION) + ? OUString("DataRegressionProperties") + : (ePropertySetType == PROPERTY_SET_TYPE_ERROR_BAR) + ? OUString("DataErrorProperties") + : OUString("DataMeanValueProperties") + , uno::Any(), std::move(spChart2ModelContact), ePropertyType ) + , m_eType( ePropertySetType ) +{ +} + +Reference< beans::XPropertySet > WrappedStatisticPropertySetProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + Reference< beans::XPropertySet > xResult; + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropertySet, uno::UNO_QUERY ); + + switch( m_eType ) + { + case PROPERTY_SET_TYPE_REGRESSION: + if( xRegCnt.is() ) + xResult = RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCnt ); + break; + case PROPERTY_SET_TYPE_ERROR_BAR: + if( xSeriesPropertySet.is()) + xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xResult; + break; + case PROPERTY_SET_TYPE_MEAN_VALUE: + if( xRegCnt.is() ) + xResult = RegressionCurveHelper::getMeanValueLine( xRegCnt ); + break; + } + + return xResult; +} + +void WrappedStatisticPropertySetProperty::setValueToSeries( + const Reference< beans::XPropertySet >& /* xSeriesPropertySet */ + , const Reference< beans::XPropertySet >& /* xNewValue */ ) const +{ +} + +namespace +{ +enum +{ + //statistic properties + PROP_CHART_STATISTIC_CONST_ERROR_LOW = FAST_PROPERTY_ID_START_CHART_STATISTIC_PROP, + PROP_CHART_STATISTIC_CONST_ERROR_HIGH, + PROP_CHART_STATISTIC_MEAN_VALUE, + PROP_CHART_STATISTIC_ERROR_CATEGORY, + PROP_CHART_STATISTIC_ERROR_BAR_STYLE, + PROP_CHART_STATISTIC_PERCENT_ERROR, + PROP_CHART_STATISTIC_ERROR_MARGIN, + PROP_CHART_STATISTIC_ERROR_INDICATOR, + PROP_CHART_STATISTIC_ERROR_RANGE_POSITIVE, + PROP_CHART_STATISTIC_ERROR_RANGE_NEGATIVE, + PROP_CHART_STATISTIC_REGRESSION_CURVES, + PROP_CHART_STATISTIC_REGRESSION_PROPERTIES, + PROP_CHART_STATISTIC_ERROR_PROPERTIES, + PROP_CHART_STATISTIC_MEAN_VALUE_PROPERTIES +}; + +/** @parameter bDataSeriesProperty if true, this property is for a single data + series, if false, it is for the whole diagram, i.e. for all + series + */ +void lcl_addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) +{ + rList.emplace_back( new WrappedConstantErrorLowProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedConstantErrorHighProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedMeanValueProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorCategoryProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorBarStyleProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedPercentageErrorProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorMarginProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorIndicatorProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorBarRangePositiveProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorBarRangeNegativeProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedRegressionCurvesProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedStatisticPropertySetProperty( + WrappedStatisticPropertySetProperty::PROPERTY_SET_TYPE_REGRESSION, spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedStatisticPropertySetProperty( + WrappedStatisticPropertySetProperty::PROPERTY_SET_TYPE_ERROR_BAR, spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedStatisticPropertySetProperty( + WrappedStatisticPropertySetProperty::PROPERTY_SET_TYPE_MEAN_VALUE, spChart2ModelContact, ePropertyType ) ); +} + +}//anonymous namespace + +void WrappedStatisticProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "ConstantErrorLow", + PROP_CHART_STATISTIC_CONST_ERROR_LOW, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ConstantErrorHigh", + PROP_CHART_STATISTIC_CONST_ERROR_HIGH, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "MeanValue", + PROP_CHART_STATISTIC_MEAN_VALUE, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorCategory", + PROP_CHART_STATISTIC_ERROR_CATEGORY, + cppu::UnoType<css::chart::ChartErrorCategory>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorBarStyle", + PROP_CHART_STATISTIC_ERROR_BAR_STYLE, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "PercentageError", + PROP_CHART_STATISTIC_PERCENT_ERROR, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorMargin", + PROP_CHART_STATISTIC_ERROR_MARGIN, + cppu::UnoType<double>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorIndicator", + PROP_CHART_STATISTIC_ERROR_INDICATOR, + cppu::UnoType<css::chart::ChartErrorIndicatorType>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorBarRangePositive", + PROP_CHART_STATISTIC_ERROR_RANGE_POSITIVE, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorBarRangeNegative", + PROP_CHART_STATISTIC_ERROR_RANGE_NEGATIVE, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "RegressionCurves", + PROP_CHART_STATISTIC_REGRESSION_CURVES, + cppu::UnoType<css::chart::ChartRegressionCurveType>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "DataRegressionProperties", + PROP_CHART_STATISTIC_REGRESSION_PROPERTIES, + cppu::UnoType<beans::XPropertySet>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "DataErrorProperties", + PROP_CHART_STATISTIC_ERROR_PROPERTIES, + cppu::UnoType<beans::XPropertySet>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "DataMeanValueProperties", + PROP_CHART_STATISTIC_MEAN_VALUE_PROPERTIES, + cppu::UnoType<beans::XPropertySet>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + | beans::PropertyAttribute::MAYBEVOID ); +} + +void WrappedStatisticProperties::addWrappedPropertiesForSeries( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DATA_SERIES ); +} + +void WrappedStatisticProperties::addWrappedPropertiesForDiagram( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DIAGRAM ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.hxx new file mode 100644 index 000000000..7831fccf4 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.hxx @@ -0,0 +1,44 @@ +/* -*- 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 <sal/types.h> +#include <memory> +#include <vector> + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedStatisticProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedPropertiesForSeries( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); + static void addWrappedPropertiesForDiagram( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedStockProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedStockProperties.cxx new file mode 100644 index 000000000..23c0b0fe5 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedStockProperties.cxx @@ -0,0 +1,281 @@ +/* -*- 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 "WrappedStockProperties.hxx" +#include "Chart2ModelContact.hxx" +#include <FastPropertyIdRanges.hxx> +#include <DataSeries.hxx> +#include <DiagramHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <WrappedProperty.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <tools/diagnose_ex.h> +#include <ChartTypeManager.hxx> +#include <ChartTypeTemplate.hxx> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace { + +class WrappedStockProperty : public WrappedProperty +{ +public: + explicit WrappedStockProperty( const OUString& rOuterName + , const css::uno::Any& rDefaulValue + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ); + + void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + virtual rtl::Reference< ::chart::ChartTypeTemplate > getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ::chart::ChartTypeManager >& xFactory ) const = 0; + +protected: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable css::uno::Any m_aOuterValue; + css::uno::Any m_aDefaultValue; +}; + +} + +WrappedStockProperty::WrappedStockProperty( const OUString& rOuterName + , const css::uno::Any& rDefaulValue + , const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact ) + : WrappedProperty(rOuterName,OUString()) + , m_spChart2ModelContact(spChart2ModelContact) + , m_aDefaultValue(rDefaulValue) +{ +} + +void WrappedStockProperty::setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "stock properties require type sal_Bool", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + sal_Int32 nDimension = ::chart::DiagramHelper::getDimension( xDiagram ); + if( !(xChartDoc.is() && xDiagram.is() && nDimension==2) ) + return; + + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate = + getNewTemplate( bNewValue, aTemplateAndService.sServiceName, xChartTypeManager ); + + if(!xTemplate.is()) + return; + + try + { + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + xTemplate->changeDiagram( xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +css::uno::Any WrappedStockProperty::getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return m_aDefaultValue; +} + +namespace { + +class WrappedVolumeProperty : public WrappedStockProperty +{ +public: + explicit WrappedVolumeProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + rtl::Reference< ::chart::ChartTypeTemplate > getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ::chart::ChartTypeManager >& xFactory ) const override; +}; + +} + +WrappedVolumeProperty::WrappedVolumeProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedStockProperty( "Volume", uno::Any(false) , spChart2ModelContact ) +{ +} + +css::uno::Any WrappedVolumeProperty::getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() && xChartDoc.is() ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + if( !aSeriesVector.empty() ) + { + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.StockVolumeLowHighClose" + || aTemplateAndService.sServiceName == "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ) + m_aOuterValue <<= true; + else if( !aTemplateAndService.sServiceName.isEmpty() || !m_aOuterValue.hasValue() ) + m_aOuterValue <<= false; + } + else if(!m_aOuterValue.hasValue()) + m_aOuterValue <<= false; + } + return m_aOuterValue; +} + +rtl::Reference< ::chart::ChartTypeTemplate > WrappedVolumeProperty::getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ::chart::ChartTypeManager >& xFactory ) const +{ + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + + if(!xFactory.is()) + return xTemplate; + + if( bNewValue ) //add volume + { + if( rCurrentTemplate == "com.sun.star.chart2.template.StockLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockVolumeLowHighClose" ); + else if( rCurrentTemplate == "com.sun.star.chart2.template.StockOpenLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ); + } + else //remove volume + { + if( rCurrentTemplate == "com.sun.star.chart2.template.StockVolumeLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockLowHighClose" ); + else if( rCurrentTemplate == "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockOpenLowHighClose" ); + } + return xTemplate; +} + +namespace { + +class WrappedUpDownProperty : public WrappedStockProperty +{ +public: + explicit WrappedUpDownProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact); + + css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + rtl::Reference< ::chart::ChartTypeTemplate > getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ChartTypeManager >& xFactory ) const override; +}; + +} + +WrappedUpDownProperty::WrappedUpDownProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact) + : WrappedStockProperty( "UpDown", uno::Any(false) , spChart2ModelContact ) +{ +} + +css::uno::Any WrappedUpDownProperty::getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() && xChartDoc.is() ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + if( !aSeriesVector.empty() ) + { + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.StockOpenLowHighClose" + || aTemplateAndService.sServiceName == "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ) + m_aOuterValue <<= true; + else if( !aTemplateAndService.sServiceName.isEmpty() || !m_aOuterValue.hasValue() ) + m_aOuterValue <<= false; + } + else if(!m_aOuterValue.hasValue()) + m_aOuterValue <<= false; + } + return m_aOuterValue; +} +rtl::Reference< ::chart::ChartTypeTemplate > WrappedUpDownProperty::getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ChartTypeManager >& xFactory ) const +{ + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + if( bNewValue ) //add open series + { + if( rCurrentTemplate == "com.sun.star.chart2.template.StockLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockOpenLowHighClose" ); + else if( rCurrentTemplate == "com.sun.star.chart2.template.StockVolumeLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ); + } + else //remove open series + { + if( rCurrentTemplate == "com.sun.star.chart2.template.StockOpenLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockLowHighClose" ); + else if( rCurrentTemplate == "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockVolumeLowHighClose" ); + } + return xTemplate; +} + +namespace +{ +enum +{ + //spline properties + PROP_CHART_STOCK_VOLUME = FAST_PROPERTY_ID_START_CHART_STOCK_PROP + , PROP_CHART_STOCK_UPDOWN +}; + +}//anonymous namespace + +void WrappedStockProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Volume", + PROP_CHART_STOCK_VOLUME, + cppu::UnoType<sal_Bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "UpDown", + PROP_CHART_STOCK_UPDOWN, + cppu::UnoType<sal_Bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); +} + +void WrappedStockProperties::addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedVolumeProperty( spChart2ModelContact ) ); + rList.emplace_back( new WrappedUpDownProperty( spChart2ModelContact ) ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedStockProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedStockProperties.hxx new file mode 100644 index 000000000..e460ba587 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedStockProperties.hxx @@ -0,0 +1,42 @@ +/* -*- 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 <sal/types.h> +#include <memory> +#include <vector> + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedStockProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.cxx new file mode 100644 index 000000000..7e2934872 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.cxx @@ -0,0 +1,531 @@ +/* -*- 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 "WrappedSymbolProperties.hxx" +#include "WrappedSeriesOrDiagramProperty.hxx" +#include <FastPropertyIdRanges.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <com/sun/star/chart2/Symbol.hpp> +#include <com/sun/star/chart2/SymbolStyle.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/chart/ChartSymbolType.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <vcl/GraphicLoader.hxx> + +#include <vcl/graph.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace +{ + +class WrappedSymbolTypeProperty : public WrappedSeriesOrDiagramProperty< sal_Int32 > +{ +public: + virtual sal_Int32 getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& aNewValue ) const override; + + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual beans::PropertyState getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + + explicit WrappedSymbolTypeProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +class WrappedSymbolBitmapURLProperty : public WrappedSeriesOrDiagramProperty<OUString> +{ +public: + virtual OUString getValueFromSeries(const Reference<beans::XPropertySet>& xSeriesPropertySet) const override; + virtual void setValueToSeries(const Reference<beans::XPropertySet> & xSeriesPropertySet, OUString const & xNewGraphicURL) const override; + + explicit WrappedSymbolBitmapURLProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +class WrappedSymbolBitmapProperty : public WrappedSeriesOrDiagramProperty<uno::Reference<graphic::XGraphic>> +{ +public: + virtual uno::Reference<graphic::XGraphic> getValueFromSeries(const Reference<beans::XPropertySet>& xSeriesPropertySet) const override; + virtual void setValueToSeries(const Reference<beans::XPropertySet> & xSeriesPropertySet, uno::Reference<graphic::XGraphic> const & xNewGraphic) const override; + + explicit WrappedSymbolBitmapProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +class WrappedSymbolSizeProperty : public WrappedSeriesOrDiagramProperty< awt::Size > +{ +public: + virtual awt::Size getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const awt::Size& aNewSize ) const override; + virtual beans::PropertyState getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + + explicit WrappedSymbolSizeProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +class WrappedSymbolAndLinesProperty : public WrappedSeriesOrDiagramProperty< bool > +{ +public: + virtual bool getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const bool& bDrawLines ) const override; + virtual beans::PropertyState getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + + explicit WrappedSymbolAndLinesProperty(const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +enum +{ + //symbol properties + PROP_CHART_SYMBOL_TYPE = FAST_PROPERTY_ID_START_CHART_SYMBOL_PROP, + PROP_CHART_SYMBOL_BITMAP_URL, + PROP_CHART_SYMBOL_BITMAP, + PROP_CHART_SYMBOL_SIZE, + PROP_CHART_SYMBOL_AND_LINES +}; + +sal_Int32 lcl_getSymbolType( const css::chart2::Symbol& rSymbol ) +{ + sal_Int32 nSymbol = css::chart::ChartSymbolType::NONE; + switch( rSymbol.Style ) + { + case chart2::SymbolStyle_NONE: + break; + case chart2::SymbolStyle_AUTO: + nSymbol = css::chart::ChartSymbolType::AUTO; + break; + case chart2::SymbolStyle_STANDARD: + nSymbol = rSymbol.StandardSymbol%15; + break; + case chart2::SymbolStyle_POLYGON://new feature + nSymbol = css::chart::ChartSymbolType::AUTO; + break; + case chart2::SymbolStyle_GRAPHIC: + nSymbol = css::chart::ChartSymbolType::BITMAPURL; + break; + default: + nSymbol = css::chart::ChartSymbolType::AUTO; + break; + } + return nSymbol; +} +void lcl_setSymbolTypeToSymbol( sal_Int32 nSymbolType, chart2::Symbol& rSymbol ) +{ + switch( nSymbolType ) + { + case css::chart::ChartSymbolType::NONE: + rSymbol.Style = chart2::SymbolStyle_NONE; + break; + case css::chart::ChartSymbolType::AUTO: + rSymbol.Style = chart2::SymbolStyle_AUTO; + break; + case css::chart::ChartSymbolType::BITMAPURL: + rSymbol.Style = chart2::SymbolStyle_GRAPHIC; + break; + default: + rSymbol.Style = chart2::SymbolStyle_STANDARD; + rSymbol.StandardSymbol = nSymbolType; + break; + } +} + +void lcl_addWrappedProperties( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) +{ + rList.emplace_back( new WrappedSymbolTypeProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedSymbolBitmapURLProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedSymbolBitmapProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedSymbolSizeProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedSymbolAndLinesProperty( spChart2ModelContact, ePropertyType ) ); +} + +}//anonymous namespace + +void WrappedSymbolProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "SymbolType", + PROP_CHART_SYMBOL_TYPE, + cppu::UnoType<sal_Int32>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "SymbolBitmapURL", + PROP_CHART_SYMBOL_BITMAP_URL, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "SymbolBitmap", + PROP_CHART_SYMBOL_BITMAP, + cppu::UnoType<graphic::XGraphic>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "SymbolSize", + PROP_CHART_SYMBOL_SIZE, + cppu::UnoType<awt::Size>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Lines", + PROP_CHART_SYMBOL_AND_LINES, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void WrappedSymbolProperties::addWrappedPropertiesForSeries( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DATA_SERIES ); +} + +void WrappedSymbolProperties::addWrappedPropertiesForDiagram( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DIAGRAM ); +} + +WrappedSymbolTypeProperty::WrappedSymbolTypeProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty< sal_Int32 >( "SymbolType" + , uno::Any( css::chart::ChartSymbolType::NONE ) + , spChart2ModelContact + , ePropertyType ) +{ +} + +sal_Int32 WrappedSymbolTypeProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + sal_Int32 aRet = 0; + m_aDefaultValue >>= aRet; + chart2::Symbol aSymbol; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol ) ) + aRet = lcl_getSymbolType( aSymbol ); + return aRet; +} + +void WrappedSymbolTypeProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& nSymbolType ) const +{ + if(!xSeriesPropertySet.is()) + return; + + chart2::Symbol aSymbol; + xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol; + + lcl_setSymbolTypeToSymbol( nSymbolType, aSymbol ); + xSeriesPropertySet->setPropertyValue( "Symbol", uno::Any( aSymbol ) ); +} + +Any WrappedSymbolTypeProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + //the old chart (< OOo 2.3) needs symbol-type="automatic" at the plot-area if any of the series should be able to have symbols + if( m_ePropertyType == DIAGRAM ) + { + bool bHasAmbiguousValue = false; + sal_Int32 aValue = 0; + if( detectInnerValue( aValue, bHasAmbiguousValue ) ) + { + if(bHasAmbiguousValue) + { + m_aOuterValue <<= css::chart::ChartSymbolType::AUTO; + } + else + { + if( aValue == css::chart::ChartSymbolType::NONE ) + m_aOuterValue <<= css::chart::ChartSymbolType::NONE; + else + m_aOuterValue <<= css::chart::ChartSymbolType::AUTO; + } + } + return m_aOuterValue; + } + else + { + css::uno::Any aRet( m_aDefaultValue ); + aRet <<= getValueFromSeries( xInnerPropertySet ); + return aRet; + } +} + +beans::PropertyState WrappedSymbolTypeProperty::getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + //the special situation for this property here is that the diagram default can be + //different from the normal default and different from all singles series values + //so we need to return PropertyState_DIRECT_VALUE for more cases + + if( m_ePropertyType == DATA_SERIES && //single series or point + m_spChart2ModelContact) + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + Reference< chart2::XDataSeries > xSeries( xInnerPropertyState, uno::UNO_QUERY ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) ); + if( ChartTypeHelper::isSupportingSymbolProperties( xChartType, 2 ) ) + return beans::PropertyState_DIRECT_VALUE; + } + return WrappedProperty::getPropertyState( xInnerPropertyState ); +} + +WrappedSymbolBitmapURLProperty::WrappedSymbolBitmapURLProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty<OUString>("SymbolBitmapURL", + uno::Any(OUString()), spChart2ModelContact, ePropertyType) +{ +} + +OUString WrappedSymbolBitmapURLProperty::getValueFromSeries(const Reference< beans::XPropertySet >& /*xSeriesPropertySet*/) const +{ + return OUString(); +} + +void WrappedSymbolBitmapURLProperty::setValueToSeries( + const Reference< beans::XPropertySet >& xSeriesPropertySet, + OUString const & xNewGraphicURL) const +{ + if (!xSeriesPropertySet.is()) + return; + + chart2::Symbol aSymbol; + if (xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol) + { + if (!xNewGraphicURL.isEmpty()) + { + Graphic aGraphic = vcl::graphic::loadFromURL(xNewGraphicURL); + aSymbol.Graphic.set(aGraphic.GetXGraphic()); + xSeriesPropertySet->setPropertyValue("Symbol", uno::Any(aSymbol)); + } + } +} + +WrappedSymbolBitmapProperty::WrappedSymbolBitmapProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty<uno::Reference<graphic::XGraphic>>("SymbolBitmap", + uno::Any(uno::Reference<graphic::XGraphic>()), spChart2ModelContact, ePropertyType) +{ +} + +uno::Reference<graphic::XGraphic> WrappedSymbolBitmapProperty::getValueFromSeries(const Reference< beans::XPropertySet >& xSeriesPropertySet) const +{ + uno::Reference<graphic::XGraphic> xGraphic; + m_aDefaultValue >>= xGraphic; + + chart2::Symbol aSymbol; + if (xSeriesPropertySet.is() && (xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol) + && aSymbol.Graphic.is()) + { + xGraphic = aSymbol.Graphic; + } + return xGraphic; +} + +void WrappedSymbolBitmapProperty::setValueToSeries( + const Reference< beans::XPropertySet >& xSeriesPropertySet, + uno::Reference<graphic::XGraphic> const & xNewGraphic) const +{ + if (!xSeriesPropertySet.is()) + return; + + chart2::Symbol aSymbol; + if (xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol) + { + if (xNewGraphic.is()) + { + aSymbol.Graphic.set(xNewGraphic); + xSeriesPropertySet->setPropertyValue("Symbol", uno::Any(aSymbol)); + } + } +} + +namespace +{ + +void lcl_correctSymbolSizeForBitmaps( chart2::Symbol& rSymbol ) +{ + if( rSymbol.Style != chart2::SymbolStyle_GRAPHIC ) + return; + if( rSymbol.Size.Width != -1 ) + return; + if( rSymbol.Size.Height != -1 ) + return; + + //find a good automatic size + try + { + const awt::Size aDefaultSize(250,250); + awt::Size aSize = aDefaultSize; + uno::Reference< beans::XPropertySet > xProp( rSymbol.Graphic, uno::UNO_QUERY ); + if( xProp.is() ) + { + bool bFoundSize = false; + try + { + if( xProp->getPropertyValue( "Size100thMM" ) >>= aSize ) + { + if( aSize.Width == 0 && aSize.Height == 0 ) + aSize = aDefaultSize; + else + bFoundSize = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + if(!bFoundSize) + { + awt::Size aAWTPixelSize(10,10); + if( xProp->getPropertyValue( "SizePixel" ) >>= aAWTPixelSize ) + { + Size aPixelSize(aAWTPixelSize.Width,aAWTPixelSize.Height); + Size aNewSize = o3tl::convert(aPixelSize, o3tl::Length::pt, o3tl::Length::mm100); + + aSize = awt::Size( aNewSize.Width(), aNewSize.Height() ); + + if( aSize.Width == 0 && aSize.Height == 0 ) + aSize = aDefaultSize; + } + } + } + rSymbol.Size = aSize; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +}//end anonymous namespace + +WrappedSymbolSizeProperty::WrappedSymbolSizeProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty< awt::Size >( "SymbolSize" + , uno::Any( awt::Size(250,250) ), spChart2ModelContact, ePropertyType ) +{ +} + +awt::Size WrappedSymbolSizeProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + awt::Size aRet; + m_aDefaultValue >>= aRet; + chart2::Symbol aSymbol; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol )) + aRet = aSymbol.Size; + return aRet; +} + +void WrappedSymbolSizeProperty::setValueToSeries( + const Reference< beans::XPropertySet >& xSeriesPropertySet, + const awt::Size& aNewSize ) const +{ + if(!xSeriesPropertySet.is()) + return; + + chart2::Symbol aSymbol; + if( xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol ) + { + aSymbol.Size = aNewSize; + lcl_correctSymbolSizeForBitmaps(aSymbol); + xSeriesPropertySet->setPropertyValue( "Symbol", uno::Any( aSymbol ) ); + } +} + +beans::PropertyState WrappedSymbolSizeProperty::getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + //only export symbol size if necessary + if( m_ePropertyType == DIAGRAM ) + return beans::PropertyState_DEFAULT_VALUE; + + try + { + chart2::Symbol aSymbol; + Reference< beans::XPropertySet > xSeriesPropertySet( xInnerPropertyState, uno::UNO_QUERY ); + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol )) + { + if( aSymbol.Style != chart2::SymbolStyle_NONE ) + return beans::PropertyState_DIRECT_VALUE; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return beans::PropertyState_DEFAULT_VALUE; +} + +WrappedSymbolAndLinesProperty::WrappedSymbolAndLinesProperty( + const std::shared_ptr<Chart2ModelContact>& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty< bool >( "Lines" + , uno::Any( true ), spChart2ModelContact, ePropertyType ) +{ +} + +bool WrappedSymbolAndLinesProperty::getValueFromSeries( const Reference< beans::XPropertySet >& /*xSeriesPropertySet*/ ) const +{ + //do not export this property anymore, instead use a linestyle none for no lines + return true; +} + +void WrappedSymbolAndLinesProperty::setValueToSeries( + const Reference< beans::XPropertySet >& xSeriesPropertySet, + const bool& bDrawLines ) const +{ + if(!xSeriesPropertySet.is()) + return; + + drawing::LineStyle eOldLineStyle( drawing::LineStyle_SOLID ); + xSeriesPropertySet->getPropertyValue( "LineStyle" ) >>= eOldLineStyle; + if( bDrawLines ) + { + //#i114298# don't overwrite dashed lines with solid lines here + if( eOldLineStyle == drawing::LineStyle_NONE ) + xSeriesPropertySet->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID ) ); + } + else + { + if( eOldLineStyle != drawing::LineStyle_NONE ) + xSeriesPropertySet->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE ) ); + } +} + +beans::PropertyState WrappedSymbolAndLinesProperty::getPropertyState( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + //do not export this property anymore, instead use a linestyle none for no lines + return beans::PropertyState_DEFAULT_VALUE; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.hxx new file mode 100644 index 000000000..f3a0fcd66 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.hxx @@ -0,0 +1,44 @@ +/* -*- 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 <sal/types.h> +#include <memory> +#include <vector> + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedSymbolProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedPropertiesForSeries( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); + static void addWrappedPropertiesForDiagram( std::vector< std::unique_ptr<WrappedProperty> >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.cxx new file mode 100644 index 000000000..c35a75e31 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.cxx @@ -0,0 +1,71 @@ +/* -*- 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 "WrappedTextRotationProperty.hxx" + +namespace com::sun::star::beans { class XPropertyState; } + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; + +namespace chart +{ + +WrappedTextRotationProperty::WrappedTextRotationProperty( bool bDirectState ) + : ::chart::WrappedProperty( "TextRotation" , "TextRotation" ) + , m_bDirectState( bDirectState ) +{ +} +WrappedTextRotationProperty::~WrappedTextRotationProperty() +{ +} + +beans::PropertyState WrappedTextRotationProperty::getPropertyState( const uno::Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( m_bDirectState ) + return beans::PropertyState_DIRECT_VALUE; + return WrappedProperty::getPropertyState( xInnerPropertyState ); +} + +Any WrappedTextRotationProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + Any aRet; + double fVal = 0; + if( rInnerValue >>= fVal ) + { + sal_Int32 n100thDegrees = static_cast< sal_Int32 >( fVal * 100.0 ); + aRet <<= n100thDegrees; + } + return aRet; +} +Any WrappedTextRotationProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + Any aRet; + sal_Int32 nVal = 0; + if( rOuterValue >>= nVal ) + { + double fDoubleDegrees = static_cast< double >( nVal ) / 100.0; + aRet <<= fDoubleDegrees; + } + return aRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.hxx new file mode 100644 index 000000000..48287dd59 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.hxx @@ -0,0 +1,43 @@ +/* -*- 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 <WrappedProperty.hxx> + +namespace chart +{ +class WrappedTextRotationProperty final : public WrappedProperty +{ +public: + explicit WrappedTextRotationProperty(bool bDirectState = false); + virtual ~WrappedTextRotationProperty() override; + + virtual css::beans::PropertyState getPropertyState( + const css::uno::Reference<css::beans::XPropertyState>& xInnerPropertyState) const override; + +private: + virtual css::uno::Any convertInnerToOuterValue(const css::uno::Any& rInnerValue) const override; + virtual css::uno::Any convertOuterToInnerValue(const css::uno::Any& rOuterValue) const override; + + bool m_bDirectState; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartcontroller.component b/chart2/source/controller/chartcontroller.component new file mode 100644 index 000000000..01201cbb2 --- /dev/null +++ b/chart2/source/controller/chartcontroller.component @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.chart.ElementSelectorToolbarController" + constructor="com_sun_star_comp_chart_ElementSelectorToolbarController_get_implementation"> + <service name="com.sun.star.frame.ToolbarController"/> + </implementation> + <implementation name="com.sun.star.comp.chart2.ChartController" + constructor="com_sun_star_comp_chart2_ChartController_get_implementation"> + <service name="com.sun.star.chart2.ChartController"/> + <service name="com.sun.star.frame.Controller"/> + </implementation> + <implementation name="com.sun.star.comp.chart2.ChartDocumentWrapper" + constructor="com_sun_star_comp_chart2_ChartDocumentWrapper_get_implementation"> + <service name="com.sun.star.beans.PropertySet"/> + <service name="com.sun.star.chart.ChartDocument"/> + <service name="com.sun.star.chart2.ChartDocumentWrapper"/> + <service name="com.sun.star.xml.UserDefinedAttributesSupplier"/> + </implementation> + <implementation name="com.sun.star.comp.chart2.ChartFrameLoader" + constructor="com_sun_star_comp_chart2_ChartFrameLoader_get_implementation"> + <service name="com.sun.star.frame.SynchronousFrameLoader"/> + </implementation> + <implementation name="com.sun.star.comp.chart2.ChartTypeDialog" + constructor="com_sun_star_comp_chart2_ChartTypeDialog_get_implementation"> + <service name="com.sun.star.chart2.ChartTypeDialog"/> + </implementation> + <implementation name="com.sun.star.comp.chart2.WizardDialog" + constructor="com_sun_star_comp_chart2_WizardDialog_get_implementation"> + <service name="com.sun.star.chart2.WizardDialog"/> + </implementation> + <implementation name="org.libreoffice.comp.chart2.sidebar.ChartPanelFactory" + constructor="org_libreoffice_comp_chart2_sidebar_ChartPanelFactory"> + <service name="com.sun.star.ui.UIElementFactory"/> + </implementation> + <implementation name="org.libreoffice.chart2.Chart2ToolboxController" + constructor="org_libreoffice_chart2_Chart2ToolboxController"> + <service name="com.sun.star.frame.ToolbarController"/> + </implementation> +</component> diff --git a/chart2/source/controller/dialogs/ChangingResource.cxx b/chart2/source/controller/dialogs/ChangingResource.cxx new file mode 100644 index 000000000..4cbbe569c --- /dev/null +++ b/chart2/source/controller/dialogs/ChangingResource.cxx @@ -0,0 +1,38 @@ +/* -*- 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 <ChangingResource.hxx> + +namespace chart +{ +ResourceChangeListener::~ResourceChangeListener() {} + +ChangingResource::ChangingResource() + : m_pChangeListener(nullptr) +{ +} +ChangingResource::~ChangingResource() {} +void ChangingResource::setChangeListener(ResourceChangeListener* pListener) +{ + m_pChangeListener = pListener; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/ChartResourceGroupDlgs.cxx b/chart2/source/controller/dialogs/ChartResourceGroupDlgs.cxx new file mode 100644 index 000000000..91307afaa --- /dev/null +++ b/chart2/source/controller/dialogs/ChartResourceGroupDlgs.cxx @@ -0,0 +1,131 @@ +/* -*- 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 <ChartResourceGroupDlgs.hxx> +#include <ChartTypeDialogController.hxx> + +#include <strings.hrc> +#include <ResId.hxx> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +const sal_uInt16 CUBIC_SPLINE_POS = 0; +const sal_uInt16 B_SPLINE_POS = 1; + +SplinePropertiesDialog::SplinePropertiesDialog(weld::Window* pParent) + : GenericDialogController(pParent, "modules/schart/ui/smoothlinesdlg.ui", "SmoothLinesDialog") + , m_xLB_Spline_Type(m_xBuilder->weld_combo_box("SplineTypeComboBox")) + , m_xMF_SplineResolution(m_xBuilder->weld_spin_button("ResolutionSpinbutton")) + , m_xFT_SplineOrder(m_xBuilder->weld_label("PolynomialsLabel")) + , m_xMF_SplineOrder(m_xBuilder->weld_spin_button("PolynomialsSpinButton")) +{ + m_xDialog->set_title(SchResId(STR_DLG_SMOOTH_LINE_PROPERTIES)); + + m_xLB_Spline_Type->connect_changed(LINK(this, SplinePropertiesDialog, SplineTypeListBoxHdl)); +} + +void SplinePropertiesDialog::fillControls(const ChartTypeParameter& rParameter) +{ + switch (rParameter.eCurveStyle) + { + case CurveStyle_CUBIC_SPLINES: + m_xLB_Spline_Type->set_active(CUBIC_SPLINE_POS); + break; + case CurveStyle_B_SPLINES: + m_xLB_Spline_Type->set_active(B_SPLINE_POS); + break; + default: + m_xLB_Spline_Type->set_active(CUBIC_SPLINE_POS); + break; + } + m_xMF_SplineOrder->set_value(rParameter.nSplineOrder); + m_xMF_SplineResolution->set_value(rParameter.nCurveResolution); + + //dis/enabling + m_xFT_SplineOrder->set_sensitive(m_xLB_Spline_Type->get_active() == B_SPLINE_POS); + m_xMF_SplineOrder->set_sensitive(m_xLB_Spline_Type->get_active() == B_SPLINE_POS); +} + +void SplinePropertiesDialog::fillParameter(ChartTypeParameter& rParameter, bool bSmoothLines) +{ + if (!bSmoothLines) + rParameter.eCurveStyle = CurveStyle_LINES; + else if (m_xLB_Spline_Type->get_active() == CUBIC_SPLINE_POS) + rParameter.eCurveStyle = CurveStyle_CUBIC_SPLINES; + else if (m_xLB_Spline_Type->get_active() == B_SPLINE_POS) + rParameter.eCurveStyle = CurveStyle_B_SPLINES; + + rParameter.nCurveResolution = m_xMF_SplineResolution->get_value(); + rParameter.nSplineOrder = m_xMF_SplineOrder->get_value(); +} + +IMPL_LINK_NOARG(SplinePropertiesDialog, SplineTypeListBoxHdl, weld::ComboBox&, void) +{ + m_xFT_SplineOrder->set_sensitive(m_xLB_Spline_Type->get_active() == B_SPLINE_POS); + m_xMF_SplineOrder->set_sensitive(m_xLB_Spline_Type->get_active() == B_SPLINE_POS); +} + +SteppedPropertiesDialog::SteppedPropertiesDialog(weld::Window* pParent) + : GenericDialogController(pParent, "modules/schart/ui/steppedlinesdlg.ui", "SteppedLinesDialog") + , m_xRB_Start(m_xBuilder->weld_radio_button("step_start_rb")) + , m_xRB_End(m_xBuilder->weld_radio_button("step_end_rb")) + , m_xRB_CenterX(m_xBuilder->weld_radio_button("step_center_x_rb")) + , m_xRB_CenterY(m_xBuilder->weld_radio_button("step_center_y_rb")) +{ + m_xDialog->set_title(SchResId(STR_DLG_STEPPED_LINE_PROPERTIES)); +} + +void SteppedPropertiesDialog::fillControls(const ChartTypeParameter& rParameter) +{ + switch (rParameter.eCurveStyle) + { + case CurveStyle_STEP_END: + m_xRB_End->set_active(true); + break; + case CurveStyle_STEP_CENTER_X: + m_xRB_CenterX->set_active(true); + break; + case CurveStyle_STEP_CENTER_Y: + m_xRB_CenterY->set_active(true); + break; + default: // includes CurveStyle_STEP_START + m_xRB_Start->set_active(true); + break; + } +} +void SteppedPropertiesDialog::fillParameter(ChartTypeParameter& rParameter, bool bSteppedLines) +{ + if (!bSteppedLines) + rParameter.eCurveStyle = CurveStyle_LINES; + else if (m_xRB_CenterY->get_active()) + rParameter.eCurveStyle = CurveStyle_STEP_CENTER_Y; + else if (m_xRB_Start->get_active()) + rParameter.eCurveStyle = CurveStyle_STEP_START; + else if (m_xRB_End->get_active()) + rParameter.eCurveStyle = CurveStyle_STEP_END; + else if (m_xRB_CenterX->get_active()) + rParameter.eCurveStyle = CurveStyle_STEP_CENTER_X; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/ChartResourceGroups.cxx b/chart2/source/controller/dialogs/ChartResourceGroups.cxx new file mode 100644 index 000000000..19534aa1e --- /dev/null +++ b/chart2/source/controller/dialogs/ChartResourceGroups.cxx @@ -0,0 +1,361 @@ +/* -*- 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 <ChartResourceGroups.hxx> +#include <ChartResourceGroupDlgs.hxx> + +#include <strings.hrc> +#include <ResId.hxx> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +Dim3DLookResourceGroup::Dim3DLookResourceGroup(weld::Builder* pBuilder) + : m_xCB_3DLook(pBuilder->weld_check_button("3dlook")) + , m_xLB_Scheme(pBuilder->weld_combo_box("3dscheme")) +{ + m_xCB_3DLook->connect_toggled(LINK(this, Dim3DLookResourceGroup, Dim3DLookCheckHdl)); + m_xLB_Scheme->connect_changed(LINK(this, Dim3DLookResourceGroup, SelectSchemeHdl)); +} + +void Dim3DLookResourceGroup::showControls(bool bShow) +{ + m_xCB_3DLook->set_visible(bShow); + m_xLB_Scheme->set_visible(bShow); +} + +void Dim3DLookResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + m_xCB_3DLook->set_active(rParameter.b3DLook); + m_xLB_Scheme->set_sensitive(rParameter.b3DLook); + + // tdf#124295 - select always a 3D scheme + switch (rParameter.eThreeDLookScheme) + { + case ThreeDLookScheme::ThreeDLookScheme_Simple: + m_xLB_Scheme->set_active(POS_3DSCHEME_SIMPLE); + break; + case ThreeDLookScheme::ThreeDLookScheme_Realistic: + case ThreeDLookScheme::ThreeDLookScheme_Unknown: + m_xLB_Scheme->set_active(POS_3DSCHEME_REALISTIC); + break; + } +} + +void Dim3DLookResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + rParameter.b3DLook = m_xCB_3DLook->get_active(); + // tdf#124295 - select always a 3D scheme + switch (m_xLB_Scheme->get_active()) + { + case POS_3DSCHEME_SIMPLE: + rParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Simple; + break; + default: + rParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + } +} + +IMPL_LINK_NOARG(Dim3DLookResourceGroup, Dim3DLookCheckHdl, weld::Toggleable&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +IMPL_LINK_NOARG(Dim3DLookResourceGroup, SelectSchemeHdl, weld::ComboBox&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +SortByXValuesResourceGroup::SortByXValuesResourceGroup(weld::Builder* pBuilder) + : m_xCB_XValueSorting(pBuilder->weld_check_button("sort")) +{ + m_xCB_XValueSorting->connect_toggled( + LINK(this, SortByXValuesResourceGroup, SortByXValuesCheckHdl)); +} + +void SortByXValuesResourceGroup::showControls(bool bShow) +{ + m_xCB_XValueSorting->set_visible(bShow); +} + +void SortByXValuesResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + m_xCB_XValueSorting->set_active(rParameter.bSortByXValues); +} + +void SortByXValuesResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + rParameter.bSortByXValues = m_xCB_XValueSorting->get_active(); +} + +IMPL_LINK_NOARG(SortByXValuesResourceGroup, SortByXValuesCheckHdl, weld::Toggleable&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +StackingResourceGroup::StackingResourceGroup(weld::Builder* pBuilder) + : m_xCB_Stacked(pBuilder->weld_check_button("stack")) + , m_xRB_Stack_Y(pBuilder->weld_radio_button("ontop")) + , m_xRB_Stack_Y_Percent(pBuilder->weld_radio_button("percent")) + , m_xRB_Stack_Z(pBuilder->weld_radio_button("deep")) +{ + m_xCB_Stacked->connect_toggled(LINK(this, StackingResourceGroup, StackingEnableHdl)); + m_xRB_Stack_Y->connect_toggled(LINK(this, StackingResourceGroup, StackingChangeHdl)); + m_xRB_Stack_Y_Percent->connect_toggled(LINK(this, StackingResourceGroup, StackingChangeHdl)); + m_xRB_Stack_Z->connect_toggled(LINK(this, StackingResourceGroup, StackingChangeHdl)); +} + +void StackingResourceGroup::showControls(bool bShow) +{ + m_xCB_Stacked->set_visible(bShow); + m_xRB_Stack_Y->set_visible(bShow); + m_xRB_Stack_Y_Percent->set_visible(bShow); + m_xRB_Stack_Z->set_visible(false); +} + +void StackingResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + m_xCB_Stacked->set_active( + rParameter.eStackMode != GlobalStackMode_NONE + && rParameter.eStackMode + != GlobalStackMode_STACK_Z); //todo remove this condition if z stacking radio button is really used + switch (rParameter.eStackMode) + { + case GlobalStackMode_STACK_Y: + m_xRB_Stack_Y->set_active(true); + break; + case GlobalStackMode_STACK_Y_PERCENT: + m_xRB_Stack_Y_Percent->set_active(true); + break; + case GlobalStackMode_STACK_Z: + //todo uncomment this condition if z stacking radio button is really used + /* + if( rParameter.b3DLook ) + m_xRB_Stack_Z->set_active(true); + else + */ + m_xRB_Stack_Y->set_active(true); + break; + default: + m_xRB_Stack_Y->set_active(true); + break; + } + //dis/enabling + m_xCB_Stacked->set_sensitive(!rParameter.bXAxisWithValues); + m_xRB_Stack_Y->set_sensitive(m_xCB_Stacked->get_active() && !rParameter.bXAxisWithValues); + m_xRB_Stack_Y_Percent->set_sensitive(m_xCB_Stacked->get_active() + && !rParameter.bXAxisWithValues); + m_xRB_Stack_Z->set_sensitive(m_xCB_Stacked->get_active() && rParameter.b3DLook); +} + +void StackingResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + if (!m_xCB_Stacked->get_active()) + rParameter.eStackMode = GlobalStackMode_NONE; + else if (m_xRB_Stack_Y->get_active()) + rParameter.eStackMode = GlobalStackMode_STACK_Y; + else if (m_xRB_Stack_Y_Percent->get_active()) + rParameter.eStackMode = GlobalStackMode_STACK_Y_PERCENT; + else if (m_xRB_Stack_Z->get_active()) + rParameter.eStackMode = GlobalStackMode_STACK_Z; +} + +IMPL_LINK(StackingResourceGroup, StackingChangeHdl, weld::Toggleable&, rRadio, void) +{ + //for each radio click there are coming two change events + //first uncheck of previous button -> ignore that call + //the second call gives the check of the new button + if (m_pChangeListener && rRadio.get_active()) + m_pChangeListener->stateChanged(); +} + +IMPL_LINK_NOARG(StackingResourceGroup, StackingEnableHdl, weld::Toggleable&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +SplineResourceGroup::SplineResourceGroup(weld::Builder* pBuilder, weld::Window* pParent) + : m_pParent(pParent) + , m_xFT_LineType(pBuilder->weld_label("linetypeft")) + , m_xLB_LineType(pBuilder->weld_combo_box("linetype")) + , m_xPB_DetailsDialog(pBuilder->weld_button("properties")) +{ + m_xLB_LineType->connect_changed(LINK(this, SplineResourceGroup, LineTypeChangeHdl)); +} + +SplinePropertiesDialog& SplineResourceGroup::getSplinePropertiesDialog() +{ + if (!m_xSplinePropertiesDialog) + { + m_xSplinePropertiesDialog.reset(new SplinePropertiesDialog(m_pParent)); + } + return *m_xSplinePropertiesDialog; +} + +SteppedPropertiesDialog& SplineResourceGroup::getSteppedPropertiesDialog() +{ + if (!m_xSteppedPropertiesDialog) + { + m_xSteppedPropertiesDialog.reset(new SteppedPropertiesDialog(m_pParent)); + } + return *m_xSteppedPropertiesDialog; +} + +void SplineResourceGroup::showControls(bool bShow) +{ + m_xFT_LineType->set_visible(bShow); + m_xLB_LineType->set_visible(bShow); + m_xPB_DetailsDialog->set_visible(bShow); +} + +void SplineResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + switch (rParameter.eCurveStyle) + { + case CurveStyle_LINES: + m_xLB_LineType->set_active(POS_LINETYPE_STRAIGHT); + m_xPB_DetailsDialog->set_sensitive(false); + break; + case CurveStyle_CUBIC_SPLINES: + case CurveStyle_B_SPLINES: + m_xLB_LineType->set_active(POS_LINETYPE_SMOOTH); + m_xPB_DetailsDialog->set_sensitive(true); + m_xPB_DetailsDialog->connect_clicked( + LINK(this, SplineResourceGroup, SplineDetailsDialogHdl)); + m_xPB_DetailsDialog->set_tooltip_text(SchResId(STR_DLG_SMOOTH_LINE_PROPERTIES)); + getSplinePropertiesDialog().fillControls(rParameter); + break; + case CurveStyle_STEP_START: + case CurveStyle_STEP_END: + case CurveStyle_STEP_CENTER_X: + case CurveStyle_STEP_CENTER_Y: + m_xLB_LineType->set_active(POS_LINETYPE_STEPPED); + m_xPB_DetailsDialog->set_sensitive(true); + m_xPB_DetailsDialog->connect_clicked( + LINK(this, SplineResourceGroup, SteppedDetailsDialogHdl)); + m_xPB_DetailsDialog->set_tooltip_text(SchResId(STR_DLG_STEPPED_LINE_PROPERTIES)); + getSteppedPropertiesDialog().fillControls(rParameter); + break; + default: + m_xLB_LineType->set_active(-1); + m_xPB_DetailsDialog->set_sensitive(false); + } +} +void SplineResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + switch (m_xLB_LineType->get_active()) + { + case POS_LINETYPE_SMOOTH: + getSplinePropertiesDialog().fillParameter(rParameter, true); + break; + case POS_LINETYPE_STEPPED: + getSteppedPropertiesDialog().fillParameter(rParameter, true); + break; + default: // includes POS_LINETYPE_STRAIGHT + rParameter.eCurveStyle = CurveStyle_LINES; + break; + } +} + +IMPL_LINK_NOARG(SplineResourceGroup, LineTypeChangeHdl, weld::ComboBox&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +IMPL_LINK_NOARG(SplineResourceGroup, SplineDetailsDialogHdl, weld::Button&, void) +{ + ChartTypeParameter aOldParameter; + getSplinePropertiesDialog().fillParameter(aOldParameter, + m_xLB_LineType->get_active() == POS_LINETYPE_SMOOTH); + + const sal_Int32 iOldLineTypePos = m_xLB_LineType->get_active(); + m_xLB_LineType->set_active(POS_LINETYPE_SMOOTH); + if (getSplinePropertiesDialog().run() == RET_OK) + { + if (m_pChangeListener) + m_pChangeListener->stateChanged(); + } + else + { + //restore old state: + m_xLB_LineType->set_active(iOldLineTypePos); + getSplinePropertiesDialog().fillControls(aOldParameter); + } +} + +IMPL_LINK_NOARG(SplineResourceGroup, SteppedDetailsDialogHdl, weld::Button&, void) +{ + ChartTypeParameter aOldParameter; + getSteppedPropertiesDialog().fillParameter(aOldParameter, m_xLB_LineType->get_active() + == POS_LINETYPE_STEPPED); + + const sal_Int32 iOldLineTypePos = m_xLB_LineType->get_active(); + m_xLB_LineType->set_active(POS_LINETYPE_STEPPED); + if (getSteppedPropertiesDialog().run() == RET_OK) + { + if (m_pChangeListener) + m_pChangeListener->stateChanged(); + } + else + { + //restore old state: + m_xLB_LineType->set_active(iOldLineTypePos); + getSteppedPropertiesDialog().fillControls(aOldParameter); + } +} + +GeometryResourceGroup::GeometryResourceGroup(weld::Builder* pBuilder) + : m_aGeometryResources(pBuilder) +{ + m_aGeometryResources.connect_changed(LINK(this, GeometryResourceGroup, GeometryChangeHdl)); +} + +void GeometryResourceGroup::showControls(bool bShow) { m_aGeometryResources.set_visible(bShow); } + +void GeometryResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + sal_uInt16 nGeometry3D = static_cast<sal_uInt16>(rParameter.nGeometry3D); + m_aGeometryResources.select(nGeometry3D); + m_aGeometryResources.set_sensitive(rParameter.b3DLook); +} + +void GeometryResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + rParameter.nGeometry3D = 1; + int nSelected = m_aGeometryResources.get_selected_index(); + if (nSelected != -1) + rParameter.nGeometry3D = nSelected; +} + +IMPL_LINK_NOARG(GeometryResourceGroup, GeometryChangeHdl, weld::TreeView&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/ChartTypeDialogController.cxx b/chart2/source/controller/dialogs/ChartTypeDialogController.cxx new file mode 100644 index 000000000..9bcce8c89 --- /dev/null +++ b/chart2/source/controller/dialogs/ChartTypeDialogController.cxx @@ -0,0 +1,1253 @@ +/* -*- 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 <ChartTypeDialogController.hxx> +#include <ChartTypeManager.hxx> +#include <ChartTypeTemplate.hxx> +#include <ResId.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <ChartModelHelper.hxx> +#include <DataSeries.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ControllerLockGuard.hxx> +#include <AxisHelper.hxx> +#include <unonames.hxx> +#include <BaseCoordinateSystem.hxx> +#include <ChartModel.hxx> + +#include <com/sun/star/chart2/DataPointGeometry3D.hpp> + +#include <svtools/valueset.hxx> +#include <vcl/image.hxx> +#include <vcl/settings.hxx> + +#include <tools/diagnose_ex.h> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +ChartTypeParameter::ChartTypeParameter() + : nSubTypeIndex( 1 ) + , bXAxisWithValues( false ) + , b3DLook( false ) + , bSymbols( true ) + , bLines( true ) + , eStackMode( GlobalStackMode_NONE ) + , eCurveStyle( CurveStyle_LINES ) + , nCurveResolution(20) + , nSplineOrder(3) + , nGeometry3D(DataPointGeometry3D::CUBOID) + , eThreeDLookScheme(ThreeDLookScheme::ThreeDLookScheme_Realistic) + , bSortByXValues(false) + , mbRoundedEdge(false) +{ +} + +ChartTypeParameter::ChartTypeParameter( sal_Int32 SubTypeIndex, bool HasXAxisWithValues + , bool Is3DLook, GlobalStackMode nStackMode + , bool HasSymbols, bool HasLines + , CurveStyle nCurveStyle ) + : nSubTypeIndex( SubTypeIndex ) + , bXAxisWithValues( HasXAxisWithValues ) + , b3DLook( Is3DLook ) + , bSymbols( HasSymbols ) + , bLines( HasLines ) + , eStackMode( nStackMode ) + , eCurveStyle( nCurveStyle ) + , nCurveResolution(20) + , nSplineOrder(3) + , nGeometry3D(DataPointGeometry3D::CUBOID) + , eThreeDLookScheme(ThreeDLookScheme::ThreeDLookScheme_Realistic) + , bSortByXValues(false) + , mbRoundedEdge(false) +{ +} + +bool ChartTypeParameter::mapsToSameService( const ChartTypeParameter& rParameter ) const +{ + return mapsToSimilarService( rParameter, 0 ); +} +bool ChartTypeParameter::mapsToSimilarService( const ChartTypeParameter& rParameter, sal_Int32 nTheHigherTheLess ) const +{ + sal_Int32 nMax=7; + if(nTheHigherTheLess>nMax) + return true; + if( bXAxisWithValues!=rParameter.bXAxisWithValues ) + return nTheHigherTheLess>nMax-1; + if( b3DLook!=rParameter.b3DLook ) + return nTheHigherTheLess>nMax-2; + if( eStackMode!=rParameter.eStackMode ) + return nTheHigherTheLess>nMax-3; + if( nSubTypeIndex!=rParameter.nSubTypeIndex ) + return nTheHigherTheLess>nMax-4; + if( bSymbols!=rParameter.bSymbols ) + return nTheHigherTheLess>nMax-5; + if( bLines!=rParameter.bLines ) + return nTheHigherTheLess>nMax-6; + return true; +} + +ChartTypeDialogController::ChartTypeDialogController() + : bSupportsXAxisWithValues(false) + , bSupports3D(true) +{ +} + +ChartTypeDialogController::~ChartTypeDialogController() +{ +} + +bool ChartTypeDialogController::isSubType( const OUString& rServiceName ) +{ + const tTemplateServiceChartTypeParameterMap& rTemplateMap = getTemplateMap(); + tTemplateServiceChartTypeParameterMap::const_iterator aIt( rTemplateMap.find( rServiceName )); + return aIt != rTemplateMap.end(); +} +ChartTypeParameter ChartTypeDialogController::getChartTypeParameterForService( + const OUString& rServiceName + , const uno::Reference< beans::XPropertySet >& xTemplateProps ) +{ + ChartTypeParameter aRet; + const tTemplateServiceChartTypeParameterMap& rTemplateMap = getTemplateMap(); + tTemplateServiceChartTypeParameterMap::const_iterator aIt( rTemplateMap.find( rServiceName )); + if( aIt != rTemplateMap.end()) + aRet = (*aIt).second; + if( xTemplateProps.is() ) + { + try + { + xTemplateProps->getPropertyValue( CHART_UNONAME_CURVE_STYLE ) >>= aRet.eCurveStyle; + xTemplateProps->getPropertyValue( CHART_UNONAME_CURVE_RESOLUTION ) >>= aRet.nCurveResolution; + xTemplateProps->getPropertyValue( CHART_UNONAME_SPLINE_ORDER ) >>= aRet.nSplineOrder; + } + catch( uno::Exception & ex ) + { + //not all templates need to support CurveStyle, CurveResolution or SplineOrder + ex.Context.is();//to have debug information without compilation warnings + } + + try + { + xTemplateProps->getPropertyValue( "Geometry3D" ) >>= aRet.nGeometry3D; + } + catch( uno::Exception& ex ) + { + //not all templates need to support Geometry3D + ex.Context.is();//to have debug information without compilation warnings + } + } + return aRet; +} +void ChartTypeDialogController::adjustSubTypeAndEnableControls( ChartTypeParameter& /*rParameter*/ ) +{ +} +void ChartTypeDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.eStackMode=GlobalStackMode_STACK_Y; + break; + case 3: + rParameter.eStackMode=GlobalStackMode_STACK_Y_PERCENT; + break; + case 4: + rParameter.eStackMode=GlobalStackMode_STACK_Z; + break; + default: + rParameter.eStackMode=GlobalStackMode_NONE; + break; + } +} +void ChartTypeDialogController::adjustParameterToMainType( ChartTypeParameter& rParameter ) +{ + bool bFoundSomeMatch=false; + + rParameter.bXAxisWithValues = bSupportsXAxisWithValues; + if( rParameter.b3DLook && !bSupports3D ) + rParameter.b3DLook = false; + if(!rParameter.b3DLook && rParameter.eStackMode==GlobalStackMode_STACK_Z) + rParameter.eStackMode = GlobalStackMode_NONE; + + const tTemplateServiceChartTypeParameterMap& rMap = getTemplateMap(); + for( sal_Int32 nMatchPrecision=0; nMatchPrecision<7 && !bFoundSomeMatch; nMatchPrecision++ ) + { + for (auto const& elem : rMap) + { + if( rParameter.mapsToSimilarService( elem.second, nMatchPrecision ) ) + { + //remind some values + ThreeDLookScheme aScheme = rParameter.eThreeDLookScheme; + sal_Int32 nCurveResolution = rParameter.nCurveResolution; + sal_Int32 nSplineOrder = rParameter.nSplineOrder; + CurveStyle eCurveStyle = rParameter.eCurveStyle; + sal_Int32 nGeometry3D = rParameter.nGeometry3D; + bool bSortByXValues = rParameter.bSortByXValues; + bool bRoundedEdge = rParameter.mbRoundedEdge; + + rParameter = elem.second; + + //some values should not be changed with charttype + rParameter.eThreeDLookScheme = aScheme; + rParameter.nCurveResolution = nCurveResolution; + rParameter.nSplineOrder =nSplineOrder; + rParameter.eCurveStyle = eCurveStyle; + rParameter.nGeometry3D = nGeometry3D; + rParameter.bSortByXValues = bSortByXValues; + rParameter.mbRoundedEdge = bRoundedEdge; + + bFoundSomeMatch = true; + break; + } + } + } + if(!bFoundSomeMatch) + { + if(!rMap.empty()) + rParameter = (*rMap.begin()).second; + else + rParameter = ChartTypeParameter(); + } +} +OUString ChartTypeDialogController::getServiceNameForParameter( const ChartTypeParameter& rParameter ) const +{ + ChartTypeParameter aParameter(rParameter); + if( aParameter.bXAxisWithValues ) + aParameter.eStackMode = GlobalStackMode_NONE; + if(!aParameter.b3DLook && aParameter.eStackMode==GlobalStackMode_STACK_Z) + aParameter.eStackMode = GlobalStackMode_NONE; + const tTemplateServiceChartTypeParameterMap& rMap = getTemplateMap(); + for (auto const& elem : rMap) + { + if( aParameter.mapsToSameService(elem.second) ) + return elem.first; + } + + OSL_FAIL( "ChartType not implemented yet - use fallback to similar type" ); + for( sal_Int32 nMatchPrecision=1; nMatchPrecision<8; nMatchPrecision++ ) + { + for (auto const& elem : rMap) + { + if( aParameter.mapsToSimilarService(elem.second, nMatchPrecision) ) + return elem.first; + } + } + return OUString(); +} +rtl::Reference< ChartTypeTemplate > ChartTypeDialogController::getCurrentTemplate( + const ChartTypeParameter& rParameter + , const rtl::Reference< ChartTypeManager >& xTemplateManager ) const +{ + rtl::Reference< ChartTypeTemplate > xTemplate; + + OUString aServiceName( getServiceNameForParameter( rParameter ) ); + if(!aServiceName.isEmpty()) + { + xTemplate = xTemplateManager->createTemplate( aServiceName ); + if(xTemplate.is()) + { + uno::Reference< beans::XPropertySet > xTemplateProps( static_cast<cppu::OWeakObject*>(xTemplate.get()), uno::UNO_QUERY ); + if(xTemplateProps.is()) + { + try + { + xTemplateProps->setPropertyValue( CHART_UNONAME_CURVE_STYLE , uno::Any(rParameter.eCurveStyle) ); + xTemplateProps->setPropertyValue( CHART_UNONAME_CURVE_RESOLUTION , uno::Any(rParameter.nCurveResolution) ); + xTemplateProps->setPropertyValue( CHART_UNONAME_SPLINE_ORDER , uno::Any(rParameter.nSplineOrder) ); + } + catch( uno::Exception & ex ) + { + //not all templates need to support CurveStyle, CurveResolution or SplineOrder + ex.Context.is();//to have debug information without compilation warnings + } + try + { + xTemplateProps->setPropertyValue( "Geometry3D" , uno::Any(rParameter.nGeometry3D) ); + } + catch( uno::Exception & ex ) + { + //not all templates need to support Geometry3D + ex.Context.is();//to have debug information without compilation warnings + } + + try + { + setTemplateProperties( xTemplateProps ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + return xTemplate; +} + +void ChartTypeDialogController::commitToModel( const ChartTypeParameter& rParameter + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< ::chart::ChartTypeManager > xTemplateManager = xChartModel->getTypeManager(); + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( getCurrentTemplate( rParameter, xTemplateManager ) ); + if(!xTemplate.is()) + return; + + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( xChartModel ); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + DiagramHelper::tTemplateWithServiceName aTemplateWithService( + DiagramHelper::getTemplateForDiagram( xDiagram, xTemplateManager )); + if( aTemplateWithService.xChartTypeTemplate.is()) + aTemplateWithService.xChartTypeTemplate->resetStyles2( xDiagram ); + xTemplate->changeDiagram( xDiagram ); + if( AllSettings::GetMathLayoutRTL() ) + AxisHelper::setRTLAxisLayout( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ) ); + if( rParameter.b3DLook ) + ThreeDHelper::setScheme( xDiagram, rParameter.eThreeDLookScheme ); + + if (xDiagram.is()) + { + xDiagram->setPropertyValue(CHART_UNONAME_SORT_BY_XVALUES, uno::Any(rParameter.bSortByXValues)); + } +} +void ChartTypeDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ ) +{ + rSubTypeList.Clear(); +} +bool ChartTypeDialogController::shouldShow_3DLookControl() const +{ + return false; +} +bool ChartTypeDialogController::shouldShow_StackingControl() const +{ + return false; +} +bool ChartTypeDialogController::shouldShow_SplineControl() const +{ + return false; +} +bool ChartTypeDialogController::shouldShow_GeometryControl() const +{ + return false; +} +bool ChartTypeDialogController::shouldShow_SortByXValuesResourceGroup() const +{ + return false; +} + +void ChartTypeDialogController::showExtraControls(weld::Builder* /*pBuilder*/) +{ +} +void ChartTypeDialogController::hideExtraControls() const +{ +} +void ChartTypeDialogController::fillExtraControls( const rtl::Reference<::chart::ChartModel>& /*xChartModel*/ + , const uno::Reference< beans::XPropertySet >& /*xTemplateProps*/ ) const +{ +} +void ChartTypeDialogController::setTemplateProperties( const uno::Reference< beans::XPropertySet >& /*xTemplateProps*/ ) const +{ +} + +ColumnOrBarChartDialogController_Base::ColumnOrBarChartDialogController_Base() +{ +} +ColumnOrBarChartDialogController_Base::~ColumnOrBarChartDialogController_Base() +{ +} +bool ColumnOrBarChartDialogController_Base::shouldShow_3DLookControl() const +{ + return true; +} +bool ColumnOrBarChartDialogController_Base::shouldShow_GeometryControl() const +{ + return true; +} +void ColumnOrBarChartDialogController_Base::adjustSubTypeAndEnableControls( ChartTypeParameter& rParameter ) +{ + if(rParameter.nSubTypeIndex>3 && !rParameter.b3DLook) + { + rParameter.nSubTypeIndex=1; + } +} +ColumnChartDialogController::ColumnChartDialogController() +{ +} +ColumnChartDialogController::~ColumnChartDialogController() +{ +} +OUString ColumnChartDialogController::getName() +{ + return SchResId(STR_TYPE_COLUMN); +} + +OUString ColumnChartDialogController::getImage() +{ + return BMP_TYPE_COLUMN; +} + +const tTemplateServiceChartTypeParameterMap& ColumnChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Column" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.StackedColumn" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedColumn" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.ThreeDColumnFlat" , ChartTypeParameter(1,false,true,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.StackedThreeDColumnFlat" , ChartTypeParameter(2,false,true,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedThreeDColumnFlat" , ChartTypeParameter(3,false,true,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.ThreeDColumnDeep" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Z)}}; + return s_aTemplateMap; +} +void ColumnChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.b3DLook ) + { + switch(rParameter.nGeometry3D) + { + case DataPointGeometry3D::CYLINDER: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_SAEULE_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_SAEULE_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_SAEULE_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_SAEULE_3D_4)); + break; + case DataPointGeometry3D::CONE: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_KEGEL_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_KEGEL_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_KEGEL_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_KEGEL_3D_4)); + break; + case DataPointGeometry3D::PYRAMID: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_PYRAMID_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_PYRAMID_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_PYRAMID_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_PYRAMID_3D_4)); + break; + default: //DataPointGeometry3D::CUBOID: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_COLUMNS_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_COLUMNS_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_COLUMNS_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_COLUMNS_3D)); + break; + } + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_COLUMNS_2D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_COLUMNS_2D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_COLUMNS_2D_3)); + } + + rSubTypeList.SetItemText( 1, SchResId( STR_NORMAL ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_STACKED ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_PERCENT ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_DEEP ) ); +} + +BarChartDialogController::BarChartDialogController() +{ +} + +BarChartDialogController::~BarChartDialogController() +{ +} + +OUString BarChartDialogController::getName() +{ + return SchResId(STR_TYPE_BAR); +} + +OUString BarChartDialogController::getImage() +{ + return BMP_TYPE_BAR; +} + +const tTemplateServiceChartTypeParameterMap& BarChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Bar" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.StackedBar" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedBar" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.ThreeDBarFlat" , ChartTypeParameter(1,false,true,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.StackedThreeDBarFlat" , ChartTypeParameter(2,false,true,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedThreeDBarFlat" , ChartTypeParameter(3,false,true,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.ThreeDBarDeep" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Z)}}; + return s_aTemplateMap; +} +void BarChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.b3DLook ) + { + switch(rParameter.nGeometry3D) + { + case DataPointGeometry3D::CYLINDER: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_ROEHRE_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_ROEHRE_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_ROEHRE_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_ROEHRE_3D_4)); + break; + case DataPointGeometry3D::CONE: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_KEGELQ_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_KEGELQ_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_KEGELQ_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_KEGELQ_3D_4)); + break; + case DataPointGeometry3D::PYRAMID: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_PYRAMIDQ_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_PYRAMIDQ_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_PYRAMIDQ_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_PYRAMIDQ_3D_4)); + break; + default: //DataPointGeometry3D::CUBOID: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_BARS_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_BARS_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_BARS_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_BARS_3D)); + break; + } + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_BARS_2D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_BARS_2D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_BARS_2D_3)); + } + rSubTypeList.SetItemText( 1, SchResId( STR_NORMAL ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_STACKED ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_PERCENT ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_DEEP ) ); +} + +PieChartDialogController::PieChartDialogController() +{ +} + +PieChartDialogController::~PieChartDialogController() +{ +} + +OUString PieChartDialogController::getName() +{ + return SchResId(STR_TYPE_PIE); +} + +OUString PieChartDialogController::getImage() +{ + return BMP_TYPE_PIE; +} + +const tTemplateServiceChartTypeParameterMap& PieChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Pie" , ChartTypeParameter(1,false,false)}, + {"com.sun.star.chart2.template.PieAllExploded" , ChartTypeParameter(2,false,false)}, + {"com.sun.star.chart2.template.Donut" , ChartTypeParameter(3,false,false)}, + {"com.sun.star.chart2.template.DonutAllExploded" , ChartTypeParameter(4,false,false)}, + {"com.sun.star.chart2.template.ThreeDPie" , ChartTypeParameter(1,false,true)}, + {"com.sun.star.chart2.template.ThreeDPieAllExploded" , ChartTypeParameter(2,false,true)}, + {"com.sun.star.chart2.template.ThreeDDonut" , ChartTypeParameter(3,false,true)}, + {"com.sun.star.chart2.template.ThreeDDonutAllExploded" , ChartTypeParameter(4,false,true)}}; + return s_aTemplateMap; +} +void PieChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.b3DLook ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_CIRCLES_3D)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_CIRCLES_3D_EXPLODED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_DONUT_3D)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_DONUT_3D_EXPLODED)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_CIRCLES_2D)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_CIRCLES_2D_EXPLODED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_DONUT_2D)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_DONUT_2D_EXPLODED)); + } + rSubTypeList.SetItemText( 1, SchResId( STR_NORMAL ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_PIE_EXPLODED ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_DONUT ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_DONUT_EXPLODED ) ); +} + +bool PieChartDialogController::shouldShow_3DLookControl() const +{ + return true; +} + +void PieChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + if(rParameter.eStackMode==GlobalStackMode_STACK_Z) + rParameter.eStackMode = GlobalStackMode_NONE; +} + +LineChartDialogController::LineChartDialogController() +{ +} + +LineChartDialogController::~LineChartDialogController() +{ +} + +OUString LineChartDialogController::getName() +{ + return SchResId(STR_TYPE_LINE); +} + +OUString LineChartDialogController::getImage() +{ + return BMP_TYPE_LINE; +} + +const tTemplateServiceChartTypeParameterMap& LineChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Symbol" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE,true,false)}, + {"com.sun.star.chart2.template.StackedSymbol" , ChartTypeParameter(1,false,false,GlobalStackMode_STACK_Y,true,false)}, + {"com.sun.star.chart2.template.PercentStackedSymbol" , ChartTypeParameter(1,false,false,GlobalStackMode_STACK_Y_PERCENT,true,false)}, + {"com.sun.star.chart2.template.LineSymbol" , ChartTypeParameter(2,false,false,GlobalStackMode_NONE,true,true)}, + {"com.sun.star.chart2.template.StackedLineSymbol" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y,true,true)}, + {"com.sun.star.chart2.template.PercentStackedLineSymbol" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y_PERCENT,true,true)}, + {"com.sun.star.chart2.template.Line" , ChartTypeParameter(3,false,false,GlobalStackMode_NONE,false,true)}, + {"com.sun.star.chart2.template.StackedLine" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y,false,true)}, + {"com.sun.star.chart2.template.PercentStackedLine" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT,false,true)}, + {"com.sun.star.chart2.template.StackedThreeDLine" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Y,false,true)}, + {"com.sun.star.chart2.template.PercentStackedThreeDLine" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Y_PERCENT,false,true)}, + {"com.sun.star.chart2.template.ThreeDLineDeep" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Z,false,true)}}; + return s_aTemplateMap; +} +void LineChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + switch( rParameter.eCurveStyle ) + { + case CurveStyle_CUBIC_SPLINES: + case CurveStyle_B_SPLINES: + if( rParameter.eStackMode == GlobalStackMode_NONE || rParameter.eStackMode == GlobalStackMode_STACK_Z ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XCATEGORY)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XCATEGORY_SMOOTH)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XCATEGORY_SMOOTH)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XCATEGORY_SMOOTH)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_STACKED)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_STACKED_SMOOTH)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_STACKED_SMOOTH)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_STACKED_SMOOTH)); + } + break; + case CurveStyle_STEP_START: + case CurveStyle_STEP_END: + case CurveStyle_STEP_CENTER_X: + case CurveStyle_STEP_CENTER_Y: + if( rParameter.eStackMode == GlobalStackMode_NONE || rParameter.eStackMode == GlobalStackMode_STACK_Z ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XCATEGORY)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XCATEGORY_STEPPED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XCATEGORY_STEPPED)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XCATEGORY_STEPPED)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_STACKED)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_STACKED_STEPPED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_STACKED_STEPPED)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_STACKED_STEPPED)); + } + break; + default: // includes CurveStyle_LINES + //direct lines + if( rParameter.eStackMode == GlobalStackMode_NONE || rParameter.eStackMode == GlobalStackMode_STACK_Z ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XCATEGORY)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XCATEGORY)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XCATEGORY)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XCATEGORY)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_STACKED)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_STACKED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_STACKED)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_STACKED)); + } + } + + rSubTypeList.SetItemText( 1, SchResId( STR_POINTS_ONLY ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_POINTS_AND_LINES ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_LINES_ONLY ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_LINES_3D ) ); +} +bool LineChartDialogController::shouldShow_StackingControl() const +{ + return true; +} +bool LineChartDialogController::shouldShow_SplineControl() const +{ + return true; +} +void LineChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.bSymbols = true; + rParameter.bLines = true; + break; + case 3: + rParameter.bSymbols = false; + rParameter.bLines = true; + break; + case 4: + rParameter.bSymbols = false; + rParameter.bLines = true; + rParameter.b3DLook = true; + if( rParameter.eStackMode == GlobalStackMode_NONE ) + rParameter.eStackMode = GlobalStackMode_STACK_Z; + break; + default: + rParameter.bSymbols = true; + rParameter.bLines = false; + break; + } + + if(!rParameter.b3DLook && rParameter.eStackMode == GlobalStackMode_STACK_Z ) + rParameter.eStackMode = GlobalStackMode_NONE; +} +void LineChartDialogController::adjustParameterToMainType( ChartTypeParameter& rParameter ) +{ + if( rParameter.b3DLook && rParameter.eStackMode == GlobalStackMode_NONE ) + rParameter.eStackMode = GlobalStackMode_STACK_Z; + + ChartTypeDialogController::adjustParameterToMainType( rParameter ); +} + +XYChartDialogController::XYChartDialogController() +{ + bSupportsXAxisWithValues = true; +} + +XYChartDialogController::~XYChartDialogController() +{ +} + +OUString XYChartDialogController::getName() +{ + return SchResId(STR_TYPE_XY); +} + +OUString XYChartDialogController::getImage() +{ + return BMP_TYPE_XY; +} + +const tTemplateServiceChartTypeParameterMap& XYChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.ScatterSymbol" , ChartTypeParameter(1,true,false,GlobalStackMode_NONE,true,false)}, + {"com.sun.star.chart2.template.ScatterLineSymbol" , ChartTypeParameter(2,true,false,GlobalStackMode_NONE,true,true)}, + {"com.sun.star.chart2.template.ScatterLine" , ChartTypeParameter(3,true,false,GlobalStackMode_NONE,false,true)}, + {"com.sun.star.chart2.template.ThreeDScatter" , ChartTypeParameter(4,true,true,GlobalStackMode_NONE,false,true)}}; + return s_aTemplateMap; +} + +void XYChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + switch (rParameter.eCurveStyle) + { + case CurveStyle_CUBIC_SPLINES: + case CurveStyle_B_SPLINES: + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XVALUES)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XVALUES_SMOOTH)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XVALUES_SMOOTH)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XVALUES_SMOOTH)); + break; + } + case CurveStyle_STEP_START: + case CurveStyle_STEP_END: + case CurveStyle_STEP_CENTER_X: + case CurveStyle_STEP_CENTER_Y: + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XVALUES)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XVALUES_STEPPED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XVALUES_STEPPED)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XVALUES_STEPPED)); + break; + } + default: // includes CurveStyle_LINES + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XVALUES)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XVALUES)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XVALUES)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XVALUES)); + } + + rSubTypeList.SetItemText( 1, SchResId( STR_POINTS_ONLY ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_POINTS_AND_LINES ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_LINES_ONLY ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_LINES_3D ) ); +} +bool XYChartDialogController::shouldShow_SplineControl() const +{ + return true; +} +bool XYChartDialogController::shouldShow_SortByXValuesResourceGroup() const +{ + return true; +} +void XYChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.eStackMode=GlobalStackMode_NONE; + rParameter.b3DLook = false; + rParameter.bXAxisWithValues = true; + + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.bSymbols = true; + rParameter.bLines = true; + break; + case 3: + rParameter.bSymbols = false; + rParameter.bLines = true; + break; + case 4: + rParameter.bSymbols = false; + rParameter.bLines = true; + rParameter.b3DLook = true; + rParameter.eStackMode=GlobalStackMode_STACK_Z; + break; + default: + rParameter.bSymbols = true; + rParameter.bLines = false; + break; + } +} + +AreaChartDialogController::AreaChartDialogController() +{ +} + +AreaChartDialogController::~AreaChartDialogController() +{ +} + +OUString AreaChartDialogController::getName() +{ + return SchResId(STR_TYPE_AREA); +} + +OUString AreaChartDialogController::getImage() +{ + return BMP_TYPE_AREA; +} + +bool AreaChartDialogController::shouldShow_3DLookControl() const +{ + return true; +} + +const tTemplateServiceChartTypeParameterMap& AreaChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Area" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.ThreeDArea" , ChartTypeParameter(1,false,true,GlobalStackMode_STACK_Z)}, + {"com.sun.star.chart2.template.StackedArea" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.StackedThreeDArea" , ChartTypeParameter(2,false,true,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedArea" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.PercentStackedThreeDArea" , ChartTypeParameter(3,false,true,GlobalStackMode_STACK_Y_PERCENT)}}; + return s_aTemplateMap; +} + +void AreaChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.b3DLook ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_AREAS_3D)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_AREAS_3D_1)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_AREAS_3D_2)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_AREAS_2D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_AREAS_2D)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_AREAS_2D_3)); + } + + rSubTypeList.SetItemText( 1, SchResId( rParameter.b3DLook ? STR_DEEP : STR_NORMAL ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_STACKED ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_PERCENT ) ); +} +void AreaChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.eCurveStyle = CurveStyle_LINES; + + if( rParameter.nSubTypeIndex>3 ) + rParameter.nSubTypeIndex = 1; + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.eStackMode=GlobalStackMode_STACK_Y; + break; + case 3: + rParameter.eStackMode=GlobalStackMode_STACK_Y_PERCENT; + break; + default: + if( rParameter.b3DLook ) + rParameter.eStackMode=GlobalStackMode_STACK_Z; + else + rParameter.eStackMode=GlobalStackMode_NONE; + break; + } +} +void AreaChartDialogController::adjustParameterToMainType( ChartTypeParameter& rParameter ) +{ + if( rParameter.b3DLook && rParameter.eStackMode == GlobalStackMode_NONE ) + rParameter.eStackMode = GlobalStackMode_STACK_Z; + + ChartTypeDialogController::adjustParameterToMainType( rParameter ); +} + +NetChartDialogController::NetChartDialogController() +{ + bSupports3D = false; +} + +NetChartDialogController::~NetChartDialogController() +{ +} + +OUString NetChartDialogController::getName() +{ + return SchResId(STR_TYPE_NET); +} + +OUString NetChartDialogController::getImage() +{ + return BMP_TYPE_NET; +} + +bool NetChartDialogController::shouldShow_StackingControl() const +{ + return true; +} + +const tTemplateServiceChartTypeParameterMap& NetChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + //@todo need templates with symbols only + {"com.sun.star.chart2.template.NetSymbol" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE,true,false)}, + {"com.sun.star.chart2.template.StackedNetSymbol" , ChartTypeParameter(1,false,false,GlobalStackMode_STACK_Y,true,false)}, + {"com.sun.star.chart2.template.PercentStackedNetSymbol" ,ChartTypeParameter(1,false,false,GlobalStackMode_STACK_Y_PERCENT,true,false)}, + + {"com.sun.star.chart2.template.Net" , ChartTypeParameter(2,false,false,GlobalStackMode_NONE,true,true)}, + {"com.sun.star.chart2.template.StackedNet" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y,true,true)}, + {"com.sun.star.chart2.template.PercentStackedNet" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y_PERCENT,true,true)}, + + {"com.sun.star.chart2.template.NetLine" , ChartTypeParameter(3,false,false,GlobalStackMode_NONE,false,true)}, + {"com.sun.star.chart2.template.StackedNetLine" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y,false,true)}, + {"com.sun.star.chart2.template.PercentStackedNetLine" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT,false,true)}, + + {"com.sun.star.chart2.template.FilledNet" , ChartTypeParameter(4,false,false,GlobalStackMode_NONE,false,false)}, + {"com.sun.star.chart2.template.StackedFilledNet" , ChartTypeParameter(4,false,false,GlobalStackMode_STACK_Y,false,false)}, + {"com.sun.star.chart2.template.PercentStackedFilledNet" ,ChartTypeParameter(4,false,false,GlobalStackMode_STACK_Y_PERCENT,false,false)}}; + return s_aTemplateMap; +} +void NetChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.eStackMode == GlobalStackMode_NONE ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_NET_SYMB)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_NET_LINESYMB)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_NET)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_NET_FILL)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_NET_SYMB_STACK)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_NET_LINESYMB_STACK)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_NET_STACK)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_NET_FILL_STACK)); + } + + rSubTypeList.SetItemText( 1, SchResId( STR_POINTS_ONLY ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_POINTS_AND_LINES ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_LINES_ONLY ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_FILLED ) ); +} +void NetChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + if(rParameter.eStackMode==GlobalStackMode_STACK_Z) + rParameter.eStackMode = GlobalStackMode_NONE; + + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.bSymbols = true; + rParameter.bLines = true; + break; + case 3: + rParameter.bSymbols = false; + rParameter.bLines = true; + break; + case 4: + rParameter.bSymbols = false; + rParameter.bLines = false; + break; + default: + rParameter.bSymbols = true; + rParameter.bLines = false; + break; + } +} +StockChartDialogController::StockChartDialogController() +{ + bSupports3D = false; +} + +StockChartDialogController::~StockChartDialogController() +{ +} + +OUString StockChartDialogController::getName() +{ + return SchResId(STR_TYPE_STOCK); +} + +OUString StockChartDialogController::getImage() +{ + return BMP_TYPE_STOCK; +} + +const tTemplateServiceChartTypeParameterMap& StockChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.StockLowHighClose" , ChartTypeParameter(1)}, + {"com.sun.star.chart2.template.StockOpenLowHighClose" , ChartTypeParameter(2)}, + {"com.sun.star.chart2.template.StockVolumeLowHighClose" , ChartTypeParameter(3)}, + {"com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ,ChartTypeParameter(4)}}; + return s_aTemplateMap; +} + +void StockChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ ) +{ + rSubTypeList.Clear(); + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_STOCK_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_STOCK_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_STOCK_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_STOCK_4)); + + rSubTypeList.SetItemText( 1, SchResId(STR_STOCK_1) ); + rSubTypeList.SetItemText( 2, SchResId(STR_STOCK_2) ); + rSubTypeList.SetItemText( 3, SchResId(STR_STOCK_3) ); + rSubTypeList.SetItemText( 4, SchResId(STR_STOCK_4) ); +} + +void StockChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + rParameter.eStackMode = GlobalStackMode_NONE; +} + +CombiColumnLineChartDialogController::CombiColumnLineChartDialogController() +{ + bSupports3D = false; +} + +OUString CombiColumnLineChartDialogController::getName() +{ + return SchResId(STR_TYPE_COMBI_COLUMN_LINE); +} + +OUString CombiColumnLineChartDialogController::getImage() +{ + return BMP_TYPE_COLUMN_LINE; +} + +const tTemplateServiceChartTypeParameterMap& CombiColumnLineChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.ColumnWithLine" , ChartTypeParameter(1)}, + {"com.sun.star.chart2.template.StackedColumnWithLine" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y)}}; + return s_aTemplateMap; +} + +void CombiColumnLineChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ ) +{ + rSubTypeList.Clear(); + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_COLUMN_LINE)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_COLUMN_LINE_STACKED)); + + rSubTypeList.SetItemText(1, SchResId(STR_LINE_COLUMN)); + rSubTypeList.SetItemText(2, SchResId(STR_LINE_STACKEDCOLUMN)); +} + +void CombiColumnLineChartDialogController::showExtraControls(weld::Builder* pBuilder) +{ + if (!m_xFT_NumberOfLines) + { + m_xFT_NumberOfLines = pBuilder->weld_label("nolinesft"); + } + if (!m_xMF_NumberOfLines) + { + m_xMF_NumberOfLines = pBuilder->weld_spin_button("nolines"); + + m_xMF_NumberOfLines->set_increments(1, 10); + m_xMF_NumberOfLines->set_range(1, 100); + + m_xMF_NumberOfLines->connect_value_changed( LINK( this, CombiColumnLineChartDialogController, ChangeLineCountHdl ) ); + } + + m_xFT_NumberOfLines->show(); + m_xMF_NumberOfLines->show(); +} + +void CombiColumnLineChartDialogController::hideExtraControls() const +{ + if (m_xFT_NumberOfLines) + m_xFT_NumberOfLines->hide(); + if (m_xMF_NumberOfLines) + m_xMF_NumberOfLines->hide(); +} + +void CombiColumnLineChartDialogController::fillExtraControls( + const rtl::Reference<::chart::ChartModel>& xChartModel + , const uno::Reference< beans::XPropertySet >& xTemplateProps ) const +{ + if (!m_xMF_NumberOfLines) + return; + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + if(!xDiagram.is()) + return; + + sal_Int32 nNumLines = 0; + + if(xTemplateProps.is()) + { + try + { + xTemplateProps->getPropertyValue( "NumberOfLines" ) >>= nNumLines; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + if( nNumLines < 0 ) + nNumLines = 0; + m_xMF_NumberOfLines->set_value(nNumLines); + + sal_Int32 nMaxLines = ChartModelHelper::getDataSeries( xChartModel ).size() - 1; + if( nMaxLines < 0 ) + nMaxLines = 0; + m_xMF_NumberOfLines->set_max(nMaxLines); +} +void CombiColumnLineChartDialogController::setTemplateProperties( const uno::Reference< beans::XPropertySet >& xTemplateProps ) const +{ + if( xTemplateProps.is() ) + { + sal_Int32 nNumLines = m_xMF_NumberOfLines->get_value(); + xTemplateProps->setPropertyValue( "NumberOfLines" , uno::Any(nNumLines) ); + } +} + +IMPL_LINK_NOARG(CombiColumnLineChartDialogController, ChangeLineCountHdl, weld::SpinButton&, void) +{ + if( m_pChangeListener ) + m_pChangeListener->stateChanged(); +} +void CombiColumnLineChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + if(rParameter.eStackMode==GlobalStackMode_STACK_Z) + rParameter.eStackMode = GlobalStackMode_NONE; + + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.eStackMode=GlobalStackMode_STACK_Y; + break; + default: + rParameter.eStackMode=GlobalStackMode_NONE; + break; + } +} + +BubbleChartDialogController::BubbleChartDialogController() +{ +} + +BubbleChartDialogController::~BubbleChartDialogController() +{ +} + +OUString BubbleChartDialogController::getName() +{ + return SchResId(STR_TYPE_BUBBLE); +} + +OUString BubbleChartDialogController::getImage() +{ + return BMP_TYPE_BUBBLE; +} + +const tTemplateServiceChartTypeParameterMap& BubbleChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Bubble" , ChartTypeParameter(1,true)}}; + return s_aTemplateMap; +} +void BubbleChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ ) +{ + rSubTypeList.Clear(); + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_BUBBLE_1)); + + rSubTypeList.SetItemText( 1, SchResId(STR_BUBBLE_1) ); +} +void BubbleChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + rParameter.eStackMode = GlobalStackMode_NONE; +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DataBrowser.cxx b/chart2/source/controller/dialogs/DataBrowser.cxx new file mode 100644 index 000000000..eb15e8f3d --- /dev/null +++ b/chart2/source/controller/dialogs/DataBrowser.cxx @@ -0,0 +1,1383 @@ +/* -*- 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 <svl/zforlist.hxx> + +#include "DataBrowser.hxx" +#include "DataBrowserModel.hxx" +#include <strings.hrc> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <DiagramHelper.hxx> +#include <CommonConverters.hxx> +#include <NumberFormatterWrapper.hxx> +#include <servicenames_charttypes.hxx> +#include <ResId.hxx> +#include <bitmaps.hlst> +#include <helpids.h> +#include <ChartModel.hxx> +#include <ChartType.hxx> + +#include <vcl/weld.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <svl/numformat.hxx> +#include <toolkit/helper/vclunohelper.hxx> + +#include <com/sun/star/container/XIndexReplace.hpp> + +#include <algorithm> +#include <limits> + + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +using namespace ::svt; + +namespace +{ +/* BrowserMode::COLUMNSELECTION : single cells may be selected rather than only + entire rows + BrowserMode::(H|V)LINES : show horizontal or vertical grid-lines + BrowserMode::AUTO_(H|V)SCROLL : scroll automated horizontally or vertically when + cursor is moved beyond the edge of the dialog + BrowserMode::HIDESELECT : Do not mark the current row with selection color + (usually blue) + ! BrowserMode::HIDECURSOR would prevent flickering in edit fields, but navigating + with shift up/down, and entering non-editable cells would be problematic, + e.g. the first cell, or when being in read-only mode +*/ +const BrowserMode BrowserStdFlags = BrowserMode::COLUMNSELECTION | + BrowserMode::HLINES | BrowserMode::VLINES | + BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL | + BrowserMode::HIDESELECT; + +sal_Int32 lcl_getColumnInData( sal_uInt16 nCol ) +{ + return static_cast< sal_Int32 >( nCol ) - 1; +} + +} // anonymous namespace + +namespace chart +{ + +namespace impl +{ + +class SeriesHeaderEdit +{ +public: + explicit SeriesHeaderEdit(std::unique_ptr<weld::Entry> xControl); + + void setStartColumn( sal_Int32 nStartColumn ); + sal_Int32 getStartColumn() const { return m_nStartColumn;} + void SetShowWarningBox( bool bShowWarning ); + + OUString GetText() const { return m_xControl->get_text(); } + void SetText(const OUString& rText) { m_xControl->set_text(rText); } + + bool HasFocus() const { return m_xControl->has_focus(); } + + void set_size_request(int nWidth, int nHeight) { m_xControl->set_size_request(nWidth, nHeight); } + void set_margin_start(int nLeft) { m_xControl->set_margin_start(nLeft); } + + void SetModifyHdl(const Link<SeriesHeaderEdit&,void>& rLink) { m_aModifyHdl = rLink; } + void SetGetFocusHdl(const Link<SeriesHeaderEdit&,void>& rLink) { m_aFocusInHdl = rLink; } + +private: + DECL_LINK(NameEdited, weld::Entry&, void); + DECL_LINK(NameFocusIn, weld::Widget&, void); + DECL_LINK(MousePressHdl, const MouseEvent&, bool); + + std::unique_ptr<weld::Entry> m_xControl; + Link<SeriesHeaderEdit&,void> m_aModifyHdl; + Link<SeriesHeaderEdit&,void> m_aFocusInHdl; + sal_Int32 m_nStartColumn; + bool m_bShowWarningBox; +}; + +SeriesHeaderEdit::SeriesHeaderEdit(std::unique_ptr<weld::Entry> xControl) + : m_xControl(std::move(xControl)) + , m_nStartColumn(0) + , m_bShowWarningBox(false) +{ + m_xControl->set_help_id(HID_SCH_DATA_SERIES_LABEL); + m_xControl->connect_changed(LINK(this, SeriesHeaderEdit, NameEdited)); + m_xControl->connect_focus_in(LINK(this, SeriesHeaderEdit, NameFocusIn)); + m_xControl->connect_mouse_press(LINK(this, SeriesHeaderEdit, MousePressHdl)); +} + +IMPL_LINK_NOARG(SeriesHeaderEdit, NameEdited, weld::Entry&, void) +{ + m_aModifyHdl.Call(*this); +} + +IMPL_LINK_NOARG(SeriesHeaderEdit, NameFocusIn, weld::Widget&, void) +{ + m_aFocusInHdl.Call(*this); +} + +void SeriesHeaderEdit::setStartColumn( sal_Int32 nStartColumn ) +{ + m_nStartColumn = nStartColumn; +} + +void SeriesHeaderEdit::SetShowWarningBox( bool bShowWarning ) +{ + m_bShowWarningBox = bShowWarning; +} + +IMPL_LINK_NOARG(SeriesHeaderEdit, MousePressHdl, const MouseEvent&, bool) +{ + if (m_bShowWarningBox) + { + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xControl.get(), + VclMessageType::Warning, VclButtonsType::Ok, + SchResId(STR_INVALID_NUMBER))); + xWarn->run(); + } + + return false; +} + +class SeriesHeader +{ +public: + explicit SeriesHeader(weld::Container* pParent, weld::Container* pColorParent); + ~SeriesHeader(); + + void SetColor( const Color & rCol ); + void SetPos(); + void SetWidth( sal_Int32 nWidth ); + void SetChartType( const rtl::Reference< ::chart::ChartType > & xChartType, + bool bSwapXAndYAxis ); + void SetSeriesName( const OUString & rName ); + void SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol ); + + void SetPixelWidth( sal_Int32 nWidth ); + + sal_Int32 GetStartColumn() const { return m_nStartCol;} + sal_Int32 GetEndColumn() const { return m_nEndCol;} + + static const sal_Int32 nSymbolHeight = 10; + static const sal_Int32 nSymbolDistance = 2; + + static sal_Int32 GetRelativeAppFontXPosForNameField() { return nSymbolHeight + nSymbolDistance; } + + void Show(); + void Hide(); + + /** call this before destroying the class. This notifies the listeners to + changes of the edit field for the series name. + */ + void applyChanges(); + + void SetGetFocusHdl(const Link<SeriesHeaderEdit&,void>& rLink); + + void SetEditChangedHdl( const Link<SeriesHeaderEdit&,void> & rLink ); + + bool HasFocus() const; + +private: + Timer m_aUpdateDataTimer; + + std::unique_ptr<weld::Builder> m_xBuilder1; + std::unique_ptr<weld::Builder> m_xBuilder2; + + weld::Container* m_pParent; + weld::Container* m_pColorParent; + + std::unique_ptr<weld::Container> m_xContainer1; + std::unique_ptr<weld::Container> m_xContainer2; + std::unique_ptr<weld::Image> m_spSymbol; + std::unique_ptr<SeriesHeaderEdit> m_spSeriesName; + std::unique_ptr<weld::Image> m_spColorBar; + VclPtr< OutputDevice> m_xDevice; + Link<SeriesHeaderEdit&,void> m_aChangeLink; + Color m_aColor; + + void notifyChanges(); + DECL_LINK( ImplUpdateDataHdl, Timer*, void ); + DECL_LINK( SeriesNameEdited, SeriesHeaderEdit&, void ); + + static OUString GetChartTypeImage( + const rtl::Reference< ::chart::ChartType > & xChartType, + bool bSwapXAndYAxis + ); + + sal_Int32 m_nStartCol, m_nEndCol; + sal_Int32 m_nWidth; + bool m_bSeriesNameChangePending; +}; + +SeriesHeader::SeriesHeader(weld::Container* pParent, weld::Container* pColorParent) + : m_aUpdateDataTimer( "SeriesHeader UpdateDataTimer" ) + , m_xBuilder1(Application::CreateBuilder(pParent, "modules/schart/ui/columnfragment.ui")) + , m_xBuilder2(Application::CreateBuilder(pColorParent, "modules/schart/ui/imagefragment.ui")) + , m_pParent(pParent) + , m_pColorParent(pColorParent) + , m_xContainer1(m_xBuilder1->weld_container("container")) + , m_xContainer2(m_xBuilder2->weld_container("container")) + , m_spSymbol(m_xBuilder1->weld_image("image")) + , m_spSeriesName(new SeriesHeaderEdit(m_xBuilder1->weld_entry("entry"))) + , m_spColorBar(m_xBuilder2->weld_image("image")) + , m_xDevice(Application::GetDefaultDevice()) + , m_nStartCol( 0 ) + , m_nEndCol( 0 ) + , m_nWidth( 42 ) + , m_bSeriesNameChangePending( false ) +{ + m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SeriesHeader, ImplUpdateDataHdl)); + m_aUpdateDataTimer.SetTimeout(4 * EDIT_UPDATEDATA_TIMEOUT); + + m_spSeriesName->SetModifyHdl(LINK(this, SeriesHeader, SeriesNameEdited)); + Show(); +} + +SeriesHeader::~SeriesHeader() +{ + m_aUpdateDataTimer.Stop(); + m_pParent->move(m_xContainer1.get(), nullptr); + m_pColorParent->move(m_xContainer2.get(), nullptr); +} + +void SeriesHeader::notifyChanges() +{ + m_aChangeLink.Call(*m_spSeriesName); + m_bSeriesNameChangePending = false; +} + +void SeriesHeader::applyChanges() +{ + if( m_bSeriesNameChangePending ) + { + notifyChanges(); + } +} + +void SeriesHeader::SetColor( const Color & rCol ) +{ + m_aColor = rCol; +} + +void SeriesHeader::SetPos() +{ + // chart type symbol + Size aSize( nSymbolHeight, nSymbolHeight ); + aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont)); + m_spSymbol->set_size_request(aSize.Width(), aSize.Height()); + + // series name edit field + m_spSeriesName->set_margin_start(2); + + aSize.setWidth(nSymbolHeight); + aSize.setHeight(12); + aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont)); + aSize.setWidth(m_nWidth - aSize.Width() - 2); + m_spSeriesName->set_size_request(aSize.Width(), aSize.Height()); + + // color bar + aSize.setHeight(3); + aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont)); + aSize.setWidth(m_nWidth); + m_spColorBar->set_size_request(aSize.Width(), aSize.Height()); + + ScopedVclPtr<VirtualDevice> xVirDev(m_spColorBar->create_virtual_device()); + xVirDev->SetOutputSizePixel(aSize); + xVirDev->SetFillColor(m_aColor); + xVirDev->SetLineColor(m_aColor); + xVirDev->DrawRect(tools::Rectangle(Point(0, 0), aSize)); + m_spColorBar->set_image(xVirDev.get()); +} + +void SeriesHeader::SetWidth( sal_Int32 nWidth ) +{ + m_nWidth = nWidth; + SetPos(); +} + +void SeriesHeader::SetPixelWidth( sal_Int32 nWidth ) +{ + SetWidth(nWidth); +} + +void SeriesHeader::SetChartType( + const rtl::Reference< ChartType > & xChartType, + bool bSwapXAndYAxis +) +{ + m_spSymbol->set_from_icon_name( GetChartTypeImage( xChartType, bSwapXAndYAxis ) ); +} + +void SeriesHeader::SetSeriesName( const OUString & rName ) +{ + m_spSeriesName->SetText(rName); +} + +void SeriesHeader::SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol ) +{ + m_nStartCol = nStartCol; + m_nEndCol = std::max(nEndCol, nStartCol); + m_spSeriesName->setStartColumn( nStartCol ); +} + +void SeriesHeader::Show() +{ + m_xContainer1->show(); + m_xContainer2->show(); +} + +void SeriesHeader::Hide() +{ + m_xContainer1->hide(); + m_xContainer2->hide(); +} + +void SeriesHeader::SetEditChangedHdl( const Link<SeriesHeaderEdit&,void> & rLink ) +{ + m_aChangeLink = rLink; +} + +IMPL_LINK_NOARG(SeriesHeader, ImplUpdateDataHdl, Timer*, void) +{ + notifyChanges(); +} + +IMPL_LINK_NOARG(SeriesHeader, SeriesNameEdited, SeriesHeaderEdit&, void) +{ + m_bSeriesNameChangePending = true; + m_aUpdateDataTimer.Start(); +} + +void SeriesHeader::SetGetFocusHdl( const Link<SeriesHeaderEdit&,void>& rLink ) +{ + m_spSeriesName->SetGetFocusHdl( rLink ); +} + +bool SeriesHeader::HasFocus() const +{ + return m_spSeriesName->HasFocus(); +} + +OUString SeriesHeader::GetChartTypeImage( + const rtl::Reference< ChartType > & xChartType, + bool bSwapXAndYAxis +) +{ + OUString aResult; + if( !xChartType.is()) + return aResult; + OUString aChartTypeName( xChartType->getChartType()); + + if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_AREA ) + { + aResult = BMP_TYPE_AREA; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) + { + if( bSwapXAndYAxis ) + aResult = BMP_TYPE_BAR; + else + aResult = BMP_TYPE_COLUMN; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_LINE ) + { + aResult = BMP_TYPE_LINE; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_SCATTER ) + { + aResult = BMP_TYPE_XY; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + { + aResult = BMP_TYPE_PIE; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_NET + || aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET ) + { + aResult = BMP_TYPE_NET; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + // @todo: correct image for candle-stick type + aResult = BMP_TYPE_STOCK; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE ) + { + aResult = BMP_TYPE_BUBBLE; + } + + return aResult; +} + +} // namespace impl + +namespace +{ + +/** returns false, if no header as the focus. + + If a header has the focus, true is returned and the index of the header + with focus is set at pIndex if pOutIndex is not 0. +*/ +bool lcl_SeriesHeaderHasFocus( + const std::vector< std::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader, + sal_Int32 * pOutIndex = nullptr ) +{ + sal_Int32 nIndex = 0; + for (auto const& elem : rSeriesHeader) + { + if(elem->HasFocus()) + { + if( pOutIndex ) + *pOutIndex = nIndex; + return true; + } + ++nIndex; + } + return false; +} + +sal_Int32 lcl_getColumnInDataOrHeader( + sal_uInt16 nCol, const std::vector< std::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader ) +{ + sal_Int32 nColIdx = 0; + bool bHeaderHasFocus( lcl_SeriesHeaderHasFocus( rSeriesHeader, &nColIdx )); + + if( bHeaderHasFocus ) + nColIdx = lcl_getColumnInData( static_cast< sal_uInt16 >( rSeriesHeader[nColIdx]->GetStartColumn())); + else + nColIdx = lcl_getColumnInData( nCol ); + + return nColIdx; +} + +} // anonymous namespace + +DataBrowser::DataBrowser(const css::uno::Reference<css::awt::XWindow> &rParent, + weld::Container* pColumns, weld::Container* pColors) : + ::svt::EditBrowseBox(VCLUnoHelper::GetWindow(rParent), + EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::HANDLE_COLUMN_TEXT, + WB_BORDER | WB_TABSTOP, BrowserStdFlags ), + m_nSeekRow( 0 ), + m_bIsReadOnly( false ), + m_bDataValid( true ), + m_aNumberEditField(VclPtr<FormattedControl>::Create(&EditBrowseBox::GetDataWindow(), false)), + m_aTextEditField(VclPtr<EditControl>::Create(&EditBrowseBox::GetDataWindow())), + m_pColumnsWin(pColumns), + m_pColorsWin(pColors), + m_rNumberEditController( new ::svt::FormattedFieldCellController( m_aNumberEditField.get() )), + m_rTextEditController( new ::svt::EditCellController( m_aTextEditField.get() )) +{ + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + rFormatter.SetDefaultValue( std::numeric_limits<double>::quiet_NaN() ); + rFormatter.TreatAsNumber( true ); + RenewTable(); +} + +DataBrowser::~DataBrowser() +{ + disposeOnce(); +} + +void DataBrowser::dispose() +{ + m_aSeriesHeaders.clear(); + m_aNumberEditField.disposeAndClear(); + m_aTextEditField.disposeAndClear(); + ::svt::EditBrowseBox::dispose(); +} + +bool DataBrowser::MayInsertRow() const +{ + return ! IsReadOnly() + && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )); +} + +bool DataBrowser::MayInsertColumn() const +{ + return ! IsReadOnly(); +} + +bool DataBrowser::MayDeleteRow() const +{ + return ! IsReadOnly() + && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )) + && ( GetCurRow() >= 0 ) + && ( GetRowCount() > 1 ); +} + +bool DataBrowser::MayDeleteColumn() const +{ + // if a series header has the focus + if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )) + return true; + + return ! IsReadOnly() + && ( GetCurColumnId() > 1 ) + && ( ColCount() > 2 ); +} + +bool DataBrowser::MayMoveUpRows() const +{ + return ! IsReadOnly() + && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )) + && ( GetCurRow() > 0 ) + && ( GetCurRow() <= GetRowCount() - 1 ); +} + +bool DataBrowser::MayMoveDownRows() const +{ + return ! IsReadOnly() + && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )) + && ( GetCurRow() >= 0 ) + && ( GetCurRow() < GetRowCount() - 1 ); +} + +bool DataBrowser::MayMoveLeftColumns() const +{ + // if a series header (except the last one) has the focus + { + sal_Int32 nColIndex(0); + if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex )) + return (o3tl::make_unsigned( nColIndex ) <= (m_aSeriesHeaders.size() - 1)) && (static_cast< sal_uInt32 >( nColIndex ) != 0); + } + + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + return ! IsReadOnly() + && ( nColIdx > 1 ) + && ( nColIdx <= ColCount() - 2 ) + && m_apDataBrowserModel + && !m_apDataBrowserModel->isCategoriesColumn( nColIdx ); +} + +bool DataBrowser::MayMoveRightColumns() const +{ + // if a series header (except the last one) has the focus + { + sal_Int32 nColIndex(0); + if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex )) + return (o3tl::make_unsigned( nColIndex ) < (m_aSeriesHeaders.size() - 1)); + } + + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + return ! IsReadOnly() + && ( nColIdx > 0 ) + && ( nColIdx < ColCount()-2 ) + && m_apDataBrowserModel + && !m_apDataBrowserModel->isCategoriesColumn( nColIdx ); +} + +void DataBrowser::clearHeaders() +{ + for( const auto& spHeader : m_aSeriesHeaders ) + spHeader->applyChanges(); + m_aSeriesHeaders.clear(); +} + +void DataBrowser::RenewTable() +{ + if (!m_apDataBrowserModel) + return; + + sal_Int32 nOldRow = GetCurRow(); + sal_uInt16 nOldColId = GetCurColumnId(); + + bool bLastUpdateMode = GetUpdateMode(); + SetUpdateMode( false ); + + if( IsModified() ) + SaveModified(); + + DeactivateCell(); + + RemoveColumns(); + RowRemoved( 1, GetRowCount() ); + + // for row numbers + InsertHandleColumn( static_cast< sal_uInt16 >( + GetDataWindow().LogicToPixel( Size( 42, 0 )).getWidth() )); + + OUString aDefaultSeriesName(SchResId(STR_COLUMN_LABEL)); + replaceParamterInString( aDefaultSeriesName, "%COLUMNNUMBER", OUString::number( 24 ) ); + sal_Int32 nColumnWidth = GetDataWindow().GetTextWidth( aDefaultSeriesName ) + + GetDataWindow().LogicToPixel(Point(8 + impl::SeriesHeader::GetRelativeAppFontXPosForNameField(), 0), MapMode(MapUnit::MapAppFont)).X(); + sal_Int32 nColumnCount = m_apDataBrowserModel->getColumnCount(); + // nRowCount is a member of a base class + sal_Int32 nRowCountLocal = m_apDataBrowserModel->getMaxRowCount(); + for( sal_Int32 nColIdx=1; nColIdx<=nColumnCount; ++nColIdx ) + { + InsertDataColumn( static_cast< sal_uInt16 >( nColIdx ), GetColString( nColIdx ), nColumnWidth ); + } + + RowInserted( 1, nRowCountLocal ); + GoToRow( std::min( nOldRow, GetRowCount() - 1 )); + GoToColumnId( std::min( nOldColId, static_cast< sal_uInt16 >( ColCount() - 1 ))); + + // fill series headers + clearHeaders(); + const DataBrowserModel::tDataHeaderVector& aHeaders( m_apDataBrowserModel->getDataHeaders()); + Link<impl::SeriesHeaderEdit&,void> aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus )); + Link<impl::SeriesHeaderEdit&,void> aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged )); + + for (auto const& elemHeader : aHeaders) + { + auto spHeader = std::make_shared<impl::SeriesHeader>( m_pColumnsWin, m_pColorsWin ); + Color nColor; + // @todo: Set "DraftColor", i.e. interpolated colors for gradients, bitmaps, etc. + if( elemHeader.m_xDataSeries.is() && + ( elemHeader.m_xDataSeries->getPropertyValue( "Color" ) >>= nColor )) + spHeader->SetColor( nColor ); + spHeader->SetChartType( elemHeader.m_xChartType, elemHeader.m_bSwapXAndYAxis ); + spHeader->SetSeriesName( + DataSeriesHelper::getDataSeriesLabel( + elemHeader.m_xDataSeries, + (elemHeader.m_xChartType.is() ? + elemHeader.m_xChartType->getRoleOfSequenceForSeriesLabel() : + OUString("values-y")))); + // index is 1-based, as 0 is for the column that contains the row-numbers + spHeader->SetRange( elemHeader.m_nStartColumn + 1, elemHeader.m_nEndColumn + 1 ); + spHeader->SetGetFocusHdl( aFocusLink ); + spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink ); + m_aSeriesHeaders.push_back( spHeader ); + } + + ImplAdjustHeaderControls(); + SetUpdateMode( bLastUpdateMode ); + ActivateCell(); + Invalidate(); +} + +OUString DataBrowser::GetColString( sal_Int32 nColumnId ) const +{ + OSL_ASSERT(m_apDataBrowserModel); + if( nColumnId > 0 ) + return m_apDataBrowserModel->getRoleOfColumn( nColumnId - 1 ); + return OUString(); +} + +OUString DataBrowser::GetCellText( sal_Int32 nRow, sal_uInt16 nColumnId ) const +{ + OUString aResult; + + if( nColumnId == 0 ) + { + aResult = OUString::number(nRow + 1); + } + else if( nRow >= 0 && m_apDataBrowserModel) + { + sal_Int32 nColIndex = static_cast< sal_Int32 >( nColumnId ) - 1; + + if( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::NUMBER ) + { + double fData( m_apDataBrowserModel->getCellNumber( nColIndex, nRow )); + + if( ! std::isnan( fData ) && + m_spNumberFormatterWrapper ) + { + bool bColorChanged = false; + Color nLabelColor; + aResult = m_spNumberFormatterWrapper->getFormattedString( + GetNumberFormatKey( nColumnId ), + fData, nLabelColor, bColorChanged ); + } + } + else if( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::TEXTORDATE ) + { + uno::Any aAny = m_apDataBrowserModel->getCellAny( nColIndex, nRow ); + OUString aText; + double fDouble=0.0; + if( aAny>>=aText ) + aResult = aText; + else if( aAny>>=fDouble ) + { + if( ! std::isnan( fDouble ) && m_spNumberFormatterWrapper ) + { + // If a numberformat was available here we could directly + // obtain the corresponding edit format in + // getDateTimeInputNumberFormat() instead of doing the + // guess work. + sal_Int32 nNumberFormat = DiagramHelper::getDateTimeInputNumberFormat( + m_xChartDoc, fDouble ); + Color nLabelColor; + bool bColorChanged = false; + aResult = m_spNumberFormatterWrapper->getFormattedString( + nNumberFormat, fDouble, nLabelColor, bColorChanged ); + } + } + } + else + { + OSL_ASSERT( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::TEXT ); + aResult = m_apDataBrowserModel->getCellText( nColIndex, nRow ); + } + } + + return aResult; +} + +double DataBrowser::GetCellNumber( sal_Int32 nRow, sal_uInt16 nColumnId ) const +{ + if(( nColumnId >= 1 ) && ( nRow >= 0 ) && m_apDataBrowserModel) + { + return m_apDataBrowserModel->getCellNumber( + static_cast< sal_Int32 >( nColumnId ) - 1, nRow ); + } + + return std::numeric_limits<double>::quiet_NaN(); +} + +void DataBrowser::Resize() +{ + bool bLastUpdateMode = GetUpdateMode(); + SetUpdateMode( false ); + + ::svt::EditBrowseBox::Resize(); + ImplAdjustHeaderControls(); + SetUpdateMode( bLastUpdateMode ); +} + +void DataBrowser::SetReadOnly( bool bNewState ) +{ + if( m_bIsReadOnly != bNewState ) + { + m_bIsReadOnly = bNewState; + Invalidate(); + DeactivateCell(); + } +} + +void DataBrowser::CursorMoved() +{ + EditBrowseBox::CursorMoved(); + + if( GetUpdateMode() ) + m_aCursorMovedHdlLink.Call( this ); +} + +void DataBrowser::MouseButtonDown( const BrowserMouseEvent& rEvt ) +{ + if( !m_bDataValid ) + ShowWarningBox(); + else + EditBrowseBox::MouseButtonDown( rEvt ); +} + +void DataBrowser::ShowWarningBox() +{ + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + SchResId(STR_INVALID_NUMBER))); + xWarn->run(); +} + +bool DataBrowser::ShowQueryBox() +{ + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + SchResId(STR_DATA_EDITOR_INCORRECT_INPUT))); + return xQueryBox->run() == RET_YES; +} + +bool DataBrowser::IsDataValid() const +{ + bool bValid = true; + const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId()); + + if( m_apDataBrowserModel->getCellType( nCol ) == DataBrowserModel::NUMBER ) + { + sal_uInt32 nDummy = 0; + double fDummy = 0.0; + OUString aText(m_aNumberEditField->get_widget().get_text()); + + if( !aText.isEmpty() && + m_spNumberFormatterWrapper && + m_spNumberFormatterWrapper->getSvNumberFormatter() && + ! m_spNumberFormatterWrapper->getSvNumberFormatter()->IsNumberFormat( + aText, nDummy, fDummy )) + { + bValid = false; + } + } + + return bValid; +} + +void DataBrowser::CellModified() +{ + m_bDataValid = IsDataValid(); + m_aCursorMovedHdlLink.Call( this ); +} + +void DataBrowser::SetDataFromModel( + const rtl::Reference<::chart::ChartModel> & xChartDoc ) +{ + m_xChartDoc = xChartDoc; + + m_apDataBrowserModel.reset( new DataBrowserModel( m_xChartDoc )); + m_spNumberFormatterWrapper = + std::make_shared<NumberFormatterWrapper>(m_xChartDoc); + + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + rFormatter.SetFormatter( m_spNumberFormatterWrapper->getSvNumberFormatter() ); + + RenewTable(); + + const sal_Int32 nColCnt = m_apDataBrowserModel->getColumnCount(); + const sal_Int32 nRowCnt = m_apDataBrowserModel->getMaxRowCount(); + if( nRowCnt && nColCnt ) + { + GoToRow( 0 ); + GoToColumnId( 1 ); + } +} + +void DataBrowser::InsertColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( nColIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->insertDataSeries( nColIdx ); + RenewTable(); + } +} + +void DataBrowser::InsertTextColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( nColIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->insertComplexCategoryLevel( nColIdx ); + RenewTable(); + } +} + +void DataBrowser::RemoveColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( nColIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_bDataValid = true; + m_apDataBrowserModel->removeDataSeriesOrComplexCategoryLevel( nColIdx ); + RenewTable(); + } +} + +void DataBrowser::InsertRow() +{ + sal_Int32 nRowIdx = GetCurRow(); + + if( nRowIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->insertDataPointForAllSeries( nRowIdx ); + RenewTable(); + } +} + +void DataBrowser::RemoveRow() +{ + sal_Int32 nRowIdx = GetCurRow(); + + if( nRowIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_bDataValid = true; + m_apDataBrowserModel->removeDataPointForAllSeries( nRowIdx ); + RenewTable(); + } +} + +void DataBrowser::MoveLeftColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( !(nColIdx > 0 && m_apDataBrowserModel)) + return; + + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->swapDataSeries( nColIdx - 1 ); + + // keep cursor in swapped column + if(( 0 < GetCurColumnId() ) && ( GetCurColumnId() <= ColCount() - 1 )) + { + Dispatch( BROWSER_CURSORLEFT ); + } + RenewTable(); +} + +void DataBrowser::MoveRightColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( !(nColIdx >= 0 && m_apDataBrowserModel)) + return; + + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->swapDataSeries( nColIdx ); + + // keep cursor in swapped column + if( GetCurColumnId() < ColCount() - 1 ) + { + Dispatch( BROWSER_CURSORRIGHT ); + } + RenewTable(); +} + +void DataBrowser::MoveUpRow() +{ + sal_Int32 nRowIdx = GetCurRow(); + + if( !(nRowIdx > 0 && m_apDataBrowserModel)) + return; + + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx - 1 ); + + // keep cursor in swapped row + if(( 0 < GetCurRow() ) && ( GetCurRow() <= GetRowCount() - 1 )) + { + Dispatch( BROWSER_CURSORUP ); + } + RenewTable(); +} + +void DataBrowser::MoveDownRow() +{ + sal_Int32 nRowIdx = GetCurRow(); + + if( !(nRowIdx >= 0 && m_apDataBrowserModel)) + return; + + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx ); + + // keep cursor in swapped row + if( GetCurRow() < GetRowCount() - 1 ) + { + Dispatch( BROWSER_CURSORDOWN ); + } + RenewTable(); +} + +void DataBrowser::SetCursorMovedHdl( const Link<DataBrowser*,void>& rLink ) +{ + m_aCursorMovedHdlLink = rLink; +} + +// implementations for ::svt::EditBrowseBox (pure virtual methods) +void DataBrowser::PaintCell( + OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const +{ + Point aPos( rRect.TopLeft()); + aPos.AdjustX(1 ); + + OUString aText = GetCellText( m_nSeekRow, nColumnId ); + Size TxtSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight()); + + // clipping + if( aPos.X() < rRect.Right() || aPos.X() + TxtSize.Width() > rRect.Right() || + aPos.Y() < rRect.Top() || aPos.Y() + TxtSize.Height() > rRect.Bottom()) + rDev.SetClipRegion(vcl::Region(rRect)); + + // allow for a disabled control ... + bool bEnabled = IsEnabled(); + Color aOriginalColor = rDev.GetTextColor(); + if( ! bEnabled ) + rDev.SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() ); + + // draw the text + rDev.DrawText( aPos, aText ); + + // reset the color (if necessary) + if( ! bEnabled ) + rDev.SetTextColor( aOriginalColor ); + + if( rDev.IsClipRegion()) + rDev.SetClipRegion(); +} + +bool DataBrowser::SeekRow( sal_Int32 nRow ) +{ + if( ! EditBrowseBox::SeekRow( nRow )) + return false; + + if( nRow < 0 ) + m_nSeekRow = - 1; + else + m_nSeekRow = nRow; + + return true; +} + +bool DataBrowser::IsTabAllowed( bool bForward ) const +{ + sal_Int32 nRow = GetCurRow(); + sal_Int32 nCol = GetCurColumnId(); + + // column 0 is header-column + sal_Int32 nBadCol = bForward + ? GetColumnCount() - 1 + : 1; + sal_Int32 nBadRow = bForward + ? GetRowCount() - 1 + : 0; + + if( !m_bDataValid ) + { + const_cast< DataBrowser* >( this )->ShowWarningBox(); + return false; + } + + return ( nRow != nBadRow || + nCol != nBadCol ); +} + +::svt::CellController* DataBrowser::GetController( sal_Int32 /*nRow*/, sal_uInt16 nCol ) +{ + if( m_bIsReadOnly ) + return nullptr; + + if( CellContainsNumbers( nCol )) + { + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + rFormatter.UseInputStringForFormatting(); + rFormatter.SetFormatKey( GetNumberFormatKey( nCol )); + return m_rNumberEditController.get(); + } + + return m_rTextEditController.get(); +} + +void DataBrowser::InitController( + ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) +{ + if( rController == m_rTextEditController ) + { + OUString aText( GetCellText( nRow, nCol ) ); + weld::Entry& rEntry = m_aTextEditField->get_widget(); + rEntry.set_text(aText); + rEntry.select_region(0, -1); + } + else if( rController == m_rNumberEditController ) + { + // treat invalid and empty text as Nan + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + rFormatter.EnableNotANumber( true ); + if( std::isnan( GetCellNumber( nRow, nCol ))) + rFormatter.SetTextValue( OUString()); + else + rFormatter.SetValue( GetCellNumber( nRow, nCol ) ); + weld::Entry& rEntry = m_aNumberEditField->get_widget(); + rEntry.select_region(0, -1); + } + else + { + OSL_FAIL( "Invalid Controller" ); + } +} + +bool DataBrowser::CellContainsNumbers( sal_uInt16 nCol ) const +{ + if (!m_apDataBrowserModel) + return false; + return m_apDataBrowserModel->getCellType( lcl_getColumnInData( nCol )) == DataBrowserModel::NUMBER; +} + +sal_uInt32 DataBrowser::GetNumberFormatKey( sal_uInt16 nCol ) const +{ + if (!m_apDataBrowserModel) + return 0; + return m_apDataBrowserModel->getNumberFormatKey( lcl_getColumnInData( nCol ) ); +} + +bool DataBrowser::isDateTimeString( const OUString& aInputString, double& fOutDateTimeValue ) +{ + sal_uInt32 nNumberFormat=0; + SvNumberFormatter* pSvNumberFormatter = m_spNumberFormatterWrapper ? m_spNumberFormatterWrapper->getSvNumberFormatter() : nullptr; + if( !aInputString.isEmpty() && pSvNumberFormatter && pSvNumberFormatter->IsNumberFormat( aInputString, nNumberFormat, fOutDateTimeValue ) ) + { + SvNumFormatType nType = pSvNumberFormatter->GetType( nNumberFormat); + return (nType & SvNumFormatType::DATE) || (nType & SvNumFormatType::TIME); + } + return false; +} + +bool DataBrowser::SaveModified() +{ + if( ! IsModified() ) + return true; + + bool bChangeValid = true; + + const sal_Int32 nRow = GetCurRow(); + const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId()); + + OSL_ENSURE( nRow >= 0 || nCol >= 0, "This cell should not be modified!" ); + + SvNumberFormatter* pSvNumberFormatter = m_spNumberFormatterWrapper ? m_spNumberFormatterWrapper->getSvNumberFormatter() : nullptr; + switch( m_apDataBrowserModel->getCellType( nCol )) + { + case DataBrowserModel::NUMBER: + { + sal_uInt32 nDummy = 0; + double fDummy = 0.0; + OUString aText(m_aNumberEditField->get_widget().get_text()); + // an empty string is valid, if no numberformatter exists, all + // values are treated as valid + if( !aText.isEmpty() && pSvNumberFormatter && + ! pSvNumberFormatter->IsNumberFormat( aText, nDummy, fDummy ) ) + { + bChangeValid = false; + } + else + { + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + double fData = rFormatter.GetValue(); + bChangeValid = m_apDataBrowserModel->setCellNumber( nCol, nRow, fData ); + } + } + break; + case DataBrowserModel::TEXTORDATE: + { + weld::Entry& rEntry = m_aTextEditField->get_widget(); + OUString aText(rEntry.get_text()); + double fValue = 0.0; + bChangeValid = false; + if( isDateTimeString( aText, fValue ) ) + bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::Any( fValue ) ); + if(!bChangeValid) + bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::Any( aText ) ); + } + break; + case DataBrowserModel::TEXT: + { + weld::Entry& rEntry = m_aTextEditField->get_widget(); + OUString aText(rEntry.get_text()); + bChangeValid = m_apDataBrowserModel->setCellText( nCol, nRow, aText ); + } + break; + } + + // the first valid change changes this to true + if( bChangeValid ) + { + RowModified( GetCurRow(), GetCurColumnId()); + ::svt::CellController* pCtrl = GetController( GetCurRow(), GetCurColumnId()); + if( pCtrl ) + pCtrl->SaveValue(); + } + + return bChangeValid; +} + +bool DataBrowser::EndEditing() +{ + SaveModified(); + + // apply changes made to series headers + for( const auto& spHeader : m_aSeriesHeaders ) + spHeader->applyChanges(); + + if( m_bDataValid ) + return true; + else + return ShowQueryBox(); +} + +void DataBrowser::ColumnResized( sal_uInt16 nColId ) +{ + bool bLastUpdateMode = GetUpdateMode(); + SetUpdateMode( false ); + + EditBrowseBox::ColumnResized( nColId ); + ImplAdjustHeaderControls(); + SetUpdateMode( bLastUpdateMode ); +} + +void DataBrowser::EndScroll() +{ + bool bLastUpdateMode = GetUpdateMode(); + SetUpdateMode( false ); + + EditBrowseBox::EndScroll(); + RenewSeriesHeaders(); + + SetUpdateMode( bLastUpdateMode ); +} + +void DataBrowser::RenewSeriesHeaders() +{ + clearHeaders(); + DataBrowserModel::tDataHeaderVector aHeaders( m_apDataBrowserModel->getDataHeaders()); + Link<impl::SeriesHeaderEdit&,void> aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus )); + Link<impl::SeriesHeaderEdit&,void> aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged )); + + for (auto const& elemHeader : aHeaders) + { + auto spHeader = std::make_shared<impl::SeriesHeader>( m_pColumnsWin, m_pColorsWin ); + Color nColor; + if( elemHeader.m_xDataSeries.is() && + ( elemHeader.m_xDataSeries->getPropertyValue( "Color" ) >>= nColor )) + spHeader->SetColor( nColor ); + spHeader->SetChartType( elemHeader.m_xChartType, elemHeader.m_bSwapXAndYAxis ); + spHeader->SetSeriesName( + DataSeriesHelper::getDataSeriesLabel( + elemHeader.m_xDataSeries, + (elemHeader.m_xChartType.is() ? + elemHeader.m_xChartType->getRoleOfSequenceForSeriesLabel() : + OUString( "values-y")))); + spHeader->SetRange( elemHeader.m_nStartColumn + 1, elemHeader.m_nEndColumn + 1 ); + spHeader->SetGetFocusHdl( aFocusLink ); + spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink ); + m_aSeriesHeaders.push_back( spHeader ); + } + + ImplAdjustHeaderControls(); +} + +void DataBrowser::ImplAdjustHeaderControls() +{ + sal_uInt16 nColCount = GetColumnCount(); + sal_uInt32 nCurrentPos = GetPosPixel().getX(); + sal_uInt32 nMaxPos = nCurrentPos + GetOutputSizePixel().getWidth(); + sal_uInt32 nStartPos = nCurrentPos; + + // width of header column + nCurrentPos += GetColumnWidth( 0 ); + + weld::Container* pWin = m_pColumnsWin; + weld::Container* pColorWin = m_pColorsWin; + pWin->set_margin_start(nCurrentPos); + pColorWin->set_margin_start(nCurrentPos); + + tSeriesHeaderContainer::iterator aIt( m_aSeriesHeaders.begin()); + sal_uInt16 i = GetFirstVisibleColNumber(); + while( (aIt != m_aSeriesHeaders.end()) && ((*aIt)->GetStartColumn() < i) ) + { + (*aIt)->Hide(); + ++aIt; + } + for( ; i < nColCount && aIt != m_aSeriesHeaders.end(); ++i ) + { + if( (*aIt)->GetStartColumn() == i ) + nStartPos = nCurrentPos; + + nCurrentPos += (GetColumnWidth( i )); + + if( (*aIt)->GetEndColumn() == i ) + { + if( nStartPos < nMaxPos ) + { + (*aIt)->SetPixelWidth( nCurrentPos - nStartPos ); + (*aIt)->Show(); + + if (pWin) + { + pWin->set_margin_start(nStartPos); + pColorWin->set_margin_start(nStartPos); + pWin = pColorWin = nullptr; + } + + } + else + (*aIt)->Hide(); + ++aIt; + } + } +} + +IMPL_LINK( DataBrowser, SeriesHeaderGotFocus, impl::SeriesHeaderEdit&, rEdit, void ) +{ + rEdit.SetShowWarningBox( !m_bDataValid ); + + if( !m_bDataValid ) + GoToCell( 0, 0 ); + else + { + MakeFieldVisible( GetCurRow(), static_cast< sal_uInt16 >( rEdit.getStartColumn()) ); + ActivateCell(); + m_aCursorMovedHdlLink.Call( this ); + } +} + +IMPL_LINK( DataBrowser, SeriesHeaderChanged, impl::SeriesHeaderEdit&, rEdit, void ) +{ + rtl::Reference< DataSeries > xSeries = + m_apDataBrowserModel->getDataSeriesByColumn( rEdit.getStartColumn() - 1 ); + if( !xSeries.is()) + return; + + rtl::Reference< ChartType > xChartType( + m_apDataBrowserModel->getHeaderForSeries( xSeries ).m_xChartType ); + if( xChartType.is()) + { + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq = + DataSeriesHelper::getDataSequenceByRole( xSeries, xChartType->getRoleOfSequenceForSeriesLabel()); + if( xLabeledSeq.is()) + { + Reference< container::XIndexReplace > xIndexReplace( xLabeledSeq->getLabel(), uno::UNO_QUERY ); + if( xIndexReplace.is()) + xIndexReplace->replaceByIndex( + 0, uno::Any( rEdit.GetText())); + } + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DataBrowser.hxx b/chart2/source/controller/dialogs/DataBrowser.hxx new file mode 100644 index 000000000..c1d6a72e6 --- /dev/null +++ b/chart2/source/controller/dialogs/DataBrowser.hxx @@ -0,0 +1,187 @@ +/* -*- 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 <svtools/editbrowsebox.hxx> +#include <vcl/weld.hxx> + +#include <memory> +#include <vector> + +namespace com::sun::star { + namespace awt { + class XWindow; + } + namespace chart2 { + class XChartDocument; + } +} + +namespace com::sun::star::uno { class XComponentContext; } + +class OutputDevice; + +namespace chart +{ + +class DataBrowserModel; +class NumberFormatterWrapper; +class ChartModel; + +namespace impl +{ +class SeriesHeader; +class SeriesHeaderEdit; +} + +class DataBrowser : public ::svt::EditBrowseBox +{ +protected: + // EditBrowseBox overridables + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const override; + virtual bool SeekRow( sal_Int32 nRow ) override; + virtual bool IsTabAllowed( bool bForward ) const override; + virtual ::svt::CellController* GetController( sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual void InitController( ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual bool SaveModified() override; + virtual void CursorMoved() override; + // called whenever the control of the current cell has been modified + virtual void CellModified() override; + virtual void ColumnResized( sal_uInt16 nColId ) override; + virtual void EndScroll() override; + virtual void MouseButtonDown( const BrowserMouseEvent& rEvt ) override; + +public: + DataBrowser(const css::uno::Reference<css::awt::XWindow> &rParent, + weld::Container* pColumns, weld::Container* pColors); + + virtual ~DataBrowser() override; + virtual void dispose() override; + + /** GetCellText returns the text at the given position + @param nRow + the number of the row + @param nColId + the ID of the column + @return + the text out of the cell + */ + virtual OUString GetCellText(sal_Int32 nRow, sal_uInt16 nColId) const override; + + /** returns the number in the given cell. If a cell is empty or contains a + string, the result will be Nan + */ + double GetCellNumber( sal_Int32 nRow, sal_uInt16 nColumnId ) const; + + bool isDateTimeString( const OUString& aInputString, double& fOutDateTimeValue ); + + // Window + virtual void Resize() override; + + void SetReadOnly( bool bNewState ); + bool IsReadOnly() const { return m_bIsReadOnly;} + + void SetDataFromModel( const rtl::Reference<::chart::ChartModel> & xChartDoc ); + + // predicates to determine what actions are possible at the current cursor + // position. This depends on the implementation of the according mutators + // below. (They are used for enabling toolbar icons) + bool MayInsertRow() const; + bool MayInsertColumn() const; + bool MayDeleteRow() const; + bool MayDeleteColumn() const; + + bool MayMoveUpRows() const; + bool MayMoveDownRows() const; + bool MayMoveRightColumns() const; + bool MayMoveLeftColumns() const; + + // mutators mutating data + void InsertRow(); + void InsertColumn(); + void InsertTextColumn(); + void RemoveRow(); + void RemoveColumn(); + + using BrowseBox::RemoveColumn; + using BrowseBox::MouseButtonDown; + + void MoveUpRow(); + void MoveDownRow(); + void MoveLeftColumn(); + void MoveRightColumn(); + + void SetCursorMovedHdl( const Link<DataBrowser*,void>& rLink ); + + /// confirms all pending changes to be ready to be closed + bool EndEditing(); + + bool CellContainsNumbers( sal_uInt16 nCol ) const; + + sal_uInt32 GetNumberFormatKey( sal_uInt16 nCol ) const; + + bool IsEnableItem() const { return m_bDataValid;} + bool IsDataValid() const; + void ShowWarningBox(); + bool ShowQueryBox(); + + void RenewSeriesHeaders(); + +private: + rtl::Reference<::chart::ChartModel> m_xChartDoc; + std::unique_ptr< DataBrowserModel > m_apDataBrowserModel; + + typedef std::vector< std::shared_ptr< impl::SeriesHeader > > tSeriesHeaderContainer; + tSeriesHeaderContainer m_aSeriesHeaders; + + std::shared_ptr< NumberFormatterWrapper > m_spNumberFormatterWrapper; + + /// the row that is currently painted + sal_Int32 m_nSeekRow; + bool m_bIsReadOnly; + bool m_bDataValid; + + VclPtr<svt::FormattedControl> m_aNumberEditField; + VclPtr<svt::EditControl> m_aTextEditField; + weld::Container* m_pColumnsWin; + weld::Container* m_pColorsWin; + + /// note: m_aNumberEditField must precede this member! + ::svt::CellControllerRef m_rNumberEditController; + /// note: m_aTextEditField must precede this member! + ::svt::CellControllerRef m_rTextEditController; + + Link<DataBrowser*,void> m_aCursorMovedHdlLink; + + void clearHeaders(); + void RenewTable(); + void ImplAdjustHeaderControls(); + + OUString GetColString( sal_Int32 nColumnId ) const; + + DECL_LINK( SeriesHeaderGotFocus, impl::SeriesHeaderEdit&, void ); + DECL_LINK( SeriesHeaderChanged, impl::SeriesHeaderEdit&, void ); + + DataBrowser( const DataBrowser & ) = delete; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DataBrowserModel.cxx b/chart2/source/controller/dialogs/DataBrowserModel.cxx new file mode 100644 index 000000000..11c6f19d7 --- /dev/null +++ b/chart2/source/controller/dialogs/DataBrowserModel.cxx @@ -0,0 +1,936 @@ +/* -*- 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 "DataBrowserModel.hxx" +#include "DialogModel.hxx" +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <ChartTypeManager.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <StatisticsHelper.hxx> +#include <ChartTypeHelper.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <ExplicitCategoriesProvider.hxx> +#include <BaseCoordinateSystem.hxx> +#include <ChartModel.hxx> +#include <unonames.hxx> + +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/chart2/XInternalDataProvider.hpp> +#include <com/sun/star/chart2/data/XDataSource.hpp> +#include <com/sun/star/chart2/data/XLabeledDataSequence.hpp> +#include <com/sun/star/chart2/data/XNumericalDataSequence.hpp> +#include <com/sun/star/chart2/data/XTextualDataSequence.hpp> +#include <o3tl/safeint.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/property.hxx> + +#include <algorithm> +#include <cstddef> +#include <limits> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart { + +namespace { + +OUString lcl_getRole( + const Reference< chart2::data::XDataSequence > & xSeq ) +{ + OUString aResult; + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + xProp->getPropertyValue( "Role" ) >>= aResult; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + return aResult; +} + +OUString lcl_getUIRoleName( + const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) +{ + OUString aResult = DataSeriesHelper::getRole(xLSeq); + if( !aResult.isEmpty()) + aResult = DialogModel::ConvertRoleFromInternalToUI(aResult); + return aResult; +} + +void lcl_copyDataSequenceProperties( + const Reference< chart2::data::XDataSequence > & xOldSequence, + const Reference< chart2::data::XDataSequence > & xNewSequence ) +{ + Reference< beans::XPropertySet > xOldSeqProp( xOldSequence, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xNewSeqProp( xNewSequence, uno::UNO_QUERY ); + comphelper::copyProperties( xOldSeqProp, xNewSeqProp ); +} + +bool lcl_SequenceOfSeriesIsShared( + const rtl::Reference< ::chart::DataSeries > & xSeries, + const Reference< chart2::data::XDataSequence > & xValues ) +{ + bool bResult = false; + if( !xValues.is()) + return bResult; + try + { + OUString aValuesRole( lcl_getRole( xValues )); + OUString aValuesRep( xValues->getSourceRangeRepresentation()); + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aLSeq( xSeries->getDataSequences2()); + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledDataSeq : aLSeq ) + if (labeledDataSeq.is() && DataSeriesHelper::getRole(labeledDataSeq) == aValuesRole) + { + // getValues().is(), because lcl_getRole checked that already + bResult = (aValuesRep == labeledDataSeq->getValues()->getSourceRangeRepresentation()); + // assumption: a role appears only once in a series + break; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return bResult; +} + +typedef std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > lcl_tSharedSeqVec; + +lcl_tSharedSeqVec lcl_getSharedSequences( const std::vector< rtl::Reference< DataSeries > > & rSeries ) +{ + // @todo: if only some series share a sequence, those have to be duplicated + // and made unshared for all series + lcl_tSharedSeqVec aResult; + // if we have only one series, we don't want any shared sequences + if( rSeries.size() <= 1 ) + return aResult; + + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledDataSeq : rSeries[0]->getDataSequences2() ) + { + Reference< chart2::data::XDataSequence > xValues( labeledDataSeq->getValues()); + bool bShared = true; + for( std::size_t nSeriesIdx=1; nSeriesIdx<rSeries.size(); ++nSeriesIdx ) + { + bShared = lcl_SequenceOfSeriesIsShared( rSeries[nSeriesIdx], xValues ); + if( !bShared ) + break; + } + if( bShared ) + aResult.push_back( labeledDataSeq ); + } + + return aResult; +} + +sal_Int32 lcl_getValuesRepresentationIndex( + const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) +{ + sal_Int32 nResult = -1; + if( xLSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLSeq->getValues()); + if( xSeq.is()) + { + OUString aRep( xSeq->getSourceRangeRepresentation()); + nResult = aRep.toInt32(); + } + } + return nResult; +} + +struct lcl_RepresentationsOfLSeqMatch +{ + explicit lcl_RepresentationsOfLSeqMatch( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) : + m_aValuesRep( xLSeq.is() ? + (xLSeq->getValues().is() ? xLSeq->getValues()->getSourceRangeRepresentation() : OUString()) + : OUString() ) + {} + bool operator() ( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) + { + if (!xLSeq.is() || !xLSeq->getValues().is()) + return false; + + return xLSeq->getValues()->getSourceRangeRepresentation() == m_aValuesRep; + } +private: + OUString m_aValuesRep; +}; + +struct lcl_RolesOfLSeqMatch +{ + explicit lcl_RolesOfLSeqMatch( const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq ) : + m_aRole(DataSeriesHelper::getRole(xLSeq)) {} + + bool operator() ( const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq ) + { + return DataSeriesHelper::getRole(xLSeq) == m_aRole; + } +private: + OUString m_aRole; +}; + +bool lcl_ShowCategoriesAsDataLabel( const rtl::Reference< ::chart::Diagram > & xDiagram ) +{ + return !DiagramHelper::isCategoryDiagram(xDiagram); +} + +} // anonymous namespace + +struct DataBrowserModel::tDataColumn +{ + rtl::Reference<DataSeries> m_xDataSeries; + OUString m_aUIRoleName; + uno::Reference<chart2::data::XLabeledDataSequence> m_xLabeledDataSequence; + eCellType m_eCellType; + sal_Int32 m_nNumberFormatKey; + + // default CTOR + tDataColumn() : m_eCellType( TEXT ), m_nNumberFormatKey( 0 ) {} + // "full" CTOR + tDataColumn( + const rtl::Reference<DataSeries> & xDataSeries, + const OUString& aUIRoleName, + const uno::Reference<chart2::data::XLabeledDataSequence>& xLabeledDataSequence, + eCellType aCellType, + sal_Int32 nNumberFormatKey ) : + m_xDataSeries( xDataSeries ), + m_aUIRoleName( aUIRoleName ), + m_xLabeledDataSequence( xLabeledDataSequence ), + m_eCellType( aCellType ), + m_nNumberFormatKey( nNumberFormatKey ) + {} +}; + +struct DataBrowserModel::implColumnLess +{ + bool operator() ( const DataBrowserModel::tDataColumn & rLeft, const DataBrowserModel::tDataColumn & rRight ) + { + if( rLeft.m_xLabeledDataSequence.is() && rRight.m_xLabeledDataSequence.is()) + { + return DialogModel::GetRoleIndexForSorting(DataSeriesHelper::getRole(rLeft.m_xLabeledDataSequence)) < + DialogModel::GetRoleIndexForSorting(DataSeriesHelper::getRole(rRight.m_xLabeledDataSequence)); + } + return true; + } +}; + +DataBrowserModel::DataBrowserModel( + const rtl::Reference<::chart::ChartModel> & xChartDoc ) : + m_xChartDocument( xChartDoc ), + m_apDialogModel( new DialogModel( xChartDoc )) +{ + updateFromModel(); +} + +DataBrowserModel::~DataBrowserModel() +{} + +namespace +{ +struct lcl_DataSeriesOfHeaderMatches +{ + explicit lcl_DataSeriesOfHeaderMatches( + const rtl::Reference< ::chart::DataSeries > & xSeriesToCompareWith ) : + m_xSeries( xSeriesToCompareWith ) + {} + bool operator() ( const ::chart::DataBrowserModel::tDataHeader & rHeader ) + { + return (m_xSeries == rHeader.m_xDataSeries); + } +private: + rtl::Reference< ::chart::DataSeries > m_xSeries; +}; +} + +void DataBrowserModel::insertDataSeries( sal_Int32 nAfterColumnIndex ) +{ + OSL_ASSERT(m_apDialogModel); + Reference< chart2::XInternalDataProvider > xDataProvider( + m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + + if (!xDataProvider.is()) + return; + + if( isCategoriesColumn(nAfterColumnIndex) ) + // Move to the last category column. + nAfterColumnIndex = getCategoryColumnCount()-1; + + sal_Int32 nStartCol = 0; + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(m_xChartDocument); + rtl::Reference<ChartType> xChartType; + rtl::Reference<DataSeries> xSeries; + if (o3tl::make_unsigned(nAfterColumnIndex) < m_aColumns.size()) + // Get the data series at specific column position (if available). + xSeries = m_aColumns[nAfterColumnIndex].m_xDataSeries; + + sal_Int32 nSeriesNumberFormat = 0; + if( xSeries.is()) + { + // Use the chart type of the currently selected data series. + xChartType = DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ); + + // Find the corresponding header and determine the last column of this + // data series. + tDataHeaderVector::const_iterator aIt( + std::find_if( m_aHeaders.begin(), m_aHeaders.end(), + lcl_DataSeriesOfHeaderMatches( xSeries ))); + if( aIt != m_aHeaders.end()) + nStartCol = aIt->m_nEndColumn; + + // Get the number format too. + if( xSeries.is() ) + xSeries->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nSeriesNumberFormat; + } + else + { + // No data series at specified column position. Use the first chart type. + xChartType = DiagramHelper::getChartTypeByIndex( xDiagram, 0 ); + nStartCol = nAfterColumnIndex; + } + + if (!xChartType.is()) + return; + + // Get shared sequences of current series. Normally multiple data series + // only share "values-x" sequences. (TODO: simplify this logic). + lcl_tSharedSeqVec aSharedSequences = lcl_getSharedSequences( xChartType->getDataSeries2()); + + rtl::Reference<::chart::DataSeries> xNewSeries = + m_apDialogModel->insertSeriesAfter(xSeries, xChartType, true); + + if (!xNewSeries.is()) + // Failed to insert new data series to the model. Bail out. + return; + + const std::vector<uno::Reference<chart2::data::XLabeledDataSequence> > & aLSequences = xNewSeries->getDataSequences2(); + sal_Int32 nSeqIdx = 0; + sal_Int32 nSeqSize = aLSequences.size(); + for (sal_Int32 nIndex = nStartCol; nSeqIdx < nSeqSize; ++nSeqIdx) + { + lcl_tSharedSeqVec::const_iterator aSharedIt( + std::find_if( aSharedSequences.begin(), aSharedSequences.end(), + lcl_RolesOfLSeqMatch( aLSequences[nSeqIdx] ))); + + if( aSharedIt != aSharedSequences.end()) + { + // Shared sequence. Most likely "values-x" sequence. Copy it from existing sequence. + aLSequences[nSeqIdx]->setValues( (*aSharedIt)->getValues()); + aLSequences[nSeqIdx]->setLabel( (*aSharedIt)->getLabel()); + } + else + { + // Insert a new column in the internal data for the new sequence. + xDataProvider->insertSequence( nIndex - 1 ); + + // values + Reference< chart2::data::XDataSequence > xNewSeq( + xDataProvider->createDataSequenceByRangeRepresentation( + OUString::number( nIndex ))); + lcl_copyDataSequenceProperties( + aLSequences[nSeqIdx]->getValues(), xNewSeq ); + aLSequences[nSeqIdx]->setValues( xNewSeq ); + + // labels + Reference< chart2::data::XDataSequence > xNewLabelSeq( + xDataProvider->createDataSequenceByRangeRepresentation( + "label " + + OUString::number( nIndex ))); + lcl_copyDataSequenceProperties( + aLSequences[nSeqIdx]->getLabel(), xNewLabelSeq ); + aLSequences[nSeqIdx]->setLabel( xNewLabelSeq ); + ++nIndex; + } + } + + if( nSeriesNumberFormat != 0 ) + { + //give the new series the same number format as the former series especially for bubble charts thus the bubble size values can be edited with same format immediately + xNewSeries->setPropertyValue(CHART_UNONAME_NUMFMT , uno::Any(nSeriesNumberFormat)); + } + + updateFromModel(); +} + +void DataBrowserModel::insertComplexCategoryLevel( sal_Int32 nAfterColumnIndex ) +{ + //create a new text column for complex categories + + OSL_ASSERT(m_apDialogModel); + Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + if (!xDataProvider.is()) + return; + + if( !isCategoriesColumn(nAfterColumnIndex) ) + nAfterColumnIndex = getCategoryColumnCount()-1; + + if(nAfterColumnIndex<0) + { + OSL_FAIL( "wrong index for category level insertion" ); + return; + } + + m_apDialogModel->startControllerLockTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + xDataProvider->insertComplexCategoryLevel( nAfterColumnIndex+1 ); + updateFromModel(); +} + +void DataBrowserModel::removeComplexCategoryLevel( sal_Int32 nAtColumnIndex ) +{ + //delete a category column if there is more than one level (in case of a single column we do not get here) + OSL_ENSURE(nAtColumnIndex>0, "wrong index for categories deletion" ); + + Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + if (!xDataProvider.is()) + return; + + m_apDialogModel->startControllerLockTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + xDataProvider->deleteComplexCategoryLevel( nAtColumnIndex ); + + updateFromModel(); +} + +void DataBrowserModel::removeDataSeriesOrComplexCategoryLevel( sal_Int32 nAtColumnIndex ) +{ + OSL_ASSERT(m_apDialogModel); + if (nAtColumnIndex < 0 || o3tl::make_unsigned(nAtColumnIndex) >= m_aColumns.size()) + // Out of bound. + return; + + if (isCategoriesColumn(nAtColumnIndex)) + { + removeComplexCategoryLevel(nAtColumnIndex); + return; + } + + const rtl::Reference<DataSeries>& xSeries = m_aColumns[nAtColumnIndex].m_xDataSeries; + + m_apDialogModel->deleteSeries(xSeries, getHeaderForSeries(xSeries).m_xChartType); + + //delete sequences from internal data provider that are not used anymore + //but do not delete sequences that are still in use by the remaining series + + Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + if (!xDataProvider.is() || !xSeries.is()) + { + // Something went wrong. Bail out. + updateFromModel(); + return; + } + + rtl::Reference<ChartType> xSeriesCnt(getHeaderForSeries(xSeries).m_xChartType); + if (!xSeriesCnt.is()) + { + // Unexpected happened. Bail out. + updateFromModel(); + return; + } + + // Collect all the remaining data sequences in the same chart type. The + // deleted data series is already gone by this point. + std::vector<uno::Reference<chart2::data::XLabeledDataSequence> > aAllDataSeqs = + DataSeriesHelper::getAllDataSequences(xSeriesCnt->getDataSeries()); + + // Check if the sequences to be deleted are still referenced by any of + // the other data series. If not, mark them for deletion. + std::vector<sal_Int32> aSequenceIndexesToDelete; + const std::vector<uno::Reference<chart2::data::XLabeledDataSequence> > & aSequencesOfDeleted = xSeries->getDataSequences2(); + for (auto const & labeledDataSeq : aSequencesOfDeleted) + { + // if not used by the remaining series this sequence can be deleted + if( std::none_of( aAllDataSeqs.begin(), aAllDataSeqs.end(), + lcl_RepresentationsOfLSeqMatch( labeledDataSeq )) ) + aSequenceIndexesToDelete.push_back( lcl_getValuesRepresentationIndex( labeledDataSeq ) ); + } + + // delete unnecessary sequences of the internal data + // iterate using greatest index first, so that deletion does not + // shift other sequences that will be deleted later + std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end()); + for( std::vector< sal_Int32 >::reverse_iterator aIt( + aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt ) + { + if( *aIt != -1 ) + xDataProvider->deleteSequence( *aIt ); + } + + updateFromModel(); +} + +void DataBrowserModel::swapDataSeries( sal_Int32 nFirstColumnIndex ) +{ + OSL_ASSERT(m_apDialogModel); + if( o3tl::make_unsigned( nFirstColumnIndex ) < m_aColumns.size() - 1 ) + { + rtl::Reference< DataSeries > xSeries( m_aColumns[nFirstColumnIndex].m_xDataSeries ); + if( xSeries.is()) + { + m_apDialogModel->moveSeries( xSeries, DialogModel::MoveDirection::Down ); + updateFromModel(); + } + } +} + +void DataBrowserModel::swapDataPointForAllSeries( sal_Int32 nFirstIndex ) +{ + OSL_ASSERT(m_apDialogModel); + Reference< chart2::XInternalDataProvider > xDataProvider( + m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + // lockControllers + ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel()); + if( xDataProvider.is()) + xDataProvider->swapDataPointWithNextOneForAllSequences( nFirstIndex ); + // unlockControllers +} + +void DataBrowserModel::insertDataPointForAllSeries( sal_Int32 nAfterIndex ) +{ + Reference< chart2::XInternalDataProvider > xDataProvider( + m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + // lockControllers + ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel()); + if( xDataProvider.is()) + xDataProvider->insertDataPointForAllSequences( nAfterIndex ); + // unlockControllers +} + +void DataBrowserModel::removeDataPointForAllSeries( sal_Int32 nAtIndex ) +{ + Reference< chart2::XInternalDataProvider > xDataProvider( + m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + // lockControllers + ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel()); + if( xDataProvider.is()) + xDataProvider->deleteDataPointForAllSequences( nAtIndex ); + // unlockControllers +} + +DataBrowserModel::tDataHeader DataBrowserModel::getHeaderForSeries( + const Reference< chart2::XDataSeries > & xSeries ) const +{ + rtl::Reference<DataSeries> pSeries = dynamic_cast<DataSeries*>(xSeries.get()); + assert(!xSeries || pSeries); + for (auto const& elemHeader : m_aHeaders) + { + if( elemHeader.m_xDataSeries == pSeries ) + return elemHeader; + } + return tDataHeader(); +} + +rtl::Reference< DataSeries > + DataBrowserModel::getDataSeriesByColumn( sal_Int32 nColumn ) const +{ + tDataColumnVector::size_type nIndex( nColumn ); + if( nIndex < m_aColumns.size()) + return m_aColumns[nIndex].m_xDataSeries; + return nullptr; +} + +DataBrowserModel::eCellType DataBrowserModel::getCellType( sal_Int32 nAtColumn ) const +{ + eCellType eResult = TEXT; + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size()) + eResult = m_aColumns[nIndex].m_eCellType; + return eResult; +} + +double DataBrowserModel::getCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow ) +{ + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size() && + m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) + { + Reference< chart2::data::XNumericalDataSequence > xData( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY ); + if( xData.is()) + { + Sequence< double > aValues( xData->getNumericalData()); + if( nAtRow < aValues.getLength()) + return aValues[nAtRow]; + } + } + return std::numeric_limits<double>::quiet_NaN(); +} + +uno::Any DataBrowserModel::getCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow ) +{ + uno::Any aResult; + + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size() && + m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) + { + Reference< chart2::data::XDataSequence > xData( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues() ); + if( xData.is() ) + { + Sequence< uno::Any > aValues( xData->getData()); + if( nAtRow < aValues.getLength()) + aResult = aValues[nAtRow]; + } + } + return aResult; +} + +OUString DataBrowserModel::getCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow ) +{ + OUString aResult; + + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size() && + m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) + { + Reference< chart2::data::XTextualDataSequence > xData( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY ); + if( xData.is()) + { + Sequence< OUString > aValues( xData->getTextualData()); + if( nAtRow < aValues.getLength()) + aResult = aValues[nAtRow]; + } + } + return aResult; +} + +sal_uInt32 DataBrowserModel::getNumberFormatKey( sal_Int32 nAtColumn ) +{ + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size()) + return m_aColumns[ nIndex ].m_nNumberFormatKey; + return 0; +} + +bool DataBrowserModel::setCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow, const uno::Any & rValue ) +{ + bool bResult = false; + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size() && + m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) + { + bResult = true; + try + { + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + + // label + if( nAtRow == -1 ) + { + Reference< container::XIndexReplace > xIndexReplace( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getLabel(), uno::UNO_QUERY_THROW ); + xIndexReplace->replaceByIndex( 0, rValue ); + } + else + { + Reference< container::XIndexReplace > xIndexReplace( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY_THROW ); + xIndexReplace->replaceByIndex( nAtRow, rValue ); + } + + m_apDialogModel->startControllerLockTimer(); + //notify change directly to the model (this is necessary here as sequences for complex categories not known directly to the chart model so they do not notify their changes) (for complex categories see issue #i82971#) + if( m_xChartDocument.is() ) + m_xChartDocument->setModified(true); + } + catch( const uno::Exception & ) + { + bResult = false; + } + } + return bResult; +} + +bool DataBrowserModel::setCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow, double fValue ) +{ + return (getCellType( nAtColumn ) == NUMBER) && + setCellAny( nAtColumn, nAtRow, uno::Any( fValue )); +} + +bool DataBrowserModel::setCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow, const OUString & rText ) +{ + return (getCellType( nAtColumn ) == TEXT) && + setCellAny( nAtColumn, nAtRow, uno::Any( rText )); +} + +sal_Int32 DataBrowserModel::getColumnCount() const +{ + return static_cast< sal_Int32 >( m_aColumns.size()); +} + +sal_Int32 DataBrowserModel::getMaxRowCount() const +{ + sal_Int32 nResult = 0; + for (auto const& column : m_aColumns) + { + if( column.m_xLabeledDataSequence.is()) + { + Reference< chart2::data::XDataSequence > xSeq( + column.m_xLabeledDataSequence->getValues()); + if( !xSeq.is()) + continue; + sal_Int32 nLength( xSeq->getData().getLength()); + if( nLength > nResult ) + nResult = nLength; + } + } + + return nResult; +} + +OUString DataBrowserModel::getRoleOfColumn( sal_Int32 nColumnIndex ) const +{ + if( nColumnIndex != -1 && + o3tl::make_unsigned( nColumnIndex ) < m_aColumns.size()) + return m_aColumns[ nColumnIndex ].m_aUIRoleName; + return OUString(); +} + +bool DataBrowserModel::isCategoriesColumn( sal_Int32 nColumnIndex ) const +{ + if (nColumnIndex < 0) + return false; + + if (o3tl::make_unsigned(nColumnIndex) >= m_aColumns.size()) + return false; + + // A column is a category when it doesn't have an associated data series. + return !m_aColumns[nColumnIndex].m_xDataSeries.is(); +} + +sal_Int32 DataBrowserModel::getCategoryColumnCount() +{ + sal_Int32 nLastTextColumnIndex = -1; + for (auto const& column : m_aColumns) + { + if( !column.m_xDataSeries.is() ) + nLastTextColumnIndex++; + else + break; + } + return nLastTextColumnIndex+1; +} + +void DataBrowserModel::updateFromModel() +{ + if( !m_xChartDocument.is()) + return; + m_aColumns.clear(); + m_aHeaders.clear(); + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( m_xChartDocument )); + if( !xDiagram.is()) + return; + + // set template at DialogModel + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = m_xChartDocument->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + if( aTemplateAndService.xChartTypeTemplate.is()) + m_apDialogModel->setTemplate( aTemplateAndService.xChartTypeTemplate ); + + sal_Int32 nHeaderStart = 0; + sal_Int32 nHeaderEnd = 0; + { + ExplicitCategoriesProvider aExplicitCategoriesProvider( ChartModelHelper::getFirstCoordinateSystem(m_xChartDocument), *m_xChartDocument ); + + const std::vector< Reference< chart2::data::XLabeledDataSequence> >& rSplitCategoriesList = aExplicitCategoriesProvider.getSplitCategoriesList(); + sal_Int32 nLevelCount = rSplitCategoriesList.size(); + for( sal_Int32 nL = 0; nL<nLevelCount; nL++ ) + { + Reference< chart2::data::XLabeledDataSequence > xCategories( rSplitCategoriesList[nL] ); + if( !xCategories.is() ) + continue; + + tDataColumn aCategories; + aCategories.m_xLabeledDataSequence = xCategories; + if( lcl_ShowCategoriesAsDataLabel( xDiagram )) + aCategories.m_aUIRoleName = DialogModel::GetRoleDataLabel(); + else + aCategories.m_aUIRoleName = lcl_getUIRoleName( xCategories ); + aCategories.m_eCellType = TEXTORDATE; + m_aColumns.push_back( aCategories ); + ++nHeaderStart; + } + } + + if( !xDiagram.is()) + return; + const std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysSeq( xDiagram->getBaseCoordinateSystems()); + for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysSeq ) + { + const std::vector< rtl::Reference< ChartType > > aChartTypes( coords->getChartTypes2()); + sal_Int32 nXAxisNumberFormat = DataSeriesHelper::getNumberFormatKeyFromAxis( nullptr, coords, 0, 0 ); + + for( auto const & CT: aChartTypes ) + { + rtl::Reference< ChartType > xSeriesCnt( CT ); + OUString aRoleForDataLabelNumberFormat = ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( CT ); + + const std::vector< rtl::Reference< DataSeries > > & aSeries( xSeriesCnt->getDataSeries2()); + lcl_tSharedSeqVec aSharedSequences( lcl_getSharedSequences( aSeries )); + for (auto const& sharedSequence : aSharedSequences) + { + tDataColumn aSharedSequence; + aSharedSequence.m_xLabeledDataSequence = sharedSequence; + aSharedSequence.m_aUIRoleName = lcl_getUIRoleName(sharedSequence); + aSharedSequence.m_eCellType = NUMBER; + // as the sequences are shared it should be ok to take the first series + // @todo: dimension index 0 for x-values used here. This is just a guess. + // Also, the axis index is 0, as there is usually only one x-axis + aSharedSequence.m_nNumberFormatKey = nXAxisNumberFormat; + m_aColumns.push_back( aSharedSequence ); + ++nHeaderStart; + } + for( rtl::Reference< DataSeries > const & dataSeries : aSeries ) + { + tDataColumnVector::size_type nStartColIndex = m_aColumns.size(); + rtl::Reference< DataSeries > xSeries( dataSeries ); + if( xSeries.is()) + { + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aLSeqs( xSeries->getDataSequences2()); + if( aLSeqs.empty() ) + continue; + nHeaderEnd = nHeaderStart; + + // @todo: dimension index 1 for y-values used here. This is just a guess + sal_Int32 nYAxisNumberFormatKey = + DataSeriesHelper::getNumberFormatKeyFromAxis( + dataSeries, coords, 1 ); + + sal_Int32 nSeqIdx=0; + for( ; nSeqIdx<static_cast<sal_Int32>(aLSeqs.size()); ++nSeqIdx ) + { + sal_Int32 nSequenceNumberFormatKey = nYAxisNumberFormatKey; + OUString aRole = DataSeriesHelper::getRole(aLSeqs[nSeqIdx]); + + if( aRole == aRoleForDataLabelNumberFormat ) + { + nSequenceNumberFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( + xSeries); + } + else if( aRole == "values-x" ) + nSequenceNumberFormatKey = nXAxisNumberFormat; + + if( std::none_of( aSharedSequences.begin(), aSharedSequences.end(), + lcl_RepresentationsOfLSeqMatch( aLSeqs[nSeqIdx] )) ) + { + // no shared sequence + m_aColumns.emplace_back( + dataSeries, + lcl_getUIRoleName( aLSeqs[nSeqIdx] ), + aLSeqs[nSeqIdx], + NUMBER, + nSequenceNumberFormatKey ); + ++nHeaderEnd; + } + // else skip + } + bool bSwapXAndYAxis = false; + try + { + coords->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndYAxis; + } + catch( const beans::UnknownPropertyException & ) {} + + // add ranges for error bars if present for a series + if( StatisticsHelper::usesErrorBarRanges( dataSeries )) + addErrorBarRanges( dataSeries, nYAxisNumberFormatKey, nSeqIdx, nHeaderEnd, true ); + + if( StatisticsHelper::usesErrorBarRanges( dataSeries, /* bYError = */ false )) + addErrorBarRanges( dataSeries, nYAxisNumberFormatKey, nSeqIdx, nHeaderEnd, false ); + + m_aHeaders.emplace_back( + dataSeries, + CT, + bSwapXAndYAxis, + nHeaderStart, + nHeaderEnd - 1 ); + + nHeaderStart = nHeaderEnd; + + std::sort( m_aColumns.begin() + nStartColIndex, m_aColumns.end(), implColumnLess() ); + } + } + } + } +} + +void DataBrowserModel::addErrorBarRanges( + const Reference< chart2::XDataSeries > & xDataSeries, + sal_Int32 nNumberFormatKey, + sal_Int32 & rInOutSequenceIndex, + sal_Int32 & rInOutHeaderEnd, bool bYError ) +{ + try + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences; + + Reference< chart2::data::XDataSource > xErrorSource( + StatisticsHelper::getErrorBars( xDataSeries, bYError ), uno::UNO_QUERY ); + + uno::Reference< chart2::data::XLabeledDataSequence > xErrorLSequence = + StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( + xErrorSource, + /* bPositiveValue = */ true, + bYError ); + if( xErrorLSequence.is()) + aSequences.push_back( xErrorLSequence ); + + xErrorLSequence = + StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( + xErrorSource, + /* bPositiveValue = */ false, + bYError ); + if( xErrorLSequence.is()) + aSequences.push_back( xErrorLSequence ); + + for (uno::Reference<chart2::data::XLabeledDataSequence> const & rDataSequence : aSequences) + { + rtl::Reference<DataSeries> pDataSeries = dynamic_cast<DataSeries*>(xDataSeries.get()); + assert(pDataSeries || !xDataSeries); + m_aColumns.emplace_back(pDataSeries, lcl_getUIRoleName(rDataSequence), + rDataSequence, NUMBER, nNumberFormatKey); + ++rInOutSequenceIndex; + ++rInOutHeaderEnd; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DataBrowserModel.hxx b/chart2/source/controller/dialogs/DataBrowserModel.hxx new file mode 100644 index 000000000..3eb1756fa --- /dev/null +++ b/chart2/source/controller/dialogs/DataBrowserModel.hxx @@ -0,0 +1,169 @@ +/* -*- 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 <DataSeries.hxx> +#include <ChartType.hxx> + +#include <com/sun/star/uno/Reference.hxx> +#include <rtl/ref.hxx> + +#include <memory> +#include <vector> + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace com::sun::star::chart2 { + class XDataSeries; + class XChartType; +} + +namespace chart +{ + +class DialogModel; +class ChartModel; +class ChartType; +class DataSeries; + +class DataBrowserModel final +{ +public: + explicit DataBrowserModel( + const rtl::Reference<::chart::ChartModel> & xChartDoc ); + ~DataBrowserModel(); + + /** Inserts a new data series after the data series to which the data column + with index nAfterColumnIndex belongs. + */ + void insertDataSeries( sal_Int32 nAfterColumnIndex ); + + /** Inserts a new text column for complex categories. + */ + void insertComplexCategoryLevel( sal_Int32 nAfterColumnIndex ); + + /** Removes a data series to which the data column with index nAtColumnIndex + belongs. + */ + void removeDataSeriesOrComplexCategoryLevel( sal_Int32 nAtColumnIndex ); + + /** Swaps the series to which the data column with index nFirstIndex belongs + with the next series (which starts at an index >= nFirstIndex + 1) + */ + void swapDataSeries( sal_Int32 nFirstIndex ); + void swapDataPointForAllSeries( sal_Int32 nFirstIndex ); + + void insertDataPointForAllSeries( sal_Int32 nAfterIndex ); + void removeDataPointForAllSeries( sal_Int32 nAtIndex ); + + enum eCellType + { + NUMBER, + TEXT, + TEXTORDATE + }; + + eCellType getCellType( sal_Int32 nAtColumn ) const; + /// If getCellType( nAtColumn, nAtRow ) returns TEXT, the result will be Nan + double getCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow ); + OUString getCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow ); + css::uno::Any getCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow ); + sal_uInt32 getNumberFormatKey( sal_Int32 nAtColumn ); + + /// returns </sal_True> if the number could successfully be set at the given position + bool setCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow, double fValue ); + /// returns </sal_True> if the text could successfully be set at the given position + bool setCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow, const OUString & rText ); + bool setCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow, const css::uno::Any & aValue ); + + sal_Int32 getColumnCount() const; + sal_Int32 getMaxRowCount() const; + + // returns the UI string of the corresponding role + OUString getRoleOfColumn( sal_Int32 nColumnIndex ) const; + bool isCategoriesColumn( sal_Int32 nColumnIndex ) const; + + struct tDataHeader + { + rtl::Reference< ::chart::DataSeries > m_xDataSeries; + rtl::Reference< ::chart::ChartType > m_xChartType; + bool m_bSwapXAndYAxis; + sal_Int32 m_nStartColumn; + sal_Int32 m_nEndColumn; + + // default CTOR + tDataHeader() : + m_bSwapXAndYAxis( false ), + m_nStartColumn( -1 ), + m_nEndColumn( -1 ) + {} + // "full" CTOR + tDataHeader( + rtl::Reference< ::chart::DataSeries > const & xDataSeries, + rtl::Reference< ::chart::ChartType > const &xChartType, + bool bSwapXAndYAxis, + sal_Int32 nStartColumn, + sal_Int32 nEndColumn ) : + m_xDataSeries( xDataSeries ), + m_xChartType( xChartType ), + m_bSwapXAndYAxis( bSwapXAndYAxis ), + m_nStartColumn( nStartColumn ), + m_nEndColumn( nEndColumn ) + {} + }; + + typedef std::vector< tDataHeader > tDataHeaderVector; + + const tDataHeaderVector& getDataHeaders() const { return m_aHeaders;} + + tDataHeader getHeaderForSeries( + const css::uno::Reference< css::chart2::XDataSeries > &xSeries ) const; + + rtl::Reference< ::chart::DataSeries > + getDataSeriesByColumn( sal_Int32 nColumn ) const; + +private: + void updateFromModel(); + + void removeComplexCategoryLevel( sal_Int32 nAtColumnIndex ); + + void addErrorBarRanges( + const css::uno::Reference<css::chart2::XDataSeries > & xDataSeries, + sal_Int32 nNumberFormatKey, + sal_Int32 & rInOutSequenceIndex, + sal_Int32 & rInOutHeaderEnd, bool bYError ); + + sal_Int32 getCategoryColumnCount(); + + rtl::Reference<::chart::ChartModel> m_xChartDocument; + std::unique_ptr< DialogModel > m_apDialogModel; + + struct tDataColumn; + struct implColumnLess; + + typedef std::vector< tDataColumn > tDataColumnVector; + + tDataColumnVector m_aColumns; + tDataHeaderVector m_aHeaders; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DialogModel.cxx b/chart2/source/controller/dialogs/DialogModel.cxx new file mode 100644 index 000000000..2d12bc6cd --- /dev/null +++ b/chart2/source/controller/dialogs/DialogModel.cxx @@ -0,0 +1,841 @@ +/* -*- 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 "DialogModel.hxx" +#include <RangeSelectionHelper.hxx> +#include <DataInterpreter.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <DataSourceHelper.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <strings.hrc> +#include <ResId.hxx> +#include <ControllerLockGuard.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <ChartTypeTemplate.hxx> +#include <ThreeDHelper.hxx> +#include <ChartModel.hxx> +#include <BaseCoordinateSystem.hxx> +#include <LabeledDataSequence.hxx> + +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> +#include <tools/diagnose_ex.h> + +#include <rtl/ustring.hxx> + +#include <utility> +#include <algorithm> +#include <cstddef> +#include <iterator> +#include <numeric> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +constexpr OUStringLiteral lcl_aLabelRole( u"label" ); + + +OUString lcl_ConvertRole( const OUString & rRoleString ) +{ + OUString aResult( rRoleString ); + + typedef std::map< OUString, OUString > tTranslationMap; + static const tTranslationMap aTranslationMap = + { + { "categories", ::chart::SchResId( STR_DATA_ROLE_CATEGORIES ) }, + { "error-bars-x", ::chart::SchResId( STR_DATA_ROLE_X_ERROR ) }, + { "error-bars-x-positive", ::chart::SchResId( STR_DATA_ROLE_X_ERROR_POSITIVE ) }, + { "error-bars-x-negative", ::chart::SchResId( STR_DATA_ROLE_X_ERROR_NEGATIVE ) }, + { "error-bars-y", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR ) }, + { "error-bars-y-positive", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR_POSITIVE ) }, + { "error-bars-y-negative", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR_NEGATIVE ) }, + { "label", ::chart::SchResId( STR_DATA_ROLE_LABEL ) }, + { "values-first", ::chart::SchResId( STR_DATA_ROLE_FIRST ) }, + { "values-last", ::chart::SchResId( STR_DATA_ROLE_LAST ) }, + { "values-max", ::chart::SchResId( STR_DATA_ROLE_MAX ) }, + { "values-min", ::chart::SchResId( STR_DATA_ROLE_MIN ) }, + { "values-x", ::chart::SchResId( STR_DATA_ROLE_X ) }, + { "values-y", ::chart::SchResId( STR_DATA_ROLE_Y ) }, + { "values-size", ::chart::SchResId( STR_DATA_ROLE_SIZE ) }, + { "FillColor", ::chart::SchResId( STR_PROPERTY_ROLE_FILLCOLOR ) }, + { "BorderColor", ::chart::SchResId( STR_PROPERTY_ROLE_BORDERCOLOR ) }, + }; + + tTranslationMap::const_iterator aIt( aTranslationMap.find( rRoleString )); + if( aIt != aTranslationMap.end()) + { + aResult = (*aIt).second; + } + return aResult; +} + +typedef std::map< OUString, sal_Int32 > lcl_tRoleIndexMap; + +lcl_tRoleIndexMap lcl_createRoleIndexMap() +{ + lcl_tRoleIndexMap aMap; + sal_Int32 nIndex = 0; + + aMap[ "label" ] = ++nIndex; + aMap[ "categories" ] = ++nIndex; + aMap[ "values-x" ] = ++nIndex; + aMap[ "values-y" ] = ++nIndex; + aMap[ "error-bars-x" ] = ++nIndex; + aMap[ "error-bars-x-positive" ] = ++nIndex; + aMap[ "error-bars-x-negative" ] = ++nIndex; + aMap[ "error-bars-y" ] = ++nIndex; + aMap[ "error-bars-y-positive" ] = ++nIndex; + aMap[ "error-bars-y-negative" ] = ++nIndex; + aMap[ "values-first" ] = ++nIndex; + aMap[ "values-min" ] = ++nIndex; + aMap[ "values-max" ] = ++nIndex; + aMap[ "values-last" ] = ++nIndex; + aMap[ "values-size" ] = ++nIndex; + + return aMap; +} + + +struct lcl_RolesWithRangeAppend +{ + typedef Reference< data::XLabeledDataSequence > value_type; + typedef ::chart::DialogModel::tRolesWithRanges tContainerType; + + explicit lcl_RolesWithRangeAppend( tContainerType * rCnt, + const OUString & aLabelRole ) + : m_rDestCnt( rCnt ), + m_aRoleForLabelSeq( aLabelRole ) + {} + + lcl_RolesWithRangeAppend & operator= ( const value_type & xVal ) + { + try + { + if( xVal.is()) + { + // data sequence + Reference< data::XDataSequence > xSeq( xVal->getValues()); + if( xSeq.is()) + { + OUString aRole; + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); + if( xProp->getPropertyValue( "Role" ) >>= aRole ) + { + m_rDestCnt->emplace(aRole, xSeq->getSourceRangeRepresentation()); + // label + if( aRole == m_aRoleForLabelSeq ) + { + Reference< data::XDataSequence > xLabelSeq( xVal->getLabel()); + if( xLabelSeq.is()) + { + m_rDestCnt->emplace( + lcl_aLabelRole, xLabelSeq->getSourceRangeRepresentation()); + } + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return *this; + } + + // Implement output operator requirements as required by std::copy (and + // implement prefix increment in terms of postfix increment to avoid unused + // member function warnings for the latter in the common case where + // std::copy would not actually need it): + lcl_RolesWithRangeAppend & operator* () { return *this; } + lcl_RolesWithRangeAppend & operator++ () { return operator++(0); } + lcl_RolesWithRangeAppend & operator++ (int) { return *this; } + +private: + tContainerType * m_rDestCnt; + OUString m_aRoleForLabelSeq; +}; + +} + +namespace std +{ + template<> struct iterator_traits<lcl_RolesWithRangeAppend> + { + typedef std::output_iterator_tag iterator_category; + typedef Reference< data::XLabeledDataSequence > value_type; + typedef value_type& reference; + }; +} + +namespace { + +void lcl_SetSequenceRole( + const Reference< data::XDataSequence > & xSeq, + const OUString & rRole ) +{ + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY ); + if( xProp.is()) + xProp->setPropertyValue( "Role" , uno::Any( rRole )); +} + +Sequence< OUString > lcl_CopyExcludingValuesFirst( + Sequence< OUString > const & i_aInput ) +{ + Sequence< OUString > aOutput( i_aInput.getLength()); + auto pOutput = aOutput.getArray(); + int nSourceIndex, nDestIndex; + for( nSourceIndex = nDestIndex = 0; nSourceIndex < i_aInput.getLength(); nSourceIndex++ ) + { + if( i_aInput[nSourceIndex] == "values-first" ) + { + aOutput.realloc( aOutput.getLength() - 1 ); + pOutput = aOutput.getArray(); + } + else + { + pOutput[nDestIndex] = i_aInput[nSourceIndex]; + nDestIndex++; + } + } + return aOutput; +} + +rtl::Reference< ::chart::DataSeries > lcl_CreateNewSeries( + const rtl::Reference< ::chart::ChartType > & xChartType, + sal_Int32 nNewSeriesIndex, + sal_Int32 nTotalNumberOfSeriesInCTGroup, + const rtl::Reference< ::chart::Diagram > & xDiagram, + const rtl::Reference< ::chart::ChartTypeTemplate > & xTemplate, + bool bCreateDataCachedSequences ) +{ + // create plain series + rtl::Reference< ::chart::DataSeries > xResult = new ::chart::DataSeries(); + if( xTemplate.is()) + { + // @deprecated: correct default color should be found by view + // without setting it as hard attribute + Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); + if( xColorScheme.is()) + xResult->setPropertyValue( "Color" , uno::Any( xColorScheme->getColorByIndex( nNewSeriesIndex ))); + std::size_t nGroupIndex=0; + if( xChartType.is()) + { + std::vector< rtl::Reference< ::chart::ChartType > > aCTs( + ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram )); + for( ; nGroupIndex < aCTs.size(); ++nGroupIndex) + if( aCTs[nGroupIndex] == xChartType ) + break; + if( nGroupIndex == aCTs.size()) + nGroupIndex = 0; + } + xTemplate->applyStyle2( xResult, nGroupIndex, nNewSeriesIndex, nTotalNumberOfSeriesInCTGroup ); + } + + if( bCreateDataCachedSequences ) + { + // set chart type specific roles + if( xChartType.is() ) + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSequences; + const OUString aRoleOfSeqForSeriesLabel = xChartType->getRoleOfSequenceForSeriesLabel(); + const OUString aLabel(::chart::SchResId(STR_DATA_UNNAMED_SERIES)); + Sequence< OUString > aPossibleRoles( xChartType->getSupportedMandatoryRoles()); + Sequence< OUString > aPossibleOptRoles( xChartType->getSupportedOptionalRoles()); + + //special handling for candlestick type + if( xTemplate.is()) + { + rtl::Reference< ::chart::DataInterpreter > xInterpreter( xTemplate->getDataInterpreter2()); + if( xInterpreter.is()) + { + sal_Int32 nStockVariant; + if( xInterpreter->getChartTypeSpecificData("stock variant") >>= nStockVariant ) + { + if( nStockVariant == 0 || nStockVariant == 2) { + //delete "values-first" role + aPossibleRoles = lcl_CopyExcludingValuesFirst(aPossibleRoles); + aPossibleOptRoles = lcl_CopyExcludingValuesFirst(aPossibleOptRoles); + } + } + } + } + + const Sequence< OUString > aRoles( aPossibleRoles ); + const Sequence< OUString > aOptRoles( aPossibleOptRoles ); + + for(OUString const & role : aRoles) + { + if( role == lcl_aLabelRole ) + continue; + Reference< data::XDataSequence > xSeq( ::chart::DataSourceHelper::createCachedDataSequence() ); + lcl_SetSequenceRole( xSeq, role ); + // assert that aRoleOfSeqForSeriesLabel is part of the mandatory roles + if( role == aRoleOfSeqForSeriesLabel ) + { + Reference< data::XDataSequence > xLabel( ::chart::DataSourceHelper::createCachedDataSequence( aLabel )); + lcl_SetSequenceRole( xLabel, lcl_aLabelRole ); + aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq, xLabel )); + } + else + aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq )); + } + + for(OUString const & role : aOptRoles) + { + if( role == lcl_aLabelRole ) + continue; + Reference< data::XDataSequence > xSeq( ::chart::DataSourceHelper::createCachedDataSequence()); + lcl_SetSequenceRole( xSeq, role ); + aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq )); + } + + xResult->setData( aNewSequences ); + } + } + + return xResult; +} + +struct lcl_addSeriesNumber +{ + sal_Int32 operator() ( sal_Int32 nCurrentNumber, const Reference< XDataSeriesContainer > & xCnt ) const + { + if( xCnt.is()) + return nCurrentNumber + (xCnt->getDataSeries().getLength()); + return nCurrentNumber; + } +}; + +} // anonymous namespace + +namespace chart +{ + +DialogModelTimeBasedInfo::DialogModelTimeBasedInfo(): + bTimeBased(false), + nStart(0), + nEnd(0) +{ +} + +DialogModel::DialogModel( + const rtl::Reference<::chart::ChartModel> & xChartDocument ) : + m_xChartDocument( xChartDocument ), + m_aTimerTriggeredControllerLock( m_xChartDocument ) +{ +} + +DialogModel::~DialogModel() +{ + if(maTimeBasedInfo.bTimeBased) + { + getModel().setTimeBasedRange(maTimeBasedInfo.nStart, maTimeBasedInfo.nEnd); + } +} + +void DialogModel::setTemplate( + const rtl::Reference< ChartTypeTemplate > & xTemplate ) +{ + m_xTemplate = xTemplate; +} + +std::shared_ptr< RangeSelectionHelper > const & + DialogModel::getRangeSelectionHelper() const +{ + if( ! m_spRangeSelectionHelper) + m_spRangeSelectionHelper = + std::make_shared<RangeSelectionHelper>( m_xChartDocument ); + + return m_spRangeSelectionHelper; +} + +const rtl::Reference<::chart::ChartModel> & DialogModel::getChartModel() const +{ + return m_xChartDocument; +} + +Reference< data::XDataProvider > DialogModel::getDataProvider() const +{ + Reference< data::XDataProvider > xResult; + if( m_xChartDocument.is()) + xResult.set( m_xChartDocument->getDataProvider()); + return xResult; +} + +std::vector< rtl::Reference< ChartType > > + DialogModel::getAllDataSeriesContainers() const +{ + std::vector< rtl::Reference< ChartType > > aResult; + + try + { + if( !m_xChartDocument ) + return {}; + rtl::Reference< Diagram > xDiagram = m_xChartDocument->getFirstChartDiagram(); + if( xDiagram.is()) + { + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysSeq( + xDiagram->getBaseCoordinateSystems()); + for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysSeq ) + { + + for (const auto & rxChartType : coords->getChartTypes2()) + aResult.push_back(rxChartType); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +std::vector< DialogModel::tSeriesWithChartTypeByName > + DialogModel::getAllDataSeriesWithLabel() const +{ + std::vector< tSeriesWithChartTypeByName > aResult; + std::vector< rtl::Reference< ChartType > > aContainers( + getAllDataSeriesContainers()); + + for (const auto & rxChartType : aContainers ) + { + try + { + const std::vector< rtl::Reference< DataSeries > > & aSeq = rxChartType->getDataSeries2(); + OUString aRole = rxChartType->getRoleOfSequenceForSeriesLabel(); + for( rtl::Reference< DataSeries > const & dataSeries : aSeq ) + { + aResult.push_back( + ::chart::DialogModel::tSeriesWithChartTypeByName( + ::chart::DataSeriesHelper::getDataSeriesLabel( dataSeries, aRole ), + std::make_pair( dataSeries, rxChartType ))); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +namespace { + +void addMissingRoles(DialogModel::tRolesWithRanges& rResult, const uno::Sequence<OUString>& rRoles) +{ + for(OUString const & role : rRoles) + { + if(rResult.find(role) == rResult.end()) + rResult.emplace(role, OUString()); + } +} + +/** + * Insert a new data series to chart type at position after specified series + * position. + * + * @param xChartType chart type that contains data series. + * @param xSeries insertion position. The new series will be inserted after + * this one. + * @param xNewSeries new data series to insert. + */ +void addNewSeriesToContainer( + const rtl::Reference<ChartType>& xChartType, + const rtl::Reference<DataSeries>& xSeries, + const rtl::Reference<DataSeries>& xNewSeries ) +{ + auto aSeries = xChartType->getDataSeries2(); + + auto aIt = std::find( aSeries.begin(), aSeries.end(), xSeries); + + if( aIt == aSeries.end()) + // if we have no series we insert at the first position. + aIt = aSeries.begin(); + else + // vector::insert inserts before, so we have to advance + ++aIt; + + aSeries.insert(aIt, xNewSeries); + xChartType->setDataSeries(aSeries); +} + +} + +DialogModel::tRolesWithRanges DialogModel::getRolesWithRanges( + const Reference< XDataSeries > & xSeries, + const OUString & aRoleOfSequenceForLabel, + const rtl::Reference< ::chart::ChartType > & xChartType ) +{ + DialogModel::tRolesWithRanges aResult; + try + { + Reference< data::XDataSource > xSource( xSeries, uno::UNO_QUERY_THROW ); + const Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSource->getDataSequences()); + std::copy( aSeq.begin(), aSeq.end(), + lcl_RolesWithRangeAppend( &aResult, aRoleOfSequenceForLabel )); + if( xChartType.is()) + { + // add missing mandatory roles + Sequence< OUString > aRoles( xChartType->getSupportedMandatoryRoles()); + addMissingRoles(aResult, aRoles); + + // add missing optional roles + aRoles = xChartType->getSupportedOptionalRoles(); + addMissingRoles(aResult, aRoles); + + // add missing property roles + aRoles = xChartType->getSupportedPropertyRoles(); + addMissingRoles(aResult, aRoles); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aResult; +} + +void DialogModel::moveSeries( + const Reference< XDataSeries > & xSeries, + MoveDirection eDirection ) +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram()); + DiagramHelper::moveSeries( xDiagram, xSeries, eDirection==MoveDirection::Down ); +} + +rtl::Reference< ::chart::DataSeries > DialogModel::insertSeriesAfter( + const Reference< XDataSeries > & xUnoSeries, + const rtl::Reference< ::chart::ChartType > & xChartType, + bool bCreateDataCachedSequences /* = false */ ) +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + rtl::Reference< ::chart::DataSeries > xNewSeries; + rtl::Reference<DataSeries> xSeries = dynamic_cast<DataSeries*>(xUnoSeries.get()); + assert(xSeries || !xUnoSeries); + + try + { + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram() ); + ThreeDLookScheme e3DScheme = ThreeDHelper::detectScheme( xDiagram ); + + sal_Int32 nSeriesInChartType = 0; + const sal_Int32 nTotalSeries = countSeries(); + if( xChartType.is()) + { + nSeriesInChartType = xChartType->getDataSeries().getLength(); + } + + // create new series + xNewSeries = + lcl_CreateNewSeries( + xChartType, + nTotalSeries, // new series' index + nSeriesInChartType, + xDiagram, + m_xTemplate, + bCreateDataCachedSequences ); + + // add new series to container + if( xNewSeries.is()) + addNewSeriesToContainer(xChartType, xSeries, xNewSeries); + + ThreeDHelper::setScheme( xDiagram, e3DScheme ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xNewSeries; +} + +void DialogModel::deleteSeries( + const Reference< XDataSeries > & xSeries, + const rtl::Reference< ChartType > & xChartType ) +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + + DataSeriesHelper::deleteSeries( xSeries, xChartType ); +} + +uno::Reference< chart2::data::XLabeledDataSequence > DialogModel::getCategories() const +{ + uno::Reference< chart2::data::XLabeledDataSequence > xResult; + try + { + if( m_xChartDocument.is()) + { + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram()); + xResult = DiagramHelper::getCategoriesFromDiagram( xDiagram ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xResult; +} + +void DialogModel::setCategories( const Reference< chart2::data::XLabeledDataSequence > & xCategories ) +{ + if( !m_xChartDocument.is()) + return; + + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram()); + if( !xDiagram.is()) + return; + + // categories + bool bSupportsCategories = true; + + rtl::Reference< ChartType > xFirstChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + if( xFirstChartType.is() ) + { + sal_Int32 nAxisType = ChartTypeHelper::getAxisType( xFirstChartType, 0 ); // x-axis + bSupportsCategories = (nAxisType == AxisType::CATEGORY); + } + DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram, true, bSupportsCategories ); +} + +OUString DialogModel::getCategoriesRange() const +{ + uno::Reference< chart2::data::XLabeledDataSequence > xLSeq( getCategories()); + OUString aRange; + if( xLSeq.is()) + { + Reference< data::XDataSequence > xSeq( xLSeq->getValues()); + if( xSeq.is()) + aRange = xSeq->getSourceRangeRepresentation(); + } + return aRange; +} + +bool DialogModel::isCategoryDiagram() const +{ + bool bRet = false; + if( m_xChartDocument.is()) + bRet = DiagramHelper::isCategoryDiagram( m_xChartDocument->getFirstChartDiagram() ); + return bRet; +} + +void DialogModel::detectArguments( + OUString & rOutRangeString, + bool & rOutUseColumns, + bool & rOutFirstCellAsLabel, + bool & rOutHasCategories ) const +{ + try + { + uno::Sequence< sal_Int32 > aSequenceMapping;//todo YYYX + + // Note: unused data is currently not supported in being passed to detectRangeSegmentation + if( m_xChartDocument.is()) + { + (void)DataSourceHelper::detectRangeSegmentation( + m_xChartDocument, + rOutRangeString, aSequenceMapping, rOutUseColumns, rOutFirstCellAsLabel, rOutHasCategories ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool DialogModel::allArgumentsForRectRangeDetected() const +{ + return DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument ); +} + +void DialogModel::startControllerLockTimer() +{ + m_aTimerTriggeredControllerLock.startTimer(); +} + +void DialogModel::setData( + const Sequence< beans::PropertyValue > & rArguments ) +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + + Reference< data::XDataProvider > xDataProvider( getDataProvider()); + if( ! xDataProvider.is() || + ! m_xTemplate.is() ) + { + OSL_FAIL( "Model objects missing" ); + return; + } + + try + { + Reference< chart2::data::XDataSource > xDataSource( + xDataProvider->createDataSource( rArguments ) ); + + rtl::Reference< ::chart::DataInterpreter > xInterpreter( + m_xTemplate->getDataInterpreter2()); + if( xInterpreter.is()) + { + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram() ); + ThreeDLookScheme e3DScheme = ThreeDHelper::detectScheme( xDiagram ); + + std::vector< rtl::Reference< DataSeries > > aSeriesToReUse = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + applyInterpretedData( + xInterpreter->interpretDataSource( + xDataSource, rArguments, + aSeriesToReUse ), + aSeriesToReUse); + + ThreeDHelper::setScheme( xDiagram, e3DScheme ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void DialogModel::setTimeBasedRange( bool bTimeBased, sal_Int32 nStart, sal_Int32 nEnd) const +{ + maTimeBasedInfo.nStart = nStart; + maTimeBasedInfo.nEnd = nEnd; + maTimeBasedInfo.bTimeBased = bTimeBased; +} + +OUString DialogModel::ConvertRoleFromInternalToUI( const OUString & rRoleString ) +{ + return lcl_ConvertRole( rRoleString ); +} + +OUString DialogModel::GetRoleDataLabel() +{ + return ::chart::SchResId(STR_OBJECT_DATALABELS); +} + +sal_Int32 DialogModel::GetRoleIndexForSorting( const OUString & rInternalRoleString ) +{ + static lcl_tRoleIndexMap aRoleIndexMap = lcl_createRoleIndexMap(); + + lcl_tRoleIndexMap::const_iterator aIt( aRoleIndexMap.find( rInternalRoleString )); + if( aIt != aRoleIndexMap.end()) + return aIt->second; + + return 0; +} + +// private methods + +void DialogModel::applyInterpretedData( + const InterpretedData & rNewData, + const std::vector< rtl::Reference< DataSeries > > & rSeriesToReUse ) +{ + if( ! m_xChartDocument.is()) + return; + + m_aTimerTriggeredControllerLock.startTimer(); + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram()); + if( !xDiagram.is()) + return; + + // styles + if( m_xTemplate.is() ) + { + sal_Int32 nGroup = 0; + sal_Int32 nSeriesCounter = 0; + sal_Int32 nNewSeriesIndex = static_cast< sal_Int32 >( rSeriesToReUse.size()); + const sal_Int32 nOuterSize=rNewData.Series.size(); + + for(; nGroup < nOuterSize; ++nGroup) + { + const std::vector< rtl::Reference< DataSeries > > & aSeries( rNewData.Series[ nGroup ] ); + const sal_Int32 nSeriesInGroup = aSeries.size(); + for( sal_Int32 nSeries=0; nSeries<nSeriesInGroup; ++nSeries, ++nSeriesCounter ) + { + if( std::find( rSeriesToReUse.begin(), rSeriesToReUse.end(), aSeries[nSeries] ) + == rSeriesToReUse.end()) + { + if( aSeries[nSeries].is()) + { + // @deprecated: correct default color should be found by view + // without setting it as hard attribute + Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); + if( xColorScheme.is()) + aSeries[nSeries]->setPropertyValue( "Color" , + uno::Any( xColorScheme->getColorByIndex( nSeriesCounter ))); + } + m_xTemplate->applyStyle2( aSeries[nSeries], nGroup, nNewSeriesIndex++, nSeriesInGroup ); + } + } + } + } + + // data series + std::vector< rtl::Reference< ChartType > > aSeriesCnt = getAllDataSeriesContainers(); + + OSL_ASSERT( aSeriesCnt.size() == rNewData.Series.size()); + + auto aSrcIt = rNewData.Series.begin(); + auto aDestIt = aSeriesCnt.begin(); + for(; aSrcIt != rNewData.Series.end() && aDestIt != aSeriesCnt.end(); + ++aSrcIt, ++aDestIt ) + { + try + { + OSL_ASSERT( (*aDestIt).is()); + (*aDestIt)->setDataSeries( *aSrcIt ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + DialogModel::setCategories(rNewData.Categories); +} + +sal_Int32 DialogModel::countSeries() const +{ + std::vector< rtl::Reference< ChartType > > aCnt( getAllDataSeriesContainers()); + return std::accumulate( aCnt.begin(), aCnt.end(), 0, lcl_addSeriesNumber()); +} + +ChartModel& DialogModel::getModel() const +{ + return *m_xChartDocument; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DialogModel.hxx b/chart2/source/controller/dialogs/DialogModel.hxx new file mode 100644 index 000000000..2f8e1c1fb --- /dev/null +++ b/chart2/source/controller/dialogs/DialogModel.hxx @@ -0,0 +1,176 @@ +/* -*- 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 <TimerTriggeredControllerLock.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ref.hxx> + +#include <map> +#include <memory> +#include <vector> + +namespace chart { class ChartModel; } +namespace com::sun::star::beans { struct PropertyValue; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::uno { template <class E> class Sequence; } + +namespace com::sun::star::chart2 { + class XDataSeriesContainer; + class XDataSeries; + class XChartType; + namespace data { + class XDataProvider; + class XLabeledDataSequence; + } +} + +namespace chart +{ +class ChartType; +class ChartTypeTemplate; +class DataSeries; +struct InterpretedData; +class LabeledDataSequence; +class RangeSelectionHelper; + +struct DialogModelTimeBasedInfo +{ + DialogModelTimeBasedInfo(); + + bool bTimeBased; + sal_Int32 nStart; + sal_Int32 nEnd; +}; + +class DialogModel +{ +public: + explicit DialogModel( const rtl::Reference<::chart::ChartModel> & xChartDocument ); + ~DialogModel(); + + typedef std::pair< + OUString, + std::pair< rtl::Reference< ::chart::DataSeries >, + rtl::Reference< ::chart::ChartType > > > + tSeriesWithChartTypeByName; + + typedef std::map< OUString, OUString > + tRolesWithRanges; + + void setTemplate( + const rtl::Reference< ::chart::ChartTypeTemplate > & xTemplate ); + + std::shared_ptr< RangeSelectionHelper > const & + getRangeSelectionHelper() const; + + const rtl::Reference<::chart::ChartModel> & + getChartModel() const; + + css::uno::Reference< css::chart2::data::XDataProvider > + getDataProvider() const; + + std::vector< rtl::Reference< ::chart::ChartType > > + getAllDataSeriesContainers() const; + + std::vector< tSeriesWithChartTypeByName > + getAllDataSeriesWithLabel() const; + + static tRolesWithRanges getRolesWithRanges( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const OUString & aRoleOfSequenceForLabel, + const rtl::Reference< ::chart::ChartType > & xChartType ); + + enum class MoveDirection + { + Down, Up + }; + + void moveSeries( const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + MoveDirection eDirection ); + + /// @return the newly inserted series + rtl::Reference< + ::chart::DataSeries > insertSeriesAfter( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::ChartType > & xChartType, + bool bCreateDataCachedSequences = false ); + + void deleteSeries( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::ChartType > & xChartType ); + + css::uno::Reference< css::chart2::data::XLabeledDataSequence > + getCategories() const; + + void setCategories( const css::uno::Reference< css::chart2::data::XLabeledDataSequence > & xCategories ); + + OUString getCategoriesRange() const; + + bool isCategoryDiagram() const; + + void detectArguments( + OUString & rOutRangeString, + bool & rOutUseColumns, bool & rOutFirstCellAsLabel, bool & rOutHasCategories ) const; + + bool allArgumentsForRectRangeDetected() const; + + void setData( const css::uno::Sequence< css::beans::PropertyValue > & rArguments ); + + void setTimeBasedRange( bool bTimeBased, sal_Int32 nStart, sal_Int32 nEnd) const; + + const DialogModelTimeBasedInfo& getTimeBasedInfo() const { return maTimeBasedInfo; } + + void startControllerLockTimer(); + + static OUString ConvertRoleFromInternalToUI( const OUString & rRoleString ); + static OUString GetRoleDataLabel(); + + // pass a role string (not translated) and get an index that serves for + // relative ordering, to get e.g. x-values and y-values in the right order + static sal_Int32 GetRoleIndexForSorting( const OUString & rInternalRoleString ); + + ChartModel& getModel() const; + +private: + rtl::Reference<::chart::ChartModel> + m_xChartDocument; + + rtl::Reference< ::chart::ChartTypeTemplate > m_xTemplate; + + mutable std::shared_ptr< RangeSelectionHelper > + m_spRangeSelectionHelper; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + +private: + void applyInterpretedData( + const InterpretedData & rNewData, + const std::vector< rtl::Reference< ::chart::DataSeries > > & rSeriesToReUse ); + + sal_Int32 countSeries() const; + + mutable DialogModelTimeBasedInfo maTimeBasedInfo; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/ObjectNameProvider.cxx b/chart2/source/controller/dialogs/ObjectNameProvider.cxx new file mode 100644 index 000000000..07b7f3503 --- /dev/null +++ b/chart2/source/controller/dialogs/ObjectNameProvider.cxx @@ -0,0 +1,860 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <ObjectNameProvider.hxx> +#include <ResId.hxx> +#include <strings.hrc> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <TitleHelper.hxx> +#include <ExplicitCategoriesProvider.hxx> +#include <CommonConverters.hxx> +#include <NumberFormatterWrapper.hxx> +#include <RegressionCurveHelper.hxx> +#include <BaseCoordinateSystem.hxx> +#include <RegressionCurveModel.hxx> +#include <rtl/math.hxx> +#include <rtl/ustring.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <unotools/localedatawrapper.hxx> + +#include <com/sun/star/chart2/XTitle.hpp> +#include <com/sun/star/chart2/MovingAverageType.hpp> +#include <tools/diagnose_ex.h> +#include <o3tl/string_view.hxx> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace +{ + +OUString lcl_getDataSeriesName( const OUString& rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartModel ); + if( xDiagram.is() && xSeries.is() ) + { + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) ); + if( xChartType.is() ) + { + aRet = ::chart::DataSeriesHelper::getDataSeriesLabel( + xSeries, xChartType->getRoleOfSequenceForSeriesLabel() ) ; + } + } + + return aRet; +} + +OUString lcl_getFullSeriesName( const OUString& rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet(SchResId(STR_TIP_DATASERIES)); + OUString aWildcard( "%SERIESNAME" ); + sal_Int32 nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), lcl_getDataSeriesName( rObjectCID, xChartModel ) ); + return aRet; +} + +void lcl_addText( OUString& rOut, std::u16string_view rSeparator, std::u16string_view rNext ) +{ + if( !(rOut.isEmpty() || rNext.empty()) ) + rOut+=rSeparator; + if( !rNext.empty() ) + rOut+=rNext; +} + +OUString lcl_getDataPointValueText( const rtl::Reference< DataSeries >& xSeries, sal_Int32 nPointIndex, + const rtl::Reference< BaseCoordinateSystem >& xCooSys, + const Reference< frame::XModel >& xChartModel ) +{ + + OUString aRet; + + if(!xSeries.is()) + return aRet; + + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aDataSequences = xSeries->getDataSequences2(); + + OUString aX, aY, aY_Min, aY_Max, aY_First, aY_Last, a_Size; + double fValue = 0; + + uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartModel, uno::UNO_QUERY ); + NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier ); + Color nLabelColor;//dummy + bool bColorChanged;//dummy + + for(sal_Int32 nN = aDataSequences.size();nN--;) + { + uno::Reference<data::XDataSequence> xDataSequence( aDataSequences[nN]->getValues()); + if( !xDataSequence.is() ) + continue; + Sequence< Any > aData( xDataSequence->getData() ); + if( nPointIndex >= aData.getLength() ) + continue; + uno::Reference<beans::XPropertySet> xProp(xDataSequence, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + uno::Any aARole = xProp->getPropertyValue( "Role" ); + OUString aRole; + aARole >>= aRole; + + if( aRole == "values-x" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aX = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-y") + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-first" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY_First = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-min" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY_Min = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-max" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY_Max = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-last" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY_Last = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-size" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + a_Size = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } + + if( aX.isEmpty() ) + { + ChartModel& rModel = dynamic_cast<ChartModel&>(*xChartModel); + aRet = ExplicitCategoriesProvider::getCategoryByIndex( xCooSys, rModel, nPointIndex ); + } + else + { + aRet = aX; + } + + OUString aSeparator( " " ); + + lcl_addText( aRet, aSeparator, aY ); + lcl_addText( aRet, aSeparator, aY_First ); + lcl_addText( aRet, aSeparator, aY_Min ); + lcl_addText( aRet, aSeparator, aY_Max ); + lcl_addText( aRet, aSeparator, aY_Last ); + lcl_addText( aRet, aSeparator, a_Size ); + + return aRet; +} + +} //end anonymous namespace + +OUString ObjectNameProvider::getName( ObjectType eObjectType, bool bPlural ) +{ + OUString aRet; + switch( eObjectType ) + { + case OBJECTTYPE_PAGE: + aRet=SchResId(STR_OBJECT_PAGE); + break; + case OBJECTTYPE_TITLE: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_TITLES); + else + aRet=SchResId(STR_OBJECT_TITLE); + } + break; + case OBJECTTYPE_LEGEND: + aRet=SchResId(STR_OBJECT_LEGEND); + break; + case OBJECTTYPE_LEGEND_ENTRY: + aRet=SchResId(STR_OBJECT_LEGEND_SYMBOL);//@todo change string if we do differentiate symbol and legend entry in future + break; + case OBJECTTYPE_DIAGRAM: + aRet=SchResId(STR_OBJECT_DIAGRAM); + break; + case OBJECTTYPE_DIAGRAM_WALL: + aRet=SchResId(STR_OBJECT_DIAGRAM_WALL); + break; + case OBJECTTYPE_DIAGRAM_FLOOR: + aRet=SchResId(STR_OBJECT_DIAGRAM_FLOOR); + break; + case OBJECTTYPE_AXIS: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_AXES); + else + aRet=SchResId(STR_OBJECT_AXIS); + } + break; + case OBJECTTYPE_AXIS_UNITLABEL: + aRet=SchResId(STR_OBJECT_LABEL);//@todo maybe a more concrete name + break; + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: //maybe todo: different names for subgrids + { + if(bPlural) + aRet=SchResId(STR_OBJECT_GRIDS); + else + aRet=SchResId(STR_OBJECT_GRID); + } + break; + case OBJECTTYPE_DATA_SERIES: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_DATASERIES_PLURAL); + else + aRet=SchResId(STR_OBJECT_DATASERIES); + } + break; + case OBJECTTYPE_DATA_POINT: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_DATAPOINTS); + else + aRet=SchResId(STR_OBJECT_DATAPOINT); + } + break; + case OBJECTTYPE_DATA_LABELS: + aRet=SchResId(STR_OBJECT_DATALABELS); + break; + case OBJECTTYPE_DATA_LABEL: + aRet=SchResId(STR_OBJECT_LABEL); + break; + case OBJECTTYPE_DATA_ERRORS_X: + aRet=SchResId(STR_OBJECT_ERROR_BARS_X); + break; + case OBJECTTYPE_DATA_ERRORS_Y: + aRet=SchResId(STR_OBJECT_ERROR_BARS_Y); + break; + case OBJECTTYPE_DATA_ERRORS_Z: + aRet=SchResId(STR_OBJECT_ERROR_BARS_Z); + break; + case OBJECTTYPE_DATA_AVERAGE_LINE: + aRet=SchResId(STR_OBJECT_AVERAGE_LINE); + break; + case OBJECTTYPE_DATA_CURVE: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_CURVES); + else + aRet=SchResId(STR_OBJECT_CURVE); + } + break; + case OBJECTTYPE_DATA_STOCK_RANGE: + break; + case OBJECTTYPE_DATA_STOCK_LOSS: + aRet=SchResId(STR_OBJECT_STOCK_LOSS); + break; + case OBJECTTYPE_DATA_STOCK_GAIN: + aRet=SchResId(STR_OBJECT_STOCK_GAIN); + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + aRet=SchResId(STR_OBJECT_CURVE_EQUATION); + break; + default: //OBJECTTYPE_UNKNOWN + ; + } + return aRet; +} + +OUString ObjectNameProvider::getAxisName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + Reference< XAxis > xAxis( + ObjectIdentifier::getObjectPropertySet( rObjectCID , xChartModel ), uno::UNO_QUERY ); + + sal_Int32 nCooSysIndex = 0; + sal_Int32 nDimensionIndex = 0; + sal_Int32 nAxisIndex = 0; + AxisHelper::getIndicesForAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ), nCooSysIndex, nDimensionIndex, nAxisIndex ); + + switch(nDimensionIndex) + { + case 0://x-axis + if( nAxisIndex == 0 ) + aRet=SchResId(STR_OBJECT_AXIS_X); + else + aRet=SchResId(STR_OBJECT_SECONDARY_X_AXIS); + break; + case 1://y-axis + if( nAxisIndex == 0 ) + aRet=SchResId(STR_OBJECT_AXIS_Y); + else + aRet=SchResId(STR_OBJECT_SECONDARY_Y_AXIS); + break; + case 2://z-axis + aRet=SchResId(STR_OBJECT_AXIS_Z); + break; + default://axis + aRet=SchResId(STR_OBJECT_AXIS); + break; + } + + return aRet; +} + +OUString ObjectNameProvider::getTitleNameByType( TitleHelper::eTitleType eType ) +{ + OUString aRet; + + switch(eType) + { + case TitleHelper::MAIN_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_MAIN); + break; + case TitleHelper::SUB_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_SUB); + break; + case TitleHelper::X_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_X_AXIS); + break; + case TitleHelper::Y_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_Y_AXIS); + break; + case TitleHelper::Z_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_Z_AXIS); + break; + case TitleHelper::SECONDARY_X_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_SECONDARY_X_AXIS); + break; + case TitleHelper::SECONDARY_Y_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_SECONDARY_Y_AXIS); + break; + default: + OSL_FAIL("unknown title type"); + break; + } + + if( aRet.isEmpty() ) + aRet=SchResId(STR_OBJECT_TITLE); + + return aRet; +} + +OUString ObjectNameProvider::getTitleName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + Reference< XTitle > xTitle( + ObjectIdentifier::getObjectPropertySet( rObjectCID , xChartModel ), uno::UNO_QUERY ); + if( xTitle.is() ) + { + TitleHelper::eTitleType eType; + if( TitleHelper::getTitleType( eType, xTitle, xChartModel ) ) + aRet = ObjectNameProvider::getTitleNameByType( eType ); + } + if( aRet.isEmpty() ) + aRet=SchResId(STR_OBJECT_TITLE); + + return aRet; +} + +OUString ObjectNameProvider::getGridName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + sal_Int32 nCooSysIndex = -1; + sal_Int32 nDimensionIndex = -1; + sal_Int32 nAxisIndex = -1; + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rObjectCID , xChartModel ); + AxisHelper::getIndicesForAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ) + , nCooSysIndex , nDimensionIndex, nAxisIndex ); + + bool bMainGrid = (ObjectIdentifier::getObjectType( rObjectCID ) == OBJECTTYPE_GRID); + + if( bMainGrid ) + { + switch(nDimensionIndex) + { + case 0://x-axis + aRet=SchResId(STR_OBJECT_GRID_MAJOR_X); + break; + case 1://y-axis + aRet=SchResId(STR_OBJECT_GRID_MAJOR_Y); + break; + case 2://z-axis + aRet=SchResId(STR_OBJECT_GRID_MAJOR_Z); + break; + default://axis + aRet=SchResId(STR_OBJECT_GRID); + break; + } + } + else + { + switch(nDimensionIndex) + { + case 0://x-axis + aRet=SchResId(STR_OBJECT_GRID_MINOR_X); + break; + case 1://y-axis + aRet=SchResId(STR_OBJECT_GRID_MINOR_Y); + break; + case 2://z-axis + aRet=SchResId(STR_OBJECT_GRID_MINOR_Z); + break; + default://axis + aRet=SchResId(STR_OBJECT_GRID); + break; + } + } + return aRet; +} + +OUString ObjectNameProvider::getHelpText( const OUString& rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel, bool bVerbose ) +{ + OUString aRet; + ObjectType eObjectType( ObjectIdentifier::getObjectType(rObjectCID) ); + if( eObjectType == OBJECTTYPE_AXIS ) + { + aRet=ObjectNameProvider::getAxisName( rObjectCID, xChartModel ); + } + else if( eObjectType == OBJECTTYPE_GRID + || eObjectType == OBJECTTYPE_SUBGRID ) + { + aRet=ObjectNameProvider::getGridName( rObjectCID, xChartModel ); + } + else if( eObjectType == OBJECTTYPE_TITLE ) + { + aRet=ObjectNameProvider::getTitleName( rObjectCID, xChartModel ); + } + else if( eObjectType == OBJECTTYPE_DATA_SERIES ) + { + aRet = lcl_getFullSeriesName( rObjectCID, xChartModel ); + } + else if( eObjectType == OBJECTTYPE_DATA_POINT ) + { + if( bVerbose ) + { + aRet= SchResId(STR_TIP_DATAPOINT_INDEX) + "\n" + + SchResId(STR_TIP_DATASERIES) + "\n" + + SchResId(STR_TIP_DATAPOINT_VALUES); + } + else + aRet=SchResId(STR_TIP_DATAPOINT); + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartModel ); + if( xDiagram.is() && xSeries.is() ) + { + sal_Int32 nPointIndex = o3tl::toInt32(ObjectIdentifier::getParticleID(rObjectCID)); + + //replace data point index + OUString aWildcard( "%POINTNUMBER" ); + sal_Int32 nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), OUString::number(nPointIndex+1) ); + } + + //replace data series index + aWildcard = "%SERIESNUMBER"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + sal_Int32 nSeriesIndex = -1; + for( nSeriesIndex=aSeriesVector.size();nSeriesIndex--;) + { + if( aSeriesVector[nSeriesIndex] == xSeries ) + { + break; + } + } + + OUString aReplacement( OUString::number(nSeriesIndex+1) ); + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), aReplacement ); + } + + //replace point values + aWildcard = "%POINTVALUES"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), lcl_getDataPointValueText( + xSeries,nPointIndex, DataSeriesHelper::getCoordinateSystemOfSeries(xSeries, xDiagram), xChartModel ) ); + + //replace series name + aWildcard = "%SERIESNAME"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), lcl_getDataSeriesName( rObjectCID, xChartModel ) ); + } + } + else if( eObjectType == OBJECTTYPE_DATA_CURVE ) + { + if( bVerbose ) + { + aRet = SchResId( STR_OBJECT_CURVE_WITH_PARAMETERS ); + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartModel )); + + if( xSeries.is()) + { + sal_Int32 nCurveIndex = ObjectIdentifier::getIndexFromParticleOrCID( rObjectCID ); + rtl::Reference< RegressionCurveModel > xCurve = RegressionCurveHelper::getRegressionCurveAtIndex(xSeries, nCurveIndex); + if( xCurve.is()) + { + try + { + Reference< chart2::XRegressionCurveCalculator > xCalculator( xCurve->getCalculator(), uno::UNO_SET_THROW ); + sal_Int32 aDegree = 2; + sal_Int32 aPeriod = 2; + sal_Int32 aMovingType = css::chart2::MovingAverageType::Prior; + bool bForceIntercept = false; + double aInterceptValue = 0.0; + OUString aXName ("x"), aYName ("f(x)"); + const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper(); + const OUString& aNumDecimalSep = rLocaleDataWrapper.getNumDecimalSep(); + sal_Unicode cDecSeparator = aNumDecimalSep[0]; + + xCurve->getPropertyValue( "PolynomialDegree") >>= aDegree; + xCurve->getPropertyValue( "MovingAveragePeriod") >>= aPeriod; + xCurve->getPropertyValue( "MovingAverageType") >>= aMovingType; + xCurve->getPropertyValue( "ForceIntercept") >>= bForceIntercept; + if (bForceIntercept) + xCurve->getPropertyValue( "InterceptValue") >>= aInterceptValue; + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + if( xEqProp.is()) + { + if ( !(xEqProp->getPropertyValue( "XName") >>= aXName) ) + aXName = "x"; + if ( !(xEqProp->getPropertyValue( "YName") >>= aYName) ) + aYName = "f(x)"; + } + xCalculator->setRegressionProperties(aDegree, bForceIntercept, aInterceptValue, 2, aMovingType); + xCalculator->setXYNames ( aXName, aYName ); + RegressionCurveHelper::initializeCurveCalculator( xCalculator, xSeries, xChartModel ); + + // change text for Moving Average + OUString aWildcard( "%PERIOD" ); + sal_Int32 nIndex = xCalculator->getRepresentation().indexOf( aWildcard ); + if( nIndex != -1 ) + { // replace period + aRet = xCalculator->getRepresentation(); + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), OUString::number(aPeriod) ); + } + + // replace formula + aWildcard = "%FORMULA"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + OUString aFormula ( xCalculator->getRepresentation() ); + if ( cDecSeparator != '.' ) + { + aFormula = aFormula.replace( '.', cDecSeparator ); + } + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), aFormula ); + } + + // replace r^2 + aWildcard = "%RSQUARED"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + double fR( xCalculator->getCorrelationCoefficient()); + aRet = aRet.replaceAt( + nIndex, aWildcard.getLength(), + ::rtl::math::doubleToUString( + fR*fR, rtl_math_StringFormat_G, 4, cDecSeparator, true )); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + else + { + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID(rObjectCID , xChartModel)); + aRet += getName(eObjectType); + + if( xSeries.is()) + { + sal_Int32 nCurveIndex = ObjectIdentifier::getIndexFromParticleOrCID( rObjectCID ); + rtl::Reference< RegressionCurveModel > xCurve( RegressionCurveHelper::getRegressionCurveAtIndex(xSeries, nCurveIndex) ); + if( xCurve.is()) + { + aRet += " (" + RegressionCurveHelper::getRegressionCurveName(xCurve) + " )"; + } + } + } + } + else if( eObjectType == OBJECTTYPE_DATA_AVERAGE_LINE ) + { + if( bVerbose ) + { + aRet = SchResId(STR_OBJECT_AVERAGE_LINE_WITH_PARAMETERS); + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartModel )); + if( xSeries.is()) + { + rtl::Reference< RegressionCurveModel > xCurve( RegressionCurveHelper::getMeanValueLine( xSeries )); + if( xCurve.is()) + { + try + { + Reference< chart2::XRegressionCurveCalculator > xCalculator( xCurve->getCalculator(), uno::UNO_SET_THROW ); + RegressionCurveHelper::initializeCurveCalculator( xCalculator, xSeries, xChartModel ); + + const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper(); + const OUString& aNumDecimalSep = rLocaleDataWrapper.getNumDecimalSep(); + sal_Unicode cDecSeparator = aNumDecimalSep[0]; + + OUString aWildcard( "%AVERAGE_VALUE" ); + sal_Int32 nIndex = aRet.indexOf( aWildcard ); + // as the curve is constant, the value at any x-value is ok + if( nIndex != -1 ) + { + const double fMeanValue( xCalculator->getCurveValue( 0.0 )); + aRet = aRet.replaceAt( + nIndex, aWildcard.getLength(), + ::rtl::math::doubleToUString( + fMeanValue, rtl_math_StringFormat_G, 4, cDecSeparator, true )); + } + + // replace standard deviation + aWildcard = "%STD_DEVIATION"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + const double fStdDev( xCalculator->getCorrelationCoefficient()); + aRet = aRet.replaceAt( + nIndex, aWildcard.getLength(), + ::rtl::math::doubleToUString( + fStdDev, rtl_math_StringFormat_G, 4, cDecSeparator, true )); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + else + { + // non-verbose + aRet = ObjectNameProvider::getName( eObjectType ); + } + } + else + { + aRet = ObjectNameProvider::getName( eObjectType ); + } + return aRet; +} + +OUString ObjectNameProvider::getSelectedObjectText( const OUString & rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + OUString aRet; + ObjectType eObjectType( ObjectIdentifier::getObjectType(rObjectCID) ); + + if( eObjectType == OBJECTTYPE_DATA_POINT ) + { + aRet = SchResId( STR_STATUS_DATAPOINT_MARKED ); + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartDocument ) ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartDocument ); + if( xDiagram.is() && xSeries.is() ) + { + sal_Int32 nPointIndex = o3tl::toInt32( ObjectIdentifier::getParticleID(rObjectCID) ); + + // replace data point index + replaceParamterInString( aRet, "%POINTNUMBER", OUString::number( nPointIndex + 1 )); + + // replace data series index + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector( + DiagramHelper::getDataSeriesFromDiagram( xDiagram ) ); + sal_Int32 nSeriesIndex = -1; + for( nSeriesIndex=aSeriesVector.size();nSeriesIndex--;) + { + if( aSeriesVector[nSeriesIndex] == xSeries ) + break; + } + replaceParamterInString( aRet, "%SERIESNUMBER", OUString::number( nSeriesIndex + 1 ) ); + } + + // replace point value + replaceParamterInString( aRet, "%POINTVALUES", lcl_getDataPointValueText( + xSeries, nPointIndex, DataSeriesHelper::getCoordinateSystemOfSeries(xSeries, xDiagram), xChartDocument ) ); + } + } + else + { + // use the verbose text including the formula for trend lines + const bool bVerbose( eObjectType == OBJECTTYPE_DATA_CURVE || eObjectType == OBJECTTYPE_DATA_AVERAGE_LINE ); + const OUString aHelpText( getHelpText( rObjectCID, xChartDocument, bVerbose )); + if( !aHelpText.isEmpty()) + { + aRet = SchResId( STR_STATUS_OBJECT_MARKED ); + replaceParamterInString( aRet, "%OBJECTNAME", aHelpText ); + } + } + + return aRet; +} + +OUString ObjectNameProvider::getNameForCID( + const OUString& rObjectCID, + const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + ObjectType eType( ObjectIdentifier::getObjectType( rObjectCID )); + + switch( eType ) + { + case OBJECTTYPE_AXIS: + return getAxisName( rObjectCID, xChartDocument ); + case OBJECTTYPE_TITLE: + return getTitleName( rObjectCID, xChartDocument ); + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + return getGridName( rObjectCID, xChartDocument ); + case OBJECTTYPE_DATA_SERIES: + return lcl_getFullSeriesName( rObjectCID, xChartDocument ); + case OBJECTTYPE_DATA_POINT: + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_CURVE: + case OBJECTTYPE_DATA_CURVE_EQUATION: + { + OUString aRet = lcl_getFullSeriesName( rObjectCID, xChartDocument ) + " "; + if( eType == OBJECTTYPE_DATA_POINT || eType == OBJECTTYPE_DATA_LABEL ) + { + aRet += getName( OBJECTTYPE_DATA_POINT ); + sal_Int32 nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( rObjectCID ); + aRet += " " + OUString::number(nPointIndex+1); + if( eType == OBJECTTYPE_DATA_LABEL ) + { + aRet += " " + getName( OBJECTTYPE_DATA_LABEL ); + } + } + else if (eType == OBJECTTYPE_DATA_CURVE || eType == OBJECTTYPE_DATA_CURVE_EQUATION) + { + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartDocument )); + + aRet += " " + getName(eType); + + if( xSeries.is()) + { + sal_Int32 nCurveIndex = ObjectIdentifier::getIndexFromParticleOrCID( rObjectCID ); + rtl::Reference< RegressionCurveModel > xCurve( RegressionCurveHelper::getRegressionCurveAtIndex(xSeries, nCurveIndex) ); + if( xCurve.is()) + { + aRet += " (" + RegressionCurveHelper::getRegressionCurveName(xCurve) + ")"; + } + } + } + else + { + aRet += getName( eType ); + } + return aRet; + } + default: + break; + } + + return getName( eType ); +} + +OUString ObjectNameProvider::getName_ObjectForSeries( + ObjectType eObjectType, + const OUString& rSeriesCID, + const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rSeriesCID , xChartDocument ); + if( xSeries.is() ) + { + OUString aRet = SchResId(STR_OBJECT_FOR_SERIES); + replaceParamterInString( aRet, "%OBJECTNAME", getName( eObjectType ) ); + replaceParamterInString( aRet, "%SERIESNAME", lcl_getDataSeriesName( rSeriesCID, xChartDocument ) ); + return aRet; + } + else + return ObjectNameProvider::getName_ObjectForAllSeries( eObjectType ); +} + +OUString ObjectNameProvider::getName_ObjectForAllSeries( ObjectType eObjectType ) +{ + OUString aRet = SchResId(STR_OBJECT_FOR_ALL_SERIES); + replaceParamterInString( aRet, "%OBJECTNAME", getName( eObjectType, true /*bPlural*/ ) ); + return aRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/RangeSelectionHelper.cxx b/chart2/source/controller/dialogs/RangeSelectionHelper.cxx new file mode 100644 index 000000000..ede420f07 --- /dev/null +++ b/chart2/source/controller/dialogs/RangeSelectionHelper.cxx @@ -0,0 +1,177 @@ +/* -*- 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 <RangeSelectionHelper.hxx> +#include <RangeSelectionListener.hxx> +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/chart2/data/XDataProvider.hpp> +#include <tools/diagnose_ex.h> +#include <ChartModel.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +RangeSelectionHelper::RangeSelectionHelper( + const rtl::Reference<::chart::ChartModel> & xChartDocument ) : + m_xChartDocument( xChartDocument ) +{} + +RangeSelectionHelper::~RangeSelectionHelper() +{} + +bool RangeSelectionHelper::hasRangeSelection() +{ + return getRangeSelection().is(); +} + +Reference< sheet::XRangeSelection > const & RangeSelectionHelper::getRangeSelection() +{ + if( !m_xRangeSelection.is() && + m_xChartDocument.is() ) + { + try + { + Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider()); + if( xDataProvider.is()) + m_xRangeSelection.set( xDataProvider->getRangeSelection()); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + + m_xRangeSelection.clear(); + } + } + + return m_xRangeSelection; +} + +void RangeSelectionHelper::raiseRangeSelectionDocument() +{ + Reference< sheet::XRangeSelection > xRangeSel( getRangeSelection()); + if( !xRangeSel.is()) + return; + + try + { + // bring document to front + Reference< frame::XController > xCtrl( xRangeSel, uno::UNO_QUERY ); + if( xCtrl.is()) + { + Reference< frame::XFrame > xFrame( xCtrl->getFrame()); + if( xFrame.is()) + { + Reference< awt::XTopWindow > xWin( xFrame->getContainerWindow(), + uno::UNO_QUERY_THROW ); + xWin->toFront(); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool RangeSelectionHelper::chooseRange( + const OUString & aCurrentRange, + const OUString & aUIString, + RangeSelectionListenerParent & rListenerParent ) +{ + ControllerLockGuardUNO aGuard( m_xChartDocument ); + + bool bResult = true; + raiseRangeSelectionDocument(); + + try + { + Reference< sheet::XRangeSelection > xRangeSel( getRangeSelection()); + if( xRangeSel.is()) + { + Sequence< beans::PropertyValue > aArgs{ + beans::PropertyValue( + "InitialValue", -1, uno::Any( aCurrentRange ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "Title", -1, + uno::Any( aUIString ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "CloseOnMouseRelease", -1, uno::Any( true ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "MultiSelectionMode", -1, uno::Any( true ), + beans::PropertyState_DIRECT_VALUE ) + }; + if( m_xRangeSelectionListener.is() ) + stopRangeListening(); + m_xRangeSelectionListener.set( Reference< sheet::XRangeSelectionListener >( + new RangeSelectionListener( rListenerParent, aCurrentRange, m_xChartDocument ))); + + xRangeSel->addRangeSelectionListener( m_xRangeSelectionListener ); + xRangeSel->startRangeSelection( aArgs ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + bResult = false; + } + + return bResult; +} + +void RangeSelectionHelper::stopRangeListening( bool bRemoveListener /* = true */ ) +{ + if( bRemoveListener && + m_xRangeSelectionListener.is() && + m_xRangeSelection.is() ) + { + m_xRangeSelection->removeRangeSelectionListener( m_xRangeSelectionListener ); + } + + m_xRangeSelectionListener = nullptr; +} + +bool RangeSelectionHelper::verifyCellRange( const OUString & rRangeStr ) +{ + Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider()); + if( ! xDataProvider.is()) + return false; + + return xDataProvider->createDataSequenceByRangeRepresentationPossible( rRangeStr ); +} + +bool RangeSelectionHelper::verifyArguments( const Sequence< beans::PropertyValue > & rArguments ) +{ + Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider()); + if( ! xDataProvider.is()) + return false; + + return xDataProvider->createDataSourcePossible( rArguments ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/RangeSelectionListener.cxx b/chart2/source/controller/dialogs/RangeSelectionListener.cxx new file mode 100644 index 000000000..473ad909f --- /dev/null +++ b/chart2/source/controller/dialogs/RangeSelectionListener.cxx @@ -0,0 +1,62 @@ +/* -*- 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 <RangeSelectionListener.hxx> +#include <ChartModel.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +RangeSelectionListener::RangeSelectionListener( + RangeSelectionListenerParent & rParent, + const OUString & rInitialRange, + const rtl::Reference<::chart::ChartModel>& xModelToLockController ) : + m_rParent( rParent ), + m_aRange( rInitialRange ), + m_aControllerLockGuard( xModelToLockController ) +{} + +RangeSelectionListener::~RangeSelectionListener() +{} + +// ____ XRangeSelectionListener ____ +void SAL_CALL RangeSelectionListener::done( const sheet::RangeSelectionEvent& aEvent ) +{ + m_aRange = aEvent.RangeDescriptor; + m_rParent.listeningFinished( m_aRange ); +} + +void SAL_CALL RangeSelectionListener::aborted( const sheet::RangeSelectionEvent& /*aEvent*/ ) +{ + m_rParent.listeningFinished( m_aRange ); +} + +// ____ XEventListener ____ +void SAL_CALL RangeSelectionListener::disposing( const lang::EventObject& /*Source*/ ) +{ + m_rParent.disposingRangeSelection(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/TextDirectionListBox.cxx b/chart2/source/controller/dialogs/TextDirectionListBox.cxx new file mode 100644 index 000000000..68181fdfc --- /dev/null +++ b/chart2/source/controller/dialogs/TextDirectionListBox.cxx @@ -0,0 +1,36 @@ +/* -*- 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 <TextDirectionListBox.hxx> +#include <ResId.hxx> +#include <strings.hrc> + +namespace chart +{ +TextDirectionListBox::TextDirectionListBox(std::unique_ptr<weld::ComboBox> pControl) + : svx::FrameDirectionListBox(std::move(pControl)) +{ + append(SvxFrameDirection::Horizontal_LR_TB, SchResId(STR_TEXT_DIRECTION_LTR)); + append(SvxFrameDirection::Horizontal_RL_TB, SchResId(STR_TEXT_DIRECTION_RTL)); + append(SvxFrameDirection::Environment, SchResId(STR_TEXT_DIRECTION_SUPER)); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/TimerTriggeredControllerLock.cxx b/chart2/source/controller/dialogs/TimerTriggeredControllerLock.cxx new file mode 100644 index 000000000..89dbc3aca --- /dev/null +++ b/chart2/source/controller/dialogs/TimerTriggeredControllerLock.cxx @@ -0,0 +1,51 @@ +/* -*- 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 <TimerTriggeredControllerLock.hxx> +#include <ControllerLockGuard.hxx> +#include <ChartModel.hxx> + +namespace chart +{ +using namespace ::com::sun::star; + +TimerTriggeredControllerLock::TimerTriggeredControllerLock( + const rtl::Reference<::chart::ChartModel>& xModel) + : m_xModel(xModel) + , m_aTimer("chart2 TimerTriggeredControllerLock") +{ + m_aTimer.SetTimeout(4 * EDIT_UPDATEDATA_TIMEOUT); + m_aTimer.SetInvokeHandler(LINK(this, TimerTriggeredControllerLock, TimerTimeout)); +} +TimerTriggeredControllerLock::~TimerTriggeredControllerLock() { m_aTimer.Stop(); } + +void TimerTriggeredControllerLock::startTimer() +{ + if (!m_apControllerLockGuard) + m_apControllerLockGuard.reset(new ControllerLockGuardUNO(m_xModel)); + m_aTimer.Start(); +} +IMPL_LINK_NOARG(TimerTriggeredControllerLock, TimerTimeout, Timer*, void) +{ + m_apControllerLockGuard.reset(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/TitleDialogData.cxx b/chart2/source/controller/dialogs/TitleDialogData.cxx new file mode 100644 index 000000000..2a8b74465 --- /dev/null +++ b/chart2/source/controller/dialogs/TitleDialogData.cxx @@ -0,0 +1,113 @@ +/* -*- 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 <sal/config.h> + +#include <TitleDialogData.hxx> +#include <TitleHelper.hxx> +#include <ChartModelHelper.hxx> +#include <Diagram.hxx> +#include <AxisHelper.hxx> +#include <ChartModel.hxx> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +TitleDialogData::TitleDialogData( std::unique_ptr<ReferenceSizeProvider> pRefSizeProvider ) + : aPossibilityList{ true, true, true, true, true, true, true } + , aExistenceList{ false, false, false, false, false, false, false } + , aTextList(7) + , apReferenceSizeProvider( std::move(pRefSizeProvider) ) +{ +} + +void TitleDialogData::readFromModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(xChartModel); + + //get possibilities + uno::Sequence< sal_Bool > aAxisPossibilityList; + AxisHelper::getAxisOrGridPossibilities( aAxisPossibilityList, xDiagram ); + sal_Bool* pPossibilityList = aPossibilityList.getArray(); + pPossibilityList[2]=aAxisPossibilityList[0];//x axis title + pPossibilityList[3]=aAxisPossibilityList[1];//y axis title + pPossibilityList[4]=aAxisPossibilityList[2];//z axis title + pPossibilityList[5]=aAxisPossibilityList[3];//secondary x axis title + pPossibilityList[6]=aAxisPossibilityList[4];//secondary y axis title + + sal_Bool* pExistenceList = aExistenceList.getArray(); + auto pTextList = aTextList.getArray(); + //find out which title exists and get their text + //main title: + for( auto nTitleIndex = +TitleHelper::TITLE_BEGIN; + nTitleIndex < +TitleHelper::NORMAL_TITLE_END; + nTitleIndex++) + { + uno::Reference< XTitle > xTitle = TitleHelper::getTitle( + static_cast< TitleHelper::eTitleType >( nTitleIndex ), xChartModel ); + pExistenceList[nTitleIndex] = xTitle.is(); + pTextList[nTitleIndex]=TitleHelper::getCompleteString( xTitle ); + } +} + +bool TitleDialogData::writeDifferenceToModel( + const rtl::Reference<::chart::ChartModel>& xChartModel + , const uno::Reference< uno::XComponentContext >& xContext + , const TitleDialogData* pOldState ) +{ + bool bChanged = false; + for( auto nN = +TitleHelper::TITLE_BEGIN; + nN < +TitleHelper::NORMAL_TITLE_END; + nN++) + { + if( !pOldState || ( pOldState->aExistenceList[nN] != aExistenceList[nN] ) ) + { + if(aExistenceList[nN]) + { + TitleHelper::createTitle( + static_cast< TitleHelper::eTitleType >( nN ), aTextList[nN], xChartModel, xContext, + apReferenceSizeProvider.get() ); + bChanged = true; + } + else + { + TitleHelper::removeTitle( static_cast< TitleHelper::eTitleType >( nN ), xChartModel ); + bChanged = true; + } + } + else if( !pOldState || ( pOldState->aTextList[nN] != aTextList[nN] ) ) + { + //change content + uno::Reference< XTitle > xTitle( + TitleHelper::getTitle( static_cast< TitleHelper::eTitleType >( nN ), xChartModel ) ); + if(xTitle.is()) + { + TitleHelper::setCompleteString( aTextList[nN], xTitle, xContext ); + bChanged = true; + } + } + } + return bChanged; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ChartType.cxx b/chart2/source/controller/dialogs/dlg_ChartType.cxx new file mode 100644 index 000000000..b62ac2215 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ChartType.cxx @@ -0,0 +1,45 @@ +/* -*- 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 <dlg_ChartType.hxx> +#include "tp_ChartType.hxx" +#include <ChartModel.hxx> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +ChartTypeDialog::ChartTypeDialog(weld::Window* pParent, + const rtl::Reference<::chart::ChartModel>& xChartModel) + : GenericDialogController(pParent, "modules/schart/ui/charttypedialog.ui", "ChartTypeDialog") + , m_xChartModel(xChartModel) + , m_xContentArea(m_xDialog->weld_content_area()) +{ + m_xChartTypeTabPage = std::make_unique<ChartTypeTabPage>( + m_xContentArea.get(), this, m_xChartModel, false /*don't show title description*/); + + m_xChartTypeTabPage->initializePage(); +} + +ChartTypeDialog::~ChartTypeDialog() { m_xChartTypeTabPage.reset(); } + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ChartType_UNO.cxx b/chart2/source/controller/dialogs/dlg_ChartType_UNO.cxx new file mode 100644 index 000000000..0e95cd75c --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ChartType_UNO.cxx @@ -0,0 +1,113 @@ +/* -*- 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 <dlg_ChartType_UNO.hxx> +#include <dlg_ChartType.hxx> +#include <ChartModel.hxx> +#include <servicenames.hxx> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> + +namespace com::sun::star::awt { class XWindow; } + +namespace chart +{ +using namespace ::com::sun::star; +ChartTypeUnoDlg::ChartTypeUnoDlg( const uno::Reference< uno::XComponentContext >& _xContext ) + : ChartTypeUnoDlg_BASE( _xContext ) +{ +} +ChartTypeUnoDlg::~ChartTypeUnoDlg() +{ + // we do this here cause the base class' call to destroyDialog won't reach us anymore: we're within a dtor, + // so this virtual-method-call the base class does not work, we're already dead then... + if (m_xDialog) + { + ::osl::MutexGuard aGuard(m_aMutex); + if (m_xDialog) + destroyDialog(); + } +} +// lang::XServiceInfo +OUString SAL_CALL ChartTypeUnoDlg::getImplementationName() +{ + return CHART_TYPE_DIALOG_SERVICE_IMPLEMENTATION_NAME; +} + +css::uno::Sequence<OUString> SAL_CALL ChartTypeUnoDlg::getSupportedServiceNames() +{ + return { CHART_TYPE_DIALOG_SERVICE_NAME }; +} +uno::Sequence< sal_Int8 > SAL_CALL ChartTypeUnoDlg::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} +void ChartTypeUnoDlg::implInitialize(const uno::Any& _rValue) +{ + beans::PropertyValue aProperty; + if (_rValue >>= aProperty) + { + if (aProperty.Name == "ChartModel") + { + uno::Reference<XInterface> xInt; + aProperty.Value >>= xInt; + assert(dynamic_cast<::chart::ChartModel*>(xInt.get())); + m_xChartModel = dynamic_cast<::chart::ChartModel*>(xInt.get()); + } + else + ChartTypeUnoDlg_BASE::implInitialize(_rValue); + } + else + ChartTypeUnoDlg_BASE::implInitialize(_rValue); +} + +std::unique_ptr<weld::DialogController> ChartTypeUnoDlg::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + ChartModel* pChartModel = dynamic_cast<ChartModel*>(rParent.get()); + assert(pChartModel); + return std::make_unique<ChartTypeDialog>(Application::GetFrameWeld(rParent), pChartModel); +} + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ChartTypeUnoDlg::getPropertySetInfo() +{ + return createPropertySetInfo( getInfoHelper() ); +} + +::cppu::IPropertyArrayHelper& ChartTypeUnoDlg::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* ChartTypeUnoDlg::createArrayHelper( ) const +{ + uno::Sequence< beans::Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartTypeDialog_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new chart::ChartTypeUnoDlg(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_CreationWizard.cxx b/chart2/source/controller/dialogs/dlg_CreationWizard.cxx new file mode 100644 index 000000000..988386eea --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_CreationWizard.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 <dlg_CreationWizard.hxx> +#include <ResId.hxx> +#include <strings.hrc> +#include <helpids.h> +#include <ChartModel.hxx> + +#include "tp_ChartType.hxx" +#include "tp_RangeChooser.hxx" +#include "tp_Wizard_TitlesAndObjects.hxx" +#include "tp_DataSource.hxx" +#include <ChartTypeTemplateProvider.hxx> +#include <ChartTypeTemplate.hxx> +#include "DialogModel.hxx" + +using namespace css; + +using vcl::RoadmapWizardTypes::WizardPath; + +namespace chart +{ +#define PATH_FULL 1 +#define STATE_FIRST 0 +#define STATE_CHARTTYPE STATE_FIRST +#define STATE_SIMPLE_RANGE 1 +#define STATE_DATA_SERIES 2 +#define STATE_OBJECTS 3 +#define STATE_LAST STATE_OBJECTS + +CreationWizard::CreationWizard(weld::Window* pParent, const rtl::Reference<::chart::ChartModel>& xChartModel, + const uno::Reference<uno::XComponentContext>& xContext) + : vcl::RoadmapWizardMachine(pParent) + , m_xChartModel(xChartModel,uno::UNO_QUERY) + , m_xComponentContext(xContext) + , m_pTemplateProvider(nullptr) + , m_aTimerTriggeredControllerLock(xChartModel) + , m_bCanTravel(true) +{ + m_pDialogModel.reset(new DialogModel(m_xChartModel)); + defaultButton(WizardButtonFlags::FINISH); + + setTitleBase(SchResId(STR_DLG_CHART_WIZARD)); + + // tdf#134386 set m_pTemplateProvider before creating any other pages + m_pTemplateProvider = static_cast<ChartTypeTabPage*>(GetOrCreatePage(STATE_CHARTTYPE)); + assert(m_pTemplateProvider && "must exist"); + m_pDialogModel->setTemplate(m_pTemplateProvider->getCurrentTemplate()); + + WizardPath aPath = { + STATE_CHARTTYPE, + STATE_SIMPLE_RANGE, + STATE_DATA_SERIES, + STATE_OBJECTS + }; + + declarePath(PATH_FULL, aPath); + + // tdf#135935 ensure help ID is set when no element is clicked in the dialog + m_xAssistant->set_help_id(HID_SCH_WIZARD_ROADMAP); + + if (!m_pDialogModel->getModel().isDataFromSpreadsheet()) + { + enableState(STATE_SIMPLE_RANGE, false); + enableState(STATE_DATA_SERIES, false); + } + + // Call ActivatePage, to create and activate the first page + ActivatePage(); + + m_xAssistant->set_current_page(0); +} + +CreationWizard::~CreationWizard() = default; + +std::unique_ptr<BuilderPage> CreationWizard::createPage(WizardState nState) +{ + std::unique_ptr<vcl::OWizardPage> xRet; + + OString sIdent(OString::number(nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch( nState ) + { + case STATE_CHARTTYPE: + { + m_aTimerTriggeredControllerLock.startTimer(); + xRet = std::make_unique<ChartTypeTabPage>(pPageContainer, this, m_xChartModel); + break; + } + case STATE_SIMPLE_RANGE: + { + m_aTimerTriggeredControllerLock.startTimer(); + xRet = std::make_unique<RangeChooserTabPage>(pPageContainer, this, *m_pDialogModel, m_pTemplateProvider); + break; + } + case STATE_DATA_SERIES: + { + m_aTimerTriggeredControllerLock.startTimer(); + xRet = std::make_unique<DataSourceTabPage>(pPageContainer, this, *m_pDialogModel, m_pTemplateProvider); + break; + } + case STATE_OBJECTS: + { + xRet = std::make_unique<TitlesAndObjectsTabPage>(pPageContainer, this, m_xChartModel, m_xComponentContext); + m_aTimerTriggeredControllerLock.startTimer(); + break; + } + default: + break; + } + + if (xRet) + xRet->SetPageTitle(OUString()); //remove title of pages to not get them in the wizard title + + return xRet; +} + +bool CreationWizard::leaveState( WizardState /*_nState*/ ) +{ + return m_bCanTravel; +} + +vcl::WizardTypes::WizardState CreationWizard::determineNextState( WizardState nCurrentState ) const +{ + if( !m_bCanTravel ) + return WZS_INVALID_STATE; + if( nCurrentState == STATE_LAST ) + return WZS_INVALID_STATE; + vcl::WizardTypes::WizardState nNextState = nCurrentState + 1; + while( !isStateEnabled( nNextState ) && nNextState <= STATE_LAST ) + ++nNextState; + return (nNextState==STATE_LAST+1) ? WZS_INVALID_STATE : nNextState; +} + +void CreationWizard::enterState(WizardState nState) +{ + m_aTimerTriggeredControllerLock.startTimer(); + enableButtons( WizardButtonFlags::PREVIOUS, nState > STATE_FIRST ); + enableButtons( WizardButtonFlags::NEXT, nState < STATE_LAST ); + if( isStateEnabled( nState )) + vcl::RoadmapWizardMachine::enterState(nState); +} + +void CreationWizard::setInvalidPage(BuilderPage* pTabPage) +{ + if (pTabPage == m_pCurTabPage) + m_bCanTravel = false; +} + +void CreationWizard::setValidPage(BuilderPage* pTabPage) +{ + if (pTabPage == m_pCurTabPage) + m_bCanTravel = true; +} + +OUString CreationWizard::getStateDisplayName( WizardState nState ) const +{ + TranslateId pResId; + switch( nState ) + { + case STATE_CHARTTYPE: + pResId = STR_PAGE_CHARTTYPE; + break; + case STATE_SIMPLE_RANGE: + pResId = STR_PAGE_DATA_RANGE; + break; + case STATE_DATA_SERIES: + pResId = STR_OBJECT_DATASERIES_PLURAL; + break; + case STATE_OBJECTS: + pResId = STR_PAGE_CHART_ELEMENTS; + break; + default: + break; + } + if (!pResId) + return OUString(); + return SchResId(pResId); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_CreationWizard_UNO.cxx b/chart2/source/controller/dialogs/dlg_CreationWizard_UNO.cxx new file mode 100644 index 000000000..973b8fa74 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_CreationWizard_UNO.cxx @@ -0,0 +1,351 @@ +/* -*- 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 <dlg_CreationWizard_UNO.hxx> +#include <dlg_CreationWizard.hxx> +#include <ChartModel.hxx> +#include <servicenames.hxx> +#include <TimerTriggeredControllerLock.hxx> +#include <vcl/svapp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <tools/diagnose_ex.h> +#include <sfx2/viewsh.hxx> + +namespace chart +{ +using namespace ::com::sun::star; + +CreationWizardUnoDlg::CreationWizardUnoDlg(const uno::Reference<uno::XComponentContext>& xContext) + : OComponentHelper(m_aMutex) + , m_xCC(xContext) + , m_bUnlockControllersOnExecute(false) +{ + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(m_xCC); + uno::Reference< frame::XTerminateListener > xListener( this ); + xDesktop->addTerminateListener( xListener ); +} + +CreationWizardUnoDlg::~CreationWizardUnoDlg() +{ + SolarMutexGuard aSolarGuard; + m_xDialog.reset(); +} + +// lang::XServiceInfo +OUString SAL_CALL CreationWizardUnoDlg::getImplementationName() +{ + return CHART_WIZARD_DIALOG_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL CreationWizardUnoDlg::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CreationWizardUnoDlg::getSupportedServiceNames() +{ + return { CHART_WIZARD_DIALOG_SERVICE_NAME }; +} + +// XInterface +uno::Any SAL_CALL CreationWizardUnoDlg::queryInterface( const uno::Type& aType ) +{ + return OComponentHelper::queryInterface( aType ); +} +void SAL_CALL CreationWizardUnoDlg::acquire() noexcept +{ + OComponentHelper::acquire(); +} +void SAL_CALL CreationWizardUnoDlg::release() noexcept +{ + OComponentHelper::release(); +} +uno::Any SAL_CALL CreationWizardUnoDlg::queryAggregation( uno::Type const & rType ) +{ + if (rType == cppu::UnoType<ui::dialogs::XAsynchronousExecutableDialog>::get()) + { + void * p = static_cast< ui::dialogs::XAsynchronousExecutableDialog * >( this ); + return uno::Any( &p, rType ); + } + else if (rType == cppu::UnoType<lang::XServiceInfo>::get()) + { + void * p = static_cast< lang::XServiceInfo * >( this ); + return uno::Any( &p, rType ); + } + else if (rType == cppu::UnoType<lang::XInitialization>::get()) + { + void * p = static_cast< lang::XInitialization * >( this ); + return uno::Any( &p, rType ); + } + else if (rType == cppu::UnoType<frame::XTerminateListener>::get()) + { + void * p = static_cast< frame::XTerminateListener * >( this ); + return uno::Any( &p, rType ); + } + else if (rType == cppu::UnoType<beans::XPropertySet>::get()) + { + void * p = static_cast< beans::XPropertySet * >( this ); + return uno::Any( &p, rType ); + } + return OComponentHelper::queryAggregation( rType ); +} + +uno::Sequence< uno::Type > CreationWizardUnoDlg::getTypes() +{ + static uno::Sequence<uno::Type> aTypeList{ cppu::UnoType<lang::XComponent>::get(), + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<uno::XAggregation>::get(), + cppu::UnoType<uno::XWeak>::get(), + cppu::UnoType<lang::XServiceInfo>::get(), + cppu::UnoType<lang::XInitialization>::get(), + cppu::UnoType<frame::XTerminateListener>::get(), + cppu::UnoType<ui::dialogs::XAsynchronousExecutableDialog>::get(), + cppu::UnoType<beans::XPropertySet>::get() }; + return aTypeList; +} + +uno::Sequence< sal_Int8 > SAL_CALL CreationWizardUnoDlg::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// XTerminateListener +void SAL_CALL CreationWizardUnoDlg::queryTermination( const lang::EventObject& /*Event*/ ) +{ +} + +void SAL_CALL CreationWizardUnoDlg::notifyTermination( const lang::EventObject& /*Event*/ ) +{ + // we are going down, so dispose us! + dispose(); +} + +void SAL_CALL CreationWizardUnoDlg::disposing( const lang::EventObject& /*Source*/ ) +{ + //Listener should deregister himself and release all references to the closing object. +} + +void SAL_CALL CreationWizardUnoDlg::setDialogTitle( const OUString& /*rTitle*/ ) +{ +} +void CreationWizardUnoDlg::createDialogOnDemand() +{ + SolarMutexGuard aSolarGuard; + if (m_xDialog) + return; + + if( !m_xParentWindow.is() && m_xChartModel.is() ) + { + uno::Reference< frame::XController > xController( + m_xChartModel->getCurrentController() ); + if( xController.is() ) + { + uno::Reference< frame::XFrame > xFrame( + xController->getFrame() ); + if(xFrame.is()) + m_xParentWindow = xFrame->getContainerWindow(); + } + } + uno::Reference< XComponent > xKeepAlive( this ); + if( m_xChartModel.is() ) + { + m_xDialog = std::make_shared<CreationWizard>(Application::GetFrameWeld(m_xParentWindow), m_xChartModel, m_xCC); + } +} + +IMPL_STATIC_LINK_NOARG(CreationWizardUnoDlg, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*) +{ + return SfxViewShell::Current(); +} + +void SAL_CALL CreationWizardUnoDlg::startExecuteModal( const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& xListener ) +{ + SolarMutexGuard aSolarGuard; + createDialogOnDemand(); + + if( !m_xDialog ) + return; + + m_xDialog->getDialog()->SetInstallLOKNotifierHdl( + LINK(this, CreationWizardUnoDlg, InstallLOKNotifierHdl)); + + TimerTriggeredControllerLock aTimerTriggeredControllerLock( m_xChartModel ); + if( m_bUnlockControllersOnExecute && m_xChartModel.is() ) + m_xChartModel->unlockControllers(); + + CreationWizardUnoDlg* xThat = this; + weld::DialogController::runAsync(m_xDialog, [xListener, xThat](sal_Int32 nResult){ + if( xListener.is() ) + { + ::css::uno::Reference< ::css::uno::XInterface > xSource; + // Notify UNO listener to perform correct action depending on the result + css::ui::dialogs::DialogClosedEvent aEvent( xSource, nResult ); + xListener->dialogClosed( aEvent ); + } + xThat->m_xDialog.reset(); + }); +} + +void SAL_CALL CreationWizardUnoDlg::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + for(const uno::Any& rArgument : aArguments) + { + beans::PropertyValue aProperty; + if(rArgument >>= aProperty) + { + if( aProperty.Name == "ParentWindow" ) + { + aProperty.Value >>= m_xParentWindow; + } + else if( aProperty.Name == "ChartModel" ) + { + uno::Reference<XInterface> xInt; + aProperty.Value >>= xInt; + m_xChartModel = dynamic_cast<::chart::ChartModel*>(xInt.get()); + assert(m_xChartModel); + } + } + } +} + +// ____ OComponentHelper ____ +/// Called in dispose method after the listeners were notified. +void SAL_CALL CreationWizardUnoDlg::disposing() +{ + m_xChartModel.clear(); + m_xParentWindow.clear(); + + SolarMutexGuard aSolarGuard; + m_xDialog.reset(); + + try + { + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(m_xCC); + uno::Reference< frame::XTerminateListener > xListener( this ); + xDesktop->removeTerminateListener( xListener ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +//XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL CreationWizardUnoDlg::getPropertySetInfo() +{ + OSL_FAIL("not implemented"); + return nullptr; +} + +void SAL_CALL CreationWizardUnoDlg::setPropertyValue(const OUString& rPropertyName, + const uno::Any& rValue) +{ + if( rPropertyName == "Position" ) + { + SolarMutexGuard aSolarGuard; + createDialogOnDemand(); + + //read only property, do nothing else + } + else if( rPropertyName == "Size") + { + //read only property, do nothing + } + else if( rPropertyName == "UnlockControllersOnExecute" ) + { + if( ! (rValue >>= m_bUnlockControllersOnExecute) ) + throw lang::IllegalArgumentException( "Property 'UnlockControllers' requires value of type boolean" , nullptr, 0 ); + } + else + throw beans::UnknownPropertyException( "unknown property was tried to set to chart wizard" , nullptr ); +} + +uno::Any SAL_CALL CreationWizardUnoDlg::getPropertyValue( const OUString& rPropertyName ) +{ + uno::Any aRet; + if( rPropertyName == "Position" ) + { + //get left upper outer corner relative to screen + //pixels, screen position + SolarMutexGuard aSolarGuard; + createDialogOnDemand(); + if (m_xDialog) + { + Point aPos(m_xDialog->getDialog()->get_position()); + awt::Point aPoint(aPos.X(), aPos.Y()); + aRet <<= aPoint; + } + } + else if( rPropertyName == "Size" ) + { + //get outer size inclusive decoration + //pixels, screen position + SolarMutexGuard aSolarGuard; + createDialogOnDemand(); + if (m_xDialog) + { + Size aRect(m_xDialog->getDialog()->get_size()); + awt::Size aSize(aRect.Width(), aRect.Height()); + aRet <<= aSize; + } + } + else if( rPropertyName == "UnlockControllersOnExecute" ) + { + aRet <<= m_bUnlockControllersOnExecute; + } + else + throw beans::UnknownPropertyException( "unknown property was tried to get from chart wizard" , nullptr ); + return aRet; +} + +void SAL_CALL CreationWizardUnoDlg::addPropertyChangeListener( + const OUString& /* aPropertyName */, const uno::Reference< beans::XPropertyChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL CreationWizardUnoDlg::removePropertyChangeListener( + const OUString& /* aPropertyName */, const uno::Reference< beans::XPropertyChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +void SAL_CALL CreationWizardUnoDlg::addVetoableChangeListener( const OUString& /* PropertyName */, const uno::Reference< beans::XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +void SAL_CALL CreationWizardUnoDlg::removeVetoableChangeListener( const OUString& /* PropertyName */, const uno::Reference< beans::XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_WizardDialog_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new chart::CreationWizardUnoDlg(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_DataEditor.cxx b/chart2/source/controller/dialogs/dlg_DataEditor.cxx new file mode 100644 index 000000000..6ea5a4264 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_DataEditor.cxx @@ -0,0 +1,147 @@ +/* -*- 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 <dlg_DataEditor.hxx> +#include "DataBrowser.hxx" +#include <ChartModel.hxx> +#include <comphelper/stl_types.hxx> + +#include <com/sun/star/awt/XWindow.hpp> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +DataEditor::DataEditor(weld::Window* pParent, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const Reference< uno::XComponentContext > & xContext) + : GenericDialogController(pParent, "modules/schart/ui/chartdatadialog.ui", "ChartDataDialog") + , m_bReadOnly(false) + , m_xChartDoc(xChartDoc) + , m_xContext(xContext) + , m_xTbxData(m_xBuilder->weld_toolbar("toolbar")) + , m_xCloseBtn(m_xBuilder->weld_button("close")) + , m_xTable(m_xBuilder->weld_container("datawindow")) + , m_xColumns(m_xBuilder->weld_container("columns")) + , m_xColors(m_xBuilder->weld_container("colorcolumns")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xBrwData(VclPtr<DataBrowser>::Create(m_xTableCtrlParent, m_xColumns.get(), m_xColors.get())) +{ + m_xCloseBtn->connect_clicked(LINK(this, DataEditor, CloseHdl)); + + Size aSize(m_xTable->get_approximate_digit_width() * 75, m_xTable->get_text_height() * 15); + m_xTable->set_size_request(aSize.Width(), aSize.Height()); + + m_xBrwData->Show(); + + m_xTbxData->connect_clicked(LINK(this, DataEditor, ToolboxHdl)); + + m_xBrwData->SetCursorMovedHdl( LINK( this, DataEditor, BrowserCursorMovedHdl )); + + m_xBrwData->SetDataFromModel( m_xChartDoc ); + m_xBrwData->GrabFocus(); + + bool bReadOnly = true; + if( m_xChartDoc.is()) + bReadOnly = m_xChartDoc->isReadonly(); + SetReadOnly( bReadOnly ); +} + +DataEditor::~DataEditor() +{ + m_xBrwData.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); +} + +// react on click (or keypress) on toolbar icon +IMPL_LINK(DataEditor, ToolboxHdl, const OString&, rId, void) +{ + if (rId == "InsertRow") + m_xBrwData->InsertRow(); + else if (rId == "InsertColumn") + m_xBrwData->InsertColumn(); + else if (rId == "InsertTextColumn") + m_xBrwData->InsertTextColumn(); + else if (rId == "RemoveRow") + m_xBrwData->RemoveRow(); + else if (rId == "RemoveColumn") + m_xBrwData->RemoveColumn(); + else if (rId == "MoveLeftColumn") + m_xBrwData->MoveLeftColumn(); + else if (rId == "MoveRightColumn") + m_xBrwData->MoveRightColumn(); + else if (rId == "MoveUpRow") + m_xBrwData->MoveUpRow(); + else if (rId == "MoveDownRow") + m_xBrwData->MoveDownRow(); +} + +// refresh toolbar icons according to currently selected cell in browse box +IMPL_LINK_NOARG(DataEditor, BrowserCursorMovedHdl, DataBrowser*, void) +{ + if( m_bReadOnly ) + return; + + bool bIsDataValid = m_xBrwData->IsEnableItem(); + + m_xTbxData->set_item_sensitive("InsertRow", bIsDataValid && m_xBrwData->MayInsertRow() ); + m_xTbxData->set_item_sensitive("InsertColumn", bIsDataValid && m_xBrwData->MayInsertColumn() ); + m_xTbxData->set_item_sensitive("InsertTextColumn", bIsDataValid && m_xBrwData->MayInsertColumn() ); + m_xTbxData->set_item_sensitive("RemoveRow", m_xBrwData->MayDeleteRow() ); + m_xTbxData->set_item_sensitive("RemoveColumn", m_xBrwData->MayDeleteColumn() ); + + m_xTbxData->set_item_sensitive("MoveLeftColumn", bIsDataValid && m_xBrwData->MayMoveLeftColumns() ); + m_xTbxData->set_item_sensitive("MoveRightColumn", bIsDataValid && m_xBrwData->MayMoveRightColumns() ); + m_xTbxData->set_item_sensitive("MoveDownRow", bIsDataValid && m_xBrwData->MayMoveDownRows() ); + m_xTbxData->set_item_sensitive("MoveUpRow", bIsDataValid && m_xBrwData->MayMoveUpRows() ); +} + +// disable all modifying controls +void DataEditor::SetReadOnly( bool bReadOnly ) +{ + m_bReadOnly = bReadOnly; + if( m_bReadOnly ) + { + m_xTbxData->set_item_sensitive("InsertRow", false); + m_xTbxData->set_item_sensitive("InsertColumn", false); + m_xTbxData->set_item_sensitive("InsertTextColumn", false); + m_xTbxData->set_item_sensitive("RemoveRow", false); + m_xTbxData->set_item_sensitive("RemoveColumn", false); + m_xTbxData->set_item_sensitive("MoveLeftColumn", false); + m_xTbxData->set_item_sensitive("MoveRightColumn", false); + m_xTbxData->set_item_sensitive("MoveUpRow", false); + m_xTbxData->set_item_sensitive("MoveDownRow", false); + } + + m_xBrwData->SetReadOnly( m_bReadOnly ); +} + +IMPL_LINK_NOARG(DataEditor, CloseHdl, weld::Button&, void) +{ + bool bApplied = m_xBrwData->EndEditing(); // apply changes to model + if (bApplied) + m_xDialog->response(RET_CLOSE); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_DataSource.cxx b/chart2/source/controller/dialogs/dlg_DataSource.cxx new file mode 100644 index 000000000..dc1296af7 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_DataSource.cxx @@ -0,0 +1,182 @@ +/* -*- 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 <com/sun/star/chart2/XChartDocument.hpp> + +#include <dlg_DataSource.hxx> +#include <ChartTypeTemplateProvider.hxx> +#include <ChartTypeTemplate.hxx> +#include <Diagram.hxx> +#include <DiagramHelper.hxx> +#include "DialogModel.hxx" +#include <ChartModel.hxx> + +#include "tp_RangeChooser.hxx" +#include "tp_DataSource.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::chart; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +namespace { + +class DocumentChartTypeTemplateProvider : public ChartTypeTemplateProvider +{ +public: + explicit DocumentChartTypeTemplateProvider( + const rtl::Reference<::chart::ChartModel> & xDoc ); + + // ____ ChartTypeTemplateProvider ____ + virtual rtl::Reference< ::chart::ChartTypeTemplate > getCurrentTemplate() const override; + +private: + rtl::Reference< ::chart::ChartTypeTemplate > m_xTemplate; +}; + +} + +DocumentChartTypeTemplateProvider::DocumentChartTypeTemplateProvider( + const rtl::Reference<::chart::ChartModel> & xDoc ) +{ + if( !xDoc.is()) + return; + + rtl::Reference< Diagram > xDia( xDoc->getFirstChartDiagram()); + if( xDia.is()) + { + DiagramHelper::tTemplateWithServiceName aResult( + DiagramHelper::getTemplateForDiagram( + xDia, + xDoc->getTypeManager() )); + m_xTemplate = aResult.xChartTypeTemplate; + } +} + +rtl::Reference< ::chart::ChartTypeTemplate > DocumentChartTypeTemplateProvider::getCurrentTemplate() const +{ + return m_xTemplate; +} + +sal_uInt16 DataSourceDialog::m_nLastPageId = 0; + +DataSourceDialog::DataSourceDialog(weld::Window * pParent, + const rtl::Reference<::chart::ChartModel> & xChartDocument) + : GenericDialogController(pParent, "modules/schart/ui/datarangedialog.ui", + "DataRangeDialog") + , m_apDocTemplateProvider(new DocumentChartTypeTemplateProvider(xChartDocument)) + , m_apDialogModel(new DialogModel(xChartDocument)) + , m_bRangeChooserTabIsValid(true) + , m_bDataSourceTabIsValid(true) + , m_bTogglingEnabled(true) + , m_xTabControl(m_xBuilder->weld_notebook("tabcontrol")) + , m_xBtnOK(m_xBuilder->weld_button("ok")) +{ + m_xRangeChooserTabPage = std::make_unique<RangeChooserTabPage>(m_xTabControl->get_page("range"), this, + *m_apDialogModel, + m_apDocTemplateProvider.get(), true /* bHideDescription */ ); + m_xDataSourceTabPage = std::make_unique<DataSourceTabPage>(m_xTabControl->get_page("series"), this, + *m_apDialogModel, + m_apDocTemplateProvider.get(), true /* bHideDescription */ ); + m_xTabControl->connect_enter_page(LINK(this, DataSourceDialog, ActivatePageHdl)); + m_xTabControl->connect_leave_page(LINK(this, DataSourceDialog, DeactivatePageHdl)); + ActivatePageHdl(m_xTabControl->get_current_page_ident()); + if (m_nLastPageId != 0) + { + m_xTabControl->set_current_page(m_nLastPageId); + ActivatePageHdl(m_xTabControl->get_current_page_ident()); + } +} + +DataSourceDialog::~DataSourceDialog() +{ + m_xRangeChooserTabPage.reset(); + m_xDataSourceTabPage.reset(); + m_nLastPageId = m_xTabControl->get_current_page(); +} + +short DataSourceDialog::run() +{ + short nResult = GenericDialogController::run(); + if( nResult == RET_OK ) + { + if( m_xRangeChooserTabPage ) + m_xRangeChooserTabPage->commitPage(); + if( m_xDataSourceTabPage ) + m_xDataSourceTabPage->commitPage(); + } + return nResult; +} + +IMPL_LINK(DataSourceDialog, ActivatePageHdl, const OString&, rPage, void) +{ + if (rPage == "range") + m_xRangeChooserTabPage->Activate(); + else if (rPage == "series") + m_xDataSourceTabPage->Activate(); +} + +// allow/disallow user to leave page +IMPL_LINK_NOARG(DataSourceDialog, DeactivatePageHdl, const OString&, bool) +{ + return m_bTogglingEnabled; +} + +void DataSourceDialog::setInvalidPage(BuilderPage* pTabPage) +{ + if (pTabPage == m_xRangeChooserTabPage.get()) + m_bRangeChooserTabIsValid = false; + else if (pTabPage == m_xDataSourceTabPage.get()) + m_bDataSourceTabIsValid = false; + + if (!(m_bRangeChooserTabIsValid && m_bDataSourceTabIsValid)) + { + m_xBtnOK->set_sensitive(false); + // note: there seems to be no suitable mechanism to address pages by + // identifier, at least it is unclear what the page identifiers are. + // @todo: change the fixed numbers to identifiers + if( m_bRangeChooserTabIsValid ) + m_xTabControl->set_current_page(1); + else if( m_bDataSourceTabIsValid ) + m_xTabControl->set_current_page(0); + m_bTogglingEnabled = false; + } +} + +void DataSourceDialog::setValidPage(BuilderPage* pTabPage) +{ + if( pTabPage == m_xRangeChooserTabPage.get() ) + m_bRangeChooserTabIsValid = true; + else if( pTabPage == m_xDataSourceTabPage.get() ) + m_bDataSourceTabIsValid = true; + + if (m_bRangeChooserTabIsValid && m_bDataSourceTabIsValid) + { + m_xBtnOK->set_sensitive(true); + m_bTogglingEnabled = true; + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertAxis_Grid.cxx b/chart2/source/controller/dialogs/dlg_InsertAxis_Grid.cxx new file mode 100644 index 000000000..f20571e22 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertAxis_Grid.cxx @@ -0,0 +1,88 @@ +/* -*- 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 <dlg_InsertAxis_Grid.hxx> + +namespace chart +{ + +InsertAxisOrGridDialogData::InsertAxisOrGridDialogData() + : aPossibilityList{ true, true, true, true, true, true } + , aExistenceList{ false, false, false, false, false, false } +{ +} + +// SchAxisDlg + +SchAxisDlg::SchAxisDlg(weld::Window* pWindow, + const InsertAxisOrGridDialogData& rInput, bool bAxisDlg) + : GenericDialogController(pWindow, + bAxisDlg ? + OUString("modules/schart/ui/insertaxisdlg.ui") : + OUString("modules/schart/ui/insertgriddlg.ui"), + bAxisDlg ? + OString("InsertAxisDialog") : + OString("InsertGridDialog")) + , m_xCbPrimaryX(m_xBuilder->weld_check_button("primaryX")) + , m_xCbPrimaryY(m_xBuilder->weld_check_button("primaryY")) + , m_xCbPrimaryZ(m_xBuilder->weld_check_button("primaryZ")) + , m_xCbSecondaryX(m_xBuilder->weld_check_button("secondaryX")) + , m_xCbSecondaryY(m_xBuilder->weld_check_button("secondaryY")) + , m_xCbSecondaryZ(m_xBuilder->weld_check_button("secondaryZ")) +{ + if (bAxisDlg) + { + //todo: remove if secondary z axis are possible somewhere + m_xCbSecondaryZ->hide(); + } + + m_xCbPrimaryX->set_active( rInput.aExistenceList[0] ); + m_xCbPrimaryY->set_active( rInput.aExistenceList[1] ); + m_xCbPrimaryZ->set_active( rInput.aExistenceList[2] ); + m_xCbSecondaryX->set_active( rInput.aExistenceList[3] ); + m_xCbSecondaryY->set_active( rInput.aExistenceList[4] ); + m_xCbSecondaryZ->set_active( rInput.aExistenceList[5] ); + + m_xCbPrimaryX->set_sensitive( rInput.aPossibilityList[0] ); + m_xCbPrimaryY->set_sensitive( rInput.aPossibilityList[1] ); + m_xCbPrimaryZ->set_sensitive( rInput.aPossibilityList[2] ); + m_xCbSecondaryX->set_sensitive( rInput.aPossibilityList[3] ); + m_xCbSecondaryY->set_sensitive( rInput.aPossibilityList[4] ); + m_xCbSecondaryZ->set_sensitive( rInput.aPossibilityList[5] ); +} + +void SchAxisDlg::getResult( InsertAxisOrGridDialogData& rOutput ) +{ + sal_Bool* pExistenceList = rOutput.aExistenceList.getArray(); + pExistenceList[0]=m_xCbPrimaryX->get_active(); + pExistenceList[1]=m_xCbPrimaryY->get_active(); + pExistenceList[2]=m_xCbPrimaryZ->get_active(); + pExistenceList[3]=m_xCbSecondaryX->get_active(); + pExistenceList[4]=m_xCbSecondaryY->get_active(); + pExistenceList[5]=m_xCbSecondaryZ->get_active(); +} + +SchGridDlg::SchGridDlg(weld::Window* pParent, const InsertAxisOrGridDialogData& rInput) + : SchAxisDlg(pParent, rInput, false) //rInAttrs, b3D, bNet, bSecondaryX, bSecondaryY, false ) +{ +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertDataLabel.cxx b/chart2/source/controller/dialogs/dlg_InsertDataLabel.cxx new file mode 100644 index 000000000..57817d883 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertDataLabel.cxx @@ -0,0 +1,43 @@ +/* -*- 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 <dlg_InsertDataLabel.hxx> +#include "res_DataLabel.hxx" + +namespace chart +{ + +DataLabelsDialog::DataLabelsDialog(weld::Window* pWindow, const SfxItemSet& rInAttrs, SvNumberFormatter* pFormatter) + : GenericDialogController(pWindow, "modules/schart/ui/dlg_DataLabel.ui", "dlg_DataLabels") + , m_apDataLabelResources(new DataLabelResources(m_xBuilder.get(), pWindow, rInAttrs)) +{ + m_apDataLabelResources->SetNumberFormatter( pFormatter ); + m_apDataLabelResources->Reset(rInAttrs); +} + +DataLabelsDialog::~DataLabelsDialog() = default; + +void DataLabelsDialog::FillItemSet(SfxItemSet& rOutAttrs) +{ + m_apDataLabelResources->FillItemSet(&rOutAttrs); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertErrorBars.cxx b/chart2/source/controller/dialogs/dlg_InsertErrorBars.cxx new file mode 100644 index 000000000..98afaa47c --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertErrorBars.cxx @@ -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 . + */ + +#include <dlg_InsertErrorBars.hxx> +#include <res_ErrorBar.hxx> +#include <chartview/ExplicitScaleValues.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <ObjectIdentifier.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <ObjectNameProvider.hxx> +#include <DataSeries.hxx> + +#include <comphelper/servicehelper.hxx> + +using ::com::sun::star::uno::Reference; +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart +{ + +InsertErrorBarsDialog::InsertErrorBarsDialog( + weld::Window* pParent, const SfxItemSet& rMyAttrs, + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ErrorBarResources::tErrorBarType eType /* = ErrorBarResources::ERROR_BAR_Y */ ) + : GenericDialogController(pParent, "modules/schart/ui/dlg_InsertErrorBars.ui", "dlg_InsertErrorBars") + , m_apErrorBarResources( new ErrorBarResources( + m_xBuilder.get(), this, rMyAttrs, + /* bNoneAvailable = */ true, eType )) +{ + ObjectType objType = eType == ErrorBarResources::ERROR_BAR_Y ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X; + + m_xDialog->set_title(ObjectNameProvider::getName_ObjectForAllSeries(objType)); + + m_apErrorBarResources->SetChartDocumentForRangeChoosing( xChartDocument ); +} + +void InsertErrorBarsDialog::FillItemSet(SfxItemSet& rOutAttrs) +{ + m_apErrorBarResources->FillItemSet(rOutAttrs); +} + +void InsertErrorBarsDialog::SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ) +{ + m_apErrorBarResources->SetAxisMinorStepWidthForErrorBarDecimals( fMinorStepWidth ); +} + +double InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const Reference< uno::XInterface >& xChartView, + const OUString& rSelectedObjectCID ) +{ + double fStepWidth = 0.001; + + ExplicitValueProvider* pExplicitValueProvider( comphelper::getFromUnoTunnel<ExplicitValueProvider>(xChartView) ); + if( pExplicitValueProvider ) + { + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rSelectedObjectCID, xChartModel ); + rtl::Reference< Axis > xAxis = DiagramHelper::getAttachedAxis( xSeries, xDiagram ); + if(!xAxis.is()) + xAxis = AxisHelper::getAxis( 1/*nDimensionIndex*/, true/*bMainAxis*/, xDiagram ); + if(xAxis.is()) + { + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + pExplicitValueProvider->getExplicitValuesForAxis( xAxis,aExplicitScale, aExplicitIncrement ); + + fStepWidth = aExplicitIncrement.Distance; + if( !aExplicitIncrement.SubIncrements.empty() && aExplicitIncrement.SubIncrements[0].IntervalCount>0 ) + fStepWidth=fStepWidth/double(aExplicitIncrement.SubIncrements[0].IntervalCount); + else + fStepWidth/=10; + } + } + + return fStepWidth; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertLegend.cxx b/chart2/source/controller/dialogs/dlg_InsertLegend.cxx new file mode 100644 index 000000000..c55ecc3e8 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertLegend.cxx @@ -0,0 +1,45 @@ +/* -*- 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 <dlg_InsertLegend.hxx> +#include <res_LegendPosition.hxx> + +namespace chart +{ +using namespace ::com::sun::star; + +SchLegendDlg::SchLegendDlg(weld::Window* pWindow, const uno::Reference<uno::XComponentContext>& xCC) + : GenericDialogController(pWindow, "modules/schart/ui/dlg_InsertLegend.ui", "dlg_InsertLegend") + , m_xLegendPositionResources(new LegendPositionResources(*m_xBuilder, xCC)) +{ +} + +void SchLegendDlg::init(const rtl::Reference<::chart::ChartModel>& xChartModel) +{ + m_xLegendPositionResources->writeToResources(xChartModel); +} + +void SchLegendDlg::writeToModel(const rtl::Reference<::chart::ChartModel>& xChartModel) const +{ + m_xLegendPositionResources->writeToModel(xChartModel); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertTitle.cxx b/chart2/source/controller/dialogs/dlg_InsertTitle.cxx new file mode 100644 index 000000000..03f942945 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertTitle.cxx @@ -0,0 +1,41 @@ +/* -*- 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 <dlg_InsertTitle.hxx> +#include <res_Titles.hxx> +#include <ObjectNameProvider.hxx> + +namespace chart +{ +SchTitleDlg::SchTitleDlg(weld::Window* pWindow, const TitleDialogData& rInput) + : GenericDialogController(pWindow, "modules/schart/ui/inserttitledlg.ui", "InsertTitleDialog") + , m_xTitleResources(new TitleResources(*m_xBuilder, true)) +{ + m_xDialog->set_title(ObjectNameProvider::getName(OBJECTTYPE_TITLE, true)); + m_xTitleResources->writeToResources(rInput); +} + +void SchTitleDlg::getResult(TitleDialogData& rOutput) +{ + m_xTitleResources->readFromResources(rOutput); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_NumberFormat.cxx b/chart2/source/controller/dialogs/dlg_NumberFormat.cxx new file mode 100644 index 000000000..7750588cc --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_NumberFormat.cxx @@ -0,0 +1,56 @@ +/* -*- 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 "dlg_NumberFormat.hxx" + +#include <svl/itemset.hxx> +#include <svx/dialogs.hrc> +#include <svx/svxids.hrc> +#include <sfx2/tabdlg.hxx> +#include <sfx2/sfxdlg.hxx> + +namespace chart +{ +using namespace ::com::sun::star; + +NumberFormatDialog::NumberFormatDialog(weld::Window* pParent, const SfxItemSet& rSet) + : SfxSingleTabDialogController(pParent, &rSet, "cui/ui/formatnumberdialog.ui", "FormatNumberDialog") +{ + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc( RID_SVXPAGE_NUMBERFORMAT ); + if (fnCreatePage) + { + std::unique_ptr<SfxTabPage> xTabPage = (*fnCreatePage)(get_content_area(), this, &rSet); + xTabPage->PageCreated(rSet); + SetTabPage(std::move(xTabPage)); + } +} + +SfxItemSet NumberFormatDialog::CreateEmptyItemSetForNumberFormatDialog( SfxItemPool& rItemPool ) +{ + return SfxItemSet( rItemPool, svl::Items< + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, + SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA, + SID_ATTR_NUMBERFORMAT_NOLANGUAGE, SID_ATTR_NUMBERFORMAT_NOLANGUAGE, + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE> ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_NumberFormat.hxx b/chart2/source/controller/dialogs/dlg_NumberFormat.hxx new file mode 100644 index 000000000..56d5acd20 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_NumberFormat.hxx @@ -0,0 +1,42 @@ +/* -*- 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 <sfx2/basedlgs.hxx> + +namespace weld +{ +class Window; +} +class SfxItemSet; +class SfxItemPool; + +namespace chart +{ +class NumberFormatDialog : public SfxSingleTabDialogController +{ +public: + NumberFormatDialog(weld::Window* pParent, const SfxItemSet& rSet); + + static SfxItemSet CreateEmptyItemSetForNumberFormatDialog(SfxItemPool& rItemPool); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx b/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx new file mode 100644 index 000000000..f0497ecdc --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx @@ -0,0 +1,627 @@ +/* -*- 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 <sal/config.h> + +#include <cstddef> + +#include <dlg_ObjectProperties.hxx> +#include <strings.hrc> +#include "tp_AxisLabel.hxx" +#include "tp_DataLabel.hxx" +#include "tp_LegendPosition.hxx" +#include "tp_PointGeometry.hxx" +#include "tp_Scale.hxx" +#include "tp_AxisPositions.hxx" +#include "tp_ErrorBars.hxx" +#include "tp_Trendline.hxx" +#include "tp_SeriesToAxis.hxx" +#include "tp_TitleRotation.hxx" +#include "tp_PolarOptions.hxx" +#include "tp_DataPointOption.hxx" +#include <ResId.hxx> +#include <ViewElementListProvider.hxx> +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <ObjectNameProvider.hxx> +#include <DataSeries.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <NumberFormatterWrapper.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <ExplicitCategoriesProvider.hxx> +#include <ChartModel.hxx> +#include <CommonConverters.hxx> +#include <RegressionCalculationHelper.hxx> +#include <BaseCoordinateSystem.hxx> + +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/XAxis.hpp> +#include <svl/intitem.hxx> +#include <svl/ctloptions.hxx> + +#include <svx/svxids.hrc> + +#include <svx/drawitem.hxx> +#include <svx/ofaitem.hxx> +#include <svx/svxgraphicitem.hxx> + +#include <svx/dialogs.hrc> +#include <editeng/flstitem.hxx> + +#include <svx/flagsdef.hxx> +#include <svx/numinf.hxx> + +#include <svl/cjkoptions.hxx> +#include <tools/diagnose_ex.h> + +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XDataSeries; } + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::beans::XPropertySet; + +ObjectPropertiesDialogParameter::ObjectPropertiesDialogParameter( const OUString& rObjectCID ) + : m_aObjectCID( rObjectCID ) + , m_eObjectType( ObjectIdentifier::getObjectType( m_aObjectCID ) ) + , m_bAffectsMultipleObjects(false) + , m_bHasGeometryProperties(false) + , m_bHasStatisticProperties(false) + , m_bProvidesSecondaryYAxis(false) + , m_bProvidesOverlapAndGapWidth(false) + , m_bProvidesBarConnectors(false) + , m_bHasAreaProperties(false) + , m_bHasSymbolProperties(false) + , m_bHasNumberProperties(false) + , m_bProvidesStartingAngle(false) + , m_bProvidesMissingValueTreatments(false) + , m_bIsPieChartDataPoint(false) + , m_bHasScaleProperties(false) + , m_bCanAxisLabelsBeStaggered(false) + , m_bSupportingAxisPositioning(false) + , m_bShowAxisOrigin(false) + , m_bIsCrossingAxisIsCategoryAxis(false) + , m_bSupportingCategoryPositioning(false) + , m_bComplexCategoriesAxis( false ) + , m_nNbPoints( 0 ) +{ + std::u16string_view aParticleID = ObjectIdentifier::getParticleID( m_aObjectCID ); + m_bAffectsMultipleObjects = (aParticleID == u"ALLELEMENTS"); +} +ObjectPropertiesDialogParameter::~ObjectPropertiesDialogParameter() +{ +} + +void ObjectPropertiesDialogParameter::init( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + m_xChartDocument = xChartModel; + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aObjectCID, xChartModel ); + rtl::Reference< ChartType > xChartType = ChartModelHelper::getChartTypeOfSeries( xChartModel, xSeries ); + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + + bool bHasSeriesProperties = (m_eObjectType==OBJECTTYPE_DATA_SERIES); + bool bHasDataPointproperties = (m_eObjectType==OBJECTTYPE_DATA_POINT); + + if( bHasSeriesProperties || bHasDataPointproperties ) + { + m_bHasGeometryProperties = ChartTypeHelper::isSupportingGeometryProperties( xChartType, nDimensionCount ); + m_bHasAreaProperties = ChartTypeHelper::isSupportingAreaProperties( xChartType, nDimensionCount ); + m_bHasSymbolProperties = ChartTypeHelper::isSupportingSymbolProperties( xChartType, nDimensionCount ); + m_bIsPieChartDataPoint = bHasDataPointproperties && ChartTypeHelper::isSupportingStartingAngle( xChartType ); + + if( bHasSeriesProperties ) + { + m_bHasStatisticProperties = ChartTypeHelper::isSupportingStatisticProperties( xChartType, nDimensionCount ); + m_bProvidesSecondaryYAxis = ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ); + m_bProvidesOverlapAndGapWidth = ChartTypeHelper::isSupportingOverlapAndGapWidthProperties( xChartType, nDimensionCount ); + m_bProvidesBarConnectors = ChartTypeHelper::isSupportingBarConnectors( xChartType, nDimensionCount ); + m_bProvidesStartingAngle = ChartTypeHelper::isSupportingStartingAngle( xChartType ); + + m_bProvidesMissingValueTreatments = ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) + .hasElements(); + } + } + + if( m_eObjectType == OBJECTTYPE_DATA_ERRORS_X || + m_eObjectType == OBJECTTYPE_DATA_ERRORS_Y || + m_eObjectType == OBJECTTYPE_DATA_ERRORS_Z) + m_bHasStatisticProperties = true; + + if( m_eObjectType == OBJECTTYPE_AXIS ) + { + //show scale properties only for a single axis not for multiselection + m_bHasScaleProperties = !m_bAffectsMultipleObjects; + + if( m_bHasScaleProperties ) + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aObjectCID, xChartModel ); + if( xAxis.is() ) + { + //no scale page for series axis + ScaleData aData( xAxis->getScaleData() ); + if( aData.AxisType == chart2::AxisType::SERIES ) + m_bHasScaleProperties = false; + if( aData.AxisType != chart2::AxisType::SERIES ) + m_bHasNumberProperties = true; + + //is the crossing main axis a category axes?: + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( xAxis, xDiagram ) ); + uno::Reference< XAxis > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ) ); + if( xCrossingMainAxis.is() ) + { + ScaleData aScale( xCrossingMainAxis->getScaleData() ); + m_bIsCrossingAxisIsCategoryAxis = ( aScale.AxisType == chart2::AxisType::CATEGORY ); + if( m_bIsCrossingAxisIsCategoryAxis ) + { + if (xChartModel) + m_aCategories = DiagramHelper::getExplicitSimpleCategories( *xChartModel ); + } + } + + sal_Int32 nCooSysIndex=0; + sal_Int32 nDimensionIndex=0; + sal_Int32 nAxisIndex=0; + if( AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ) ) + { + xChartType = AxisHelper::getFirstChartTypeWithSeriesAttachedToAxisIndex( xDiagram, nAxisIndex ); + //show positioning controls only if they make sense + m_bSupportingAxisPositioning = ChartTypeHelper::isSupportingAxisPositioning( xChartType, nDimensionCount, nDimensionIndex ); + + //show axis origin only for secondary y axis + if( nDimensionIndex==1 && nAxisIndex==1 && ChartTypeHelper::isSupportingBaseValue( xChartType ) ) + m_bShowAxisOrigin = true; + + if ( nDimensionIndex == 0 && ( aData.AxisType == chart2::AxisType::CATEGORY || aData.AxisType == chart2::AxisType::DATE ) ) + { + if (xChartModel) + { + ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, *xChartModel ); + m_bComplexCategoriesAxis = aExplicitCategoriesProvider.hasComplexCategories(); + } + + if (!m_bComplexCategoriesAxis) + m_bSupportingCategoryPositioning = ChartTypeHelper::isSupportingCategoryPositioning( xChartType, nDimensionCount ); + } + } + } + } + + //no staggering of labels for 3D axis + m_bCanAxisLabelsBeStaggered = nDimensionCount==2; + } + + if( m_eObjectType == OBJECTTYPE_DATA_CURVE ) + { + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aDataSeqs( xSeries->getDataSequences2()); + Sequence< double > aXValues, aYValues; + bool bXValuesFound = false, bYValuesFound = false; + m_nNbPoints = 0; + for( std::size_t i=0; + ! (bXValuesFound && bYValuesFound) && i<aDataSeqs.size(); + ++i ) + { + try + { + Reference< data::XDataSequence > xSeq( aDataSeqs[i]->getValues()); + Reference< XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); + OUString aRole; + if( xProp->getPropertyValue( "Role" ) >>= aRole ) + { + if( !bXValuesFound && aRole == "values-x" ) + { + aXValues = DataSequenceToDoubleSequence( xSeq ); + bXValuesFound = true; + } + else if( !bYValuesFound && aRole == "values-y" ) + { + aYValues = DataSequenceToDoubleSequence( xSeq ); + bYValuesFound = true; + } + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + if( !bXValuesFound && bYValuesFound ) + { + // initialize with 1, 2, ... + //first category (index 0) matches with real number 1.0 + aXValues.realloc( aYValues.getLength() ); + auto pXValues = aXValues.getArray(); + for( sal_Int32 i=0; i<aXValues.getLength(); ++i ) + pXValues[i] = i+1; + bXValuesFound = true; + } + + if( bXValuesFound && bYValuesFound && + aXValues.hasElements() && + aYValues.hasElements() ) + { + RegressionCalculationHelper::tDoubleVectorPair aValues( + RegressionCalculationHelper::cleanup( aXValues, aYValues, RegressionCalculationHelper::isValid())); + m_nNbPoints = aValues.second.size(); + } + } + + //create gui name for this object + { + if( !m_bAffectsMultipleObjects && m_eObjectType == OBJECTTYPE_AXIS ) + { + m_aLocalizedName = ObjectNameProvider::getAxisName( m_aObjectCID, xChartModel ); + } + else if( !m_bAffectsMultipleObjects && ( m_eObjectType == OBJECTTYPE_GRID || m_eObjectType == OBJECTTYPE_SUBGRID ) ) + { + m_aLocalizedName = ObjectNameProvider::getGridName( m_aObjectCID, xChartModel ); + } + else if( !m_bAffectsMultipleObjects && m_eObjectType == OBJECTTYPE_TITLE ) + { + m_aLocalizedName = ObjectNameProvider::getTitleName( m_aObjectCID, xChartModel ); + } + else + { + switch( m_eObjectType ) + { + case OBJECTTYPE_DATA_POINT: + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_CURVE: + case OBJECTTYPE_DATA_CURVE_EQUATION: + if( m_bAffectsMultipleObjects ) + m_aLocalizedName = ObjectNameProvider::getName_ObjectForAllSeries( m_eObjectType ); + else + m_aLocalizedName = ObjectNameProvider::getName_ObjectForSeries( m_eObjectType, m_aObjectCID, m_xChartDocument ); + break; + default: + m_aLocalizedName = ObjectNameProvider::getName(m_eObjectType,m_bAffectsMultipleObjects); + break; + } + } + } +} + +const sal_uInt16 nNoArrowNoShadowDlg = 1101; + +void SchAttribTabDlg::setSymbolInformation( SfxItemSet&& rSymbolShapeProperties, + std::unique_ptr<Graphic> pAutoSymbolGraphic ) +{ + m_oSymbolShapeProperties.emplace(std::move(rSymbolShapeProperties)); + m_pAutoSymbolGraphic = std::move(pAutoSymbolGraphic); +} + +void SchAttribTabDlg::SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ) +{ + m_fAxisMinorStepWidthForErrorBarDecimals = fMinorStepWidth; +} + +SchAttribTabDlg::SchAttribTabDlg(weld::Window* pParent, + const SfxItemSet* pAttr, + const ObjectPropertiesDialogParameter* pDialogParameter, + const ViewElementListProvider* pViewElementListProvider, + const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier) + : SfxTabDialogController(pParent, "modules/schart/ui/attributedialog.ui", "AttributeDialog", pAttr) + , m_pParameter( pDialogParameter ) + , m_pViewElementListProvider( pViewElementListProvider ) + , m_pNumberFormatter(nullptr) + , m_fAxisMinorStepWidthForErrorBarDecimals(0.1) + , m_bOKPressed(false) +{ + NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier ); + m_pNumberFormatter = aNumberFormatterWrapper.getSvNumberFormatter(); + + m_xDialog->set_title(pDialogParameter->getLocalizedName()); + + switch (pDialogParameter->getObjectType()) + { + case OBJECTTYPE_TITLE: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("alignment", SchResId(STR_PAGE_ALIGNMENT), SchAlignmentTabPage::Create); + if( SvtCJKOptions::IsAsianTypographyEnabled() ) + AddTabPage("asian", SchResId(STR_PAGE_ASIAN), RID_SVXPAGE_PARA_ASIAN); + break; + + case OBJECTTYPE_LEGEND: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("legendpos", SchResId(STR_PAGE_POSITION), SchLegendPosTabPage::Create); + if (SvtCJKOptions::IsAsianTypographyEnabled()) + AddTabPage("asian", SchResId(STR_PAGE_ASIAN), RID_SVXPAGE_PARA_ASIAN); + break; + + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_DATA_POINT: + if( m_pParameter->ProvidesSecondaryYAxis() || m_pParameter->ProvidesOverlapAndGapWidth() || m_pParameter->ProvidesMissingValueTreatments() ) + AddTabPage("options", SchResId(STR_PAGE_OPTIONS),SchOptionTabPage::Create); + if( m_pParameter->ProvidesStartingAngle()) + AddTabPage("polaroptions", SchResId(STR_PAGE_OPTIONS), PolarOptionsTabPage::Create); + if (m_pParameter->IsPieChartDataPoint()) + AddTabPage("datapointoption", SchResId(STR_PAGE_OPTIONS), DataPointOptionTabPage::Create); + + if( m_pParameter->HasGeometryProperties() ) + AddTabPage("layout", SchResId(STR_PAGE_LAYOUT), SchLayoutTabPage::Create); + + if(m_pParameter->HasAreaProperties()) + { + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + } + AddTabPage("border", SchResId( m_pParameter->HasAreaProperties() ? STR_PAGE_BORDER : STR_PAGE_LINE ), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_LABELS: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("datalabels", SchResId(STR_OBJECT_DATALABELS), DataLabelsTabPage::Create); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + if( SvtCJKOptions::IsAsianTypographyEnabled() ) + AddTabPage("asian", SchResId(STR_PAGE_ASIAN), RID_SVXPAGE_PARA_ASIAN); + + break; + + case OBJECTTYPE_AXIS: + { + if( m_pParameter->HasScaleProperties() ) + { + AddTabPage("scale", SchResId(STR_PAGE_SCALE), ScaleTabPage::Create); + //no positioning page for z axes so far as the tickmarks are not shown so far + AddTabPage("axispos", SchResId(STR_PAGE_POSITIONING), AxisPositionsTabPage::Create); + } + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + AddTabPage("axislabel", SchResId(STR_OBJECT_LABEL), SchAxisLabelTabPage::Create); + if( m_pParameter->HasNumberProperties() ) + AddTabPage("numberformat", SchResId(STR_PAGE_NUMBERS), RID_SVXPAGE_NUMBERFORMAT); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + if( SvtCJKOptions::IsAsianTypographyEnabled() ) + AddTabPage("asian", SchResId(STR_PAGE_ASIAN), RID_SVXPAGE_PARA_ASIAN); + break; + } + + case OBJECTTYPE_DATA_ERRORS_X: + AddTabPage("xerrorbar", SchResId(STR_PAGE_XERROR_BARS), ErrorBarsTabPage::Create); + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_ERRORS_Y: + AddTabPage("yerrorbar", SchResId(STR_PAGE_YERROR_BARS), ErrorBarsTabPage::Create); + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_ERRORS_Z: + break; + + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_STOCK_RANGE: + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_CURVE: + AddTabPage("trendline", SchResId(STR_PAGE_TRENDLINE_TYPE), TrendlineTabPage::Create); + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_STOCK_LOSS: + case OBJECTTYPE_DATA_STOCK_GAIN: + case OBJECTTYPE_PAGE: + case OBJECTTYPE_DIAGRAM_FLOOR: + case OBJECTTYPE_DIAGRAM_WALL: + case OBJECTTYPE_DIAGRAM: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + break; + + case OBJECTTYPE_LEGEND_ENTRY: + case OBJECTTYPE_AXIS_UNITLABEL: + case OBJECTTYPE_UNKNOWN: + // nothing + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("numberformat", SchResId(STR_PAGE_NUMBERS), RID_SVXPAGE_NUMBERFORMAT); + if (SvtCTLOptions().IsCTLFontEnabled()) + { + /* When rotation is supported for equation text boxes, use + SchAlignmentTabPage::Create here. The special + SchAlignmentTabPage::CreateWithoutRotation can be deleted. */ + AddTabPage("alignment", SchResId(STR_PAGE_ALIGNMENT), SchAlignmentTabPage::CreateWithoutRotation); + } + break; + default: + break; + } + + // used to find out if user left the dialog with OK. When OK is pressed but + // no changes were done, Cancel is returned by the SfxTabDialog. See method + // DialogWasClosedWithOK. + GetOKButton().connect_clicked(LINK(this, SchAttribTabDlg, OKPressed)); +} + +SchAttribTabDlg::~SchAttribTabDlg() +{ +} + +void SchAttribTabDlg::PageCreated(const OString& rId, SfxTabPage &rPage) +{ + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rId == "border") + { + aSet.Put (SvxColorListItem(m_pViewElementListProvider->GetColorTable(),SID_COLOR_TABLE)); + aSet.Put (SvxDashListItem(m_pViewElementListProvider->GetDashList(),SID_DASH_LIST)); + aSet.Put (SvxLineEndListItem(m_pViewElementListProvider->GetLineEndList(),SID_LINEEND_LIST)); + aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0)); + aSet.Put (SfxUInt16Item(SID_DLG_TYPE,nNoArrowNoShadowDlg)); + + if( m_pParameter->HasSymbolProperties() ) + { + aSet.Put(OfaPtrItem(SID_OBJECT_LIST,m_pViewElementListProvider->GetSymbolList())); + if( m_oSymbolShapeProperties ) + aSet.Put(SfxTabDialogItem(SID_ATTR_SET, *m_oSymbolShapeProperties)); + if( m_pAutoSymbolGraphic ) + aSet.Put(SvxGraphicItem(*m_pAutoSymbolGraphic)); + } + rPage.PageCreated(aSet); + } + else if (rId == "area") + { + aSet.Put(SvxColorListItem(m_pViewElementListProvider->GetColorTable(),SID_COLOR_TABLE)); + aSet.Put(SvxGradientListItem(m_pViewElementListProvider->GetGradientList(),SID_GRADIENT_LIST)); + aSet.Put(SvxHatchListItem(m_pViewElementListProvider->GetHatchList(),SID_HATCH_LIST)); + aSet.Put(SvxBitmapListItem(m_pViewElementListProvider->GetBitmapList(),SID_BITMAP_LIST)); + aSet.Put(SvxPatternListItem(m_pViewElementListProvider->GetPatternList(),SID_PATTERN_LIST)); + aSet.Put(SfxUInt16Item(SID_PAGE_TYPE,0)); + aSet.Put(SfxUInt16Item(SID_DLG_TYPE,nNoArrowNoShadowDlg)); + rPage.PageCreated(aSet); + } + else if (rId == "transparent") + { + aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0)); + aSet.Put (SfxUInt16Item(SID_DLG_TYPE,nNoArrowNoShadowDlg)); + rPage.PageCreated(aSet); + } + else if (rId == "fontname") + { + aSet.Put (SvxFontListItem(m_pViewElementListProvider->getFontList(), SID_ATTR_CHAR_FONTLIST)); + rPage.PageCreated(aSet); + } + else if (rId == "effects") + { + aSet.Put (SfxUInt16Item(SID_DISABLE_CTL,DISABLE_CASEMAP)); + rPage.PageCreated(aSet); + } + else if (rId == "axislabel") + { + bool bShowStaggeringControls = m_pParameter->CanAxisLabelsBeStaggered(); + auto & rLabelPage = static_cast<SchAxisLabelTabPage&>(rPage); + rLabelPage.ShowStaggeringControls( bShowStaggeringControls ); + rLabelPage.SetComplexCategories( m_pParameter->IsComplexCategoriesAxis() ); + } + else if (rId == "axispos") + { + AxisPositionsTabPage* pPage = dynamic_cast< AxisPositionsTabPage* >( &rPage ); + if(pPage) + { + pPage->SetNumFormatter( m_pNumberFormatter ); + if( m_pParameter->IsCrossingAxisIsCategoryAxis() ) + { + pPage->SetCrossingAxisIsCategoryAxis( m_pParameter->IsCrossingAxisIsCategoryAxis() ); + pPage->SetCategories( m_pParameter->GetCategories() ); + } + pPage->SupportAxisPositioning( m_pParameter->IsSupportingAxisPositioning() ); + pPage->SupportCategoryPositioning( m_pParameter->IsSupportingCategoryPositioning() ); + } + } + else if (rId == "scale") + { + ScaleTabPage* pScaleTabPage = dynamic_cast< ScaleTabPage* >( &rPage ); + if(pScaleTabPage) + { + pScaleTabPage->SetNumFormatter( m_pNumberFormatter ); + pScaleTabPage->ShowAxisOrigin( m_pParameter->ShowAxisOrigin() ); + } + } + else if (rId == "datalabels") + { + DataLabelsTabPage* pLabelPage = dynamic_cast< DataLabelsTabPage* >( &rPage ); + if( pLabelPage ) + pLabelPage->SetNumberFormatter( m_pNumberFormatter ); + } + else if (rId == "numberformat") + { + aSet.Put (SvxNumberInfoItem( m_pNumberFormatter, SID_ATTR_NUMBERFORMAT_INFO)); + rPage.PageCreated(aSet); + } + else if (rId == "xerrorbar") + { + ErrorBarsTabPage * pTabPage = dynamic_cast< ErrorBarsTabPage * >( &rPage ); + OSL_ASSERT( pTabPage ); + if( pTabPage ) + { + pTabPage->SetAxisMinorStepWidthForErrorBarDecimals( m_fAxisMinorStepWidthForErrorBarDecimals ); + pTabPage->SetErrorBarType( ErrorBarResources::ERROR_BAR_X ); + pTabPage->SetChartDocumentForRangeChoosing( m_pParameter->getDocument()); + } + } + else if (rId == "yerrorbar") + { + ErrorBarsTabPage * pTabPage = dynamic_cast< ErrorBarsTabPage * >( &rPage ); + OSL_ASSERT( pTabPage ); + if( pTabPage ) + { + pTabPage->SetAxisMinorStepWidthForErrorBarDecimals( m_fAxisMinorStepWidthForErrorBarDecimals ); + pTabPage->SetErrorBarType( ErrorBarResources::ERROR_BAR_Y ); + pTabPage->SetChartDocumentForRangeChoosing( m_pParameter->getDocument()); + } + } + else if (rId == "options") + { + SchOptionTabPage* pTabPage = dynamic_cast< SchOptionTabPage* >( &rPage ); + if( pTabPage && m_pParameter ) + pTabPage->Init( m_pParameter->ProvidesSecondaryYAxis(), m_pParameter->ProvidesOverlapAndGapWidth(), + m_pParameter->ProvidesBarConnectors() ); + } + else if (rId == "trendline") + { + TrendlineTabPage* pTrendlineTabPage = dynamic_cast< TrendlineTabPage* >( &rPage ); + if(pTrendlineTabPage) + { + pTrendlineTabPage->SetNumFormatter( m_pNumberFormatter ); + pTrendlineTabPage->SetNbPoints( m_pParameter->getNbPoints() ); + } + } +} + +IMPL_LINK(SchAttribTabDlg, OKPressed, weld::Button&, rButton, void) +{ + m_bOKPressed = true; + OkHdl(rButton); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ShapeFont.cxx b/chart2/source/controller/dialogs/dlg_ShapeFont.cxx new file mode 100644 index 000000000..f5fc702a2 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ShapeFont.cxx @@ -0,0 +1,61 @@ +/* -*- 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 <dlg_ShapeFont.hxx> +#include <ViewElementListProvider.hxx> + +#include <svl/intitem.hxx> +#include <svx/dialogs.hrc> +#include <svx/svxids.hrc> +#include <svx/flagsdef.hxx> +#include <editeng/flstitem.hxx> + +using namespace ::com::sun::star; + +namespace chart +{ + +ShapeFontDialog::ShapeFontDialog(weld::Window* pParent, const SfxItemSet* pAttr, + const ViewElementListProvider* pViewElementListProvider) + : SfxTabDialogController(pParent, "modules/schart/ui/chardialog.ui", "CharDialog", pAttr) + , m_pViewElementListProvider(pViewElementListProvider) +{ + AddTabPage("font", RID_SVXPAGE_CHAR_NAME); + AddTabPage("fonteffects", RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("position", RID_SVXPAGE_CHAR_POSITION ); +} + +void ShapeFontDialog::PageCreated(const OString& rId, SfxTabPage& rPage) +{ + SfxAllItemSet aSet( *( GetInputSetImpl()->GetPool() ) ); + if (rId == "font") + { + aSet.Put( SvxFontListItem( m_pViewElementListProvider->getFontList(), SID_ATTR_CHAR_FONTLIST ) ); + rPage.PageCreated( aSet ); + } + else if (rId == "fonteffects") + { + aSet.Put( SfxUInt16Item( SID_DISABLE_CTL, DISABLE_CASEMAP ) ); + rPage.PageCreated( aSet ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ShapeParagraph.cxx b/chart2/source/controller/dialogs/dlg_ShapeParagraph.cxx new file mode 100644 index 000000000..e5b422cea --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ShapeParagraph.cxx @@ -0,0 +1,64 @@ +/* -*- 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 <dlg_ShapeParagraph.hxx> + +#include <svl/cjkoptions.hxx> +#include <svl/intitem.hxx> +#include <svx/dialogs.hrc> +#include <svx/svxids.hrc> +#include <svx/flagsdef.hxx> + +using namespace ::com::sun::star; + +namespace chart +{ + +ShapeParagraphDialog::ShapeParagraphDialog(weld::Window* pParent, + const SfxItemSet* pAttr) + : SfxTabDialogController(pParent, "modules/schart/ui/paradialog.ui", "ParagraphDialog", pAttr) +{ + AddTabPage("labelTP_PARA_STD", RID_SVXPAGE_STD_PARAGRAPH); + AddTabPage("labelTP_PARA_ALIGN", RID_SVXPAGE_ALIGN_PARAGRAPH ); + if (SvtCJKOptions::IsAsianTypographyEnabled()) + { + AddTabPage("labelTP_PARA_ASIAN", RID_SVXPAGE_PARA_ASIAN); + } + else + { + RemoveTabPage("labelTP_PARA_ASIAN"); + } + AddTabPage("labelTP_TABULATOR", RID_SVXPAGE_TABULATOR); +} + +void ShapeParagraphDialog::PageCreated(const OString& rId, SfxTabPage& rPage) +{ + if (rId == "labelTP_TABULATOR") + { + SfxAllItemSet aSet( *( GetInputSetImpl()->GetPool() ) ); + TabulatorDisableFlags const nFlags(( TabulatorDisableFlags::TypeMask &~TabulatorDisableFlags::TypeLeft ) | + ( TabulatorDisableFlags::FillMask &~TabulatorDisableFlags::FillNone )); + aSet.Put( SfxUInt16Item( SID_SVXTABULATORTABPAGE_DISABLEFLAGS, static_cast<sal_uInt16>(nFlags)) ); + rPage.PageCreated( aSet ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_View3D.cxx b/chart2/source/controller/dialogs/dlg_View3D.cxx new file mode 100644 index 000000000..abc2645de --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_View3D.cxx @@ -0,0 +1,81 @@ +/* -*- 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 <dlg_View3D.hxx> +#include <strings.hrc> +#include <ResId.hxx> +#include "tp_3D_SceneGeometry.hxx" +#include "tp_3D_SceneAppearance.hxx" +#include "tp_3D_SceneIllumination.hxx" +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <Diagram.hxx> + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +sal_uInt16 View3DDialog::m_nLastPageId = 0; + +View3DDialog::View3DDialog(weld::Window* pParent, const rtl::Reference<::chart::ChartModel> & xChartModel) + : GenericDialogController(pParent, "modules/schart/ui/3dviewdialog.ui", "3DViewDialog") + , m_aControllerLocker(xChartModel) + , m_xTabControl(m_xBuilder->weld_notebook("tabcontrol")) +{ + rtl::Reference< Diagram > xSceneProperties = ChartModelHelper::findDiagram( xChartModel ); + + m_xTabControl->append_page("geometry", SchResId(STR_PAGE_PERSPECTIVE)); + m_xGeometry.reset(new ThreeD_SceneGeometry_TabPage(m_xTabControl->get_page("geometry"), xSceneProperties, m_aControllerLocker)); + + m_xTabControl->append_page("appearance", SchResId(STR_PAGE_APPEARANCE)); + m_xAppearance.reset(new ThreeD_SceneAppearance_TabPage(m_xTabControl->get_page("appearance"), xChartModel, m_aControllerLocker)); + + m_xTabControl->append_page("illumination", SchResId(STR_PAGE_ILLUMINATION)); + m_xIllumination.reset(new ThreeD_SceneIllumination_TabPage(m_xTabControl->get_page("illumination"), m_xDialog.get(), + xSceneProperties, xChartModel)); + + m_xTabControl->connect_enter_page(LINK(this, View3DDialog, ActivatePageHdl)); + + m_xTabControl->set_current_page(m_nLastPageId); +} + +IMPL_LINK(View3DDialog, ActivatePageHdl, const OString&, rPage, void) +{ + if (rPage == "appearance") + m_xAppearance->ActivatePage(); +} + +View3DDialog::~View3DDialog() +{ + m_nLastPageId = m_xTabControl->get_current_page(); +} + +short View3DDialog::run() +{ + short nResult = GenericDialogController::run(); + if (nResult == RET_OK && m_xGeometry) + m_xGeometry->commitPendingChanges(); + return nResult; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_BarGeometry.cxx b/chart2/source/controller/dialogs/res_BarGeometry.cxx new file mode 100644 index 000000000..97befbe1f --- /dev/null +++ b/chart2/source/controller/dialogs/res_BarGeometry.cxx @@ -0,0 +1,66 @@ +/* -*- 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 <res_BarGeometry.hxx> +#include <ResId.hxx> +#include <chart.hrc> + +namespace chart +{ +BarGeometryResources::BarGeometryResources(weld::Builder* pBuilder) + : m_xFT_Geometry(pBuilder->weld_label("shapeft")) + , m_xLB_Geometry(pBuilder->weld_tree_view("shape")) +{ + for (size_t i = 0; i < std::size(CHART_TYPE); ++i) + m_xLB_Geometry->append_text(SchResId(CHART_TYPE[i])); + m_xLB_Geometry->set_size_request(-1, + m_xLB_Geometry->get_height_rows(SAL_N_ELEMENTS(CHART_TYPE))); +} + +void BarGeometryResources::connect_changed(const Link<weld::TreeView&, void>& rLink) +{ + m_xLB_Geometry->connect_changed(rLink); +} + +void BarGeometryResources::set_visible(bool bShow) +{ + m_xFT_Geometry->set_visible(bShow); + m_xLB_Geometry->set_visible(bShow); +} + +void BarGeometryResources::set_sensitive(bool bEnable) +{ + m_xFT_Geometry->set_sensitive(bEnable); + m_xLB_Geometry->set_sensitive(bEnable); +} + +sal_Int32 BarGeometryResources::get_selected_index() const +{ + return m_xLB_Geometry->get_selected_index(); +} + +void BarGeometryResources::select(sal_Int32 nPos) +{ + if (nPos < m_xLB_Geometry->n_children()) + m_xLB_Geometry->select(nPos); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_DataLabel.cxx b/chart2/source/controller/dialogs/res_DataLabel.cxx new file mode 100644 index 000000000..3c6950e8e --- /dev/null +++ b/chart2/source/controller/dialogs/res_DataLabel.cxx @@ -0,0 +1,362 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include "res_DataLabel.hxx" + +#include <TextDirectionListBox.hxx> +#include <chartview/ChartSfxItemIds.hxx> +#include "dlg_NumberFormat.hxx" + +#include <svx/numinf.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svl/ilstitem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <svx/sdangitm.hxx> +#include <svx/svxids.hrc> +#include <osl/diagnose.h> + +namespace chart +{ + +namespace +{ + +const std::u16string_view our_aLBEntryMap[] = {u" ", u", ", u"; ", u"\n", u". "}; + +bool lcl_ReadNumberFormatFromItemSet( const SfxItemSet& rSet, TypedWhichId<SfxUInt32Item> nValueWhich, TypedWhichId<SfxBoolItem> nSourceFormatWhich, sal_uInt32& rnFormatKeyOut, bool& rbSourceFormatOut, bool& rbSourceFormatMixedStateOut ) +{ + bool bSet = false; + if( const SfxUInt32Item* pNumItem = rSet.GetItemIfSet( nValueWhich ) ) + { + rnFormatKeyOut = pNumItem->GetValue(); + bSet = true; + } + + rbSourceFormatMixedStateOut=true; + if( const SfxBoolItem * pBoolItem = rSet.GetItemIfSet( nSourceFormatWhich ) ) + { + rbSourceFormatOut = pBoolItem->GetValue(); + rbSourceFormatMixedStateOut=false; + } + return bSet; +} + +void lcl_setBoolItemToCheckBox(const SfxItemSet& rInAttrs, TypedWhichId<SfxBoolItem> nWhichId, weld::CheckButton& rCheckbox) +{ + if( const SfxBoolItem* pPoolItem = rInAttrs.GetItemIfSet(nWhichId) ) + rCheckbox.set_active(pPoolItem->GetValue()); + else + rCheckbox.set_state(TRISTATE_INDET); +} + +}//end anonymous namespace + +DataLabelResources::DataLabelResources(weld::Builder* pBuilder, weld::Window* pParent, const SfxItemSet& rInAttrs) + : m_pNumberFormatter(nullptr) + , m_bNumberFormatMixedState(true) + , m_bPercentFormatMixedState(true) + , m_nNumberFormatForValue(0) + , m_nNumberFormatForPercent(11) + , m_bSourceFormatMixedState(true) + , m_bPercentSourceMixedState(true) + , m_bSourceFormatForValue(true) + , m_bSourceFormatForPercent(true) + , m_pWindow(pParent) + , m_pPool(rInAttrs.GetPool()) + , m_xCBNumber(pBuilder->weld_check_button("CB_VALUE_AS_NUMBER")) + , m_xPB_NumberFormatForValue(pBuilder->weld_button("PB_NUMBERFORMAT")) + , m_xCBPercent(pBuilder->weld_check_button("CB_VALUE_AS_PERCENTAGE")) + , m_xPB_NumberFormatForPercent(pBuilder->weld_button("PB_PERCENT_NUMBERFORMAT")) + , m_xFT_NumberFormatForPercent(pBuilder->weld_label("STR_DLG_NUMBERFORMAT_FOR_PERCENTAGE_VALUE")) + , m_xCBCategory(pBuilder->weld_check_button("CB_CATEGORY")) + , m_xCBSymbol(pBuilder->weld_check_button("CB_SYMBOL")) + , m_xCBDataSeries(pBuilder->weld_check_button("CB_DATA_SERIES_NAME")) + , m_xCBWrapText(pBuilder->weld_check_button("CB_WRAP_TEXT")) + , m_xLB_Separator(pBuilder->weld_combo_box("LB_TEXT_SEPARATOR")) + , m_xLB_LabelPlacement(pBuilder->weld_combo_box("LB_LABEL_PLACEMENT")) + , m_xBxOrientation(pBuilder->weld_widget("boxORIENTATION")) + , m_xFT_Dial(pBuilder->weld_label("CT_LABEL_DIAL")) + , m_xNF_Degrees(pBuilder->weld_metric_spin_button("NF_LABEL_DEGREES", FieldUnit::DEGREE)) + , m_xBxTextDirection(pBuilder->weld_widget("boxTXT_DIRECTION")) + , m_xLB_TextDirection(new TextDirectionListBox(pBuilder->weld_combo_box("LB_LABEL_TEXTDIR"))) + , m_xDC_Dial(new svx::DialControl) + , m_xDC_DialWin(new weld::CustomWeld(*pBuilder, "CT_DIAL", *m_xDC_Dial)) + , m_xCBCustomLeaderLines(pBuilder->weld_check_button("CB_CUSTOM_LEADER_LINES")) +{ + m_xDC_Dial->SetText(m_xFT_Dial->get_label()); + + //fill label placement list + std::map< sal_Int32, OUString > aPlacementToStringMap; + for( sal_Int32 nEnum=0; nEnum<m_xLB_LabelPlacement->get_count(); ++nEnum ) + aPlacementToStringMap[nEnum] = m_xLB_LabelPlacement->get_text(static_cast<sal_uInt16>(nEnum)); + + + std::vector< sal_Int32 > aAvailablePlacementList; + if( const SfxIntegerListItem* pPlacementsItem = rInAttrs.GetItemIfSet(SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS) ) + aAvailablePlacementList = pPlacementsItem->GetList(); + + m_xLB_LabelPlacement->clear(); + for( size_t nN=0; nN<aAvailablePlacementList.size(); ++nN ) + { + sal_uInt16 nListBoxPos = static_cast<sal_uInt16>( nN ); + sal_Int32 nPlacement = aAvailablePlacementList[nN]; + m_aPlacementToListBoxMap[nPlacement]=nListBoxPos; + m_aListBoxToPlacementMap[nListBoxPos]=nPlacement; + m_xLB_LabelPlacement->append_text( aPlacementToStringMap[nPlacement] ); + } + + //some click handler + m_xPB_NumberFormatForValue->connect_clicked( LINK( this, DataLabelResources, NumberFormatDialogHdl ) ); + m_xPB_NumberFormatForPercent->connect_clicked( LINK( this, DataLabelResources, NumberFormatDialogHdl ) ); + m_xCBNumber->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBPercent->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBCategory->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBSymbol->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBDataSeries->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBWrapText->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBCustomLeaderLines->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + + m_bNumberFormatMixedState = !lcl_ReadNumberFormatFromItemSet( rInAttrs, SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_SOURCE, m_nNumberFormatForValue, m_bSourceFormatForValue, m_bSourceFormatMixedState ); + m_bPercentFormatMixedState = !lcl_ReadNumberFormatFromItemSet( rInAttrs, SCHATTR_PERCENT_NUMBERFORMAT_VALUE, SCHATTR_PERCENT_NUMBERFORMAT_SOURCE, m_nNumberFormatForPercent, m_bSourceFormatForPercent , m_bPercentSourceMixedState); + + if( const SfxBoolItem* pNoPercentValueItem = rInAttrs.GetItemIfSet(SCHATTR_DATADESCR_NO_PERCENTVALUE) ) + { + bool bForbidPercentValue = pNoPercentValueItem->GetValue(); + if( bForbidPercentValue ) + m_xCBPercent->set_sensitive(false); + } + + m_xDC_Dial->SetLinkedField(m_xNF_Degrees.get()); +} + +DataLabelResources::~DataLabelResources() +{ +} + +void DataLabelResources::SetNumberFormatter( SvNumberFormatter* pFormatter ) +{ + m_pNumberFormatter = pFormatter; +} + +IMPL_LINK(DataLabelResources, NumberFormatDialogHdl, weld::Button&, rButton, void) +{ + if( !m_pPool || !m_pNumberFormatter ) + { + OSL_FAIL("Missing item pool or number formatter"); + return; + } + + if (&rButton == m_xPB_NumberFormatForValue.get() && !m_xCBNumber->get_active()) + m_xCBNumber->set_active(true); + else if (&rButton == m_xPB_NumberFormatForPercent.get() && !m_xCBPercent->get_active()) + m_xCBPercent->set_active(true); + + SfxItemSet aNumberSet = NumberFormatDialog::CreateEmptyItemSetForNumberFormatDialog( *m_pPool ); + aNumberSet.Put (SvxNumberInfoItem( m_pNumberFormatter, SID_ATTR_NUMBERFORMAT_INFO)); + + bool bPercent = (&rButton == m_xPB_NumberFormatForPercent.get()); + + sal_uInt32& rnFormatKey = bPercent ? m_nNumberFormatForPercent : m_nNumberFormatForValue; + bool& rUseSourceFormat = bPercent ? m_bSourceFormatForPercent : m_bSourceFormatForValue; + bool& rbMixedState = bPercent ? m_bPercentFormatMixedState : m_bNumberFormatMixedState; + bool& rbSourceMixedState = bPercent ? m_bPercentSourceMixedState : m_bSourceFormatMixedState; + + if(!rbMixedState) + aNumberSet.Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE, rnFormatKey )); + aNumberSet.Put( SfxBoolItem( SID_ATTR_NUMBERFORMAT_SOURCE, rUseSourceFormat )); + + NumberFormatDialog aDlg(m_pWindow, aNumberSet); + if( bPercent ) + aDlg.set_title(m_xFT_NumberFormatForPercent->get_label()); + if (aDlg.run() != RET_OK) + return; + + const SfxItemSet* pResult = aDlg.GetOutputItemSet(); + if( pResult ) + { + bool bOldSource = rUseSourceFormat; + sal_uInt32 nOldFormat = rnFormatKey; + bool bOldMixedState = rbMixedState || rbSourceMixedState; + + rbMixedState = !lcl_ReadNumberFormatFromItemSet( *pResult, SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_SOURCE, rnFormatKey, rUseSourceFormat, rbSourceMixedState ); + + //todo this maybe can be removed when the numberformatter dialog does handle mixed state for source format correctly + if( bOldMixedState && bOldSource == rUseSourceFormat && nOldFormat == rnFormatKey ) + rbMixedState = rbSourceMixedState = true; + } +} + +IMPL_LINK_NOARG(DataLabelResources, CheckHdl, weld::Toggleable&, void) +{ + EnableControls(); +} + +void DataLabelResources::EnableControls() +{ + m_xCBSymbol->set_sensitive( m_xCBNumber->get_active() || (m_xCBPercent->get_active() && m_xCBPercent->get_sensitive()) + || m_xCBCategory->get_active() || m_xCBDataSeries->get_active()); + + m_xCBWrapText->set_sensitive( m_xCBNumber->get_active() || (m_xCBPercent->get_active() && m_xCBPercent->get_sensitive()) + || m_xCBCategory->get_active() || m_xCBDataSeries->get_active() ); + + // Enable or disable separator, placement and direction based on the check + // box states. Note that the check boxes are tri-state. + { + tools::Long nNumberOfCheckedLabelParts = 0; + if (m_xCBNumber->get_state() != TRISTATE_FALSE) + ++nNumberOfCheckedLabelParts; + if (m_xCBPercent->get_state() != TRISTATE_FALSE && m_xCBPercent->get_sensitive()) + ++nNumberOfCheckedLabelParts; + if (m_xCBCategory->get_state() != TRISTATE_FALSE) + ++nNumberOfCheckedLabelParts; + if (m_xCBDataSeries->get_state() != TRISTATE_FALSE) + ++nNumberOfCheckedLabelParts; + + m_xLB_Separator->set_sensitive( nNumberOfCheckedLabelParts > 1 ); + + bool bEnableTextDir = nNumberOfCheckedLabelParts > 0; + m_xBxTextDirection->set_sensitive( bEnableTextDir ); + bool bEnablePlacement = nNumberOfCheckedLabelParts > 0 && m_xLB_LabelPlacement->get_count()>1; + m_xLB_LabelPlacement->set_sensitive( bEnablePlacement ); + } + + m_xPB_NumberFormatForValue->set_sensitive( m_pNumberFormatter && m_xCBNumber->get_active() ); + m_xPB_NumberFormatForPercent->set_sensitive( m_pNumberFormatter && m_xCBPercent->get_active() && m_xCBPercent->get_sensitive() ); + + bool bEnableRotation = (m_xCBNumber->get_active() || m_xCBPercent->get_active() + || m_xCBCategory->get_active() || m_xCBDataSeries->get_active()); + m_xBxOrientation->set_sensitive(bEnableRotation); +} + +void DataLabelResources::FillItemSet( SfxItemSet* rOutAttrs ) const +{ + if( m_xCBNumber->get_active() ) + { + if( !m_bNumberFormatMixedState ) + rOutAttrs->Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE, m_nNumberFormatForValue )); + if( !m_bSourceFormatMixedState ) + rOutAttrs->Put( SfxBoolItem( SID_ATTR_NUMBERFORMAT_SOURCE, m_bSourceFormatForValue )); + } + if( m_xCBPercent->get_active() ) + { + if( !m_bPercentFormatMixedState ) + rOutAttrs->Put( SfxUInt32Item( SCHATTR_PERCENT_NUMBERFORMAT_VALUE, m_nNumberFormatForPercent )); + if( !m_bPercentSourceMixedState ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_PERCENT_NUMBERFORMAT_SOURCE, m_bSourceFormatForPercent )); + } + + if( m_xCBNumber->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_NUMBER, m_xCBNumber->get_active() ) ); + if( m_xCBPercent->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_PERCENTAGE, m_xCBPercent->get_active() ) ); + if( m_xCBCategory->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_CATEGORY, m_xCBCategory->get_active() ) ); + if( m_xCBSymbol->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_SYMBOL, m_xCBSymbol->get_active()) ); + if( m_xCBDataSeries->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME, m_xCBDataSeries->get_active()) ); + if( m_xCBWrapText->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_WRAP_TEXT, m_xCBWrapText->get_active()) ); + if( m_xCBCustomLeaderLines->get_state() != TRISTATE_INDET ) + rOutAttrs->Put(SfxBoolItem( SCHATTR_DATADESCR_CUSTOM_LEADER_LINES, m_xCBCustomLeaderLines->get_active()) ); + + auto const aSep = our_aLBEntryMap[m_xLB_Separator->get_active()]; + rOutAttrs->Put( SfxStringItem( SCHATTR_DATADESCR_SEPARATOR, OUString(aSep)) ); + + std::map< sal_uInt16, sal_Int32 >::const_iterator aIt( m_aListBoxToPlacementMap.find(m_xLB_LabelPlacement->get_active()) ); + if(aIt!=m_aListBoxToPlacementMap.end()) + { + sal_Int32 nValue = aIt->second; + rOutAttrs->Put( SfxInt32Item( SCHATTR_DATADESCR_PLACEMENT, nValue ) ); + } + + if (m_xLB_TextDirection->get_active() != -1) + rOutAttrs->Put( SvxFrameDirectionItem( m_xLB_TextDirection->get_active_id(), EE_PARA_WRITINGDIR ) ); + + if( m_xDC_Dial->IsVisible() ) + { + Degree100 nDegrees = m_xDC_Dial->GetRotation(); + rOutAttrs->Put(SdrAngleItem( SCHATTR_TEXT_DEGREES, nDegrees ) ); + } +} + +void DataLabelResources::Reset(const SfxItemSet& rInAttrs) +{ + // default state + m_xCBSymbol->set_sensitive( false ); + + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_NUMBER, *m_xCBNumber ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_PERCENTAGE, *m_xCBPercent ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_CATEGORY, *m_xCBCategory ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_SYMBOL, *m_xCBSymbol ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME, *m_xCBDataSeries ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_WRAP_TEXT, *m_xCBWrapText ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_CUSTOM_LEADER_LINES, *m_xCBCustomLeaderLines ); + + m_bNumberFormatMixedState = !lcl_ReadNumberFormatFromItemSet( rInAttrs, SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_SOURCE, m_nNumberFormatForValue, m_bSourceFormatForValue, m_bSourceFormatMixedState ); + m_bPercentFormatMixedState = !lcl_ReadNumberFormatFromItemSet( rInAttrs, SCHATTR_PERCENT_NUMBERFORMAT_VALUE, SCHATTR_PERCENT_NUMBERFORMAT_SOURCE, m_nNumberFormatForPercent, m_bSourceFormatForPercent , m_bPercentSourceMixedState); + + if( const SfxStringItem* pSeparatorItem = rInAttrs.GetItemIfSet(SCHATTR_DATADESCR_SEPARATOR) ) + for(size_t i=0; i < std::size(our_aLBEntryMap); ++i ) + { + if( our_aLBEntryMap[i] == pSeparatorItem->GetValue()) + m_xLB_Separator->set_active( i ); + } + else + m_xLB_Separator->set_active( 0 ); + + if( const SfxInt32Item* pPlacementItem = rInAttrs.GetItemIfSet(SCHATTR_DATADESCR_PLACEMENT) ) + { + sal_Int32 nPlacement = pPlacementItem->GetValue(); + std::map< sal_Int32, sal_uInt16 >::const_iterator aIt( m_aPlacementToListBoxMap.find(nPlacement) ); + if(aIt!=m_aPlacementToListBoxMap.end()) + { + sal_uInt16 nPos = aIt->second; + m_xLB_LabelPlacement->set_active( nPos ); + } + else + m_xLB_LabelPlacement->set_active(-1); + } + else + m_xLB_LabelPlacement->set_active(-1); + + if( const SvxFrameDirectionItem* pDirectionItem = rInAttrs.GetItemIfSet(EE_PARA_WRITINGDIR) ) + m_xLB_TextDirection->set_active_id( pDirectionItem->GetValue() ); + + if( const SdrAngleItem* pAngleItem = rInAttrs.GetItemIfSet( SCHATTR_TEXT_DEGREES ) ) + { + Degree100 nDegrees = pAngleItem->GetValue(); + m_xDC_Dial->SetRotation( nDegrees ); + } + else + m_xDC_Dial->SetRotation( 0_deg100 ); + + EnableControls(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_DataLabel.hxx b/chart2/source/controller/dialogs/res_DataLabel.hxx new file mode 100644 index 000000000..56115b2a7 --- /dev/null +++ b/chart2/source/controller/dialogs/res_DataLabel.hxx @@ -0,0 +1,93 @@ +/* -*- 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 <svl/itemset.hxx> +#include <svx/dialcontrol.hxx> + +#include <map> + +class SvNumberFormatter; +namespace chart { class TextDirectionListBox; } + +namespace chart +{ + +class DataLabelResources final +{ +public: + DataLabelResources(weld::Builder* pBuilder, weld::Window* pParent, const SfxItemSet& rInAttrs); + ~DataLabelResources(); + + void FillItemSet(SfxItemSet* rOutAttrs) const; + void Reset(const SfxItemSet& rInAttrs); + + void SetNumberFormatter( SvNumberFormatter* pFormatter ); + +private: + std::map< sal_Int32, sal_uInt16 > m_aPlacementToListBoxMap; + std::map< sal_uInt16, sal_Int32 > m_aListBoxToPlacementMap; + + SvNumberFormatter* m_pNumberFormatter; + bool m_bNumberFormatMixedState; + bool m_bPercentFormatMixedState; + sal_uInt32 m_nNumberFormatForValue; + sal_uInt32 m_nNumberFormatForPercent; + + bool m_bSourceFormatMixedState; + bool m_bPercentSourceMixedState; + bool m_bSourceFormatForValue; + bool m_bSourceFormatForPercent; + + weld::Window* m_pWindow; + SfxItemPool* m_pPool; + + std::unique_ptr<weld::CheckButton> m_xCBNumber; + std::unique_ptr<weld::Button> m_xPB_NumberFormatForValue; + std::unique_ptr<weld::CheckButton> m_xCBPercent; + std::unique_ptr<weld::Button> m_xPB_NumberFormatForPercent; + std::unique_ptr<weld::Label> m_xFT_NumberFormatForPercent; + std::unique_ptr<weld::CheckButton> m_xCBCategory; + std::unique_ptr<weld::CheckButton> m_xCBSymbol; + std::unique_ptr<weld::CheckButton> m_xCBDataSeries; + std::unique_ptr<weld::CheckButton> m_xCBWrapText; + + std::unique_ptr<weld::ComboBox> m_xLB_Separator; + std::unique_ptr<weld::ComboBox> m_xLB_LabelPlacement; + + std::unique_ptr<weld::Widget> m_xBxOrientation; + std::unique_ptr<weld::Label> m_xFT_Dial; + std::unique_ptr<weld::MetricSpinButton> m_xNF_Degrees; + + std::unique_ptr<weld::Widget> m_xBxTextDirection; + + std::unique_ptr<TextDirectionListBox> m_xLB_TextDirection; + std::unique_ptr<svx::DialControl> m_xDC_Dial; + std::unique_ptr<weld::CustomWeld> m_xDC_DialWin; + + std::unique_ptr<weld::CheckButton> m_xCBCustomLeaderLines; + + DECL_LINK(NumberFormatDialogHdl, weld::Button&, void ); + DECL_LINK(CheckHdl, weld::Toggleable&, void ); + void EnableControls(); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_ErrorBar.cxx b/chart2/source/controller/dialogs/res_ErrorBar.cxx new file mode 100644 index 000000000..12fabc659 --- /dev/null +++ b/chart2/source/controller/dialogs/res_ErrorBar.cxx @@ -0,0 +1,716 @@ +/* -*- 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 <res_ErrorBar.hxx> +#include <bitmaps.hlst> +#include <RangeSelectionHelper.hxx> +#include <helpids.h> +#include <chartview/ChartSfxItemIds.hxx> +#include <vcl/weld.hxx> +#include <ChartModel.hxx> + +#include <rtl/math.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <svl/stritem.hxx> + +#define CHART_LB_FUNCTION_STD_ERROR 0 +#define CHART_LB_FUNCTION_STD_DEV 1 +#define CHART_LB_FUNCTION_VARIANCE 2 +#define CHART_LB_FUNCTION_ERROR_MARGIN 3 + +using namespace ::com::sun::star; + +namespace +{ +void lcl_enableRangeChoosing(bool bEnable, weld::DialogController* pController) +{ + weld::Window* pWeldDialog = pController->getDialog(); + pWeldDialog->set_modal(!bEnable); + pWeldDialog->set_visible(!bEnable); +} + +sal_uInt16 lcl_getLbEntryPosByErrorKind( SvxChartKindError eErrorKind ) +{ + sal_uInt16 nResult = 0; + switch( eErrorKind ) + { + // for these cases select the default in the list box + case SvxChartKindError::NONE: + case SvxChartKindError::Percent: + case SvxChartKindError::Const: + case SvxChartKindError::Range: + nResult = CHART_LB_FUNCTION_STD_DEV; + break; + case SvxChartKindError::Variant: + nResult = CHART_LB_FUNCTION_VARIANCE; + break; + case SvxChartKindError::Sigma: + nResult = CHART_LB_FUNCTION_STD_DEV; + break; + case SvxChartKindError::BigError: + nResult = CHART_LB_FUNCTION_ERROR_MARGIN; + break; + case SvxChartKindError::StdError: + nResult = CHART_LB_FUNCTION_STD_ERROR; + break; + } + return nResult; +} +} // anonymous namespace + +namespace chart +{ + +ErrorBarResources::ErrorBarResources(weld::Builder* pParent, weld::DialogController* pController, + const SfxItemSet& rInAttrs, bool bNoneAvailable, + tErrorBarType eType /* = ERROR_BAR_Y */ ) + : m_eErrorKind( SvxChartKindError::NONE ) + , m_eIndicate( SvxChartIndicate::Both ) + , m_bErrorKindUnique( true ) + , m_bIndicatorUnique( true ) + , m_bRangePosUnique( true ) + , m_bRangeNegUnique( true ) + , m_eErrorBarType( eType ) + , m_nConstDecimalDigits( 1 ) + , m_nConstSpinSize( 1 ) + , m_fPlusValue(0.0) + , m_fMinusValue(0.0) + , m_pController(pController) + , m_pCurrentRangeChoosingField( nullptr ) + , m_bHasInternalDataProvider( true ) + , m_bEnableDataTableDialog( true ) + , m_xRbNone(pParent->weld_radio_button("RB_NONE")) + , m_xRbConst(pParent->weld_radio_button("RB_CONST")) + , m_xRbPercent(pParent->weld_radio_button("RB_PERCENT")) + , m_xRbFunction(pParent->weld_radio_button("RB_FUNCTION")) + , m_xRbRange(pParent->weld_radio_button("RB_RANGE")) + , m_xLbFunction(pParent->weld_combo_box("LB_FUNCTION")) + , m_xFlParameters(pParent->weld_frame("framePARAMETERS")) + , m_xBxPositive(pParent->weld_widget("boxPOSITIVE")) + , m_xMfPositive(pParent->weld_metric_spin_button("MF_POSITIVE", FieldUnit::NONE)) + , m_xEdRangePositive(pParent->weld_entry("ED_RANGE_POSITIVE")) + , m_xIbRangePositive(pParent->weld_button("IB_RANGE_POSITIVE")) + , m_xBxNegative(pParent->weld_widget("boxNEGATIVE")) + , m_xMfNegative(pParent->weld_metric_spin_button("MF_NEGATIVE", FieldUnit::NONE)) + , m_xEdRangeNegative(pParent->weld_entry("ED_RANGE_NEGATIVE")) + , m_xIbRangeNegative(pParent->weld_button("IB_RANGE_NEGATIVE")) + , m_xCbSyncPosNeg(pParent->weld_check_button("CB_SYN_POS_NEG")) + , m_xRbBoth(pParent->weld_radio_button("RB_BOTH")) + , m_xRbPositive(pParent->weld_radio_button("RB_POSITIVE")) + , m_xRbNegative(pParent->weld_radio_button("RB_NEGATIVE")) + , m_xFiBoth(pParent->weld_image("FI_BOTH")) + , m_xFiPositive(pParent->weld_image("FI_POSITIVE")) + , m_xFiNegative(pParent->weld_image("FI_NEGATIVE")) + , m_xUIStringPos(pParent->weld_label("STR_DATA_SELECT_RANGE_FOR_POSITIVE_ERRORBARS")) + , m_xUIStringNeg(pParent->weld_label("STR_DATA_SELECT_RANGE_FOR_NEGATIVE_ERRORBARS")) + , m_xUIStringRbRange(pParent->weld_label("STR_CONTROLTEXT_ERROR_BARS_FROM_DATA")) +{ + if( bNoneAvailable ) + m_xRbNone->connect_toggled(LINK(this, ErrorBarResources, CategoryChosen)); + else + m_xRbNone->hide(); + + m_xRbConst->connect_toggled( LINK( this, ErrorBarResources, CategoryChosen )); + m_xRbPercent->connect_toggled( LINK( this, ErrorBarResources, CategoryChosen )); + m_xRbFunction->connect_toggled( LINK( this, ErrorBarResources, CategoryChosen )); + m_xRbRange->connect_toggled( LINK( this, ErrorBarResources, CategoryChosen )); + m_xLbFunction->connect_changed( LINK( this, ErrorBarResources, CategoryChosen2 )); + + m_xCbSyncPosNeg->set_active( false ); + m_xCbSyncPosNeg->connect_toggled( LINK( this, ErrorBarResources, SynchronizePosAndNeg )); + + m_xMfPositive->connect_value_changed( LINK( this, ErrorBarResources, PosValueChanged )); + m_xEdRangePositive->connect_changed( LINK( this, ErrorBarResources, RangeChanged )); + m_xEdRangeNegative->connect_changed( LINK( this, ErrorBarResources, RangeChanged )); + + m_xRbPositive->connect_toggled( LINK( this, ErrorBarResources, IndicatorChanged )); + m_xRbNegative->connect_toggled( LINK( this, ErrorBarResources, IndicatorChanged )); + m_xRbBoth->connect_toggled( LINK( this, ErrorBarResources, IndicatorChanged )); + + m_xIbRangePositive->connect_clicked( LINK( this, ErrorBarResources, ChooseRange )); + m_xIbRangeNegative->connect_clicked( LINK( this, ErrorBarResources, ChooseRange )); + + FillValueSets(); + Reset( rInAttrs ); +} + +ErrorBarResources::~ErrorBarResources() +{ +} + +void ErrorBarResources::SetErrorBarType( tErrorBarType eNewType ) +{ + if( m_eErrorBarType != eNewType ) + { + m_eErrorBarType = eNewType; + FillValueSets(); + } +} + +void ErrorBarResources::SetChartDocumentForRangeChoosing( + const rtl::Reference<::chart::ChartModel> & xChartDocument ) +{ + if( xChartDocument.is()) + { + m_bHasInternalDataProvider = xChartDocument->hasInternalDataProvider(); + uno::Reference< beans::XPropertySet > xProps( static_cast<cppu::OWeakObject*>(xChartDocument.get()), uno::UNO_QUERY ); + if ( xProps.is() ) + { + try + { + xProps->getPropertyValue("EnableDataTableDialog") >>= m_bEnableDataTableDialog; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } + m_apRangeSelectionHelper.reset( new RangeSelectionHelper( xChartDocument )); + + // has internal data provider => rename "cell range" to "from data" + OSL_ASSERT(m_apRangeSelectionHelper); + if( m_bHasInternalDataProvider ) + { + m_xRbRange->set_label(m_xUIStringRbRange->get_label()); + m_xRbRange->set_help_id(HID_SCH_ERROR_BARS_FROM_DATA); + } + + if( m_xRbRange->get_active()) + { + isRangeFieldContentValid( *m_xEdRangePositive ); + isRangeFieldContentValid( *m_xEdRangeNegative ); + } +} + +void ErrorBarResources::SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ) +{ + if( fMinorStepWidth < 0 ) + fMinorStepWidth = -fMinorStepWidth; + + sal_Int32 nExponent = static_cast< sal_Int32 >( ::rtl::math::approxFloor( log10( fMinorStepWidth ))); + if( nExponent <= 0 ) + { + // one digit precision more + m_nConstDecimalDigits = static_cast< sal_uInt16 >( (-nExponent) + 1 ); + m_nConstSpinSize = 10; + } + else + { + m_nConstDecimalDigits = 0; + m_nConstSpinSize = static_cast< sal_Int64 >( pow( 10.0, static_cast<int>(nExponent) )); + } +} + +void ErrorBarResources::UpdateControlStates() +{ + // function + bool bIsFunction = m_xRbFunction->get_active(); + m_xLbFunction->set_sensitive( bIsFunction ); + + // range buttons + m_xRbRange->set_sensitive( !m_bHasInternalDataProvider || m_bEnableDataTableDialog ); + bool bShowRange = m_xRbRange->get_active(); + bool bCanChooseRange = + ( bShowRange && + m_apRangeSelectionHelper && + m_apRangeSelectionHelper->hasRangeSelection()); + + m_xMfPositive->set_visible( ! bShowRange ); + m_xMfNegative->set_visible( ! bShowRange ); + + // use range but without range chooser => hide controls + m_xEdRangePositive->set_visible( bShowRange && ! m_bHasInternalDataProvider ); + m_xIbRangePositive->set_visible( bCanChooseRange ); + m_xEdRangeNegative->set_visible( bShowRange && ! m_bHasInternalDataProvider ); + m_xIbRangeNegative->set_visible( bCanChooseRange ); + + bool bShowPosNegAndSync = ! (bShowRange && m_bHasInternalDataProvider); + m_xFlParameters->set_visible( bShowPosNegAndSync ); + + // unit for metric fields + bool bIsErrorMargin( + ( m_xRbFunction->get_active()) && + ( m_xLbFunction->get_active() == CHART_LB_FUNCTION_ERROR_MARGIN )); + bool bIsPercentage( m_xRbPercent->get_active() || bIsErrorMargin ); + FieldUnit eFieldUnit = FieldUnit::NONE; + + if( bIsPercentage ) + { + eFieldUnit = FieldUnit::PERCENT; + m_xMfPositive->set_digits( 1 ); + m_xMfPositive->set_increments(10, 100, FieldUnit::NONE); + m_xMfNegative->set_digits( 1 ); + m_xMfNegative->set_increments(10, 100, FieldUnit::NONE); + } + else + { + m_xMfPositive->set_digits( m_nConstDecimalDigits ); + m_xMfPositive->set_increments(m_nConstSpinSize, m_nConstSpinSize * 10, FieldUnit::NONE); + m_xMfNegative->set_digits( m_nConstDecimalDigits ); + m_xMfNegative->set_increments(m_nConstSpinSize, m_nConstSpinSize * 10, FieldUnit::NONE); + } + + sal_Int32 nPlusValue = static_cast< sal_Int32 >( m_fPlusValue * pow(10.0,m_xMfPositive->get_digits()) ); + sal_Int32 nMinusValue = static_cast< sal_Int32 >( m_fMinusValue * pow(10.0,m_xMfNegative->get_digits()) ); + + m_xMfPositive->set_value(nPlusValue, FieldUnit::NONE); + m_xMfNegative->set_value(nMinusValue, FieldUnit::NONE); + + m_xMfPositive->set_unit(eFieldUnit); + m_xMfNegative->set_unit(eFieldUnit); + + // positive and negative value fields + bool bPosEnabled = ( m_xRbPositive->get_active() || m_xRbBoth->get_active()); + bool bNegEnabled = ( m_xRbNegative->get_active() || m_xRbBoth->get_active()); + if( !( bPosEnabled || bNegEnabled )) + { + // all three controls are not checked -> ambiguous state + bPosEnabled = true; + bNegEnabled = true; + } + + // functions with only one parameter + bool bOneParameterCategory = + bIsErrorMargin || m_xRbPercent->get_active(); + if( bOneParameterCategory ) + { + m_xCbSyncPosNeg->set_active(true); + } + + if( m_xCbSyncPosNeg->get_active()) + { + bPosEnabled = true; + bNegEnabled = false; + } + + // all functions except error margin take no arguments + if( m_xRbFunction->get_active() && ( m_xLbFunction->get_active() != CHART_LB_FUNCTION_ERROR_MARGIN )) + { + bPosEnabled = false; + bNegEnabled = false; + } + + // enable/disable pos/neg fields + m_xBxPositive->set_sensitive( bPosEnabled ); + m_xBxNegative->set_sensitive( bNegEnabled ); + if( bShowRange ) + { + m_xEdRangePositive->set_sensitive( bPosEnabled ); + m_xIbRangePositive->set_sensitive( bPosEnabled ); + m_xEdRangeNegative->set_sensitive( bNegEnabled ); + m_xIbRangeNegative->set_sensitive( bNegEnabled ); + } + else + { + m_xMfPositive->set_sensitive( bPosEnabled ); + m_xMfNegative->set_sensitive( bNegEnabled ); + } + + m_xCbSyncPosNeg->set_sensitive( !bOneParameterCategory && ( bPosEnabled || bNegEnabled )); + + // mark invalid entries in the range fields + if( bShowRange && ! m_bHasInternalDataProvider ) + { + isRangeFieldContentValid( *m_xEdRangePositive ); + isRangeFieldContentValid( *m_xEdRangeNegative ); + } +} + +IMPL_LINK_NOARG( ErrorBarResources, CategoryChosen2, weld::ComboBox&, void ) +{ + CategoryChosen(*m_xRbConst); +} + +IMPL_LINK_NOARG( ErrorBarResources, CategoryChosen, weld::Toggleable&, void ) +{ + m_bErrorKindUnique = true; + SvxChartKindError eOldError = m_eErrorKind; + + if( m_xRbNone->get_active()) + m_eErrorKind = SvxChartKindError::NONE; + else if( m_xRbConst->get_active()) + m_eErrorKind = SvxChartKindError::Const; + else if( m_xRbPercent->get_active()) + m_eErrorKind = SvxChartKindError::Percent; + else if( m_xRbRange->get_active()) + m_eErrorKind = SvxChartKindError::Range; + else if( m_xRbFunction->get_active()) + { + switch( m_xLbFunction->get_active()) + { + case CHART_LB_FUNCTION_STD_ERROR: + m_eErrorKind = SvxChartKindError::StdError; break; + case CHART_LB_FUNCTION_STD_DEV: + m_eErrorKind = SvxChartKindError::Sigma; break; + case CHART_LB_FUNCTION_VARIANCE: + m_eErrorKind = SvxChartKindError::Variant; break; + case CHART_LB_FUNCTION_ERROR_MARGIN: + m_eErrorKind = SvxChartKindError::BigError; break; + default: + m_bErrorKindUnique = false; + } + } + else + { + OSL_FAIL( "Unknown category chosen" ); + m_bErrorKindUnique = false; + } + + // changed to range + if( m_eErrorKind == SvxChartKindError::Range && + eOldError != SvxChartKindError::Range ) + { + m_xCbSyncPosNeg->set_active( + (!m_xEdRangePositive->get_text().isEmpty()) && + m_xEdRangePositive->get_text() == m_xEdRangeNegative->get_text()); + } + // changed from range + else if( m_eErrorKind != SvxChartKindError::Range && + eOldError == SvxChartKindError::Range ) + { + m_xCbSyncPosNeg->set_active( m_xMfPositive->get_value(FieldUnit::NONE) == m_xMfNegative->get_value(FieldUnit::NONE)); + } + + UpdateControlStates(); +} + +IMPL_LINK_NOARG(ErrorBarResources, SynchronizePosAndNeg, weld::Toggleable&, void) +{ + UpdateControlStates(); + PosValueChanged( *m_xMfPositive ); +} + +IMPL_LINK_NOARG(ErrorBarResources, PosValueChanged, weld::MetricSpinButton&, void) +{ + if( m_xCbSyncPosNeg->get_active()) + { + if( m_xRbRange->get_active()) + { + m_xEdRangeNegative->set_text( m_xEdRangePositive->get_text()); + m_bRangeNegUnique = m_bRangePosUnique; + } + else + m_xMfNegative->set_value(m_xMfPositive->get_value(FieldUnit::NONE), FieldUnit::NONE); + } +} + +IMPL_LINK_NOARG(ErrorBarResources, IndicatorChanged, weld::Toggleable&, void) +{ + m_bIndicatorUnique = true; + if( m_xRbBoth->get_active()) + m_eIndicate = SvxChartIndicate::Both; + else if( m_xRbPositive->get_active()) + m_eIndicate = SvxChartIndicate::Up; + else if( m_xRbNegative->get_active()) + m_eIndicate = SvxChartIndicate::Down; + else + m_bIndicatorUnique = false; + + UpdateControlStates(); +} + +IMPL_LINK(ErrorBarResources, ChooseRange, weld::Button&, rButton, void) +{ + OSL_ASSERT(m_apRangeSelectionHelper); + if (!m_apRangeSelectionHelper) + return; + OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr ); + + OUString aUIString; + + if (&rButton == m_xIbRangePositive.get()) + { + m_pCurrentRangeChoosingField = m_xEdRangePositive.get(); + aUIString = m_xUIStringPos->get_label(); + } + else + { + m_pCurrentRangeChoosingField = m_xEdRangeNegative.get(); + aUIString = m_xUIStringNeg->get_label(); + } + + lcl_enableRangeChoosing(true, m_pController); + m_apRangeSelectionHelper->chooseRange( + m_pCurrentRangeChoosingField->get_text(), + aUIString, *this ); +} + +IMPL_LINK( ErrorBarResources, RangeChanged, weld::Entry&, rEdit, void ) +{ + if( &rEdit == m_xEdRangePositive.get() ) + { + m_bRangePosUnique = true; + PosValueChanged( *m_xMfPositive ); + } + else + { + m_bRangeNegUnique = true; + } + + isRangeFieldContentValid( rEdit ); +} + +void ErrorBarResources::Reset(const SfxItemSet& rInAttrs) +{ + const SfxPoolItem *pPoolItem = nullptr; + + // category + m_eErrorKind = SvxChartKindError::NONE; + SfxItemState aState = rInAttrs.GetItemState( SCHATTR_STAT_KIND_ERROR, true, &pPoolItem ); + m_bErrorKindUnique = ( aState != SfxItemState::DONTCARE ); + + if( aState == SfxItemState::SET ) + m_eErrorKind = static_cast<const SvxChartKindErrorItem*>(pPoolItem)->GetValue(); + + m_xLbFunction->set_active( lcl_getLbEntryPosByErrorKind( m_eErrorKind )); + + if( m_bErrorKindUnique ) + { + switch( m_eErrorKind ) + { + case SvxChartKindError::NONE: + m_xRbNone->set_active(true); + break; + case SvxChartKindError::Percent: + m_xRbPercent->set_active(true); + break; + case SvxChartKindError::Const: + m_xRbConst->set_active(true); + break; + case SvxChartKindError::StdError: + case SvxChartKindError::Variant: + case SvxChartKindError::Sigma: + case SvxChartKindError::BigError: + m_xRbFunction->set_active(true); + break; + case SvxChartKindError::Range: + m_xRbRange->set_active(true); + break; + } + } + else + { + m_xRbNone->set_active( false ); + m_xRbConst->set_active( false ); + m_xRbPercent->set_active( false ); + m_xRbFunction->set_active( false ); + } + + // parameters + if( const SvxDoubleItem* pDoubleItem = rInAttrs.GetItemIfSet( SCHATTR_STAT_CONSTPLUS ) ) + { + m_fPlusValue = pDoubleItem->GetValue(); + } + + if( const SvxDoubleItem* pStatItem = rInAttrs.GetItemIfSet( SCHATTR_STAT_CONSTMINUS ) ) + { + m_fMinusValue = pStatItem->GetValue(); + + if( m_eErrorKind != SvxChartKindError::Range && + m_fPlusValue == m_fMinusValue ) + m_xCbSyncPosNeg->set_active(true); + } + + // indicator + aState = rInAttrs.GetItemState( SCHATTR_STAT_INDICATE, true, &pPoolItem ); + m_bIndicatorUnique = ( aState != SfxItemState::DONTCARE ); + if( aState == SfxItemState::SET) + m_eIndicate = static_cast<const SvxChartIndicateItem *>(pPoolItem)->GetValue(); + + if( m_bIndicatorUnique ) + { + switch( m_eIndicate ) + { + case SvxChartIndicate::NONE : + // no longer used, use both as default + m_eIndicate = SvxChartIndicate::Both; + [[fallthrough]]; // to BOTH + case SvxChartIndicate::Both : + m_xRbBoth->set_active(true); break; + case SvxChartIndicate::Up : + m_xRbPositive->set_active(true); break; + case SvxChartIndicate::Down : + m_xRbNegative->set_active(true); break; + } + } + else + { + m_xRbBoth->set_active( false ); + m_xRbPositive->set_active( false ); + m_xRbNegative->set_active( false ); + } + + // ranges + aState = rInAttrs.GetItemState( SCHATTR_STAT_RANGE_POS, true, &pPoolItem ); + m_bRangePosUnique = ( aState != SfxItemState::DONTCARE ); + if( aState == SfxItemState::SET ) + { + OUString sRangePositive = static_cast< const SfxStringItem * >( pPoolItem )->GetValue(); + m_xEdRangePositive->set_text( sRangePositive ); + } + + aState = rInAttrs.GetItemState( SCHATTR_STAT_RANGE_NEG, true, &pPoolItem ); + m_bRangeNegUnique = ( aState != SfxItemState::DONTCARE ); + if( aState == SfxItemState::SET ) + { + OUString sRangeNegative = static_cast< const SfxStringItem * >( pPoolItem )->GetValue(); + m_xEdRangeNegative->set_text( sRangeNegative ); + if( m_eErrorKind == SvxChartKindError::Range && + !sRangeNegative.isEmpty() && + sRangeNegative == m_xEdRangePositive->get_text() ) + m_xCbSyncPosNeg->set_active(true); + } + + UpdateControlStates(); +} + +void ErrorBarResources::FillItemSet(SfxItemSet& rOutAttrs) const +{ + if( m_bErrorKindUnique ) + rOutAttrs.Put( SvxChartKindErrorItem( m_eErrorKind, SCHATTR_STAT_KIND_ERROR )); + if( m_bIndicatorUnique ) + rOutAttrs.Put( SvxChartIndicateItem( m_eIndicate, SCHATTR_STAT_INDICATE )); + + if( m_bErrorKindUnique ) + { + if( m_eErrorKind == SvxChartKindError::Range ) + { + OUString aPosRange; + OUString aNegRange; + if( m_bHasInternalDataProvider ) + { + // the strings aPosRange/aNegRange have to be set to a non-empty + // arbitrary string to generate error-bar sequences + aPosRange = "x"; + aNegRange = aPosRange; + } + else + { + aPosRange = m_xEdRangePositive->get_text(); + if( m_xCbSyncPosNeg->get_active()) + aNegRange = aPosRange; + else + aNegRange = m_xEdRangeNegative->get_text(); + } + + if( m_bRangePosUnique ) + rOutAttrs.Put( SfxStringItem( SCHATTR_STAT_RANGE_POS, aPosRange )); + if( m_bRangeNegUnique ) + rOutAttrs.Put( SfxStringItem( SCHATTR_STAT_RANGE_NEG, aNegRange )); + } + else if( m_eErrorKind == SvxChartKindError::Const || + m_eErrorKind == SvxChartKindError::Percent || + m_eErrorKind == SvxChartKindError::BigError ) + { + double fPosValue = static_cast< double >( m_xMfPositive->get_value(FieldUnit::NONE)) / + pow( 10.0, m_xMfPositive->get_digits()); + double fNegValue = 0.0; + + if( m_xCbSyncPosNeg->get_active()) + fNegValue = fPosValue; + else + fNegValue = static_cast< double >( m_xMfNegative->get_value(FieldUnit::NONE)) / + pow( 10.0, m_xMfNegative->get_digits()); + + rOutAttrs.Put( SvxDoubleItem( fPosValue, SCHATTR_STAT_CONSTPLUS )); + rOutAttrs.Put( SvxDoubleItem( fNegValue, SCHATTR_STAT_CONSTMINUS )); + } + } + + rOutAttrs.Put( SfxBoolItem( SCHATTR_STAT_ERRORBAR_TYPE , m_eErrorBarType == ERROR_BAR_Y )); +} + +void ErrorBarResources::FillValueSets() +{ + if( m_eErrorBarType == ERROR_BAR_Y ) + { + m_xFiNegative->set_from_icon_name(BMP_INDICATE_DOWN); + m_xFiPositive->set_from_icon_name(BMP_INDICATE_UP); + m_xFiBoth->set_from_icon_name(BMP_INDICATE_BOTH_VERTI); + } + else if( m_eErrorBarType == ERROR_BAR_X ) + { + m_xFiNegative->set_from_icon_name(BMP_INDICATE_LEFT); + m_xFiPositive->set_from_icon_name(BMP_INDICATE_RIGHT); + m_xFiBoth->set_from_icon_name(BMP_INDICATE_BOTH_HORI); + } +} + +void ErrorBarResources::listeningFinished( + const OUString & rNewRange ) +{ + OSL_ASSERT(m_apRangeSelectionHelper); + if (!m_apRangeSelectionHelper) + return; + + // rNewRange becomes invalid after removing the listener + OUString aRange( rNewRange ); + + // stop listening + m_apRangeSelectionHelper->stopRangeListening(); + + // change edit field +// if( m_pParentWindow ) +// { +// m_pParentWindow->ToTop(); +// m_pParentWindow->grab_focus(); +// } + + if( m_pCurrentRangeChoosingField ) + { + m_pCurrentRangeChoosingField->set_text( aRange ); + m_pCurrentRangeChoosingField->grab_focus(); + PosValueChanged( *m_xMfPositive ); + } + + m_pCurrentRangeChoosingField = nullptr; + + UpdateControlStates(); + lcl_enableRangeChoosing(false, m_pController); +} + +void ErrorBarResources::disposingRangeSelection() +{ + OSL_ASSERT(m_apRangeSelectionHelper); + if (m_apRangeSelectionHelper) + m_apRangeSelectionHelper->stopRangeListening( false ); +} + +void ErrorBarResources::isRangeFieldContentValid(weld::Entry& rEdit) +{ + OUString aRange( rEdit.get_text()); + bool bIsValid = ( aRange.isEmpty() ) || + ( m_apRangeSelectionHelper && + m_apRangeSelectionHelper->verifyCellRange( aRange )); + + if( bIsValid || !rEdit.get_sensitive()) + { + rEdit.set_message_type(weld::EntryMessageType::Normal); + } + else + { + rEdit.set_message_type(weld::EntryMessageType::Error); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_LegendPosition.cxx b/chart2/source/controller/dialogs/res_LegendPosition.cxx new file mode 100644 index 000000000..c461d20c5 --- /dev/null +++ b/chart2/source/controller/dialogs/res_LegendPosition.cxx @@ -0,0 +1,243 @@ +/* -*- 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 <res_LegendPosition.hxx> +#include <ChartModelHelper.hxx> +#include <Legend.hxx> +#include <LegendHelper.hxx> +#include <ChartModel.hxx> +#include <Diagram.hxx> + +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart/ChartLegendExpansion.hpp> + +//itemset stuff +#include <chartview/ChartSfxItemIds.hxx> +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/weld.hxx> + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +LegendPositionResources::LegendPositionResources(weld::Builder& rBuilder) + : m_xRbtLeft(rBuilder.weld_radio_button("left")) + , m_xRbtRight(rBuilder.weld_radio_button("right")) + , m_xRbtTop(rBuilder.weld_radio_button("top")) + , m_xRbtBottom(rBuilder.weld_radio_button("bottom")) +{ + impl_setRadioButtonToggleHdl(); +} + +LegendPositionResources::LegendPositionResources(weld::Builder& rBuilder, + const uno::Reference< uno::XComponentContext >& xCC) + : m_xCC(xCC) + , m_xCbxShow(rBuilder.weld_check_button("show")) + , m_xRbtLeft(rBuilder.weld_radio_button("left")) + , m_xRbtRight(rBuilder.weld_radio_button("right")) + , m_xRbtTop(rBuilder.weld_radio_button("top")) + , m_xRbtBottom(rBuilder.weld_radio_button("bottom")) +{ + m_xCbxShow->connect_toggled( LINK( this, LegendPositionResources, PositionEnableHdl ) ); + impl_setRadioButtonToggleHdl(); +} + +void LegendPositionResources::impl_setRadioButtonToggleHdl() +{ + m_xRbtLeft->connect_toggled( LINK( this, LegendPositionResources, PositionChangeHdl ) ); + m_xRbtTop->connect_toggled( LINK( this, LegendPositionResources, PositionChangeHdl ) ); + m_xRbtRight->connect_toggled( LINK( this, LegendPositionResources, PositionChangeHdl ) ); + m_xRbtBottom->connect_toggled( LINK( this, LegendPositionResources, PositionChangeHdl ) ); +} + +LegendPositionResources::~LegendPositionResources() +{ +} + +void LegendPositionResources::writeToResources( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + try + { + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + uno::Reference< beans::XPropertySet > xProp( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xProp.is() ) + { + //show + bool bShowLegend = false; + xProp->getPropertyValue( "Show" ) >>= bShowLegend; + if (m_xCbxShow) + m_xCbxShow->set_active( bShowLegend ); + PositionEnable(); + + //position + chart2::LegendPosition ePos; + xProp->getPropertyValue( "AnchorPosition" ) >>= ePos; + switch( ePos ) + { + case chart2::LegendPosition_LINE_START: + m_xRbtLeft->set_active(true); + break; + case chart2::LegendPosition_PAGE_START: + m_xRbtTop->set_active(true); + break; + case chart2::LegendPosition_PAGE_END: + m_xRbtBottom->set_active(true); + break; + case chart2::LegendPosition_LINE_END: + default: + m_xRbtRight->set_active(true); + break; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void LegendPositionResources::writeToModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) const +{ + try + { + bool bShowLegend = m_xCbxShow && m_xCbxShow->get_active(); + ChartModel& rModel = *xChartModel; + rtl::Reference< Legend > xProp = LegendHelper::getLegend(rModel, m_xCC, bShowLegend); + if( xProp.is() ) + { + //show + xProp->setPropertyValue( "Show" , uno::Any( bShowLegend )); + + //position + chart2::LegendPosition eNewPos; + css::chart::ChartLegendExpansion eExp = css::chart::ChartLegendExpansion_HIGH; + + if( m_xRbtLeft->get_active() ) + eNewPos = chart2::LegendPosition_LINE_START; + else if( m_xRbtRight->get_active() ) + { + eNewPos = chart2::LegendPosition_LINE_END; + } + else if( m_xRbtTop->get_active() ) + { + eNewPos = chart2::LegendPosition_PAGE_START; + eExp = css::chart::ChartLegendExpansion_WIDE; + } + else if( m_xRbtBottom->get_active() ) + { + eNewPos = chart2::LegendPosition_PAGE_END; + eExp = css::chart::ChartLegendExpansion_WIDE; + } + + xProp->setPropertyValue( "AnchorPosition" , uno::Any( eNewPos )); + xProp->setPropertyValue( "Expansion" , uno::Any( eExp )); + xProp->setPropertyValue( "RelativePosition" , uno::Any()); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +IMPL_LINK_NOARG(LegendPositionResources, PositionEnableHdl, weld::Toggleable&, void) +{ + PositionEnable(); +} + +void LegendPositionResources::PositionEnable() +{ + bool bEnable = !m_xCbxShow || m_xCbxShow->get_active(); + + m_xRbtLeft->set_sensitive( bEnable ); + m_xRbtTop->set_sensitive( bEnable ); + m_xRbtRight->set_sensitive( bEnable ); + m_xRbtBottom->set_sensitive( bEnable ); + + m_aChangeLink.Call(nullptr); +} + +void LegendPositionResources::initFromItemSet( const SfxItemSet& rInAttrs ) +{ + if( const SfxInt32Item* pPosItem = rInAttrs.GetItemIfSet( SCHATTR_LEGEND_POS ) ) + { + chart2::LegendPosition nLegendPosition = static_cast<chart2::LegendPosition>(pPosItem->GetValue()); + switch( nLegendPosition ) + { + case chart2::LegendPosition_LINE_START: + m_xRbtLeft->set_active(true); + break; + case chart2::LegendPosition_PAGE_START: + m_xRbtTop->set_active(true); + break; + case chart2::LegendPosition_LINE_END: + m_xRbtRight->set_active(true); + break; + case chart2::LegendPosition_PAGE_END: + m_xRbtBottom->set_active(true); + break; + default: + break; + } + } + + const SfxBoolItem* pShowItem; + if( m_xCbxShow && (pShowItem = rInAttrs.GetItemIfSet( SCHATTR_LEGEND_SHOW )) ) + { + m_xCbxShow->set_active(pShowItem->GetValue()); + } +} + +void LegendPositionResources::writeToItemSet( SfxItemSet& rOutAttrs ) const +{ + chart2::LegendPosition nLegendPosition = chart2::LegendPosition_LINE_END; + if( m_xRbtLeft->get_active() ) + nLegendPosition = chart2::LegendPosition_LINE_START; + else if( m_xRbtTop->get_active() ) + nLegendPosition = chart2::LegendPosition_PAGE_START; + else if( m_xRbtRight->get_active() ) + nLegendPosition = chart2::LegendPosition_LINE_END; + else if( m_xRbtBottom->get_active() ) + nLegendPosition = chart2::LegendPosition_PAGE_END; + rOutAttrs.Put( SfxInt32Item(SCHATTR_LEGEND_POS, static_cast<sal_Int32>(nLegendPosition) ) ); + + rOutAttrs.Put( SfxBoolItem(SCHATTR_LEGEND_SHOW, !m_xCbxShow || m_xCbxShow->get_active()) ); +} + +IMPL_LINK (LegendPositionResources, PositionChangeHdl, weld::Toggleable&, rRadio, void) +{ + //for each radio click there are coming two change events + //first uncheck of previous button -> ignore that call + //the second call gives the check of the new button + if( rRadio.get_active() ) + m_aChangeLink.Call(nullptr); +} + +void LegendPositionResources::SetChangeHdl( const Link<LinkParamNone*,void>& rLink ) +{ + m_aChangeLink = rLink; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_Titles.cxx b/chart2/source/controller/dialogs/res_Titles.cxx new file mode 100644 index 000000000..59b0f00b9 --- /dev/null +++ b/chart2/source/controller/dialogs/res_Titles.cxx @@ -0,0 +1,132 @@ +/* -*- 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 <res_Titles.hxx> +#include <TitleDialogData.hxx> +#include <vcl/weld.hxx> + +namespace chart +{ +TitleResources::TitleResources(weld::Builder& rBuilder, bool bShowSecondaryAxesTitle) + : m_xFT_Main(rBuilder.weld_label("labelMainTitle")) + , m_xFT_Sub(rBuilder.weld_label("labelSubTitle")) + , m_xEd_Main(rBuilder.weld_entry("maintitle")) + , m_xEd_Sub(rBuilder.weld_entry("subtitle")) + , m_xFT_XAxis(rBuilder.weld_label("labelPrimaryXaxis")) + , m_xFT_YAxis(rBuilder.weld_label("labelPrimaryYaxis")) + , m_xFT_ZAxis(rBuilder.weld_label("labelPrimaryZaxis")) + , m_xEd_XAxis(rBuilder.weld_entry("primaryXaxis")) + , m_xEd_YAxis(rBuilder.weld_entry("primaryYaxis")) + , m_xEd_ZAxis(rBuilder.weld_entry("primaryZaxis")) + , m_xFT_SecondaryXAxis(rBuilder.weld_label("labelSecondaryXAxis")) + , m_xFT_SecondaryYAxis(rBuilder.weld_label("labelSecondaryYAxis")) + , m_xEd_SecondaryXAxis(rBuilder.weld_entry("secondaryXaxis")) + , m_xEd_SecondaryYAxis(rBuilder.weld_entry("secondaryYaxis")) +{ + m_xFT_SecondaryXAxis->set_visible(bShowSecondaryAxesTitle); + m_xFT_SecondaryYAxis->set_visible(bShowSecondaryAxesTitle); + m_xEd_SecondaryXAxis->set_visible(bShowSecondaryAxesTitle); + m_xEd_SecondaryYAxis->set_visible(bShowSecondaryAxesTitle); +} + +TitleResources::~TitleResources() {} + +void TitleResources::connect_changed(const Link<weld::Entry&, void>& rLink) +{ + m_xEd_Main->connect_changed(rLink); + m_xEd_Sub->connect_changed(rLink); + m_xEd_XAxis->connect_changed(rLink); + m_xEd_YAxis->connect_changed(rLink); + m_xEd_ZAxis->connect_changed(rLink); + m_xEd_SecondaryXAxis->connect_changed(rLink); + m_xEd_SecondaryYAxis->connect_changed(rLink); +} + +bool TitleResources::get_value_changed_from_saved() const +{ + return m_xEd_Main->get_value_changed_from_saved() || m_xEd_Sub->get_value_changed_from_saved() + || m_xEd_XAxis->get_value_changed_from_saved() + || m_xEd_YAxis->get_value_changed_from_saved() + || m_xEd_ZAxis->get_value_changed_from_saved() + || m_xEd_SecondaryXAxis->get_value_changed_from_saved() + || m_xEd_SecondaryYAxis->get_value_changed_from_saved(); +} + +void TitleResources::save_value() +{ + m_xEd_Main->save_value(); + m_xEd_Sub->save_value(); + m_xEd_XAxis->save_value(); + m_xEd_YAxis->save_value(); + m_xEd_ZAxis->save_value(); + m_xEd_SecondaryXAxis->save_value(); + m_xEd_SecondaryYAxis->save_value(); +} + +void TitleResources::writeToResources(const TitleDialogData& rInput) +{ + m_xFT_Main->set_sensitive(rInput.aPossibilityList[0]); + m_xFT_Sub->set_sensitive(rInput.aPossibilityList[1]); + m_xFT_XAxis->set_sensitive(rInput.aPossibilityList[2]); + m_xFT_YAxis->set_sensitive(rInput.aPossibilityList[3]); + m_xFT_ZAxis->set_sensitive(rInput.aPossibilityList[4]); + m_xFT_SecondaryXAxis->set_sensitive(rInput.aPossibilityList[5]); + m_xFT_SecondaryYAxis->set_sensitive(rInput.aPossibilityList[6]); + + m_xEd_Main->set_sensitive(rInput.aPossibilityList[0]); + m_xEd_Sub->set_sensitive(rInput.aPossibilityList[1]); + m_xEd_XAxis->set_sensitive(rInput.aPossibilityList[2]); + m_xEd_YAxis->set_sensitive(rInput.aPossibilityList[3]); + m_xEd_ZAxis->set_sensitive(rInput.aPossibilityList[4]); + m_xEd_SecondaryXAxis->set_sensitive(rInput.aPossibilityList[5]); + m_xEd_SecondaryYAxis->set_sensitive(rInput.aPossibilityList[6]); + + m_xEd_Main->set_text(rInput.aTextList[0]); + m_xEd_Sub->set_text(rInput.aTextList[1]); + m_xEd_XAxis->set_text(rInput.aTextList[2]); + m_xEd_YAxis->set_text(rInput.aTextList[3]); + m_xEd_ZAxis->set_text(rInput.aTextList[4]); + m_xEd_SecondaryXAxis->set_text(rInput.aTextList[5]); + m_xEd_SecondaryYAxis->set_text(rInput.aTextList[6]); +} + +void TitleResources::readFromResources(TitleDialogData& rOutput) +{ + sal_Bool* pExistenceList = rOutput.aExistenceList.getArray(); + pExistenceList[0] = !m_xEd_Main->get_text().isEmpty(); + pExistenceList[1] = !m_xEd_Sub->get_text().isEmpty(); + pExistenceList[2] = !m_xEd_XAxis->get_text().isEmpty(); + pExistenceList[3] = !m_xEd_YAxis->get_text().isEmpty(); + pExistenceList[4] = !m_xEd_ZAxis->get_text().isEmpty(); + pExistenceList[5] = !m_xEd_SecondaryXAxis->get_text().isEmpty(); + pExistenceList[6] = !m_xEd_SecondaryYAxis->get_text().isEmpty(); + + auto pTextList = rOutput.aTextList.getArray(); + pTextList[0] = m_xEd_Main->get_text(); + pTextList[1] = m_xEd_Sub->get_text(); + pTextList[2] = m_xEd_XAxis->get_text(); + pTextList[3] = m_xEd_YAxis->get_text(); + pTextList[4] = m_xEd_ZAxis->get_text(); + pTextList[5] = m_xEd_SecondaryXAxis->get_text(); + pTextList[6] = m_xEd_SecondaryYAxis->get_text(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_Trendline.cxx b/chart2/source/controller/dialogs/res_Trendline.cxx new file mode 100644 index 000000000..647c071b1 --- /dev/null +++ b/chart2/source/controller/dialogs/res_Trendline.cxx @@ -0,0 +1,438 @@ +/* -*- 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 "res_Trendline.hxx" +#include <bitmaps.hlst> +#include <chartview/ChartSfxItemIds.hxx> + +#include <com/sun/star/chart2/MovingAverageType.hpp> + +#include <svl/intitem.hxx> +#include <svl/numformat.hxx> +#include <svl/stritem.hxx> +#include <vcl/formatter.hxx> +#include <vcl/weld.hxx> + +using namespace css::chart2; + +namespace chart +{ + +static void lcl_setValue(weld::FormattedSpinButton& rFmtField, double fValue ) +{ + Formatter& rFieldFormatter = rFmtField.GetFormatter(); + rFieldFormatter.SetValue(fValue); + rFieldFormatter.SetDefaultValue( fValue ); +} + +TrendlineResources::TrendlineResources(weld::Builder& rBuilder, const SfxItemSet& rInAttrs) + : m_eTrendLineType(SvxChartRegress::Linear) + , m_bTrendLineUnique(true) + , m_pNumFormatter(nullptr) + , m_nNbPoints(0) + , m_xRB_Linear(rBuilder.weld_radio_button("linear")) + , m_xRB_Logarithmic(rBuilder.weld_radio_button("logarithmic")) + , m_xRB_Exponential(rBuilder.weld_radio_button("exponential")) + , m_xRB_Power(rBuilder.weld_radio_button("power")) + , m_xRB_Polynomial(rBuilder.weld_radio_button("polynomial")) + , m_xRB_MovingAverage(rBuilder.weld_radio_button("movingAverage")) + , m_xFI_Linear(rBuilder.weld_image("imageLinear")) + , m_xFI_Logarithmic(rBuilder.weld_image("imageLogarithmic")) + , m_xFI_Exponential(rBuilder.weld_image("imageExponential")) + , m_xFI_Power(rBuilder.weld_image("imagePower")) + , m_xFI_Polynomial(rBuilder.weld_image("imagePolynomial")) + , m_xFI_MovingAverage(rBuilder.weld_image("imageMovingAverage")) + , m_xNF_Degree(rBuilder.weld_spin_button("degree")) + , m_xNF_Period(rBuilder.weld_spin_button("period")) + , m_xEE_Name(rBuilder.weld_entry("entry_name")) + , m_xFmtFld_ExtrapolateForward(rBuilder.weld_formatted_spin_button("extrapolateForward")) + , m_xFmtFld_ExtrapolateBackward(rBuilder.weld_formatted_spin_button("extrapolateBackward")) + , m_xCB_SetIntercept(rBuilder.weld_check_button("setIntercept")) + , m_xFmtFld_InterceptValue(rBuilder.weld_formatted_spin_button("interceptValue")) + , m_xCB_ShowEquation(rBuilder.weld_check_button("showEquation")) + , m_xEE_XName(rBuilder.weld_entry("entry_Xname")) + , m_xEE_YName(rBuilder.weld_entry("entry_Yname")) + , m_xCB_ShowCorrelationCoeff(rBuilder.weld_check_button("showCorrelationCoefficient")) + , m_xCB_RegressionMovingType(rBuilder.weld_combo_box("combo_moving_type")) +{ + FillValueSets(); + + Formatter& rForwardFormatter = m_xFmtFld_ExtrapolateForward->GetFormatter(); + rForwardFormatter.ClearMinValue(); + rForwardFormatter.ClearMaxValue(); + Formatter& rBackwardFormatter = m_xFmtFld_ExtrapolateBackward->GetFormatter(); + rBackwardFormatter.ClearMinValue(); + rBackwardFormatter.ClearMaxValue(); + Formatter& rInterceptFormatter = m_xFmtFld_InterceptValue->GetFormatter(); + rInterceptFormatter.ClearMinValue(); + rInterceptFormatter.ClearMaxValue(); + + Link<weld::Toggleable&,void> aLink = LINK(this, TrendlineResources, SelectTrendLine); + m_xRB_Linear->connect_toggled( aLink ); + m_xRB_Logarithmic->connect_toggled( aLink ); + m_xRB_Exponential->connect_toggled( aLink ); + m_xRB_Power->connect_toggled( aLink ); + m_xRB_Polynomial->connect_toggled( aLink ); + m_xRB_MovingAverage->connect_toggled( aLink ); + + Link<weld::SpinButton&,void> aLink2 = LINK(this, TrendlineResources, ChangeSpinValue); + m_xNF_Degree->connect_value_changed(aLink2); + m_xNF_Period->connect_value_changed(aLink2); + m_xFmtFld_InterceptValue->connect_value_changed(LINK(this, TrendlineResources, ChangeFormattedValue)); + + m_xCB_ShowEquation->connect_toggled(LINK(this, TrendlineResources, ShowEquation)); + + Reset( rInAttrs ); + UpdateControlStates(); +} + +TrendlineResources::~TrendlineResources() +{} + +IMPL_LINK_NOARG(TrendlineResources, SelectTrendLine, weld::Toggleable&, void) +{ + if (m_xRB_Linear->get_active()) + m_eTrendLineType = SvxChartRegress::Linear; + else if (m_xRB_Logarithmic->get_active()) + m_eTrendLineType = SvxChartRegress::Log; + else if (m_xRB_Exponential->get_active()) + m_eTrendLineType = SvxChartRegress::Exp; + else if (m_xRB_Power->get_active()) + m_eTrendLineType = SvxChartRegress::Power; + else if (m_xRB_Polynomial->get_active()) + m_eTrendLineType = SvxChartRegress::Polynomial; + else if (m_xRB_MovingAverage->get_active()) + m_eTrendLineType = SvxChartRegress::MovingAverage; + m_bTrendLineUnique = true; + + UpdateControlStates(); +} + +void TrendlineResources::Reset( const SfxItemSet& rInAttrs ) +{ + if( const SfxStringItem* pCurveNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_CURVE_NAME ) ) + { + OUString aName = pCurveNameItem->GetValue(); + m_xEE_Name->set_text(aName); + } + else + { + m_xEE_Name->set_text(""); + } + if( const SfxStringItem* pRegressionXNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_XNAME ) ) + { + OUString aName = pRegressionXNameItem->GetValue(); + m_xEE_XName->set_text(aName); + } + else + { + m_xEE_XName->set_text("x"); + } + if( const SfxStringItem* pRegressionYNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_YNAME ) ) + { + OUString aName = pRegressionYNameItem->GetValue(); + m_xEE_YName->set_text(aName); + } + else + { + m_xEE_YName->set_text("f(x)"); + } + + const SfxPoolItem* pPoolItem = nullptr; + SfxItemState aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_TYPE, true, &pPoolItem ); + m_bTrendLineUnique = ( aState != SfxItemState::DONTCARE ); + if( aState == SfxItemState::SET ) + { + const SvxChartRegressItem * pItem = dynamic_cast< const SvxChartRegressItem * >( pPoolItem ); + if( pItem ) + { + m_eTrendLineType = pItem->GetValue(); + } + } + + if( const SfxInt32Item* pDegreeItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_DEGREE ) ) + { + sal_Int32 nDegree = pDegreeItem->GetValue(); + m_xNF_Degree->set_value( nDegree ); + } + else + { + m_xNF_Degree->set_value( 2 ); + } + + m_xNF_Degree->save_value(); + + if( const SfxInt32Item* pPeriodItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_PERIOD ) ) + { + sal_Int32 nPeriod = pPeriodItem->GetValue(); + m_xNF_Period->set_value( nPeriod ); + } + else + { + m_xNF_Period->set_value( 2 ); + } + + m_xNF_Period->save_value(); + + double nValue = 0.0; + if( const SvxDoubleItem* pForwardItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD ) ) + { + nValue = pForwardItem->GetValue() ; + } + lcl_setValue(*m_xFmtFld_ExtrapolateForward, nValue); + + nValue = 0.0; + if( const SvxDoubleItem* pBackwardItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD ) ) + { + nValue = pBackwardItem->GetValue() ; + } + lcl_setValue(*m_xFmtFld_ExtrapolateBackward, nValue); + + nValue = 0.0; + if( const SvxDoubleItem* pValueItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_INTERCEPT_VALUE ) ) + { + nValue = pValueItem->GetValue() ; + } + lcl_setValue(*m_xFmtFld_InterceptValue, nValue); + + aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SET_INTERCEPT, true, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCB_SetIntercept->set_state(TRISTATE_INDET); + } + else + { + if( aState == SfxItemState::SET ) + m_xCB_SetIntercept->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue()); + } + + aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SHOW_EQUATION, true, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCB_ShowEquation->set_state(TRISTATE_INDET); + } + else + { + if( aState == SfxItemState::SET ) + m_xCB_ShowEquation->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue()); + } + + aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SHOW_COEFF, true, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCB_ShowCorrelationCoeff->set_state(TRISTATE_INDET); + } + else + { + if( aState == SfxItemState::SET ) + m_xCB_ShowCorrelationCoeff->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue()); + } + + if( const SfxInt32Item* pMovingTypeItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_MOVING_TYPE ) ) + { + sal_Int32 nMovingType = pMovingTypeItem->GetValue(); + if (nMovingType == MovingAverageType::Prior) + m_xCB_RegressionMovingType->set_active(0); + else if (nMovingType == MovingAverageType::Central) + m_xCB_RegressionMovingType->set_active(1); + else if (nMovingType == MovingAverageType::AveragedAbscissa) + m_xCB_RegressionMovingType->set_active(2); + } + else + { + m_xCB_RegressionMovingType->set_active(0); + } + + if( !m_bTrendLineUnique ) + return; + + switch( m_eTrendLineType ) + { + case SvxChartRegress::Linear : + m_xRB_Linear->set_active(true); + break; + case SvxChartRegress::Log : + m_xRB_Logarithmic->set_active(true); + break; + case SvxChartRegress::Exp : + m_xRB_Exponential->set_active(true); + break; + case SvxChartRegress::Power : + m_xRB_Power->set_active(true); + break; + case SvxChartRegress::Polynomial : + m_xRB_Polynomial->set_active(true); + break; + case SvxChartRegress::MovingAverage : + m_xRB_MovingAverage->set_active(true); + break; + default: + break; + } +} + +void TrendlineResources::FillItemSet(SfxItemSet* rOutAttrs) const +{ + if( m_bTrendLineUnique ) + rOutAttrs->Put( SvxChartRegressItem( m_eTrendLineType, SCHATTR_REGRESSION_TYPE )); + + if (m_eTrendLineType == SvxChartRegress::MovingAverage) + { + sal_Int32 nType = MovingAverageType::Prior; + if (m_xCB_RegressionMovingType->get_active() == 1) + nType = MovingAverageType::Central; + else if (m_xCB_RegressionMovingType->get_active() == 2) + nType = MovingAverageType::AveragedAbscissa; + + rOutAttrs->Put(SfxInt32Item(SCHATTR_REGRESSION_MOVING_TYPE, nType)); + } + + if( m_xCB_ShowEquation->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SHOW_EQUATION, m_xCB_ShowEquation->get_active() )); + + if( m_xCB_ShowCorrelationCoeff->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SHOW_COEFF, m_xCB_ShowCorrelationCoeff->get_active() )); + + OUString aName = m_xEE_Name->get_text(); + rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_CURVE_NAME, aName)); + aName = m_xEE_XName->get_text(); + if ( aName.isEmpty() ) + aName = "x"; + rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_XNAME, aName)); + aName = m_xEE_YName->get_text(); + if ( aName.isEmpty() ) + aName = "f(x)"; + rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_YNAME, aName)); + + sal_Int32 aDegree = m_xNF_Degree->get_value(); + rOutAttrs->Put(SfxInt32Item( SCHATTR_REGRESSION_DEGREE, aDegree ) ); + + sal_Int32 aPeriod = m_xNF_Period->get_value(); + rOutAttrs->Put(SfxInt32Item( SCHATTR_REGRESSION_PERIOD, aPeriod ) ); + + sal_uInt32 nIndex = 0; + double aValue = 0.0; + (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_ExtrapolateForward->get_text(),nIndex,aValue); + rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD ) ); + + aValue = 0.0; + (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_ExtrapolateBackward->get_text(),nIndex,aValue); + rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD ) ); + + if( m_xCB_SetIntercept->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SET_INTERCEPT, m_xCB_SetIntercept->get_active() )); + + aValue = 0.0; + (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_InterceptValue->get_text(),nIndex,aValue); + rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_INTERCEPT_VALUE ) ); +} + +void TrendlineResources::FillValueSets() +{ + m_xFI_Linear->set_from_icon_name(BMP_REGRESSION_LINEAR); + m_xFI_Logarithmic->set_from_icon_name(BMP_REGRESSION_LOG); + m_xFI_Exponential->set_from_icon_name(BMP_REGRESSION_EXP); + m_xFI_Power->set_from_icon_name(BMP_REGRESSION_POWER); + m_xFI_Polynomial->set_from_icon_name(BMP_REGRESSION_POLYNOMIAL); + m_xFI_MovingAverage->set_from_icon_name(BMP_REGRESSION_MOVING_AVERAGE); +} + +void TrendlineResources::UpdateControlStates() +{ + if( m_nNbPoints > 0 ) + { + sal_Int32 nMaxValue = m_nNbPoints - 1 + (m_xCB_SetIntercept->get_active() ? 1 : 0); + m_xNF_Degree->set_max(nMaxValue); + m_xNF_Period->set_max(m_nNbPoints - 1); + } + bool bMovingAverage = ( m_eTrendLineType == SvxChartRegress::MovingAverage ); + bool bPolynomial = ( m_eTrendLineType == SvxChartRegress::Polynomial ); + bool bInterceptAvailable = ( m_eTrendLineType == SvxChartRegress::Linear ) + || ( m_eTrendLineType == SvxChartRegress::Polynomial ) + || ( m_eTrendLineType == SvxChartRegress::Exp ); + m_xFmtFld_ExtrapolateForward->set_sensitive( !bMovingAverage ); + m_xFmtFld_ExtrapolateBackward->set_sensitive( !bMovingAverage ); + m_xCB_SetIntercept->set_sensitive( bInterceptAvailable ); + m_xFmtFld_InterceptValue->set_sensitive( bInterceptAvailable ); + if( bMovingAverage ) + { + m_xCB_ShowEquation->set_state(TRISTATE_FALSE); + m_xCB_ShowCorrelationCoeff->set_state(TRISTATE_FALSE); + } + m_xCB_ShowEquation->set_sensitive( !bMovingAverage ); + m_xCB_ShowCorrelationCoeff->set_sensitive( !bMovingAverage ); + m_xCB_RegressionMovingType->set_sensitive(bMovingAverage); + m_xNF_Period->set_sensitive(bMovingAverage); + m_xNF_Degree->set_sensitive(bPolynomial); + m_xEE_XName->set_sensitive( !bMovingAverage && m_xCB_ShowEquation->get_active() ); + m_xEE_YName->set_sensitive( !bMovingAverage && m_xCB_ShowEquation->get_active() ); +} + +IMPL_LINK(TrendlineResources, ChangeSpinValue, weld::SpinButton&, rNumericField, void) +{ + if (&rNumericField == m_xNF_Degree.get()) + { + if (!m_xRB_Polynomial->get_active() && m_xNF_Degree->get_value_changed_from_saved()) + { + m_xRB_Polynomial->set_active(true); + SelectTrendLine(*m_xRB_Polynomial); + } + } + else if (&rNumericField == m_xNF_Period.get()) + { + if (!m_xRB_MovingAverage->get_active() && m_xNF_Period->get_value_changed_from_saved()) + { + m_xRB_MovingAverage->set_active(true); + SelectTrendLine(*m_xRB_MovingAverage); + } + } + UpdateControlStates(); +} + +IMPL_LINK_NOARG(TrendlineResources, ChangeFormattedValue, weld::FormattedSpinButton&, void) +{ + if (!m_xCB_SetIntercept->get_active()) + m_xCB_SetIntercept->set_active(true); + UpdateControlStates(); +} + +void TrendlineResources::SetNumFormatter( SvNumberFormatter* pFormatter ) +{ + m_pNumFormatter = pFormatter; + m_xFmtFld_ExtrapolateForward->GetFormatter().SetFormatter(m_pNumFormatter); + m_xFmtFld_ExtrapolateBackward->GetFormatter().SetFormatter(m_pNumFormatter); + m_xFmtFld_InterceptValue->GetFormatter().SetFormatter(m_pNumFormatter); +} + +void TrendlineResources::SetNbPoints( sal_Int32 nNbPoints ) +{ + m_nNbPoints = nNbPoints; + UpdateControlStates(); +} + +IMPL_LINK_NOARG(TrendlineResources, ShowEquation, weld::Toggleable&, void) +{ + m_xEE_XName->set_sensitive(m_xCB_ShowEquation->get_active()); + m_xEE_YName->set_sensitive(m_xCB_ShowEquation->get_active()); + UpdateControlStates(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_Trendline.hxx b/chart2/source/controller/dialogs/res_Trendline.hxx new file mode 100644 index 000000000..e520d6da3 --- /dev/null +++ b/chart2/source/controller/dialogs/res_Trendline.hxx @@ -0,0 +1,98 @@ +/* -*- 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 <tools/link.hxx> +#include <svl/itemset.hxx> +#include <svx/chrtitem.hxx> + +namespace weld { class Builder; } +namespace weld { class CheckButton; } +namespace weld { class ComboBox; } +namespace weld { class Entry; } +namespace weld { class FormattedSpinButton; } +namespace weld { class Image; } +namespace weld { class RadioButton; } +namespace weld { class SpinButton; } +namespace weld { class Toggleable; } + +class SvNumberFormatter; + +namespace chart +{ + +class TrendlineResources final +{ +public: + TrendlineResources(weld::Builder& rParent, const SfxItemSet& rInAttrs); + ~TrendlineResources(); + + void Reset(const SfxItemSet& rInAttrs); + void FillItemSet(SfxItemSet* rOutAttrs) const; + + void FillValueSets(); + + void SetNumFormatter( SvNumberFormatter* pFormatter ); + void SetNbPoints( sal_Int32 nNbPoints ); + +private: + SvxChartRegress m_eTrendLineType; + + bool m_bTrendLineUnique; + + SvNumberFormatter* m_pNumFormatter; + sal_Int32 m_nNbPoints; + + std::unique_ptr<weld::RadioButton> m_xRB_Linear; + std::unique_ptr<weld::RadioButton> m_xRB_Logarithmic; + std::unique_ptr<weld::RadioButton> m_xRB_Exponential; + std::unique_ptr<weld::RadioButton> m_xRB_Power; + std::unique_ptr<weld::RadioButton> m_xRB_Polynomial; + std::unique_ptr<weld::RadioButton> m_xRB_MovingAverage; + + std::unique_ptr<weld::Image> m_xFI_Linear; + std::unique_ptr<weld::Image> m_xFI_Logarithmic; + std::unique_ptr<weld::Image> m_xFI_Exponential; + std::unique_ptr<weld::Image> m_xFI_Power; + std::unique_ptr<weld::Image> m_xFI_Polynomial; + std::unique_ptr<weld::Image> m_xFI_MovingAverage; + + std::unique_ptr<weld::SpinButton> m_xNF_Degree; + std::unique_ptr<weld::SpinButton> m_xNF_Period; + std::unique_ptr<weld::Entry> m_xEE_Name; + std::unique_ptr<weld::FormattedSpinButton> m_xFmtFld_ExtrapolateForward; + std::unique_ptr<weld::FormattedSpinButton> m_xFmtFld_ExtrapolateBackward; + std::unique_ptr<weld::CheckButton> m_xCB_SetIntercept; + std::unique_ptr<weld::FormattedSpinButton> m_xFmtFld_InterceptValue; + std::unique_ptr<weld::CheckButton> m_xCB_ShowEquation; + std::unique_ptr<weld::Entry> m_xEE_XName; + std::unique_ptr<weld::Entry> m_xEE_YName; + std::unique_ptr<weld::CheckButton> m_xCB_ShowCorrelationCoeff; + std::unique_ptr<weld::ComboBox> m_xCB_RegressionMovingType; + + void UpdateControlStates(); + DECL_LINK(SelectTrendLine, weld::Toggleable&, void); + DECL_LINK(ChangeSpinValue, weld::SpinButton&, void); + DECL_LINK(ChangeFormattedValue, weld::FormattedSpinButton&, void); + DECL_LINK(ShowEquation, weld::Toggleable&, void); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneAppearance.cxx b/chart2/source/controller/dialogs/tp_3D_SceneAppearance.cxx new file mode 100644 index 000000000..c2a84536f --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneAppearance.cxx @@ -0,0 +1,317 @@ +/* -*- 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 "tp_3D_SceneAppearance.hxx" +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <ThreeDHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <Diagram.hxx> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; + +namespace +{ + +struct lcl_ModelProperties +{ + drawing::ShadeMode m_aShadeMode; + sal_Int32 m_nRoundedEdges; + sal_Int32 m_nObjectLines; + ::chart::ThreeDLookScheme m_eScheme; + + lcl_ModelProperties() + : m_aShadeMode(drawing::ShadeMode_FLAT) + , m_nRoundedEdges(-1) + , m_nObjectLines(-1) + , m_eScheme(::chart::ThreeDLookScheme::ThreeDLookScheme_Unknown) + {} +}; + +lcl_ModelProperties lcl_getPropertiesFromModel( rtl::Reference<::chart::ChartModel> const & xModel ) +{ + lcl_ModelProperties aProps; + try + { + rtl::Reference< ::chart::Diagram > xDiagram( ::chart::ChartModelHelper::findDiagram( xModel ) ); + xDiagram->getPropertyValue( "D3DSceneShadeMode" ) >>= aProps.m_aShadeMode; + ::chart::ThreeDHelper::getRoundedEdgesAndObjectLines( xDiagram, aProps.m_nRoundedEdges, aProps.m_nObjectLines ); + aProps.m_eScheme = ::chart::ThreeDHelper::detectScheme( xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aProps; +} + +void lcl_setShadeModeAtModel( rtl::Reference<::chart::ChartModel> const & xModel, drawing::ShadeMode aShadeMode ) +{ + try + { + rtl::Reference< ::chart::Diagram > xDiaProp = ::chart::ChartModelHelper::findDiagram( xModel ); + xDiaProp->setPropertyValue( "D3DSceneShadeMode" , uno::Any( aShadeMode )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // anonymous namespace + +namespace chart +{ + +#define POS_3DSCHEME_SIMPLE 0 +#define POS_3DSCHEME_REALISTIC 1 +#define POS_3DSCHEME_CUSTOM 2 + +ThreeD_SceneAppearance_TabPage::ThreeD_SceneAppearance_TabPage(weld::Container* pParent, + const rtl::Reference<::chart::ChartModel>& xChartModel, + ControllerLockHelper& rControllerLockHelper) + : m_xChartModel(xChartModel) + , m_bUpdateOtherControls(true) + , m_bCommitToModel(true) + , m_rControllerLockHelper(rControllerLockHelper) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/schart/ui/tp_3D_SceneAppearance.ui")) + , m_xContainer(m_xBuilder->weld_container("tp_3D_SceneAppearance")) + , m_xLB_Scheme(m_xBuilder->weld_combo_box("LB_SCHEME")) + , m_xCB_Shading(m_xBuilder->weld_check_button("CB_SHADING")) + , m_xCB_ObjectLines(m_xBuilder->weld_check_button("CB_OBJECTLINES")) + , m_xCB_RoundedEdge(m_xBuilder->weld_check_button("CB_ROUNDEDEDGE")) +{ + m_aCustom = m_xLB_Scheme->get_text(POS_3DSCHEME_CUSTOM); + m_xLB_Scheme->remove(POS_3DSCHEME_CUSTOM); + + m_xLB_Scheme->connect_changed( LINK( this, ThreeD_SceneAppearance_TabPage, SelectSchemeHdl ) ); + + m_xCB_RoundedEdge->connect_toggled( LINK( this, ThreeD_SceneAppearance_TabPage, SelectRoundedEdgeOrObjectLines ) ); + m_xCB_Shading->connect_toggled( LINK( this, ThreeD_SceneAppearance_TabPage, SelectShading ) ); + m_xCB_ObjectLines->connect_toggled( LINK( this, ThreeD_SceneAppearance_TabPage, SelectRoundedEdgeOrObjectLines ) ); + + initControlsFromModel(); +} + +ThreeD_SceneAppearance_TabPage::~ThreeD_SceneAppearance_TabPage() +{ +} + +void ThreeD_SceneAppearance_TabPage::ActivatePage() +{ + updateScheme(); +} + +void ThreeD_SceneAppearance_TabPage::applyRoundedEdgeAndObjectLinesToModel() +{ + if(!m_bCommitToModel) + return; + + sal_Int32 nObjectLines = -1; + + switch( m_xCB_ObjectLines->get_state()) + { + case TRISTATE_FALSE: + nObjectLines = 0; + break; + case TRISTATE_TRUE: + nObjectLines = 1; + break; + case TRISTATE_INDET: + nObjectLines = -1; + break; + } + + sal_Int32 nCurrentRoundedEdges = -1; + switch( m_xCB_RoundedEdge->get_state() ) + { + case TRISTATE_FALSE: + nCurrentRoundedEdges = 0; + break; + case TRISTATE_TRUE: + nCurrentRoundedEdges = 5; + break; + case TRISTATE_INDET: + nCurrentRoundedEdges = -1; + break; + } + + // locked controllers + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + ThreeDHelper::setRoundedEdgesAndObjectLines( + ::chart::ChartModelHelper::findDiagram( m_xChartModel ), nCurrentRoundedEdges, nObjectLines ); +} + +void ThreeD_SceneAppearance_TabPage::applyShadeModeToModel() +{ + if(!m_bCommitToModel) + return; + + drawing::ShadeMode aShadeMode = drawing::ShadeMode_PHONG; + + switch( m_xCB_Shading->get_state()) + { + case TRISTATE_FALSE: + aShadeMode = drawing::ShadeMode_FLAT; + break; + case TRISTATE_TRUE: + aShadeMode = drawing::ShadeMode_SMOOTH; + break; + case TRISTATE_INDET: + // nothing + break; + } + + lcl_setShadeModeAtModel( m_xChartModel, aShadeMode ); +} + +void ThreeD_SceneAppearance_TabPage::initControlsFromModel() +{ + m_bCommitToModel = false; + m_bUpdateOtherControls = false; + + lcl_ModelProperties aProps( lcl_getPropertiesFromModel( m_xChartModel )); + + if(aProps.m_aShadeMode == drawing::ShadeMode_FLAT) + { + m_xCB_Shading->set_active(false); + } + else if(aProps.m_aShadeMode == drawing::ShadeMode_SMOOTH) + { + m_xCB_Shading->set_active(true); + } + else + { + m_xCB_Shading->set_state(TRISTATE_INDET); + } + + if(aProps.m_nObjectLines == 0) + { + m_xCB_ObjectLines->set_active(false); + } + else if(aProps.m_nObjectLines==1) + { + m_xCB_ObjectLines->set_active(true); + } + else + { + m_xCB_ObjectLines->set_state(TRISTATE_INDET); + } + + if(aProps.m_nRoundedEdges >= 5) + { + m_xCB_RoundedEdge->set_active(true); + } + else if(aProps.m_nRoundedEdges<0) + { + m_xCB_RoundedEdge->set_state(TRISTATE_INDET); + } + else + { + m_xCB_RoundedEdge->set_active(false); + } + m_xCB_RoundedEdge->set_sensitive( !m_xCB_ObjectLines->get_active() ); + + updateScheme(); + + m_bCommitToModel = true; + m_bUpdateOtherControls = true; +} + +void ThreeD_SceneAppearance_TabPage::updateScheme() +{ + lcl_ModelProperties aProps( lcl_getPropertiesFromModel( m_xChartModel )); + + if (m_xLB_Scheme->get_count() == (POS_3DSCHEME_CUSTOM+1)) + m_xLB_Scheme->remove(POS_3DSCHEME_CUSTOM); + switch( aProps.m_eScheme ) + { + case ThreeDLookScheme::ThreeDLookScheme_Simple: + m_xLB_Scheme->set_active( POS_3DSCHEME_SIMPLE ); + break; + case ThreeDLookScheme::ThreeDLookScheme_Realistic: + m_xLB_Scheme->set_active( POS_3DSCHEME_REALISTIC ); + break; + case ThreeDLookScheme::ThreeDLookScheme_Unknown: + { + m_xLB_Scheme->insert_text(POS_3DSCHEME_CUSTOM, m_aCustom); + m_xLB_Scheme->set_active(POS_3DSCHEME_CUSTOM); + } + break; + } +} + +IMPL_LINK_NOARG(ThreeD_SceneAppearance_TabPage, SelectSchemeHdl, weld::ComboBox&, void) +{ + if( !m_bUpdateOtherControls ) + return; + + { + // locked controllers + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + rtl::Reference< Diagram > xDiagram = ::chart::ChartModelHelper::findDiagram( m_xChartModel ); + + if( m_xLB_Scheme->get_active() == POS_3DSCHEME_REALISTIC ) + ThreeDHelper::setScheme( xDiagram, ThreeDLookScheme::ThreeDLookScheme_Realistic ); + else if( m_xLB_Scheme->get_active() == POS_3DSCHEME_SIMPLE ) + ThreeDHelper::setScheme( xDiagram, ThreeDLookScheme::ThreeDLookScheme_Simple ); + else + { + OSL_FAIL( "Invalid Entry selected" ); + } + } + + // update other controls + initControlsFromModel(); +} + +IMPL_LINK_NOARG(ThreeD_SceneAppearance_TabPage, SelectShading, weld::Toggleable&, void) +{ + if( !m_bUpdateOtherControls ) + return; + + applyShadeModeToModel(); + updateScheme(); +} + +IMPL_LINK(ThreeD_SceneAppearance_TabPage, SelectRoundedEdgeOrObjectLines, weld::Toggleable&, rCheckBox, void) +{ + if( !m_bUpdateOtherControls ) + return; + + if (&rCheckBox == m_xCB_ObjectLines.get()) + { + m_bUpdateOtherControls = false; + m_xCB_RoundedEdge->set_sensitive( !m_xCB_ObjectLines->get_active() ); + if(!m_xCB_RoundedEdge->get_sensitive()) + m_xCB_RoundedEdge->set_active(false); + m_bUpdateOtherControls = true; + } + + applyRoundedEdgeAndObjectLinesToModel(); + updateScheme(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneAppearance.hxx b/chart2/source/controller/dialogs/tp_3D_SceneAppearance.hxx new file mode 100644 index 000000000..9d255c076 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneAppearance.hxx @@ -0,0 +1,69 @@ +/* -*- 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 <vcl/weld.hxx> + +namespace chart { class ControllerLockHelper; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class ChartModel; + +class ThreeD_SceneAppearance_TabPage +{ +public: + ThreeD_SceneAppearance_TabPage( + weld::Container* pParent, + const rtl::Reference<::chart::ChartModel> & xChartModel, + ControllerLockHelper & rControllerLockHelper ); + void ActivatePage(); + ~ThreeD_SceneAppearance_TabPage(); + +private: + DECL_LINK( SelectSchemeHdl, weld::ComboBox&, void ); + DECL_LINK( SelectShading, weld::Toggleable&, void ); + DECL_LINK( SelectRoundedEdgeOrObjectLines, weld::Toggleable&, void ); + + void initControlsFromModel(); + void applyShadeModeToModel(); + void applyRoundedEdgeAndObjectLinesToModel(); + void updateScheme(); + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + + bool m_bUpdateOtherControls; + bool m_bCommitToModel; + OUString m_aCustom; + + ControllerLockHelper& m_rControllerLockHelper; + + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + std::unique_ptr<weld::ComboBox> m_xLB_Scheme; + std::unique_ptr<weld::CheckButton> m_xCB_Shading; + std::unique_ptr<weld::CheckButton> m_xCB_ObjectLines; + std::unique_ptr<weld::CheckButton> m_xCB_RoundedEdge; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneGeometry.cxx b/chart2/source/controller/dialogs/tp_3D_SceneGeometry.cxx new file mode 100644 index 000000000..df1d8e907 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneGeometry.cxx @@ -0,0 +1,256 @@ +/* -*- 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 "tp_3D_SceneGeometry.hxx" + +#include <Diagram.hxx> +#include <DiagramHelper.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <ThreeDHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <com/sun/star/drawing/ProjectionMode.hpp> +#include <tools/diagnose_ex.h> +#include <tools/helpers.hxx> +#include <vcl/svapp.hxx> + +namespace chart +{ + +using namespace ::com::sun::star; + +namespace +{ + +void lcl_SetMetricFieldLimits(weld::MetricSpinButton& rField, sal_Int64 nLimit) +{ + rField.set_range(-1*nLimit, nLimit, FieldUnit::DEGREE); +} + +} + +ThreeD_SceneGeometry_TabPage::ThreeD_SceneGeometry_TabPage(weld::Container* pParent, + const rtl::Reference< ::chart::Diagram > & xDiagram, + ControllerLockHelper & rControllerLockHelper) + : m_xDiagram( xDiagram ) + , m_aAngleTimer("chart2 ThreeD_SceneGeometry_TabPage m_aAngleTimer") + , m_aPerspectiveTimer("chart2 ThreeD_SceneGeometry_TabPage m_aPerspectiveTimer") + , m_nXRotation(0) + , m_nYRotation(0) + , m_nZRotation(0) + , m_bAngleChangePending( false ) + , m_bPerspectiveChangePending( false ) + , m_rControllerLockHelper( rControllerLockHelper ) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/schart/ui/tp_3D_SceneGeometry.ui")) + , m_xContainer(m_xBuilder->weld_container("tp_3DSceneGeometry")) + , m_xCbxRightAngledAxes(m_xBuilder->weld_check_button("CBX_RIGHT_ANGLED_AXES")) + , m_xMFXRotation(m_xBuilder->weld_metric_spin_button("MTR_FLD_X_ROTATION", FieldUnit::DEGREE)) + , m_xMFYRotation(m_xBuilder->weld_metric_spin_button("MTR_FLD_Y_ROTATION", FieldUnit::DEGREE)) + , m_xFtZRotation(m_xBuilder->weld_label("FT_Z_ROTATION")) + , m_xMFZRotation(m_xBuilder->weld_metric_spin_button("MTR_FLD_Z_ROTATION", FieldUnit::DEGREE)) + , m_xCbxPerspective(m_xBuilder->weld_check_button("CBX_PERSPECTIVE")) + , m_xMFPerspective(m_xBuilder->weld_metric_spin_button("MTR_FLD_PERSPECTIVE", FieldUnit::PERCENT)) +{ + double fXAngle, fYAngle, fZAngle; + ThreeDHelper::getRotationAngleFromDiagram( m_xDiagram, fXAngle, fYAngle, fZAngle ); + + fXAngle = basegfx::rad2deg(fXAngle); + fYAngle = basegfx::rad2deg(fYAngle); + fZAngle = basegfx::rad2deg(fZAngle); + + OSL_ENSURE( fZAngle>=-90 && fZAngle<=90, "z angle is out of valid range" ); + + lcl_SetMetricFieldLimits( *m_xMFZRotation, 90 ); + + m_nXRotation = NormAngle180( + ::basegfx::fround(fXAngle * pow(10.0, m_xMFXRotation->get_digits()))); + m_nYRotation = NormAngle180( + ::basegfx::fround(-1.0 * fYAngle * pow(10.0, m_xMFYRotation->get_digits()))); + m_nZRotation = NormAngle180( + ::basegfx::fround(-1.0 * fZAngle * pow(10.0, m_xMFZRotation->get_digits()))); + + m_xMFXRotation->set_value(m_nXRotation, FieldUnit::DEGREE); + m_xMFYRotation->set_value(m_nYRotation, FieldUnit::DEGREE); + m_xMFZRotation->set_value(m_nZRotation, FieldUnit::DEGREE); + + const int nTimeout = 4*EDIT_UPDATEDATA_TIMEOUT; + m_aAngleTimer.SetTimeout(nTimeout); + m_aAngleTimer.SetInvokeHandler( LINK( this, ThreeD_SceneGeometry_TabPage, AngleChanged ) ); + + Link<weld::MetricSpinButton&,void> aAngleEditedLink( LINK( this, ThreeD_SceneGeometry_TabPage, AngleEdited )); + m_xMFXRotation->connect_value_changed( aAngleEditedLink ); + m_xMFYRotation->connect_value_changed( aAngleEditedLink ); + m_xMFZRotation->connect_value_changed( aAngleEditedLink ); + + drawing::ProjectionMode aProjectionMode = drawing::ProjectionMode_PERSPECTIVE; + m_xDiagram->getPropertyValue( "D3DScenePerspective" ) >>= aProjectionMode; + m_xCbxPerspective->set_active( aProjectionMode == drawing::ProjectionMode_PERSPECTIVE ); + m_xCbxPerspective->connect_toggled( LINK( this, ThreeD_SceneGeometry_TabPage, PerspectiveToggled )); + + sal_Int32 nPerspectivePercentage = 20; + m_xDiagram->getPropertyValue( "Perspective" ) >>= nPerspectivePercentage; + m_xMFPerspective->set_value(nPerspectivePercentage, FieldUnit::PERCENT); + + m_aPerspectiveTimer.SetTimeout(nTimeout); + m_aPerspectiveTimer.SetInvokeHandler( LINK( this, ThreeD_SceneGeometry_TabPage, PerspectiveChanged ) ); + m_xMFPerspective->connect_value_changed( LINK( this, ThreeD_SceneGeometry_TabPage, PerspectiveEdited ) ); + m_xMFPerspective->set_sensitive( m_xCbxPerspective->get_active() ); + + //RightAngledAxes + if (ChartTypeHelper::isSupportingRightAngledAxes(DiagramHelper::getChartTypeByIndex(m_xDiagram, 0))) + { + bool bRightAngledAxes = false; + m_xDiagram->getPropertyValue( "RightAngledAxes" ) >>= bRightAngledAxes; + m_xCbxRightAngledAxes->connect_toggled( LINK( this, ThreeD_SceneGeometry_TabPage, RightAngledAxesToggled )); + m_xCbxRightAngledAxes->set_active( bRightAngledAxes ); + RightAngledAxesToggled(*m_xCbxRightAngledAxes); + } + else + { + m_xCbxRightAngledAxes->set_sensitive(false); + } +} + +ThreeD_SceneGeometry_TabPage::~ThreeD_SceneGeometry_TabPage() +{ +} + +void ThreeD_SceneGeometry_TabPage::commitPendingChanges() +{ + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + if( m_bAngleChangePending ) + applyAnglesToModel(); + if( m_bPerspectiveChangePending ) + applyPerspectiveToModel(); +} + +void ThreeD_SceneGeometry_TabPage::applyAnglesToModel() +{ + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + double fXAngle = 0.0, fYAngle = 0.0, fZAngle = 0.0; + + if (m_xMFZRotation->get_sensitive()) + m_nZRotation = m_xMFZRotation->get_value(FieldUnit::DEGREE); + + fXAngle = double(m_nXRotation)/pow(10.0,m_xMFXRotation->get_digits()); + fYAngle = double(-1.0*m_nYRotation)/pow(10.0,m_xMFYRotation->get_digits()); + fZAngle = double(-1.0*m_nZRotation)/pow(10.0,m_xMFZRotation->get_digits()); + + fXAngle = basegfx::deg2rad(fXAngle); + fYAngle = basegfx::deg2rad(fYAngle); + fZAngle = basegfx::deg2rad(fZAngle); + + ThreeDHelper::setRotationAngleToDiagram( m_xDiagram, fXAngle, fYAngle, fZAngle ); + + m_bAngleChangePending = false; + m_aAngleTimer.Stop(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, AngleEdited, weld::MetricSpinButton&, void) +{ + m_nXRotation = m_xMFXRotation->get_value(FieldUnit::DEGREE); + m_nYRotation = m_xMFYRotation->get_value(FieldUnit::DEGREE); + + m_bAngleChangePending = true; + + m_aAngleTimer.Start(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, AngleChanged, Timer *, void) +{ + applyAnglesToModel(); +} + +void ThreeD_SceneGeometry_TabPage::applyPerspectiveToModel() +{ + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + drawing::ProjectionMode aMode = m_xCbxPerspective->get_active() + ? drawing::ProjectionMode_PERSPECTIVE + : drawing::ProjectionMode_PARALLEL; + + try + { + m_xDiagram->setPropertyValue( "D3DScenePerspective" , uno::Any( aMode )); + m_xDiagram->setPropertyValue( "Perspective" , uno::Any( static_cast<sal_Int32>(m_xMFPerspective->get_value(FieldUnit::PERCENT)) )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + m_bPerspectiveChangePending = false; + m_aPerspectiveTimer.Stop(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, PerspectiveEdited, weld::MetricSpinButton&, void) +{ + m_bPerspectiveChangePending = true; + m_aPerspectiveTimer.Start(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, PerspectiveChanged, Timer *, void) +{ + applyPerspectiveToModel(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, PerspectiveToggled, weld::Toggleable&, void) +{ + m_xMFPerspective->set_sensitive(m_xCbxPerspective->get_active()); + applyPerspectiveToModel(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, RightAngledAxesToggled, weld::Toggleable&, void) +{ + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + bool bEnableZ = !m_xCbxRightAngledAxes->get_active(); + m_xFtZRotation->set_sensitive( bEnableZ ); + m_xMFZRotation->set_sensitive( bEnableZ ); + if (!bEnableZ) + { + m_nXRotation = m_xMFXRotation->get_value(FieldUnit::DEGREE); + m_nYRotation = m_xMFYRotation->get_value(FieldUnit::DEGREE); + m_nZRotation = m_xMFZRotation->get_value(FieldUnit::DEGREE); + + m_xMFXRotation->set_value(static_cast<sal_Int64>(ThreeDHelper::getValueClippedToRange(static_cast<double>(m_nXRotation), ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes())), FieldUnit::DEGREE); + m_xMFYRotation->set_value(static_cast<sal_Int64>(ThreeDHelper::getValueClippedToRange(static_cast<double>(m_nYRotation), ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes())), FieldUnit::DEGREE); + m_xMFZRotation->set_text(""); + + lcl_SetMetricFieldLimits( *m_xMFXRotation, static_cast<sal_Int64>(ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes())); + lcl_SetMetricFieldLimits( *m_xMFYRotation, static_cast<sal_Int64>(ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes())); + } + else + { + lcl_SetMetricFieldLimits( *m_xMFXRotation, 180 ); + lcl_SetMetricFieldLimits( *m_xMFYRotation, 180 ); + + m_xMFXRotation->set_value(m_nXRotation, FieldUnit::DEGREE); + m_xMFYRotation->set_value(m_nYRotation, FieldUnit::DEGREE); + m_xMFZRotation->set_value(m_nZRotation, FieldUnit::DEGREE); + } + + ThreeDHelper::switchRightAngledAxes( m_xDiagram, m_xCbxRightAngledAxes->get_active() ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneGeometry.hxx b/chart2/source/controller/dialogs/tp_3D_SceneGeometry.hxx new file mode 100644 index 000000000..4bcdd8ca6 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneGeometry.hxx @@ -0,0 +1,87 @@ +/* -*- 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 <vcl/timer.hxx> +#include <vcl/weld.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star::beans { class XPropertySet; } +namespace chart { class ControllerLockHelper; } + +namespace chart +{ +class Diagram; + +class ThreeD_SceneGeometry_TabPage +{ +public: + ThreeD_SceneGeometry_TabPage(weld::Container* pWindow, + const rtl::Reference< ::chart::Diagram > & xDiagram, + ControllerLockHelper & rControllerLockHelper); + ~ThreeD_SceneGeometry_TabPage(); + + // has to be called in case the dialog was closed with OK + void commitPendingChanges(); + + // is called by timer to apply changes to model + DECL_LINK( AngleChanged, Timer *, void); + // is called immediately when a field changes + DECL_LINK( AngleEdited, weld::MetricSpinButton&, void ); + + // is called by timer to apply changes to model + DECL_LINK( PerspectiveChanged, Timer *, void); + // is called immediately when a field changes + DECL_LINK( PerspectiveEdited, weld::MetricSpinButton&, void ); + DECL_LINK( PerspectiveToggled, weld::Toggleable&, void ); + DECL_LINK( RightAngledAxesToggled, weld::Toggleable&, void ); + +private: + void applyAnglesToModel(); + void applyPerspectiveToModel(); + + rtl::Reference< ::chart::Diagram > m_xDiagram; + + Timer m_aAngleTimer; + Timer m_aPerspectiveTimer; + + //to keep old values when switching to right angled axes + sal_Int64 m_nXRotation; + sal_Int64 m_nYRotation; + sal_Int64 m_nZRotation; + + bool m_bAngleChangePending; + bool m_bPerspectiveChangePending; + + ControllerLockHelper & m_rControllerLockHelper; + + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + std::unique_ptr<weld::CheckButton> m_xCbxRightAngledAxes; + std::unique_ptr<weld::MetricSpinButton> m_xMFXRotation; + std::unique_ptr<weld::MetricSpinButton> m_xMFYRotation; + std::unique_ptr<weld::Label> m_xFtZRotation; + std::unique_ptr<weld::MetricSpinButton> m_xMFZRotation; + std::unique_ptr<weld::CheckButton> m_xCbxPerspective; + std::unique_ptr<weld::MetricSpinButton> m_xMFPerspective; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneIllumination.cxx b/chart2/source/controller/dialogs/tp_3D_SceneIllumination.cxx new file mode 100644 index 000000000..abfa395ca --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneIllumination.cxx @@ -0,0 +1,531 @@ +/* -*- 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 "tp_3D_SceneIllumination.hxx" +#include <CommonConverters.hxx> +#include <ControllerLockGuard.hxx> +#include <ChartModel.hxx> + +#include <svx/colorbox.hxx> +#include <svx/float3d.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <svtools/colrdlg.hxx> +#include <svx/svx3ditems.hxx> +#include <svx/svddef.hxx> +#include <vcl/svapp.hxx> +#include <tools/diagnose_ex.h> + +#include <com/sun/star/beans/XPropertySet.hpp> + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace { + +struct LightSource +{ + Color nDiffuseColor; + css::drawing::Direction3D aDirection; + bool bIsEnabled; + + LightSource() : + nDiffuseColor( 0xcccccc ), + aDirection( 1.0, 1.0, -1.0 ), + bIsEnabled( false ) + {} +}; + +} + +struct LightSourceInfo +{ + LightButton* pButton; + LightSource aLightSource; + + LightSourceInfo(); + void initButtonFromSource(); +}; + +LightSourceInfo::LightSourceInfo() + : pButton(nullptr) +{ + aLightSource.nDiffuseColor = Color(0xffffff); // white + aLightSource.aDirection = drawing::Direction3D(1,1,1); + aLightSource.bIsEnabled = false; +} + +void LightSourceInfo::initButtonFromSource() +{ + if (!pButton) + return; + pButton->switchLightOn(aLightSource.bIsEnabled); +} + +namespace +{ + OUString lcl_makeColorName(const Color& rColor) + { + OUString aStr = SvxResId(RID_SVXFLOAT3D_FIX_R) + + OUString::number(rColor.GetRed()) + + " " + + SvxResId(RID_SVXFLOAT3D_FIX_G) + + OUString::number(rColor.GetGreen()) + + " " + + SvxResId(RID_SVXFLOAT3D_FIX_B) + + OUString::number(rColor.GetBlue()); + return aStr; + } + + void lcl_selectColor(ColorListBox& rListBox, const Color& rColor) + { + rListBox.SetNoSelection(); + rListBox.SelectEntry(std::make_pair(rColor, lcl_makeColorName(rColor))); + } + + ::chart::LightSource lcl_getLightSourceFromProperties( + const uno::Reference< beans::XPropertySet > & xSceneProperties, + sal_Int32 nIndex ) + { + ::chart::LightSource aResult; + if( 0 <= nIndex && nIndex < 8 ) + { + OUString aIndex( OUString::number( nIndex + 1 )); + + try + { + xSceneProperties->getPropertyValue( "D3DSceneLightColor" + aIndex ) >>= aResult.nDiffuseColor; + xSceneProperties->getPropertyValue( "D3DSceneLightDirection" + aIndex ) >>= aResult.aDirection; + xSceneProperties->getPropertyValue( "D3DSceneLightOn" + aIndex ) >>= aResult.bIsEnabled; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + return aResult; + } + + void lcl_setLightSource( + const uno::Reference< beans::XPropertySet > & xSceneProperties, + const ::chart::LightSource & rLightSource, + sal_Int32 nIndex ) + { + if( 0 > nIndex || nIndex >= 8 ) + return; + + OUString aIndex( OUString::number( nIndex + 1 )); + + try + { + xSceneProperties->setPropertyValue( "D3DSceneLightColor" + aIndex, + uno::Any( rLightSource.nDiffuseColor )); + xSceneProperties->setPropertyValue( "D3DSceneLightDirection" + aIndex, + uno::Any( rLightSource.aDirection )); + xSceneProperties->setPropertyValue( "D3DSceneLightOn" + aIndex, + uno::Any( rLightSource.bIsEnabled )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + Color lcl_getAmbientColor( + const uno::Reference< beans::XPropertySet > & xSceneProperties ) + { + Color nResult; + try + { + xSceneProperties->getPropertyValue("D3DSceneAmbientColor") >>= nResult; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nResult; + } + + void lcl_setAmbientColor( + const uno::Reference< beans::XPropertySet > & xSceneProperties, + const Color & rColor ) + { + try + { + xSceneProperties->setPropertyValue("D3DSceneAmbientColor", + uno::Any( rColor )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +ThreeD_SceneIllumination_TabPage::ThreeD_SceneIllumination_TabPage(weld::Container* pParent, + weld::Window* pTopLevel, + const uno::Reference< beans::XPropertySet > & xSceneProperties, + const rtl::Reference<::chart::ChartModel>& xChartModel) + : m_xSceneProperties( xSceneProperties ) + , m_aTimerTriggeredControllerLock( xChartModel ) + , m_bInCommitToModel( false ) + , m_aModelChangeListener( LINK( this, ThreeD_SceneIllumination_TabPage, fillControlsFromModel ) ) + , m_xChartModel( xChartModel ) + , m_pTopLevel(pTopLevel) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/schart/ui/tp_3D_SceneIllumination.ui")) + , m_xContainer(m_xBuilder->weld_container("tp_3D_SceneIllumination")) + , m_xBtn_Light1(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_1"))) + , m_xBtn_Light2(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_2"))) + , m_xBtn_Light3(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_3"))) + , m_xBtn_Light4(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_4"))) + , m_xBtn_Light5(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_5"))) + , m_xBtn_Light6(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_6"))) + , m_xBtn_Light7(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_7"))) + , m_xBtn_Light8(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_8"))) + , m_xLB_LightSource(new ColorListBox(m_xBuilder->weld_menu_button("LB_LIGHTSOURCE"), [this]{ return m_pTopLevel; })) + , m_xBtn_LightSource_Color(m_xBuilder->weld_button("BTN_LIGHTSOURCE_COLOR")) + , m_xLB_AmbientLight(new ColorListBox(m_xBuilder->weld_menu_button("LB_AMBIENTLIGHT"), [this]{ return m_pTopLevel; })) + , m_xBtn_AmbientLight_Color(m_xBuilder->weld_button("BTN_AMBIENT_COLOR")) + , m_xHoriScale(m_xBuilder->weld_scale("hori")) + , m_xVertScale(m_xBuilder->weld_scale("vert")) + , m_xBtn_Corner(m_xBuilder->weld_button("corner")) + , m_xPreview(new Svx3DLightControl) + , m_xPreviewWnd(new weld::CustomWeld(*m_xBuilder, "CTL_LIGHT_PREVIEW", *m_xPreview)) + , m_xCtl_Preview(new SvxLightCtl3D(*m_xPreview, *m_xHoriScale, *m_xVertScale, *m_xBtn_Corner)) +{ + m_pLightSourceInfoList.reset(new LightSourceInfo[8]); + m_pLightSourceInfoList[0].pButton = m_xBtn_Light1.get(); + m_pLightSourceInfoList[1].pButton = m_xBtn_Light2.get(); + m_pLightSourceInfoList[2].pButton = m_xBtn_Light3.get(); + m_pLightSourceInfoList[3].pButton = m_xBtn_Light4.get(); + m_pLightSourceInfoList[4].pButton = m_xBtn_Light5.get(); + m_pLightSourceInfoList[5].pButton = m_xBtn_Light6.get(); + m_pLightSourceInfoList[6].pButton = m_xBtn_Light7.get(); + m_pLightSourceInfoList[7].pButton = m_xBtn_Light8.get(); + + fillControlsFromModel(nullptr); + + m_xBtn_Light1->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light2->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light3->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light4->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light5->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light6->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light7->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light8->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + + m_xLB_AmbientLight->SetSelectHdl( LINK( this, ThreeD_SceneIllumination_TabPage, SelectColorHdl ) ); + m_xLB_LightSource->SetSelectHdl( LINK( this, ThreeD_SceneIllumination_TabPage, SelectColorHdl ) ); + + m_xBtn_AmbientLight_Color->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ColorDialogHdl ) ); + m_xBtn_LightSource_Color->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ColorDialogHdl ) ); + + m_xCtl_Preview->SetUserInteractiveChangeCallback( LINK( this, ThreeD_SceneIllumination_TabPage, PreviewChangeHdl ) ); + m_xCtl_Preview->SetUserSelectionChangeCallback( LINK( this, ThreeD_SceneIllumination_TabPage, PreviewSelectHdl ) ); + + ClickLightSourceButtonHdl(*m_xBtn_Light2->get_widget()); + + m_aModelChangeListener.startListening( uno::Reference< util::XModifyBroadcaster >(m_xSceneProperties, uno::UNO_QUERY) ); +} + +ThreeD_SceneIllumination_TabPage::~ThreeD_SceneIllumination_TabPage() +{ +} + +IMPL_LINK_NOARG(ThreeD_SceneIllumination_TabPage, fillControlsFromModel, void*, void) +{ + if( m_bInCommitToModel )//don't read own changes + return; + + sal_Int32 nL=0; + for( nL=0; nL<8; nL++) + m_pLightSourceInfoList[nL].aLightSource = lcl_getLightSourceFromProperties( m_xSceneProperties, nL ); + for( nL=0; nL<8; nL++) + m_pLightSourceInfoList[nL].initButtonFromSource(); + + lcl_selectColor( *m_xLB_AmbientLight, lcl_getAmbientColor( m_xSceneProperties )); + + updatePreview(); +} + +void ThreeD_SceneIllumination_TabPage::applyLightSourceToModel( sal_uInt32 nLightNumber ) +{ + ControllerLockGuardUNO aGuard( m_xChartModel ); + m_bInCommitToModel = true; + sal_Int32 nIndex( nLightNumber ); + lcl_setLightSource( m_xSceneProperties, m_pLightSourceInfoList[nIndex].aLightSource, nIndex ); + m_bInCommitToModel = false; +} + +void ThreeD_SceneIllumination_TabPage::applyLightSourcesToModel() +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aGuard( m_xChartModel ); + for( sal_Int32 nL=0; nL<8; nL++) + applyLightSourceToModel( nL ); + m_aTimerTriggeredControllerLock.startTimer(); +} + +IMPL_LINK_NOARG(ThreeD_SceneIllumination_TabPage, PreviewChangeHdl, SvxLightCtl3D*, void) +{ + m_aTimerTriggeredControllerLock.startTimer(); + + //update m_pLightSourceInfoList from preview + const SfxItemSet a3DLightAttributes(m_xCtl_Preview->GetSvx3DLightControl().Get3DAttributes()); + LightSourceInfo* pInfo = &m_pLightSourceInfoList[0]; + + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1).GetValue()); + + pInfo = &m_pLightSourceInfoList[1]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2).GetValue()); + + pInfo = &m_pLightSourceInfoList[2]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3).GetValue()); + + pInfo = &m_pLightSourceInfoList[3]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4).GetValue()); + + pInfo = &m_pLightSourceInfoList[4]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5).GetValue()); + + pInfo = &m_pLightSourceInfoList[5]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6).GetValue()); + + pInfo = &m_pLightSourceInfoList[6]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7).GetValue()); + + pInfo = &m_pLightSourceInfoList[7]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8).GetValue()); + + applyLightSourcesToModel(); +} + +IMPL_LINK_NOARG(ThreeD_SceneIllumination_TabPage, PreviewSelectHdl, SvxLightCtl3D*, void) +{ + sal_uInt32 nLightNumber = m_xCtl_Preview->GetSvx3DLightControl().GetSelectedLight(); + if(nLightNumber<8) + { + LightButton* pButton = m_pLightSourceInfoList[nLightNumber].pButton; + if(!pButton->get_active()) + ClickLightSourceButtonHdl(*pButton->get_widget()); + + applyLightSourcesToModel(); + } +} + +IMPL_LINK( ThreeD_SceneIllumination_TabPage, ColorDialogHdl, weld::Button&, rButton, void ) +{ + bool bIsAmbientLight = (&rButton == m_xBtn_AmbientLight_Color.get()); + ColorListBox* pListBox = bIsAmbientLight ? m_xLB_AmbientLight.get() : m_xLB_LightSource.get(); + + SvColorDialog aColorDlg; + aColorDlg.SetColor( pListBox->GetSelectEntryColor() ); + if( aColorDlg.Execute(m_pTopLevel) != RET_OK ) + return; + + Color aColor( aColorDlg.GetColor()); + lcl_selectColor( *pListBox, aColor ); + if( bIsAmbientLight ) + { + m_bInCommitToModel = true; + lcl_setAmbientColor( m_xSceneProperties, aColor ); + m_bInCommitToModel = false; + } + else + { + //get active lightsource: + LightSourceInfo* pInfo = nullptr; + sal_Int32 nL=0; + for( nL=0; nL<8; nL++) + { + pInfo = &m_pLightSourceInfoList[nL]; + if(pInfo->pButton->get_active()) + break; + pInfo = nullptr; + } + if(pInfo) + applyLightSourceToModel( nL ); + } + SelectColorHdl( *pListBox ); +} + +IMPL_LINK( ThreeD_SceneIllumination_TabPage, SelectColorHdl, ColorListBox&, rBox, void ) +{ + ColorListBox* pListBox = &rBox; + if (pListBox == m_xLB_AmbientLight.get()) + { + m_bInCommitToModel = true; + lcl_setAmbientColor( m_xSceneProperties, pListBox->GetSelectEntryColor()); + m_bInCommitToModel = false; + } + else if (pListBox == m_xLB_LightSource.get()) + { + //get active lightsource: + LightSourceInfo* pInfo = nullptr; + sal_Int32 nL=0; + for( nL=0; nL<8; nL++) + { + pInfo = &m_pLightSourceInfoList[nL]; + if (pInfo->pButton->get_active()) + break; + pInfo = nullptr; + } + if(pInfo) + { + pInfo->aLightSource.nDiffuseColor = pListBox->GetSelectEntryColor(); + applyLightSourceToModel( nL ); + } + } + updatePreview(); +} + +IMPL_LINK(ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl, weld::Button&, rBtn, void) +{ + LightButton* pButton = nullptr; + LightSourceInfo* pInfo = nullptr; + sal_Int32 nL=0; + for( nL=0; nL<8; nL++) + { + if (m_pLightSourceInfoList[nL].pButton->get_widget() == &rBtn) + { + pButton = m_pLightSourceInfoList[nL].pButton; + pInfo = &m_pLightSourceInfoList[nL]; + break; + } + } + + assert(pInfo); + + bool bIsChecked = pInfo->pButton->get_prev_active(); + + ControllerLockGuardUNO aGuard( m_xChartModel ); + for (sal_Int32 i = 0; i < 8; ++i) + { + LightButton* pLightButton = m_pLightSourceInfoList[i].pButton; + if (pLightButton == pButton) + { + pLightButton->set_active(true); + if (!pLightButton->get_widget()->has_focus()) + pLightButton->get_widget()->grab_focus(); + m_pLightSourceInfoList[i].pButton->set_prev_active(true); + } + else + { + pLightButton->set_active(false); + m_pLightSourceInfoList[i].pButton->set_prev_active(false); + } + } + + //update light button + if (bIsChecked) + { + pButton->switchLightOn(!pButton->isLightOn()); + pInfo->aLightSource.bIsEnabled=pButton->isLightOn(); + applyLightSourceToModel( nL ); + } + + //update color list box + lcl_selectColor( *m_xLB_LightSource, pInfo->aLightSource.nDiffuseColor ); + updatePreview(); +} + +void ThreeD_SceneIllumination_TabPage::updatePreview() +{ + SfxItemSet aItemSet(m_xCtl_Preview->GetSvx3DLightControl().Get3DAttributes()); + LightSourceInfo* pInfo = &m_pLightSourceInfoList[0]; + + // AmbientColor + aItemSet.Put(makeSvx3DAmbientcolorItem(m_xLB_AmbientLight->GetSelectEntryColor())); + + aItemSet.Put(makeSvx3DLightcolor1Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff1Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection1Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[1]; + aItemSet.Put(makeSvx3DLightcolor2Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff2Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection2Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[2]; + aItemSet.Put(makeSvx3DLightcolor3Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff3Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection3Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[3]; + aItemSet.Put(makeSvx3DLightcolor4Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff4Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection4Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[4]; + aItemSet.Put(makeSvx3DLightcolor5Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff5Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection5Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[5]; + aItemSet.Put(makeSvx3DLightcolor6Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff6Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection6Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[6]; + aItemSet.Put(makeSvx3DLightcolor7Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff7Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection7Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[7]; + aItemSet.Put(makeSvx3DLightcolor8Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff8Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection8Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + // set lights and ambient light + m_xCtl_Preview->GetSvx3DLightControl().Set3DAttributes(aItemSet); + + // select light + for(sal_uInt32 a(0); a < 8; a++) + { + if (m_pLightSourceInfoList[a].pButton->get_active()) + { + m_xCtl_Preview->GetSvx3DLightControl().SelectLight(a); + m_xCtl_Preview->CheckSelection(); + break; + } + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneIllumination.hxx b/chart2/source/controller/dialogs/tp_3D_SceneIllumination.hxx new file mode 100644 index 000000000..7ad91e225 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneIllumination.hxx @@ -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 . + */ +#pragma once + +#include <ModifyListenerCallBack.hxx> +#include <TimerTriggeredControllerLock.hxx> +#include <vcl/weld.hxx> +#include <svx/dlgctl3d.hxx> + +namespace com::sun::star::beans +{ +class XPropertySet; +} + +class ColorListBox; +class LightButton; + +namespace chart +{ +struct LightSourceInfo; +class ChartModel; + +class ThreeD_SceneIllumination_TabPage +{ +public: + ThreeD_SceneIllumination_TabPage( + weld::Container* pParent, weld::Window* pTopLevel, + const css::uno::Reference<css::beans::XPropertySet>& xSceneProperties, + const rtl::Reference<::chart::ChartModel>& xChartModel); + ~ThreeD_SceneIllumination_TabPage(); + +private: + DECL_LINK(ClickLightSourceButtonHdl, weld::Button&, void); + DECL_LINK(SelectColorHdl, ColorListBox&, void); + DECL_LINK(ColorDialogHdl, weld::Button&, void); + DECL_LINK(PreviewChangeHdl, SvxLightCtl3D*, void); + DECL_LINK(PreviewSelectHdl, SvxLightCtl3D*, void); + + void updatePreview(); + +private: + DECL_LINK(fillControlsFromModel, void*, void); + + void applyLightSourceToModel(sal_uInt32 nLightNumber); + void applyLightSourcesToModel(); + + std::unique_ptr<LightSourceInfo[]> m_pLightSourceInfoList; + + css::uno::Reference<css::beans::XPropertySet> m_xSceneProperties; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + bool m_bInCommitToModel; + + ModifyListenerCallBack m_aModelChangeListener; + rtl::Reference<::chart::ChartModel> m_xChartModel; + + weld::Window* m_pTopLevel; + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + std::unique_ptr<LightButton> m_xBtn_Light1; + std::unique_ptr<LightButton> m_xBtn_Light2; + std::unique_ptr<LightButton> m_xBtn_Light3; + std::unique_ptr<LightButton> m_xBtn_Light4; + std::unique_ptr<LightButton> m_xBtn_Light5; + std::unique_ptr<LightButton> m_xBtn_Light6; + std::unique_ptr<LightButton> m_xBtn_Light7; + std::unique_ptr<LightButton> m_xBtn_Light8; + std::unique_ptr<ColorListBox> m_xLB_LightSource; + std::unique_ptr<weld::Button> m_xBtn_LightSource_Color; + std::unique_ptr<ColorListBox> m_xLB_AmbientLight; + std::unique_ptr<weld::Button> m_xBtn_AmbientLight_Color; + std::unique_ptr<weld::Scale> m_xHoriScale; + std::unique_ptr<weld::Scale> m_xVertScale; + std::unique_ptr<weld::Button> m_xBtn_Corner; + std::unique_ptr<Svx3DLightControl> m_xPreview; + std::unique_ptr<weld::CustomWeld> m_xPreviewWnd; + std::unique_ptr<SvxLightCtl3D> m_xCtl_Preview; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_AxisLabel.cxx b/chart2/source/controller/dialogs/tp_AxisLabel.cxx new file mode 100644 index 000000000..2f7d0b743 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_AxisLabel.cxx @@ -0,0 +1,302 @@ +/* -*- 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 "tp_AxisLabel.hxx" + +#include <chartview/ChartSfxItemIds.hxx> +#include <TextDirectionListBox.hxx> + +#include <svx/chrtitem.hxx> +#include <svx/sdangitm.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/frmdiritem.hxx> + +namespace chart +{ + +SchAxisLabelTabPage::SchAxisLabelTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_axisLabel.ui", "AxisLabelTabPage", &rInAttrs) + , m_bShowStaggeringControls( true ) + , m_nInitialDegrees( 0 ) + , m_bHasInitialDegrees( true ) + , m_bInitialStacking( false ) + , m_bHasInitialStacking( true ) + , m_bComplexCategories( false ) + , m_xCbShowDescription(m_xBuilder->weld_check_button("showlabelsCB")) + , m_xFlOrder(m_xBuilder->weld_label("orderL")) + , m_xRbSideBySide(m_xBuilder->weld_radio_button("tile")) + , m_xRbUpDown(m_xBuilder->weld_radio_button("odd")) + , m_xRbDownUp(m_xBuilder->weld_radio_button("even")) + , m_xRbAuto(m_xBuilder->weld_radio_button("auto")) + , m_xFlTextFlow(m_xBuilder->weld_label("textflowL")) + , m_xCbTextOverlap(m_xBuilder->weld_check_button("overlapCB")) + , m_xCbTextBreak(m_xBuilder->weld_check_button("breakCB")) + , m_xFtABCD(m_xBuilder->weld_label("labelABCD")) + , m_xFlOrient(m_xBuilder->weld_label("labelTextOrient")) + , m_xFtRotate(m_xBuilder->weld_label("degreeL")) + , m_xNfRotate(m_xBuilder->weld_metric_spin_button("OrientDegree", FieldUnit::DEGREE)) + , m_xCbStacked(m_xBuilder->weld_check_button("stackedCB")) + , m_xFtTextDirection(m_xBuilder->weld_label("textdirL")) + , m_xLbTextDirection(new TextDirectionListBox(m_xBuilder->weld_combo_box("textdirLB"))) + , m_xCtrlDial(new svx::DialControl) + , m_xCtrlDialWin(new weld::CustomWeld(*m_xBuilder, "dialCtrl", *m_xCtrlDial)) +{ + m_xCtrlDial->SetText(m_xFtABCD->get_label()); + m_xCtrlDial->SetLinkedField(m_xNfRotate.get()); + m_xCtrlDialWin->set_sensitive(true); + m_xNfRotate->set_sensitive(true); + m_xCbStacked->set_sensitive(true); + m_xFtRotate->set_sensitive(true); + + m_xCbStacked->connect_toggled(LINK(this, SchAxisLabelTabPage, StackedToggleHdl)); + m_xCbShowDescription->connect_toggled(LINK(this, SchAxisLabelTabPage, ToggleShowLabel)); +} + +SchAxisLabelTabPage::~SchAxisLabelTabPage() +{ + m_xCtrlDialWin.reset(); + m_xCtrlDial.reset(); + m_xLbTextDirection.reset(); +} + +std::unique_ptr<SfxTabPage> SchAxisLabelTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrs) +{ + return std::make_unique<SchAxisLabelTabPage>(pPage, pController, *rAttrs); +} + +bool SchAxisLabelTabPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + bool bStacked = false; + if (m_xCbStacked->get_state() != TRISTATE_INDET ) + { + bStacked = m_xCbStacked->get_state() == TRISTATE_TRUE; + if( !m_bHasInitialStacking || (bStacked != m_bInitialStacking) ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_TEXT_STACKED, bStacked ) ); + } + + if( m_xCtrlDial->HasRotation() ) + { + Degree100 nDegrees = bStacked ? 0_deg100 : m_xCtrlDial->GetRotation(); + if( !m_bHasInitialDegrees || (nDegrees != m_nInitialDegrees) ) + rOutAttrs->Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, nDegrees ) ); + } + + if( m_bShowStaggeringControls ) + { + SvxChartTextOrder eOrder = SvxChartTextOrder::SideBySide; + bool bRadioButtonChecked = true; + + if( m_xRbUpDown->get_active()) + eOrder = SvxChartTextOrder::UpDown; + else if( m_xRbDownUp->get_active()) + eOrder = SvxChartTextOrder::DownUp; + else if( m_xRbAuto->get_active()) + eOrder = SvxChartTextOrder::Auto; + else if( m_xRbSideBySide->get_active()) + eOrder = SvxChartTextOrder::SideBySide; + else + bRadioButtonChecked = false; + + if( bRadioButtonChecked ) + rOutAttrs->Put( SvxChartTextOrderItem( eOrder, SCHATTR_AXIS_LABEL_ORDER )); + } + + if( m_xCbTextOverlap->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_AXIS_LABEL_OVERLAP, m_xCbTextOverlap->get_active() ) ); + if( m_xCbTextBreak->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_AXIS_LABEL_BREAK, m_xCbTextBreak->get_active() ) ); + if( m_xCbShowDescription->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_AXIS_SHOWDESCR, m_xCbShowDescription->get_active() ) ); + + if (m_xLbTextDirection->get_active() != -1) + rOutAttrs->Put( SvxFrameDirectionItem( m_xLbTextDirection->get_active_id(), EE_PARA_WRITINGDIR ) ); + + return true; +} + +void SchAxisLabelTabPage::Reset( const SfxItemSet* rInAttrs ) +{ + const SfxPoolItem* pPoolItem = nullptr; + + // show description + SfxItemState aState = rInAttrs->GetItemState( SCHATTR_AXIS_SHOWDESCR, false, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCbShowDescription->set_state( TRISTATE_INDET ); + } + else + { + bool bCheck = false; + if( aState == SfxItemState::SET ) + bCheck = static_cast< const SfxBoolItem * >( pPoolItem )->GetValue(); + m_xCbShowDescription->set_active( bCheck ); + + if( aState != SfxItemState::DEFAULT && aState != SfxItemState::SET ) + m_xCbShowDescription->hide(); + } + + // Rotation as orient item or in degrees ---------- + + // check new degree item + m_nInitialDegrees = 0_deg100; + aState = rInAttrs->GetItemState( SCHATTR_TEXT_DEGREES, false, &pPoolItem ); + if( aState == SfxItemState::SET ) + m_nInitialDegrees = static_cast< const SdrAngleItem * >( pPoolItem )->GetValue(); + + m_bHasInitialDegrees = aState != SfxItemState::DONTCARE; + if( m_bHasInitialDegrees ) + m_xCtrlDial->SetRotation( m_nInitialDegrees ); + else + m_xCtrlDial->SetNoRotation(); + + // check stacked item + m_bInitialStacking = false; + aState = rInAttrs->GetItemState( SCHATTR_TEXT_STACKED, false, &pPoolItem ); + if( aState == SfxItemState::SET ) + m_bInitialStacking = static_cast< const SfxBoolItem * >( pPoolItem )->GetValue(); + + m_bHasInitialStacking = aState != SfxItemState::DONTCARE; + if( m_bHasInitialDegrees ) + m_xCbStacked->set_state(m_bInitialStacking ? TRISTATE_TRUE : TRISTATE_FALSE); + else + m_xCbStacked->set_state(TRISTATE_INDET); + StackedToggleHdl(*m_xCbStacked); + + if( const SvxFrameDirectionItem* pDirectionItem = rInAttrs->GetItemIfSet( EE_PARA_WRITINGDIR ) ) + m_xLbTextDirection->set_active_id( pDirectionItem->GetValue() ); + + // Text overlap ---------- + aState = rInAttrs->GetItemState( SCHATTR_AXIS_LABEL_OVERLAP, false, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCbTextOverlap->set_state( TRISTATE_INDET ); + } + else + { + bool bCheck = false; + if( aState == SfxItemState::SET ) + bCheck = static_cast< const SfxBoolItem * >( pPoolItem )->GetValue(); + m_xCbTextOverlap->set_active( bCheck ); + + if( aState != SfxItemState::DEFAULT && aState != SfxItemState::SET ) + m_xCbTextOverlap->hide(); + } + + // text break ---------- + aState = rInAttrs->GetItemState( SCHATTR_AXIS_LABEL_BREAK, false, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCbTextBreak->set_state( TRISTATE_INDET ); + } + else + { + bool bCheck = false; + if( aState == SfxItemState::SET ) + bCheck = static_cast< const SfxBoolItem * >( pPoolItem )->GetValue(); + m_xCbTextBreak->set_active( bCheck ); + + if( aState != SfxItemState::DEFAULT && aState != SfxItemState::SET ) + { + m_xCbTextBreak->hide(); + if( ! m_xCbTextOverlap->get_visible() ) + m_xFlTextFlow->hide(); + } + } + + // text order ---------- + if( m_bShowStaggeringControls ) + { + if( const SvxChartTextOrderItem* pOrderItem = rInAttrs->GetItemIfSet( SCHATTR_AXIS_LABEL_ORDER, false ) ) + { + SvxChartTextOrder eOrder = pOrderItem->GetValue(); + + switch( eOrder ) + { + case SvxChartTextOrder::SideBySide: + m_xRbSideBySide->set_active(true); + break; + case SvxChartTextOrder::UpDown: + m_xRbUpDown->set_active(true); + break; + case SvxChartTextOrder::DownUp: + m_xRbDownUp->set_active(true); + break; + case SvxChartTextOrder::Auto: + m_xRbAuto->set_active(true); + break; + } + } + } + + ToggleShowLabel(*m_xCbShowDescription); +} + +void SchAxisLabelTabPage::ShowStaggeringControls( bool bShowStaggeringControls ) +{ + m_bShowStaggeringControls = bShowStaggeringControls; + + if( !m_bShowStaggeringControls ) + { + m_xRbSideBySide->hide(); + m_xRbUpDown->hide(); + m_xRbDownUp->hide(); + m_xRbAuto->hide(); + m_xFlOrder->hide(); + } +} + +void SchAxisLabelTabPage::SetComplexCategories( bool bComplexCategories ) +{ + m_bComplexCategories = bComplexCategories; +} + +// event handling routines + +IMPL_LINK_NOARG(SchAxisLabelTabPage, StackedToggleHdl, weld::Toggleable&, void) +{ + bool bActive = m_xCbStacked->get_active() && m_xCbStacked->get_sensitive(); + m_xNfRotate->set_sensitive(!bActive); + m_xCtrlDialWin->set_sensitive(!bActive); + m_xCtrlDial->StyleUpdated(); + m_xFtRotate->set_sensitive(!bActive); +} + +IMPL_LINK_NOARG(SchAxisLabelTabPage, ToggleShowLabel, weld::Toggleable&, void) +{ + bool bEnable = ( m_xCbShowDescription->get_state() != TRISTATE_FALSE ); + + m_xCbStacked->set_sensitive(bEnable); + StackedToggleHdl(*m_xCbStacked); + + m_xFlOrder->set_sensitive( bEnable ); + m_xRbSideBySide->set_sensitive( bEnable ); + m_xRbUpDown->set_sensitive( bEnable ); + m_xRbDownUp->set_sensitive( bEnable ); + m_xRbAuto->set_sensitive( bEnable ); + + m_xFlTextFlow->set_sensitive( bEnable ); + m_xCbTextOverlap->set_sensitive( bEnable && !m_bComplexCategories ); + m_xCbTextBreak->set_sensitive( bEnable ); + + m_xFtTextDirection->set_sensitive( bEnable ); + m_xLbTextDirection->set_sensitive( bEnable ); +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_AxisLabel.hxx b/chart2/source/controller/dialogs/tp_AxisLabel.hxx new file mode 100644 index 000000000..a94a030fe --- /dev/null +++ b/chart2/source/controller/dialogs/tp_AxisLabel.hxx @@ -0,0 +1,84 @@ +/* -*- 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 <sfx2/tabdlg.hxx> +#include <svx/dialcontrol.hxx> +#include <tools/degree.hxx> + +namespace chart { class TextDirectionListBox; } +namespace weld { + class CheckButton; + class CustomWeld; + class Label; + class RadioButton; + class SpinButton; + class ToggleButton; +} + +namespace chart +{ + +class SchAxisLabelTabPage : public SfxTabPage +{ +private: + bool m_bShowStaggeringControls; + + Degree100 m_nInitialDegrees; + bool m_bHasInitialDegrees; /// false = DialControl in tristate + bool m_bInitialStacking; + bool m_bHasInitialStacking; /// false = checkbox in tristate + bool m_bComplexCategories; + + std::unique_ptr<weld::CheckButton> m_xCbShowDescription; + std::unique_ptr<weld::Label> m_xFlOrder; + std::unique_ptr<weld::RadioButton> m_xRbSideBySide; + std::unique_ptr<weld::RadioButton> m_xRbUpDown; + std::unique_ptr<weld::RadioButton> m_xRbDownUp; + std::unique_ptr<weld::RadioButton> m_xRbAuto; + std::unique_ptr<weld::Label> m_xFlTextFlow; + std::unique_ptr<weld::CheckButton> m_xCbTextOverlap; + std::unique_ptr<weld::CheckButton> m_xCbTextBreak; + std::unique_ptr<weld::Label> m_xFtABCD; + std::unique_ptr<weld::Label> m_xFlOrient; + std::unique_ptr<weld::Label> m_xFtRotate; + std::unique_ptr<weld::MetricSpinButton> m_xNfRotate; + std::unique_ptr<weld::CheckButton> m_xCbStacked; + std::unique_ptr<weld::Label> m_xFtTextDirection; + std::unique_ptr<TextDirectionListBox> m_xLbTextDirection; + std::unique_ptr<svx::DialControl> m_xCtrlDial; + std::unique_ptr<weld::CustomWeld> m_xCtrlDialWin; + + DECL_LINK(StackedToggleHdl, weld::Toggleable&, void); + DECL_LINK(ToggleShowLabel, weld::Toggleable&, void); + +public: + SchAxisLabelTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~SchAxisLabelTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + + void ShowStaggeringControls( bool bShowStaggeringControls ); + void SetComplexCategories( bool bComplexCategories ); +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_AxisPositions.cxx b/chart2/source/controller/dialogs/tp_AxisPositions.cxx new file mode 100644 index 000000000..75e662fbb --- /dev/null +++ b/chart2/source/controller/dialogs/tp_AxisPositions.cxx @@ -0,0 +1,322 @@ +/* -*- 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 "tp_AxisPositions.hxx" + +#include <chartview/ChartSfxItemIds.hxx> +#include <AxisHelper.hxx> + +#include <rtl/math.hxx> +#include <svx/chrtitem.hxx> +#include <svl/intitem.hxx> +#include <vcl/formatter.hxx> + +using namespace ::com::sun::star; + +namespace chart +{ + +AxisPositionsTabPage::AxisPositionsTabPage(weld::Container* pPage, weld::DialogController* pController,const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_AxisPositions.ui", "tp_AxisPositions", &rInAttrs) + , m_pNumFormatter(nullptr) + , m_bCrossingAxisIsCategoryAxis(false) + , m_bSupportAxisPositioning(false) + , m_bSupportCategoryPositioning(false) + , m_xFL_AxisLine(m_xBuilder->weld_frame("FL_AXIS_LINE")) + , m_xLB_CrossesAt(m_xBuilder->weld_combo_box("LB_CROSSES_OTHER_AXIS_AT")) + , m_xED_CrossesAt(m_xBuilder->weld_formatted_spin_button("EDT_CROSSES_OTHER_AXIS_AT")) + , m_xED_CrossesAtCategory(m_xBuilder->weld_combo_box( "EDT_CROSSES_OTHER_AXIS_AT_CATEGORY")) + , m_xCB_AxisBetweenCategories(m_xBuilder->weld_check_button("CB_AXIS_BETWEEN_CATEGORIES")) + , m_xFL_Position(m_xBuilder->weld_frame("FL_POSITION")) + , m_xRB_On(m_xBuilder->weld_radio_button("RB_ON")) + , m_xRB_Between(m_xBuilder->weld_radio_button("RB_BETWEEN")) + , m_xFL_Labels(m_xBuilder->weld_frame("FL_LABELS")) + , m_xLB_PlaceLabels(m_xBuilder->weld_combo_box("LB_PLACE_LABELS")) + , m_xED_LabelDistance(m_xBuilder->weld_formatted_spin_button("EDT_AXIS_LABEL_DISTANCE")) + , m_xCB_TicksInner(m_xBuilder->weld_check_button("CB_TICKS_INNER")) + , m_xCB_TicksOuter(m_xBuilder->weld_check_button("CB_TICKS_OUTER")) + , m_xCB_MinorInner(m_xBuilder->weld_check_button("CB_MINOR_INNER")) + , m_xCB_MinorOuter(m_xBuilder->weld_check_button("CB_MINOR_OUTER")) + , m_xBxPlaceTicks(m_xBuilder->weld_widget("boxPLACE_TICKS")) + , m_xLB_PlaceTicks(m_xBuilder->weld_combo_box("LB_PLACE_TICKS")) +{ + m_xLB_CrossesAt->connect_changed(LINK(this, AxisPositionsTabPage, CrossesAtSelectHdl)); + m_xLB_PlaceLabels->connect_changed(LINK(this, AxisPositionsTabPage, PlaceLabelsSelectHdl)); + + Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter(); + rCrossFormatter.ClearMinValue(); + rCrossFormatter.ClearMaxValue(); + Formatter& rDistanceFormatter = m_xED_CrossesAt->GetFormatter(); + rDistanceFormatter.ClearMinValue(); + rDistanceFormatter.ClearMaxValue(); +} + +AxisPositionsTabPage::~AxisPositionsTabPage() +{ +} + +std::unique_ptr<SfxTabPage> AxisPositionsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique<AxisPositionsTabPage>(pPage, pController, *rOutAttrs); +} + +bool AxisPositionsTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + // axis line + sal_Int32 nPos = m_xLB_CrossesAt->get_active(); + rOutAttrs->Put( SfxInt32Item( SCHATTR_AXIS_POSITION, nPos+1 )); + if( nPos==2 ) + { + Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter(); + double fCrossover = rCrossFormatter.GetValue(); + if( m_bCrossingAxisIsCategoryAxis ) + fCrossover = m_xED_CrossesAtCategory->get_active()+1; + rOutAttrs->Put(SvxDoubleItem(fCrossover,SCHATTR_AXIS_POSITION_VALUE)); + } + + // shifted category position + if (m_xFL_Position->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION, m_xRB_Between->get_active())); + + // labels + sal_Int32 nLabelPos = m_xLB_PlaceLabels->get_active(); + if (nLabelPos != -1) + rOutAttrs->Put( SfxInt32Item( SCHATTR_AXIS_LABEL_POSITION, nLabelPos )); + + // tick marks + sal_Int32 nTicks=0; + sal_Int32 nMinorTicks=0; + + if(m_xCB_MinorInner->get_active()) + nMinorTicks|=CHAXIS_MARK_INNER; + if(m_xCB_MinorOuter->get_active()) + nMinorTicks|=CHAXIS_MARK_OUTER; + if(m_xCB_TicksInner->get_active()) + nTicks|=CHAXIS_MARK_INNER; + if(m_xCB_TicksOuter->get_active()) + nTicks|=CHAXIS_MARK_OUTER; + + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_TICKS,nTicks)); + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_HELPTICKS,nMinorTicks)); + + sal_Int32 nMarkPos = m_xLB_PlaceTicks->get_active(); + if (nMarkPos != -1) + rOutAttrs->Put( SfxInt32Item( SCHATTR_AXIS_MARK_POSITION, nMarkPos )); + + return true; +} + +void AxisPositionsTabPage::Reset(const SfxItemSet* rInAttrs) +{ + //init and enable controls + m_xED_CrossesAt->set_visible( !m_bCrossingAxisIsCategoryAxis ); + m_xED_CrossesAtCategory->set_visible( m_bCrossingAxisIsCategoryAxis ); + if (m_bCrossingAxisIsCategoryAxis) + { + for( auto const & cat : std::as_const(m_aCategories) ) + m_xED_CrossesAtCategory->append_text(cat); + } + + if( m_xLB_CrossesAt->get_count() > 3 ) + { + if( m_bCrossingAxisIsCategoryAxis ) + m_xLB_CrossesAt->remove(2); + else + m_xLB_CrossesAt->remove(3); + } + + //fill controls + + //axis line + if(SfxInt32Item const * pPositionItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_POSITION)) + { + bool bZero = false; + sal_Int32 nPos = pPositionItem->GetValue(); + if(nPos==0) + { + //switch to value + bZero = true; + nPos = 2; + } + else + nPos--; + + if( nPos < m_xLB_CrossesAt->get_count() ) + m_xLB_CrossesAt->set_active( nPos ); + CrossesAtSelectHdl( *m_xLB_CrossesAt ); + + const SvxDoubleItem* pPosValueItem; + if( (pPosValueItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_POSITION_VALUE)) || bZero ) + { + double fCrossover = 0.0; + if( !bZero ) + fCrossover = pPosValueItem->GetValue(); + if( m_bCrossingAxisIsCategoryAxis ) + m_xED_CrossesAtCategory->set_active( static_cast<sal_uInt16>(::rtl::math::round(fCrossover-1.0)) ); + else + { + Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter(); + rCrossFormatter.SetValue(fCrossover); + } + } + else + { + m_xED_CrossesAtCategory->set_active(-1); + m_xED_CrossesAt->set_text(""); + } + } + else + { + m_xLB_CrossesAt->set_active(-1); + m_xED_CrossesAt->set_sensitive( false ); + } + + // shifted category position + const SfxBoolItem* pCatPosItem; + if (m_bSupportCategoryPositioning && (pCatPosItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION))) + { + if (pCatPosItem->GetValue()) + m_xRB_Between->set_active(true); + else + m_xRB_On->set_active(true); + } + else + m_xFL_Position->hide(); + + // Labels + if( const SfxInt32Item* pLabelPosItem = rInAttrs->GetItemIfSet( SCHATTR_AXIS_LABEL_POSITION, false) ) + { + sal_Int32 nPos = pLabelPosItem->GetValue(); + if( nPos < m_xLB_PlaceLabels->get_count() ) + m_xLB_PlaceLabels->set_active( nPos ); + } + else + m_xLB_PlaceLabels->set_active(-1); + PlaceLabelsSelectHdl( *m_xLB_PlaceLabels ); + + // Tick marks + tools::Long nTicks = 0, nMinorTicks = 0; + if (const SfxInt32Item* pTicksItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_TICKS)) + nTicks = pTicksItem->GetValue(); + if (const SfxInt32Item* pHelpTicksItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_HELPTICKS)) + nMinorTicks = pHelpTicksItem->GetValue(); + + m_xCB_TicksInner->set_active(bool(nTicks&CHAXIS_MARK_INNER)); + m_xCB_TicksOuter->set_active(bool(nTicks&CHAXIS_MARK_OUTER)); + m_xCB_MinorInner->set_active(bool(nMinorTicks&CHAXIS_MARK_INNER)); + m_xCB_MinorOuter->set_active(bool(nMinorTicks&CHAXIS_MARK_OUTER)); + + // Tick position + if( const SfxInt32Item* pMarkPosItem = rInAttrs->GetItemIfSet( SCHATTR_AXIS_MARK_POSITION, false) ) + { + sal_Int32 nPos = pMarkPosItem->GetValue(); + if( nPos < m_xLB_PlaceTicks->get_count() ) + m_xLB_PlaceTicks->set_active( nPos ); + } + else + m_xLB_PlaceTicks->set_active(-1); + + if( !m_bSupportAxisPositioning ) + { + m_xFL_AxisLine->hide(); + m_xFL_Labels->hide(); + m_xBxPlaceTicks->hide(); + } + else if( !AxisHelper::isAxisPositioningEnabled() ) + { + m_xFL_AxisLine->set_sensitive(false); + m_xFL_Labels->set_sensitive(false); + m_xBxPlaceTicks->set_sensitive(false); + //todo: maybe set a special help id to all those controls + } +} + +DeactivateRC AxisPositionsTabPage::DeactivatePage(SfxItemSet* pItemSet) +{ + if( pItemSet ) + FillItemSet( pItemSet ); + + return DeactivateRC::LeavePage; +} + +void AxisPositionsTabPage::SetNumFormatter( SvNumberFormatter* pFormatter ) +{ + m_pNumFormatter = pFormatter; + Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter(); + rCrossFormatter.SetFormatter(m_pNumFormatter); + rCrossFormatter.UseInputStringForFormatting(); + + if( const SfxUInt32Item* pNumFormatItem = GetItemSet().GetItemIfSet(SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT) ) + { + sal_uLong nFmt = pNumFormatItem->GetValue(); + rCrossFormatter.SetFormatKey(nFmt); + } +} + +void AxisPositionsTabPage::SetCrossingAxisIsCategoryAxis( bool bCrossingAxisIsCategoryAxis ) +{ + m_bCrossingAxisIsCategoryAxis = bCrossingAxisIsCategoryAxis; +} + +void AxisPositionsTabPage::SetCategories( const css::uno::Sequence< OUString >& rCategories ) +{ + m_aCategories = rCategories; +} + +void AxisPositionsTabPage::SupportAxisPositioning( bool bSupportAxisPositioning ) +{ + m_bSupportAxisPositioning = bSupportAxisPositioning; +} + +void AxisPositionsTabPage::SupportCategoryPositioning( bool bSupportCategoryPositioning ) +{ + m_bSupportCategoryPositioning = bSupportCategoryPositioning; +} + +IMPL_LINK_NOARG(AxisPositionsTabPage, CrossesAtSelectHdl, weld::ComboBox&, void) +{ + sal_Int32 nPos = m_xLB_CrossesAt->get_active(); + m_xED_CrossesAt->set_visible( (nPos==2) && !m_bCrossingAxisIsCategoryAxis ); + m_xED_CrossesAtCategory->set_visible( (nPos==2) && m_bCrossingAxisIsCategoryAxis ); + + if (m_xED_CrossesAt->get_text().isEmpty()) + m_xED_CrossesAt->GetFormatter().SetValue(0.0); + if (m_xED_CrossesAtCategory->get_active() == -1) + m_xED_CrossesAtCategory->set_active(0); + + PlaceLabelsSelectHdl(*m_xLB_PlaceLabels); +} + +IMPL_LINK_NOARG(AxisPositionsTabPage, PlaceLabelsSelectHdl, weld::ComboBox&, void) +{ + sal_Int32 nLabelPos = m_xLB_PlaceLabels->get_active(); + + bool bEnableTickmarkPlacement = (nLabelPos>1); + if( bEnableTickmarkPlacement ) + { + sal_Int32 nAxisPos = m_xLB_CrossesAt->get_active(); + if( nLabelPos-2 == nAxisPos ) + bEnableTickmarkPlacement=false; + } + m_xBxPlaceTicks->set_sensitive(bEnableTickmarkPlacement); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_AxisPositions.hxx b/chart2/source/controller/dialogs/tp_AxisPositions.hxx new file mode 100644 index 000000000..d7f18242d --- /dev/null +++ b/chart2/source/controller/dialogs/tp_AxisPositions.hxx @@ -0,0 +1,85 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +namespace chart +{ +class AxisPositionsTabPage : public SfxTabPage +{ +public: + AxisPositionsTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + virtual ~AxisPositionsTabPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pItemSet) override; + + void SetNumFormatter(SvNumberFormatter* pFormatter); + + void SetCrossingAxisIsCategoryAxis(bool bCrossingAxisIsCategoryAxis); + void SetCategories(const css::uno::Sequence<OUString>& rCategories); + + void SupportAxisPositioning(bool bSupportAxisPositioning); + void SupportCategoryPositioning(bool bSupportCategoryPositioning); + +private: //methods: + DECL_LINK(CrossesAtSelectHdl, weld::ComboBox&, void); + DECL_LINK(PlaceLabelsSelectHdl, weld::ComboBox&, void); + +private: //member: + SvNumberFormatter* m_pNumFormatter; + + bool m_bCrossingAxisIsCategoryAxis; + css::uno::Sequence<OUString> m_aCategories; + + bool m_bSupportAxisPositioning; + bool m_bSupportCategoryPositioning; + + std::unique_ptr<weld::Frame> m_xFL_AxisLine; + std::unique_ptr<weld::ComboBox> m_xLB_CrossesAt; + std::unique_ptr<weld::FormattedSpinButton> m_xED_CrossesAt; + std::unique_ptr<weld::ComboBox> m_xED_CrossesAtCategory; + std::unique_ptr<weld::CheckButton> m_xCB_AxisBetweenCategories; + + std::unique_ptr<weld::Frame> m_xFL_Position; + std::unique_ptr<weld::RadioButton> m_xRB_On; + std::unique_ptr<weld::RadioButton> m_xRB_Between; + + std::unique_ptr<weld::Frame> m_xFL_Labels; + std::unique_ptr<weld::ComboBox> m_xLB_PlaceLabels; + std::unique_ptr<weld::FormattedSpinButton> m_xED_LabelDistance; + + std::unique_ptr<weld::CheckButton> m_xCB_TicksInner; + std::unique_ptr<weld::CheckButton> m_xCB_TicksOuter; + + std::unique_ptr<weld::CheckButton> m_xCB_MinorInner; + std::unique_ptr<weld::CheckButton> m_xCB_MinorOuter; + + std::unique_ptr<weld::Widget> m_xBxPlaceTicks; + std::unique_ptr<weld::ComboBox> m_xLB_PlaceTicks; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ChartType.cxx b/chart2/source/controller/dialogs/tp_ChartType.cxx new file mode 100644 index 000000000..7a007f9da --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ChartType.cxx @@ -0,0 +1,380 @@ +/* -*- 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 "tp_ChartType.hxx" +#include <ChartResourceGroups.hxx> +#include <ChartTypeManager.hxx> +#include <strings.hrc> +#include <ResId.hxx> +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <ChartTypeTemplate.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <unonames.hxx> + +#include <svtools/valueset.hxx> + +#include <vcl/weld.hxx> +#include <vcl/outdev.hxx> +#include <tools/diagnose_ex.h> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +ChartTypeTabPage::ChartTypeTabPage(weld::Container* pPage, weld::DialogController* pController, const rtl::Reference<::chart::ChartModel>& xChartModel, + bool bShowDescription) + : OWizardPage(pPage, pController, "modules/schart/ui/tp_ChartType.ui", "tp_ChartType") + , m_pDim3DLookResourceGroup( new Dim3DLookResourceGroup(m_xBuilder.get()) ) + , m_pStackingResourceGroup( new StackingResourceGroup(m_xBuilder.get()) ) + , m_pSplineResourceGroup( new SplineResourceGroup(m_xBuilder.get(), pController->getDialog()) ) + , m_pGeometryResourceGroup( new GeometryResourceGroup(m_xBuilder.get()) ) + , m_pSortByXValuesResourceGroup( new SortByXValuesResourceGroup(m_xBuilder.get()) ) + , m_xChartModel( xChartModel ) + , m_aChartTypeDialogControllerList(0) + , m_pCurrentMainType(nullptr) + , m_nChangingCalls(0) + , m_aTimerTriggeredControllerLock( m_xChartModel ) + , m_xFT_ChooseType(m_xBuilder->weld_label("FT_CAPTION_FOR_WIZARD")) + , m_xMainTypeList(m_xBuilder->weld_tree_view("charttype")) + , m_xSubTypeList(new ValueSet(m_xBuilder->weld_scrolled_window("subtypewin", true))) + , m_xSubTypeListWin(new weld::CustomWeld(*m_xBuilder, "subtype", *m_xSubTypeList)) +{ + Size aSize(m_xSubTypeList->GetDrawingArea()->get_ref_device().LogicToPixel(Size(150, 50), MapMode(MapUnit::MapAppFont))); + m_xSubTypeListWin->set_size_request(aSize.Width(), aSize.Height()); + + if (bShowDescription) + { + m_xFT_ChooseType->show(); + } + else + { + m_xFT_ChooseType->hide(); + } + + SetPageTitle(SchResId(STR_PAGE_CHARTTYPE)); + + m_xMainTypeList->connect_changed(LINK(this, ChartTypeTabPage, SelectMainTypeHdl)); + m_xSubTypeList->SetSelectHdl( LINK( this, ChartTypeTabPage, SelectSubTypeHdl ) ); + + m_xSubTypeList->SetStyle(m_xSubTypeList->GetStyle() | + WB_ITEMBORDER | WB_DOUBLEBORDER | WB_NAMEFIELD | WB_FLATVALUESET | WB_3DLOOK ); + m_xSubTypeList->SetColCount(4); + m_xSubTypeList->SetLineCount(1); + + bool bEnableComplexChartTypes = true; + uno::Reference< beans::XPropertySet > xProps( static_cast<cppu::OWeakObject*>(m_xChartModel.get()), uno::UNO_QUERY ); + if ( xProps.is() ) + { + try + { + xProps->getPropertyValue("EnableComplexChartTypes") >>= bEnableComplexChartTypes; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + + m_aChartTypeDialogControllerList.push_back(std::make_unique<ColumnChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<BarChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<PieChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<AreaChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<LineChartDialogController>()); + if (bEnableComplexChartTypes) + { + m_aChartTypeDialogControllerList.push_back(std::make_unique<XYChartDialogController>()); + m_aChartTypeDialogControllerList.push_back( + std::make_unique<BubbleChartDialogController>()); + } + m_aChartTypeDialogControllerList.push_back(std::make_unique<NetChartDialogController>()); + if (bEnableComplexChartTypes) + { + m_aChartTypeDialogControllerList.push_back(std::make_unique<StockChartDialogController>()); + } + m_aChartTypeDialogControllerList.push_back( + std::make_unique<CombiColumnLineChartDialogController>()); + + for (auto const& elem : m_aChartTypeDialogControllerList) + { + m_xMainTypeList->append("", elem->getName(), elem->getImage()); + elem->setChangeListener( this ); + } + + m_xMainTypeList->set_size_request(m_xMainTypeList->get_preferred_size().Width(), -1); + + m_pDim3DLookResourceGroup->setChangeListener( this ); + m_pStackingResourceGroup->setChangeListener( this ); + m_pSplineResourceGroup->setChangeListener( this ); + m_pGeometryResourceGroup->setChangeListener( this ); + m_pSortByXValuesResourceGroup->setChangeListener( this ); +} + +ChartTypeTabPage::~ChartTypeTabPage() +{ + //delete all dialog controller + m_aChartTypeDialogControllerList.clear(); + + //delete all resource helper + m_pDim3DLookResourceGroup.reset(); + m_pStackingResourceGroup.reset(); + m_pSplineResourceGroup.reset(); + m_pGeometryResourceGroup.reset(); + m_pSortByXValuesResourceGroup.reset(); + m_xSubTypeListWin.reset(); + m_xSubTypeList.reset(); +} + +ChartTypeParameter ChartTypeTabPage::getCurrentParamter() const +{ + ChartTypeParameter aParameter; + aParameter.nSubTypeIndex = static_cast<sal_Int32>(m_xSubTypeList->GetSelectedItemId()); + m_pDim3DLookResourceGroup->fillParameter( aParameter ); + m_pStackingResourceGroup->fillParameter( aParameter ); + m_pSplineResourceGroup->fillParameter( aParameter ); + m_pGeometryResourceGroup->fillParameter( aParameter ); + m_pSortByXValuesResourceGroup->fillParameter( aParameter ); + return aParameter; +} + +void ChartTypeTabPage::commitToModel( const ChartTypeParameter& rParameter ) +{ + if( !m_pCurrentMainType ) + return; + + m_aTimerTriggeredControllerLock.startTimer(); + m_pCurrentMainType->commitToModel( rParameter, m_xChartModel ); +} + +void ChartTypeTabPage::stateChanged() +{ + if(m_nChangingCalls) + return; + m_nChangingCalls++; + + ChartTypeParameter aParameter( getCurrentParamter() ); + if( m_pCurrentMainType ) + { + m_pCurrentMainType->adjustParameterToSubType( aParameter ); + m_pCurrentMainType->adjustSubTypeAndEnableControls( aParameter ); + } + commitToModel( aParameter ); + + //detect the new ThreeDLookScheme + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + // tdf#124295 - select always a 3D scheme + if (ThreeDLookScheme aThreeDLookScheme = ThreeDHelper::detectScheme(xDiagram); + aThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Unknown) + aParameter.eThreeDLookScheme = aThreeDLookScheme; + + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + //the controls have to be enabled/disabled accordingly + fillAllControls( aParameter ); + + m_nChangingCalls--; +} + +ChartTypeDialogController* ChartTypeTabPage::getSelectedMainType() +{ + ChartTypeDialogController* pTypeController = nullptr; + auto nM = static_cast< std::vector< ChartTypeDialogController* >::size_type >( + m_xMainTypeList->get_selected_index() ); + if( nM<m_aChartTypeDialogControllerList.size() ) + pTypeController = m_aChartTypeDialogControllerList[nM].get(); + return pTypeController; +} + +IMPL_LINK_NOARG(ChartTypeTabPage, SelectSubTypeHdl, ValueSet*, void) +{ + if( m_pCurrentMainType ) + { + ChartTypeParameter aParameter( getCurrentParamter() ); + m_pCurrentMainType->adjustParameterToSubType( aParameter ); + fillAllControls( aParameter, false ); + commitToModel( aParameter ); + } +} + +IMPL_LINK_NOARG(ChartTypeTabPage, SelectMainTypeHdl, weld::TreeView&, void) +{ + selectMainType(); +} + +void ChartTypeTabPage::selectMainType() +{ + ChartTypeParameter aParameter( getCurrentParamter() ); + + if( m_pCurrentMainType ) + { + m_pCurrentMainType->adjustParameterToSubType( aParameter ); + m_pCurrentMainType->hideExtraControls(); + } + + m_pCurrentMainType = getSelectedMainType(); + if( !m_pCurrentMainType ) + return; + + showAllControls(*m_pCurrentMainType); + + m_pCurrentMainType->adjustParameterToMainType( aParameter ); + commitToModel( aParameter ); + //detect the new ThreeDLookScheme + aParameter.eThreeDLookScheme = ThreeDHelper::detectScheme( ChartModelHelper::findDiagram( m_xChartModel ) ); + if (!aParameter.b3DLook + && aParameter.eThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Realistic) + aParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + fillAllControls( aParameter ); + uno::Reference< beans::XPropertySet > xTemplateProps( static_cast<cppu::OWeakObject*>(getCurrentTemplate().get()), uno::UNO_QUERY ); + m_pCurrentMainType->fillExtraControls(m_xChartModel,xTemplateProps); +} + +void ChartTypeTabPage::showAllControls( ChartTypeDialogController& rTypeController ) +{ + m_xMainTypeList->show(); + m_xSubTypeList->Show(); + + bool bShow = rTypeController.shouldShow_3DLookControl(); + m_pDim3DLookResourceGroup->showControls( bShow ); + bShow = rTypeController.shouldShow_StackingControl(); + m_pStackingResourceGroup->showControls( bShow ); + bShow = rTypeController.shouldShow_SplineControl(); + m_pSplineResourceGroup->showControls( bShow ); + bShow = rTypeController.shouldShow_GeometryControl(); + m_pGeometryResourceGroup->showControls( bShow ); + bShow = rTypeController.shouldShow_SortByXValuesResourceGroup(); + m_pSortByXValuesResourceGroup->showControls( bShow ); + rTypeController.showExtraControls(m_xBuilder.get()); +} + +void ChartTypeTabPage::fillAllControls( const ChartTypeParameter& rParameter, bool bAlsoResetSubTypeList ) +{ + m_nChangingCalls++; + if( m_pCurrentMainType && bAlsoResetSubTypeList ) + { + m_pCurrentMainType->fillSubTypeList(*m_xSubTypeList, rParameter); + } + m_xSubTypeList->SelectItem( static_cast<sal_uInt16>( rParameter.nSubTypeIndex) ); + m_pDim3DLookResourceGroup->fillControls( rParameter ); + m_pStackingResourceGroup->fillControls( rParameter ); + m_pSplineResourceGroup->fillControls( rParameter ); + m_pGeometryResourceGroup->fillControls( rParameter ); + m_pSortByXValuesResourceGroup->fillControls( rParameter ); + m_nChangingCalls--; +} + +void ChartTypeTabPage::initializePage() +{ + if( !m_xChartModel.is() ) + return; + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = m_xChartModel->getTypeManager(); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartModel ); + DiagramHelper::tTemplateWithServiceName aTemplate = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + OUString aServiceName( aTemplate.sServiceName ); + + bool bFound = false; + + sal_uInt16 nM=0; + for (auto const& elem : m_aChartTypeDialogControllerList) + { + if( elem->isSubType(aServiceName) ) + { + bFound = true; + + m_xMainTypeList->select(nM); + showAllControls(*elem); + uno::Reference< beans::XPropertySet > xTemplateProps( static_cast<cppu::OWeakObject*>(aTemplate.xChartTypeTemplate.get()), uno::UNO_QUERY ); + ChartTypeParameter aParameter = elem->getChartTypeParameterForService( aServiceName, xTemplateProps ); + m_pCurrentMainType = getSelectedMainType(); + + //set ThreeDLookScheme + aParameter.eThreeDLookScheme = ThreeDHelper::detectScheme( xDiagram ); + if (!aParameter.b3DLook + && aParameter.eThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Realistic) + aParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + fillAllControls( aParameter ); + if( m_pCurrentMainType ) + m_pCurrentMainType->fillExtraControls(m_xChartModel,xTemplateProps); + break; + } + ++nM; + } + + if( !bFound ) + { + m_xMainTypeList->show(); + m_xSubTypeList->Show(); + m_pDim3DLookResourceGroup->showControls( false ); + m_pStackingResourceGroup->showControls( false ); + m_pSplineResourceGroup->showControls( false ); + m_pGeometryResourceGroup->showControls( false ); + m_pSortByXValuesResourceGroup->showControls( false ); + } +} + +bool ChartTypeTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ ) +{ + return true; // return false if this page should not be left +} + +rtl::Reference< ChartTypeTemplate > ChartTypeTabPage::getCurrentTemplate() const +{ + if( m_pCurrentMainType && m_xChartModel.is() ) + { + ChartTypeParameter aParameter( getCurrentParamter() ); + m_pCurrentMainType->adjustParameterToSubType( aParameter ); + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = m_xChartModel->getTypeManager(); + return m_pCurrentMainType->getCurrentTemplate( aParameter, xChartTypeManager ); + } + return nullptr; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ChartType.hxx b/chart2/source/controller/dialogs/tp_ChartType.hxx new file mode 100644 index 000000000..34ed8abf2 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ChartType.hxx @@ -0,0 +1,94 @@ +/* -*- 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 <vector> + +#include <ChartTypeDialogController.hxx> +#include <ChartTypeTemplateProvider.hxx> +#include <TimerTriggeredControllerLock.hxx> + +#include <vcl/wizardmachine.hxx> + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace weld { class CustomWeld; } + +class ValueSet; + +namespace chart +{ + +class Dim3DLookResourceGroup; +class StackingResourceGroup; +class SplineResourceGroup; +class GeometryResourceGroup; +class SortByXValuesResourceGroup; + +class ChartTypeTabPage final : public ResourceChangeListener, public vcl::OWizardPage, public ChartTypeTemplateProvider +{ +public: + ChartTypeTabPage( weld::Container* pPage, weld::DialogController* pController + , const rtl::Reference<::chart::ChartModel>& xChartModel + , bool bShowDescription = true ); + virtual ~ChartTypeTabPage() override; + + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason eReason ) override; + + virtual rtl::Reference< ::chart::ChartTypeTemplate > getCurrentTemplate() const override; + +private: + ChartTypeDialogController* getSelectedMainType(); + void showAllControls( ChartTypeDialogController& rTypeController ); + void fillAllControls( const ChartTypeParameter& rParameter, bool bAlsoResetSubTypeList=true ); + ChartTypeParameter getCurrentParamter() const; + + virtual void stateChanged() override; + + void commitToModel( const ChartTypeParameter& rParameter ); + void selectMainType(); + + DECL_LINK(SelectMainTypeHdl, weld::TreeView&, void); + DECL_LINK(SelectSubTypeHdl, ValueSet*, void ); + + std::unique_ptr<Dim3DLookResourceGroup> m_pDim3DLookResourceGroup; + std::unique_ptr<StackingResourceGroup> m_pStackingResourceGroup; + std::unique_ptr<SplineResourceGroup> m_pSplineResourceGroup; + std::unique_ptr<GeometryResourceGroup> m_pGeometryResourceGroup; + std::unique_ptr<SortByXValuesResourceGroup> m_pSortByXValuesResourceGroup; + + rtl::Reference<::chart::ChartModel> m_xChartModel; + + std::vector< std::unique_ptr<ChartTypeDialogController> > m_aChartTypeDialogControllerList; + ChartTypeDialogController* m_pCurrentMainType; + + sal_Int32 m_nChangingCalls; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + std::unique_ptr<weld::Label> m_xFT_ChooseType; + std::unique_ptr<weld::TreeView> m_xMainTypeList; + std::unique_ptr<ValueSet> m_xSubTypeList; + std::unique_ptr<weld::CustomWeld> m_xSubTypeListWin; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataLabel.cxx b/chart2/source/controller/dialogs/tp_DataLabel.cxx new file mode 100644 index 000000000..3594e3e8f --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataLabel.cxx @@ -0,0 +1,54 @@ +/* -*- 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 "tp_DataLabel.hxx" + +namespace chart +{ + +DataLabelsTabPage::DataLabelsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_DataLabel.ui", "tp_DataLabel", &rInAttrs) + , m_aDataLabelResources(m_xBuilder.get(), pController->getDialog(), rInAttrs) +{ +} + +std::unique_ptr<SfxTabPage> DataLabelsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique<DataLabelsTabPage>(pPage, pController, *rOutAttrs); +} + +bool DataLabelsTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + m_aDataLabelResources.FillItemSet(rOutAttrs); + return true; +} + +void DataLabelsTabPage::Reset(const SfxItemSet* rInAttrs) +{ + m_aDataLabelResources.Reset(*rInAttrs); +} + +void DataLabelsTabPage::SetNumberFormatter( SvNumberFormatter* pFormatter ) +{ + m_aDataLabelResources.SetNumberFormatter( pFormatter ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataLabel.hxx b/chart2/source/controller/dialogs/tp_DataLabel.hxx new file mode 100644 index 000000000..200063af9 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataLabel.hxx @@ -0,0 +1,48 @@ +/* -*- 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 "res_DataLabel.hxx" +#include <sfx2/tabdlg.hxx> + +class SvNumberFormatter; + +namespace chart +{ +class DataLabelsTabPage : public SfxTabPage +{ +public: + DataLabelsTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + + void SetNumberFormatter(SvNumberFormatter* pFormatter); + + virtual void Reset(const SfxItemSet* rInAttrs) override; + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + +private: + DataLabelResources m_aDataLabelResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataPointOption.cxx b/chart2/source/controller/dialogs/tp_DataPointOption.cxx new file mode 100644 index 000000000..4c8242872 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataPointOption.cxx @@ -0,0 +1,66 @@ +/* -*- 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 "tp_DataPointOption.hxx" + +#include <chartview/ChartSfxItemIds.hxx> +#include <svl/eitem.hxx> + +namespace chart +{ +DataPointOptionTabPage::DataPointOptionTabPage(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_DataPointOption.ui", + "tp_DataPointOption", &rInAttrs) + , m_xCBHideLegendEntry(m_xBuilder->weld_check_button("CB_LEGEND_ENTRY_HIDDEN")) +{ +} + +DataPointOptionTabPage::~DataPointOptionTabPage() {} + +std::unique_ptr<SfxTabPage> DataPointOptionTabPage::Create(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet* rOutAttrs) +{ + return std::make_unique<DataPointOptionTabPage>(pPage, pController, *rOutAttrs); +} + +bool DataPointOptionTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + if (m_xCBHideLegendEntry->get_visible()) + rOutAttrs->Put( + SfxBoolItem(SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, m_xCBHideLegendEntry->get_active())); + + return true; +} + +void DataPointOptionTabPage::Reset(const SfxItemSet* rInAttrs) +{ + if (const SfxBoolItem* pEntryItem + = rInAttrs->GetItemIfSet(SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY)) + { + bool bVal = pEntryItem->GetValue(); + m_xCBHideLegendEntry->set_active(bVal); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataPointOption.hxx b/chart2/source/controller/dialogs/tp_DataPointOption.hxx new file mode 100644 index 000000000..b73a8a609 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataPointOption.hxx @@ -0,0 +1,48 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +namespace weld +{ +class CheckButton; +} + +namespace chart +{ +class DataPointOptionTabPage : public SfxTabPage +{ +public: + DataPointOptionTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + virtual ~DataPointOptionTabPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + +private: + std::unique_ptr<weld::CheckButton> m_xCBHideLegendEntry; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataSource.cxx b/chart2/source/controller/dialogs/tp_DataSource.cxx new file mode 100644 index 000000000..b142825b3 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataSource.cxx @@ -0,0 +1,926 @@ +/* -*- 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 "tp_DataSource.hxx" +#include <strings.hrc> +#include <ResId.hxx> +#include <ChartType.hxx> +#include <ChartTypeTemplateProvider.hxx> +#include <ChartTypeTemplate.hxx> +#include <ChartModel.hxx> +#include <RangeSelectionHelper.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <DataSourceHelper.hxx> +#include <LabeledDataSequence.hxx> +#include "DialogModel.hxx" +#include <o3tl/safeint.hxx> +#include <TabPageNotifiable.hxx> +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <com/sun/star/chart2/data/XDataProvider.hpp> + +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +constexpr OUStringLiteral lcl_aLabelRole( u"label" ); + +void lcl_UpdateCurrentRange(weld::TreeView& rOutListBox, const OUString & rRole, + const OUString& rRange) +{ + int nEntry = rOutListBox.get_selected_index(); + if (nEntry != -1) + { + rOutListBox.set_text(nEntry, ::chart::DialogModel::ConvertRoleFromInternalToUI(rRole), 0); + rOutListBox.set_text(nEntry, rRange, 1); + ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(rOutListBox.get_id(nEntry)); + pEntry->m_sRole = rRole; + } +} + +bool lcl_UpdateCurrentSeriesName(weld::TreeView& rOutListBox) +{ + int nEntry = rOutListBox.get_selected_index(); + if (nEntry == -1) + return false; + + bool bResult = false; + ::chart::SeriesEntry * pEntry = weld::fromId<::chart::SeriesEntry*>(rOutListBox.get_id(nEntry)); + if (pEntry->m_xDataSeries.is() && pEntry->m_xChartType.is()) + { + OUString aLabel(::chart::DataSeriesHelper::getDataSeriesLabel( + pEntry->m_xDataSeries, + pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel())); + if (!aLabel.isEmpty()) + { + rOutListBox.set_text(nEntry, aLabel); + bResult = true; + } + } + return bResult; +} + +OUString lcl_GetSelectedRole(const weld::TreeView& rRoleListBox, bool bUITranslated = false) +{ + int nEntry = rRoleListBox.get_selected_index(); + if (nEntry != -1) + { + if (bUITranslated) + return rRoleListBox.get_text(nEntry); + ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(rRoleListBox.get_id(nEntry)); + return pEntry->m_sRole; + } + return OUString(); +} + +OUString lcl_GetSelectedRolesRange( const weld::TreeView& rRoleListBox ) +{ + OUString aResult; + int nEntry = rRoleListBox.get_selected_index(); + if (nEntry != -1) + aResult = rRoleListBox.get_text(nEntry, 1); + return aResult; +} + +OUString lcl_GetSequenceNameForLabel(const ::chart::SeriesEntry* pEntry) +{ + OUString aResult("values-y"); + if (pEntry && pEntry->m_xChartType.is()) + aResult = pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel(); + return aResult; +} + +void lcl_enableRangeChoosing(bool bEnable, weld::DialogController* pDialog) +{ + if (!pDialog) + return; + weld::Dialog* pDlg = pDialog->getDialog(); + pDlg->set_modal(!bEnable); + pDlg->set_visible(!bEnable); +} + +void lcl_addLSequenceToDataSource( + const uno::Reference< chart2::data::XLabeledDataSequence > & xLSequence, + const Reference< ::chart::DataSeries > & xSource ) +{ + if( xSource.is()) + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = xSource->getDataSequences2(); + aData.push_back( xLSequence ); + xSource->setData( aData ); + } +} + +uno::Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel( + const rtl::Reference< ::chart::DataSeries > & xDataSource ) +{ + uno::Reference< chart2::data::XLabeledDataSequence > xResult; + + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledDataSeq : xDataSource->getDataSequences2() ) + { + // no values are set but a label exists + if( ! labeledDataSeq->getValues().is() && + labeledDataSeq->getLabel().is()) + { + xResult = labeledDataSeq; + break; + } + } + + return xResult; +} + +} // anonymous namespace + +namespace chart +{ + +DataSourceTabPage::DataSourceTabPage(weld::Container* pPage, weld::DialogController* pController, + DialogModel & rDialogModel, + ChartTypeTemplateProvider* pTemplateProvider, + bool bHideDescription /* = false */) + : ::vcl::OWizardPage(pPage, pController, "modules/schart/ui/tp_DataSource.ui", "tp_DataSource") + , m_pTemplateProvider(pTemplateProvider) + , m_rDialogModel(rDialogModel) + , m_pCurrentRangeChoosingField( nullptr ) + , m_bIsDirty( false ) + , m_pTabPageNotifiable(dynamic_cast<TabPageNotifiable*>(pController)) + , m_xFT_CAPTION(m_xBuilder->weld_label("FT_CAPTION_FOR_WIZARD")) + , m_xFT_SERIES(m_xBuilder->weld_label("FT_SERIES")) + , m_xLB_SERIES(m_xBuilder->weld_tree_view("LB_SERIES")) + , m_xBTN_ADD(m_xBuilder->weld_button("BTN_ADD")) + , m_xBTN_REMOVE(m_xBuilder->weld_button("BTN_REMOVE")) + , m_xBTN_UP(m_xBuilder->weld_button("BTN_UP")) + , m_xBTN_DOWN(m_xBuilder->weld_button("BTN_DOWN")) + , m_xFT_ROLE(m_xBuilder->weld_label("FT_ROLE")) + , m_xLB_ROLE(m_xBuilder->weld_tree_view("LB_ROLE")) + , m_xFT_RANGE(m_xBuilder->weld_label("FT_RANGE")) + , m_xEDT_RANGE(m_xBuilder->weld_entry("EDT_RANGE")) + , m_xIMB_RANGE_MAIN(m_xBuilder->weld_button("IMB_RANGE_MAIN")) + , m_xFT_CATEGORIES(m_xBuilder->weld_label("FT_CATEGORIES")) + , m_xFT_DATALABELS(m_xBuilder->weld_label("FT_DATALABELS")) + , m_xEDT_CATEGORIES(m_xBuilder->weld_entry("EDT_CATEGORIES")) + , m_xIMB_RANGE_CAT(m_xBuilder->weld_button("IMB_RANGE_CAT")) +{ + m_xLB_SERIES->set_size_request(m_xLB_SERIES->get_approximate_digit_width() * 25, + m_xLB_SERIES->get_height_rows(10)); + m_xLB_ROLE->set_size_request(m_xLB_ROLE->get_approximate_digit_width() * 60, + m_xLB_ROLE->get_height_rows(5)); + m_xFT_CAPTION->set_visible(!bHideDescription); + + m_aFixedTextRange = m_xFT_RANGE->get_label(); + SetPageTitle(SchResId(STR_OBJECT_DATASERIES_PLURAL)); + + // set handlers + m_xLB_SERIES->connect_changed(LINK(this, DataSourceTabPage, SeriesSelectionChangedHdl)); + m_xLB_ROLE->connect_changed(LINK(this, DataSourceTabPage, RoleSelectionChangedHdl)); + + m_xIMB_RANGE_MAIN->connect_clicked(LINK(this, DataSourceTabPage, MainRangeButtonClickedHdl)); + m_xIMB_RANGE_CAT->connect_clicked(LINK(this, DataSourceTabPage, CategoriesRangeButtonClickedHdl)); + + m_xBTN_ADD->connect_clicked(LINK(this, DataSourceTabPage, AddButtonClickedHdl)); + m_xBTN_REMOVE->connect_clicked(LINK(this, DataSourceTabPage, RemoveButtonClickedHdl)); + + m_xBTN_UP->connect_clicked(LINK(this, DataSourceTabPage, UpButtonClickedHdl)); + m_xBTN_DOWN->connect_clicked(LINK(this, DataSourceTabPage, DownButtonClickedHdl)); + + m_xEDT_RANGE->connect_changed(LINK(this, DataSourceTabPage, RangeModifiedHdl)); + m_xEDT_CATEGORIES->connect_changed(LINK( this, DataSourceTabPage, RangeModifiedHdl)); + + // init controls + std::vector<int> aWidths { o3tl::narrowing<int>(m_xLB_ROLE->get_approximate_digit_width() * 20) }; + m_xLB_ROLE->set_column_fixed_widths(aWidths); + m_xLB_ROLE->show(); + + updateControlsFromDialogModel(); + + // select first series + if (m_xLB_SERIES->n_children()) + m_xLB_SERIES->select(0); +} + +void DataSourceTabPage::InsertRoleLBEntry(const OUString& rRole, const OUString& rRange) +{ + m_aEntries.emplace_back(new SeriesEntry); + SeriesEntry* pEntry = m_aEntries.back().get(); + pEntry->m_sRole = rRole; + m_xLB_ROLE->append(weld::toId(pEntry), + ::chart::DialogModel::ConvertRoleFromInternalToUI(rRole)); + m_xLB_ROLE->set_text(m_xLB_ROLE->n_children() - 1, rRange, 1); +} + +DataSourceTabPage::~DataSourceTabPage() +{ +} + +void DataSourceTabPage::Activate() +{ + OWizardPage::Activate(); + updateControlsFromDialogModel(); + m_xLB_SERIES->grab_focus(); +} + +void DataSourceTabPage::initializePage() +{ +} + +void DataSourceTabPage::Deactivate() +{ + commitPage(); + vcl::OWizardPage::Deactivate(); +} + +void DataSourceTabPage::commitPage() +{ + commitPage(::vcl::WizardTypes::eFinish); +} + +bool DataSourceTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ ) +{ + //ranges may have been edited in the meanwhile (dirty is true in that case here) + if( isValid() ) + { + updateModelFromControl(); + return true; //return false if this page should not be left + } + else + return false; +} + +bool DataSourceTabPage::isRangeFieldContentValid(weld::Entry& rEdit ) +{ + OUString aRange(rEdit.get_text()); + bool bIsValid = aRange.isEmpty() || + m_rDialogModel.getRangeSelectionHelper()->verifyCellRange(aRange); + rEdit.set_message_type(bIsValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error); + return bIsValid; +} + +bool DataSourceTabPage::isValid() +{ + bool bRoleRangeValid = true; + bool bCategoriesRangeValid = true; + bool bHasSelectedEntry = (m_xLB_SERIES->get_selected_index() != -1); + + if (bHasSelectedEntry) + bRoleRangeValid = isRangeFieldContentValid(*m_xEDT_RANGE); + if (m_xEDT_CATEGORIES->get_sensitive()) + bCategoriesRangeValid = isRangeFieldContentValid( *m_xEDT_CATEGORIES ); + bool bValid = ( bRoleRangeValid && bCategoriesRangeValid ); + + if( m_pTabPageNotifiable ) + { + if( bValid ) + m_pTabPageNotifiable->setValidPage( this ); + else + m_pTabPageNotifiable->setInvalidPage( this ); + } + + return bValid; +} + +void DataSourceTabPage::setDirty() +{ + m_bIsDirty = true; +} + +void DataSourceTabPage::updateControlsFromDialogModel() +{ + // series + fillSeriesListBox(); + SeriesSelectionChangedHdl(*m_xLB_SERIES); + + // categories + m_xEDT_CATEGORIES->set_text(m_rDialogModel.getCategoriesRange()); + + updateControlState(); +} + +void DataSourceTabPage::fillSeriesListBox() +{ + rtl::Reference< DataSeries > xSelected; + SeriesEntry* pEntry = nullptr; + int nEntry = m_xLB_SERIES->get_selected_index(); + if (nEntry != -1) + { + pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry)); + xSelected = pEntry->m_xDataSeries; + } + + bool bHasSelectedEntry = (pEntry != nullptr); + int nSelectedEntry = -1; + + m_xLB_SERIES->freeze(); + m_xLB_SERIES->clear(); + + std::vector< DialogModel::tSeriesWithChartTypeByName > aSeries( + m_rDialogModel.getAllDataSeriesWithLabel() ); + + sal_Int32 nUnnamedSeriesIndex = 1; + nEntry = 0; + for (auto const& series : aSeries) + { + OUString aLabel(series.first); + if (aLabel.isEmpty()) + { + if( nUnnamedSeriesIndex > 1 ) + { + OUString aResString(::chart::SchResId( STR_DATA_UNNAMED_SERIES_WITH_INDEX )); + + // replace index of unnamed series + static const OUStringLiteral aReplacementStr( u"%NUMBER" ); + sal_Int32 nIndex = aResString.indexOf( aReplacementStr ); + if( nIndex != -1 ) + aLabel = aResString.replaceAt( + nIndex, aReplacementStr.getLength(), + OUString::number(nUnnamedSeriesIndex)); + } + if( aLabel.isEmpty() ) + aLabel = ::chart::SchResId( STR_DATA_UNNAMED_SERIES ); + + ++nUnnamedSeriesIndex; + } + + m_aEntries.emplace_back(new SeriesEntry); + pEntry = m_aEntries.back().get(); + pEntry->m_xDataSeries = series.second.first; + pEntry->m_xChartType = series.second.second; + m_xLB_SERIES->append(weld::toId(pEntry), aLabel); + if (bHasSelectedEntry && series.second.first == xSelected) + nSelectedEntry = nEntry; + ++nEntry; + } + + m_xLB_SERIES->thaw(); + + if (bHasSelectedEntry && nSelectedEntry != -1) + m_xLB_SERIES->select(nSelectedEntry); +} + +void DataSourceTabPage::fillRoleListBox() +{ + int nSeriesEntry = m_xLB_SERIES->get_selected_index(); + SeriesEntry* pSeriesEntry = nullptr; + if (nSeriesEntry != -1) + pSeriesEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nSeriesEntry)); + bool bHasSelectedEntry = (pSeriesEntry != nullptr); + + int nRoleIndex = m_xLB_ROLE->get_selected_index(); + if (!bHasSelectedEntry) + return; + + DialogModel::tRolesWithRanges aRoles( + DialogModel::getRolesWithRanges( + pSeriesEntry->m_xDataSeries, + lcl_GetSequenceNameForLabel( pSeriesEntry ), + pSeriesEntry->m_xChartType )); + + // fill role list + m_xLB_ROLE->freeze(); + m_xLB_ROLE->clear(); + + for (auto const& elemRole : aRoles) + { + InsertRoleLBEntry(elemRole.first, elemRole.second); + } + + m_xLB_ROLE->thaw(); + + // series may contain no roles, check listbox size before selecting entries + if (m_xLB_ROLE->n_children() > 0) + { + if (nRoleIndex == -1 || nRoleIndex >= m_xLB_ROLE->n_children()) + nRoleIndex = 0; + m_xLB_ROLE->select(nRoleIndex); + } +} + +void DataSourceTabPage::updateControlState() +{ + int nSeriesEntry = m_xLB_SERIES->get_selected_index(); + bool bHasSelectedSeries = nSeriesEntry != -1; + bool bHasValidRole = false; + bool bHasRangeChooser = m_rDialogModel.getRangeSelectionHelper()->hasRangeSelection(); + + if( bHasSelectedSeries ) + { + int nRoleEntry = m_xLB_ROLE->get_selected_index(); + bHasValidRole = nRoleEntry != -1; + } + + m_xBTN_ADD->set_sensitive(true); + m_xBTN_REMOVE->set_sensitive(bHasSelectedSeries); + + m_xBTN_UP->set_sensitive(bHasSelectedSeries && (nSeriesEntry != 0)); + m_xBTN_DOWN->set_sensitive(bHasSelectedSeries && (nSeriesEntry != m_xLB_SERIES->n_children() - 1)); + + bool bHasCategories = m_rDialogModel.isCategoryDiagram(); + + m_xFT_DATALABELS->set_visible(!bHasCategories); + m_xFT_CATEGORIES->set_visible( bHasCategories); + bool bShowIB = bHasRangeChooser; + + m_xIMB_RANGE_CAT->set_visible(bShowIB); + + m_xFT_ROLE->set_sensitive(bHasSelectedSeries); + m_xLB_ROLE->set_sensitive(bHasSelectedSeries); + + m_xFT_RANGE->set_sensitive(bHasValidRole); + m_xEDT_RANGE->set_sensitive(bHasValidRole); + + m_xFT_SERIES->set_sensitive(true); + m_xLB_SERIES->set_sensitive(true); + + m_xIMB_RANGE_MAIN->set_visible(bShowIB); + + isValid(); +} + +IMPL_LINK_NOARG(DataSourceTabPage, SeriesSelectionChangedHdl, weld::TreeView&, void) +{ + m_rDialogModel.startControllerLockTimer(); + if (m_xLB_SERIES->get_selected_index() != -1) + { + fillRoleListBox(); + RoleSelectionChangedHdl(*m_xLB_ROLE); + } + updateControlState(); +} + +IMPL_LINK_NOARG(DataSourceTabPage, RoleSelectionChangedHdl, weld::TreeView&, void) +{ + m_rDialogModel.startControllerLockTimer(); + int nEntry = m_xLB_ROLE->get_selected_index(); + if (nEntry == -1) + return; + + OUString aSelectedRoleUI = lcl_GetSelectedRole( *m_xLB_ROLE, true ); + OUString aSelectedRange = lcl_GetSelectedRolesRange( *m_xLB_ROLE ); + + // replace role in fixed text label + static const OUStringLiteral aReplacementStr( u"%VALUETYPE" ); + sal_Int32 nIndex = m_aFixedTextRange.indexOf( aReplacementStr ); + if( nIndex != -1 ) + { + m_xFT_RANGE->set_label( + m_aFixedTextRange.replaceAt( + nIndex, aReplacementStr.getLength(), aSelectedRoleUI )); + } + + m_xEDT_RANGE->set_text(aSelectedRange); + isValid(); +} + +IMPL_LINK_NOARG(DataSourceTabPage, MainRangeButtonClickedHdl, weld::Button&, void) +{ + OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr ); + m_pCurrentRangeChoosingField = m_xEDT_RANGE.get(); + if (!m_xEDT_RANGE->get_text().isEmpty() && + !updateModelFromControl( m_pCurrentRangeChoosingField)) + return; + + int nEntry = m_xLB_SERIES->get_selected_index(); + bool bHasSelectedEntry = (nEntry != -1); + + OUString aSelectedRolesRange = lcl_GetSelectedRolesRange(*m_xLB_ROLE); + + if (bHasSelectedEntry && (m_xLB_ROLE->get_selected_index() != -1)) + { + OUString aUIStr(SchResId(STR_DATA_SELECT_RANGE_FOR_SERIES)); + + // replace role + OUString aReplacement( "%VALUETYPE" ); + sal_Int32 nIndex = aUIStr.indexOf( aReplacement ); + if( nIndex != -1 ) + { + aUIStr = aUIStr.replaceAt( nIndex, aReplacement.getLength(), + lcl_GetSelectedRole( *m_xLB_ROLE, true )); + } + // replace series name + aReplacement = "%SERIESNAME"; + nIndex = aUIStr.indexOf( aReplacement ); + if( nIndex != -1 ) + { + aUIStr = aUIStr.replaceAt(nIndex, aReplacement.getLength(), + m_xLB_SERIES->get_text(nEntry)); + } + + lcl_enableRangeChoosing(true, m_pDialogController); + m_rDialogModel.getRangeSelectionHelper()->chooseRange( aSelectedRolesRange, aUIStr, *this ); + } + else + m_pCurrentRangeChoosingField = nullptr; +} + +IMPL_LINK_NOARG(DataSourceTabPage, CategoriesRangeButtonClickedHdl, weld::Button&, void) +{ + OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr ); + m_pCurrentRangeChoosingField = m_xEDT_CATEGORIES.get(); + if( !m_xEDT_CATEGORIES->get_text().isEmpty() && + ! updateModelFromControl( m_pCurrentRangeChoosingField )) + return; + + OUString aStr(SchResId(m_xFT_CATEGORIES->get_visible() ? STR_DATA_SELECT_RANGE_FOR_CATEGORIES : STR_DATA_SELECT_RANGE_FOR_DATALABELS)); + lcl_enableRangeChoosing(true, m_pDialogController); + m_rDialogModel.getRangeSelectionHelper()->chooseRange( + m_rDialogModel.getCategoriesRange(), aStr, *this ); +} + +IMPL_LINK_NOARG(DataSourceTabPage, AddButtonClickedHdl, weld::Button&, void) +{ + m_rDialogModel.startControllerLockTimer(); + int nEntry = m_xLB_SERIES->get_selected_index(); + rtl::Reference< DataSeries > xSeriesToInsertAfter; + rtl::Reference< ChartType > xChartTypeForNewSeries; + if( m_pTemplateProvider ) + m_rDialogModel.setTemplate( m_pTemplateProvider->getCurrentTemplate()); + + if (nEntry != -1) + { + ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry)); + xSeriesToInsertAfter = pEntry->m_xDataSeries; + xChartTypeForNewSeries = pEntry->m_xChartType; + } + else + { + std::vector< rtl::Reference< ChartType > > aCntVec( + m_rDialogModel.getAllDataSeriesContainers()); + if( ! aCntVec.empty()) + xChartTypeForNewSeries = aCntVec.front(); + } + OSL_ENSURE( xChartTypeForNewSeries.is(), "Cannot insert new series" ); + + m_rDialogModel.insertSeriesAfter( xSeriesToInsertAfter, xChartTypeForNewSeries ); + setDirty(); + + fillSeriesListBox(); + // note the box was cleared and refilled, so nEntry is invalid now + + int nSelEntry = m_xLB_SERIES->get_selected_index(); + if (nSelEntry != -1) + { + ++nSelEntry; + if (nSelEntry < m_xLB_SERIES->n_children()) + m_xLB_SERIES->select(nSelEntry); + } + SeriesSelectionChangedHdl(*m_xLB_SERIES); +} + +IMPL_LINK_NOARG(DataSourceTabPage, RemoveButtonClickedHdl, weld::Button&, void) +{ + m_rDialogModel.startControllerLockTimer(); + int nEntry = m_xLB_SERIES->get_selected_index(); + if (nEntry == -1) + return; + + SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry)); + rtl::Reference< DataSeries > xNewSelSeries; + SeriesEntry * pNewSelEntry = nullptr; + if (nEntry + 1 < m_xLB_SERIES->n_children()) + pNewSelEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry + 1)); + else if (nEntry > 0) + pNewSelEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry - 1)); + if (pNewSelEntry) + xNewSelSeries = pNewSelEntry->m_xDataSeries; + + m_rDialogModel.deleteSeries( pEntry->m_xDataSeries, pEntry->m_xChartType ); + setDirty(); + + m_xLB_SERIES->remove(nEntry); + fillSeriesListBox(); + + // select previous or next series + if (xNewSelSeries.is()) + { + for (int i = 0; i < m_xLB_SERIES->n_children(); ++i) + { + pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(i)); + if (pEntry->m_xDataSeries == xNewSelSeries) + { + m_xLB_SERIES->select(i); + break; + } + } + } + SeriesSelectionChangedHdl(*m_xLB_SERIES); +} + +IMPL_LINK_NOARG(DataSourceTabPage, UpButtonClickedHdl, weld::Button&, void) +{ + m_rDialogModel.startControllerLockTimer(); + + int nEntry = m_xLB_SERIES->get_selected_index(); + SeriesEntry* pEntry = nullptr; + if (nEntry != -1) + pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry)); + + bool bHasSelectedEntry = (pEntry != nullptr); + + if (bHasSelectedEntry) + { + m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MoveDirection::Up ); + setDirty(); + fillSeriesListBox(); + SeriesSelectionChangedHdl(*m_xLB_SERIES); + } +} + +IMPL_LINK_NOARG(DataSourceTabPage, DownButtonClickedHdl, weld::Button&, void) +{ + m_rDialogModel.startControllerLockTimer(); + + int nEntry = m_xLB_SERIES->get_selected_index(); + SeriesEntry* pEntry = nullptr; + if (nEntry != -1) + pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry)); + + bool bHasSelectedEntry = (pEntry != nullptr); + + if (bHasSelectedEntry) + { + m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MoveDirection::Down ); + setDirty(); + fillSeriesListBox(); + SeriesSelectionChangedHdl(*m_xLB_SERIES); + } +} + +IMPL_LINK(DataSourceTabPage, RangeModifiedHdl, weld::Entry&, rEdit, void) +{ + // note: isValid sets the color of the edit field + if( isRangeFieldContentValid( rEdit )) + { + setDirty(); + updateModelFromControl( &rEdit ); + if (&rEdit == m_xEDT_RANGE.get()) + { + if( ! lcl_UpdateCurrentSeriesName( *m_xLB_SERIES )) + fillSeriesListBox(); + } + } + + // enable/disable OK button + isValid(); +} + +void DataSourceTabPage::listeningFinished( + const OUString & rNewRange ) +{ + // rNewRange becomes invalid after removing the listener + OUString aRange( rNewRange ); + + m_rDialogModel.startControllerLockTimer(); + + // stop listening + m_rDialogModel.getRangeSelectionHelper()->stopRangeListening(); + + // change edit field + if( m_pCurrentRangeChoosingField ) + { + m_pCurrentRangeChoosingField->set_text(aRange); + m_pCurrentRangeChoosingField->grab_focus(); + } + + if (m_pCurrentRangeChoosingField == m_xEDT_RANGE.get()) + { + m_xEDT_RANGE->set_text(aRange); + setDirty(); + } + else if (m_pCurrentRangeChoosingField == m_xEDT_CATEGORIES.get()) + { + m_xEDT_CATEGORIES->set_text(aRange); + setDirty(); + } + + updateModelFromControl(m_pCurrentRangeChoosingField); + if (!lcl_UpdateCurrentSeriesName(*m_xLB_SERIES)) + fillSeriesListBox(); + + m_pCurrentRangeChoosingField = nullptr; + + updateControlState(); + lcl_enableRangeChoosing(false, m_pDialogController); +} + +void DataSourceTabPage::disposingRangeSelection() +{ + m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false ); +} + +bool DataSourceTabPage::updateModelFromControl(const weld::Entry* pField) +{ + if (!m_bIsDirty) + return true; + + ControllerLockGuardUNO aLockedControllers( m_rDialogModel.getChartModel() ); + + // @todo: validity check of field content + bool bResult = true; + bool bAll = (pField == nullptr); + Reference< data::XDataProvider > xDataProvider( m_rDialogModel.getDataProvider()); + + if (bAll || (pField == m_xEDT_CATEGORIES.get())) + { + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( m_rDialogModel.getCategories() ); + if( xDataProvider.is()) + { + OUString aRange(m_xEDT_CATEGORIES->get_text()); + if (!aRange.isEmpty()) + { + // create or change categories + if( !xLabeledSeq.is()) + { + xLabeledSeq = DataSourceHelper::createLabeledDataSequence(); + m_rDialogModel.setCategories( xLabeledSeq ); + } + try + { + xLabeledSeq->setValues( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); + } + catch( const uno::Exception & ) + { + // should work as validation should have happened before + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else if( xLabeledSeq.is()) + { + // clear existing categories + xLabeledSeq.set(nullptr); + m_rDialogModel.setCategories( xLabeledSeq ); + } + } + } + + int nSeriesEntry = m_xLB_SERIES->get_selected_index(); + SeriesEntry* pSeriesEntry = nullptr; + if (nSeriesEntry != -1) + pSeriesEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nSeriesEntry)); + bool bHasSelectedEntry = (pSeriesEntry != nullptr); + + if( bHasSelectedEntry ) + { + if( bAll || (pField == m_xEDT_RANGE.get()) ) + { + try + { + OUString aSelectedRole = lcl_GetSelectedRole( *m_xLB_ROLE ); + OUString aRange(m_xEDT_RANGE->get_text()); + OUString aSequenceRole( aSelectedRole ); + bool bIsLabel = (aSequenceRole == lcl_aLabelRole ); + OUString aSequenceNameForLabel( lcl_GetSequenceNameForLabel( pSeriesEntry )); + + if( bIsLabel ) + aSequenceRole = aSequenceNameForLabel; + + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq = + DataSeriesHelper::getDataSequenceByRole( pSeriesEntry->m_xDataSeries, aSequenceRole ); + + if( xDataProvider.is()) + { + if( bIsLabel ) + { + if( ! xLabeledSeq.is()) + { + // check if there is already an "orphan" label sequence + xLabeledSeq = lcl_findLSequenceWithOnlyLabel( pSeriesEntry->m_xDataSeries ); + if( ! xLabeledSeq.is()) + { + // no corresponding labeled data sequence for label found + xLabeledSeq = DataSourceHelper::createLabeledDataSequence(); + lcl_addLSequenceToDataSource( xLabeledSeq, pSeriesEntry->m_xDataSeries ); + } + } + if( xLabeledSeq.is()) + { + if( !aRange.isEmpty()) + { + Reference< data::XDataSequence > xNewSeq; + try + { + xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); + } + catch( const uno::Exception & ) + { + // should work as validation should have happened before + DBG_UNHANDLED_EXCEPTION("chart2"); + } + if( xNewSeq.is()) + { + // update range name by the full string provided + // by the data provider. E.g. "a1" might become + // "$Sheet1.$A$1" + aRange = xNewSeq->getSourceRangeRepresentation(); + Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW ); + xProp->setPropertyValue( "Role" , uno::Any( OUString(lcl_aLabelRole) )); + + //Labels should always include hidden cells, regardless of the setting chosen + xProp->setPropertyValue( "IncludeHiddenCells", uno::Any(true)); + xLabeledSeq->setLabel( xNewSeq ); + } + } + else + { + xLabeledSeq->setLabel( Reference< data::XDataSequence >()); + } + } + } + else + { + if( !aRange.isEmpty()) + { + Reference< data::XDataSequence > xNewSeq; + try + { + xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); + } + catch( const uno::Exception & ) + { + // should work as validation should have happened before + DBG_UNHANDLED_EXCEPTION("chart2"); + } + if( xNewSeq.is()) + { + // update range name by the full string provided + // by the data provider. E.g. "a1:e1" might become + // "$Sheet1.$A$1:$E$1" + aRange = xNewSeq->getSourceRangeRepresentation(); + + Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW ); + xProp->setPropertyValue( "Role" , uno::Any( aSelectedRole )); + if( !xLabeledSeq.is()) + { + if( aSelectedRole == aSequenceNameForLabel ) + xLabeledSeq = lcl_findLSequenceWithOnlyLabel( pSeriesEntry->m_xDataSeries ); + if( ! xLabeledSeq.is()) + { + xLabeledSeq = DataSourceHelper::createLabeledDataSequence(); + lcl_addLSequenceToDataSource( xLabeledSeq, pSeriesEntry->m_xDataSeries ); + } + } + xLabeledSeq->setValues( xNewSeq ); + } + } + } + } + + lcl_UpdateCurrentRange( *m_xLB_ROLE, aSelectedRole, aRange ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + bResult = false; + } + } + } + + // update View + // @todo remove this when automatic view updates from calc, writer and own data sequences are available + if( bResult ) + { + try + { + if( m_rDialogModel.getChartModel() ) + m_rDialogModel.getChartModel()->setModified( true ); + const DialogModelTimeBasedInfo& rInfo = m_rDialogModel.getTimeBasedInfo(); + if(rInfo.bTimeBased) + { + m_rDialogModel.setTimeBasedRange(rInfo.bTimeBased, rInfo.nStart, rInfo.nEnd); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return bResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataSource.hxx b/chart2/source/controller/dialogs/tp_DataSource.hxx new file mode 100644 index 000000000..40219d917 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataSource.hxx @@ -0,0 +1,149 @@ +/* -*- 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 <DataSeries.hxx> +#include <ChartType.hxx> + +#include <vcl/wizardmachine.hxx> + +#include <RangeSelectionListener.hxx> + +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XDataSeries; } + +namespace chart { class TabPageNotifiable; } + +namespace chart +{ +class ChartType; +class ChartTypeTemplateProvider; +class DataSeries; +class DialogModel; + +class SeriesEntry +{ +public: + OUString m_sRole; + + /// the corresponding data series + rtl::Reference< ::chart::DataSeries > m_xDataSeries; + + /// the chart type that contains the series (via XDataSeriesContainer) + rtl::Reference< ::chart::ChartType > m_xChartType; +}; + +class DataSourceTabPage final : + public ::vcl::OWizardPage, + public RangeSelectionListenerParent +{ +public: + explicit DataSourceTabPage(weld::Container* pPage, weld::DialogController* pController, + DialogModel & rDialogModel, + ChartTypeTemplateProvider* pTemplateProvider, + bool bHideDescription = false); + virtual ~DataSourceTabPage() override; + + virtual void Activate() override; + + void commitPage(); + +private: + // OWizardPage + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason eReason ) override; + + //TabPage + virtual void Deactivate() override; + + virtual void initializePage() override; + + DECL_LINK( SeriesSelectionChangedHdl, weld::TreeView&, void ); + DECL_LINK( RoleSelectionChangedHdl, weld::TreeView&, void ); + DECL_LINK( MainRangeButtonClickedHdl, weld::Button&, void ); + DECL_LINK( CategoriesRangeButtonClickedHdl, weld::Button&, void ); + DECL_LINK( AddButtonClickedHdl, weld::Button&, void ); + DECL_LINK( RemoveButtonClickedHdl, weld::Button&, void ); + DECL_LINK( RangeModifiedHdl, weld::Entry&, void ); + DECL_LINK( UpButtonClickedHdl, weld::Button&, void ); + DECL_LINK( DownButtonClickedHdl, weld::Button&, void ); + + // ____ RangeSelectionListenerParent ____ + virtual void listeningFinished( const OUString & rNewRange ) override; + virtual void disposingRangeSelection() override; + + void InsertRoleLBEntry(const OUString& rRole, const OUString& rRange); + + void updateControlState(); + + /** updates the internal data according to the content of the given edit + field. If pField is 0, all relevant fields are used + + @return + <TRUE/> if the text from the field is a valid format to the internal + data was valid + */ + bool updateModelFromControl(const weld::Entry* pField = nullptr); + + /** @return </sal_True>, if the edit field contains a valid range entry. If no + XCellRangesAccess can be obtained, </sal_False> is returned. + */ + bool isRangeFieldContentValid(weld::Entry& rEdit); + + /** @return </sal_True>, if the tab-page is in a consistent (committable) state + */ + bool isValid(); + void setDirty(); + + void updateControlsFromDialogModel(); + + void fillSeriesListBox(); + void fillRoleListBox(); + + std::vector<std::unique_ptr<SeriesEntry>> m_aEntries; + + OUString m_aFixedTextRange; + + ChartTypeTemplateProvider * m_pTemplateProvider; + DialogModel & m_rDialogModel; + weld::Entry* m_pCurrentRangeChoosingField; + bool m_bIsDirty; + + TabPageNotifiable * m_pTabPageNotifiable; + + std::unique_ptr<weld::Label> m_xFT_CAPTION; + std::unique_ptr<weld::Label> m_xFT_SERIES; + std::unique_ptr<weld::TreeView> m_xLB_SERIES; + std::unique_ptr<weld::Button> m_xBTN_ADD; + std::unique_ptr<weld::Button> m_xBTN_REMOVE; + std::unique_ptr<weld::Button> m_xBTN_UP; + std::unique_ptr<weld::Button> m_xBTN_DOWN; + std::unique_ptr<weld::Label> m_xFT_ROLE; + std::unique_ptr<weld::TreeView> m_xLB_ROLE; + std::unique_ptr<weld::Label> m_xFT_RANGE; + std::unique_ptr<weld::Entry> m_xEDT_RANGE; + std::unique_ptr<weld::Button> m_xIMB_RANGE_MAIN; + std::unique_ptr<weld::Label> m_xFT_CATEGORIES; + std::unique_ptr<weld::Label> m_xFT_DATALABELS;//used for xy charts + std::unique_ptr<weld::Entry> m_xEDT_CATEGORIES; + std::unique_ptr<weld::Button> m_xIMB_RANGE_CAT; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ErrorBars.cxx b/chart2/source/controller/dialogs/tp_ErrorBars.cxx new file mode 100644 index 000000000..927bf1130 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ErrorBars.cxx @@ -0,0 +1,67 @@ +/* -*- 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 "tp_ErrorBars.hxx" + +using namespace ::com::sun::star; + +namespace chart +{ + +ErrorBarsTabPage::ErrorBarsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_ErrorBars.ui", "tp_ErrorBars", &rInAttrs) + , m_aErrorBarResources(m_xBuilder.get(), pController, rInAttrs, /* bNoneAvailable = */ false) +{ +} + +std::unique_ptr<SfxTabPage> ErrorBarsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique<ErrorBarsTabPage>(pPage, pController, *rOutAttrs); +} + +bool ErrorBarsTabPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + m_aErrorBarResources.FillItemSet( *rOutAttrs ); + return true; +} + +void ErrorBarsTabPage::Reset( const SfxItemSet* rInAttrs ) +{ + m_aErrorBarResources.Reset( *rInAttrs ); +} + +void ErrorBarsTabPage::SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ) +{ + m_aErrorBarResources.SetAxisMinorStepWidthForErrorBarDecimals( fMinorStepWidth ); +} + +void ErrorBarsTabPage::SetErrorBarType( ErrorBarResources::tErrorBarType eNewType ) +{ + m_aErrorBarResources.SetErrorBarType( eNewType ); +} + +void ErrorBarsTabPage::SetChartDocumentForRangeChoosing( + const rtl::Reference<::chart::ChartModel> & xChartDocument ) +{ + m_aErrorBarResources.SetChartDocumentForRangeChoosing( xChartDocument ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ErrorBars.hxx b/chart2/source/controller/dialogs/tp_ErrorBars.hxx new file mode 100644 index 000000000..159de22b0 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ErrorBars.hxx @@ -0,0 +1,50 @@ +/* -*- 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 <res_ErrorBar.hxx> + +#include <sfx2/tabdlg.hxx> +#include <rtl/ref.hxx> + +namespace chart +{ +class ChartModel; + +class ErrorBarsTabPage : public SfxTabPage +{ +public: + ErrorBarsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + + void SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ); + void SetErrorBarType( ErrorBarResources::tErrorBarType eNewType ); + void SetChartDocumentForRangeChoosing( + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + +private: + ErrorBarResources m_aErrorBarResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_LegendPosition.cxx b/chart2/source/controller/dialogs/tp_LegendPosition.cxx new file mode 100644 index 000000000..00a0d54b1 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_LegendPosition.cxx @@ -0,0 +1,77 @@ +/* -*- 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 "tp_LegendPosition.hxx" +#include <res_LegendPosition.hxx> +#include <TextDirectionListBox.hxx> +#include <chartview/ChartSfxItemIds.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/frmdiritem.hxx> + +namespace chart +{ + +SchLegendPosTabPage::SchLegendPosTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_LegendPosition.ui", "tp_LegendPosition", &rInAttrs) + , m_aLegendPositionResources(*m_xBuilder) + , m_xLbTextDirection(new TextDirectionListBox(m_xBuilder->weld_combo_box("LB_LEGEND_TEXTDIR"))) + , m_xCBLegendNoOverlay(m_xBuilder->weld_check_button("CB_NO_OVERLAY")) +{ +} + +SchLegendPosTabPage::~SchLegendPosTabPage() +{ + m_xLbTextDirection.reset(); +} + +std::unique_ptr<SfxTabPage> SchLegendPosTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique<SchLegendPosTabPage>(pPage, pController, *rOutAttrs); +} + +bool SchLegendPosTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + m_aLegendPositionResources.writeToItemSet(*rOutAttrs); + + if (m_xLbTextDirection->get_active() != -1) + rOutAttrs->Put(SvxFrameDirectionItem(m_xLbTextDirection->get_active_id(), EE_PARA_WRITINGDIR)); + + if (m_xCBLegendNoOverlay->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_LEGEND_NO_OVERLAY, m_xCBLegendNoOverlay->get_active())); + + return true; +} + +void SchLegendPosTabPage::Reset(const SfxItemSet* rInAttrs) +{ + m_aLegendPositionResources.initFromItemSet(*rInAttrs); + + if( const SvxFrameDirectionItem* pDirectionItem = rInAttrs->GetItemIfSet( EE_PARA_WRITINGDIR ) ) + m_xLbTextDirection->set_active_id( pDirectionItem->GetValue() ); + + if (const SfxBoolItem* pNoOverlayItem = rInAttrs->GetItemIfSet(SCHATTR_LEGEND_NO_OVERLAY)) + { + bool bVal = pNoOverlayItem->GetValue(); + m_xCBLegendNoOverlay->set_active(bVal); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_LegendPosition.hxx b/chart2/source/controller/dialogs/tp_LegendPosition.hxx new file mode 100644 index 000000000..9e5f32d28 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_LegendPosition.hxx @@ -0,0 +1,49 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +#include <res_LegendPosition.hxx> + +namespace chart { class TextDirectionListBox; } + +namespace chart +{ + +class SchLegendPosTabPage : public SfxTabPage +{ +private: + + LegendPositionResources m_aLegendPositionResources; + std::unique_ptr<TextDirectionListBox> m_xLbTextDirection; + std::unique_ptr<weld::CheckButton> m_xCBLegendNoOverlay; + +public: + SchLegendPosTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~SchLegendPosTabPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_PointGeometry.cxx b/chart2/source/controller/dialogs/tp_PointGeometry.cxx new file mode 100644 index 000000000..7c2c4d942 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_PointGeometry.cxx @@ -0,0 +1,78 @@ +/* -*- 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 "tp_PointGeometry.hxx" +#include <res_BarGeometry.hxx> + +#include <chartview/ChartSfxItemIds.hxx> + +#include <svl/intitem.hxx> +#include <svx/svx3ditems.hxx> + +namespace chart +{ + +SchLayoutTabPage::SchLayoutTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_ChartType.ui", "tp_ChartType", &rInAttrs) +{ + m_pGeometryResources.reset(new BarGeometryResources(m_xBuilder.get())); +} + +SchLayoutTabPage::~SchLayoutTabPage() +{ + m_pGeometryResources.reset(); +} + +std::unique_ptr<SfxTabPage> SchLayoutTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique<SchLayoutTabPage>(pPage, pController, *rOutAttrs); +} + +bool SchLayoutTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + int nShape = m_pGeometryResources ? m_pGeometryResources->get_selected_index() : -1; + if (nShape != -1) + { + tools::Long nSegs=32; + + if (nShape==CHART_SHAPE3D_PYRAMID) + nSegs=4; + + rOutAttrs->Put(SfxInt32Item(SCHATTR_STYLE_SHAPE,nShape)); + rOutAttrs->Put(makeSvx3DHorizontalSegmentsItem(nSegs)); + } + return true; +} + +void SchLayoutTabPage::Reset(const SfxItemSet* rInAttrs) +{ + if (const SfxInt32Item* pShapeItem = rInAttrs->GetItemIfSet(SCHATTR_STYLE_SHAPE)) + { + tools::Long nVal = pShapeItem->GetValue(); + if(m_pGeometryResources) + { + m_pGeometryResources->select(static_cast<sal_uInt16>(nVal)); + m_pGeometryResources->set_visible(true); + } + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_PointGeometry.hxx b/chart2/source/controller/dialogs/tp_PointGeometry.hxx new file mode 100644 index 000000000..326cc9025 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_PointGeometry.hxx @@ -0,0 +1,44 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +namespace chart +{ +class BarGeometryResources; +class SchLayoutTabPage : public SfxTabPage +{ +public: + SchLayoutTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + virtual ~SchLayoutTabPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + +private: + std::unique_ptr<BarGeometryResources> m_pGeometryResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_PolarOptions.cxx b/chart2/source/controller/dialogs/tp_PolarOptions.cxx new file mode 100644 index 000000000..ad7b2b6f0 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_PolarOptions.cxx @@ -0,0 +1,106 @@ +/* -*- 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 "tp_PolarOptions.hxx" +#include <chartview/ChartSfxItemIds.hxx> + +#include <svl/eitem.hxx> +#include <svx/sdangitm.hxx> +#include <officecfg/Office/Compatibility.hxx> + +namespace chart +{ + +PolarOptionsTabPage::PolarOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_PolarOptions.ui", "tp_PolarOptions", &rInAttrs) + , m_xCB_Clockwise(m_xBuilder->weld_check_button("CB_CLOCKWISE")) + , m_xFL_StartingAngle(m_xBuilder->weld_frame("frameANGLE")) + , m_xNF_StartingAngle(m_xBuilder->weld_metric_spin_button("NF_STARTING_ANGLE", FieldUnit::DEGREE)) + , m_xFL_PlotOptions(m_xBuilder->weld_frame("framePLOT_OPTIONS")) + , m_xCB_IncludeHiddenCells(m_xBuilder->weld_check_button("CB_INCLUDE_HIDDEN_CELLS_POLAR")) + , m_xAngleDial(new svx::DialControl) + , m_xAngleDialWin(new weld::CustomWeld(*m_xBuilder, "CT_ANGLE_DIAL", *m_xAngleDial)) +{ + m_xAngleDial->SetLinkedField(m_xNF_StartingAngle.get()); +} + +PolarOptionsTabPage::~PolarOptionsTabPage() +{ + m_xAngleDialWin.reset(); + m_xAngleDial.reset(); +} + +std::unique_ptr<SfxTabPage> PolarOptionsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique<PolarOptionsTabPage>(pPage, pController, *rOutAttrs); +} + +bool PolarOptionsTabPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + if (m_xAngleDialWin->get_visible()) + { + rOutAttrs->Put(SdrAngleItem(SCHATTR_STARTING_ANGLE, m_xAngleDial->GetRotation())); + } + + if( m_xCB_Clockwise->get_visible() ) + rOutAttrs->Put(SfxBoolItem(SCHATTR_CLOCKWISE,m_xCB_Clockwise->get_active())); + + if (m_xCB_IncludeHiddenCells->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_INCLUDE_HIDDEN_CELLS, m_xCB_IncludeHiddenCells->get_active())); + + return true; +} + +void PolarOptionsTabPage::Reset(const SfxItemSet* rInAttrs) +{ + if (const SdrAngleItem* pAngleItem = rInAttrs->GetItemIfSet(SCHATTR_STARTING_ANGLE)) + { + Degree100 nTmp = pAngleItem->GetValue(); + m_xAngleDial->SetRotation( nTmp ); + } + else + { + m_xFL_StartingAngle->hide(); + } + // tdf#108059 Hide clockwise orientation checkbox in OOXML-heavy environments it would be useless anyways + const SfxBoolItem* pClockWiseItem = nullptr; + if (!officecfg::Office::Compatibility::View::ClockwisePieChartDirection::get() && + (pClockWiseItem = rInAttrs->GetItemIfSet(SCHATTR_CLOCKWISE))) + { + bool bCheck = pClockWiseItem->GetValue(); + m_xCB_Clockwise->set_active(bCheck); + } + else + { + m_xCB_Clockwise->hide(); + } + if (const SfxBoolItem* pHiddenCellsItem = rInAttrs->GetItemIfSet(SCHATTR_INCLUDE_HIDDEN_CELLS)) + { + bool bVal = pHiddenCellsItem->GetValue(); + m_xCB_IncludeHiddenCells->set_active(bVal); + } + else + { + m_xFL_PlotOptions->hide(); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_PolarOptions.hxx b/chart2/source/controller/dialogs/tp_PolarOptions.hxx new file mode 100644 index 000000000..eba401805 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_PolarOptions.hxx @@ -0,0 +1,57 @@ +/* -*- 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 <sfx2/tabdlg.hxx> +#include <svx/dialcontrol.hxx> + +namespace weld { + class CheckButton; + class CustomWeld; + class Frame; + class SpinButton; +} + +namespace chart +{ + +class PolarOptionsTabPage : public SfxTabPage +{ + +public: + PolarOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~PolarOptionsTabPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + +private: + std::unique_ptr<weld::CheckButton> m_xCB_Clockwise; + std::unique_ptr<weld::Frame> m_xFL_StartingAngle; + std::unique_ptr<weld::MetricSpinButton> m_xNF_StartingAngle; + std::unique_ptr<weld::Frame> m_xFL_PlotOptions; + std::unique_ptr<weld::CheckButton> m_xCB_IncludeHiddenCells; + std::unique_ptr<svx::DialControl> m_xAngleDial; + std::unique_ptr<weld::CustomWeld> m_xAngleDialWin; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_RangeChooser.cxx b/chart2/source/controller/dialogs/tp_RangeChooser.cxx new file mode 100644 index 000000000..05f137f5a --- /dev/null +++ b/chart2/source/controller/dialogs/tp_RangeChooser.cxx @@ -0,0 +1,381 @@ +/* -*- 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 "tp_RangeChooser.hxx" +#include <DataSourceHelper.hxx> +#include <ChartTypeTemplateProvider.hxx> +#include <ChartTypeTemplate.hxx> +#include "DialogModel.hxx" +#include <RangeSelectionHelper.hxx> +#include <TabPageNotifiable.hxx> +#include <com/sun/star/beans/PropertyState.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <officecfg/Office/Common.hxx> +#include <osl/diagnose.h> + +namespace +{ + void lcl_ShowChooserButton( + weld::Button& rChooserButton, + bool bShow) + { + if( rChooserButton.get_visible() != bShow ) + { + rChooserButton.set_visible( bShow ); + } + } + + void lcl_enableRangeChoosing(bool bEnable, weld::DialogController* pDialog) + { + if (!pDialog) + return; + weld::Dialog* pDlg = pDialog->getDialog(); + pDlg->set_modal(!bEnable); + pDlg->set_visible(!bEnable); + } + +} // anonymous namespace + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Sequence; + +RangeChooserTabPage::RangeChooserTabPage(weld::Container* pPage, weld::DialogController* pController, DialogModel & rDialogModel, + ChartTypeTemplateProvider* pTemplateProvider, + bool bHideDescription /* = false */) + : OWizardPage(pPage, pController, "modules/schart/ui/tp_RangeChooser.ui", "tp_RangeChooser") + , m_nChangingControlCalls(0) + , m_bIsDirty(false) + , m_pTemplateProvider(pTemplateProvider) + , m_rDialogModel( rDialogModel ) + , m_pTabPageNotifiable(dynamic_cast<TabPageNotifiable*>(pController)) + , m_xFT_Caption(m_xBuilder->weld_label("FT_CAPTION_FOR_WIZARD")) + , m_xFT_Range(m_xBuilder->weld_label("FT_RANGE")) + , m_xED_Range(m_xBuilder->weld_entry("ED_RANGE")) + , m_xIB_Range(m_xBuilder->weld_button("IB_RANGE")) + , m_xRB_Rows(m_xBuilder->weld_radio_button("RB_DATAROWS")) + , m_xRB_Columns(m_xBuilder->weld_radio_button("RB_DATACOLS")) + , m_xCB_FirstRowAsLabel(m_xBuilder->weld_check_button("CB_FIRST_ROW_ASLABELS")) + , m_xCB_FirstColumnAsLabel(m_xBuilder->weld_check_button("CB_FIRST_COLUMN_ASLABELS")) + , m_xFTTitle(m_xBuilder->weld_label("STR_PAGE_DATA_RANGE")) + , m_xFL_TimeBased(m_xBuilder->weld_widget("separator1")) + , m_xCB_TimeBased(m_xBuilder->weld_check_button("CB_TIME_BASED")) + , m_xFT_TimeStart(m_xBuilder->weld_label("label1")) + , m_xEd_TimeStart(m_xBuilder->weld_entry("ED_TIME_BASED_START")) + , m_xFT_TimeEnd(m_xBuilder->weld_label("label2")) + , m_xEd_TimeEnd(m_xBuilder->weld_entry("ED_TIME_BASED_END")) +{ + m_xFT_Caption->set_visible(!bHideDescription); + + SetPageTitle(m_xFTTitle->get_label());// OH:remove later with dialog + + // set defaults as long as DetectArguments does not work + m_xRB_Columns->set_active(true); + m_xCB_FirstColumnAsLabel->set_active(true); + m_xCB_FirstRowAsLabel->set_active(true); + + // BM: Note, that the range selection is not available, if there is no view. + // This happens for charts having their own embedded spreadsheet. If you + // force to get the range selection here, this would mean when entering this + // page the calc view would be created in this case. So, I enable the + // button here, and in the worst case nothing happens when it is pressed. + // Not nice, but I see no better solution for the moment. + m_xIB_Range->connect_clicked( LINK( this, RangeChooserTabPage, ChooseRangeHdl )); + + m_xED_Range->connect_changed( LINK( this, RangeChooserTabPage, ControlEditedHdl )); + m_xRB_Rows->connect_toggled( LINK( this, RangeChooserTabPage, ControlChangedRadioHdl ) ); + m_xCB_FirstRowAsLabel->connect_toggled( LINK( this, RangeChooserTabPage, ControlChangedCheckBoxHdl ) ); + m_xCB_FirstColumnAsLabel->connect_toggled( LINK( this, RangeChooserTabPage, ControlChangedCheckBoxHdl ) ); + m_xCB_TimeBased->connect_toggled( LINK( this, RangeChooserTabPage, ControlChangedCheckBoxHdl ) ); + m_xEd_TimeStart->connect_changed( LINK( this, RangeChooserTabPage, ControlChangedHdl ) ); + m_xEd_TimeEnd->connect_changed( LINK( this, RangeChooserTabPage, ControlChangedHdl ) ); + + if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() ) + { + m_xFL_TimeBased->hide(); + m_xCB_TimeBased->hide(); + m_xFT_TimeStart->hide(); + m_xEd_TimeStart->hide(); + m_xFT_TimeEnd->hide(); + m_xEd_TimeEnd->hide(); + } +} + +RangeChooserTabPage::~RangeChooserTabPage() +{ +} + +void RangeChooserTabPage::Activate() +{ + OWizardPage::Activate(); + initControlsFromModel(); + m_xED_Range->grab_focus(); +} + +void RangeChooserTabPage::initControlsFromModel() +{ + m_nChangingControlCalls++; + + if(m_pTemplateProvider) + m_xCurrentChartTypeTemplate = m_pTemplateProvider->getCurrentTemplate(); + + bool bUseColumns = !m_xRB_Rows->get_active(); + bool bFirstCellAsLabel = bUseColumns ? m_xCB_FirstRowAsLabel->get_active() : m_xCB_FirstColumnAsLabel->get_active(); + bool bHasCategories = bUseColumns ? m_xCB_FirstColumnAsLabel->get_active() : m_xCB_FirstRowAsLabel->get_active(); + + bool bIsValid = m_rDialogModel.allArgumentsForRectRangeDetected(); + if( bIsValid ) + m_rDialogModel.detectArguments(m_aLastValidRangeString, bUseColumns, bFirstCellAsLabel, bHasCategories ); + else + m_aLastValidRangeString.clear(); + + m_xED_Range->set_text( m_aLastValidRangeString ); + + m_xRB_Rows->set_active( !bUseColumns ); + m_xRB_Columns->set_active( bUseColumns ); + + m_xCB_FirstRowAsLabel->set_active( m_xRB_Rows->get_active()?bHasCategories:bFirstCellAsLabel ); + m_xCB_FirstColumnAsLabel->set_active( m_xRB_Columns->get_active()?bHasCategories:bFirstCellAsLabel ); + + isValid(); + + m_nChangingControlCalls--; +} + +void RangeChooserTabPage::Deactivate() +{ + commitPage(); + vcl::OWizardPage::Deactivate(); +} + +void RangeChooserTabPage::commitPage() +{ + commitPage(::vcl::WizardTypes::eFinish); +} + +bool RangeChooserTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ ) +{ + //ranges may have been edited in the meanwhile (dirty is true in that case here) + if( isValid() ) + { + changeDialogModelAccordingToControls(); + return true; // return false if this page should not be left + } + else + return false; +} + +void RangeChooserTabPage::changeDialogModelAccordingToControls() +{ + if(m_nChangingControlCalls>0) + return; + + if( !m_xCurrentChartTypeTemplate.is() ) + { + if(m_pTemplateProvider) + m_xCurrentChartTypeTemplate = m_pTemplateProvider->getCurrentTemplate(); + if( !m_xCurrentChartTypeTemplate.is()) + { + OSL_FAIL( "Need a template to change data source" ); + return; + } + } + + if( !m_bIsDirty ) + return; + + bool bFirstCellAsLabel = ( m_xCB_FirstColumnAsLabel->get_active() && !m_xRB_Columns->get_active() ) + || ( m_xCB_FirstRowAsLabel->get_active() && !m_xRB_Rows->get_active() ); + bool bHasCategories = ( m_xCB_FirstColumnAsLabel->get_active() && m_xRB_Columns->get_active() ) + || ( m_xCB_FirstRowAsLabel->get_active() && m_xRB_Rows->get_active() ); + bool bTimeBased = m_xCB_TimeBased->get_active(); + + Sequence< beans::PropertyValue > aArguments( + DataSourceHelper::createArguments( + m_xRB_Columns->get_active(), bFirstCellAsLabel, bHasCategories ) ); + + if(bTimeBased) + { + aArguments.realloc( aArguments.getLength() + 1 ); + aArguments.getArray()[aArguments.getLength() - 1] = + beans::PropertyValue( "TimeBased", -1, uno::Any(bTimeBased), + beans::PropertyState_DIRECT_VALUE ); + } + + // only if range is valid + if( m_aLastValidRangeString != m_xED_Range->get_text()) + return; + + m_rDialogModel.setTemplate( m_xCurrentChartTypeTemplate ); + aArguments.realloc( aArguments.getLength() + 1 ); + aArguments.getArray()[aArguments.getLength() - 1] = + beans::PropertyValue( "CellRangeRepresentation" , -1, + uno::Any( m_aLastValidRangeString ), + beans::PropertyState_DIRECT_VALUE ); + m_rDialogModel.setData( aArguments ); + m_bIsDirty = false; + + if(bTimeBased) + { + sal_Int32 nStart = m_xEd_TimeStart->get_text().toInt32(); + sal_Int32 nEnd = m_xEd_TimeEnd->get_text().toInt32(); + m_rDialogModel.setTimeBasedRange(true, nStart, nEnd); + } + + //@todo warn user that the selected range is not valid + //@todo better: disable OK-Button if range is invalid +} + +bool RangeChooserTabPage::isValid() +{ + OUString aRange( m_xED_Range->get_text()); + bool bFirstCellAsLabel = ( m_xCB_FirstColumnAsLabel->get_active() && !m_xRB_Columns->get_active() ) + || ( m_xCB_FirstRowAsLabel->get_active() && !m_xRB_Rows->get_active() ); + bool bHasCategories = ( m_xCB_FirstColumnAsLabel->get_active() && m_xRB_Columns->get_active() ) + || ( m_xCB_FirstRowAsLabel->get_active() && m_xRB_Rows->get_active() ); + bool bIsValid = ( aRange.isEmpty() ) || + m_rDialogModel.getRangeSelectionHelper()->verifyArguments( + DataSourceHelper::createArguments( + aRange, Sequence< sal_Int32 >(), m_xRB_Columns->get_active(), bFirstCellAsLabel, bHasCategories )); + + if( bIsValid ) + { + m_xED_Range->set_message_type(weld::EntryMessageType::Normal); + if( m_pTabPageNotifiable ) + m_pTabPageNotifiable->setValidPage( this ); + m_aLastValidRangeString = aRange; + } + else + { + m_xED_Range->set_message_type(weld::EntryMessageType::Error); + if( m_pTabPageNotifiable ) + m_pTabPageNotifiable->setInvalidPage( this ); + } + + // enable/disable controls + // #i79531# if the range is valid but an action of one of these buttons + // would render it invalid, the button should be disabled + if( bIsValid ) + { + bool bDataInColumns = m_xRB_Columns->get_active(); + bool bIsSwappedRangeValid = m_rDialogModel.getRangeSelectionHelper()->verifyArguments( + DataSourceHelper::createArguments( + aRange, Sequence< sal_Int32 >(), ! bDataInColumns, bHasCategories, bFirstCellAsLabel )); + m_xRB_Rows->set_sensitive( bIsSwappedRangeValid ); + m_xRB_Columns->set_sensitive( bIsSwappedRangeValid ); + + m_xCB_FirstRowAsLabel->set_sensitive( + m_rDialogModel.getRangeSelectionHelper()->verifyArguments( + DataSourceHelper::createArguments( + aRange, Sequence< sal_Int32 >(), m_xRB_Columns->get_active(), + bDataInColumns ? ! bFirstCellAsLabel : bFirstCellAsLabel, + bDataInColumns ? bHasCategories : ! bHasCategories ))); + m_xCB_FirstColumnAsLabel->set_sensitive( + m_rDialogModel.getRangeSelectionHelper()->verifyArguments( + DataSourceHelper::createArguments( + aRange, Sequence< sal_Int32 >(), m_xRB_Columns->get_active(), + bDataInColumns ? bFirstCellAsLabel : ! bFirstCellAsLabel, + bDataInColumns ? ! bHasCategories : bHasCategories ))); + } + else + { + m_xRB_Rows->set_sensitive( bIsValid ); + m_xRB_Columns->set_sensitive( bIsValid ); + m_xCB_FirstRowAsLabel->set_sensitive( bIsValid ); + m_xCB_FirstColumnAsLabel->set_sensitive( bIsValid ); + } + + bool bShowIB = m_rDialogModel.getRangeSelectionHelper()->hasRangeSelection(); + lcl_ShowChooserButton( *m_xIB_Range, bShowIB ); + + return bIsValid; +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ControlEditedHdl, weld::Entry&, void) +{ + setDirty(); + isValid(); +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ControlChangedRadioHdl, weld::Toggleable&, void) +{ + ControlChangedHdl(*m_xED_Range); +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ControlChangedCheckBoxHdl, weld::Toggleable&, void) +{ + ControlChangedHdl(*m_xED_Range); +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ControlChangedHdl, weld::Entry&, void) +{ + setDirty(); + if( isValid()) + changeDialogModelAccordingToControls(); +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ChooseRangeHdl, weld::Button&, void) +{ + OUString aRange = m_xED_Range->get_text(); + OUString aTitle = m_xFTTitle->get_label(); + + lcl_enableRangeChoosing(true, m_pDialogController); + m_rDialogModel.getRangeSelectionHelper()->chooseRange( aRange, aTitle, *this ); +} + +void RangeChooserTabPage::listeningFinished( const OUString & rNewRange ) +{ + //user has selected a new range + + // rNewRange becomes invalid after removing the listener + OUString aRange( rNewRange ); + + m_rDialogModel.startControllerLockTimer(); + + // stop listening + m_rDialogModel.getRangeSelectionHelper()->stopRangeListening(); + + //update dialog state + m_xED_Range->set_text(aRange); + m_xED_Range->grab_focus(); + + setDirty(); + if( isValid()) + changeDialogModelAccordingToControls(); + + lcl_enableRangeChoosing(false, m_pDialogController); +} + +void RangeChooserTabPage::disposingRangeSelection() +{ + m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false ); +} + +void RangeChooserTabPage::setDirty() +{ + if( m_nChangingControlCalls == 0 ) + m_bIsDirty = true; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_RangeChooser.hxx b/chart2/source/controller/dialogs/tp_RangeChooser.hxx new file mode 100644 index 000000000..fff338324 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_RangeChooser.hxx @@ -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 . + */ + +#pragma once + +#include <RangeSelectionListener.hxx> + +#include <vcl/wizardmachine.hxx> + +namespace chart { class TabPageNotifiable; } + +namespace chart +{ +class ChartTypeTemplate; +class ChartTypeTemplateProvider; +class DialogModel; + +class RangeChooserTabPage final : public vcl::OWizardPage, public RangeSelectionListenerParent +{ +public: + + RangeChooserTabPage(weld::Container* pPage, weld::DialogController* pController, DialogModel & rDialogModel, + ChartTypeTemplateProvider* pTemplateProvider, + bool bHideDescription = false); + virtual ~RangeChooserTabPage() override; + + //RangeSelectionListenerParent + virtual void listeningFinished( const OUString & rNewRange ) override; + virtual void disposingRangeSelection() override; + + virtual void Activate() override; + + void commitPage(); + +private: + + //OWizardPage + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason eReason ) override; + + //TabPage + virtual void Deactivate() override; + + void initControlsFromModel(); + void changeDialogModelAccordingToControls(); + bool isValid(); + void setDirty(); + + DECL_LINK( ChooseRangeHdl, weld::Button&, void ); + DECL_LINK( ControlChangedHdl, weld::Entry&, void ); + DECL_LINK( ControlChangedCheckBoxHdl, weld::Toggleable&, void ); + DECL_LINK( ControlChangedRadioHdl, weld::Toggleable&, void ); + DECL_LINK( ControlEditedHdl, weld::Entry&, void ); + + sal_Int32 m_nChangingControlCalls; + bool m_bIsDirty; + + OUString m_aLastValidRangeString; + rtl::Reference< ::chart::ChartTypeTemplate > m_xCurrentChartTypeTemplate; + ChartTypeTemplateProvider* m_pTemplateProvider; + + DialogModel & m_rDialogModel; + TabPageNotifiable * m_pTabPageNotifiable; + + std::unique_ptr<weld::Label> m_xFT_Caption; + std::unique_ptr<weld::Label> m_xFT_Range; + std::unique_ptr<weld::Entry> m_xED_Range; + std::unique_ptr<weld::Button> m_xIB_Range; + std::unique_ptr<weld::RadioButton> m_xRB_Rows; + std::unique_ptr<weld::RadioButton> m_xRB_Columns; + std::unique_ptr<weld::CheckButton> m_xCB_FirstRowAsLabel; + std::unique_ptr<weld::CheckButton> m_xCB_FirstColumnAsLabel; + std::unique_ptr<weld::Label> m_xFTTitle; + std::unique_ptr<weld::Widget> m_xFL_TimeBased; + std::unique_ptr<weld::CheckButton> m_xCB_TimeBased; + std::unique_ptr<weld::Label> m_xFT_TimeStart; + std::unique_ptr<weld::Entry> m_xEd_TimeStart; + std::unique_ptr<weld::Label> m_xFT_TimeEnd; + std::unique_ptr<weld::Entry> m_xEd_TimeEnd; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Scale.cxx b/chart2/source/controller/dialogs/tp_Scale.cxx new file mode 100644 index 000000000..7147dfa84 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Scale.cxx @@ -0,0 +1,637 @@ +/* -*- 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 "tp_Scale.hxx" + +#include <ResId.hxx> +#include <strings.hrc> +#include <chartview/ChartSfxItemIds.hxx> +#include <AxisHelper.hxx> + +#include <svx/svxids.hrc> +#include <osl/diagnose.h> +#include <sfx2/dialoghelper.hxx> +#include <svx/chrtitem.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/numformat.hxx> +#include <vcl/formatter.hxx> +#include <vcl/weld.hxx> +#include <svl/zformat.hxx> +#include <vcl/svapp.hxx> + +#include <com/sun/star/chart2/AxisType.hpp> + +using namespace ::com::sun::star; + +namespace chart +{ + +namespace +{ + +void lcl_setValue(weld::FormattedSpinButton& rFmtField, double fValue) +{ + rFmtField.GetFormatter().SetValue(fValue); +} + +} + +ScaleTabPage::ScaleTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_Scale.ui", "tp_Scale", &rInAttrs) + , fMin(0.0) + , fMax(0.0) + , fStepMain(0.0) + , nStepHelp(0) + , fOrigin(0.0) + , m_nTimeResolution(1) + , m_nMainTimeUnit(1) + , m_nHelpTimeUnit(1) + , m_nAxisType(chart2::AxisType::REALNUMBER) + , m_bAllowDateAxis(false) + , pNumFormatter(nullptr) + , m_bShowAxisOrigin(false) + , m_xCbxReverse(m_xBuilder->weld_check_button("CBX_REVERSE")) + , m_xCbxLogarithm(m_xBuilder->weld_check_button("CBX_LOGARITHM")) + , m_xBxType(m_xBuilder->weld_widget("boxTYPE")) + , m_xLB_AxisType(m_xBuilder->weld_combo_box("LB_AXIS_TYPE")) + , m_xBxMinMax(m_xBuilder->weld_widget("gridMINMAX")) + , m_xFmtFldMin(m_xBuilder->weld_formatted_spin_button("EDT_MIN")) + , m_xCbxAutoMin(m_xBuilder->weld_check_button("CBX_AUTO_MIN")) + , m_xFmtFldMax(m_xBuilder->weld_formatted_spin_button("EDT_MAX")) + , m_xCbxAutoMax(m_xBuilder->weld_check_button("CBX_AUTO_MAX")) + , m_xBxResolution(m_xBuilder->weld_widget("boxRESOLUTION")) + , m_xLB_TimeResolution(m_xBuilder->weld_combo_box("LB_TIME_RESOLUTION")) + , m_xCbx_AutoTimeResolution(m_xBuilder->weld_check_button("CBX_AUTO_TIME_RESOLUTION")) + , m_xTxtMain(m_xBuilder->weld_label("TXT_STEP_MAIN")) + , m_xFmtFldStepMain(m_xBuilder->weld_formatted_spin_button("EDT_STEP_MAIN")) + , m_xMt_MainDateStep(m_xBuilder->weld_spin_button("MT_MAIN_DATE_STEP")) + , m_xLB_MainTimeUnit(m_xBuilder->weld_combo_box("LB_MAIN_TIME_UNIT")) + , m_xCbxAutoStepMain(m_xBuilder->weld_check_button("CBX_AUTO_STEP_MAIN")) + , m_xTxtHelpCount(m_xBuilder->weld_label("TXT_STEP_HELP_COUNT")) + , m_xTxtHelp(m_xBuilder->weld_label("TXT_STEP_HELP")) + , m_xMtStepHelp(m_xBuilder->weld_spin_button("MT_STEPHELP")) + , m_xLB_HelpTimeUnit(m_xBuilder->weld_combo_box("LB_HELP_TIME_UNIT")) + , m_xCbxAutoStepHelp(m_xBuilder->weld_check_button("CBX_AUTO_STEP_HELP")) + , m_xFmtFldOrigin(m_xBuilder->weld_formatted_spin_button("EDT_ORIGIN")) + , m_xCbxAutoOrigin(m_xBuilder->weld_check_button("CBX_AUTO_ORIGIN")) + , m_xBxOrigin(m_xBuilder->weld_widget("boxORIGIN")) +{ + m_xCbxAutoMin->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbxAutoMax->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbxAutoStepMain->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbxAutoStepHelp->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbxAutoOrigin->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbx_AutoTimeResolution->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + + Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter(); + rFmtFldMax.ClearMinValue(); + rFmtFldMax.ClearMaxValue(); + Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter(); + rFmtFldMin.ClearMinValue(); + rFmtFldMin.ClearMaxValue(); + Formatter& rFmtFldStepMain = m_xFmtFldStepMain->GetFormatter(); + rFmtFldStepMain.ClearMinValue(); + rFmtFldStepMain.ClearMaxValue(); + Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter(); + rFmtFldOrigin.ClearMinValue(); + rFmtFldOrigin.ClearMaxValue(); + + m_xLB_AxisType->connect_changed(LINK(this, ScaleTabPage, SelectAxisTypeHdl)); + + HideAllControls(); +} + +ScaleTabPage::~ScaleTabPage() +{ +} + +void ScaleTabPage::EnableControls() +{ + bool bValueAxis = m_nAxisType == chart2::AxisType::REALNUMBER + || m_nAxisType == chart2::AxisType::PERCENT + || m_nAxisType == chart2::AxisType::DATE; + bool bDateAxis = m_nAxisType == chart2::AxisType::DATE; + + m_xBxType->set_visible(m_bAllowDateAxis); + + m_xCbxLogarithm->set_visible( bValueAxis && !bDateAxis ); + + m_xBxMinMax->set_visible(bValueAxis); + + m_xTxtMain->set_visible( bValueAxis ); + m_xCbxAutoStepMain->set_visible( bValueAxis ); + + m_xTxtHelpCount->set_visible( bValueAxis && !bDateAxis ); + m_xTxtHelp->set_visible( bDateAxis ); + m_xMtStepHelp->set_visible( bValueAxis ); + m_xCbxAutoStepHelp->set_visible( bValueAxis ); + + m_xBxOrigin->set_visible( m_bShowAxisOrigin && bValueAxis ); + m_xBxResolution->set_visible( bDateAxis ); + + bool bWasDateAxis = m_xMt_MainDateStep->get_visible(); + if( bWasDateAxis != bDateAxis ) + { + //transport value from one to other control + if( bWasDateAxis ) + lcl_setValue( *m_xFmtFldStepMain, m_xMt_MainDateStep->get_value() ); + else + m_xMt_MainDateStep->set_value(m_xFmtFldStepMain->GetFormatter().GetValue()); + } + + m_xFmtFldStepMain->set_visible( bValueAxis && !bDateAxis ); + m_xMt_MainDateStep->set_visible( bDateAxis ); + + m_xLB_MainTimeUnit->set_visible( bDateAxis ); + m_xLB_HelpTimeUnit->set_visible( bDateAxis ); + + EnableValueHdl(*m_xCbxAutoMin); + EnableValueHdl(*m_xCbxAutoMax); + EnableValueHdl(*m_xCbxAutoStepMain); + EnableValueHdl(*m_xCbxAutoStepHelp); + EnableValueHdl(*m_xCbxAutoOrigin); + EnableValueHdl(*m_xCbx_AutoTimeResolution); +} + +IMPL_LINK( ScaleTabPage, EnableValueHdl, weld::Toggleable&, rCbx, void ) +{ + bool bEnable = !rCbx.get_active() && rCbx.get_sensitive(); + if (&rCbx == m_xCbxAutoMin.get()) + { + m_xFmtFldMin->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbxAutoMax.get()) + { + m_xFmtFldMax->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbxAutoStepMain.get()) + { + m_xFmtFldStepMain->set_sensitive( bEnable ); + m_xMt_MainDateStep->set_sensitive( bEnable ); + m_xLB_MainTimeUnit->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbxAutoStepHelp.get()) + { + m_xMtStepHelp->set_sensitive( bEnable ); + m_xLB_HelpTimeUnit->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbx_AutoTimeResolution.get()) + { + m_xLB_TimeResolution->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbxAutoOrigin.get()) + { + m_xFmtFldOrigin->set_sensitive( bEnable ); + } +} + +namespace { + +enum AxisTypeListBoxEntry +{ + TYPE_AUTO=0, + TYPE_TEXT=1, + TYPE_DATE=2 +}; + +} + +IMPL_LINK_NOARG(ScaleTabPage, SelectAxisTypeHdl, weld::ComboBox&, void) +{ + const sal_Int32 nPos = m_xLB_AxisType->get_active(); + if( nPos==TYPE_DATE ) + m_nAxisType = chart2::AxisType::DATE; + else + m_nAxisType = chart2::AxisType::CATEGORY; + if( m_nAxisType == chart2::AxisType::DATE ) + m_xCbxLogarithm->set_active(false); + EnableControls(); + SetNumFormat(); +} + +std::unique_ptr<SfxTabPage> ScaleTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique<ScaleTabPage>(pPage, pController, *rOutAttrs); +} + +bool ScaleTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + OSL_PRECOND( pNumFormatter, "No NumberFormatter available" ); + + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXISTYPE, m_nAxisType)); + if(m_bAllowDateAxis) + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_DATEAXIS, m_xLB_AxisType->get_active()==TYPE_AUTO)); + + bool bAutoScale = false; + if( m_nAxisType==chart2::AxisType::CATEGORY ) + bAutoScale = true;//reset scaling for category charts + + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_MIN ,bAutoScale || m_xCbxAutoMin->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_MAX ,bAutoScale || m_xCbxAutoMax->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_HELP,bAutoScale || m_xCbxAutoStepHelp->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_ORIGIN ,bAutoScale || m_xCbxAutoOrigin->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_LOGARITHM ,m_xCbxLogarithm->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_REVERSE ,m_xCbxReverse->get_active())); + rOutAttrs->Put(SvxDoubleItem(fMax , SCHATTR_AXIS_MAX)); + rOutAttrs->Put(SvxDoubleItem(fMin , SCHATTR_AXIS_MIN)); + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_STEP_HELP, nStepHelp)); + rOutAttrs->Put(SvxDoubleItem(fOrigin , SCHATTR_AXIS_ORIGIN)); + + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_MAIN,bAutoScale || m_xCbxAutoStepMain->get_active())); + rOutAttrs->Put(SvxDoubleItem(fStepMain,SCHATTR_AXIS_STEP_MAIN)); + + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_TIME_RESOLUTION,bAutoScale || m_xCbx_AutoTimeResolution->get_active())); + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_TIME_RESOLUTION,m_nTimeResolution)); + + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_MAIN_TIME_UNIT,m_nMainTimeUnit)); + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_HELP_TIME_UNIT,m_nHelpTimeUnit)); + + return true; +} + +void ScaleTabPage::Reset(const SfxItemSet* rInAttrs) +{ + OSL_PRECOND( pNumFormatter, "No NumberFormatter available" ); + if(!pNumFormatter) + return; + + if (const SfxBoolItem* pDateAxisItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_ALLOW_DATEAXIS)) + m_bAllowDateAxis = pDateAxisItem->GetValue(); + m_nAxisType=chart2::AxisType::REALNUMBER; + if (const SfxInt32Item* pAxisTypeItem = rInAttrs->GetItemIfSet(SCHATTR_AXISTYPE)) + m_nAxisType = static_cast<int>(pAxisTypeItem->GetValue()); + if( m_nAxisType==chart2::AxisType::DATE && !m_bAllowDateAxis ) + m_nAxisType=chart2::AxisType::CATEGORY; + if( m_bAllowDateAxis ) + { + bool bAutoDateAxis = false; + if (const SfxBoolItem* pDateAxisItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_DATEAXIS)) + bAutoDateAxis = pDateAxisItem->GetValue(); + + sal_uInt16 nPos = 0; + if( m_nAxisType==chart2::AxisType::DATE ) + nPos=TYPE_DATE; + else if( bAutoDateAxis ) + nPos=TYPE_AUTO; + else + nPos=TYPE_TEXT; + m_xLB_AxisType->set_active( nPos ); + } + + m_xCbxAutoMin->set_active(true); + m_xCbxAutoMax->set_active(true); + m_xCbxAutoStepMain->set_active(true); + m_xCbxAutoStepHelp->set_active(true); + m_xCbxAutoOrigin->set_active(true); + m_xCbx_AutoTimeResolution->set_active(true); + + if (const SfxBoolItem* pAutoMinItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_MIN)) + m_xCbxAutoMin->set_active(pAutoMinItem->GetValue()); + + if (const SvxDoubleItem* pAxisMinItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_MIN)) + { + fMin = pAxisMinItem->GetValue(); + lcl_setValue( *m_xFmtFldMin, fMin ); + m_xFmtFldMin->save_value(); + } + + if (const SfxBoolItem* pAutoMaxItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_MAX)) + m_xCbxAutoMax->set_active(pAutoMaxItem->GetValue()); + + if (const SvxDoubleItem* pAxisMaxItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_MAX)) + { + fMax = pAxisMaxItem->GetValue(); + lcl_setValue( *m_xFmtFldMax, fMax ); + m_xFmtFldMax->save_value(); + } + + if (const SfxBoolItem* pAutoStepMainItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_STEP_MAIN)) + m_xCbxAutoStepMain->set_active(pAutoStepMainItem->GetValue()); + + if (const SvxDoubleItem* pStepMainItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_STEP_MAIN)) + { + fStepMain = pStepMainItem->GetValue(); + lcl_setValue( *m_xFmtFldStepMain, fStepMain ); + m_xFmtFldStepMain->save_value(); + m_xMt_MainDateStep->set_value( static_cast<sal_Int32>(fStepMain) ); + m_xMt_MainDateStep->save_value(); + } + if (const SfxBoolItem* pAutoStepHelpItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_STEP_HELP)) + m_xCbxAutoStepHelp->set_active(pAutoStepHelpItem->GetValue()); + if (const SfxBoolItem* pLogItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_LOGARITHM)) + m_xCbxLogarithm->set_active(pLogItem->GetValue()); + if (const SfxBoolItem* pReverseItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_REVERSE)) + m_xCbxReverse->set_active(pReverseItem->GetValue()); + if (const SfxInt32Item* pStepHelpItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_STEP_HELP)) + { + nStepHelp = pStepHelpItem->GetValue(); + m_xMtStepHelp->set_value( nStepHelp ); + m_xMtStepHelp->save_value(); + } + if (const SfxBoolItem* pOriginItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_ORIGIN)) + m_xCbxAutoOrigin->set_active(pOriginItem->GetValue()); + if (const SvxDoubleItem* pOriginItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_ORIGIN)) + { + fOrigin = pOriginItem->GetValue(); + lcl_setValue( *m_xFmtFldOrigin, fOrigin ); + m_xFmtFldOrigin->save_value(); + } + + if (const SfxBoolItem* pAutoTimeResItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_TIME_RESOLUTION)) + m_xCbx_AutoTimeResolution->set_active(pAutoTimeResItem->GetValue()); + if (const SfxInt32Item* pTimeResItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_TIME_RESOLUTION)) + { + m_nTimeResolution = pTimeResItem->GetValue(); + m_xLB_TimeResolution->set_active( m_nTimeResolution ); + } + + if (const SfxInt32Item* pMainTimeUnitItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_MAIN_TIME_UNIT)) + { + m_nMainTimeUnit = pMainTimeUnitItem->GetValue(); + m_xLB_MainTimeUnit->set_active( m_nMainTimeUnit ); + } + if (const SfxInt32Item* pHelpTimeUnitItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_HELP_TIME_UNIT)) + { + m_nHelpTimeUnit = pHelpTimeUnitItem->GetValue(); + m_xLB_HelpTimeUnit->set_active( m_nHelpTimeUnit ); + } + + EnableControls(); + SetNumFormat(); +} + +DeactivateRC ScaleTabPage::DeactivatePage(SfxItemSet* pItemSet) +{ + if( !pNumFormatter ) + { + OSL_FAIL( "No NumberFormatter available" ); + return DeactivateRC::LeavePage; + } + + bool bDateAxis = m_nAxisType == chart2::AxisType::DATE; + + sal_uInt32 nMinMaxOriginFmt = m_xFmtFldMax->GetFormatter().GetFormatKey(); + if (pNumFormatter->GetType(nMinMaxOriginFmt) == SvNumFormatType::TEXT) + nMinMaxOriginFmt = 0; + // numberformat_text cause numbers to fail being numbers... Shouldn't happen, but can. + sal_uInt32 nStepFmt = m_xFmtFldStepMain->GetFormatter().GetFormatKey(); + if (pNumFormatter->GetType(nStepFmt) == SvNumFormatType::TEXT) + nStepFmt = 0; + + weld::Widget* pControl = nullptr; + TranslateId pErrStrId; + double fDummy; + + fMax = m_xFmtFldMax->GetFormatter().GetValue(); + fMin = m_xFmtFldMin->GetFormatter().GetValue(); + fOrigin = m_xFmtFldOrigin->GetFormatter().GetValue(); + fStepMain = bDateAxis ? m_xMt_MainDateStep->get_value() : m_xFmtFldStepMain->GetFormatter().GetValue(); + nStepHelp = m_xMtStepHelp->get_value(); + m_nTimeResolution = m_xLB_TimeResolution->get_active(); + m_nMainTimeUnit = m_xLB_MainTimeUnit->get_active(); + m_nHelpTimeUnit = m_xLB_HelpTimeUnit->get_active(); + + if( m_nAxisType != chart2::AxisType::REALNUMBER ) + m_xCbxLogarithm->hide(); + + //check which entries need user action + + if ( m_xCbxLogarithm->get_active() && + ( ( !m_xCbxAutoMin->get_active() && fMin <= 0.0 ) + || ( !m_xCbxAutoMax->get_active() && fMax <= 0.0 ) ) ) + { + pControl = m_xFmtFldMin.get(); + pErrStrId = STR_BAD_LOGARITHM; + } + // check for entries that cannot be parsed for the current number format + else if ( m_xFmtFldMin->get_value_changed_from_saved() + && !m_xCbxAutoMin->get_active() + && !pNumFormatter->IsNumberFormat( m_xFmtFldMin->get_text(), nMinMaxOriginFmt, fDummy)) + { + pControl = m_xFmtFldMin.get(); + pErrStrId = STR_INVALID_NUMBER; + } + else if ( m_xFmtFldMax->get_value_changed_from_saved() + && !m_xCbxAutoMax->get_active() + && !pNumFormatter->IsNumberFormat( m_xFmtFldMax->get_text(), nMinMaxOriginFmt, fDummy)) + { + pControl = m_xFmtFldMax.get(); + pErrStrId = STR_INVALID_NUMBER; + } + else if ( !bDateAxis && m_xFmtFldStepMain->get_value_changed_from_saved() + && !m_xCbxAutoStepMain->get_active() + && !pNumFormatter->IsNumberFormat( m_xFmtFldStepMain->get_text(), nStepFmt, fDummy)) + { + pControl = m_xFmtFldStepMain.get(); + pErrStrId = STR_INVALID_NUMBER; + } + else if (m_xFmtFldOrigin->get_value_changed_from_saved() && !m_xCbxAutoOrigin->get_active() && + !pNumFormatter->IsNumberFormat( m_xFmtFldOrigin->get_text(), nMinMaxOriginFmt, fDummy)) + { + pControl = m_xFmtFldOrigin.get(); + pErrStrId = STR_INVALID_NUMBER; + } + else if (!m_xCbxAutoStepMain->get_active() && fStepMain <= 0.0) + { + pControl = m_xFmtFldStepMain.get(); + pErrStrId = STR_STEP_GT_ZERO; + } + else if (!m_xCbxAutoMax->get_active() && !m_xCbxAutoMin->get_active() && + fMin >= fMax) + { + pControl = m_xFmtFldMin.get(); + pErrStrId = STR_MIN_GREATER_MAX; + } + else if( bDateAxis ) + { + if( !m_xCbxAutoStepMain->get_active() && !m_xCbxAutoStepHelp->get_active() ) + { + if( m_nHelpTimeUnit > m_nMainTimeUnit ) + { + pControl = m_xLB_MainTimeUnit.get(); + pErrStrId = STR_INVALID_INTERVALS; + } + else if( m_nHelpTimeUnit == m_nMainTimeUnit && nStepHelp > fStepMain ) + { + pControl = m_xLB_MainTimeUnit.get(); + pErrStrId = STR_INVALID_INTERVALS; + } + } + if( !pErrStrId && !m_xCbx_AutoTimeResolution->get_active() ) + { + if( (!m_xCbxAutoStepMain->get_active() && m_nTimeResolution > m_nMainTimeUnit ) + || + (!m_xCbxAutoStepHelp->get_active() && m_nTimeResolution > m_nHelpTimeUnit ) + ) + { + pControl = m_xLB_TimeResolution.get(); + pErrStrId = STR_INVALID_TIME_UNIT; + } + } + } + + if( ShowWarning( pErrStrId, pControl ) ) + return DeactivateRC::KeepPage; + + if( pItemSet ) + FillItemSet( pItemSet ); + + return DeactivateRC::LeavePage; +} + +void ScaleTabPage::SetNumFormatter( SvNumberFormatter* pFormatter ) +{ + pNumFormatter = pFormatter; + + Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter(); + Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter(); + Formatter& rFmtFldStepMain = m_xFmtFldStepMain->GetFormatter(); + Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter(); + + rFmtFldMax.SetFormatter( pNumFormatter ); + rFmtFldMin.SetFormatter( pNumFormatter ); + rFmtFldStepMain.SetFormatter( pNumFormatter ); + rFmtFldOrigin.SetFormatter( pNumFormatter ); + + // #i6278# allow more decimal places than the output format. As + // the numbers shown in the edit fields are used for input, it makes more + // sense to display the values in the input format rather than the output + // format. + rFmtFldMax.UseInputStringForFormatting(); + rFmtFldMin.UseInputStringForFormatting(); + rFmtFldStepMain.UseInputStringForFormatting(); + rFmtFldOrigin.UseInputStringForFormatting(); + + SetNumFormat(); +} + +void ScaleTabPage::SetNumFormat() +{ + const SfxUInt32Item *pNumFormatItem = GetItemSet().GetItemIfSet( SID_ATTR_NUMBERFORMAT_VALUE ); + + if( !pNumFormatItem ) + return; + + sal_uLong nFmt = pNumFormatItem->GetValue(); + + Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter(); + rFmtFldMax.SetFormatKey(nFmt); + Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter(); + rFmtFldMin.SetFormatKey(nFmt); + Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter(); + rFmtFldOrigin.SetFormatKey(nFmt); + + if( pNumFormatter ) + { + SvNumFormatType eType = pNumFormatter->GetType( nFmt ); + if( eType == SvNumFormatType::DATE ) + { + // for intervals use standard format for dates (so you can enter a number of days) + const SvNumberformat* pFormat = pNumFormatter->GetEntry( nFmt ); + if( pFormat ) + nFmt = pNumFormatter->GetStandardIndex( pFormat->GetLanguage()); + else + nFmt = pNumFormatter->GetStandardIndex(); + } + else if( eType == SvNumFormatType::DATETIME ) + { + // for intervals use time format for date times + const SvNumberformat* pFormat = pNumFormatter->GetEntry( nFmt ); + if( pFormat ) + nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::TIME, pFormat->GetLanguage() ); + else + nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::TIME ); + + // tdf#141625 give enough space to see full date+time + int nWidestTime(m_xFmtFldMin->get_pixel_size(getWidestDateTime(Application::GetSettings().GetLocaleDataWrapper(), true)).Width()); + int nWidthChars = std::ceil(nWidestTime / m_xFmtFldMin->get_approximate_digit_width()) + 1; + m_xFmtFldMin->set_width_chars(nWidthChars); + m_xFmtFldMax->set_width_chars(nWidthChars); + } + + if( m_nAxisType == chart2::AxisType::DATE && ( eType != SvNumFormatType::DATE && eType != SvNumFormatType::DATETIME) ) + { + const SvNumberformat* pFormat = pNumFormatter->GetEntry( nFmt ); + if( pFormat ) + nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::DATE, pFormat->GetLanguage() ); + else + nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::DATE ); + + rFmtFldMax.SetFormatKey(nFmt); + rFmtFldMin.SetFormatKey(nFmt); + rFmtFldOrigin.SetFormatKey(nFmt); + } + } + + m_xFmtFldStepMain->GetFormatter().SetFormatKey(nFmt); +} + +void ScaleTabPage::ShowAxisOrigin( bool bShowOrigin ) +{ + m_bShowAxisOrigin = bShowOrigin; + if( !AxisHelper::isAxisPositioningEnabled() ) + m_bShowAxisOrigin = true; +} + +bool ScaleTabPage::ShowWarning(TranslateId pResIdMessage, weld::Widget* pControl /* = nullptr */) +{ + if (!pResIdMessage) + return false; + + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + SchResId(pResIdMessage))); + xWarn->run(); + if (pControl) + { + pControl->grab_focus(); + weld::Entry* pEdit = dynamic_cast<weld::Entry*>(pControl); + if (pEdit) + pEdit->select_region(0, -1); + } + return true; +} + +void ScaleTabPage::HideAllControls() +{ + // We need to set these controls invisible when the class is instantiated + // since some code in EnableControls() depends on that logic. The real + // visibility of these controls depend on axis data type, and are + // set in EnableControls(). + + m_xBxType->hide(); + m_xCbxLogarithm->hide(); + m_xBxMinMax->hide(); + m_xTxtMain->hide(); + m_xFmtFldStepMain->hide(); + m_xMt_MainDateStep->hide(); + m_xLB_MainTimeUnit->hide(); + m_xCbxAutoStepMain->hide(); + m_xTxtHelpCount->hide(); + m_xTxtHelp->hide(); + m_xMtStepHelp->hide(); + m_xCbxAutoStepHelp->hide(); + m_xBxOrigin->hide(); + m_xBxResolution->hide(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Scale.hxx b/chart2/source/controller/dialogs/tp_Scale.hxx new file mode 100644 index 000000000..b90d3ef20 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Scale.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 <sfx2/tabdlg.hxx> +#include <unotools/resmgr.hxx> + +namespace chart +{ + +class ScaleTabPage : public SfxTabPage +{ +public: + ScaleTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~ScaleTabPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + virtual DeactivateRC DeactivatePage( SfxItemSet* pItemSet ) override; + + void SetNumFormatter( SvNumberFormatter* pFormatter ); + void SetNumFormat(); + + void ShowAxisOrigin( bool bShowOrigin ); + +private: + double fMin; + double fMax; + double fStepMain; + sal_Int32 nStepHelp; + double fOrigin; + sal_Int32 m_nTimeResolution; + sal_Int32 m_nMainTimeUnit; + sal_Int32 m_nHelpTimeUnit; + int m_nAxisType; + bool m_bAllowDateAxis; + SvNumberFormatter* pNumFormatter; + + bool m_bShowAxisOrigin; + + std::unique_ptr<weld::CheckButton> m_xCbxReverse; + std::unique_ptr<weld::CheckButton> m_xCbxLogarithm; + std::unique_ptr<weld::Widget> m_xBxType; + std::unique_ptr<weld::ComboBox> m_xLB_AxisType; + std::unique_ptr<weld::Widget> m_xBxMinMax; + std::unique_ptr<weld::FormattedSpinButton> m_xFmtFldMin; + std::unique_ptr<weld::CheckButton> m_xCbxAutoMin; + std::unique_ptr<weld::FormattedSpinButton> m_xFmtFldMax; + std::unique_ptr<weld::CheckButton> m_xCbxAutoMax; + std::unique_ptr<weld::Widget> m_xBxResolution; + std::unique_ptr<weld::ComboBox> m_xLB_TimeResolution; + std::unique_ptr<weld::CheckButton> m_xCbx_AutoTimeResolution; + std::unique_ptr<weld::Label> m_xTxtMain; + std::unique_ptr<weld::FormattedSpinButton> m_xFmtFldStepMain; + std::unique_ptr<weld::SpinButton> m_xMt_MainDateStep; + std::unique_ptr<weld::ComboBox> m_xLB_MainTimeUnit; + std::unique_ptr<weld::CheckButton> m_xCbxAutoStepMain; + std::unique_ptr<weld::Label> m_xTxtHelpCount; + std::unique_ptr<weld::Label> m_xTxtHelp; + std::unique_ptr<weld::SpinButton> m_xMtStepHelp; + std::unique_ptr<weld::ComboBox> m_xLB_HelpTimeUnit; + std::unique_ptr<weld::CheckButton> m_xCbxAutoStepHelp; + std::unique_ptr<weld::FormattedSpinButton> m_xFmtFldOrigin; + std::unique_ptr<weld::CheckButton> m_xCbxAutoOrigin; + std::unique_ptr<weld::Widget> m_xBxOrigin; + + void EnableControls(); + + DECL_LINK(SelectAxisTypeHdl, weld::ComboBox&, void); + DECL_LINK(EnableValueHdl, weld::Toggleable&, void); + + /** shows a warning window due to an invalid input. + + @param pResIdMessage + The resource identifier that represents the localized warning text. + If this is nullptr, no warning is shown and false is returned. + + @param pControl + If non-NULL, contains a pointer to the control in which the + erroneous value was in. This method gives this control the focus + and selects its content. + + @return false, if nResIdMessage was 0, true otherwise + */ + bool ShowWarning(TranslateId pResIdMessage, weld::Widget* pControl); + + void HideAllControls(); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_SeriesToAxis.cxx b/chart2/source/controller/dialogs/tp_SeriesToAxis.cxx new file mode 100644 index 000000000..3ffbc3642 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_SeriesToAxis.cxx @@ -0,0 +1,248 @@ +/* -*- 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 "tp_SeriesToAxis.hxx" + +#include <chartview/ChartSfxItemIds.hxx> + +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/ilstitem.hxx> + +#include <com/sun/star/chart/MissingValueTreatment.hpp> + +namespace chart +{ + +SchOptionTabPage::SchOptionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_SeriesToAxis.ui", "TP_OPTIONS", &rInAttrs) + , m_nAllSeriesAxisIndex(0) + , m_bProvidesSecondaryYAxis(true) + , m_bProvidesOverlapAndGapWidth(false) + , m_bProvidesBarConnectors(false) + , m_xGrpAxis(m_xBuilder->weld_widget("frameGrpAxis")) + , m_xRbtAxis1(m_xBuilder->weld_radio_button("RBT_OPT_AXIS_1")) + , m_xRbtAxis2(m_xBuilder->weld_radio_button("RBT_OPT_AXIS_2")) + , m_xGrpBar(m_xBuilder->weld_widget("frameSettings")) + , m_xMTGap(m_xBuilder->weld_metric_spin_button("MT_GAP", FieldUnit::PERCENT)) + , m_xMTOverlap(m_xBuilder->weld_metric_spin_button("MT_OVERLAP", FieldUnit::PERCENT)) + , m_xCBConnect(m_xBuilder->weld_check_button("CB_CONNECTOR")) + , m_xCBAxisSideBySide(m_xBuilder->weld_check_button("CB_BARS_SIDE_BY_SIDE")) + , m_xGrpPlotOptions(m_xBuilder->weld_widget("frameFL_PLOT_OPTIONS")) + , m_xGridPlotOptions(m_xBuilder->weld_widget("gridPLOT_OPTIONS")) + , m_xRB_DontPaint(m_xBuilder->weld_radio_button("RB_DONT_PAINT")) + , m_xRB_AssumeZero(m_xBuilder->weld_radio_button("RB_ASSUME_ZERO")) + , m_xRB_ContinueLine(m_xBuilder->weld_radio_button("RB_CONTINUE_LINE")) + , m_xCBIncludeHiddenCells(m_xBuilder->weld_check_button("CB_INCLUDE_HIDDEN_CELLS")) + , m_xCBHideLegendEntry(m_xBuilder->weld_check_button("CB_LEGEND_ENTRY_HIDDEN")) +{ + m_xRbtAxis1->connect_toggled(LINK(this, SchOptionTabPage, EnableHdl)); + m_xRbtAxis2->connect_toggled(LINK(this, SchOptionTabPage, EnableHdl)); +} + +SchOptionTabPage::~SchOptionTabPage() +{ +} + +IMPL_LINK_NOARG(SchOptionTabPage, EnableHdl, weld::Toggleable&, void) +{ + if( m_nAllSeriesAxisIndex == 0 ) + m_xCBAxisSideBySide->set_sensitive( m_xRbtAxis2->get_active()); + else if( m_nAllSeriesAxisIndex == 1 ) + m_xCBAxisSideBySide->set_sensitive( m_xRbtAxis1->get_active()); +} + +std::unique_ptr<SfxTabPage> SchOptionTabPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rOutAttrs) +{ + return std::make_unique<SchOptionTabPage>(pPage, pController, *rOutAttrs); +} + +bool SchOptionTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + if(m_xRbtAxis2->get_active()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS,CHART_AXIS_SECONDARY_Y)); + else + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS,CHART_AXIS_PRIMARY_Y)); + + if(m_xMTGap->get_visible()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_BAR_GAPWIDTH,static_cast< sal_Int32 >( m_xMTGap->get_value(FieldUnit::PERCENT)))); + + if(m_xMTOverlap->get_visible()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_BAR_OVERLAP,static_cast< sal_Int32 >( m_xMTOverlap->get_value(FieldUnit::PERCENT)))); + + if(m_xCBConnect->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_BAR_CONNECT,m_xCBConnect->get_active())); + + // model property is "group bars per axis", UI feature is the other way + // round: "show bars side by side" + if(m_xCBAxisSideBySide->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_GROUP_BARS_PER_AXIS, ! m_xCBAxisSideBySide->get_active())); + + if(m_xRB_DontPaint->get_active()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT,css::chart::MissingValueTreatment::LEAVE_GAP)); + else if(m_xRB_AssumeZero->get_active()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT,css::chart::MissingValueTreatment::USE_ZERO)); + else if(m_xRB_ContinueLine->get_active()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT,css::chart::MissingValueTreatment::CONTINUE)); + + if (m_xCBIncludeHiddenCells->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_INCLUDE_HIDDEN_CELLS, m_xCBIncludeHiddenCells->get_active())); + + if(m_xCBHideLegendEntry->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_HIDE_LEGEND_ENTRY, m_xCBHideLegendEntry->get_active())); + + return true; +} + +void SchOptionTabPage::Reset(const SfxItemSet* rInAttrs) +{ + m_xRbtAxis1->set_active(true); + m_xRbtAxis2->set_active(false); + if (const SfxInt32Item* pAxisItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS)) + { + tools::Long nVal = pAxisItem->GetValue(); + if(nVal==CHART_AXIS_SECONDARY_Y) + { + m_xRbtAxis2->set_active(true); + m_xRbtAxis1->set_active(false); + } + } + + tools::Long nTmp; + if (const SfxInt32Item* pGapWidthItem = rInAttrs->GetItemIfSet(SCHATTR_BAR_GAPWIDTH)) + { + nTmp = static_cast<tools::Long>(pGapWidthItem->GetValue()); + m_xMTGap->set_value(nTmp, FieldUnit::PERCENT); + } + + if (const SfxInt32Item* pOverlapItem = rInAttrs->GetItemIfSet(SCHATTR_BAR_OVERLAP)) + { + nTmp = static_cast<tools::Long>(pOverlapItem->GetValue()); + m_xMTOverlap->set_value(nTmp, FieldUnit::PERCENT); + } + + if (const SfxBoolItem* pConnectItem = rInAttrs->GetItemIfSet(SCHATTR_BAR_CONNECT)) + { + bool bCheck = pConnectItem->GetValue(); + m_xCBConnect->set_active(bCheck); + } + + if (const SfxInt32Item* pAllSeriesItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_FOR_ALL_SERIES)) + { + m_nAllSeriesAxisIndex = pAllSeriesItem->GetValue(); + m_xCBAxisSideBySide->set_sensitive(false); + } + if (const SfxBoolItem* pPerAxisItem = rInAttrs->GetItemIfSet(SCHATTR_GROUP_BARS_PER_AXIS)) + { + // model property is "group bars per axis", UI feature is the other way + // round: "show bars side by side" + bool bCheck = ! pPerAxisItem->GetValue(); + m_xCBAxisSideBySide->set_active( bCheck ); + } + else + { + m_xCBAxisSideBySide->hide(); + } + + //missing value treatment + { + std::vector< sal_Int32 > aMissingValueTreatments; + if (const SfxIntegerListItem* pValueTreatmentsItem = rInAttrs->GetItemIfSet(SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS)) + aMissingValueTreatments = pValueTreatmentsItem->GetList(); + + const SfxInt32Item* pMissingValueTreatmentItem; + if ( aMissingValueTreatments.size()>1 && + (pMissingValueTreatmentItem = rInAttrs->GetItemIfSet(SCHATTR_MISSING_VALUE_TREATMENT)) ) + { + m_xRB_DontPaint->set_sensitive(false); + m_xRB_AssumeZero->set_sensitive(false); + m_xRB_ContinueLine->set_sensitive(false); + + for(int nVal : aMissingValueTreatments) + { + if(nVal==css::chart::MissingValueTreatment::LEAVE_GAP) + m_xRB_DontPaint->set_sensitive(true); + else if(nVal==css::chart::MissingValueTreatment::USE_ZERO) + m_xRB_AssumeZero->set_sensitive(true); + else if(nVal==css::chart::MissingValueTreatment::CONTINUE) + m_xRB_ContinueLine->set_sensitive(true); + } + + tools::Long nVal=pMissingValueTreatmentItem->GetValue(); + if(nVal==css::chart::MissingValueTreatment::LEAVE_GAP) + m_xRB_DontPaint->set_active(true); + else if(nVal==css::chart::MissingValueTreatment::USE_ZERO) + m_xRB_AssumeZero->set_active(true); + else if(nVal==css::chart::MissingValueTreatment::CONTINUE) + m_xRB_ContinueLine->set_active(true); + } + else + { + m_xGridPlotOptions->hide(); + } + } + + // Include hidden cells + if (const SfxBoolItem* pHiddenCellsItem = rInAttrs->GetItemIfSet(SCHATTR_INCLUDE_HIDDEN_CELLS)) + { + bool bVal = pHiddenCellsItem->GetValue(); + m_xCBIncludeHiddenCells->set_active(bVal); + } + else + { + m_xCBIncludeHiddenCells->hide(); + // check if the radiobutton guys above + // are visible. If they aren't, we can + // as well hide the whole frame + if(!m_xGridPlotOptions->get_visible()) + m_xGrpPlotOptions->hide(); + } + + if (const SfxBoolItem* pEntryItem = rInAttrs->GetItemIfSet(SCHATTR_HIDE_LEGEND_ENTRY)) + { + bool bVal = pEntryItem->GetValue(); + m_xCBHideLegendEntry->set_active(bVal); + } + + AdaptControlPositionsAndVisibility(); +} + +void SchOptionTabPage::Init( bool bProvidesSecondaryYAxis, bool bProvidesOverlapAndGapWidth, bool bProvidesBarConnectors ) +{ + m_bProvidesSecondaryYAxis = bProvidesSecondaryYAxis; + m_bProvidesOverlapAndGapWidth = bProvidesOverlapAndGapWidth; + m_bProvidesBarConnectors = bProvidesBarConnectors; + + AdaptControlPositionsAndVisibility(); +} + +void SchOptionTabPage::AdaptControlPositionsAndVisibility() +{ + m_xGrpAxis->set_visible(m_bProvidesSecondaryYAxis); + m_xGrpBar->set_visible(m_bProvidesOverlapAndGapWidth); + m_xCBConnect->set_visible(m_bProvidesBarConnectors); + + if (!m_xMTGap->get_visible() && !m_xMTOverlap->get_visible()) + m_xGrpBar->hide(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_SeriesToAxis.hxx b/chart2/source/controller/dialogs/tp_SeriesToAxis.hxx new file mode 100644 index 000000000..6b163f3c8 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_SeriesToAxis.hxx @@ -0,0 +1,77 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +namespace weld { + class CheckButton; + class MetricSpinButton; + class RadioButton; + class ToggleButton; + class Widget; +} + +namespace chart +{ + +class SchOptionTabPage : public SfxTabPage +{ +public: + SchOptionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~SchOptionTabPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + + void Init( bool bProvidesSecondaryYAxis, bool bProvidesOverlapAndGapWidth, bool bProvidesBarConnectors ); + +private: //methods + void AdaptControlPositionsAndVisibility(); + +private: //member + DECL_LINK(EnableHdl, weld::Toggleable&, void ); + + sal_Int32 m_nAllSeriesAxisIndex; + + bool m_bProvidesSecondaryYAxis; + bool m_bProvidesOverlapAndGapWidth; + bool m_bProvidesBarConnectors; + + std::unique_ptr<weld::Widget> m_xGrpAxis; + std::unique_ptr<weld::RadioButton> m_xRbtAxis1; + std::unique_ptr<weld::RadioButton> m_xRbtAxis2; + std::unique_ptr<weld::Widget> m_xGrpBar; + std::unique_ptr<weld::MetricSpinButton> m_xMTGap; + std::unique_ptr<weld::MetricSpinButton> m_xMTOverlap; + std::unique_ptr<weld::CheckButton> m_xCBConnect; + std::unique_ptr<weld::CheckButton> m_xCBAxisSideBySide; + std::unique_ptr<weld::Widget> m_xGrpPlotOptions; + std::unique_ptr<weld::Widget> m_xGridPlotOptions; + std::unique_ptr<weld::RadioButton> m_xRB_DontPaint; + std::unique_ptr<weld::RadioButton> m_xRB_AssumeZero; + std::unique_ptr<weld::RadioButton> m_xRB_ContinueLine; + std::unique_ptr<weld::CheckButton> m_xCBIncludeHiddenCells; + std::unique_ptr<weld::CheckButton> m_xCBHideLegendEntry; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_TitleRotation.cxx b/chart2/source/controller/dialogs/tp_TitleRotation.cxx new file mode 100644 index 000000000..2cc802f70 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_TitleRotation.cxx @@ -0,0 +1,123 @@ +/* -*- 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 "tp_TitleRotation.hxx" + +#include <chartview/ChartSfxItemIds.hxx> +#include <TextDirectionListBox.hxx> + +#include <editeng/eeitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <svx/sdangitm.hxx> + +namespace chart +{ + +SchAlignmentTabPage::SchAlignmentTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs, bool bWithRotation) + : SfxTabPage(pPage, pController, "modules/schart/ui/titlerotationtabpage.ui", "TitleRotationTabPage", &rInAttrs) + , m_xFtRotate(m_xBuilder->weld_label("degreeL")) + , m_xNfRotate(m_xBuilder->weld_metric_spin_button("OrientDegree", FieldUnit::DEGREE)) + , m_xCbStacked(m_xBuilder->weld_check_button("stackedCB")) + , m_xFtTextDirection(m_xBuilder->weld_label("textdirL")) + , m_xFtABCD(m_xBuilder->weld_label("labelABCD")) + , m_xLbTextDirection(new TextDirectionListBox(m_xBuilder->weld_combo_box("textdirLB"))) + , m_xCtrlDial(new svx::DialControl) + , m_xCtrlDialWin(new weld::CustomWeld(*m_xBuilder, "dialCtrl", *m_xCtrlDial)) +{ + m_xCtrlDial->SetLinkedField(m_xNfRotate.get()); + m_xCtrlDial->SetText(m_xFtABCD->get_label()); + m_xCbStacked->connect_toggled(LINK(this, SchAlignmentTabPage, StackedToggleHdl)); + + m_xCtrlDialWin->set_sensitive(true); + m_xNfRotate->set_sensitive(true); + m_xCbStacked->set_sensitive(true); + m_xFtRotate->set_sensitive(true); + + if( !bWithRotation ) + { + m_xCtrlDialWin->hide(); + m_xNfRotate->hide(); + m_xCbStacked->hide(); + m_xFtRotate->hide(); + } +} + +IMPL_LINK_NOARG(SchAlignmentTabPage, StackedToggleHdl, weld::Toggleable&, void) +{ + bool bActive = m_xCbStacked->get_active(); + m_xNfRotate->set_sensitive(!bActive); + m_xCtrlDialWin->set_sensitive(!bActive); + m_xCtrlDial->StyleUpdated(); + m_xFtRotate->set_sensitive(!bActive); +} + +SchAlignmentTabPage::~SchAlignmentTabPage() +{ + m_xCtrlDialWin.reset(); + m_xCtrlDial.reset(); + m_xLbTextDirection.reset(); +} + +std::unique_ptr<SfxTabPage> SchAlignmentTabPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rInAttrs) +{ + return std::make_unique<SchAlignmentTabPage>(pPage, pController, *rInAttrs); +} + +std::unique_ptr<SfxTabPage> SchAlignmentTabPage::CreateWithoutRotation(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rInAttrs) +{ + return std::make_unique<SchAlignmentTabPage>(pPage, pController, *rInAttrs, false); +} + +bool SchAlignmentTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + //Since 04/1998 text can be rotated by an arbitrary angle: SCHATTR_TEXT_DEGREES + bool bStacked = m_xCbStacked->get_active(); + rOutAttrs->Put( SfxBoolItem( SCHATTR_TEXT_STACKED, bStacked ) ); + + Degree100 nDegrees = bStacked ? 0_deg100 : m_xCtrlDial->GetRotation(); + rOutAttrs->Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, nDegrees ) ); + + SvxFrameDirection aDirection( m_xLbTextDirection->get_active_id() ); + rOutAttrs->Put( SvxFrameDirectionItem( aDirection, EE_PARA_WRITINGDIR ) ); + + return true; +} + +void SchAlignmentTabPage::Reset(const SfxItemSet* rInAttrs) +{ + const SfxPoolItem* pItem = GetItem( *rInAttrs, SCHATTR_TEXT_DEGREES ); + + Degree100 nDegrees = pItem ? static_cast<const SdrAngleItem*>(pItem)->GetValue() : 0_deg100; + m_xCtrlDial->SetRotation( nDegrees ); + + pItem = GetItem( *rInAttrs, SCHATTR_TEXT_STACKED ); + bool bStacked = pItem && static_cast<const SfxBoolItem*>(pItem)->GetValue(); + m_xCbStacked->set_active(bStacked); + StackedToggleHdl(*m_xCbStacked); + + if( const SvxFrameDirectionItem* pDirectionItem = rInAttrs->GetItemIfSet(EE_PARA_WRITINGDIR) ) + m_xLbTextDirection->set_active_id(pDirectionItem->GetValue()); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_TitleRotation.hxx b/chart2/source/controller/dialogs/tp_TitleRotation.hxx new file mode 100644 index 000000000..b303e4d35 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_TitleRotation.hxx @@ -0,0 +1,62 @@ +/* -*- 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 <sfx2/tabdlg.hxx> +#include <svx/dialcontrol.hxx> + +namespace chart { class TextDirectionListBox; } +namespace weld { + class CheckButton; + class CustomWeld; + class Label; + class SpinButton; + class ToggleButton; +} + +namespace chart +{ + +class SchAlignmentTabPage : public SfxTabPage +{ +private: + std::unique_ptr<weld::Label> m_xFtRotate; + std::unique_ptr<weld::MetricSpinButton> m_xNfRotate; + std::unique_ptr<weld::CheckButton> m_xCbStacked; + std::unique_ptr<weld::Label> m_xFtTextDirection; + std::unique_ptr<weld::Label> m_xFtABCD; + std::unique_ptr<TextDirectionListBox> m_xLbTextDirection; + std::unique_ptr<svx::DialControl> m_xCtrlDial; + std::unique_ptr<weld::CustomWeld> m_xCtrlDialWin; + + DECL_LINK(StackedToggleHdl, weld::Toggleable&, void); + +public: + SchAlignmentTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs, bool bWithRotation = true); + virtual ~SchAlignmentTabPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + static std::unique_ptr<SfxTabPage> CreateWithoutRotation(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Trendline.cxx b/chart2/source/controller/dialogs/tp_Trendline.cxx new file mode 100644 index 000000000..fe25959bd --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Trendline.cxx @@ -0,0 +1,59 @@ +/* -*- 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 "tp_Trendline.hxx" + +namespace chart +{ + +TrendlineTabPage::TrendlineTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_Trendline.ui", "TP_TRENDLINE", &rInAttrs) + , m_aTrendlineResources(*m_xBuilder, rInAttrs) +{ +} + +std::unique_ptr<SfxTabPage> TrendlineTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique<TrendlineTabPage>(pPage, pController, *rOutAttrs); +} + +bool TrendlineTabPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + m_aTrendlineResources.FillItemSet( rOutAttrs ); + return true; +} + +void TrendlineTabPage::Reset( const SfxItemSet* rInAttrs ) +{ + m_aTrendlineResources.Reset( *rInAttrs ); +} + +void TrendlineTabPage::SetNumFormatter( SvNumberFormatter* pNumFormatter ) +{ + m_aTrendlineResources.SetNumFormatter( pNumFormatter ); +} + +void TrendlineTabPage::SetNbPoints( sal_Int32 nNbPoints ) +{ + m_aTrendlineResources.SetNbPoints( nNbPoints ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Trendline.hxx b/chart2/source/controller/dialogs/tp_Trendline.hxx new file mode 100644 index 000000000..3a240af38 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Trendline.hxx @@ -0,0 +1,46 @@ +/* -*- 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 "res_Trendline.hxx" + +#include <sfx2/tabdlg.hxx> + +namespace chart +{ + +class TrendlineTabPage : public SfxTabPage +{ +public: + TrendlineTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + + void SetNumFormatter( SvNumberFormatter* pFormatter ); + void SetNbPoints( sal_Int32 nNbPoints ); + +private: + TrendlineResources m_aTrendlineResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.cxx b/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.cxx new file mode 100644 index 000000000..be6948b51 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.cxx @@ -0,0 +1,159 @@ +/* -*- 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 "tp_Wizard_TitlesAndObjects.hxx" +#include <res_Titles.hxx> +#include <res_LegendPosition.hxx> +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <Diagram.hxx> +#include <AxisHelper.hxx> +#include <ControllerLockGuard.hxx> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +TitlesAndObjectsTabPage::TitlesAndObjectsTabPage(weld::Container* pPage, weld::DialogController* pController, + const rtl::Reference<::chart::ChartModel>& xChartModel, + const uno::Reference< uno::XComponentContext >& xContext ) + : OWizardPage(pPage, pController, "modules/schart/ui/wizelementspage.ui", "WizElementsPage") + , m_xTitleResources(new TitleResources(*m_xBuilder, false)) + , m_xLegendPositionResources(new LegendPositionResources(*m_xBuilder, xContext)) + , m_xChartModel(xChartModel) + , m_xCC(xContext) + , m_bCommitToModel(true) + , m_aTimerTriggeredControllerLock( m_xChartModel ) + , m_xCB_Grid_X(m_xBuilder->weld_check_button("x")) + , m_xCB_Grid_Y(m_xBuilder->weld_check_button("y")) + , m_xCB_Grid_Z(m_xBuilder->weld_check_button("z")) +{ + m_xTitleResources->connect_changed( LINK( this, TitlesAndObjectsTabPage, ChangeEditHdl )); + m_xLegendPositionResources->SetChangeHdl( LINK( this, TitlesAndObjectsTabPage, ChangeHdl )); + + m_xCB_Grid_X->connect_toggled( LINK( this, TitlesAndObjectsTabPage, ChangeCheckBoxHdl )); + m_xCB_Grid_Y->connect_toggled( LINK( this, TitlesAndObjectsTabPage, ChangeCheckBoxHdl )); + m_xCB_Grid_Z->connect_toggled( LINK( this, TitlesAndObjectsTabPage, ChangeCheckBoxHdl )); +} + +TitlesAndObjectsTabPage::~TitlesAndObjectsTabPage() +{ +} + +void TitlesAndObjectsTabPage::initializePage() +{ + m_bCommitToModel = false; + + //init titles + { + TitleDialogData aTitleInput; + aTitleInput.readFromModel( m_xChartModel ); + m_xTitleResources->writeToResources( aTitleInput ); + } + + //init legend + { + m_xLegendPositionResources->writeToResources( m_xChartModel ); + } + + //init grid checkboxes + { + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartModel ); + uno::Sequence< sal_Bool > aPossibilityList; + uno::Sequence< sal_Bool > aExistenceList; + AxisHelper::getAxisOrGridPossibilities( aPossibilityList, xDiagram, false ); + AxisHelper::getAxisOrGridExistence( aExistenceList, xDiagram, false ); + m_xCB_Grid_X->set_sensitive( aPossibilityList[0] ); + m_xCB_Grid_Y->set_sensitive( aPossibilityList[1] ); + m_xCB_Grid_Z->set_sensitive( aPossibilityList[2] ); + m_xCB_Grid_X->set_active( aExistenceList[0] ); + m_xCB_Grid_Y->set_active( aExistenceList[1] ); + m_xCB_Grid_Z->set_active( aExistenceList[2] ); + } + + m_bCommitToModel = true; +} + +bool TitlesAndObjectsTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ ) +{ + if( m_xTitleResources->get_value_changed_from_saved() ) //titles may have changed in the meanwhile + commitToModel(); + return true;//return false if this page should not be left +} + +void TitlesAndObjectsTabPage::commitToModel() +{ + m_aTimerTriggeredControllerLock.startTimer(); + rtl::Reference<::chart::ChartModel> xModel = m_xChartModel; + + ControllerLockGuardUNO aLockedControllers( xModel ); + + //commit title changes to model + { + TitleDialogData aTitleOutput; + m_xTitleResources->readFromResources( aTitleOutput ); + aTitleOutput.writeDifferenceToModel( xModel, m_xCC ); + m_xTitleResources->save_value(); + } + + //commit legend changes to model + { + m_xLegendPositionResources->writeToModel( xModel ); + } + + //commit grid changes to model + { + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + uno::Sequence< sal_Bool > aOldExistenceList; + AxisHelper::getAxisOrGridExistence( aOldExistenceList, xDiagram, false ); + uno::Sequence< sal_Bool > aNewExistenceList(aOldExistenceList); + sal_Bool* pNewExistenceList = aNewExistenceList.getArray(); + pNewExistenceList[0] = m_xCB_Grid_X->get_active(); + pNewExistenceList[1] = m_xCB_Grid_Y->get_active(); + pNewExistenceList[2] = m_xCB_Grid_Z->get_active(); + AxisHelper::changeVisibilityOfGrids( xDiagram + , aOldExistenceList, aNewExistenceList ); + } +} + +IMPL_LINK_NOARG(TitlesAndObjectsTabPage, ChangeCheckBoxHdl, weld::Toggleable&, void) +{ + ChangeHdl(nullptr); +} + +IMPL_LINK_NOARG(TitlesAndObjectsTabPage, ChangeEditHdl, weld::Entry&, void) +{ + ChangeHdl(nullptr); +} + +IMPL_LINK_NOARG(TitlesAndObjectsTabPage, ChangeHdl, LinkParamNone*, void) +{ + if( m_bCommitToModel ) + commitToModel(); +} + +bool TitlesAndObjectsTabPage::canAdvance() const +{ + return false; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.hxx b/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.hxx new file mode 100644 index 000000000..f06a3e7ec --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.hxx @@ -0,0 +1,72 @@ +/* -*- 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 <TimerTriggeredControllerLock.hxx> + +#include <vcl/wizardmachine.hxx> +#include <rtl/ref.hxx> + +#include <memory> + +namespace chart { class LegendPositionResources; } +namespace chart { class TitleResources; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class ChartModel; + +class TitlesAndObjectsTabPage final : public vcl::OWizardPage +{ +public: + TitlesAndObjectsTabPage(weld::Container* pPage, weld::DialogController* pController, + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference< css::uno::XComponentContext >& xContext); + virtual ~TitlesAndObjectsTabPage() override; + + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason eReason ) override; + virtual bool canAdvance() const override; + +private: + void commitToModel(); + DECL_LINK( ChangeHdl, LinkParamNone*, void ); + DECL_LINK( ChangeEditHdl, weld::Entry&, void ); + DECL_LINK( ChangeCheckBoxHdl, weld::Toggleable&, void ); + + std::unique_ptr< TitleResources > m_xTitleResources; + std::unique_ptr< LegendPositionResources > m_xLegendPositionResources; + + rtl::Reference<::chart::ChartModel> m_xChartModel; + css::uno::Reference< css::uno::XComponentContext> m_xCC; + + bool m_bCommitToModel; + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + std::unique_ptr<weld::CheckButton> m_xCB_Grid_X; + std::unique_ptr<weld::CheckButton> m_xCB_Grid_Y; + std::unique_ptr<weld::CheckButton> m_xCB_Grid_Z; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx b/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx new file mode 100644 index 000000000..3918a296e --- /dev/null +++ b/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx @@ -0,0 +1,357 @@ +/* -*- 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 <DrawViewWrapper.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <ConfigurationAccess.hxx> + +#include <unotools/lingucfg.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/langitem.hxx> +#include <svl/intitem.hxx> +#include <svl/itempool.hxx> +#include <svx/obj3d.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdetc.hxx> +#include <svx/svdoutl.hxx> +#include <svx/svxids.hrc> +#include <editeng/fhgtitem.hxx> +#include <osl/diagnose.h> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/drawing/XShape.hpp> + +#include <sfx2/objsh.hxx> +#include <svx/helperhittest3d.hxx> + +using namespace ::com::sun::star; + +namespace chart +{ + +namespace +{ + short lcl_getHitTolerance( OutputDevice const * pOutDev ) + { + const short HITPIX=2; //hit-tolerance in pixel + short nHitTolerance = 50; + if(pOutDev) + nHitTolerance = static_cast<short>(pOutDev->PixelToLogic(Size(HITPIX,0)).Width()); + return nHitTolerance; + } + +// this code is copied from sfx2/source/doc/objembed.cxx. It is a workaround to +// get the reference device (e.g. printer) from the parent document +OutputDevice * lcl_GetParentRefDevice( const uno::Reference< frame::XModel > & xModel ) +{ + SfxObjectShell* pParent = SfxObjectShell::GetParentShell(xModel); + if ( pParent ) + return pParent->GetDocumentRefDev(); + return nullptr; +} + +} + +DrawViewWrapper::DrawViewWrapper( + SdrModel& rSdrModel, + OutputDevice* pOut) +: E3dView(rSdrModel, pOut) + ,m_pMarkHandleProvider(nullptr) + ,m_apOutliner(SdrMakeOutliner(OutlinerMode::TextObject, rSdrModel)) + ,m_bRestoreMapMode( false ) +{ + SetBufferedOutputAllowed(true); + SetBufferedOverlayAllowed(true); + SetPagePaintingAllowed(true); + + // #i12587# support for shapes in chart + SdrOutliner* pOutliner = getOutliner(); + SfxItemPool* pOutlinerPool = ( pOutliner ? pOutliner->GetEditTextObjectPool() : nullptr ); + if ( pOutlinerPool ) + { + SvtLinguConfig aLinguConfig; + SvtLinguOptions aLinguOptions; + aLinguConfig.GetOptions( aLinguOptions ); + pOutlinerPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOptions.nDefaultLanguage, EE_CHAR_LANGUAGE ) ); + pOutlinerPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOptions.nDefaultLanguage_CJK, EE_CHAR_LANGUAGE_CJK ) ); + pOutlinerPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOptions.nDefaultLanguage_CTL, EE_CHAR_LANGUAGE_CTL ) ); + + // set font height without changing SdrEngineDefaults + pOutlinerPool->SetPoolDefaultItem( SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT ) ); // 12pt + } + + // #i121463# Use big handles by default + SetMarkHdlSizePixel(9); + + ReInit(); +} + +void DrawViewWrapper::ReInit() +{ + OutputDevice* pOutDev = GetFirstOutputDevice(); + Size aOutputSize(100,100); + if(pOutDev) + aOutputSize = pOutDev->GetOutputSize(); + + mbPageVisible = false; + mbPageBorderVisible = false; + mbBordVisible = false; + mbGridVisible = false; + mbHlplVisible = false; + + SetNoDragXorPolys(true);//for interactive 3D resize-dragging: paint only a single rectangle (not a simulated 3D object) + + //a correct work area is at least necessary for correct values in the position and size dialog + tools::Rectangle aRect(Point(0,0), aOutputSize); + SetWorkArea(aRect); + + ShowSdrPage(GetModel()->GetPage(0)); +} + +DrawViewWrapper::~DrawViewWrapper() +{ + maComeBackIdle.Stop();//@todo this should be done in destructor of base class + UnmarkAllObj();//necessary to avoid a paint call during the destructor hierarchy +} + +SdrPageView* DrawViewWrapper::GetPageView() const +{ + SdrPageView* pSdrPageView = GetSdrPageView(); + return pSdrPageView; +}; + +void DrawViewWrapper::SetMarkHandles(SfxViewShell* pOtherShell) +{ + if( m_pMarkHandleProvider && m_pMarkHandleProvider->getMarkHandles( maHdlList ) ) + return; + else + SdrView::SetMarkHandles(pOtherShell); +} + +SdrObject* DrawViewWrapper::getHitObject( const Point& rPnt ) const +{ + SdrPageView* pSdrPageView = GetPageView(); + SdrObject* pRet = SdrView::PickObj(rPnt, lcl_getHitTolerance( GetFirstOutputDevice() ), pSdrPageView, + SdrSearchOptions::DEEP | SdrSearchOptions::TESTMARKABLE); + + if( pRet ) + { + // ignore some special shapes + OUString aShapeName = pRet->GetName(); + + // return right away if it is a field button + if (aShapeName.startsWith("FieldButton")) + return pRet; + + if( aShapeName.match("PlotAreaIncludingAxes") || aShapeName.match("PlotAreaExcludingAxes") ) + { + pRet->SetMarkProtect( true ); + return getHitObject( rPnt ); + } + + //3d objects need a special treatment + //because the simple PickObj method is not accurate in this case for performance reasons + E3dObject* pE3d = dynamic_cast< E3dObject* >(pRet); + if( pE3d ) + { + E3dScene* pScene(pE3d->getRootE3dSceneFromE3dObject()); + + if(nullptr != pScene) + { + // prepare result vector and call helper + std::vector< const E3dCompoundObject* > aHitList; + const basegfx::B2DPoint aHitPoint(rPnt.X(), rPnt.Y()); + getAllHit3DObjectsSortedFrontToBack(aHitPoint, *pScene, aHitList); + + if(!aHitList.empty()) + { + // choose the frontmost hit 3D object of the scene + pRet = const_cast< E3dCompoundObject* >(aHitList[0]); + } + } + } + } + return pRet; +} + +void DrawViewWrapper::MarkObject( SdrObject* pObj ) +{ + bool bFrameDragSingles = true;//true == green == surrounding handles + if(pObj) + pObj->SetMarkProtect(false); + if( m_pMarkHandleProvider ) + bFrameDragSingles = m_pMarkHandleProvider->getFrameDragSingles(); + + SetFrameDragSingles(bFrameDragSingles);//decide whether each single object should get handles + SdrView::MarkObj( pObj, GetPageView() ); + showMarkHandles(); +} + +void DrawViewWrapper::setMarkHandleProvider( MarkHandleProvider* pMarkHandleProvider ) +{ + m_pMarkHandleProvider = pMarkHandleProvider; +} + +void DrawViewWrapper::CompleteRedraw(OutputDevice* pOut, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* /* pRedirector */) +{ + svtools::ColorConfig aColorConfig; + Color aFillColor( aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor ); + SetApplicationBackgroundColor(aFillColor); + E3dView::CompleteRedraw( pOut, rReg ); +} + +SdrObject* DrawViewWrapper::getSelectedObject() const +{ + SdrObject* pObj(nullptr); + const SdrMarkList& rMarkList = GetMarkedObjectList(); + if(rMarkList.GetMarkCount() == 1) + { + SdrMark* pMark = rMarkList.GetMark(0); + pObj = pMark->GetMarkedSdrObj(); + } + return pObj; +} + +SdrObject* DrawViewWrapper::getTextEditObject() const +{ + SdrObject* pObj = getSelectedObject(); + SdrObject* pTextObj = nullptr; + if( pObj && pObj->HasTextEdit()) + pTextObj = pObj; + return pTextObj; +} + +void DrawViewWrapper::attachParentReferenceDevice( const uno::Reference< frame::XModel > & xChartModel ) +{ + OutputDevice * pParentRefDev( lcl_GetParentRefDevice( xChartModel )); + SdrOutliner * pOutliner( getOutliner()); + if( pParentRefDev && pOutliner ) + { + pOutliner->SetRefDevice( pParentRefDev ); + } +} + +SdrOutliner* DrawViewWrapper::getOutliner() const +{ + return m_apOutliner.get(); +} + +SfxItemSet DrawViewWrapper::getPositionAndSizeItemSetFromMarkedObject() const +{ + SfxItemSet aFullSet( + GetModel()->GetItemPool(), + svl::Items< + SDRATTR_CORNER_RADIUS, SDRATTR_CORNER_RADIUS, + SID_ATTR_TRANSFORM_POS_X, SID_ATTR_TRANSFORM_ANGLE, + SID_ATTR_TRANSFORM_PROTECT_POS, SID_ATTR_TRANSFORM_AUTOHEIGHT, + SID_ATTR_METRIC, SID_ATTR_METRIC>); + SfxItemSet aGeoSet( E3dView::GetGeoAttrFromMarked() ); + aFullSet.Put( aGeoSet ); + aFullSet.Put( SfxUInt16Item(SID_ATTR_METRIC,static_cast< sal_uInt16 >( ConfigurationAccess::getFieldUnit()))); + return aFullSet; +} + +SdrObject* DrawViewWrapper::getNamedSdrObject( const OUString& rName ) const +{ + if(rName.isEmpty()) + return nullptr; + SdrPageView* pSdrPageView = GetPageView(); + if( pSdrPageView ) + { + return DrawModelWrapper::getNamedSdrObject( rName, pSdrPageView->GetObjList() ); + } + return nullptr; +} + +bool DrawViewWrapper::IsObjectHit( SdrObject const * pObj, const Point& rPnt ) +{ + if(pObj) + { + tools::Rectangle aRect(pObj->GetCurrentBoundRect()); + return aRect.Contains(rPnt); + } + return false; +} + +void DrawViewWrapper::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) +{ + //prevent wrong reselection of objects + SdrModel* pSdrModel( GetModel() ); + if( pSdrModel && pSdrModel->isLocked() ) + return; + + const SdrHint* pSdrHint = ( rHint.GetId() == SfxHintId::ThisIsAnSdrHint ? static_cast<const SdrHint*>(&rHint) : nullptr ); + + //#i76053# do nothing when only changes on the hidden draw page were made ( e.g. when the symbols for the dialogs are created ) + SdrPageView* pSdrPageView = GetPageView(); + if( pSdrHint && pSdrPageView ) + { + if( pSdrPageView->GetPage() != pSdrHint->GetPage() ) + return; + } + + E3dView::Notify(rBC, rHint); + + if( pSdrHint == nullptr ) + return; + + SdrHintKind eKind = pSdrHint->GetKind(); + if( eKind == SdrHintKind::BeginEdit ) + { + // #i79965# remember map mode + OSL_ASSERT( ! m_bRestoreMapMode ); + OutputDevice* pOutDev = GetFirstOutputDevice(); + if( pOutDev ) + { + m_aMapModeToRestore = pOutDev->GetMapMode(); + m_bRestoreMapMode = true; + } + } + else if( eKind == SdrHintKind::EndEdit ) + { + // #i79965# scroll back view when ending text edit + OSL_ASSERT( m_bRestoreMapMode ); + if( m_bRestoreMapMode ) + { + OutputDevice* pOutDev = GetFirstOutputDevice(); + if( pOutDev ) + { + pOutDev->SetMapMode( m_aMapModeToRestore ); + m_bRestoreMapMode = false; + } + } + } +} + +SdrObject* DrawViewWrapper::getSdrObject( const uno::Reference< + drawing::XShape >& xShape ) +{ + SdrObject* pRet = nullptr; + uno::Reference< lang::XTypeProvider > xTypeProvider( xShape, uno::UNO_QUERY ); + if(xTypeProvider.is()) + { + pRet = SdrObject::getSdrObjectFromXShape(xShape); + } + return pRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/drawinglayer/ViewElementListProvider.cxx b/chart2/source/controller/drawinglayer/ViewElementListProvider.cxx new file mode 100644 index 000000000..ef7eba88e --- /dev/null +++ b/chart2/source/controller/drawinglayer/ViewElementListProvider.cxx @@ -0,0 +1,196 @@ +/* -*- 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 <ViewElementListProvider.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <chartview/DataPointSymbolSupplier.hxx> +#include <DrawViewWrapper.hxx> + +#include <com/sun/star/drawing/Direction3D.hpp> +#include <o3tl/safeint.hxx> +#include <svx/xtable.hxx> +#include <svl/itempool.hxx> +#include <svtools/ctrltool.hxx> +#include <vcl/svapp.hxx> +#include <svx/svdobj.hxx> +#include <vcl/virdev.hxx> +#include <svx/svdview.hxx> +#include <svx/svdpage.hxx> +#include <tools/diagnose_ex.h> + +namespace chart +{ +using namespace ::com::sun::star; + +ViewElementListProvider::ViewElementListProvider( DrawModelWrapper* pDrawModelWrapper ) + : m_pDrawModelWrapper( pDrawModelWrapper ) +{ +} + +ViewElementListProvider::ViewElementListProvider(ViewElementListProvider&& rOther) noexcept +{ + m_pDrawModelWrapper = rOther.m_pDrawModelWrapper; + m_pFontList = std::move(rOther.m_pFontList); +} + +ViewElementListProvider::~ViewElementListProvider() +{ +} + +XColorListRef ViewElementListProvider::GetColorTable() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetColorList(); + return XColorListRef(); +} + +XDashListRef ViewElementListProvider::GetDashList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetDashList(); + return XDashListRef(); +} + +XLineEndListRef ViewElementListProvider::GetLineEndList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetLineEndList(); + return XLineEndListRef(); +} + +XGradientListRef ViewElementListProvider::GetGradientList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetGradientList(); + return XGradientListRef(); +} +XHatchListRef ViewElementListProvider::GetHatchList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetHatchList(); + return nullptr; +} + +XBitmapListRef ViewElementListProvider::GetBitmapList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetBitmapList(); + return XBitmapListRef(); +} + +XPatternListRef ViewElementListProvider::GetPatternList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetPatternList(); + return XPatternListRef(); +} + +//create chartspecific symbols for linecharts +SdrObjList* ViewElementListProvider::GetSymbolList() const +{ + SdrObjList* pSymbolList = nullptr; + try + { + //@todo use mutex + + //get hidden draw page (target): + rtl::Reference<SvxDrawPage> xTarget = m_pDrawModelWrapper->getHiddenDrawPage(); + + //create symbols via uno and convert to native sdr objects + drawing::Direction3D aSymbolSize(220, 220, 0); // should be 250, but 250 -> 280 ?? + rtl::Reference< SvxShapeGroup > xSymbols + = DataPointSymbolSupplier::create2DSymbolList(xTarget, aSymbolSize); + + SdrObject* pSdrObject = DrawViewWrapper::getSdrObject( + uno::Reference<drawing::XShape>(static_cast<cppu::OWeakObject*>(xSymbols.get()), uno::UNO_QUERY)); + if (pSdrObject) + pSymbolList = pSdrObject->GetSubList(); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return pSymbolList; +} + +Graphic ViewElementListProvider::GetSymbolGraphic( sal_Int32 nStandardSymbol, const SfxItemSet* pSymbolShapeProperties ) const +{ + SdrObjList* pSymbolList = GetSymbolList(); + if( !pSymbolList->GetObjCount() ) + return Graphic(); + if(nStandardSymbol<0) + nStandardSymbol*=-1; + if( o3tl::make_unsigned(nStandardSymbol) >= pSymbolList->GetObjCount() ) + nStandardSymbol %= pSymbolList->GetObjCount(); + SdrObject* pObj = pSymbolList->GetObj(nStandardSymbol); + + ScopedVclPtrInstance< VirtualDevice > pVDev; + pVDev->SetMapMode(MapMode(MapUnit::Map100thMM)); + + std::unique_ptr<SdrModel> pModel( + new SdrModel()); + + pModel->GetItemPool().FreezeIdRanges(); + rtl::Reference<SdrPage> pPage = new SdrPage( *pModel, false ); + pPage->SetSize(Size(1000,1000)); + pModel->InsertPage( pPage.get(), 0 ); + SdrView aView(*pModel, pVDev); + aView.hideMarkHandles(); + SdrPageView* pPageView = aView.ShowSdrPage(pPage.get()); + + // directly clone to target SdrModel + pObj = pObj->CloneSdrObject(*pModel); + + pPage->NbcInsertObject(pObj); + aView.MarkObj(pObj,pPageView); + if( pSymbolShapeProperties ) + pObj->SetMergedItemSet(*pSymbolShapeProperties); + + GDIMetaFile aMeta(aView.GetMarkedObjMetaFile()); + + Graphic aGraph(aMeta); + Size aSize = pObj->GetSnapRect().GetSize(); + aGraph.SetPrefSize(aSize); + aGraph.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + + aView.UnmarkAll(); + pObj=pPage->RemoveObject(0); + SdrObject::Free( pObj ); + + return aGraph; +} + +FontList* ViewElementListProvider::getFontList() const +{ + //was old chart: + //SvxFontListItem* SfxObjectShell::.GetItem(SID_ATTR_CHAR_FONTLIST) + + if(!m_pFontList) + { + OutputDevice* pRefDev = m_pDrawModelWrapper ? m_pDrawModelWrapper->getReferenceDevice() : nullptr; + OutputDevice* pDefaultOut = Application::GetDefaultDevice(); + m_pFontList.reset( new FontList( pRefDev ? pRefDev : pDefaultOut + , pRefDev ? pDefaultOut : nullptr) ); + } + return m_pFontList.get(); +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/AccessibleBase.hxx b/chart2/source/controller/inc/AccessibleBase.hxx new file mode 100644 index 000000000..44f326f2a --- /dev/null +++ b/chart2/source/controller/inc/AccessibleBase.hxx @@ -0,0 +1,324 @@ +/* -*- 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 <ObjectIdentifier.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <comphelper/accessibleeventnotifier.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <rtl/ref.hxx> +#include <tools/color.hxx> +#include <unotools/weakref.hxx> + +#include <map> +#include <vector> +#include <memory> + +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::view { class XSelectionSupplier; } +namespace utl { class AccessibleStateSetHelper; } + + +class SdrView; + +namespace accessibility +{ +class IAccessibleViewForwarder; +} + +namespace chart +{ + +class AccessibleBase; +class ObjectHierarchy; + +typedef ObjectIdentifier AccessibleUniqueId; + +struct AccessibleElementInfo +{ + AccessibleUniqueId m_aOID; + + unotools::WeakReference< ::chart::ChartModel > m_xChartDocument; + css::uno::WeakReference< css::view::XSelectionSupplier > m_xSelectionSupplier; + css::uno::WeakReference< css::uno::XInterface > m_xView; + css::uno::WeakReference< css::awt::XWindow > m_xWindow; + + std::shared_ptr< ObjectHierarchy > m_spObjectHierarchy; + + AccessibleBase * m_pParent; + SdrView* m_pSdrView; + ::accessibility::IAccessibleViewForwarder* m_pViewForwarder; +}; + +namespace impl +{ +typedef ::cppu::WeakComponentImplHelper< + css::accessibility::XAccessible, + css::accessibility::XAccessibleContext, + css::accessibility::XAccessibleComponent, + css::accessibility::XAccessibleEventBroadcaster, + css::lang::XServiceInfo, + css::lang::XEventListener + > AccessibleBase_Base; +} + +/** Base class for all Chart Accessibility objects + */ +class AccessibleBase : + public cppu::BaseMutex, + public impl::AccessibleBase_Base +{ +public: + enum class EventType + { + GOT_SELECTION, + LOST_SELECTION + }; + + AccessibleBase( const AccessibleElementInfo & rAccInfo, + bool bMayHaveChildren, + bool bAlwaysTransparent ); + virtual ~AccessibleBase() override; + +protected: + // for all calls to protected methods it is assumed that the mutex is locked + // unless calls outside via UNO, e.g. event notification, are done + + /** @param bThrowException if true, a DisposedException is thrown if the + object is already disposed + @return true, if the component is already disposed and bThrowException is false, + false otherwise + @throws css::lang::DisposedException + */ + bool CheckDisposeState( bool bThrowException = true ) const; + + /** Events coming from the core have to be processed in this methods. The + default implementation returns false, which indicates that the object is + not interested in the event. To react on events you have to implement + this method in derived classes. + + The default implementation iterates over all children and forwards the + event until the first child returns true. + + @param nObjId contains the object id of chart objects. If the object is + no chart object, the event is not broadcast. + @return If an object is the addressee of the event it should return + true, false otherwise. + */ + bool NotifyEvent( EventType eType, const AccessibleUniqueId & rId ); + + /** Adds a state to the set. + + @throws css::uno::RuntimeException + */ + void AddState( sal_Int16 aState ); + + /** Removes a state from the set if the set contains the state, otherwise + nothing is done. + + @throws css::uno::RuntimeException + */ + void RemoveState( sal_Int16 aState ); + + /** has to be overridden by derived classes that support child elements. + With this method a rescan is initiated that should result in a correct + list of children. + + This method is called when access to any methods concerning children is + invoked for the first time. + */ + bool UpdateChildren(); + + /** Is called by UpdateChildren. This method is only called if an update is + really necessary. + */ + virtual bool ImplUpdateChildren(); + + /** adds a child to the end of the internal vector of children. As a + result, the child-count increases by one, but all existing children keep + their indices. + + Important: as the implementation is needed, this should remain the only + method for adding children (i.e. there mustn't be an AddChild( Reference< + XAccessible > ) or the like). + */ + void AddChild( AccessibleBase* pChild ); + + /** removes a child from the internal vector. All children with index + greater than the index of the removed element get an index one less than + before. + */ + void RemoveChildByOId( const ObjectIdentifier& rOId ); + + /** Retrieve the pixel coordinates of logical coordinates (0,0) of the + current logic coordinate system. This can be used for + getLocationOnScreen, if the coordinates of an object are not relative to + its direct parent, but a parent higher up in hierarchy. + + @return the (x,y) pixel coordinates of the upper left corner + */ + virtual css::awt::Point GetUpperLeftOnScreen() const; + + /** This method creates an AccessibleEventObject and sends it to all + listeners that are currently listening to this object + */ + void BroadcastAccEvent( sal_Int16 nId, + const css::uno::Any & rNew, + const css::uno::Any & rOld ) const; + + /** Removes all children from the internal lists and broadcasts child remove + events. + + This method cares about mutex locking, and thus should be called without + the mutex locked. + */ + void KillAllChildren(); + + /** Is called from getAccessibleChild(). Before this method is called, an + update of children is done if necessary. + + @throws css::lang::IndexOutOfBoundsException + @throws css::uno::RuntimeException + */ + virtual css::uno::Reference< css::accessibility::XAccessible > + ImplGetAccessibleChildById( sal_Int32 i ) const; + + /** Is called from getAccessibleChildCount(). Before this method is called, + an update of children is done if necessary. + + @throws css::uno::RuntimeException + */ + virtual sal_Int32 ImplGetAccessibleChildCount() const; + + const AccessibleElementInfo& GetInfo() const { return m_aAccInfo;} + void SetInfo( const AccessibleElementInfo & rNewInfo ); + const AccessibleUniqueId& GetId() const { return m_aAccInfo.m_aOID;} + + // ________ WeakComponentImplHelper (XComponent::dispose) ________ + virtual void SAL_CALL disposing() override; + + // ________ XAccessible ________ + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext() override; + + // ________ XAccessibleContext ________ + virtual sal_Int32 SAL_CALL getAccessibleChildCount() override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL + getAccessibleChild( sal_Int32 i ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL + getAccessibleParent() override; + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override; + /// @return AccessibleRole.SHAPE + virtual sal_Int16 SAL_CALL getAccessibleRole() override; + // has to be implemented by derived classes +// virtual OUString SAL_CALL getAccessibleName() +// throw (css::uno::RuntimeException); + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL + getAccessibleRelationSet() override; + virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL + getAccessibleStateSet() override; + virtual css::lang::Locale SAL_CALL getLocale() override; + // has to be implemented by derived classes +// virtual OUString SAL_CALL getAccessibleDescription() +// throw (css::uno::RuntimeException); + + // ________ XAccessibleComponent ________ + virtual sal_Bool SAL_CALL containsPoint( + const css::awt::Point& aPoint ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL + getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + // has to be defined in derived classes + virtual css::awt::Rectangle SAL_CALL getBounds() override; + virtual css::awt::Point SAL_CALL getLocation() override; + virtual css::awt::Point SAL_CALL getLocationOnScreen() override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL grabFocus() override; + virtual sal_Int32 SAL_CALL getForeground() override; + virtual sal_Int32 SAL_CALL getBackground() override; + + // ________ XServiceInfo ________ + 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; + + // ________ XEventListener ________ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ________ XAccessibleEventBroadcaster ________ + virtual void SAL_CALL addAccessibleEventListener( + const css::uno::Reference< css::accessibility::XAccessibleEventListener >& xListener ) override; + virtual void SAL_CALL removeAccessibleEventListener( + const css::uno::Reference< css::accessibility::XAccessibleEventListener >& xListener ) override; + +private: + enum eColorType + { + ACC_BASE_FOREGROUND, + ACC_BASE_BACKGROUND + }; + Color getColor( eColorType eColType ); + +private: + /** type of the vector containing the accessible children + */ + typedef std::vector< css::uno::Reference< css::accessibility::XAccessible > > ChildListVectorType; + /** type of the hash containing a vector index for every AccessibleUniqueId + of the object in the child list + */ + typedef std::map< ObjectIdentifier, css::uno::Reference< css::accessibility::XAccessible > > ChildOIDMap; + + bool m_bIsDisposed; + const bool m_bMayHaveChildren; + bool m_bChildrenInitialized; + ChildListVectorType m_aChildList; + + ChildOIDMap m_aChildOIDMap; + + ::comphelper::AccessibleEventNotifier::TClientId m_nEventNotifierId; + + /** Implementation helper for getAccessibleStateSet() + + Note: This member must come before m_aStateSet! + */ + rtl::Reference<::utl::AccessibleStateSetHelper> m_xStateSetHelper; + + AccessibleElementInfo m_aAccInfo; + const bool m_bAlwaysTransparent; + /** denotes if the state-set is initialized. On initialization the selected + state is checked. + + This variable is monitored by the solar mutex! + + Note: declared volatile to enable double-check-locking + */ + volatile bool m_bStateSetInitialized; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/AccessibleChartView.hxx b/chart2/source/controller/inc/AccessibleChartView.hxx new file mode 100644 index 000000000..eb3367b20 --- /dev/null +++ b/chart2/source/controller/inc/AccessibleChartView.hxx @@ -0,0 +1,118 @@ +/* -*- 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 "AccessibleBase.hxx" +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/weakref.hxx> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/view/XSelectionChangeListener.hpp> + +#include <memory> + +namespace com::sun::star::accessibility { class XAccessible; } +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::view { class XSelectionSupplier; } + +namespace accessibility +{ +class IAccessibleViewForwarder; +} + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::ImplInheritanceHelper< + ::chart::AccessibleBase, + css::lang::XInitialization, + css::view::XSelectionChangeListener > + AccessibleChartView_Base; +} + +class AccessibleChartView final : + public impl::AccessibleChartView_Base +{ +public: + AccessibleChartView(SdrView* pView ); + virtual ~AccessibleChartView() override; + + AccessibleChartView() = delete; + + // ____ WeakComponentHelper (called from XComponent::dispose()) ____ + using AccessibleBase::disposing; + + // ____ lang::XInitialization ____ + // 0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself + // 1: frame::XModel representing the chart model - offers access to object data + // 2: lang::XInterface representing the normal chart view - offers access to some extra object data + // 3: accessibility::XAccessible representing the parent accessible + // 4: awt::XWindow representing the view's window (is a vcl Window) + // all arguments are only valid until next initialization - don't keep them longer + virtual void SAL_CALL initialize( + const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // ____ view::XSelectionChangeListener ____ + virtual void SAL_CALL selectionChanged( const css::lang::EventObject& aEvent ) override; + + // ________ XEventListener ________ + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // ________ XAccessibleContext ________ + virtual OUString SAL_CALL getAccessibleDescription() override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override; + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override; + virtual OUString SAL_CALL getAccessibleName() override; + virtual sal_Int16 SAL_CALL getAccessibleRole() override; + + // ________ XAccessibleComponent ________ + virtual css::awt::Rectangle SAL_CALL getBounds() override; + virtual css::awt::Point SAL_CALL getLocationOnScreen() override; + +protected: + // ________ AccessibleChartElement ________ + virtual css::awt::Point GetUpperLeftOnScreen() const override; + +private: // methods + /** @return the result that m_xWindow->getPosSize() _should_ return. It + returns (0,0) as upper left corner. When calling + getAccessibleParent, you get the parent's parent, which contains + a decoration. Thus you have an offset of (currently) (2,2) + which isn't taken into account. + */ + css::awt::Rectangle GetWindowPosSize() const; + +private: // members + css::uno::WeakReference< css::view::XSelectionSupplier > m_xSelectionSupplier; + unotools::WeakReference<::chart::ChartModel> m_xChartModel; + css::uno::WeakReference< css::uno::XInterface > m_xChartView; + css::uno::WeakReference< css::awt::XWindow > m_xWindow; + css::uno::WeakReference< css::accessibility::XAccessible > m_xParent; + + std::shared_ptr< ObjectHierarchy > m_spObjectHierarchy; + AccessibleUniqueId m_aCurrentSelectionOID; + SdrView* m_pSdrView; + std::unique_ptr<::accessibility::IAccessibleViewForwarder> m_pViewForwarder; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/AccessibleTextHelper.hxx b/chart2/source/controller/inc/AccessibleTextHelper.hxx new file mode 100644 index 000000000..075fbf0f9 --- /dev/null +++ b/chart2/source/controller/inc/AccessibleTextHelper.hxx @@ -0,0 +1,88 @@ +/* -*- 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 <memory> +#include <comphelper/compbase.hxx> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +// forward declaration of helper class from svx +namespace accessibility +{ +class AccessibleTextHelper; +} + +namespace chart +{ + +class DrawViewWrapper; + +namespace impl +{ +typedef comphelper::WeakComponentImplHelper< + css::lang::XInitialization, + css::accessibility::XAccessibleContext > + AccessibleTextHelper_Base; +} + +class AccessibleTextHelper final : + public impl::AccessibleTextHelper_Base +{ +public: + explicit AccessibleTextHelper( DrawViewWrapper * pDrawViewWrapper ); + virtual ~AccessibleTextHelper() override; + + // ____ XInitialization ____ + /** Must be called at least once for this helper class to work. + + mandatory parameter 0: type string. This is the CID that is used to find + the corresponding drawing object that contains the text that should + be handled by this helper class. +1 + mandatory parameter 1: type XAccessible. Is used as EventSource for the + ::accessibility::AccessibleTextHelper (svx) + + mandatory parameter 2: type awt::XWindow. The Window that shows the + text currently. + */ + virtual void SAL_CALL initialize( + const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // ____ XAccessibleContext ____ + virtual ::sal_Int32 SAL_CALL getAccessibleChildCount() override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( + ::sal_Int32 i ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override; + virtual ::sal_Int32 SAL_CALL getAccessibleIndexInParent() override; + virtual ::sal_Int16 SAL_CALL getAccessibleRole() override; + virtual OUString SAL_CALL getAccessibleDescription() override; + virtual OUString SAL_CALL getAccessibleName() override; + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override; + virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override; + virtual css::lang::Locale SAL_CALL getLocale() override; + +private: + std::unique_ptr<::accessibility::AccessibleTextHelper> m_pTextHelper; + DrawViewWrapper * m_pDrawViewWrapper; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/AxisItemConverter.hxx b/chart2/source/controller/inc/AxisItemConverter.hxx new file mode 100644 index 000000000..cbb75d2a1 --- /dev/null +++ b/chart2/source/controller/inc/AxisItemConverter.hxx @@ -0,0 +1,74 @@ +/* -*- 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 "ItemConverter.hxx" +#include <rtl/ref.hxx> + +#include <vector> + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace chart { struct ExplicitIncrementData; } +namespace chart { struct ExplicitScaleData; } +namespace chart { class ChartModel; } + +class SdrModel; + +namespace chart::wrapper { + +class AxisItemConverter final : public ItemConverter +{ +public: + AxisItemConverter( + const css::uno::Reference<css::beans::XPropertySet>& rPropertySet, + SfxItemPool& rItemPool, SdrModel& rDrawModel, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + ExplicitScaleData const * pScale, + ExplicitIncrementData const * pIncrement, + const css::awt::Size* pRefSize ); + + virtual ~AxisItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr<ItemConverter> > m_aConverters; + css::uno::Reference< + css::chart2::XAxis > m_xAxis; + + rtl::Reference<::chart::ChartModel>m_xChartDoc; + + std::unique_ptr<ExplicitScaleData> m_pExplicitScale; + std::unique_ptr<ExplicitIncrementData> m_pExplicitIncrement; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/CharacterPropertyItemConverter.hxx b/chart2/source/controller/inc/CharacterPropertyItemConverter.hxx new file mode 100644 index 000000000..96138e237 --- /dev/null +++ b/chart2/source/controller/inc/CharacterPropertyItemConverter.hxx @@ -0,0 +1,59 @@ +/* -*- 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 "ItemConverter.hxx" +#include <com/sun/star/awt/Size.hpp> + +#include <optional> + +namespace chart::wrapper { + +class CharacterPropertyItemConverter final : public ItemConverter +{ +public: + CharacterPropertyItemConverter( + const css::uno::Reference<css::beans::XPropertySet>& rPropertySet, + SfxItemPool& rItemPool ); + + CharacterPropertyItemConverter( + const css::uno::Reference<css::beans::XPropertySet>& rPropertySet, + SfxItemPool& rItemPool, + const css::awt::Size* pRefSize, + const OUString & rRefSizePropertyName, + const css::uno::Reference<css::beans::XPropertySet>& rRefSizePropSet = css::uno::Reference<css::beans::XPropertySet>() ); + + virtual ~CharacterPropertyItemConverter() override; + +private: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + + const css::uno::Reference<css::beans::XPropertySet>& GetRefSizePropertySet() const; + + OUString m_aRefSizePropertyName; + css::uno::Reference<css::beans::XPropertySet> m_xRefSizePropSet; + std::optional<css::awt::Size> m_pRefSize; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ChartController.hxx b/chart2/source/controller/inc/ChartController.hxx new file mode 100644 index 000000000..d50800fd6 --- /dev/null +++ b/chart2/source/controller/inc/ChartController.hxx @@ -0,0 +1,562 @@ +/* -*- 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 <LifeTime.hxx> +#include "CommandDispatchContainer.hxx" +#include "SelectionHelper.hxx" + +#include <svx/svdtypes.hxx> +#include <vcl/timer.hxx> + +#include <cppuhelper/implbase.hxx> +#include <o3tl/sorted_vector.hxx> +#include <salhelper/simplereferenceobject.hxx> + +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/ui/XContextMenuInterception.hpp> +#include <com/sun/star/util/XModeChangeListener.hpp> +#include <com/sun/star/util/XCloseListener.hpp> +#include <com/sun/star/util/XModifyListener.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/XLayoutManagerListener.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <memory> +#include <string_view> + +namespace com::sun::star::accessibility { class XAccessible; } +namespace com::sun::star::accessibility { class XAccessibleContext; } +namespace com::sun::star::awt { class XFocusListener; } +namespace com::sun::star::awt { class XKeyListener; } +namespace com::sun::star::awt { class XMouseListener; } +namespace com::sun::star::awt { class XMouseMotionListener; } +namespace com::sun::star::awt { class XPaintListener; } +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::awt { class XWindowListener; } +namespace com::sun::star::awt { struct Point; } +namespace com::sun::star::document { class XUndoManager; } +namespace com::sun::star::frame { class XDispatch; } +namespace com::sun::star::frame { class XLayoutManagerEventBroadcaster; } +namespace com::sun::star::graphic { class XGraphic; } +namespace com::sun::star::lang { class XInitialization; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { class XCloseable; } +namespace com::sun::star::view { class XSelectionSupplier; } + + +class SdrModel; + +namespace svt +{ + class AcceleratorExecute; +} + +namespace svx::sidebar { + class SelectionChangeHandler; +} + +namespace weld { + class Window; +} + +class DropTargetHelper; + +namespace chart +{ + +class UndoGuard; +class ChartWindow; +class DrawModelWrapper; +class DrawViewWrapper; +class ReferenceSizeProvider; +class ViewElementListProvider; +class Diagram; + +enum ChartDrawMode { CHARTDRAW_INSERT, CHARTDRAW_SELECT }; + + +class ChartController final : public ::cppu::WeakImplHelper < + css::frame::XController //comprehends XComponent (required interface) + ,css::frame::XDispatchProvider //(required interface) + ,css::view::XSelectionSupplier //(optional interface) + ,css::ui::XContextMenuInterception //(optional interface) + ,css::util::XCloseListener //(needed for communication with XModel) + ,css::lang::XServiceInfo + ,css::frame::XDispatch + ,css::awt::XWindow //this is the Window Controller part of this Controller, that will be given to a Frame via setComponent + ,css::lang::XMultiServiceFactory + ,css::util::XModifyListener + ,css::util::XModeChangeListener + ,css::frame::XLayoutManagerListener + > +{ +public: + ChartController() = delete; + explicit ChartController(css::uno::Reference< css::uno::XComponentContext > const & xContext); + virtual ~ChartController() override; + + OUString GetContextName(); + + // css::lang::XServiceInfo + 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; + + // css::frame::XController (required interface) + virtual void SAL_CALL + attachFrame( const css::uno::Reference< css::frame::XFrame > & xFrame ) override; + + virtual sal_Bool SAL_CALL + attachModel( const css::uno::Reference< css::frame::XModel > & xModel ) override; + + virtual css::uno::Reference< css::frame::XFrame > SAL_CALL + getFrame() override; + + virtual css::uno::Reference< css::frame::XModel > SAL_CALL + getModel() override; + + virtual css::uno::Any SAL_CALL + getViewData() override; + + virtual void SAL_CALL + restoreViewData( const css::uno::Any& rValue ) override; + + virtual sal_Bool SAL_CALL + suspend( sal_Bool bSuspend ) override; + + // css::lang::XComponent (base of XController) + virtual void SAL_CALL + dispose() override; + + virtual void SAL_CALL + addEventListener( const css::uno::Reference< css::lang::XEventListener > & xListener ) override; + + virtual void SAL_CALL + removeEventListener( const css::uno::Reference< css::lang::XEventListener > & xListener ) override; + + // css::frame::XDispatchProvider (required interface) + virtual css::uno::Reference< css::frame::XDispatch> SAL_CALL + queryDispatch( const css::util::URL& rURL + , const OUString& rTargetFrameName + , sal_Int32 nSearchFlags) override; + + virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL + queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor > & xDescripts) override; + + // css::view::XSelectionSupplier (optional interface) + virtual sal_Bool SAL_CALL + select( const css::uno::Any& rSelection ) override; + + virtual css::uno::Any SAL_CALL + getSelection() override; + + virtual void SAL_CALL + addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener > & xListener ) override; + + virtual void SAL_CALL + removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener > & xListener ) override; + + // css::ui::XContextMenuInterception (optional interface) + virtual void SAL_CALL + registerContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor > & xInterceptor) override; + + virtual void SAL_CALL + releaseContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor > & xInterceptor) override; + + //additional interfaces + + // css::util::XCloseListener + virtual void SAL_CALL + queryClosing( const css::lang::EventObject& Source + , sal_Bool GetsOwnership ) override; + + virtual void SAL_CALL + notifyClosing( const css::lang::EventObject& Source ) override; + + // css::util::XEventListener (base of XCloseListener and XModifyListener) + virtual void SAL_CALL + disposing( const css::lang::EventObject& Source ) override; + + // css::frame::XDispatch + + virtual void SAL_CALL + dispatch( const css::util::URL& aURL + , const css::uno::Sequence< css::beans::PropertyValue >& aArgs ) override; + + virtual void SAL_CALL + addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xControl + , const css::util::URL& aURL ) override; + + virtual void SAL_CALL + removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xControl + , const css::util::URL& aURL ) override; + + // css::awt::XWindow + virtual void SAL_CALL + setPosSize( sal_Int32 X, sal_Int32 Y + , sal_Int32 Width, sal_Int32 Height, sal_Int16 Flags ) override; + + virtual css::awt::Rectangle SAL_CALL + getPosSize() override; + + virtual void SAL_CALL + setVisible( sal_Bool Visible ) override; + + virtual void SAL_CALL + setEnable( sal_Bool Enable ) override; + + virtual void SAL_CALL + setFocus() override; + + virtual void SAL_CALL + addWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override; + + virtual void SAL_CALL + removeWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override; + + virtual void SAL_CALL + addFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override; + + virtual void SAL_CALL + removeFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override; + + virtual void SAL_CALL + addKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override; + + virtual void SAL_CALL + removeKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override; + + virtual void SAL_CALL + addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override; + + virtual void SAL_CALL + removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override; + + virtual void SAL_CALL + addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override; + + virtual void SAL_CALL + removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override; + + virtual void SAL_CALL + addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override; + + virtual void SAL_CALL + removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override; + + // css::lang XMultiServiceFactory + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstance( const OUString& aServiceSpecifier ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArguments( const OUString& ServiceSpecifier, + const css::uno::Sequence< + css::uno::Any >& Arguments ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getAvailableServiceNames() override; + + // css::util::XModifyListener + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // css::util::XModeChangeListener + virtual void SAL_CALL modeChanged( + const css::util::ModeChangeEvent& _rSource ) override; + + // css::frame::XLayoutManagerListener + virtual void SAL_CALL layoutEvent( + const css::lang::EventObject& aSource, + ::sal_Int16 eLayoutEvent, + const css::uno::Any& aInfo ) override; + + // WindowController stuff + void PrePaint(); + void execute_Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); + void execute_MouseButtonDown( const MouseEvent& rMEvt ); + void execute_MouseMove( const MouseEvent& rMEvt ); + void execute_MouseButtonUp( const MouseEvent& rMEvt ); + void execute_Resize(); + void execute_Command( const CommandEvent& rCEvt ); + bool execute_KeyInput( const KeyEvent& rKEvt ); + + /** get help text to be shown in a quick help + + @param aAtLogicPosition the position in logic coordinates (of the + window) of the mouse cursor to determine for + which object help is requested. + + @param bIsBalloonHelp determines whether to return the long text version + (balloon help) or the shorter one (quick help). + + @param rOutQuickHelpText is filled with the quick help text + + @param rOutEqualRect is filled with a rectangle that denotes the region + in which the quick help does not change. + + @return </sal_True>, if a quick help should be shown. + */ + bool requestQuickHelp( + ::Point aAtLogicPosition, bool bIsBalloonHelp, + OUString & rOutQuickHelpText, css::awt::Rectangle & rOutEqualRect ); + + css::uno::Reference< css::accessibility::XAccessible > CreateAccessible(); + + static bool isObjectDeleteable( const css::uno::Any& rSelection ); + + void setDrawMode( ChartDrawMode eMode ) { m_eDrawMode = eMode; } + + bool isShapeContext() const; + + ViewElementListProvider getViewElementListProvider(); + DrawModelWrapper* GetDrawModelWrapper(); + DrawViewWrapper* GetDrawViewWrapper(); + ChartWindow* GetChartWindow() const; + weld::Window* GetChartFrame(); + bool isAdditionalShapeSelected() const; + void SetAndApplySelection(const css::uno::Reference<css::drawing::XShape>& rxShape); + void StartTextEdit( const Point* pMousePixel = nullptr ); + + void NotifyUndoActionHdl( std::unique_ptr<SdrUndoAction> ); + + css::uno::Reference<css::uno::XInterface> const & getChartView() const; + + rtl::Reference<::chart::ChartModel> getChartModel(); + rtl::Reference<::chart::Diagram> getFirstDiagram(); + +private: + class TheModel : public salhelper::SimpleReferenceObject + { + public: + explicit TheModel( const rtl::Reference<::chart::ChartModel> & xModel ); + + virtual ~TheModel() override; + + void addListener( ChartController* pController ); + void removeListener( ChartController* pController ); + void tryTermination(); + const rtl::Reference<::chart::ChartModel>& + getModel() const { return m_xModel;} + + private: + rtl::Reference<::chart::ChartModel> m_xModel; + + //the ownership between model and controller is not clear at first + //each controller might consider himself as owner of the model first + bool m_bOwnership; + }; + class TheModelRef final + { + public: + TheModelRef( TheModel* pTheModel, ::osl::Mutex& rMutex ); + TheModelRef( const TheModelRef& rTheModel, ::osl::Mutex& rMutex ); + TheModelRef& operator=(ChartController::TheModel* pTheModel); + TheModelRef& operator=(const TheModelRef& rTheModel); + ~TheModelRef(); + bool is() const; + TheModel* operator->() const { return m_xTheModel.get(); } + private: + rtl::Reference<TheModel> m_xTheModel; + ::osl::Mutex& m_rModelMutex; + }; + + mutable ::apphelper::LifeTimeManager m_aLifeTimeManager; + + bool m_bSuspended; + + css::uno::Reference< css::uno::XComponentContext> m_xCC; + + //model + css::uno::Reference< css::frame::XFrame > m_xFrame; + mutable ::osl::Mutex m_aModelMutex; + TheModelRef m_aModel; + + //view + css::uno::Reference<css::awt::XWindow> m_xViewWindow; + css::uno::Reference<css::uno::XInterface> m_xChartView; + std::shared_ptr< DrawModelWrapper > m_pDrawModelWrapper; + std::unique_ptr<DrawViewWrapper> m_pDrawViewWrapper; + + Selection m_aSelection; + SdrDragMode m_eDragMode; + + Timer m_aDoubleClickTimer; + bool m_bWaitingForDoubleClick; + bool m_bWaitingForMouseUp; + bool m_bFieldButtonDown; + + bool m_bConnectingToView; + bool m_bDisposed; + + css::uno::Reference< css::document::XUndoManager > m_xUndoManager; + std::unique_ptr< UndoGuard > m_pTextActionUndoGuard; + + std::unique_ptr< ::svt::AcceleratorExecute > m_apAccelExecute; + + CommandDispatchContainer m_aDispatchContainer; + + std::unique_ptr< DropTargetHelper > m_apDropTargetHelper; + css::uno::Reference< + css::frame::XLayoutManagerEventBroadcaster > m_xLayoutManagerEventBroadcaster; + + ChartDrawMode m_eDrawMode; + + rtl::Reference<svx::sidebar::SelectionChangeHandler> mpSelectionChangeHandler; + + bool impl_isDisposedOrSuspended() const; + std::unique_ptr<ReferenceSizeProvider> impl_createReferenceSizeProvider(); + void impl_adaptDataSeriesAutoResize(); + + void impl_createDrawViewController(); + void impl_deleteDrawViewController(); + + //executeDispatch methods + void executeDispatch_ObjectProperties(); + void executeDispatch_FormatObject( std::u16string_view rDispatchCommand ); + void executeDlg_ObjectProperties( const OUString& rObjectCID ); + bool executeDlg_ObjectProperties_withoutUndoGuard( const OUString& rObjectCID, bool bSuccessOnUnchanged ); + + void executeDispatch_ChartType(); + + void executeDispatch_InsertTitles(); + void executeDispatch_InsertLegend(); + void executeDispatch_DeleteLegend(); + void executeDispatch_OpenLegendDialog(); + void executeDispatch_InsertAxes(); + void executeDispatch_InsertGrid(); + + void executeDispatch_InsertMenu_DataLabels(); + void executeDispatch_InsertMenu_Trendlines(); + void executeDispatch_InsertMenu_MeanValues(); + + void executeDispatch_InsertMeanValue(); + void executeDispatch_InsertTrendline(); + void executeDispatch_InsertTrendlineEquation( bool bInsertR2=false ); + void executeDispatch_InsertErrorBars( bool bYError ); + + void executeDispatch_InsertR2Value(); + void executeDispatch_DeleteR2Value(); + + void executeDispatch_DeleteMeanValue(); + void executeDispatch_DeleteTrendline(); + void executeDispatch_DeleteTrendlineEquation(); + void executeDispatch_DeleteErrorBars( bool bYError ); + + void executeDispatch_InsertDataLabels(); + void executeDispatch_InsertDataLabel(); + void executeDispatch_DeleteDataLabels(); + void executeDispatch_DeleteDataLabel(); + + void executeDispatch_ResetAllDataPoints(); + void executeDispatch_ResetDataPoint(); + + void executeDispatch_InsertAxis(); + void executeDispatch_InsertAxisTitle(); + void executeDispatch_InsertMajorGrid(); + void executeDispatch_InsertMinorGrid(); + void executeDispatch_DeleteAxis(); + void executeDispatch_DeleteMajorGrid(); + void executeDispatch_DeleteMinorGrid(); + + void executeDispatch_InsertSpecialCharacter(); + void executeDispatch_EditText( const Point* pMousePixel = nullptr ); + void executeDispatch_SourceData(); + void executeDispatch_MoveSeries( bool bForward ); + + bool EndTextEdit(); + + void executeDispatch_View3D(); + void executeDispatch_PositionAndSize( const ::css::uno::Sequence< ::css::beans::PropertyValue >* pArgs = nullptr ); + + void executeDispatch_EditData(); + + void executeDispatch_NewArrangement(); + void executeDispatch_ScaleText(); + + void executeDispatch_Paste(); + void executeDispatch_Copy(); + void executeDispatch_Cut(); + bool executeDispatch_Delete(); + void executeDispatch_ToggleLegend(); + void executeDispatch_ToggleGridHorizontal(); + void executeDispatch_ToggleGridVertical(); + + void executeDispatch_LOKSetTextSelection(int nType, int nX, int nY); + void executeDispatch_LOKPieSegmentDragging(int nOffset); + void executeDispatch_FillColor(sal_uInt32 nColor); + void executeDispatch_FillGradient(OUString sJSONGradient); + void executeDispatch_LineColor(sal_uInt32 nColor); + void executeDispatch_LineWidth(sal_uInt32 nWidth); + + void sendPopupRequest(OUString const & rCID, tools::Rectangle aRectangle); + + void impl_ShapeControllerDispatch( const css::util::URL& rURL, + const css::uno::Sequence< css::beans::PropertyValue >& rArgs ); + + DECL_LINK( DoubleClickWaitingHdl, Timer*, void ); + void execute_DoubleClick( const Point* pMousePixel ); + void startDoubleClickWaiting(); + void stopDoubleClickWaiting(); + + void impl_selectObjectAndNotiy(); + void impl_notifySelectionChangeListeners(); + void impl_invalidateAccessible(); + void impl_initializeAccessible(); + void impl_initializeAccessible( const css::uno::Reference< css::lang::XInitialization >& xInit ); + + //sets the model member to null if it equals the parameter + //returns true if successful + bool impl_releaseThisModel( const css::uno::Reference< css::uno::XInterface > & xModel ); + + enum eMoveOrResizeType + { + MOVE_OBJECT, + CENTERED_RESIZE_OBJECT + }; + /// @return </sal_True>, if resize/move was successful + bool impl_moveOrResizeObject( + const OUString & rCID, eMoveOrResizeType eType, double fAmountLogicX, double fAmountLogicY ); + bool impl_DragDataPoint( const OUString & rCID, double fOffset ); + + static const o3tl::sorted_vector< OUString >& impl_getAvailableCommands(); + + /** Creates a helper accessibility class that must be initialized via XInitialization. For + parameters see + + The returned object should not be used directly. Instead a proxy object + should use this helper to retrieve its children and add them to its own + children. + */ + css::uno::Reference< css::accessibility::XAccessibleContext > + impl_createAccessibleTextContext(); + + void impl_PasteGraphic( css::uno::Reference< css::graphic::XGraphic > const & xGraphic, + const ::Point & aPosition ); + void impl_PasteShapes( SdrModel* pModel ); + void impl_PasteStringAsTextShape( const OUString& rString, const css::awt::Point& rPosition ); + void impl_SetMousePointer( const MouseEvent & rEvent ); + + void impl_ClearSelection(); + + void impl_switchDiagramPositioningToExcludingPositioning(); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ChartDocumentWrapper.hxx b/chart2/source/controller/inc/ChartDocumentWrapper.hxx new file mode 100644 index 000000000..04f76d705 --- /dev/null +++ b/chart2/source/controller/inc/ChartDocumentWrapper.hxx @@ -0,0 +1,172 @@ +/* -*- 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 <WrappedPropertySet.hxx> +#include <com/sun/star/chart/XChartDocument.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XAggregation.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase.hxx> +#include <unotools/eventlisteneradapter.hxx> +#include <rtl/ref.hxx> +#include <svx/unopage.hxx> +#include <memory> + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { class XRefreshable; } +namespace chart { class ChartView; } + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class ChartDocumentWrapper_Base : public ::cppu::ImplInheritanceHelper + < WrappedPropertySet + , css::chart::XChartDocument + , css::drawing::XDrawPageSupplier + , css::lang::XMultiServiceFactory + , css::lang::XServiceInfo + , css::uno::XAggregation + > +{ +}; + +class ChartDocumentWrapper final : public ChartDocumentWrapper_Base + , public ::utl::OEventListenerAdapter +{ +public: + explicit ChartDocumentWrapper( const css::uno::Reference< css::uno::XComponentContext > & xContext ); + virtual ~ChartDocumentWrapper() 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; + + void setAddIn( const css::uno::Reference< css::util::XRefreshable >& xAddIn ); + const css::uno::Reference< css::util::XRefreshable >& getAddIn() const { return m_xAddIn;} + + void setUpdateAddIn( bool bUpdateAddIn ); + bool getUpdateAddIn() const { return m_bUpdateAddIn;} + + void setBaseDiagram( const OUString& rBaseDiagram ); + const OUString& getBaseDiagram() const { return m_aBaseDiagram;} + + css::uno::Reference< css::drawing::XShapes > getAdditionalShapes() const; + + /// @throws css::uno::RuntimeException + rtl::Reference<SvxDrawPage> impl_getDrawPage() const; + +protected: + + // ____ chart::XChartDocument ____ + virtual css::uno::Reference< css::drawing::XShape > SAL_CALL getTitle() override; + virtual css::uno::Reference< css::drawing::XShape > SAL_CALL getSubTitle() override; + virtual css::uno::Reference< css::drawing::XShape > SAL_CALL getLegend() override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getArea() override; + virtual css::uno::Reference< css::chart::XDiagram > SAL_CALL getDiagram() override; + virtual void SAL_CALL setDiagram( const css::uno::Reference< + css::chart::XDiagram >& xDiagram ) override; + virtual css::uno::Reference< css::chart::XChartData > SAL_CALL getData() override; + virtual void SAL_CALL attachData( const css::uno::Reference< + css::chart::XChartData >& xData ) override; + + // ____ XModel ____ + virtual sal_Bool SAL_CALL attachResource( const OUString& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + virtual OUString SAL_CALL getURL() override; + virtual css::uno::Sequence< + css::beans::PropertyValue > SAL_CALL getArgs() override; + virtual void SAL_CALL connectController( const css::uno::Reference< + css::frame::XController >& Controller ) override; + virtual void SAL_CALL disconnectController( const css::uno::Reference< + css::frame::XController >& Controller ) override; + virtual void SAL_CALL lockControllers() override; + virtual void SAL_CALL unlockControllers() override; + virtual sal_Bool SAL_CALL hasControllersLocked() override; + virtual css::uno::Reference< + css::frame::XController > SAL_CALL getCurrentController() override; + virtual void SAL_CALL setCurrentController( const css::uno::Reference< css::frame::XController >& Controller ) override; + virtual css::uno::Reference<css::uno::XInterface > SAL_CALL getCurrentSelection() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // ____ XInterface (for new interfaces) ____ + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + + // ____ ::utl::OEventListenerAdapter ____ + virtual void _disposing( const css::lang::EventObject& rSource ) override; + + // ____ XDrawPageSupplier ____ + virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getDrawPage() override; + + // ____ XMultiServiceFactory ____ + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( const OUString& aServiceSpecifier ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( + const OUString& ServiceSpecifier, + const css::uno::Sequence< css::uno::Any >& Arguments ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames() override; + + // ____ XAggregation ____ + virtual void SAL_CALL setDelegator( + const css::uno::Reference< css::uno::XInterface >& rDelegator ) override; + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& aType ) override; + + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr<WrappedProperty> > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: //methods + void impl_resetAddIn(); + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + + css::uno::Reference< css::uno::XInterface > m_xDelegator; + + css::uno::Reference< css::drawing::XShape > m_xTitle; + css::uno::Reference< css::drawing::XShape > m_xSubTitle; + css::uno::Reference< css::drawing::XShape > m_xLegend; + css::uno::Reference< css::chart::XChartData > m_xChartData; + css::uno::Reference< css::chart::XDiagram > m_xDiagram; + css::uno::Reference< css::beans::XPropertySet > m_xArea; + + css::uno::Reference< css::util::XRefreshable > m_xAddIn; + OUString m_aBaseDiagram; + bool m_bUpdateAddIn; + + rtl::Reference< ChartView > m_xChartView; + css::uno::Reference< css::lang::XMultiServiceFactory> + m_xShapeFactory; + + bool m_bIsDisposed; +}; + +} // namespace chart::wrapper + +// CHART_CHARTDOCUMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ChartToolbarController.hxx b/chart2/source/controller/inc/ChartToolbarController.hxx new file mode 100644 index 000000000..ce493bba6 --- /dev/null +++ b/chart2/source/controller/inc/ChartToolbarController.hxx @@ -0,0 +1,79 @@ +/* -*- 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/. + */ + +#pragma once + +#include <comphelper/compbase.hxx> + +#include <com/sun/star/frame/XToolbarController.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::frame { class XFramesSupplier; } + +namespace chart { + +typedef comphelper::WeakComponentImplHelper< + css::frame::XToolbarController, css::frame::XStatusListener, + css::util::XUpdatable, css::lang::XInitialization, + css::lang::XServiceInfo> ChartToolbarControllerBase; + +class ChartToolbarController final : public ChartToolbarControllerBase +{ +public: + ChartToolbarController(const css::uno::Sequence<css::uno::Any>& rProperties); + virtual ~ChartToolbarController() override; + + ChartToolbarController(const ChartToolbarController&) = delete; + const ChartToolbarController& operator=(const ChartToolbarController&) = delete; + + // XToolbarController + virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override; + + virtual void SAL_CALL click() override; + + virtual void SAL_CALL doubleClick() override; + + virtual css::uno::Reference<css::awt::XWindow> SAL_CALL createPopupWindow() override; + + virtual css::uno::Reference<css::awt::XWindow> SAL_CALL + createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XStatusListener + virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override; + + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& rSource) override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rAny) override; + + // XUpdatable + virtual void SAL_CALL update() override; + + using comphelper::WeakComponentImplHelperBase::disposing; + +private: + + css::uno::Reference<css::frame::XFramesSupplier> mxFramesSupplier; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ChartWindow.hxx b/chart2/source/controller/inc/ChartWindow.hxx new file mode 100644 index 000000000..4ab65ddd9 --- /dev/null +++ b/chart2/source/controller/inc/ChartWindow.hxx @@ -0,0 +1,91 @@ +/* -*- 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 <vcl/window.hxx> + +namespace chart +{ + +class ChartController; + +/** The ChartWindow collects events from the window and forwards them the to the controller +thus the controller can perform appropriate actions +*/ + +class ChartWindow final : public vcl::Window +{ +public: + ChartWindow( ChartController* pController, vcl::Window* pParent, WinBits nStyle ); + virtual ~ChartWindow() override; + virtual void dispose() override; + + //from base class Window: + virtual void PrePaint(vcl::RenderContext& rRenderContext) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void Tracking( const TrackingEvent& rTEvt ) override; + virtual void MouseButtonUp( const MouseEvent& rMEvt ) override; + virtual void Resize() override; + virtual void Activate() override; + virtual void Deactivate() override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + virtual void Command( const CommandEvent& rCEvt ) override; + virtual void KeyInput( const KeyEvent& rKEvt ) override; + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + virtual void RequestHelp( const HelpEvent& rHEvt ) override; + + /// For LibreOfficeKit, we need to route these to the mouse events. + virtual void LogicMouseButtonDown(const MouseEvent&) override; + virtual void LogicMouseButtonUp(const MouseEvent&) override; + virtual void LogicMouseMove(const MouseEvent&) override; + + void ForceInvalidate(); + virtual void Invalidate( InvalidateFlags nFlags = InvalidateFlags::NONE ) override; + virtual void Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags = InvalidateFlags::NONE ) override; + virtual void Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags = InvalidateFlags::NONE ) override; + /// Notify the LOK client about an invalidated area. + virtual void LogicInvalidate( const tools::Rectangle* pRectangle ) override; + + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + + virtual FactoryFunction GetUITestFactory() const override; + + ChartController* GetController(); + + virtual bool IsChart() const override { return true; } + vcl::Window* GetParentEditWin(); + +private: + // returns the chart bounding box in twips + tools::Rectangle GetBoundingBox(); + +private: + ChartController* m_pWindowController; + bool m_bInPaint; + VclPtr<vcl::Window> m_pViewShellWindow; + + void adjustHighContrastMode(); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/CommandDispatchContainer.hxx b/chart2/source/controller/inc/CommandDispatchContainer.hxx new file mode 100644 index 000000000..ae95313c0 --- /dev/null +++ b/chart2/source/controller/inc/CommandDispatchContainer.hxx @@ -0,0 +1,136 @@ +/* -*- 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 <unotools/weakref.hxx> +#include <o3tl/sorted_vector.hxx> + +#include <map> +#include <vector> + +namespace com::sun::star::frame { class XController; } +namespace com::sun::star::frame { class XDispatch; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::frame { struct DispatchDescriptor; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { struct URL; } + +namespace chart +{ +class ChartModel; +class DrawCommandDispatch; +class ShapeController; + +/** @HTML + + Helper class for implementing the <code>XDispatchProvider</code> interface + of the ChartController. This class handles all commands to queryDispatch and + queryDispatches in the following way: + + <ul> + <li>Check if there is a cached <code>XDispatch</code> for a given command. + If so, use it.</li> + <li>Check if the command is handled by this class, e.g. Undo. If so, + return a corresponding <code>XDispatch</code> implementation, and cache + this implementation for later use</li> + <li>Otherwise send the command to the chart dispatch provider, if it + can handle this dispatch (determined by the list of commands given in + <code>setChartDispatch()</code>).</li> + </ul> + + <p>The <code>XDispatch</code>Provider is designed to return different + <code>XDispatch</code> implementations for each command. This class here + decides which implementation to use for which command.</p> + + <p>As most commands need much information of the controller and are + implemented there, the controller handles most of the commands itself (it + also implements <code>XDispatch</code>). Therefore it is set here as + chart dispatch.</p> + */ +class CommandDispatchContainer +{ +public: + // note: the chart dispatcher should be removed when all commands are + // handled by other dispatchers. (Chart is currently the controller + // itself) + explicit CommandDispatchContainer( + const css::uno::Reference< css::uno::XComponentContext > & xContext ); + + void setModel( + const rtl::Reference<::chart::ChartModel> & xModel ); + + /** Set a chart dispatcher that is used for all commands contained in + rChartCommands + */ + void setChartDispatch( + const css::uno::Reference< css::frame::XDispatch >& rChartDispatch, + o3tl::sorted_vector< OUString > && rChartCommands ); + + /** Returns the dispatch that is able to do the command given in rURL, if + implemented here. If the URL is not implemented here, it should be + checked whether the command is one of the commands given via + the setChartDispatch() method. If so, call the chart dispatch. + + <p>If all this fails, return an empty dispatch.</p> + */ + css::uno::Reference< css::frame::XDispatch > getDispatchForURL( + const css::util::URL & rURL ); + + css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > getDispatchesForURLs( + const css::uno::Sequence< css::frame::DispatchDescriptor > & aDescriptors ); + + void DisposeAndClear(); + + static css::uno::Reference< css::frame::XDispatch > + getContainerDispatchForURL( + const css::uno::Reference< css::frame::XController > & xChartController, + const css::util::URL & rURL ); + + const css::uno::Reference< css::frame::XDispatch > & getChartDispatcher() const { return m_xChartDispatcher; } + + void setDrawCommandDispatch( DrawCommandDispatch* pDispatch ); + DrawCommandDispatch* getDrawCommandDispatch() { return m_pDrawCommandDispatch; } + void setShapeController( ShapeController* pController ); + ShapeController* getShapeController() { return m_pShapeController; } + +private: + typedef + std::map< OUString, + css::uno::Reference< css::frame::XDispatch > > + tDispatchMap; + + typedef + std::vector< css::uno::Reference< css::frame::XDispatch > > tDisposeVector; + + mutable tDispatchMap m_aCachedDispatches; + mutable tDisposeVector m_aToBeDisposedDispatches; + + css::uno::Reference< css::uno::XComponentContext > m_xContext; + unotools::WeakReference< ::chart::ChartModel > m_xModel; + + css::uno::Reference< css::frame::XDispatch > m_xChartDispatcher; + o3tl::sorted_vector< OUString > m_aChartCommands; + + DrawCommandDispatch* m_pDrawCommandDispatch; + ShapeController* m_pShapeController; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ConfigurationAccess.hxx b/chart2/source/controller/inc/ConfigurationAccess.hxx new file mode 100644 index 000000000..2fb4636d2 --- /dev/null +++ b/chart2/source/controller/inc/ConfigurationAccess.hxx @@ -0,0 +1,38 @@ +/* -*- 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 <tools/fldunit.hxx> + +namespace chart::ConfigurationAccess +{ +/** @descr Retrieve the FieldUnit to be used for the UI. This unit is retrieved + from the registry settings of the Calc application. + + If this setting can not be found there is a fallback to cm which is the most + common setting worldwide (or not?) + + @return the FieldUnit enum. See <vcl/fldunit.hxx> for definition + */ +FieldUnit getFieldUnit(); + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/DataPointItemConverter.hxx b/chart2/source/controller/inc/DataPointItemConverter.hxx new file mode 100644 index 000000000..3c6e276ff --- /dev/null +++ b/chart2/source/controller/inc/DataPointItemConverter.hxx @@ -0,0 +1,90 @@ +/* -*- 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 "ItemConverter.hxx" +#include "GraphicPropertyItemConverter.hxx" +#include <com/sun/star/uno/Sequence.h> + +#include <tools/color.hxx> +#include <rtl/ref.hxx> + +#include <vector> + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } +namespace chart { class ChartModel; } +namespace chart { class DataSeries; } +class SdrModel; + +namespace chart::wrapper { + +class DataPointItemConverter final : public ItemConverter +{ +public: + DataPointItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const css::uno::Reference<css::beans::XPropertySet>& rPropertySet, + const rtl::Reference<::chart::DataSeries>& xSeries, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference<css::lang::XMultiServiceFactory>& xNamedPropertyContainerFactory, + GraphicObjectType eMapTo, + const css::awt::Size* pRefSize = nullptr, + bool bDataSeries = false, + bool bUseSpecialFillColor = false, + sal_Int32 nSpecialFillColor = 0, + bool bOverwriteLabelsForAttributedDataPointsAlso = false, + sal_Int32 nNumberFormat = 0, + sal_Int32 nPercentNumberFormat = 0, + sal_Int32 nPointIndex = -1 ); + + virtual ~DataPointItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr<ItemConverter> > m_aConverters; + bool m_bDataSeries; + bool m_bOverwriteLabelsForAttributedDataPointsAlso; + bool m_bUseSpecialFillColor; + Color m_nSpecialFillColor; + sal_Int32 m_nNumberFormat; + sal_Int32 m_nPercentNumberFormat; + css::uno::Sequence<sal_Int32> m_aAvailableLabelPlacements; + bool m_bForbidPercentValue; + bool m_bHideLegendEntry; + sal_Int32 m_nPointIndex; + rtl::Reference<::chart::DataSeries> m_xSeries; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/DrawViewWrapper.hxx b/chart2/source/controller/inc/DrawViewWrapper.hxx new file mode 100644 index 000000000..28c2a927e --- /dev/null +++ b/chart2/source/controller/inc/DrawViewWrapper.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 <memory> +#include <svx/view3d.hxx> + +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::frame { class XModel; } + +class SdrModel; + +namespace chart +{ + +/** The DrawViewWrapper should help us to reduce effort if the underlying DrawingLayer changes. +Another task is to hide functionality we do not need, for example more than one page. +*/ + +class MarkHandleProvider +{ +public: + virtual bool getMarkHandles( SdrHdlList& rHdlList ) =0; + virtual bool getFrameDragSingles() =0; + +protected: + ~MarkHandleProvider() {} +}; + +class DrawViewWrapper final : public E3dView +{ +public: + DrawViewWrapper( + SdrModel& rSdrModel, + OutputDevice* pOut); + + virtual ~DrawViewWrapper() override; + + //triggers the use of an updated first page + void ReInit(); + + /// tries to get an OutputDevice from the XParent of the model to use as reference device + void attachParentReferenceDevice( + const css::uno::Reference< css::frame::XModel > & xChartModel ); + + //fill list of selection handles 'aHdl' + virtual void SetMarkHandles(SfxViewShell* pOtherShell) override; + + SdrPageView* GetPageView() const; + + SdrObject* getHitObject( const Point& rPnt ) const; + + void MarkObject( SdrObject* pObj ); + + //pMarkHandleProvider can be NULL; ownership is not taken + void setMarkHandleProvider( MarkHandleProvider* pMarkHandleProvider ); + void CompleteRedraw(OutputDevice* pOut, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector = nullptr) override; + + SdrObject* getSelectedObject() const; + SdrObject* getTextEditObject() const; + SdrOutliner* getOutliner() const; + + SfxItemSet getPositionAndSizeItemSetFromMarkedObject() const; + + SdrObject* getNamedSdrObject( const OUString& rName ) const; + static bool IsObjectHit( SdrObject const * pObj, const Point& rPnt ); + + virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override; + + static SdrObject* getSdrObject( const css::uno::Reference< css::drawing::XShape >& xShape ); + +private: + mutable MarkHandleProvider* m_pMarkHandleProvider; + + std::unique_ptr< SdrOutliner > m_apOutliner; + + // #i79965# scroll back view when ending text edit + bool m_bRestoreMapMode; + MapMode m_aMapModeToRestore; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ErrorBarItemConverter.hxx b/chart2/source/controller/inc/ErrorBarItemConverter.hxx new file mode 100644 index 000000000..997bda7d2 --- /dev/null +++ b/chart2/source/controller/inc/ErrorBarItemConverter.hxx @@ -0,0 +1,60 @@ +/* -*- 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 "ItemConverter.hxx" + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper +{ + +class ErrorBarItemConverter final : public ItemConverter +{ +public: + ErrorBarItemConverter( + const css::uno::Reference< css::frame::XModel > & xChartModel, + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ); + virtual ~ErrorBarItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::shared_ptr< ItemConverter > m_spGraphicConverter; + css::uno::Reference< css::frame::XModel > m_xModel; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/GraphicPropertyItemConverter.hxx b/chart2/source/controller/inc/GraphicPropertyItemConverter.hxx new file mode 100644 index 000000000..234e50751 --- /dev/null +++ b/chart2/source/controller/inc/GraphicPropertyItemConverter.hxx @@ -0,0 +1,64 @@ +/* -*- 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 "ItemConverter.hxx" + +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper +{ + +enum class GraphicObjectType +{ + FilledDataPoint, + LineDataPoint, + LineProperties, + LineAndFillProperties +}; + +class GraphicPropertyItemConverter final : public ItemConverter +{ +public: + GraphicPropertyItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + GraphicObjectType eObjectType ); + virtual ~GraphicPropertyItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + GraphicObjectType m_GraphicObjectType; + SdrModel & m_rDrawModel; + css::uno::Reference< css::lang::XMultiServiceFactory > m_xNamedPropertyTableFactory; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ItemConverter.hxx b/chart2/source/controller/inc/ItemConverter.hxx new file mode 100644 index 000000000..865268a3a --- /dev/null +++ b/chart2/source/controller/inc/ItemConverter.hxx @@ -0,0 +1,185 @@ +/* -*- 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 <unotools/eventlisteneradapter.hxx> +#include <svl/itemset.hxx> + +#include <utility> + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::beans { class XPropertySetInfo; } + +namespace chart::wrapper { + + +/** This class serves for conversion between properties of an XPropertySet and + SfxItems in SfxItemSets. + + With this helper classes, you can feed dialogs with XPropertySets and let + those modify by the dialogs. + + You must implement GetWhichPairs() such that an SfxItemSet created with + CreateEmptyItemSet() is able to hold all items that may be mapped. + + You also have to implement GetItemProperty(), in order to return the + property name for a given which-id together with the corresponding member-id + that has to be used for conversion in QueryValue/PutValue. + + FillSpecialItem and ApplySpecialItem may be used for special handling of + individual item, e.g. if you need member-ids in QueryValue/PutValue + + A typical use could be the following: + + ::comphelper::ChartTypeItemConverter aItemConverter( xPropertySet, GetItemPool() ); + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemConverter.FillItemSet( aItemSet ); + bool bChanged = false; + + MyDialog aDlg( aItemSet ); + if( aDlg.Execute() == RET_OK ) + { + const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet(); + if( pOutItemSet ) + bChanged = aItemConverter.ApplyItemSet( *pOutItemSet ); + } + + if( bChanged ) + { + [ apply model changes to view ] + } + */ +class ItemConverter : + public ::utl::OEventListenerAdapter +{ +public: + /** Construct an item converter that uses the given property set for + reading/writing converted items + */ + ItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet , + SfxItemPool& rItemPool ); + virtual ~ItemConverter() override; + + typedef sal_uInt16 tWhichIdType; + typedef OUString tPropertyNameType; + typedef sal_uInt8 tMemberIdType; + + typedef std::pair< tPropertyNameType, tMemberIdType > tPropertyNameWithMemberId; + + /** applies all properties that can be mapped to items into the given item + set. + + Call this method before opening a dialog. + + @param rOutItemSet + the SfxItemSet is filled with all items that are a result of a + conversion from a property of the internal XPropertySet. + */ + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const; + + /** applies all properties that are results of a conversion from all items + in rItemSet to the internal XPropertySet. + + Call this method after a dialog was closed with OK + + @return true, if any properties have been changed, false otherwise. + */ + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ); + + /** creates an empty item set using the given pool or a common pool if empty + (see GetItemPool) and allowing all items given in the ranges returned by + GetWhichPairs. + */ + SfxItemSet CreateEmptyItemSet() const; + + /** Invalidates all items in rDestSet, that are set (state SfxItemState::SET) in + both item sets (rDestSet and rSourceSet) and have differing content. + */ + static void InvalidateUnequalItems( SfxItemSet &rDestSet, const SfxItemSet &rSourceSet ); + +protected: + + /** implement this method to provide an array of which-ranges + */ + virtual const WhichRangesContainer& GetWhichPairs() const = 0; + + /** implement this method to return a Property object for a given which id. + + @param rOutProperty + If true is returned, this contains the property name and the + corresponding Member-Id. + + @return true, if the item can be mapped to a property. + */ + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const = 0; + + /** for items that can not be mapped directly to a property. + + This method is called from FillItemSet(), if GetItemProperty() returns + false. + + The default implementation does nothing except showing an assertion + + @throws css::uno::Exception + */ + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const; + + /** for items that can not be mapped directly to a property. + + This method is called from ApplyItemSet(), if GetItemProperty() returns + false. + + The default implementation returns just false and shows an assertion + + @return true if the item changed a property, false otherwise. + + @throws css::uno::Exception + */ + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ); + + /// Returns the pool + SfxItemPool & GetItemPool() const { return m_rItemPool;} + + /** Returns the XPropertySet that was given in the CTOR and is used to apply + items in ApplyItemSet(). + */ + const css::uno::Reference< css::beans::XPropertySet >& GetPropertySet() const { return m_xPropertySet;} + + // ____ ::utl::OEventListenerAdapter ____ + virtual void _disposing( const css::lang::EventObject& rSource ) override; + +protected: + /** sets a new property set, that you get with GetPropertySet(). It should + not be necessary to use this method. It is introduced to allow changing + the regression type of a regression curve which changes the object + identity. + */ + void resetPropertySet( const css::uno::Reference< css::beans::XPropertySet > & xPropSet ); + +private: + css::uno::Reference< css::beans::XPropertySet > m_xPropertySet; + css::uno::Reference< css::beans::XPropertySetInfo > m_xPropertySetInfo; + + SfxItemPool& m_rItemPool; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ItemPropertyMap.hxx b/chart2/source/controller/inc/ItemPropertyMap.hxx new file mode 100644 index 000000000..7bee6ae81 --- /dev/null +++ b/chart2/source/controller/inc/ItemPropertyMap.hxx @@ -0,0 +1,34 @@ +/* -*- 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 <sal/config.h> + +#include "ItemConverter.hxx" + +#include <map> + +namespace chart::wrapper +{ +typedef std::map<ItemConverter::tWhichIdType, + std::pair<ItemConverter::tPropertyNameType, ItemConverter::tMemberIdType>> + ItemPropertyMapType; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/LegendItemConverter.hxx b/chart2/source/controller/inc/LegendItemConverter.hxx new file mode 100644 index 000000000..3e9315acc --- /dev/null +++ b/chart2/source/controller/inc/LegendItemConverter.hxx @@ -0,0 +1,61 @@ +/* -*- 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 "ItemConverter.hxx" + +#include <vector> + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper +{ + +class LegendItemConverter final : public ItemConverter +{ +public: + LegendItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const css::awt::Size* pRefSize ); + + virtual ~LegendItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr<ItemConverter> > m_aConverters; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/MultipleChartConverters.hxx b/chart2/source/controller/inc/MultipleChartConverters.hxx new file mode 100644 index 000000000..4fe1bb1de --- /dev/null +++ b/chart2/source/controller/inc/MultipleChartConverters.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 "MultipleItemConverter.hxx" +#include <rtl/ref.hxx> + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace chart { class ChartModel; } +class SdrModel; + +namespace chart::wrapper { + +class AllAxisItemConverter final : public MultipleItemConverter +{ +public: + AllAxisItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::awt::Size* pRefSize ); + + virtual ~AllAxisItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +class AllGridItemConverter final : public MultipleItemConverter +{ +public: + AllGridItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference<css::lang::XMultiServiceFactory> & xNamedPropertyContainerFactory ); + virtual ~AllGridItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +class AllDataLabelItemConverter final : public MultipleItemConverter +{ +public: + AllDataLabelItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference<css::lang::XMultiServiceFactory>& xNamedPropertyContainerFactory ); + + virtual ~AllDataLabelItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +class AllTitleItemConverter final : public MultipleItemConverter +{ +public: + AllTitleItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + SfxItemPool& rItemPool, SdrModel& rDrawModel, + const css::uno::Reference<css::lang::XMultiServiceFactory>& xNamedPropertyContainerFactory ); + + virtual ~AllTitleItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +class AllSeriesStatisticsConverter final : public MultipleItemConverter +{ +public: + AllSeriesStatisticsConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, SfxItemPool& rItemPool ); + virtual ~AllSeriesStatisticsConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/MultipleItemConverter.hxx b/chart2/source/controller/inc/MultipleItemConverter.hxx new file mode 100644 index 000000000..e2e8f0775 --- /dev/null +++ b/chart2/source/controller/inc/MultipleItemConverter.hxx @@ -0,0 +1,49 @@ +/* -*- 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 "ItemConverter.hxx" + +#include <vector> + +namespace chart::wrapper { + +/** Note: virtual const sal_uInt16 * GetWhichPairs() const; is still pure virtual + */ +class MultipleItemConverter : public ItemConverter +{ +public: + virtual ~MultipleItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + + /// implemented empty (returns always false) + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + +protected: + MultipleItemConverter( SfxItemPool& rItemPool ); + + std::vector< std::unique_ptr<ItemConverter> > m_aConverters; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ObjectHierarchy.hxx b/chart2/source/controller/inc/ObjectHierarchy.hxx new file mode 100644 index 000000000..55c073bf2 --- /dev/null +++ b/chart2/source/controller/inc/ObjectHierarchy.hxx @@ -0,0 +1,127 @@ +/* -*- 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 <ChartModel.hxx> +#include <ObjectIdentifier.hxx> +#include <map> +#include <vector> + +namespace com::sun::star::awt { struct KeyEvent; } +namespace com::sun::star::chart2 { class XChartDocument; } + +namespace chart +{ + +class ExplicitValueProvider; + +class ObjectHierarchy +{ +public: + typedef std::vector< ObjectIdentifier > tChildContainer; + + /** @param bFlattenDiagram + If <TRUE/>, the content of the diagram (data series, wall, floor, + etc.) is treated as being at the same level as the diagram. (This is + used for keyboard navigation). + */ + explicit ObjectHierarchy( + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ExplicitValueProvider * pExplicitValueProvider, + bool bFlattenDiagram = false, + bool bOrderingForElementSelector = false ); + ~ObjectHierarchy(); + + static ObjectIdentifier getRootNodeOID(); + static bool isRootNode( const ObjectIdentifier& rOID ); + + /// equal to getChildren( getRootNodeOID()) + const tChildContainer & getTopLevelChildren() const; + bool hasChildren( const ObjectIdentifier& rParent ) const; + const tChildContainer & getChildren( const ObjectIdentifier& rParent ) const; + + const tChildContainer & getSiblings( const ObjectIdentifier& rNode ) const; + + /// The result is empty, if the node cannot be found in the tree + ObjectIdentifier getParent( const ObjectIdentifier& rNode ) const; + /// @returns -1, if no parent can be determined + sal_Int32 getIndexInParent( const ObjectIdentifier& rNode ) const; + +private: + void createTree( const rtl::Reference<::chart::ChartModel> & xChartDocument ); + void createAxesTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + void createDiagramTree( + ObjectHierarchy::tChildContainer& rContainer, + const rtl::Reference<::chart::ChartModel>& xChartDoc, + const rtl::Reference< ::chart::Diagram >& xDiagram ); + void createDataSeriesTree( + ObjectHierarchy::tChildContainer & rOutDiagramSubContainer, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + static void createWallAndFloor( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + void createLegendTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + void createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer ); + ObjectIdentifier getParentImpl( + const ObjectIdentifier& rParentOID, + const ObjectIdentifier& rOID ) const; + + typedef std::map< ObjectIdentifier, ObjectHierarchy::tChildContainer > + tChildMap; + tChildMap m_aChildMap; + ExplicitValueProvider* m_pExplicitValueProvider; + bool m_bFlattenDiagram; + bool m_bOrderingForElementSelector; +}; + +class ObjectKeyNavigation +{ +public: + explicit ObjectKeyNavigation( const ObjectIdentifier & rCurrentOID, + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ExplicitValueProvider * pExplicitValueProvider ); + + bool handleKeyEvent( const css::awt::KeyEvent & rEvent ); + const ObjectIdentifier& getCurrentSelection() const { return m_aCurrentOID;} + +private: + void setCurrentSelection( const ObjectIdentifier& rOID ); + bool first(); + bool last(); + bool next(); + bool previous(); + bool up(); + bool down(); + bool veryFirst(); + bool veryLast(); + + ObjectIdentifier m_aCurrentOID; + rtl::Reference<::chart::ChartModel> m_xChartDocument; + ExplicitValueProvider * m_pExplicitValueProvider; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ObjectNameProvider.hxx b/chart2/source/controller/inc/ObjectNameProvider.hxx new file mode 100644 index 000000000..276e58977 --- /dev/null +++ b/chart2/source/controller/inc/ObjectNameProvider.hxx @@ -0,0 +1,69 @@ +/* -*- 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 <ObjectIdentifier.hxx> +#include <TitleHelper.hxx> + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ + +/** Provides localized ui strings for the userinterface. +*/ + +class ObjectNameProvider +{ +public: + static OUString getName( ObjectType eObjectType, bool bPlural=false ); + static OUString getAxisName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + static OUString getGridName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + static OUString getTitleName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + static OUString getTitleNameByType( TitleHelper::eTitleType eType ); + + static OUString getNameForCID( + const OUString& rObjectCID, + const rtl::Reference<::chart::ChartModel>& xChartDocument ); + + static OUString getName_ObjectForSeries( + ObjectType eObjectType, + const OUString& rSeriesCID, + const rtl::Reference<::chart::ChartModel>& xChartDocument ); + static OUString getName_ObjectForAllSeries( ObjectType eObjectType ); + + /** Provides help texts for the various chart elements. + The parameter rObjectCID has to be a ClassifiedIdentifier - see class ObjectIdentifier. + */ + static OUString getHelpText( const OUString& rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel, bool bVerbose=false ); + + /** This is used for showing the currently selected object in the status bar + (command "Context") + */ + static OUString getSelectedObjectText( const OUString & rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartDocument ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/PositionAndSizeHelper.hxx b/chart2/source/controller/inc/PositionAndSizeHelper.hxx new file mode 100644 index 000000000..f70ccf302 --- /dev/null +++ b/chart2/source/controller/inc/PositionAndSizeHelper.hxx @@ -0,0 +1,48 @@ +/* -*- 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 <ObjectIdentifier.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::awt { struct Rectangle; } + +namespace chart +{ + +class PositionAndSizeHelper +{ +public: + static bool moveObject( ObjectType eObjectType + , const css::uno::Reference< css::beans::XPropertySet >& xObjectProp + , const css::awt::Rectangle& rNewPositionAndSize + , const css::awt::Rectangle& rOldPositionAndSize + , const css::awt::Rectangle& rPageRectangle ); + + static bool moveObject( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , const css::awt::Rectangle& rNewPositionAndSize + , const css::awt::Rectangle& rOldPositionAndSize + , const css::awt::Rectangle& rPageRectangle ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/RangeSelectionHelper.hxx b/chart2/source/controller/inc/RangeSelectionHelper.hxx new file mode 100644 index 000000000..02db335a1 --- /dev/null +++ b/chart2/source/controller/inc/RangeSelectionHelper.hxx @@ -0,0 +1,71 @@ +/* -*- 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/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> +#include <rtl/ustring.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star::beans { struct PropertyValue; } +namespace com::sun::star::chart2 { class XChartDocument; } + +namespace com::sun::star { + namespace sheet{ + class XRangeSelection; + class XRangeSelectionListener; + } +} + +namespace chart +{ +class ChartModel; +class RangeSelectionListenerParent; + +class RangeSelectionHelper +{ +public: + explicit RangeSelectionHelper( + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + ~RangeSelectionHelper(); + + bool hasRangeSelection(); + css::uno::Reference< css::sheet::XRangeSelection > const & getRangeSelection(); + void raiseRangeSelectionDocument(); + bool chooseRange( + const OUString & aCurrentRange, + const OUString & aUIString, + RangeSelectionListenerParent & rListenerParent ); + void stopRangeListening( bool bRemoveListener = true ); + bool verifyCellRange( const OUString & rRangeStr ); + bool verifyArguments( const css::uno::Sequence< css::beans::PropertyValue >& rArguments ); + +private: + css::uno::Reference< css::sheet::XRangeSelection > + m_xRangeSelection; + + rtl::Reference<::chart::ChartModel> m_xChartDocument; + + css::uno::Reference< css::sheet::XRangeSelectionListener > + m_xRangeSelectionListener; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/RangeSelectionListener.hxx b/chart2/source/controller/inc/RangeSelectionListener.hxx new file mode 100644 index 000000000..29bea261c --- /dev/null +++ b/chart2/source/controller/inc/RangeSelectionListener.hxx @@ -0,0 +1,70 @@ +/* -*- 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 <ControllerLockGuard.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/sheet/XRangeSelectionListener.hpp> +#include <rtl/ref.hxx> + +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class ChartModel; + +class RangeSelectionListenerParent +{ +public: + virtual void listeningFinished(const OUString& rNewRange) = 0; + virtual void disposingRangeSelection() = 0; + +protected: + ~RangeSelectionListenerParent() {} +}; + +class RangeSelectionListener final + : public ::cppu::WeakImplHelper<css::sheet::XRangeSelectionListener> +{ +public: + explicit RangeSelectionListener( + RangeSelectionListenerParent& rParent, const OUString& rInitialRange, + const rtl::Reference<::chart::ChartModel>& xModelToLockController); + virtual ~RangeSelectionListener() override; + +protected: + // ____ XRangeSelectionListener ____ + virtual void SAL_CALL done(const css::sheet::RangeSelectionEvent& aEvent) override; + virtual void SAL_CALL aborted(const css::sheet::RangeSelectionEvent& aEvent) override; + + // ____ XEventListener ____ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + +private: + RangeSelectionListenerParent& m_rParent; + OUString m_aRange; + ControllerLockGuardUNO m_aControllerLockGuard; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/RegressionCurveItemConverter.hxx b/chart2/source/controller/inc/RegressionCurveItemConverter.hxx new file mode 100644 index 000000000..30c74c4c2 --- /dev/null +++ b/chart2/source/controller/inc/RegressionCurveItemConverter.hxx @@ -0,0 +1,60 @@ +/* -*- 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 "ItemConverter.hxx" +#include <rtl/ref.hxx> + +namespace com::sun::star::chart2 { class XRegressionCurveContainer; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace chart { class DataSeries; } +class SdrModel; + +namespace chart::wrapper +{ + +class RegressionCurveItemConverter final : public ItemConverter +{ +public: + RegressionCurveItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + const rtl::Reference< ::chart::DataSeries > & xRegCurveCnt, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ); + virtual ~RegressionCurveItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::shared_ptr< ItemConverter > m_spGraphicConverter; + rtl::Reference< ::chart::DataSeries > m_xCurveContainer; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/RegressionEquationItemConverter.hxx b/chart2/source/controller/inc/RegressionEquationItemConverter.hxx new file mode 100644 index 000000000..0b32e4b9e --- /dev/null +++ b/chart2/source/controller/inc/RegressionEquationItemConverter.hxx @@ -0,0 +1,61 @@ +/* -*- 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 "ItemConverter.hxx" + +#include <vector> + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper { + +class RegressionEquationItemConverter final : public ItemConverter +{ +public: + RegressionEquationItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const css::awt::Size* pRefSize ); + + virtual ~RegressionEquationItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr<ItemConverter> > m_aConverters; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/SelectionHelper.hxx b/chart2/source/controller/inc/SelectionHelper.hxx new file mode 100644 index 000000000..ff0e95eee --- /dev/null +++ b/chart2/source/controller/inc/SelectionHelper.hxx @@ -0,0 +1,115 @@ +/* -*- 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 "DrawViewWrapper.hxx" +#include <ObjectIdentifier.hxx> + +class SdrObject; + +namespace com::sun::star::drawing { class XShape; } + +namespace chart +{ + +class Selection +{ +public: //methods + bool hasSelection() const; + + OUString const & getSelectedCID() const; + css::uno::Reference< css::drawing::XShape > const & getSelectedAdditionalShape() const; + const ObjectIdentifier& getSelectedOID() const { return m_aSelectedOID;} + + bool isResizeableObjectSelected() const; + bool isRotateableObjectSelected( const rtl::Reference<::chart::ChartModel>& xChartModel ) const; + bool isDragableObjectSelected() const; + + bool isAdditionalShapeSelected() const; + + //returns true if selection has changed + bool setSelection( const OUString& rCID ); + bool setSelection( const css::uno::Reference< css::drawing::XShape >& xShape ); + + void clearSelection(); + + //returns true if the selection has changed + bool maybeSwitchSelectionAfterSingleClickWasEnsured(); + void resetPossibleSelectionAfterSingleClickWasEnsured(); + + void remindSelectionBeforeMouseDown(); + bool isSelectionDifferentFromBeforeMouseDown() const; + + void adaptSelectionToNewPos( const Point& rMousePos, DrawViewWrapper const * pDrawViewWrapper + , bool bIsRightMouse, bool bWaitingForDoubleClick ); + + void applySelection( DrawViewWrapper* pDrawViewWrapper ); + +private: //member + //the selection could be given by a CID or by a shape + //if m_aSelectedObjectCID is not empty this indicates the selection + //the content of m_xSelectedShape is ignored in that case + //the strings are used for autogenerated chart specific objects + //the shape reference is used for additional shapes + ObjectIdentifier m_aSelectedOID; //only single object selection so far + ObjectIdentifier m_aSelectedOID_beforeMouseDown; + ObjectIdentifier m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing; +}; + +class SelectionHelper final : public MarkHandleProvider +{ +public: + static bool findNamedParent( SdrObject*& pInOutObject + , OUString& rOutName + , bool bGivenObjectMayBeResult ); + static bool findNamedParent( SdrObject*& pInOutObject + , ObjectIdentifier& rOutObject + , bool bGivenObjectMayBeResult ); + static SdrObject* getMarkHandlesObject( SdrObject* pObj ); + static E3dScene* getSceneToRotate( SdrObject* pObj ); + static bool isDragableObjectHitTwice( const Point& rMPos + , const OUString& rNameOfSelectedObject + , const DrawViewWrapper& rDrawViewWrapper ); + + static OUString getHitObjectCID( + const Point& rMPos, + DrawViewWrapper const & rDrawViewWrapper, + bool bGetDiagramInsteadOf_Wall=false ); + + static bool isRotateableObject( std::u16string_view rCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + + explicit SelectionHelper( SdrObject* pSelectedObj ); + virtual ~SelectionHelper(); + + //MarkHandleProvider: + virtual bool getMarkHandles( SdrHdlList& rHdlList ) override; + virtual bool getFrameDragSingles() override; + + SdrObject* getObjectToMark();//sets also internally the mark object + //-> getMarkHandles will behave different if this method has found a Mark Object different from m_pSelectedObj + +private: + SdrObject* m_pSelectedObj;//hit and logically selected object + SdrObject* m_pMarkObj;//object that is marked instead to have more pretty handles +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/SeriesOptionsItemConverter.hxx b/chart2/source/controller/inc/SeriesOptionsItemConverter.hxx new file mode 100644 index 000000000..f9bc42dcc --- /dev/null +++ b/chart2/source/controller/inc/SeriesOptionsItemConverter.hxx @@ -0,0 +1,83 @@ +/* -*- 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 "ItemConverter.hxx" +#include <com/sun/star/uno/Sequence.h> +#include <rtl/ref.hxx> + +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } +namespace chart { class ChartModel; } +namespace chart { class BaseCoordinateSystem; } + +namespace chart::wrapper +{ + +class SeriesOptionsItemConverter final : public ItemConverter +{ +public: + SeriesOptionsItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ); + virtual ~SeriesOptionsItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + css::uno::Reference< css::uno::XComponentContext> m_xCC; + + bool m_bAttachToMainAxis; + bool m_bSupportingOverlapAndGapWidthProperties; + bool m_bSupportingBarConnectors; + + sal_Int32 m_nBarOverlap; + sal_Int32 m_nGapWidth; + bool m_bConnectBars; + + bool m_bSupportingAxisSideBySide; + bool m_bGroupBarsPerAxis; + + bool m_bSupportingStartingAngle; + sal_Int32 m_nStartingAngle; + + bool m_bClockwise; + rtl::Reference< ::chart::BaseCoordinateSystem > m_xCooSys; + + css::uno::Sequence< sal_Int32 > m_aSupportedMissingValueTreatments; + sal_Int32 m_nMissingValueTreatment; + + bool m_bSupportingPlottingOfHiddenCells; + bool m_bIncludeHiddenCells; + + bool m_bHideLegendEntry; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ShapeController.h b/chart2/source/controller/inc/ShapeController.h new file mode 100644 index 000000000..392c28d2f --- /dev/null +++ b/chart2/source/controller/inc/ShapeController.h @@ -0,0 +1,38 @@ +/* -*- 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 . + */ +#ifndef CHART_SHAPECONTROLLER_H +#define CHART_SHAPECONTROLLER_H + +//Command Ids: +#define COMMAND_ID_FORMAT_LINE 1 +#define COMMAND_ID_FORMAT_AREA 2 +#define COMMAND_ID_TEXT_ATTRIBUTES 3 +#define COMMAND_ID_TRANSFORM_DIALOG 4 +#define COMMAND_ID_OBJECT_TITLE_DESCRIPTION 5 +#define COMMAND_ID_RENAME_OBJECT 6 +#define COMMAND_ID_BRING_TO_FRONT 8 +#define COMMAND_ID_FORWARD 9 +#define COMMAND_ID_BACKWARD 10 +#define COMMAND_ID_SEND_TO_BACK 11 +#define COMMAND_ID_FONT_DIALOG 15 +#define COMMAND_ID_PARAGRAPH_DIALOG 16 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/StatisticsItemConverter.hxx b/chart2/source/controller/inc/StatisticsItemConverter.hxx new file mode 100644 index 000000000..b82c1c230 --- /dev/null +++ b/chart2/source/controller/inc/StatisticsItemConverter.hxx @@ -0,0 +1,52 @@ +/* -*- 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 "ItemConverter.hxx" +#include <rtl/ref.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace chart { class ChartModel; } + +namespace chart::wrapper +{ + +class StatisticsItemConverter final : public ItemConverter +{ +public: + StatisticsItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ); + virtual ~StatisticsItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + rtl::Reference<::chart::ChartModel> m_xModel; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TabPageNotifiable.hxx b/chart2/source/controller/inc/TabPageNotifiable.hxx new file mode 100644 index 000000000..440cda2de --- /dev/null +++ b/chart2/source/controller/inc/TabPageNotifiable.hxx @@ -0,0 +1,42 @@ +/* -*- 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 + +// color to use as foreground for an invalid range +#define RANGE_SELECTION_INVALID_RANGE_FOREGROUND_COLOR COL_WHITE +// color to use as background for an invalid range +#define RANGE_SELECTION_INVALID_RANGE_BACKGROUND_COLOR Color(0xff6563) + +class BuilderPage; + +namespace chart +{ +class TabPageNotifiable +{ +public: + virtual void setInvalidPage(BuilderPage* pTabPage) = 0; + virtual void setValidPage(BuilderPage* pTabPage) = 0; + +protected: + ~TabPageNotifiable() {} +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TextDirectionListBox.hxx b/chart2/source/controller/inc/TextDirectionListBox.hxx new file mode 100644 index 000000000..d346a23cb --- /dev/null +++ b/chart2/source/controller/inc/TextDirectionListBox.hxx @@ -0,0 +1,34 @@ +/* -*- 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 <svx/frmdirlbox.hxx> + +namespace chart +{ +class TextDirectionListBox final : public svx::FrameDirectionListBox +{ +public: + explicit TextDirectionListBox(std::unique_ptr<weld::ComboBox> pControl); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TextLabelItemConverter.hxx b/chart2/source/controller/inc/TextLabelItemConverter.hxx new file mode 100644 index 000000000..9df2a65e1 --- /dev/null +++ b/chart2/source/controller/inc/TextLabelItemConverter.hxx @@ -0,0 +1,74 @@ +/* -*- 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 "ItemConverter.hxx" + +#include <com/sun/star/uno/Sequence.h> +#include <rtl/ref.hxx> +#include <vector> + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::frame { class XModel; } +namespace chart { class ChartModel; } +namespace chart { class DataSeries; } + +namespace chart::wrapper { + +class TextLabelItemConverter final : public ItemConverter +{ +public: + TextLabelItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference<css::beans::XPropertySet>& rPropertySet, + const rtl::Reference<::chart::DataSeries>& xSeries, + SfxItemPool& rItemPool, + const css::awt::Size* pRefSize, + bool bDataSeries, + sal_Int32 nNumberFormat, + sal_Int32 nPercentNumberFormat ); + + virtual ~TextLabelItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector<std::unique_ptr<ItemConverter>> maConverters; + sal_Int32 mnNumberFormat; + sal_Int32 mnPercentNumberFormat; + css::uno::Sequence<sal_Int32> maAvailableLabelPlacements; + + bool mbDataSeries:1; + bool mbForbidPercentValue:1; + + rtl::Reference<::chart::DataSeries> m_xSeries; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TimerTriggeredControllerLock.hxx b/chart2/source/controller/inc/TimerTriggeredControllerLock.hxx new file mode 100644 index 000000000..34a4880c0 --- /dev/null +++ b/chart2/source/controller/inc/TimerTriggeredControllerLock.hxx @@ -0,0 +1,58 @@ +/* -*- 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 <vcl/timer.hxx> +#include <rtl/ref.hxx> + +#include <memory> + +namespace com::sun::star::frame +{ +class XModel; +} +namespace chart +{ +class ControllerLockGuardUNO; +} + +namespace chart +{ +class ChartModel; + +class TimerTriggeredControllerLock final +{ +public: + TimerTriggeredControllerLock(const rtl::Reference<::chart::ChartModel>& xModel); + ~TimerTriggeredControllerLock(); + + void startTimer(); + +private: + rtl::Reference<::chart::ChartModel> m_xModel; + std::unique_ptr<ControllerLockGuardUNO> m_apControllerLockGuard; + AutoTimer m_aTimer; + + DECL_LINK(TimerTimeout, Timer*, void); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TitleDialogData.hxx b/chart2/source/controller/inc/TitleDialogData.hxx new file mode 100644 index 000000000..70b03c8a6 --- /dev/null +++ b/chart2/source/controller/inc/TitleDialogData.hxx @@ -0,0 +1,53 @@ +/* -*- 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 <ReferenceSizeProvider.hxx> +#include <memory> +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class ChartModel; + +struct TitleDialogData +{ + css::uno::Sequence< sal_Bool > aPossibilityList; + css::uno::Sequence< sal_Bool > aExistenceList; + css::uno::Sequence< OUString > aTextList; + std::unique_ptr< ReferenceSizeProvider > apReferenceSizeProvider; + + TitleDialogData(std::unique_ptr<ReferenceSizeProvider> pReferenzeSizeProvider = nullptr); + + void readFromModel( const rtl::Reference<::chart::ChartModel>& xChartModel ); + /* return true if anything has changed; + when pOldState is NULL then all data are written to the model + */ + bool writeDifferenceToModel( const rtl::Reference<::chart::ChartModel>& xChartModel + , const css::uno::Reference< css::uno::XComponentContext >& xContext + , const TitleDialogData* pOldState=nullptr ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TitleItemConverter.hxx b/chart2/source/controller/inc/TitleItemConverter.hxx new file mode 100644 index 000000000..5a2686d62 --- /dev/null +++ b/chart2/source/controller/inc/TitleItemConverter.hxx @@ -0,0 +1,59 @@ +/* -*- 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 "ItemConverter.hxx" + +#include <vector> + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper { + +class TitleItemConverter final : public ItemConverter +{ +public: + TitleItemConverter( + const css::uno::Reference<css::beans::XPropertySet>& rPropertySet, + SfxItemPool& rItemPool, SdrModel& rDrawModel, + const css::uno::Reference<css::lang::XMultiServiceFactory>& xNamedPropertyContainerFactory, + const css::awt::Size* pRefSize ); + + virtual ~TitleItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr<ItemConverter> > m_aConverters; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ViewElementListProvider.hxx b/chart2/source/controller/inc/ViewElementListProvider.hxx new file mode 100644 index 000000000..d8b8ffc42 --- /dev/null +++ b/chart2/source/controller/inc/ViewElementListProvider.hxx @@ -0,0 +1,63 @@ +/* -*- 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 <memory> +#include <svx/xtable.hxx> + +class FontList; +class SdrObjList; +class SfxItemSet; + +namespace chart +{ + +class DrawModelWrapper; + +class ViewElementListProvider final +{ +public: + ViewElementListProvider( DrawModelWrapper* pDrawModelWrapper ); + ViewElementListProvider(ViewElementListProvider&&) noexcept; + ~ViewElementListProvider(); + + XColorListRef GetColorTable() const; + XDashListRef GetDashList() const; + XLineEndListRef GetLineEndList() const; + XGradientListRef GetGradientList() const; + XHatchListRef GetHatchList() const; + XBitmapListRef GetBitmapList() const; + XPatternListRef GetPatternList() const; + + //create chartspecific symbols for linecharts + SdrObjList* GetSymbolList() const; + Graphic GetSymbolGraphic( sal_Int32 nStandardSymbol, const SfxItemSet* pSymbolShapeProperties ) const; + + FontList* getFontList() const; + //SfxPrinter* getPrinter(); + +private: + DrawModelWrapper* m_pDrawModelWrapper; + mutable std::unique_ptr<FontList> m_pFontList; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ChartType.hxx b/chart2/source/controller/inc/dlg_ChartType.hxx new file mode 100644 index 000000000..7520869e8 --- /dev/null +++ b/chart2/source/controller/inc/dlg_ChartType.hxx @@ -0,0 +1,48 @@ +/* -*- 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 <vcl/weld.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class ChartModel; +class ChartTypeTabPage; + +class ChartTypeDialog final : public weld::GenericDialogController +{ +public: + ChartTypeDialog(weld::Window* pWindow, const rtl::Reference<::chart::ChartModel>& xChartModel); + virtual ~ChartTypeDialog() override; + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + std::unique_ptr<weld::Container> m_xContentArea; + std::unique_ptr<ChartTypeTabPage> m_xChartTypeTabPage; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ChartType_UNO.hxx b/chart2/source/controller/inc/dlg_ChartType_UNO.hxx new file mode 100644 index 000000000..4566ec751 --- /dev/null +++ b/chart2/source/controller/inc/dlg_ChartType_UNO.hxx @@ -0,0 +1,67 @@ +/* -*- 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 <comphelper/proparrhlp.hxx> +#include <svtools/genericunodialog.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::beans { class XPropertySetInfo; } + +namespace chart +{ +class ChartModel; + +typedef ::svt::OGenericUnoDialog ChartTypeUnoDlg_BASE; +class ChartTypeUnoDlg final : public ChartTypeUnoDlg_BASE + ,public ::comphelper::OPropertyArrayUsageHelper< ChartTypeUnoDlg > +{ +public: + ChartTypeUnoDlg( const css::uno::Reference< css::uno::XComponentContext >& xContext ); + +private: + virtual ~ChartTypeUnoDlg() override; + + // OGenericUnoDialog overridables + virtual void implInitialize(const css::uno::Any& _rValue) override; + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override; + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + ChartTypeUnoDlg(const ChartTypeUnoDlg&) = delete; + void operator =(const ChartTypeUnoDlg&) = delete; + + rtl::Reference<::chart::ChartModel> m_xChartModel; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_CreationWizard.hxx b/chart2/source/controller/inc/dlg_CreationWizard.hxx new file mode 100644 index 000000000..a0fcc9dae --- /dev/null +++ b/chart2/source/controller/inc/dlg_CreationWizard.hxx @@ -0,0 +1,83 @@ +/* -*- 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 "TimerTriggeredControllerLock.hxx" +#include "TabPageNotifiable.hxx" + +#include <rtl/ref.hxx> +#include <vcl/roadmapwizard.hxx> + +#include <memory> + +namespace com::sun::star::chart2 +{ +class XChartDocument; +} +namespace com::sun::star::uno +{ +class XComponentContext; +} + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace chart +{ +class ChartModel; +class ChartTypeTemplateProvider; +class DialogModel; + +class CreationWizard final : public vcl::RoadmapWizardMachine, public TabPageNotifiable +{ +public: + CreationWizard(weld::Window* pParent, const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference<css::uno::XComponentContext>& xContext); + + CreationWizard() = delete; + virtual ~CreationWizard() override; + + // TabPageNotifiable + virtual void setInvalidPage(BuilderPage* pTabPage) override; + virtual void setValidPage(BuilderPage* pTabPage) override; + +protected: + virtual bool leaveState(WizardState _nState) override; + virtual WizardState determineNextState(WizardState nCurrentState) const override; + virtual void enterState(WizardState nState) override; + + virtual OUString getStateDisplayName(WizardState nState) const override; + +private: + virtual std::unique_ptr<BuilderPage> createPage(WizardState nState) override; + + rtl::Reference<::chart::ChartModel> m_xChartModel; + css::uno::Reference<css::uno::XComponentContext> m_xComponentContext; + ChartTypeTemplateProvider* m_pTemplateProvider; + std::unique_ptr<DialogModel> m_pDialogModel; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + bool m_bCanTravel; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_CreationWizard_UNO.hxx b/chart2/source/controller/inc/dlg_CreationWizard_UNO.hxx new file mode 100644 index 000000000..7e1792f08 --- /dev/null +++ b/chart2/source/controller/inc/dlg_CreationWizard_UNO.hxx @@ -0,0 +1,116 @@ +/* -*- 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/basemutex.hxx> +#include <cppuhelper/component.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp> +#include <rtl/ref.hxx> + +#include "dlg_CreationWizard.hxx" +#include <tools/link.hxx> + +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } + +class VclWindowEvent; + +namespace chart +{ +class ChartModel; + +class CreationWizardUnoDlg final : public cppu::BaseMutex + , public ::cppu::OComponentHelper + , public css::ui::dialogs::XAsynchronousExecutableDialog + , public css::lang::XServiceInfo + , public css::lang::XInitialization + , public css::frame::XTerminateListener + , public css::beans::XPropertySet +{ +public: + CreationWizardUnoDlg() = delete; + + CreationWizardUnoDlg( const css::uno::Reference< css::uno::XComponentContext >& xContext ); + virtual ~CreationWizardUnoDlg() override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual css::uno::Any SAL_CALL queryAggregation( css::uno::Type const & rType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // XServiceInfo + 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; + + // XAsynchronousExecutableDialog + virtual void SAL_CALL setDialogTitle( const OUString& aTitle ) override; + virtual void SAL_CALL startExecuteModal( const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& xListener ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override; + + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + //XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + +protected: + // ____ OComponentHelper ____ + /// Called in dispose method after the listeners were notified. + virtual void SAL_CALL disposing() override; + +private: + void createDialogOnDemand(); + DECL_STATIC_LINK(CreationWizardUnoDlg, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*); + +private: + rtl::Reference< ::chart::ChartModel > m_xChartModel; + css::uno::Reference< css::uno::XComponentContext> m_xCC; + css::uno::Reference< css::awt::XWindow > m_xParentWindow; + + std::shared_ptr<CreationWizard> m_xDialog; + bool m_bUnlockControllersOnExecute; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_DataEditor.hxx b/chart2/source/controller/inc/dlg_DataEditor.hxx new file mode 100644 index 000000000..5156e0831 --- /dev/null +++ b/chart2/source/controller/inc/dlg_DataEditor.hxx @@ -0,0 +1,73 @@ +/* -*- 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 <vcl/weld.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star::uno { class XComponentContext; } +namespace comphelper { template <class Tp, class Arg> class mem_fun1_t; } + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + } +} + +namespace chart +{ +class ChartModel; +class DataBrowser; + +class DataEditor final : public weld::GenericDialogController +{ +public: + DataEditor(weld::Window* pParent, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const css::uno::Reference<css::uno::XComponentContext> & xContext); + virtual ~DataEditor() override; + + DECL_LINK(CloseHdl, weld::Button&, void); + + void SetReadOnly( bool bReadOnly ); + +private: + bool m_bReadOnly; + + rtl::Reference<::chart::ChartModel> m_xChartDoc; + css::uno::Reference<css::uno::XComponentContext> m_xContext; + + std::unique_ptr<weld::Toolbar> m_xTbxData; + std::unique_ptr<weld::Button> m_xCloseBtn; + std::unique_ptr<weld::Container> m_xTable; + std::unique_ptr<weld::Container> m_xColumns; + std::unique_ptr<weld::Container> m_xColors; + css::uno::Reference<css::awt::XWindow> m_xTableCtrlParent; + VclPtr<DataBrowser> m_xBrwData; + + /// handles actions of the toolbox + DECL_LINK( ToolboxHdl, const OString&, void ); + /// is called, if the cursor of the table has moved + DECL_LINK( BrowserCursorMovedHdl, DataBrowser*, void); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_DataSource.hxx b/chart2/source/controller/inc/dlg_DataSource.hxx new file mode 100644 index 000000000..2dce4169d --- /dev/null +++ b/chart2/source/controller/inc/dlg_DataSource.hxx @@ -0,0 +1,75 @@ +/* -*- 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 "TabPageNotifiable.hxx" +#include <vcl/weld.hxx> +#include <memory> + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::uno { class XComponentContext; } +class BuilderPage; + +namespace chart +{ +class ChartModel; +class ChartTypeTemplateProvider; +class DataSourceTabPage; +class DialogModel; +class RangeChooserTabPage; + +class DataSourceDialog final : + public weld::GenericDialogController, + public TabPageNotifiable +{ +public: + explicit DataSourceDialog( + weld::Window * pParent, + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + virtual ~DataSourceDialog() override; + + // from GenericDialogController base + virtual short run() override; + + // TabPageNotifiable + virtual void setInvalidPage( BuilderPage * pTabPage ) override; + virtual void setValidPage( BuilderPage * pTabPage ) override; + +private: + DECL_LINK(ActivatePageHdl, const OString&, void); + DECL_LINK(DeactivatePageHdl, const OString&, bool); + + std::unique_ptr< ChartTypeTemplateProvider > m_apDocTemplateProvider; + std::unique_ptr< DialogModel > m_apDialogModel; + + std::unique_ptr<RangeChooserTabPage> m_xRangeChooserTabPage; + std::unique_ptr<DataSourceTabPage> m_xDataSourceTabPage; + bool m_bRangeChooserTabIsValid; + bool m_bDataSourceTabIsValid; + bool m_bTogglingEnabled; + + std::unique_ptr<weld::Notebook> m_xTabControl; + std::unique_ptr<weld::Button> m_xBtnOK; + + static sal_uInt16 m_nLastPageId; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertAxis_Grid.hxx b/chart2/source/controller/inc/dlg_InsertAxis_Grid.hxx new file mode 100644 index 000000000..b69ab70f6 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertAxis_Grid.hxx @@ -0,0 +1,68 @@ +/* -*- 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 <vcl/weld.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +namespace chart +{ +struct InsertAxisOrGridDialogData +{ + css::uno::Sequence<sal_Bool> aPossibilityList; + css::uno::Sequence<sal_Bool> aExistenceList; + + InsertAxisOrGridDialogData(); +}; + +/************************************************************************* +|* +|* insert Axis dialog (also base for grid dialog) +|* +\************************************************************************/ +class SchAxisDlg : public weld::GenericDialogController +{ +protected: + std::unique_ptr<weld::CheckButton> m_xCbPrimaryX; + std::unique_ptr<weld::CheckButton> m_xCbPrimaryY; + std::unique_ptr<weld::CheckButton> m_xCbPrimaryZ; + std::unique_ptr<weld::CheckButton> m_xCbSecondaryX; + std::unique_ptr<weld::CheckButton> m_xCbSecondaryY; + std::unique_ptr<weld::CheckButton> m_xCbSecondaryZ; + +public: + SchAxisDlg(weld::Window* pParent, const InsertAxisOrGridDialogData& rInput, + bool bAxisDlg = true); + void getResult(InsertAxisOrGridDialogData& rOutput); +}; + +/************************************************************************* +|* +|* Grid dialog +|* +\************************************************************************/ +class SchGridDlg final : public SchAxisDlg +{ +public: + SchGridDlg(weld::Window* pParent, const InsertAxisOrGridDialogData& rInput); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertDataLabel.hxx b/chart2/source/controller/inc/dlg_InsertDataLabel.hxx new file mode 100644 index 000000000..7777db3c9 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertDataLabel.hxx @@ -0,0 +1,46 @@ +/* -*- 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 <vcl/weld.hxx> +#include <svl/itemset.hxx> +#include <memory> + +class SvNumberFormatter; + +namespace chart +{ +class DataLabelResources; + +class DataLabelsDialog final : public weld::GenericDialogController +{ +private: + std::unique_ptr<DataLabelResources> m_apDataLabelResources; + +public: + DataLabelsDialog(weld::Window* pParent, const SfxItemSet& rInAttrs, + SvNumberFormatter* pFormatter); + virtual ~DataLabelsDialog() override; + + void FillItemSet(SfxItemSet& rOutAttrs); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertErrorBars.hxx b/chart2/source/controller/inc/dlg_InsertErrorBars.hxx new file mode 100644 index 000000000..e68036153 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertErrorBars.hxx @@ -0,0 +1,56 @@ +/* -*- 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 <memory> +#include <vcl/weld.hxx> +#include <svl/itemset.hxx> + +#include "res_ErrorBar.hxx" + +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class InsertErrorBarsDialog final : public weld::GenericDialogController +{ +public: + InsertErrorBarsDialog(weld::Window* pParent, const SfxItemSet& rMyAttrs, + const rtl::Reference<::chart::ChartModel>& xChartDocument, + ErrorBarResources::tErrorBarType eType); + + void SetAxisMinorStepWidthForErrorBarDecimals(double fMinorStepWidth); + + static double getAxisMinorStepWidthForErrorBarDecimals( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference<css::uno::XInterface>& xChartView, + const OUString& rSelectedObjectCID); + + void FillItemSet(SfxItemSet& rOutAttrs); + +private: + std::unique_ptr<ErrorBarResources> m_apErrorBarResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertLegend.hxx b/chart2/source/controller/inc/dlg_InsertLegend.hxx new file mode 100644 index 000000000..0e2cccc38 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertLegend.hxx @@ -0,0 +1,49 @@ +/* -*- 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 <vcl/weld.hxx> +#include <rtl/ref.hxx> + +#include <memory> + +#include "res_LegendPosition.hxx" + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class ChartModel; + +class SchLegendDlg final : public weld::GenericDialogController +{ +private: + std::unique_ptr<LegendPositionResources> m_xLegendPositionResources; + +public: + SchLegendDlg(weld::Window* pParent, const css::uno::Reference< css::uno::XComponentContext>& xCC); + + void init( const rtl::Reference<::chart::ChartModel>& xChartModel ); + void writeToModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) const; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertTitle.hxx b/chart2/source/controller/inc/dlg_InsertTitle.hxx new file mode 100644 index 000000000..096628529 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertTitle.hxx @@ -0,0 +1,40 @@ +/* -*- 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 "res_Titles.hxx" +#include <vcl/weld.hxx> +#include <memory> + +namespace chart +{ +class SchTitleDlg final : public weld::GenericDialogController +{ +private: + std::unique_ptr<TitleResources> m_xTitleResources; + +public: + SchTitleDlg(weld::Window* pParent, const TitleDialogData& rInput); + + void getResult(TitleDialogData& rOutput); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ObjectProperties.hxx b/chart2/source/controller/inc/dlg_ObjectProperties.hxx new file mode 100644 index 000000000..238ccc83b --- /dev/null +++ b/chart2/source/controller/inc/dlg_ObjectProperties.hxx @@ -0,0 +1,145 @@ +/* -*- 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 <ObjectIdentifier.hxx> +#include <sfx2/tabdlg.hxx> + +namespace com::sun::star::util { class XNumberFormatsSupplier; } +class Graphic; + +namespace chart +{ + +class ObjectPropertiesDialogParameter final +{ +public: + ObjectPropertiesDialogParameter( const OUString& rObjectCID ); + ~ObjectPropertiesDialogParameter(); + + void init( const rtl::Reference<::chart::ChartModel>& xModel ); + ObjectType getObjectType() const { return m_eObjectType;} + const OUString& getLocalizedName() const { return m_aLocalizedName;} + + bool HasGeometryProperties() const { return m_bHasGeometryProperties;} + bool HasStatisticProperties() const { return m_bHasStatisticProperties;} + bool ProvidesSecondaryYAxis() const { return m_bProvidesSecondaryYAxis;} + bool ProvidesOverlapAndGapWidth() const { return m_bProvidesOverlapAndGapWidth;} + bool ProvidesBarConnectors() const { return m_bProvidesBarConnectors;} + bool HasAreaProperties() const { return m_bHasAreaProperties;} + bool HasSymbolProperties() const { return m_bHasSymbolProperties;} + bool HasNumberProperties() const { return m_bHasNumberProperties;} + bool ProvidesStartingAngle() const { return m_bProvidesStartingAngle;} + bool ProvidesMissingValueTreatments() const { return m_bProvidesMissingValueTreatments;} + bool IsPieChartDataPoint() const { return m_bIsPieChartDataPoint;} + + bool HasScaleProperties() const { return m_bHasScaleProperties;} + bool CanAxisLabelsBeStaggered() const { return m_bCanAxisLabelsBeStaggered;} + bool IsSupportingAxisPositioning() const { return m_bSupportingAxisPositioning;} + bool ShowAxisOrigin() const { return m_bShowAxisOrigin;} + bool IsCrossingAxisIsCategoryAxis() const { return m_bIsCrossingAxisIsCategoryAxis;} + bool IsSupportingCategoryPositioning() const { return m_bSupportingCategoryPositioning;} + const css::uno::Sequence< OUString >& GetCategories() const { return m_aCategories;} + + const rtl::Reference<::chart::ChartModel>& + getDocument() const { return m_xChartDocument;} + + bool IsComplexCategoriesAxis() const { return m_bComplexCategoriesAxis;} + + sal_Int32 getNbPoints() const { return m_nNbPoints;} + +private: + OUString m_aObjectCID; + ObjectType m_eObjectType; + bool m_bAffectsMultipleObjects;//is true if more than one object of the given type will be changed (e.g. all axes or all titles) + + OUString m_aLocalizedName; + + bool m_bHasGeometryProperties; + bool m_bHasStatisticProperties; + bool m_bProvidesSecondaryYAxis; + bool m_bProvidesOverlapAndGapWidth; + bool m_bProvidesBarConnectors; + bool m_bHasAreaProperties; + bool m_bHasSymbolProperties; + bool m_bHasNumberProperties; + bool m_bProvidesStartingAngle; + bool m_bProvidesMissingValueTreatments; + bool m_bIsPieChartDataPoint; + + bool m_bHasScaleProperties; + bool m_bCanAxisLabelsBeStaggered; + + bool m_bSupportingAxisPositioning; + bool m_bShowAxisOrigin; + bool m_bIsCrossingAxisIsCategoryAxis; + bool m_bSupportingCategoryPositioning; + css::uno::Sequence< OUString > m_aCategories; + + rtl::Reference<::chart::ChartModel> m_xChartDocument; + + bool m_bComplexCategoriesAxis; + + sal_Int32 m_nNbPoints; +}; + +/************************************************************************* +|* +|* dialog for properties of different chart object +|* +\************************************************************************/ + +class ViewElementListProvider; + +class SchAttribTabDlg final : public SfxTabDialogController +{ +private: + const ObjectPropertiesDialogParameter * const m_pParameter; + const ViewElementListProvider* const m_pViewElementListProvider; + SvNumberFormatter* m_pNumberFormatter; + + std::optional<SfxItemSet> m_oSymbolShapeProperties; + std::unique_ptr<Graphic> m_pAutoSymbolGraphic; + + double m_fAxisMinorStepWidthForErrorBarDecimals; + bool m_bOKPressed; + + DECL_LINK(OKPressed, weld::Button&, void); + + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; + +public: + SchAttribTabDlg(weld::Window* pParent, const SfxItemSet* pAttr, + const ObjectPropertiesDialogParameter* pDialogParameter, + const ViewElementListProvider* pViewElementListProvider, + const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier ); + virtual ~SchAttribTabDlg() override; + + //pSymbolShapeProperties: Properties to be set on the symbollist shapes + //pAutoSymbolGraphic: Graphic to be shown if AutoSymbol gets selected + void setSymbolInformation( SfxItemSet&& rSymbolShapeProperties, std::unique_ptr<Graphic> pAutoSymbolGraphic ); + + void SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ); + + bool DialogWasClosedWithOK() const { return m_bOKPressed;} +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ShapeFont.hxx b/chart2/source/controller/inc/dlg_ShapeFont.hxx new file mode 100644 index 000000000..6998ba470 --- /dev/null +++ b/chart2/source/controller/inc/dlg_ShapeFont.hxx @@ -0,0 +1,43 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +namespace chart +{ +class ViewElementListProvider; + +/** dialog for font properties of shapes + */ +class ShapeFontDialog final : public SfxTabDialogController +{ +public: + ShapeFontDialog(weld::Window* pParent, const SfxItemSet* pAttr, + const ViewElementListProvider* pViewElementListProvider); + +private: + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; + + const ViewElementListProvider* m_pViewElementListProvider; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ShapeParagraph.hxx b/chart2/source/controller/inc/dlg_ShapeParagraph.hxx new file mode 100644 index 000000000..9d4d7496d --- /dev/null +++ b/chart2/source/controller/inc/dlg_ShapeParagraph.hxx @@ -0,0 +1,38 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +namespace chart +{ +/** dialog for paragraph properties of shapes + */ +class ShapeParagraphDialog final : public SfxTabDialogController +{ +public: + ShapeParagraphDialog(weld::Window* pParent, const SfxItemSet* pAttr); + +private: + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_View3D.hxx b/chart2/source/controller/inc/dlg_View3D.hxx new file mode 100644 index 000000000..c165e8285 --- /dev/null +++ b/chart2/source/controller/inc/dlg_View3D.hxx @@ -0,0 +1,58 @@ +/* -*- 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 <vcl/weld.hxx> +#include <ControllerLockGuard.hxx> + +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class ThreeD_SceneGeometry_TabPage; +class ThreeD_SceneAppearance_TabPage; +class ThreeD_SceneIllumination_TabPage; + +class View3DDialog final : public weld::GenericDialogController +{ +public: + View3DDialog(weld::Window* pWindow, const rtl::Reference<::chart::ChartModel>& xChartModel); + virtual ~View3DDialog() override; + + virtual short run() override; + +private: + DECL_LINK(ActivatePageHdl, const OString&, void); + + ControllerLockHelper m_aControllerLocker; + + static sal_uInt16 m_nLastPageId; + + std::unique_ptr<weld::Notebook> m_xTabControl; + std::unique_ptr<ThreeD_SceneGeometry_TabPage> m_xGeometry; + std::unique_ptr<ThreeD_SceneAppearance_TabPage> m_xAppearance; + std::unique_ptr<ThreeD_SceneIllumination_TabPage> m_xIllumination; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/helpids.h b/chart2/source/controller/inc/helpids.h new file mode 100644 index 000000000..69a23771c --- /dev/null +++ b/chart2/source/controller/inc/helpids.h @@ -0,0 +1,32 @@ +/* -*- 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 <rtl/string.hxx> + +inline constexpr OStringLiteral HID_SCH_WIN_DOCUMENT = "CHART2_HID_SCH_WIN_DOCUMENT"; +inline constexpr OStringLiteral HID_SCH_ERROR_BARS_FROM_DATA = "CHART2_SCH_ERROR_BARS_FROM_DATA"; + + + +inline constexpr OStringLiteral HID_SCH_WIZARD_ROADMAP = "CHART2_HID_SCH_WIZARD_ROADMAP"; +inline constexpr OStringLiteral HID_SCH_DATA_SERIES_LABEL = "CHART2_HID_SCH_DATA_SERIES_LABEL"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/res_ErrorBar.hxx b/chart2/source/controller/inc/res_ErrorBar.hxx new file mode 100644 index 000000000..c3521d5ba --- /dev/null +++ b/chart2/source/controller/inc/res_ErrorBar.hxx @@ -0,0 +1,142 @@ +/* -*- 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 <memory> +#include <tools/link.hxx> +#include <svl/itemset.hxx> +#include <svx/chrtitem.hxx> +#include "RangeSelectionListener.hxx" +#include <rtl/ref.hxx> + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace weld { class Builder; } +namespace weld { class Button; } +namespace weld { class CheckButton; } +namespace weld { class ComboBox; } +namespace weld { class DialogController; } +namespace weld { class Entry; } +namespace weld { class Frame; } +namespace weld { class Image; } +namespace weld { class Label; } +namespace weld { class MetricSpinButton; } +namespace weld { class RadioButton; } +namespace weld { class Toggleable; } +namespace weld { class Widget; } + +namespace chart +{ +class ChartModel; +class RangeSelectionHelper; + +class ErrorBarResources final : public RangeSelectionListenerParent +{ +public: + enum tErrorBarType + { + ERROR_BAR_X, + ERROR_BAR_Y + }; + + ErrorBarResources( + weld::Builder* pParent, weld::DialogController* pControllerDialog, const SfxItemSet& rInAttrs, bool bNoneAvailable, chart::ErrorBarResources::tErrorBarType eType = ERROR_BAR_Y); + virtual ~ErrorBarResources(); + + void SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ); + void SetErrorBarType( tErrorBarType eNewType ); + void SetChartDocumentForRangeChoosing( + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + void Reset(const SfxItemSet& rInAttrs); + void FillItemSet(SfxItemSet& rOutAttrs) const; + + void FillValueSets(); + + // ____ RangeSelectionListenerParent ____ + virtual void listeningFinished( const OUString & rNewRange ) override; + virtual void disposingRangeSelection() override; + +private: + SvxChartKindError m_eErrorKind; + SvxChartIndicate m_eIndicate; + + bool m_bErrorKindUnique; + bool m_bIndicatorUnique; + bool m_bRangePosUnique; + bool m_bRangeNegUnique; + + tErrorBarType m_eErrorBarType; + sal_uInt16 m_nConstDecimalDigits; + sal_Int64 m_nConstSpinSize; + double m_fPlusValue; + double m_fMinusValue; + + weld::DialogController* m_pController; + std::unique_ptr< RangeSelectionHelper > m_apRangeSelectionHelper; + weld::Entry* m_pCurrentRangeChoosingField; + bool m_bHasInternalDataProvider; + bool m_bEnableDataTableDialog; + + + // category + std::unique_ptr<weld::RadioButton> m_xRbNone; + std::unique_ptr<weld::RadioButton> m_xRbConst; + std::unique_ptr<weld::RadioButton> m_xRbPercent; + std::unique_ptr<weld::RadioButton> m_xRbFunction; + std::unique_ptr<weld::RadioButton> m_xRbRange; + std::unique_ptr<weld::ComboBox> m_xLbFunction; + + // parameters + std::unique_ptr<weld::Frame> m_xFlParameters; + std::unique_ptr<weld::Widget> m_xBxPositive; + std::unique_ptr<weld::MetricSpinButton> m_xMfPositive; + std::unique_ptr<weld::Entry> m_xEdRangePositive; + std::unique_ptr<weld::Button> m_xIbRangePositive; + std::unique_ptr<weld::Widget> m_xBxNegative; + std::unique_ptr<weld::MetricSpinButton> m_xMfNegative; + std::unique_ptr<weld::Entry> m_xEdRangeNegative; + std::unique_ptr<weld::Button> m_xIbRangeNegative; + std::unique_ptr<weld::CheckButton> m_xCbSyncPosNeg; + + // indicator + std::unique_ptr<weld::RadioButton> m_xRbBoth; + std::unique_ptr<weld::RadioButton> m_xRbPositive; + std::unique_ptr<weld::RadioButton> m_xRbNegative; + std::unique_ptr<weld::Image> m_xFiBoth; + std::unique_ptr<weld::Image> m_xFiPositive; + std::unique_ptr<weld::Image> m_xFiNegative; + + std::unique_ptr<weld::Label> m_xUIStringPos; + std::unique_ptr<weld::Label> m_xUIStringNeg; + std::unique_ptr<weld::Label> m_xUIStringRbRange; + + DECL_LINK( CategoryChosen, weld::Toggleable&, void ); + DECL_LINK( CategoryChosen2, weld::ComboBox&, void ); + DECL_LINK( SynchronizePosAndNeg, weld::Toggleable&, void ); + DECL_LINK( PosValueChanged, weld::MetricSpinButton&, void ); + DECL_LINK( IndicatorChanged, weld::Toggleable&, void ); + DECL_LINK( ChooseRange, weld::Button&, void ); + DECL_LINK( RangeChanged, weld::Entry&, void ); + + void UpdateControlStates(); + void isRangeFieldContentValid(weld::Entry& rEdit); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/res_LegendPosition.hxx b/chart2/source/controller/inc/res_LegendPosition.hxx new file mode 100644 index 000000000..ca0870dd4 --- /dev/null +++ b/chart2/source/controller/inc/res_LegendPosition.hxx @@ -0,0 +1,75 @@ +/* -*- 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 <svl/itemset.hxx> +#include <tools/link.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } +namespace weld { class Builder; } +namespace weld { class CheckButton; } +namespace weld { class RadioButton; } +namespace weld { class Toggleable; } + +namespace chart +{ +class ChartModel; + +class LegendPositionResources final +{ + +public: + //constructor without Display checkbox + LegendPositionResources(weld::Builder& rBuilder); + //constructor inclusive Display checkbox + LegendPositionResources(weld::Builder& rBuilder, const css::uno::Reference< + css::uno::XComponentContext>& xCC ); + ~LegendPositionResources(); + + void writeToResources( const rtl::Reference<::chart::ChartModel>& xChartModel ); + void writeToModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) const; + + void initFromItemSet( const SfxItemSet& rInAttrs ); + void writeToItemSet( SfxItemSet& rOutAttrs ) const; + + void SetChangeHdl( const Link<LinkParamNone*,void>& rLink ); + + DECL_LINK( PositionEnableHdl, weld::Toggleable&, void ); + DECL_LINK( PositionChangeHdl, weld::Toggleable&, void ); + +private: + void impl_setRadioButtonToggleHdl(); + void PositionEnable(); + +private: + css::uno::Reference< css::uno::XComponentContext> m_xCC; + Link<LinkParamNone*,void> m_aChangeLink; + + std::unique_ptr<weld::CheckButton> m_xCbxShow; + std::unique_ptr<weld::RadioButton> m_xRbtLeft; + std::unique_ptr<weld::RadioButton> m_xRbtRight; + std::unique_ptr<weld::RadioButton> m_xRbtTop; + std::unique_ptr<weld::RadioButton> m_xRbtBottom; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/res_Titles.hxx b/chart2/source/controller/inc/res_Titles.hxx new file mode 100644 index 000000000..a7a2eba57 --- /dev/null +++ b/chart2/source/controller/inc/res_Titles.hxx @@ -0,0 +1,73 @@ +/* -*- 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 "TitleDialogData.hxx" + +template <typename Arg, typename Ret> class Link; +namespace weld +{ +class Builder; +} +namespace weld +{ +class Entry; +} +namespace weld +{ +class Label; +} + +namespace chart +{ +class TitleResources final +{ +public: + TitleResources(weld::Builder& rParent, bool bShowSecondaryAxesTitle); + ~TitleResources(); + + void writeToResources(const TitleDialogData& rInput); + void readFromResources(TitleDialogData& rOutput); + + void connect_changed(const Link<weld::Entry&, void>& rLink); + bool get_value_changed_from_saved() const; + void save_value(); + +private: + std::unique_ptr<weld::Label> m_xFT_Main; + std::unique_ptr<weld::Label> m_xFT_Sub; + std::unique_ptr<weld::Entry> m_xEd_Main; + std::unique_ptr<weld::Entry> m_xEd_Sub; + + std::unique_ptr<weld::Label> m_xFT_XAxis; + std::unique_ptr<weld::Label> m_xFT_YAxis; + std::unique_ptr<weld::Label> m_xFT_ZAxis; + std::unique_ptr<weld::Entry> m_xEd_XAxis; + std::unique_ptr<weld::Entry> m_xEd_YAxis; + std::unique_ptr<weld::Entry> m_xEd_ZAxis; + + std::unique_ptr<weld::Label> m_xFT_SecondaryXAxis; + std::unique_ptr<weld::Label> m_xFT_SecondaryYAxis; + std::unique_ptr<weld::Entry> m_xEd_SecondaryXAxis; + std::unique_ptr<weld::Entry> m_xEd_SecondaryYAxis; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/uiobject.hxx b/chart2/source/controller/inc/uiobject.hxx new file mode 100644 index 000000000..b40fffb44 --- /dev/null +++ b/chart2/source/controller/inc/uiobject.hxx @@ -0,0 +1,68 @@ +/* -*- 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/. + */ + +#pragma once + +#include <memory> +#include <vcl/uitest/uiobject.hxx> + +#include "ChartWindow.hxx" + +class ChartUIObject final : public UIObject +{ +public: + + ChartUIObject(const VclPtr<chart::ChartWindow>& xChartWindow, + const OUString& rCID); + + StringMap get_state() override; + + virtual void execute(const OUString& rAction, + const StringMap& rParameters) override; + + virtual std::unique_ptr<UIObject> get_child(const OUString& rID) override; + + virtual std::set<OUString> get_children() const override; + + virtual OUString get_type() const override; + +private: + + OUString maCID; + VclPtr<chart::ChartWindow> mxChartWindow; + std::vector<std::unique_ptr<OUString>> maCommands; + + DECL_LINK(PostCommand, void*, void); +}; + +class ChartWindowUIObject final : public WindowUIObject +{ + VclPtr<chart::ChartWindow> mxChartWindow; + +public: + + ChartWindowUIObject(const VclPtr<chart::ChartWindow>& xChartWindow); + + virtual StringMap get_state() override; + + virtual void execute(const OUString& rAction, + const StringMap& rParameters) override; + + virtual std::unique_ptr<UIObject> get_child(const OUString& rID) override; + + virtual std::set<OUString> get_children() const override; + + static std::unique_ptr<UIObject> create(vcl::Window* pWindow); + +protected: + + virtual OUString get_name() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/AxisItemConverter.cxx b/chart2/source/controller/itemsetwrapper/AxisItemConverter.cxx new file mode 100644 index 000000000..20ad1504f --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/AxisItemConverter.cxx @@ -0,0 +1,987 @@ +/* -*- 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 <AxisItemConverter.hxx> +#include <ItemPropertyMap.hxx> +#include <CharacterPropertyItemConverter.hxx> +#include <GraphicPropertyItemConverter.hxx> +#include <chartview/ChartSfxItemIds.hxx> +#include <chartview/ExplicitScaleValues.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include "SchWhichPairs.hxx" +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <CommonConverters.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <Diagram.hxx> +#include <unonames.hxx> +#include <BaseCoordinateSystem.hxx> +#include <memory> + +#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/chart/TimeInterval.hpp> +#include <com/sun/star/chart2/XAxis.hpp> +#include <com/sun/star/chart2/AxisOrientation.hpp> +#include <com/sun/star/chart2/AxisType.hpp> + +#include <osl/diagnose.h> +#include <o3tl/any.hxx> +#include <svl/eitem.hxx> +#include <svx/chrtitem.hxx> +#include <svx/sdangitm.hxx> +#include <svl/intitem.hxx> +#include <rtl/math.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::chart::TimeInterval; +using ::com::sun::star::chart::TimeIncrement; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetAxisPropertyMap() +{ + static ItemPropertyMapType aAxisPropertyMap{ + {SCHATTR_AXIS_SHOWDESCR, {"DisplayLabels", 0}}, + {SCHATTR_AXIS_TICKS, {"MajorTickmarks", 0}}, + {SCHATTR_AXIS_HELPTICKS, {"MinorTickmarks", 0}}, + {SCHATTR_AXIS_LABEL_ORDER, {"ArrangeOrder", 0}}, + {SCHATTR_TEXT_STACKED, {"StackCharacters", 0}}, + {SCHATTR_AXIS_LABEL_BREAK, {"TextBreak", 0}}, + {SCHATTR_AXIS_LABEL_OVERLAP, {"TextOverlap", 0}}}; + return aAxisPropertyMap; +}; + +} // anonymous namespace + +AxisItemConverter::AxisItemConverter( + const Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + ::chart::ExplicitScaleData const * pScale /* = NULL */, + ::chart::ExplicitIncrementData const * pIncrement /* = NULL */, + const awt::Size* pRefSize ) : + ItemConverter( rPropertySet, rItemPool ), + m_xChartDoc( xChartDoc ) +{ + if( pScale ) + m_pExplicitScale.reset( new ::chart::ExplicitScaleData( *pScale ) ); + if( pIncrement ) + m_pExplicitIncrement.reset( new ::chart::ExplicitIncrementData( *pIncrement ) ); + + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, + xChartDoc, + GraphicObjectType::LineProperties )); + m_aConverters.emplace_back( + new CharacterPropertyItemConverter(rPropertySet, rItemPool, pRefSize, "ReferencePageSize")); + + m_xAxis.set( Reference< chart2::XAxis >( rPropertySet, uno::UNO_QUERY ) ); + OSL_ASSERT( m_xAxis.is()); +} + +AxisItemConverter::~AxisItemConverter() +{ +} + +void AxisItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool AxisItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& AxisItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nAxisWhichPairs; +} + +bool AxisItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetAxisPropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + + return true; +} + +static bool lcl_hasTimeIntervalValue( const uno::Any& rAny ) +{ + bool bRet = false; + TimeInterval aValue; + if( rAny >>= aValue ) + bRet = true; + return bRet; +} + +void AxisItemConverter::FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + if( !m_xAxis.is() ) + return; + + const chart2::ScaleData& rScale( m_xAxis->getScaleData() ); + const chart2::IncrementData& rIncrement( rScale.IncrementData ); + const uno::Sequence< chart2::SubIncrement >& rSubIncrements( rScale.IncrementData.SubIncrements ); + const TimeIncrement& rTimeIncrement( rScale.TimeIncrement ); + bool bDateAxis = (rScale.AxisType == chart2::AxisType::DATE); + if( m_pExplicitScale ) + bDateAxis = (m_pExplicitScale->AxisType == chart2::AxisType::DATE); + + switch( nWhichId ) + { + case SCHATTR_AXIS_AUTO_MAX: + rOutItemSet.Put( SfxBoolItem( nWhichId, !hasDoubleValue(rScale.Maximum) ) ); + break; + + case SCHATTR_AXIS_MAX: + { + double fMax = 10.0; + if( rScale.Maximum >>= fMax ) + rOutItemSet.Put( SvxDoubleItem( fMax, SCHATTR_AXIS_MAX ) ); + else + { + if( m_pExplicitScale ) + fMax = m_pExplicitScale->Maximum; + rOutItemSet.Put( SvxDoubleItem( fMax, SCHATTR_AXIS_MAX ) ); + } + } + break; + + case SCHATTR_AXIS_AUTO_MIN: + rOutItemSet.Put( SfxBoolItem( nWhichId, !hasDoubleValue(rScale.Minimum) ) ); + break; + + case SCHATTR_AXIS_MIN: + { + double fMin = 0.0; + if( rScale.Minimum >>= fMin ) + rOutItemSet.Put( SvxDoubleItem( fMin, SCHATTR_AXIS_MIN ) ); + else if( m_pExplicitScale ) + rOutItemSet.Put( SvxDoubleItem( m_pExplicitScale->Minimum, SCHATTR_AXIS_MIN )); + } + break; + + case SCHATTR_AXIS_LOGARITHM: + { + bool bValue = AxisHelper::isLogarithmic( rScale.Scaling ); + rOutItemSet.Put( SfxBoolItem( nWhichId, bValue )); + } + break; + + case SCHATTR_AXIS_REVERSE: + rOutItemSet.Put( SfxBoolItem( nWhichId, (rScale.Orientation == AxisOrientation_REVERSE) )); + break; + + // Increment + case SCHATTR_AXIS_AUTO_STEP_MAIN: + if( bDateAxis ) + rOutItemSet.Put( SfxBoolItem( nWhichId, !lcl_hasTimeIntervalValue(rTimeIncrement.MajorTimeInterval) ) ); + else + rOutItemSet.Put( SfxBoolItem( nWhichId, !hasDoubleValue(rIncrement.Distance) ) ); + break; + + case SCHATTR_AXIS_MAIN_TIME_UNIT: + { + TimeInterval aTimeInterval; + if( rTimeIncrement.MajorTimeInterval >>= aTimeInterval ) + rOutItemSet.Put( SfxInt32Item( nWhichId, aTimeInterval.TimeUnit ) ); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_pExplicitIncrement->MajorTimeInterval.TimeUnit ) ); + } + break; + + case SCHATTR_AXIS_STEP_MAIN: + if( bDateAxis ) + { + TimeInterval aTimeInterval; + if( rTimeIncrement.MajorTimeInterval >>= aTimeInterval ) + rOutItemSet.Put( SvxDoubleItem(aTimeInterval.Number, SCHATTR_AXIS_STEP_MAIN )); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SvxDoubleItem( m_pExplicitIncrement->MajorTimeInterval.Number, SCHATTR_AXIS_STEP_MAIN )); + } + else + { + double fDistance = 1.0; + if( rIncrement.Distance >>= fDistance ) + rOutItemSet.Put( SvxDoubleItem(fDistance, SCHATTR_AXIS_STEP_MAIN )); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SvxDoubleItem( m_pExplicitIncrement->Distance, SCHATTR_AXIS_STEP_MAIN )); + } + break; + + // SubIncrement + case SCHATTR_AXIS_AUTO_STEP_HELP: + if( bDateAxis ) + rOutItemSet.Put( SfxBoolItem( nWhichId, !lcl_hasTimeIntervalValue(rTimeIncrement.MinorTimeInterval) ) ); + else + rOutItemSet.Put( SfxBoolItem( nWhichId, + ! ( rSubIncrements.hasElements() && rSubIncrements[0].IntervalCount.hasValue() ))); + break; + + case SCHATTR_AXIS_HELP_TIME_UNIT: + { + TimeInterval aTimeInterval; + if( rTimeIncrement.MinorTimeInterval >>= aTimeInterval ) + rOutItemSet.Put( SfxInt32Item( nWhichId, aTimeInterval.TimeUnit ) ); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_pExplicitIncrement->MinorTimeInterval.TimeUnit ) ); + } + break; + + case SCHATTR_AXIS_STEP_HELP: + if( bDateAxis ) + { + TimeInterval aTimeInterval; + if( rTimeIncrement.MinorTimeInterval >>= aTimeInterval ) + rOutItemSet.Put( SfxInt32Item( nWhichId, aTimeInterval.Number )); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_pExplicitIncrement->MinorTimeInterval.Number )); + } + else + { + if( rSubIncrements.hasElements() && rSubIncrements[0].IntervalCount.hasValue()) + { + rOutItemSet.Put( SfxInt32Item( nWhichId, + *o3tl::doAccess<sal_Int32>( + rSubIncrements[0].IntervalCount) )); + } + else + { + if( m_pExplicitIncrement && !m_pExplicitIncrement->SubIncrements.empty() ) + { + rOutItemSet.Put( SfxInt32Item( nWhichId, + m_pExplicitIncrement->SubIncrements[0].IntervalCount )); + } + } + } + break; + + case SCHATTR_AXIS_AUTO_TIME_RESOLUTION: + { + rOutItemSet.Put( SfxBoolItem( nWhichId, + !rTimeIncrement.TimeResolution.hasValue() )); + } + break; + case SCHATTR_AXIS_TIME_RESOLUTION: + { + sal_Int32 nTimeResolution=0; + if( rTimeIncrement.TimeResolution >>= nTimeResolution ) + rOutItemSet.Put( SfxInt32Item( nWhichId, nTimeResolution ) ); + else if( m_pExplicitScale ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_pExplicitScale->TimeResolution ) ); + } + break; + + case SCHATTR_AXIS_AUTO_ORIGIN: + { + rOutItemSet.Put( SfxBoolItem( nWhichId, ( !hasDoubleValue(rScale.Origin) ))); + } + break; + + case SCHATTR_AXIS_ORIGIN: + { + double fOrigin = 0.0; + if( !(rScale.Origin >>= fOrigin) ) + { + if( m_pExplicitScale ) + fOrigin = m_pExplicitScale->Origin; + } + rOutItemSet.Put( SvxDoubleItem( fOrigin, SCHATTR_AXIS_ORIGIN )); + } + break; + + case SCHATTR_AXIS_POSITION: + { + css::chart::ChartAxisPosition eAxisPos( css::chart::ChartAxisPosition_ZERO ); + GetPropertySet()->getPropertyValue( "CrossoverPosition" ) >>= eAxisPos; + rOutItemSet.Put( SfxInt32Item( nWhichId, static_cast<sal_Int32>(eAxisPos) ) ); + } + break; + + case SCHATTR_AXIS_POSITION_VALUE: + { + double fValue = 0.0; + if( GetPropertySet()->getPropertyValue( "CrossoverValue" ) >>= fValue ) + rOutItemSet.Put( SvxDoubleItem( fValue, SCHATTR_AXIS_POSITION_VALUE ) ); + } + break; + + case SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT: + { + //read only item + //necessary tp display the crossing value with an appropriate format + + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + + rtl::Reference< Axis > xCrossingMainAxis = AxisHelper::getCrossingMainAxis( m_xAxis, xCooSys ); + + sal_Int32 nFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + xCrossingMainAxis, xCooSys, m_xChartDoc); + + rOutItemSet.Put( SfxUInt32Item( nWhichId, nFormatKey )); + } + break; + + case SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION: + rOutItemSet.Put(SfxBoolItem(nWhichId, rScale.ShiftedCategoryPosition)); + break; + + case SCHATTR_AXIS_LABEL_POSITION: + { + css::chart::ChartAxisLabelPosition ePos( css::chart::ChartAxisLabelPosition_NEAR_AXIS ); + GetPropertySet()->getPropertyValue( "LabelPosition" ) >>= ePos; + rOutItemSet.Put( SfxInt32Item( nWhichId, static_cast<sal_Int32>(ePos) ) ); + } + break; + + case SCHATTR_AXIS_MARK_POSITION: + { + css::chart::ChartAxisMarkPosition ePos( css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ); + GetPropertySet()->getPropertyValue( "MarkPosition" ) >>= ePos; + rOutItemSet.Put( SfxInt32Item( nWhichId, static_cast<sal_Int32>(ePos) ) ); + } + break; + + case SCHATTR_TEXT_DEGREES: + { + // convert double to int (times 100) + double fVal = 0; + + if( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fVal ) + { + rOutItemSet.Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, Degree100(static_cast< sal_Int32 >( + ::rtl::math::round( fVal * 100.0 )) ) )); + } + } + break; + + case SID_ATTR_NUMBERFORMAT_VALUE: + { + if( m_pExplicitScale ) + { + rtl::Reference< BaseCoordinateSystem > xCooSys( + AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + + sal_Int32 nFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + m_xAxis, xCooSys, m_xChartDoc); + + rOutItemSet.Put( SfxUInt32Item( nWhichId, nFormatKey )); + } + } + break; + + case SID_ATTR_NUMBERFORMAT_SOURCE: + { + bool bLinkToSource = true; + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource; + rOutItemSet.Put(SfxBoolItem(nWhichId, bLinkToSource)); + } + break; + + case SCHATTR_AXISTYPE: + rOutItemSet.Put( SfxInt32Item( nWhichId, rScale.AxisType )); + break; + + case SCHATTR_AXIS_AUTO_DATEAXIS: + rOutItemSet.Put( SfxBoolItem( nWhichId, rScale.AutoDateAxis )); + break; + + case SCHATTR_AXIS_ALLOW_DATEAXIS: + { + rtl::Reference< BaseCoordinateSystem > xCooSys( + AxisHelper::getCoordinateSystemOfAxis( m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + sal_Int32 nDimensionIndex=0; sal_Int32 nAxisIndex=0; + AxisHelper::getIndicesForAxis(m_xAxis, xCooSys, nDimensionIndex, nAxisIndex ); + bool bChartTypeAllowsDateAxis = ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( xCooSys, 0 ), nDimensionIndex ); + rOutItemSet.Put( SfxBoolItem( nWhichId, bChartTypeAllowsDateAxis )); + } + break; + } +} + +static bool lcl_isDateAxis( const SfxItemSet & rItemSet ) +{ + sal_Int32 nAxisType = rItemSet.Get( SCHATTR_AXISTYPE ).GetValue();//css::chart2::AxisType + return (nAxisType == chart2::AxisType::DATE); +} + +static bool lcl_isAutoMajor( const SfxItemSet & rItemSet ) +{ + bool bRet = rItemSet.Get( SCHATTR_AXIS_AUTO_STEP_MAIN ).GetValue(); + return bRet; +} + +static bool lcl_isAutoMinor( const SfxItemSet & rItemSet ) +{ + bool bRet = rItemSet.Get( SCHATTR_AXIS_AUTO_STEP_HELP ).GetValue(); + return bRet; +} + +bool AxisItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + if( !m_xAxis.is() ) + return false; + + chart2::ScaleData aScale( m_xAxis->getScaleData() ); + + bool bSetScale = false; + bool bChangedOtherwise = false; + + uno::Any aValue; + + switch( nWhichId ) + { + case SCHATTR_AXIS_AUTO_MAX: + if( static_cast< const SfxBoolItem & >(rItemSet.Get( nWhichId )).GetValue() ) + { + aScale.Maximum.clear(); + bSetScale = true; + } + // else SCHATTR_AXIS_MAX must have some value + break; + + case SCHATTR_AXIS_MAX: + // only if auto if false + if( ! (rItemSet.Get( SCHATTR_AXIS_AUTO_MAX ).GetValue() )) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + + if( aScale.Maximum != aValue ) + { + aScale.Maximum = aValue; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_AUTO_MIN: + if( static_cast< const SfxBoolItem & >(rItemSet.Get( nWhichId )).GetValue() ) + { + aScale.Minimum.clear(); + bSetScale = true; + } + // else SCHATTR_AXIS_MIN must have some value + break; + + case SCHATTR_AXIS_MIN: + // only if auto if false + if( ! (rItemSet.Get( SCHATTR_AXIS_AUTO_MIN ).GetValue() )) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + + if( aScale.Minimum != aValue ) + { + aScale.Minimum = aValue; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_LOGARITHM: + { + bool bWasLogarithm = AxisHelper::isLogarithmic( aScale.Scaling ); + + if( static_cast< const SfxBoolItem & >(rItemSet.Get( nWhichId )).GetValue() ) + { + // logarithm is true + if( ! bWasLogarithm ) + { + aScale.Scaling = AxisHelper::createLogarithmicScaling( 10.0 ); + bSetScale = true; + } + } + else + { + // logarithm is false => linear scaling + if( bWasLogarithm ) + { + aScale.Scaling = AxisHelper::createLinearScaling(); + bSetScale = true; + } + } + } + break; + + case SCHATTR_AXIS_REVERSE: + { + bool bWasReverse = ( aScale.Orientation == AxisOrientation_REVERSE ); + bool bNewReverse = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( bWasReverse != bNewReverse ) + { + aScale.Orientation = bNewReverse ? AxisOrientation_REVERSE : AxisOrientation_MATHEMATICAL; + bSetScale = true; + } + } + break; + + // Increment + case SCHATTR_AXIS_AUTO_STEP_MAIN: + if( lcl_isAutoMajor(rItemSet) ) + { + aScale.IncrementData.Distance.clear(); + aScale.TimeIncrement.MajorTimeInterval.clear(); + bSetScale = true; + } + // else SCHATTR_AXIS_STEP_MAIN must have some value + break; + + case SCHATTR_AXIS_MAIN_TIME_UNIT: + if( !lcl_isAutoMajor(rItemSet) ) + { + if( rItemSet.Get( nWhichId ).QueryValue( aValue ) ) + { + TimeInterval aTimeInterval; + aScale.TimeIncrement.MajorTimeInterval >>= aTimeInterval; + aValue >>= aTimeInterval.TimeUnit; + aScale.TimeIncrement.MajorTimeInterval <<= aTimeInterval; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_STEP_MAIN: + // only if auto if false + if( !lcl_isAutoMajor(rItemSet) ) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + if( lcl_isDateAxis(rItemSet) ) + { + double fValue = 1.0; + if( aValue >>= fValue ) + { + TimeInterval aTimeInterval; + aScale.TimeIncrement.MajorTimeInterval >>= aTimeInterval; + aTimeInterval.Number = static_cast<sal_Int32>(fValue); + aScale.TimeIncrement.MajorTimeInterval <<= aTimeInterval; + bSetScale = true; + } + } + else if( aScale.IncrementData.Distance != aValue ) + { + aScale.IncrementData.Distance = aValue; + bSetScale = true; + } + } + break; + + // SubIncrement + case SCHATTR_AXIS_AUTO_STEP_HELP: + if( lcl_isAutoMinor(rItemSet) ) + { + if( aScale.IncrementData.SubIncrements.hasElements() && + aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() ) + { + aScale.IncrementData.SubIncrements.getArray()[0].IntervalCount.clear(); + bSetScale = true; + } + if( aScale.TimeIncrement.MinorTimeInterval.hasValue() ) + { + aScale.TimeIncrement.MinorTimeInterval.clear(); + bSetScale = true; + } + } + // else SCHATTR_AXIS_STEP_MAIN must have some value + break; + + case SCHATTR_AXIS_HELP_TIME_UNIT: + if( !lcl_isAutoMinor(rItemSet) ) + { + if( rItemSet.Get( nWhichId ).QueryValue( aValue ) ) + { + TimeInterval aTimeInterval; + aScale.TimeIncrement.MinorTimeInterval >>= aTimeInterval; + aValue >>= aTimeInterval.TimeUnit; + aScale.TimeIncrement.MinorTimeInterval <<= aTimeInterval; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_STEP_HELP: + // only if auto is false + if( !lcl_isAutoMinor(rItemSet) ) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + if( lcl_isDateAxis(rItemSet) ) + { + TimeInterval aTimeInterval; + aScale.TimeIncrement.MinorTimeInterval >>= aTimeInterval; + aValue >>= aTimeInterval.Number; + aScale.TimeIncrement.MinorTimeInterval <<= aTimeInterval; + bSetScale = true; + } + else if( aScale.IncrementData.SubIncrements.hasElements() ) + { + if( ! aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() || + aScale.IncrementData.SubIncrements[0].IntervalCount != aValue ) + { + OSL_ASSERT( aValue.getValueTypeClass() == uno::TypeClass_LONG ); + aScale.IncrementData.SubIncrements.getArray()[0].IntervalCount = aValue; + bSetScale = true; + } + } + } + break; + + case SCHATTR_AXIS_AUTO_TIME_RESOLUTION: + if( static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue() ) + { + aScale.TimeIncrement.TimeResolution.clear(); + bSetScale = true; + } + break; + case SCHATTR_AXIS_TIME_RESOLUTION: + // only if auto is false + if( ! ( rItemSet.Get( SCHATTR_AXIS_AUTO_TIME_RESOLUTION ).GetValue() )) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + + if( aScale.TimeIncrement.TimeResolution != aValue ) + { + aScale.TimeIncrement.TimeResolution = aValue; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_AUTO_ORIGIN: + { + if( static_cast< const SfxBoolItem & >(rItemSet.Get( nWhichId )).GetValue() ) + { + aScale.Origin.clear(); + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_ORIGIN: + { + // only if auto is false + if( ! (rItemSet.Get( SCHATTR_AXIS_AUTO_ORIGIN ).GetValue() )) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + + if( aScale.Origin != aValue ) + { + aScale.Origin = aValue; + bSetScale = true; + + if( !AxisHelper::isAxisPositioningEnabled() ) + { + //keep old and new settings for axis positioning in sync somehow + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + + sal_Int32 nDimensionIndex=0; + sal_Int32 nAxisIndex=0; + if( AxisHelper::getIndicesForAxis( m_xAxis, xCooSys, nDimensionIndex, nAxisIndex ) && nAxisIndex==0 ) + { + rtl::Reference< Axis > xCrossingMainAxis = AxisHelper::getCrossingMainAxis( m_xAxis, xCooSys ); + if( xCrossingMainAxis.is() ) + { + double fValue = 0.0; + if( aValue >>= fValue ) + { + xCrossingMainAxis->setPropertyValue( "CrossoverPosition" , uno::Any( css::chart::ChartAxisPosition_VALUE )); + xCrossingMainAxis->setPropertyValue( "CrossoverValue" , uno::Any( fValue )); + } + else + xCrossingMainAxis->setPropertyValue( "CrossoverPosition" , uno::Any( css::chart::ChartAxisPosition_START )); + } + } + } + } + } + } + break; + + case SCHATTR_AXIS_POSITION: + { + css::chart::ChartAxisPosition eAxisPos = + static_cast<css::chart::ChartAxisPosition>(static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue()); + + css::chart::ChartAxisPosition eOldAxisPos( css::chart::ChartAxisPosition_ZERO ); + bool bPropExisted = ( GetPropertySet()->getPropertyValue( "CrossoverPosition" ) >>= eOldAxisPos ); + + if( !bPropExisted || ( eOldAxisPos != eAxisPos )) + { + GetPropertySet()->setPropertyValue( "CrossoverPosition" , uno::Any( eAxisPos )); + bChangedOtherwise = true; + + //move the parallel axes to the other side if necessary + if( eAxisPos==css::chart::ChartAxisPosition_START || eAxisPos==css::chart::ChartAxisPosition_END ) + { + rtl::Reference< Axis > xParallelAxis = AxisHelper::getParallelAxis( m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ); + if( xParallelAxis.is() ) + { + css::chart::ChartAxisPosition eOtherPos; + if( xParallelAxis->getPropertyValue( "CrossoverPosition" ) >>= eOtherPos ) + { + if( eOtherPos == eAxisPos ) + { + css::chart::ChartAxisPosition eOppositePos = + (eAxisPos==css::chart::ChartAxisPosition_START) + ? css::chart::ChartAxisPosition_END + : css::chart::ChartAxisPosition_START; + xParallelAxis->setPropertyValue( "CrossoverPosition" , uno::Any( eOppositePos )); + } + } + } + } + } + } + break; + + case SCHATTR_AXIS_POSITION_VALUE: + { + double fValue = static_cast< const SvxDoubleItem & >( rItemSet.Get( nWhichId )).GetValue(); + + double fOldValue = 0.0; + bool bPropExisted = ( GetPropertySet()->getPropertyValue( "CrossoverValue" ) >>= fOldValue ); + + if( !bPropExisted || ( fOldValue != fValue )) + { + GetPropertySet()->setPropertyValue( "CrossoverValue" , uno::Any( fValue )); + bChangedOtherwise = true; + + //keep old and new settings for axis positioning in sync somehow + { + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + + sal_Int32 nDimensionIndex=0; + sal_Int32 nAxisIndex=0; + if( AxisHelper::getIndicesForAxis( m_xAxis, xCooSys, nDimensionIndex, nAxisIndex ) && nAxisIndex==0 ) + { + Reference< chart2::XAxis > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( m_xAxis, xCooSys ) ); + if( xCrossingMainAxis.is() ) + { + ScaleData aCrossingScale( xCrossingMainAxis->getScaleData() ); + aCrossingScale.Origin <<= fValue; + xCrossingMainAxis->setScaleData(aCrossingScale); + } + } + } + } + } + break; + + case SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION: + { + bool bNewValue = static_cast<const SfxBoolItem &> (rItemSet.Get(nWhichId)).GetValue(); + bool bOldValue = aScale.ShiftedCategoryPosition; + if (bOldValue != bNewValue) + { + aScale.ShiftedCategoryPosition = bNewValue; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_LABEL_POSITION: + { + css::chart::ChartAxisLabelPosition ePos = + static_cast<css::chart::ChartAxisLabelPosition>(static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue()); + + css::chart::ChartAxisLabelPosition eOldPos( css::chart::ChartAxisLabelPosition_NEAR_AXIS ); + bool bPropExisted = ( GetPropertySet()->getPropertyValue( "LabelPosition" ) >>= eOldPos ); + + if( !bPropExisted || ( eOldPos != ePos )) + { + GetPropertySet()->setPropertyValue( "LabelPosition" , uno::Any( ePos )); + bChangedOtherwise = true; + + //move the parallel axes to the other side if necessary + if( ePos==css::chart::ChartAxisLabelPosition_OUTSIDE_START || ePos==css::chart::ChartAxisLabelPosition_OUTSIDE_END ) + { + rtl::Reference< Axis > xParallelAxis = AxisHelper::getParallelAxis( m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ); + if( xParallelAxis.is() ) + { + css::chart::ChartAxisLabelPosition eOtherPos; + if( xParallelAxis->getPropertyValue( "LabelPosition" ) >>= eOtherPos ) + { + if( eOtherPos == ePos ) + { + css::chart::ChartAxisLabelPosition eOppositePos = + (ePos==css::chart::ChartAxisLabelPosition_OUTSIDE_START) + ? css::chart::ChartAxisLabelPosition_OUTSIDE_END + : css::chart::ChartAxisLabelPosition_OUTSIDE_START; + xParallelAxis->setPropertyValue( "LabelPosition" , uno::Any( eOppositePos )); + } + } + } + } + } + } + break; + + case SCHATTR_AXIS_MARK_POSITION: + { + css::chart::ChartAxisMarkPosition ePos = + static_cast<css::chart::ChartAxisMarkPosition>(static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue()); + + css::chart::ChartAxisMarkPosition eOldPos( css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ); + bool bPropExisted = ( GetPropertySet()->getPropertyValue( "MarkPosition" ) >>= eOldPos ); + + if( !bPropExisted || ( eOldPos != ePos )) + { + GetPropertySet()->setPropertyValue( "MarkPosition" , uno::Any( ePos )); + bChangedOtherwise = true; + } + } + break; + + case SCHATTR_TEXT_DEGREES: + { + double fVal = toDegrees(rItemSet.Get(SCHATTR_TEXT_DEGREES).GetValue()); + double fOldVal = 0.0; + bool bPropExisted = + ( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fOldVal ); + + if( ! bPropExisted || fOldVal != fVal ) + { + GetPropertySet()->setPropertyValue( "TextRotation" , uno::Any( fVal )); + bChangedOtherwise = true; + } + } + break; + + case SID_ATTR_NUMBERFORMAT_VALUE: + { + if( m_pExplicitScale ) + { + bool bUseSourceFormat = + rItemSet.Get( SID_ATTR_NUMBERFORMAT_SOURCE ).GetValue(); + + if( ! bUseSourceFormat ) + { + sal_Int32 nFmt = static_cast< sal_Int32 >( + static_cast< const SfxUInt32Item & >( + rItemSet.Get( nWhichId )).GetValue()); + + aValue <<= nFmt; + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) != aValue) + { + GetPropertySet()->setPropertyValue(CHART_UNONAME_NUMFMT , aValue); + bChangedOtherwise = true; + } + } + } + } + break; + + case SID_ATTR_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = + static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + GetPropertySet()->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(bUseSourceFormat)); + + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT).hasValue(); + + bChangedOtherwise = (bUseSourceFormat == bNumberFormatIsSet); + if( bChangedOtherwise ) + { + if( ! bUseSourceFormat ) + { + SfxItemState aState = rItemSet.GetItemState( SID_ATTR_NUMBERFORMAT_VALUE ); + if( aState == SfxItemState::SET ) + { + sal_Int32 nFormatKey = static_cast< sal_Int32 >( + rItemSet.Get( SID_ATTR_NUMBERFORMAT_VALUE ).GetValue()); + aValue <<= nFormatKey; + } + else + { + rtl::Reference< BaseCoordinateSystem > xCooSys = + AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ); + + sal_Int32 nFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + m_xAxis, xCooSys, m_xChartDoc); + + aValue <<= nFormatKey; + } + } + // else set a void Any + GetPropertySet()->setPropertyValue(CHART_UNONAME_NUMFMT , aValue); + } + } + break; + + case SCHATTR_AXISTYPE: + { + sal_Int32 nNewAxisType = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue();//css::chart2::AxisType + aScale.AxisType = nNewAxisType; + bSetScale = true; + } + break; + + case SCHATTR_AXIS_AUTO_DATEAXIS: + { + bool bNewValue = static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue(); + bool bOldValue = aScale.AutoDateAxis; + if( bOldValue != bNewValue ) + { + aScale.AutoDateAxis = bNewValue; + bSetScale = true; + } + } + break; + } + + if( bSetScale ) + m_xAxis->setScaleData( aScale ); + + return (bSetScale || bChangedOtherwise); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/CharacterPropertyItemConverter.cxx b/chart2/source/controller/itemsetwrapper/CharacterPropertyItemConverter.cxx new file mode 100644 index 000000000..5345f9168 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/CharacterPropertyItemConverter.cxx @@ -0,0 +1,556 @@ +/* -*- 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 <CharacterPropertyItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <ItemPropertyMap.hxx> +#include <RelativeSizeHelper.hxx> +#include <editeng/memberids.h> +#include <editeng/eeitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <o3tl/any.hxx> +#include <svl/stritem.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart2/XFormattedString.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetCharacterPropertyPropertyMap() +{ + static ItemPropertyMapType aCharacterPropertyMap{ + {EE_CHAR_COLOR, {"CharColor", 0}}, + {EE_CHAR_LANGUAGE, {"CharLocale", MID_LANG_LOCALE}}, + {EE_CHAR_LANGUAGE_CJK, {"CharLocaleAsian", MID_LANG_LOCALE}}, + {EE_CHAR_LANGUAGE_CTL, {"CharLocaleComplex", MID_LANG_LOCALE}}, + + {EE_CHAR_STRIKEOUT, {"CharStrikeout", MID_CROSS_OUT}}, + {EE_CHAR_WLM, {"CharWordMode", 0}}, + {EE_CHAR_SHADOW, {"CharShadowed", 0}}, + {EE_CHAR_RELIEF, {"CharRelief", 0}}, + {EE_CHAR_OUTLINE, {"CharContoured", 0}}, + {EE_CHAR_EMPHASISMARK, {"CharEmphasis", 0}}, + + {EE_PARA_WRITINGDIR, {"WritingMode", 0}}, + + {EE_PARA_ASIANCJKSPACING, {"ParaIsCharacterDistance", 0}}}; + + return aCharacterPropertyMap; +} +} // anonymous namespace + +CharacterPropertyItemConverter::CharacterPropertyItemConverter( + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ) : + ItemConverter( rPropertySet, rItemPool ) +{} + +CharacterPropertyItemConverter::CharacterPropertyItemConverter( + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + const awt::Size* pRefSize, + const OUString & rRefSizePropertyName, + const uno::Reference< beans::XPropertySet > & rRefSizePropSet ) : + ItemConverter( rPropertySet, rItemPool ), + m_aRefSizePropertyName( rRefSizePropertyName ), + m_xRefSizePropSet( rRefSizePropSet.is() ? rRefSizePropSet : rPropertySet ) +{ + if (pRefSize) + m_pRefSize = *pRefSize; +} + +CharacterPropertyItemConverter::~CharacterPropertyItemConverter() +{} + +const WhichRangesContainer& CharacterPropertyItemConverter::GetWhichPairs() const +{ + return nCharacterPropertyWhichPairs; +} + +bool CharacterPropertyItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetCharacterPropertyPropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +void CharacterPropertyItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_FONTINFO_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_FONTINFO_CTL ) + aPostfix = "Complex"; + + SvxFontItem aItem( nWhichId ); + + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontName" + aPostfix), + MID_FONT_FAMILY_NAME ); + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontFamily" + aPostfix), + MID_FONT_FAMILY ); + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontStyleName" + aPostfix), + MID_FONT_STYLE_NAME ); + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontCharSet" + aPostfix), + MID_FONT_CHAR_SET ); + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontPitch" + aPostfix), + MID_FONT_PITCH ); + + rOutItemSet.Put( aItem ); + } + break; + + case EE_CHAR_UNDERLINE: + { + SvxUnderlineItem aItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE); + bool bModified = false; + + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharUnderline" )); + if( aValue.hasValue()) + { + aItem.PutValue( aValue, MID_TL_STYLE ); + bModified = true; + } + + aValue = GetPropertySet()->getPropertyValue( "CharUnderlineHasColor" ); + if( aValue.hasValue() && *o3tl::doAccess<bool>(aValue) ) + { + aItem.PutValue( aValue, MID_TL_HASCOLOR ); + bModified = true; + } + + aValue = GetPropertySet()->getPropertyValue( "CharUnderlineColor" ); + if( aValue.hasValue()) + { + aItem.PutValue( aValue, MID_TL_COLOR ); + bModified = true; + } + + if( bModified ) + rOutItemSet.Put( aItem ); + } + break; + + case EE_CHAR_OVERLINE: + { + SvxOverlineItem aItem( LINESTYLE_NONE, EE_CHAR_OVERLINE ); + bool bModified = false; + + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharOverline" ) ); + if ( aValue.hasValue() ) + { + aItem.PutValue( aValue, MID_TL_STYLE ); + bModified = true; + } + + aValue = GetPropertySet()->getPropertyValue( "CharOverlineHasColor" ); + if ( aValue.hasValue() && *o3tl::doAccess<bool>(aValue) ) + { + aItem.PutValue( aValue, MID_TL_HASCOLOR ); + bModified = true; + } + + aValue = GetPropertySet()->getPropertyValue( "CharOverlineColor" ); + if ( aValue.hasValue() ) + { + aItem.PutValue( aValue, MID_TL_COLOR ); + bModified = true; + } + + if ( bModified ) + { + rOutItemSet.Put( aItem ); + } + } + break; + + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_ITALIC_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_ITALIC_CTL ) + aPostfix = "Complex"; + + SvxPostureItem aItem( ITALIC_NONE, nWhichId ); + + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharPosture" + aPostfix)); + if( aValue.hasValue()) + { + aItem.PutValue( aValue, MID_POSTURE ); + rOutItemSet.Put( aItem ); + } + } + break; + + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_WEIGHT_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_WEIGHT_CTL ) + aPostfix = "Complex"; + + SvxWeightItem aItem( WEIGHT_NORMAL, nWhichId ); + + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharWeight" + aPostfix)); + if( aValue.hasValue()) + { + aItem.PutValue( aValue, MID_WEIGHT ); + rOutItemSet.Put( aItem ); + } + } + break; + + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_FONTHEIGHT_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_FONTHEIGHT_CTL ) + aPostfix = "Complex"; + + SvxFontHeightItem aItem( 240, 100, nWhichId ); + + try + { + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharHeight" + aPostfix )); + float fHeight; + if( aValue >>= fHeight ) + { + if (m_pRefSize) + { + awt::Size aOldRefSize; + if( GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ) >>= aOldRefSize ) + { + // calculate font height in view + fHeight = static_cast< float >( + RelativeSizeHelper::calculate( fHeight, aOldRefSize, *m_pRefSize )); + aValue <<= fHeight; + } + } + + aItem.PutValue( aValue, MID_FONTHEIGHT ); + rOutItemSet.Put( aItem ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + break; + + case SID_CHAR_DLG_PREVIEW_STRING: + { + uno::Reference< chart2::XFormattedString > xFormattedString( GetPropertySet(), uno::UNO_QUERY ); + if( xFormattedString.is() ) + { + OUString aString = xFormattedString->getString(); + rOutItemSet.Put( SfxStringItem( nWhichId, aString ) ); + } + else + rOutItemSet.Put( SfxStringItem( nWhichId, OUString() ) ); + } + break; + + case EE_PARA_FORBIDDENRULES: + case EE_PARA_HANGINGPUNCTUATION: + rOutItemSet.DisableItem( nWhichId ); + break; + } +} + +bool CharacterPropertyItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + uno::Any aValue; + + switch( nWhichId ) + { + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_FONTINFO_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_FONTINFO_CTL ) + aPostfix = "Complex"; + + const SvxFontItem & rItem = + static_cast< const SvxFontItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_FONT_FAMILY_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontName" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontName" + aPostfix, aValue ); + bChanged = true; + } + } + if( rItem.QueryValue( aValue, MID_FONT_FAMILY )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontFamily" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontFamily" + aPostfix, aValue ); + bChanged = true; + } + } + if( rItem.QueryValue( aValue, MID_FONT_STYLE_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontStyleName" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontStyleName" + aPostfix, aValue ); + bChanged = true; + } + } + if( rItem.QueryValue( aValue, MID_FONT_CHAR_SET )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontCharSet" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontCharSet" + aPostfix, aValue ); + bChanged = true; + } + } + if( rItem.QueryValue( aValue, MID_FONT_PITCH )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontPitch" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontPitch" + aPostfix, aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_UNDERLINE: + { + const SvxUnderlineItem & rItem = + static_cast< const SvxUnderlineItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_TL_STYLE )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharUnderline" )) + { + GetPropertySet()->setPropertyValue( "CharUnderline" , aValue ); + bChanged = true; + } + } + + if( rItem.QueryValue( aValue, MID_TL_COLOR )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharUnderlineColor" )) + { + GetPropertySet()->setPropertyValue( "CharUnderlineColor" , aValue ); + bChanged = true; + } + } + + if( rItem.QueryValue( aValue, MID_TL_HASCOLOR )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharUnderlineHasColor" )) + { + GetPropertySet()->setPropertyValue( "CharUnderlineHasColor" , aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_OVERLINE: + { + const SvxOverlineItem& rItem = static_cast< const SvxOverlineItem & >( rItemSet.Get( nWhichId ) ); + + if ( rItem.QueryValue( aValue, MID_TL_STYLE ) ) + { + if ( aValue != GetPropertySet()->getPropertyValue( "CharOverline" ) ) + { + GetPropertySet()->setPropertyValue( "CharOverline" , aValue ); + bChanged = true; + } + } + + if ( rItem.QueryValue( aValue, MID_TL_COLOR ) ) + { + if ( aValue != GetPropertySet()->getPropertyValue( "CharOverlineColor" ) ) + { + GetPropertySet()->setPropertyValue( "CharOverlineColor" , aValue ); + bChanged = true; + } + } + + if ( rItem.QueryValue( aValue, MID_TL_HASCOLOR ) ) + { + if ( aValue != GetPropertySet()->getPropertyValue( "CharOverlineHasColor" ) ) + { + GetPropertySet()->setPropertyValue( "CharOverlineHasColor" , aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_ITALIC_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_ITALIC_CTL ) + aPostfix = "Complex"; + + const SvxPostureItem & rItem = + static_cast< const SvxPostureItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_POSTURE )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharPosture" + aPostfix)) + { + GetPropertySet()->setPropertyValue( "CharPosture" + aPostfix, aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_WEIGHT_CJK ) + aPostfix = "Asian" ; + else if( nWhichId == EE_CHAR_WEIGHT_CTL ) + aPostfix = "Complex"; + + const SvxWeightItem & rItem = + static_cast< const SvxWeightItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_WEIGHT )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharWeight" + aPostfix)) + { + GetPropertySet()->setPropertyValue( "CharWeight" + aPostfix, aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_FONTHEIGHT_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_FONTHEIGHT_CTL ) + aPostfix = "Complex"; + + const SvxFontHeightItem & rItem = + static_cast< const SvxFontHeightItem & >( + rItemSet.Get( nWhichId )); + + try + { + if( rItem.QueryValue( aValue, MID_FONTHEIGHT ) ) + { + bool bSetValue = false; + if( aValue != GetPropertySet()->getPropertyValue( "CharHeight" + aPostfix )) + bSetValue = true; + else + { + if (m_pRefSize) + { + awt::Size aNewRefSize = *m_pRefSize; + awt::Size aOldRefSize; + if( GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ) >>= aOldRefSize ) + { + if( aNewRefSize.Width != aOldRefSize.Width + || aNewRefSize.Height != aOldRefSize.Height ) + bSetValue = true; + } + } + } + if( bSetValue ) + { + // set new reference size only if there was a reference size before (auto-scaling on) + if (m_pRefSize && GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ).hasValue()) + { + GetRefSizePropertySet()->setPropertyValue( + m_aRefSizePropertyName, uno::Any(*m_pRefSize)); + } + + GetPropertySet()->setPropertyValue( "CharHeight" + aPostfix, aValue ); + bChanged = true; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + break; + } + + return bChanged; +} + +const uno::Reference<beans::XPropertySet>& CharacterPropertyItemConverter::GetRefSizePropertySet() const +{ + return m_xRefSizePropSet; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx b/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx new file mode 100644 index 000000000..a6c4c34dc --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx @@ -0,0 +1,822 @@ +/* -*- 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 <DataPointItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <ItemPropertyMap.hxx> + +#include <GraphicPropertyItemConverter.hxx> +#include <CharacterPropertyItemConverter.hxx> +#include <StatisticsItemConverter.hxx> +#include <SeriesOptionsItemConverter.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <unonames.hxx> + +#include <com/sun/star/chart/DataLabelPlacement.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <com/sun/star/chart2/Symbol.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <comphelper/sequence.hxx> +#include <svx/xflclit.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <editeng/sizeitem.hxx> +#include <svl/stritem.hxx> +#include <editeng/brushitem.hxx> +#include <svl/ilstitem.hxx> +#include <svx/sdangitm.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/graph.hxx> +#include <rtl/math.hxx> + +#include <svx/tabline.hxx> + +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetDataPointPropertyMap() +{ + static ItemPropertyMapType aDataPointPropertyMap{ + {SCHATTR_STYLE_SHAPE, {"Geometry3D", 0}}}; + return aDataPointPropertyMap; +}; + +sal_Int32 lcl_getSymbolStyleForSymbol( const chart2::Symbol & rSymbol ) +{ + sal_Int32 nStyle = SVX_SYMBOLTYPE_UNKNOWN; + switch( rSymbol.Style ) + { + case chart2::SymbolStyle_NONE: + nStyle = SVX_SYMBOLTYPE_NONE; + break; + case chart2::SymbolStyle_AUTO: + nStyle = SVX_SYMBOLTYPE_AUTO; + break; + case chart2::SymbolStyle_GRAPHIC: + nStyle = SVX_SYMBOLTYPE_BRUSHITEM; + break; + case chart2::SymbolStyle_STANDARD: + nStyle = rSymbol.StandardSymbol; + break; + + case chart2::SymbolStyle_POLYGON: + // to avoid warning + case chart2::SymbolStyle::SymbolStyle_MAKE_FIXED_SIZE: + // nothing + break; + } + return nStyle; +} + +bool lcl_NumberFormatFromItemToPropertySet( sal_uInt16 nWhichId, const SfxItemSet & rItemSet, const uno::Reference< beans::XPropertySet > & xPropertySet, bool bOverwriteAttributedDataPointsAlso ) +{ + bool bChanged = false; + if( !xPropertySet.is() ) + return bChanged; + OUString aPropertyName = (nWhichId==SID_ATTR_NUMBERFORMAT_VALUE) ? OUString(CHART_UNONAME_NUMFMT) : OUString( "PercentageNumberFormat" ); + sal_uInt16 nSourceWhich = (nWhichId==SID_ATTR_NUMBERFORMAT_VALUE) ? SID_ATTR_NUMBERFORMAT_SOURCE : SCHATTR_PERCENT_NUMBERFORMAT_SOURCE; + + if( rItemSet.GetItemState( nSourceWhich ) != SfxItemState::SET ) + return bChanged; + + uno::Any aValue; + bool bUseSourceFormat = static_cast< const SfxBoolItem & >( + rItemSet.Get( nSourceWhich )).GetValue(); + if( !bUseSourceFormat ) + { + SfxItemState aState = rItemSet.GetItemState( nWhichId ); + if( aState == SfxItemState::SET ) + { + sal_Int32 nFmt = static_cast< sal_Int32 >( + static_cast< const SfxUInt32Item & >( + rItemSet.Get( nWhichId )).GetValue()); + aValue <<= nFmt; + } + else + return bChanged; + } + + uno::Any aOldValue( xPropertySet->getPropertyValue(aPropertyName) ); + if( bOverwriteAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( xPropertySet, uno::UNO_QUERY); + if( aValue != aOldValue || + ::chart::DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, aPropertyName, aOldValue ) ) + { + ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, aPropertyName, aValue ); + bChanged = true; + } + } + else if( aOldValue != aValue ) + { + xPropertySet->setPropertyValue(aPropertyName, aValue ); + bChanged = true; + } + return bChanged; +} + +bool lcl_UseSourceFormatFromItemToPropertySet( sal_uInt16 nWhichId, const SfxItemSet & rItemSet, const uno::Reference< beans::XPropertySet > & xPropertySet, bool bOverwriteAttributedDataPointsAlso ) +{ + bool bChanged = false; + if( !xPropertySet.is() ) + return bChanged; + OUString aPropertyName = (nWhichId==SID_ATTR_NUMBERFORMAT_SOURCE) ? OUString(CHART_UNONAME_NUMFMT) : OUString( "PercentageNumberFormat" ); + sal_uInt16 nFormatWhich = (nWhichId==SID_ATTR_NUMBERFORMAT_SOURCE) ? SID_ATTR_NUMBERFORMAT_VALUE : SCHATTR_PERCENT_NUMBERFORMAT_VALUE; + + if( rItemSet.GetItemState( nWhichId ) != SfxItemState::SET ) + return bChanged; + + uno::Any aNewValue; + bool bUseSourceFormat = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + xPropertySet->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(bUseSourceFormat)); + if( !bUseSourceFormat ) + { + SfxItemState aState = rItemSet.GetItemState( nFormatWhich ); + if( aState == SfxItemState::SET ) + { + sal_Int32 nFormatKey = static_cast< sal_Int32 >( + static_cast< const SfxUInt32Item & >( + rItemSet.Get( nFormatWhich )).GetValue()); + aNewValue <<= nFormatKey; + } + else + return bChanged; + } + + uno::Any aOldValue( xPropertySet->getPropertyValue(aPropertyName) ); + if( bOverwriteAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( xPropertySet, uno::UNO_QUERY); + if( aNewValue != aOldValue || + ::chart::DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, aPropertyName, aOldValue ) ) + { + ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, aPropertyName, aNewValue ); + bChanged = true; + } + } + else if( aOldValue != aNewValue ) + { + xPropertySet->setPropertyValue( aPropertyName, aNewValue ); + bChanged = true; + } + + return bChanged; +} + +} // anonymous namespace + +DataPointItemConverter::DataPointItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + const uno::Reference< uno::XComponentContext > & xContext, + const uno::Reference< beans::XPropertySet > & rPropertySet, + const rtl::Reference< DataSeries > & xSeries, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference<lang::XMultiServiceFactory>& xNamedPropertyContainerFactory, + GraphicObjectType eMapTo, + const awt::Size* pRefSize, + bool bDataSeries, + bool bUseSpecialFillColor, + sal_Int32 nSpecialFillColor, + bool bOverwriteLabelsForAttributedDataPointsAlso, + sal_Int32 nNumberFormat, + sal_Int32 nPercentNumberFormat, + sal_Int32 nPointIndex ) : + ItemConverter( rPropertySet, rItemPool ), + m_bDataSeries( bDataSeries ), + m_bOverwriteLabelsForAttributedDataPointsAlso(m_bDataSeries && bOverwriteLabelsForAttributedDataPointsAlso), + m_bUseSpecialFillColor(bUseSpecialFillColor), + m_nSpecialFillColor(ColorTransparency, nSpecialFillColor), + m_nNumberFormat(nNumberFormat), + m_nPercentNumberFormat(nPercentNumberFormat), + m_bForbidPercentValue(true), + m_bHideLegendEntry(false), + m_nPointIndex(nPointIndex), + m_xSeries(xSeries) +{ + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, xNamedPropertyContainerFactory, eMapTo )); + m_aConverters.emplace_back( new CharacterPropertyItemConverter(rPropertySet, rItemPool, pRefSize, "ReferencePageSize")); + if( bDataSeries ) + { + m_aConverters.emplace_back( new StatisticsItemConverter( xChartModel, rPropertySet, rItemPool )); + m_aConverters.emplace_back( new SeriesOptionsItemConverter( xChartModel, xContext, rPropertySet, rItemPool )); + } + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram(xChartModel) ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram , xSeries ) ); + bool bFound = false; + bool bAmbiguous = false; + bool bSwapXAndY = DiagramHelper::getVertical( xDiagram, bFound, bAmbiguous ); + m_aAvailableLabelPlacements = ChartTypeHelper::getSupportedLabelPlacements( xChartType, bSwapXAndY, xSeries ); + + m_bForbidPercentValue = ChartTypeHelper::getAxisType( xChartType, 0 ) != AxisType::CATEGORY; + + if (bDataSeries) + return; + + uno::Sequence<sal_Int32> deletedLegendEntriesSeq; + xSeries->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq; + for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq)) + { + if (nPointIndex == deletedLegendEntry) + { + m_bHideLegendEntry = true; + break; + } + } +} + +DataPointItemConverter::~DataPointItemConverter() +{ +} + +void DataPointItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); + + if( m_bUseSpecialFillColor ) + { + Color aColor(m_nSpecialFillColor); + rOutItemSet.Put( XFillColorItem( OUString(), aColor ) ); + } +} + +bool DataPointItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& DataPointItemConverter::GetWhichPairs() const +{ + // must span all used items! + if( m_bDataSeries ) + return nRowWhichPairs; + return nDataPointWhichPairs; +} + +bool DataPointItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetDataPointPropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +bool DataPointItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SCHATTR_DATADESCR_SHOW_NUMBER: + case SCHATTR_DATADESCR_SHOW_PERCENTAGE: + case SCHATTR_DATADESCR_SHOW_CATEGORY: + case SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME: + case SCHATTR_DATADESCR_SHOW_SYMBOL: + { + const SfxBoolItem & rItem = static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )); + + uno::Any aOldValue = GetPropertySet()->getPropertyValue(CHART_UNONAME_LABEL); + chart2::DataPointLabel aLabel; + if( aOldValue >>= aLabel ) + { + sal_Bool& rValue = (nWhichId==SCHATTR_DATADESCR_SHOW_NUMBER) ? aLabel.ShowNumber : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_PERCENTAGE) ? aLabel.ShowNumberInPercent : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_CATEGORY) ? aLabel.ShowCategoryName : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME) ? aLabel.ShowSeriesName : aLabel.ShowLegendSymbol ))); + bool bOldValue = rValue; + rValue = rItem.GetValue(); + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( bOldValue != bool(rValue) || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, CHART_UNONAME_LABEL , aOldValue ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_LABEL , uno::Any( aLabel ) ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any() ); + bChanged = true; + } + } + else if( bOldValue != bool(rValue) ) + { + GetPropertySet()->setPropertyValue(CHART_UNONAME_LABEL , uno::Any(aLabel)); + bChanged = true; + } + } + } + break; + + case SID_ATTR_NUMBERFORMAT_VALUE: + case SCHATTR_PERCENT_NUMBERFORMAT_VALUE: //fall through intended + { + bChanged = lcl_NumberFormatFromItemToPropertySet( nWhichId, rItemSet, GetPropertySet(), m_bOverwriteLabelsForAttributedDataPointsAlso ); + } + break; + + case SID_ATTR_NUMBERFORMAT_SOURCE: + case SCHATTR_PERCENT_NUMBERFORMAT_SOURCE: //fall through intended + { + bChanged = lcl_UseSourceFormatFromItemToPropertySet( nWhichId, rItemSet, GetPropertySet(), m_bOverwriteLabelsForAttributedDataPointsAlso ); + } + break; + + case SCHATTR_DATADESCR_SEPARATOR: + { + OUString aNewValue = static_cast< const SfxStringItem & >( rItemSet.Get( nWhichId )).GetValue(); + try + { + OUString aOldValue; + GetPropertySet()->getPropertyValue( "LabelSeparator" ) >>= aOldValue; + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( aOldValue != aNewValue || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, "LabelSeparator" , uno::Any( aOldValue ) ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "LabelSeparator" , uno::Any( aNewValue ) ); + bChanged = true; + } + } + else if( aOldValue != aNewValue ) + { + GetPropertySet()->setPropertyValue( "LabelSeparator" , uno::Any( aNewValue )); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_WRAP_TEXT: + { + + try + { + bool bNew = static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue(); + bool bOld = false; + GetPropertySet()->getPropertyValue( "TextWordWrap" ) >>= bOld; + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( bOld!=bNew || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, "TextWordWrap", uno::Any( bOld ) ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "TextWordWrap", uno::Any( bNew ) ); + bChanged = true; + } + } + else if( bOld!=bNew ) + { + GetPropertySet()->setPropertyValue( "TextWordWrap", uno::Any( bNew )); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_PLACEMENT: + { + + try + { + sal_Int32 nNew = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue(); + sal_Int32 nOld = -1; + RelativePosition aCustomLabelPosition; + GetPropertySet()->getPropertyValue("LabelPlacement") >>= nOld; + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( nOld!=nNew || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, "LabelPlacement" , uno::Any( nOld ) ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "LabelPlacement" , uno::Any( nNew ) ); + bChanged = true; + } + } + else if( nOld!=nNew || (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) ) + { + GetPropertySet()->setPropertyValue("LabelPlacement", uno::Any(nNew)); + GetPropertySet()->setPropertyValue("CustomLabelPosition", uno::Any()); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_STYLE_SYMBOL: + { + sal_Int32 nStyle = + static_cast< const SfxInt32Item & >( + rItemSet.Get( nWhichId )).GetValue(); + chart2::Symbol aSymbol; + + GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol; + sal_Int32 nOldStyle = lcl_getSymbolStyleForSymbol( aSymbol ); + + if( nStyle != nOldStyle ) + { + bool bDeleteSymbol = false; + switch( nStyle ) + { + case SVX_SYMBOLTYPE_NONE: + aSymbol.Style = chart2::SymbolStyle_NONE; + break; + case SVX_SYMBOLTYPE_AUTO: + aSymbol.Style = chart2::SymbolStyle_AUTO; + break; + case SVX_SYMBOLTYPE_BRUSHITEM: + aSymbol.Style = chart2::SymbolStyle_GRAPHIC; + break; + case SVX_SYMBOLTYPE_UNKNOWN: + bDeleteSymbol = true; + break; + + default: + aSymbol.Style = chart2::SymbolStyle_STANDARD; + aSymbol.StandardSymbol = nStyle; + } + + if( bDeleteSymbol ) + GetPropertySet()->setPropertyValue( "Symbol" , uno::Any()); + else + GetPropertySet()->setPropertyValue( "Symbol" , uno::Any( aSymbol )); + bChanged = true; + } + } + break; + + case SCHATTR_SYMBOL_SIZE: + { + Size aSize = static_cast< const SvxSizeItem & >( + rItemSet.Get( nWhichId )).GetSize(); + chart2::Symbol aSymbol; + + GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol; + if( aSize.getWidth() != aSymbol.Size.Width || + aSize.getHeight() != aSymbol.Size.Height ) + { + aSymbol.Size.Width = aSize.getWidth(); + aSymbol.Size.Height = aSize.getHeight(); + + GetPropertySet()->setPropertyValue( "Symbol" , uno::Any( aSymbol )); + bChanged = true; + } + } + break; + + case SCHATTR_SYMBOL_BRUSH: + { + const SvxBrushItem & rBrshItem( static_cast< const SvxBrushItem & >( + rItemSet.Get( nWhichId ))); + uno::Any aXGraphicAny; + const Graphic *pGraphic( rBrshItem.GetGraphic()); + if( pGraphic ) + { + uno::Reference< graphic::XGraphic > xGraphic( pGraphic->GetXGraphic()); + if( xGraphic.is()) + { + aXGraphicAny <<= xGraphic; + chart2::Symbol aSymbol; + GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol; + if( aSymbol.Graphic != xGraphic ) + { + aSymbol.Graphic = xGraphic; + GetPropertySet()->setPropertyValue( "Symbol" , uno::Any( aSymbol )); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_TEXT_DEGREES: + { + double fValue = toDegrees(rItemSet.Get(SCHATTR_TEXT_DEGREES).GetValue()); + double fOldValue = 0.0; + bool bPropExisted = + ( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fOldValue ); + + if( ! bPropExisted || fOldValue != fValue ) + { + GetPropertySet()->setPropertyValue( "TextRotation" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY: + { + bool bHideLegendEntry = static_cast<const SfxBoolItem &>(rItemSet.Get(nWhichId)).GetValue(); + if (bHideLegendEntry != m_bHideLegendEntry) + { + uno::Sequence<sal_Int32> deletedLegendEntriesSeq; + m_xSeries->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq; + std::vector<sal_Int32> deletedLegendEntries; + for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq)) + { + if (bHideLegendEntry || m_nPointIndex != deletedLegendEntry) + deletedLegendEntries.push_back(deletedLegendEntry); + } + if (bHideLegendEntry) + deletedLegendEntries.push_back(m_nPointIndex); + m_xSeries->setPropertyValue("DeletedLegendEntries", uno::Any(comphelper::containerToSequence(deletedLegendEntries))); + } + } + break; + + case SCHATTR_DATADESCR_CUSTOM_LEADER_LINES: + { + try + { + bool bNew = static_cast<const SfxBoolItem&>(rItemSet.Get(nWhichId)).GetValue(); + bool bOld = true; + if( (m_xSeries->getPropertyValue("ShowCustomLeaderLines") >>= bOld) && bOld != bNew ) + { + m_xSeries->setPropertyValue("ShowCustomLeaderLines", uno::Any(bNew)); + bChanged = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + } + + return bChanged; +} + +void DataPointItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_DATADESCR_SHOW_NUMBER: + case SCHATTR_DATADESCR_SHOW_PERCENTAGE: + case SCHATTR_DATADESCR_SHOW_CATEGORY: + case SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME: + case SCHATTR_DATADESCR_SHOW_SYMBOL: + { + chart2::DataPointLabel aLabel; + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel) + { + bool bValue = (nWhichId==SCHATTR_DATADESCR_SHOW_NUMBER) ? aLabel.ShowNumber : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_PERCENTAGE) ? aLabel.ShowNumberInPercent : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_CATEGORY) ? aLabel.ShowCategoryName : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME) ? aLabel.ShowSeriesName : aLabel.ShowLegendSymbol ))); + + rOutItemSet.Put( SfxBoolItem( nWhichId, bValue )); + + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + if( DataSeriesHelper::hasAttributedDataPointDifferentValue( + Reference< chart2::XDataSeries >( GetPropertySet(), uno::UNO_QUERY), CHART_UNONAME_LABEL , uno::Any(aLabel) ) ) + { + rOutItemSet.InvalidateItem(nWhichId); + } + } + } + } + break; + + case SID_ATTR_NUMBERFORMAT_VALUE: + { + sal_Int32 nKey = 0; + if (!(GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nKey)) + nKey = m_nNumberFormat; + rOutItemSet.Put( SfxUInt32Item( nWhichId, nKey )); + } + break; + + case SCHATTR_PERCENT_NUMBERFORMAT_VALUE: + { + sal_Int32 nKey = 0; + if( !(GetPropertySet()->getPropertyValue( "PercentageNumberFormat" ) >>= nKey) ) + nKey = m_nPercentNumberFormat; + rOutItemSet.Put( SfxUInt32Item( nWhichId, nKey )); + } + break; + + case SID_ATTR_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = false; + try + { + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bUseSourceFormat; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT).hasValue() && !bUseSourceFormat; + rOutItemSet.Put( SfxBoolItem( nWhichId, ! bNumberFormatIsSet )); + } + break; + case SCHATTR_PERCENT_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = false; + try + { + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bUseSourceFormat; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue( "PercentageNumberFormat" ).hasValue() && !bUseSourceFormat; + rOutItemSet.Put( SfxBoolItem( nWhichId, ! bNumberFormatIsSet )); + } + break; + + case SCHATTR_DATADESCR_SEPARATOR: + { + try + { + OUString aValue; + GetPropertySet()->getPropertyValue( "LabelSeparator" ) >>= aValue; + rOutItemSet.Put( SfxStringItem( nWhichId, aValue )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_WRAP_TEXT: + { + try + { + bool bValue = false; + GetPropertySet()->getPropertyValue( "TextWordWrap" ) >>= bValue; + rOutItemSet.Put( SfxBoolItem( nWhichId, bValue )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_PLACEMENT: + { + try + { + sal_Int32 nPlacement=0; + RelativePosition aCustomLabelPosition; + if( !m_bOverwriteLabelsForAttributedDataPointsAlso && (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) ) + rOutItemSet.Put(SfxInt32Item(nWhichId, css::chart::DataLabelPlacement::CUSTOM)); + else if( GetPropertySet()->getPropertyValue( "LabelPlacement" ) >>= nPlacement ) + rOutItemSet.Put( SfxInt32Item( nWhichId, nPlacement )); + else if( m_aAvailableLabelPlacements.hasElements() ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_aAvailableLabelPlacements[0] )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS: + { + rOutItemSet.Put( SfxIntegerListItem( nWhichId, m_aAvailableLabelPlacements ) ); + } + break; + + case SCHATTR_DATADESCR_NO_PERCENTVALUE: + { + rOutItemSet.Put( SfxBoolItem( nWhichId, m_bForbidPercentValue )); + } + break; + + case SCHATTR_DATADESCR_CUSTOM_LEADER_LINES: + { + try + { + bool bValue = true; + if( m_xSeries->getPropertyValue( "ShowCustomLeaderLines" ) >>= bValue ) + rOutItemSet.Put(SfxBoolItem(nWhichId, bValue)); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + + case SCHATTR_STYLE_SYMBOL: + { + chart2::Symbol aSymbol; + if( GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol ) + rOutItemSet.Put( SfxInt32Item( nWhichId, lcl_getSymbolStyleForSymbol( aSymbol ) )); + } + break; + + case SCHATTR_SYMBOL_SIZE: + { + chart2::Symbol aSymbol; + if( GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol ) + rOutItemSet.Put( + SvxSizeItem( nWhichId, Size( aSymbol.Size.Width, aSymbol.Size.Height ) )); + } + break; + + case SCHATTR_SYMBOL_BRUSH: + { + chart2::Symbol aSymbol; + if(( GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol ) + && aSymbol.Graphic.is() ) + { + rOutItemSet.Put( SvxBrushItem( Graphic( aSymbol.Graphic ), GPOS_MM, SCHATTR_SYMBOL_BRUSH )); + } + } + break; + + case SCHATTR_TEXT_DEGREES: + { + double fValue = 0; + + if( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fValue ) + { + rOutItemSet.Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, Degree100(static_cast< sal_Int32 >( + ::rtl::math::round( fValue * 100.0 ) ) ))); + } + } + break; + + case SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY: + { + rOutItemSet.Put(SfxBoolItem(nWhichId, m_bHideLegendEntry)); + break; + } + break; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/ErrorBarItemConverter.cxx b/chart2/source/controller/itemsetwrapper/ErrorBarItemConverter.cxx new file mode 100644 index 000000000..8e23902f6 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/ErrorBarItemConverter.cxx @@ -0,0 +1,433 @@ +/* -*- 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 <ErrorBarItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <StatisticsHelper.hxx> + +#include <GraphicPropertyItemConverter.hxx> + +#include <svl/stritem.hxx> +#include <svx/chrtitem.hxx> +#include <rtl/math.hxx> + +#include <com/sun/star/chart2/XInternalDataProvider.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart/ErrorBarStyle.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; + +namespace +{ + +void lcl_getErrorValues( const uno::Reference< beans::XPropertySet > & xErrorBarProp, + double & rOutPosError, double & rOutNegError ) +{ + if( ! xErrorBarProp.is()) + return; + + try + { + xErrorBarProp->getPropertyValue( "PositiveError" ) >>= rOutPosError; + xErrorBarProp->getPropertyValue( "NegativeError" ) >>= rOutNegError; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void lcl_getErrorIndicatorValues( + const uno::Reference< beans::XPropertySet > & xErrorBarProp, + bool & rOutShowPosError, bool & rOutShowNegError ) +{ + if( ! xErrorBarProp.is()) + return; + + try + { + xErrorBarProp->getPropertyValue( "ShowPositiveError" ) >>= rOutShowPosError; + xErrorBarProp->getPropertyValue( "ShowNegativeError" ) >>= rOutShowNegError; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +ErrorBarItemConverter::ErrorBarItemConverter( + const uno::Reference< frame::XModel > & xModel, + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) : + ItemConverter( rPropertySet, rItemPool ), + m_spGraphicConverter( std::make_shared<GraphicPropertyItemConverter>( + rPropertySet, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, + GraphicObjectType::LineProperties )), + m_xModel( xModel ) +{} + +ErrorBarItemConverter::~ErrorBarItemConverter() +{} + +void ErrorBarItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + m_spGraphicConverter->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool ErrorBarItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = m_spGraphicConverter->ApplyItemSet( rItemSet ); + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& ErrorBarItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nErrorBarWhichPairs; +} + +bool ErrorBarItemConverter::GetItemProperty( + tWhichIdType /* nWhichId */, + tPropertyNameWithMemberId & /* rOutProperty */ ) const +{ + return false; +} + +bool ErrorBarItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + // Attention !!! This case must be passed before SCHATTR_STAT_PERCENT, + // SCHATTR_STAT_BIGERROR, SCHATTR_STAT_CONSTPLUS, + // SCHATTR_STAT_CONSTMINUS and SCHATTR_STAT_INDICATE + case SCHATTR_STAT_KIND_ERROR: + { + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + SvxChartKindError eErrorKind = + static_cast< const SvxChartKindErrorItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + if( !xErrorBarProp.is() && eErrorKind == SvxChartKindError::NONE) + { + //nothing to do + } + else + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + + switch( eErrorKind ) + { + case SvxChartKindError::NONE: + nStyle = css::chart::ErrorBarStyle::NONE; break; + case SvxChartKindError::Variant: + nStyle = css::chart::ErrorBarStyle::VARIANCE; break; + case SvxChartKindError::Sigma: + nStyle = css::chart::ErrorBarStyle::STANDARD_DEVIATION; break; + case SvxChartKindError::Percent: + nStyle = css::chart::ErrorBarStyle::RELATIVE; break; + case SvxChartKindError::BigError: + nStyle = css::chart::ErrorBarStyle::ERROR_MARGIN; break; + case SvxChartKindError::Const: + nStyle = css::chart::ErrorBarStyle::ABSOLUTE; break; + case SvxChartKindError::StdError: + nStyle = css::chart::ErrorBarStyle::STANDARD_ERROR; break; + case SvxChartKindError::Range: + nStyle = css::chart::ErrorBarStyle::FROM_DATA; break; + } + + xErrorBarProp->setPropertyValue( "ErrorBarStyle" , uno::Any( nStyle )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_PERCENT: + case SCHATTR_STAT_BIGERROR: + { + OSL_FAIL( "Deprecated item" ); + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( ! ( ::rtl::math::approxEqual( fPos, fValue ) && + ::rtl::math::approxEqual( fNeg, fValue ))) + { + xErrorBarProp->setPropertyValue( "PositiveError" , uno::Any( fValue )); + xErrorBarProp->setPropertyValue( "NegativeError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_CONSTPLUS: + { + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + + if( ! ::rtl::math::approxEqual( fPos, fValue )) + { + GetPropertySet()->setPropertyValue( "PositiveError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_CONSTMINUS: + { + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( ! ::rtl::math::approxEqual( fNeg, fValue )) + { + xErrorBarProp->setPropertyValue( "NegativeError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_INDICATE: + { + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + SvxChartIndicate eIndicate = + static_cast< const SvxChartIndicateItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + bool bNewIndPos = (eIndicate == SvxChartIndicate::Both || eIndicate == SvxChartIndicate::Up ); + bool bNewIndNeg = (eIndicate == SvxChartIndicate::Both || eIndicate == SvxChartIndicate::Down ); + + bool bShowPos(false), bShowNeg(false); + lcl_getErrorIndicatorValues( xErrorBarProp, bShowPos, bShowNeg ); + + if( bShowPos != bNewIndPos || + bShowNeg != bNewIndNeg ) + { + xErrorBarProp->setPropertyValue( "ShowPositiveError" , uno::Any( bNewIndPos )); + xErrorBarProp->setPropertyValue( "ShowNegativeError" , uno::Any( bNewIndNeg )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_RANGE_POS: + case SCHATTR_STAT_RANGE_NEG: + { + // @todo: also be able to deal with x-error bars + const bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< chart2::data::XDataSource > xErrorBarSource( GetPropertySet(), uno::UNO_QUERY ); + uno::Reference< chart2::XChartDocument > xChartDoc( m_xModel, uno::UNO_QUERY ); + uno::Reference< chart2::data::XDataProvider > xDataProvider; + + if( xChartDoc.is()) + xDataProvider.set( xChartDoc->getDataProvider()); + if( xErrorBarSource.is() && xDataProvider.is()) + { + OUString aNewRange( static_cast< const SfxStringItem & >( rItemSet.Get( nWhichId )).GetValue()); + bool bApplyNewRange = false; + + bool bIsPositiveValue( nWhichId == SCHATTR_STAT_RANGE_POS ); + if( xChartDoc->hasInternalDataProvider()) + { + if( !aNewRange.isEmpty()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, bIsPositiveValue, bYError )); + if( ! xSeq.is()) + { + // no data range for error bars yet => create + uno::Reference< chart2::XInternalDataProvider > xIntDataProvider( xDataProvider, uno::UNO_QUERY ); + OSL_ASSERT( xIntDataProvider.is()); + if( xIntDataProvider.is()) + { + xIntDataProvider->appendSequence(); + aNewRange = "last"; + bApplyNewRange = true; + } + } + } + } + else + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, bIsPositiveValue, bYError )); + bApplyNewRange = + ! ( xSeq.is() && (aNewRange == xSeq->getSourceRangeRepresentation())); + } + + if( bApplyNewRange ) + StatisticsHelper::setErrorDataSequence( + xErrorBarSource, xDataProvider, aNewRange, bIsPositiveValue, bYError ); + } + } + break; + } + + return bChanged; +} + +void ErrorBarItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_STAT_KIND_ERROR: + { + SvxChartKindError eErrorKind = SvxChartKindError::NONE; + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + sal_Int32 nStyle = 0; + if( xErrorBarProp->getPropertyValue( "ErrorBarStyle" ) >>= nStyle ) + { + switch( nStyle ) + { + case css::chart::ErrorBarStyle::NONE: + break; + case css::chart::ErrorBarStyle::VARIANCE: + eErrorKind = SvxChartKindError::Variant; break; + case css::chart::ErrorBarStyle::STANDARD_DEVIATION: + eErrorKind = SvxChartKindError::Sigma; break; + case css::chart::ErrorBarStyle::ABSOLUTE: + eErrorKind = SvxChartKindError::Const; break; + case css::chart::ErrorBarStyle::RELATIVE: + eErrorKind = SvxChartKindError::Percent; break; + case css::chart::ErrorBarStyle::ERROR_MARGIN: + eErrorKind = SvxChartKindError::BigError; break; + case css::chart::ErrorBarStyle::STANDARD_ERROR: + eErrorKind = SvxChartKindError::StdError; break; + case css::chart::ErrorBarStyle::FROM_DATA: + eErrorKind = SvxChartKindError::Range; break; + } + } + rOutItemSet.Put( SvxChartKindErrorItem( eErrorKind, SCHATTR_STAT_KIND_ERROR )); + } + break; + + case SCHATTR_STAT_PERCENT: + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, SCHATTR_STAT_PERCENT )); + } + break; + + case SCHATTR_STAT_BIGERROR: + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, SCHATTR_STAT_BIGERROR )); + } + break; + + case SCHATTR_STAT_CONSTPLUS: + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( fPos, SCHATTR_STAT_CONSTPLUS )); + } + break; + + case SCHATTR_STAT_CONSTMINUS: + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( fNeg, SCHATTR_STAT_CONSTMINUS )); + } + break; + + case SCHATTR_STAT_INDICATE: + { + SvxChartIndicate eIndicate = SvxChartIndicate::Both; + bool bShowPos(false), bShowNeg(false); + lcl_getErrorIndicatorValues( GetPropertySet(), bShowPos, bShowNeg ); + + if( bShowPos ) + { + if( bShowNeg ) + eIndicate = SvxChartIndicate::Both; + else + eIndicate = SvxChartIndicate::Up; + } + else + { + if( bShowNeg ) + eIndicate = SvxChartIndicate::Down; + else + eIndicate = SvxChartIndicate::NONE; + } + rOutItemSet.Put( SvxChartIndicateItem( eIndicate, SCHATTR_STAT_INDICATE )); + } + break; + + case SCHATTR_STAT_RANGE_POS: + case SCHATTR_STAT_RANGE_NEG: + { + const bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< chart2::data::XDataSource > xErrorBarSource( GetPropertySet(), uno::UNO_QUERY ); + if( xErrorBarSource.is()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, (nWhichId == SCHATTR_STAT_RANGE_POS), bYError )); + if( xSeq.is()) + rOutItemSet.Put( SfxStringItem( nWhichId, xSeq->getSourceRangeRepresentation())); + } + } + break; + } +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx b/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx new file mode 100644 index 000000000..e265e4198 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx @@ -0,0 +1,751 @@ +/* -*- 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 <GraphicPropertyItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <ItemPropertyMap.hxx> +#include <PropertyHelper.hxx> +#include <CommonConverters.hxx> +#include <editeng/memberids.h> +#include <svx/unomid.hxx> +#include <svx/xflbmtit.hxx> +#include <svx/xflbstit.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/xflftrit.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xfltrit.hxx> +#include <svx/xlntrit.hxx> +#include <svx/xgrscit.hxx> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetDataPointFilledPropertyMap() +{ + static ItemPropertyMapType aDataPointPropertyFilledMap{ + {XATTR_FILLSTYLE, {"FillStyle", 0}}, + {XATTR_FILLCOLOR, {"Color", 0}}, + {XATTR_LINECOLOR, {"BorderColor", 0}}, + {XATTR_LINESTYLE, {"BorderStyle", 0}}, + {XATTR_LINEWIDTH, {"BorderWidth", 0}}, + {XATTR_FILLBACKGROUND, {"FillBackground", 0}}, + {XATTR_FILLBMP_POS, {"FillBitmapRectanglePoint", 0}}, + {XATTR_FILLBMP_SIZEX, {"FillBitmapSizeX", 0}}, + {XATTR_FILLBMP_SIZEY, {"FillBitmapSizeY", 0}}, + {XATTR_FILLBMP_SIZELOG, {"FillBitmapLogicalSize", 0}}, + {XATTR_FILLBMP_TILEOFFSETX, {"FillBitmapOffsetX", 0}}, + {XATTR_FILLBMP_TILEOFFSETY, {"FillBitmapOffsetY", 0}}, + {XATTR_FILLBMP_POSOFFSETX, {"FillBitmapPositionOffsetX", 0}}, + {XATTR_FILLBMP_POSOFFSETY, {"FillBitmapPositionOffsetY", 0}}}; + return aDataPointPropertyFilledMap; +} +ItemPropertyMapType & lcl_GetDataPointLinePropertyMap() +{ + static ItemPropertyMapType aDataPointPropertyLineMap{ + {XATTR_LINECOLOR, {"Color", 0}}, + {XATTR_LINESTYLE, {"LineStyle", 0}}, + {XATTR_LINEWIDTH, {"LineWidth", 0}}, + {XATTR_LINECAP, {"LineCap", 0}}}; + return aDataPointPropertyLineMap; +} +ItemPropertyMapType & lcl_GetLinePropertyMap() +{ + static ItemPropertyMapType aLinePropertyMap{ + {XATTR_LINESTYLE, {"LineStyle", 0}}, + {XATTR_LINEWIDTH, {"LineWidth", 0}}, + {XATTR_LINECOLOR, {"LineColor", 0}}, + {XATTR_LINEJOINT, {"LineJoint", 0}}, + {XATTR_LINECAP, {"LineCap", 0}}}; + return aLinePropertyMap; +} +ItemPropertyMapType & lcl_GetFillPropertyMap() +{ + static ItemPropertyMapType aFillPropertyMap{ + {XATTR_FILLSTYLE, {"FillStyle", 0}}, + {XATTR_FILLCOLOR, {"FillColor", 0}}, + {XATTR_FILLBACKGROUND, {"FillBackground", 0}}, + {XATTR_FILLBMP_POS, {"FillBitmapRectanglePoint", 0}}, + {XATTR_FILLBMP_SIZEX, {"FillBitmapSizeX", 0}}, + {XATTR_FILLBMP_SIZEY, {"FillBitmapSizeY", 0}}, + {XATTR_FILLBMP_SIZELOG, {"FillBitmapLogicalSize", 0}}, + {XATTR_FILLBMP_TILEOFFSETX, {"FillBitmapOffsetX", 0}}, + {XATTR_FILLBMP_TILEOFFSETY, {"FillBitmapOffsetY", 0}}, + {XATTR_FILLBMP_POSOFFSETX, {"FillBitmapPositionOffsetX", 0}}, + {XATTR_FILLBMP_POSOFFSETY, {"FillBitmapPositionOffsetY", 0}}}; + return aFillPropertyMap; +} + +bool lcl_supportsFillProperties( ::chart::wrapper::GraphicObjectType eType ) +{ + return ( eType == ::chart::wrapper::GraphicObjectType::FilledDataPoint || + eType == ::chart::wrapper::GraphicObjectType::LineAndFillProperties ); +} + +bool lcl_SetContentForNamedProperty( + const uno::Reference< lang::XMultiServiceFactory > & xFactory, + const OUString & rTableName, + NameOrIndex & rItem, sal_uInt8 nMemberId ) +{ + bool bResult = false; + if( xFactory.is()) + { + OUString aPropertyValue( rItem.GetName()); + uno::Reference< container::XNameAccess > xNameAcc( + xFactory->createInstance( rTableName ), + uno::UNO_QUERY ); + if( xNameAcc.is() && + xNameAcc->hasByName( aPropertyValue )) + { + rItem.PutValue( xNameAcc->getByName( aPropertyValue ), nMemberId ); + bResult = true; + } + } + return bResult; +} + +} // anonymous namespace + +GraphicPropertyItemConverter::GraphicPropertyItemConverter( + const uno::Reference< + beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + GraphicObjectType eObjectType /* = FILL_PROPERTIES */ ) : + ItemConverter( rPropertySet, rItemPool ), + m_GraphicObjectType( eObjectType ), + m_rDrawModel( rDrawModel ), + m_xNamedPropertyTableFactory( xNamedPropertyContainerFactory ) +{} + +GraphicPropertyItemConverter::~GraphicPropertyItemConverter() +{} + +const WhichRangesContainer& GraphicPropertyItemConverter::GetWhichPairs() const +{ + switch( m_GraphicObjectType ) + { + case GraphicObjectType::LineDataPoint: + case GraphicObjectType::FilledDataPoint: + return nRowWhichPairs; + case GraphicObjectType::LineProperties: + return nLinePropertyWhichPairs; + case GraphicObjectType::LineAndFillProperties: + return nLineAndFillPropertyWhichPairs; + } + + static const WhichRangesContainer empty; + return empty; +} + +bool GraphicPropertyItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType::const_iterator aEndIt; + ItemPropertyMapType::const_iterator aIt; + + switch( m_GraphicObjectType ) + { + case GraphicObjectType::LineDataPoint: + aEndIt = lcl_GetDataPointLinePropertyMap().end(); + aIt = lcl_GetDataPointLinePropertyMap().find( nWhichId ); + break; + case GraphicObjectType::FilledDataPoint: + aEndIt = lcl_GetDataPointFilledPropertyMap().end(); + aIt = lcl_GetDataPointFilledPropertyMap().find( nWhichId ); + break; + case GraphicObjectType::LineProperties: + aEndIt = lcl_GetLinePropertyMap().end(); + aIt = lcl_GetLinePropertyMap().find( nWhichId ); + break; + + case GraphicObjectType::LineAndFillProperties: + // line + aEndIt = lcl_GetLinePropertyMap().end(); + aIt = lcl_GetLinePropertyMap().find( nWhichId ); + + // not found => try fill + if( aIt == aEndIt ) + { + aEndIt = lcl_GetFillPropertyMap().end(); + aIt = lcl_GetFillPropertyMap().find( nWhichId ); + } + break; + } + + if( aIt == aEndIt ) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +void GraphicPropertyItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + // bitmap property + case XATTR_FILLBMP_TILE: + case XATTR_FILLBMP_STRETCH: + { + drawing::BitmapMode aMode = drawing::BitmapMode_REPEAT; + if( GetPropertySet()->getPropertyValue( "FillBitmapMode" ) >>= aMode ) + { + rOutItemSet.Put( XFillBmpTileItem( aMode == drawing::BitmapMode_REPEAT )); + rOutItemSet.Put( XFillBmpStretchItem( aMode == drawing::BitmapMode_STRETCH )); + } + } + break; + + case XATTR_FILLFLOATTRANSPARENCE: + try + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "TransparencyGradientName" ) + : OUString( "FillTransparenceGradientName" ); + + uno::Any aValue( GetPropertySet()->getPropertyValue( aPropName )); + if( aValue.hasValue()) + { + XFillFloatTransparenceItem aItem; + aItem.PutValue( aValue, MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.TransparencyGradientTable" , + aItem, MID_FILLGRADIENT ); + + // this is important to enable the item + OUString aName; + if( (aValue >>= aName) && + !aName.isEmpty()) + { + aItem.SetEnabled( true ); + rOutItemSet.Put( aItem ); + } + } + } + } + catch( const beans::UnknownPropertyException & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + break; + + case XATTR_GRADIENTSTEPCOUNT: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "GradientStepCount" ) + : OUString( "FillGradientStepCount" ); + + uno::Any aValue( GetPropertySet()->getPropertyValue( aPropName ) ); + if( hasLongOrShortValue(aValue) ) + { + sal_Int16 nStepCount = getShortForLongAlso(aValue); + rOutItemSet.Put( XGradientStepCountItem( nStepCount )); + } + } + break; + + case XATTR_LINEDASH: + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "BorderDashName" ) + : OUString( "LineDashName" ); + + XLineDashItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.DashTable" , + aItem, MID_LINEDASH ); + + // translate model name to UI-name for predefined entries, so + // that the correct entry is chosen in the list of UI-names + std::unique_ptr<XLineDashItem> pItemToPut = aItem.checkForUniqueItem( & m_rDrawModel ); + + if(pItemToPut) + rOutItemSet.Put( std::move(pItemToPut) ); + else + rOutItemSet.Put(aItem); + } + break; + + case XATTR_FILLGRADIENT: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "GradientName" ) + : OUString( "FillGradientName" ); + + XFillGradientItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.GradientTable" , + aItem, MID_FILLGRADIENT ); + + // translate model name to UI-name for predefined entries, so + // that the correct entry is chosen in the list of UI-names + std::unique_ptr<XFillGradientItem> pItemToPut = aItem.checkForUniqueItem( & m_rDrawModel ); + + if(pItemToPut) + rOutItemSet.Put(std::move(pItemToPut) ); + else + rOutItemSet.Put(aItem); + } + break; + + case XATTR_FILLHATCH: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "HatchName" ) + : OUString( "FillHatchName" ); + + XFillHatchItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.HatchTable" , + aItem, MID_FILLHATCH ); + + // translate model name to UI-name for predefined entries, so + // that the correct entry is chosen in the list of UI-names + std::unique_ptr<XFillHatchItem> pItemToPut = aItem.checkForUniqueItem( & m_rDrawModel ); + + if(pItemToPut) + rOutItemSet.Put( std::move(pItemToPut) ); + else + rOutItemSet.Put(aItem); + } + break; + + case XATTR_FILLBITMAP: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + XFillBitmapItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( "FillBitmapName" ), MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.BitmapTable" , + aItem, MID_BITMAP ); + + // translate model name to UI-name for predefined entries, so + // that the correct entry is chosen in the list of UI-names + std::unique_ptr<XFillBitmapItem> pItemToPut = aItem.checkForUniqueItem( & m_rDrawModel ); + + if(pItemToPut) + rOutItemSet.Put( std::move(pItemToPut) ); + else + rOutItemSet.Put(aItem); + } + break; + + // hack, because QueryValue of XLineTransparenceItem returns sal_Int32 + // instead of sal_Int16 + case XATTR_LINETRANSPARENCE: + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "BorderTransparency" ) + : (m_GraphicObjectType == GraphicObjectType::LineDataPoint) + ? OUString( "Transparency" ) + : OUString( "LineTransparence" ); + + XLineTransparenceItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), 0 ); + + rOutItemSet.Put( aItem ); + } + break; + + // hack, because QueryValue of XFillTransparenceItem returns sal_Int32 + // instead of sal_Int16 + case XATTR_FILLTRANSPARENCE: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "Transparency" ) + : OUString( "FillTransparence" ); + + XFillTransparenceItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), 0 ); + + rOutItemSet.Put( aItem ); + } + break; + } +} + +bool GraphicPropertyItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + uno::Any aValue; + + switch( nWhichId ) + { + // bitmap property + case XATTR_FILLBMP_STRETCH: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + static const OUStringLiteral aModePropName(u"FillBitmapMode"); + bool bStretched = rItemSet.Get( XATTR_FILLBMP_STRETCH ).GetValue(); + drawing::BitmapMode aMode = + (bStretched ? drawing::BitmapMode_STRETCH : drawing::BitmapMode_NO_REPEAT); + drawing::BitmapMode aOtherMode = drawing::BitmapMode_NO_REPEAT; + + aValue <<= aMode; + GetPropertySet()->getPropertyValue( aModePropName ) >>= aOtherMode; + + // don't overwrite if it has been set to BitmapMode_REPEAT (= tiled) already + // XATTR_FILLBMP_STRETCH and XATTR_FILLBMP_TILE often come in pairs, tdf#104658 + if( aMode != aOtherMode && aOtherMode != drawing::BitmapMode_REPEAT ) + { + GetPropertySet()->setPropertyValue( aModePropName, aValue ); + bChanged = true; + } + } + break; + + case XATTR_FILLBMP_TILE: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + static const OUStringLiteral aModePropName(u"FillBitmapMode"); + bool bTiled = rItemSet.Get( XATTR_FILLBMP_TILE ).GetValue(); + drawing::BitmapMode aMode = + (bTiled ? drawing::BitmapMode_REPEAT : drawing::BitmapMode_NO_REPEAT); + + aValue <<= aMode; + if( aValue != GetPropertySet()->getPropertyValue( aModePropName )) + { + GetPropertySet()->setPropertyValue( aModePropName, aValue ); + bChanged = true; + } + } + break; + + case XATTR_FILLFLOATTRANSPARENCE: + try + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "TransparencyGradientName" ) + : OUString( "FillTransparenceGradientName" ); + + const XFillFloatTransparenceItem & rItem = + static_cast< const XFillFloatTransparenceItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.IsEnabled() && + rItem.QueryValue( aValue, MID_NAME )) + { + uno::Any aGradient; + rItem.QueryValue( aGradient, MID_FILLGRADIENT ); + + // add TransparencyGradient to list if it does not already exist + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addTransparencyGradientUniqueNameToTable( + aGradient, m_xNamedPropertyTableFactory, aPreferredName ); + + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + else + { + OUString aName; + if( ( GetPropertySet()->getPropertyValue( aPropName ) >>= aName ) + && !aName.isEmpty() ) + { + uno::Reference< beans::XPropertyState > xState( GetPropertySet(), uno::UNO_QUERY ); + if( xState.is()) + xState->setPropertyToDefault( aPropName ); + bChanged = true; + } + } + } + } + catch( const beans::UnknownPropertyException & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + break; + + case XATTR_GRADIENTSTEPCOUNT: + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "GradientStepCount" ) + : OUString( "FillGradientStepCount" ); + + sal_Int16 nStepCount = static_cast< const XGradientStepCountItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + aValue <<= nStepCount; + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + } + break; + + case XATTR_LINEDASH: + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "BorderDashName" ) + : OUString( "LineDashName" ); + + const XLineDashItem & rItem = + static_cast< const XLineDashItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + // add LineDash to list + uno::Any aLineDash; + rItem.QueryValue( aLineDash, MID_LINEDASH ); + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addLineDashUniqueNameToTable( + aLineDash, m_xNamedPropertyTableFactory, aPreferredName ); + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + } + break; + + case XATTR_FILLGRADIENT: + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "GradientName" ) + : OUString( "FillGradientName" ); + + const XFillGradientItem & rItem = + static_cast< const XFillGradientItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + // add Gradient to list + uno::Any aGradient; + rItem.QueryValue( aGradient, MID_FILLGRADIENT ); + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addGradientUniqueNameToTable( + aGradient, m_xNamedPropertyTableFactory, aPreferredName ); + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + } + } + break; + + case XATTR_FILLHATCH: + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "HatchName" ) + : OUString( "FillHatchName" ); + + const XFillHatchItem & rItem = + static_cast< const XFillHatchItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + // add Hatch to list + uno::Any aHatch; + rItem.QueryValue( aHatch, MID_FILLHATCH ); + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addHatchUniqueNameToTable( + aHatch, m_xNamedPropertyTableFactory, aPreferredName ); + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + } + } + break; + + case XATTR_FILLBITMAP: + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + const XFillBitmapItem & rItem = + static_cast< const XFillBitmapItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( "FillBitmapName" )) + { + // add Bitmap to list + uno::Any aBitmap; + rItem.QueryValue(aBitmap, MID_BITMAP); + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addBitmapUniqueNameToTable( + aBitmap, m_xNamedPropertyTableFactory, aPreferredName ); + + GetPropertySet()->setPropertyValue( "FillBitmapName" , aValue ); + bChanged = true; + } + } + } + } + break; + + // hack, because QueryValue of XLineTransparenceItem returns sal_Int32 + // instead of sal_Int16 + case XATTR_LINETRANSPARENCE: + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "BorderTransparency" ) + : (m_GraphicObjectType == GraphicObjectType::LineDataPoint) + ? OUString( "Transparency" ) + : OUString( "LineTransparence" ); + + const XLineTransparenceItem & rItem = + static_cast< const XLineTransparenceItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue )) + { + OSL_ENSURE( ! aValue.isExtractableTo( + cppu::UnoType<sal_Int16>::get()), + "TransparenceItem QueryValue bug is fixed. Remove hack." ); + sal_Int32 nValue = 0; + if( aValue >>= nValue ) + { + OSL_ENSURE( nValue < SAL_MAX_INT16, "Transparency value too large" ); + sal_Int16 nValueToSet( static_cast< sal_Int16 >( nValue )); + aValue <<= nValueToSet; + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + else + { + OSL_FAIL( "Wrong type in Transparency Any" ); + } + } + } + break; + + // hack, because QueryValue of XFillTransparenceItem returns sal_Int32 + // instead of sal_Int16 + case XATTR_FILLTRANSPARENCE: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "Transparency" ) + : OUString( "FillTransparence" ); + + const XFillTransparenceItem & rItem = + static_cast< const XFillTransparenceItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue )) + { + OSL_ENSURE( ! aValue.isExtractableTo( + cppu::UnoType<sal_Int16>::get()), + "TransparenceItem QueryValue bug is fixed. Remove hack." ); + sal_Int32 nValue = 0; + if( aValue >>= nValue ) + { + OSL_ENSURE( nValue < SAL_MAX_INT16, "Transparency value too large" ); + sal_Int16 nValueToSet( static_cast< sal_Int16 >( nValue )); + aValue <<= nValueToSet; + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + // if linear or no transparence is set, delete the gradient + OUString aTransGradPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "TransparencyGradientName" ) + : OUString( "FillTransparenceGradientName" ); + GetPropertySet()->setPropertyValue( + aTransGradPropName, uno::Any( OUString() )); + + bChanged = true; + } + else + { + OSL_FAIL( "Wrong type in Transparency Any" ); + } + } + } + break; + } + + return bChanged; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/ItemConverter.cxx b/chart2/source/controller/itemsetwrapper/ItemConverter.cxx new file mode 100644 index 000000000..d79079b77 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/ItemConverter.cxx @@ -0,0 +1,222 @@ +/* -*- 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 <ItemConverter.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <osl/diagnose.h> +#include <svl/itempool.hxx> +#include <svl/itemiter.hxx> +#include <svl/whiter.hxx> +#include <svx/svxids.hrc> +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +ItemConverter::ItemConverter( + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ) : + m_xPropertySet( rPropertySet ), + m_rItemPool( rItemPool ) +{ + resetPropertySet( m_xPropertySet ); +} + +ItemConverter::~ItemConverter() +{ + stopAllComponentListening(); +} + +void ItemConverter::resetPropertySet( + const uno::Reference< beans::XPropertySet > & xPropSet ) +{ + if( !xPropSet.is()) + return; + + stopAllComponentListening(); + m_xPropertySet = xPropSet; + m_xPropertySetInfo = m_xPropertySet->getPropertySetInfo(); + + uno::Reference< lang::XComponent > xComp( m_xPropertySet, uno::UNO_QUERY ); + if( xComp.is()) + { + // method of base class ::utl::OEventListenerAdapter + startComponentListening( xComp ); + } +} + +SfxItemSet ItemConverter::CreateEmptyItemSet() const +{ + return SfxItemSet( GetItemPool(), GetWhichPairs() ); +} + +void ItemConverter::_disposing( const lang::EventObject& ) +{ +} + +void ItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + const WhichRangesContainer& pRanges = rOutItemSet.GetRanges(); + tPropertyNameWithMemberId aProperty; + SfxItemPool & rPool = GetItemPool(); + + assert(!pRanges.empty()); + OSL_ASSERT( m_xPropertySetInfo.is()); + OSL_ASSERT( m_xPropertySet.is()); + + for(const auto& rPair : pRanges) + { + sal_uInt16 nBeg = rPair.first; + sal_uInt16 nEnd = rPair.second; + + OSL_ASSERT( nBeg <= nEnd ); + for( sal_uInt16 nWhich = nBeg; nWhich <= nEnd; ++nWhich ) + { + if( GetItemProperty( nWhich, aProperty )) + { + // put the Property into the itemset + std::unique_ptr<SfxPoolItem> pItem(rPool.GetDefaultItem( nWhich ).Clone()); + + if( pItem ) + { + try + { + if( pItem->PutValue( m_xPropertySet->getPropertyValue( aProperty.first ), + aProperty.second // nMemberId + )) + { + pItem->SetWhich(nWhich); + rOutItemSet.Put( std::move(pItem) ); + } + } + catch( const beans::UnknownPropertyException & ) + { + TOOLS_WARN_EXCEPTION( "chart2", "unknown Property: " << aProperty.first); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + else + { + try + { + FillSpecialItem( nWhich, rOutItemSet ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } +} + +void ItemConverter::FillSpecialItem( + sal_uInt16 /*nWhichId*/, SfxItemSet & /*rOutItemSet*/ ) const +{ + OSL_FAIL( "ItemConverter: Unhandled special item found!" ); +} + +bool ItemConverter::ApplySpecialItem( + sal_uInt16 /*nWhichId*/, const SfxItemSet & /*rItemSet*/ ) +{ + OSL_FAIL( "ItemConverter: Unhandled special item found!" ); + return false; +} + +bool ItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + OSL_ASSERT( m_xPropertySet.is()); + + bool bItemsChanged = false; + SfxItemIter aIter( rItemSet ); + tPropertyNameWithMemberId aProperty; + uno::Any aValue; + + for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + { + if( aIter.GetItemState( false ) == SfxItemState::SET ) + { + if( GetItemProperty( pItem->Which(), aProperty )) + { + pItem->QueryValue( aValue, aProperty.second /* nMemberId */ ); + + try + { + if( aValue != m_xPropertySet->getPropertyValue( aProperty.first )) + { + m_xPropertySet->setPropertyValue( aProperty.first, aValue ); + bItemsChanged = true; + } + } + catch( const beans::UnknownPropertyException & ) + { + TOOLS_WARN_EXCEPTION( "chart2", "unknown Property: " << aProperty.first); + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION( "chart2", "" ); + } + } + else + { + bItemsChanged = ApplySpecialItem( pItem->Which(), rItemSet ) || bItemsChanged; + } + } + } + + return bItemsChanged; +} + +void ItemConverter::InvalidateUnequalItems( SfxItemSet &rDestSet, const SfxItemSet &rSourceSet ) +{ + SfxWhichIter aIter (rSourceSet); + sal_uInt16 nWhich = aIter.FirstWhich (); + const SfxPoolItem *pPoolItem = nullptr; + + while (nWhich) + { + SfxItemState nSourceItemState = aIter.GetItemState(true, &pPoolItem); + if ((nSourceItemState == SfxItemState::SET) && + (rDestSet.GetItemState(nWhich, true, &pPoolItem) == SfxItemState::SET)) + { + if (rSourceSet.Get(nWhich) != rDestSet.Get(nWhich)) + { + if( nWhich != SID_CHAR_DLG_PREVIEW_STRING ) + { + rDestSet.InvalidateItem(nWhich); + } + } + } + else if( nSourceItemState == SfxItemState::DONTCARE ) + rDestSet.InvalidateItem(nWhich); + + nWhich = aIter.NextWhich (); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/LegendItemConverter.cxx b/chart2/source/controller/itemsetwrapper/LegendItemConverter.cxx new file mode 100644 index 000000000..7a8dab188 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/LegendItemConverter.cxx @@ -0,0 +1,205 @@ +/* -*- 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 <LegendItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <GraphicPropertyItemConverter.hxx> +#include <CharacterPropertyItemConverter.hxx> +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart/ChartLegendExpansion.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <tools/diagnose_ex.h> + +#include <memory> + +using namespace ::com::sun::star; + +namespace chart::wrapper +{ + +LegendItemConverter::LegendItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const awt::Size* pRefSize ) : + ItemConverter( rPropertySet, rItemPool ) +{ + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, xNamedPropertyContainerFactory, + GraphicObjectType::LineAndFillProperties )); + m_aConverters.emplace_back( new CharacterPropertyItemConverter( + rPropertySet, rItemPool, pRefSize, + "ReferencePageSize" )); +} + +LegendItemConverter::~LegendItemConverter() +{ +} + +void LegendItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool LegendItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& LegendItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nLegendWhichPairs; +} + +bool LegendItemConverter::GetItemProperty( tWhichIdType /*nWhichId*/, tPropertyNameWithMemberId & /*rOutProperty*/ ) const +{ + // No own (non-special) properties + return false; +} + +bool LegendItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet& rInItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SCHATTR_LEGEND_SHOW: + { + if( const SfxBoolItem* pShowItem = rInItemSet.GetItemIfSet( SCHATTR_LEGEND_SHOW ) ) + { + bool bShow = pShowItem->GetValue(); + bool bWasShown = true; + if( ! (GetPropertySet()->getPropertyValue( "Show" ) >>= bWasShown) || + ( bWasShown != bShow )) + { + GetPropertySet()->setPropertyValue( "Show" , uno::Any( bShow )); + bChanged = true; + } + } + + } + break; + case SCHATTR_LEGEND_POS: + { + if( const SfxInt32Item* pPosItem = rInItemSet.GetItemIfSet( SCHATTR_LEGEND_POS ) ) + { + chart2::LegendPosition eNewPos = static_cast<chart2::LegendPosition>(pPosItem->GetValue()); + + css::chart::ChartLegendExpansion eExpansion = css::chart::ChartLegendExpansion_HIGH; + switch( eNewPos ) + { + case chart2::LegendPosition_LINE_START: + case chart2::LegendPosition_LINE_END: + eExpansion = css::chart::ChartLegendExpansion_HIGH; + break; + case chart2::LegendPosition_PAGE_START: + case chart2::LegendPosition_PAGE_END: + eExpansion = css::chart::ChartLegendExpansion_WIDE; + break; + default: + break; + } + + try + { + chart2::LegendPosition eOldPos; + if( ! ( GetPropertySet()->getPropertyValue( "AnchorPosition" ) >>= eOldPos ) || + ( eOldPos != eNewPos )) + { + GetPropertySet()->setPropertyValue( "AnchorPosition" , uno::Any( eNewPos )); + GetPropertySet()->setPropertyValue( "Expansion" , uno::Any( eExpansion )); + GetPropertySet()->setPropertyValue( "RelativePosition" , uno::Any()); + bChanged = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + break; + case SCHATTR_LEGEND_NO_OVERLAY: + { + if(const SfxBoolItem* pNoOverlayItem = rInItemSet.GetItemIfSet(SCHATTR_LEGEND_NO_OVERLAY)) + { + bool bOverlay = !pNoOverlayItem->GetValue(); + bool bOldOverlay = false; + if(!(GetPropertySet()->getPropertyValue("Overlay") >>= bOldOverlay) || + (bOldOverlay != bOverlay)) + { + GetPropertySet()->setPropertyValue("Overlay", uno::Any(bOverlay)); + bChanged = true; + } + } + + } + break; + } + + return bChanged; +} + +void LegendItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_LEGEND_SHOW: + { + bool bShow = true; + GetPropertySet()->getPropertyValue( "Show" ) >>= bShow; + rOutItemSet.Put( SfxBoolItem(SCHATTR_LEGEND_SHOW, bShow) ); + } + break; + case SCHATTR_LEGEND_POS: + { + chart2::LegendPosition eLegendPos( chart2::LegendPosition_LINE_END ); + GetPropertySet()->getPropertyValue( "AnchorPosition" ) >>= eLegendPos; + rOutItemSet.Put( SfxInt32Item(SCHATTR_LEGEND_POS, static_cast<sal_Int32>(eLegendPos) ) ); + } + break; + case SCHATTR_LEGEND_NO_OVERLAY: + { + bool bOverlay = false; + GetPropertySet()->getPropertyValue("Overlay") >>= bOverlay; + rOutItemSet.Put(SfxBoolItem(SCHATTR_LEGEND_NO_OVERLAY, !bOverlay)); + } + break; + } +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/MultipleChartConverters.cxx b/chart2/source/controller/itemsetwrapper/MultipleChartConverters.cxx new file mode 100644 index 000000000..5f460be98 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/MultipleChartConverters.cxx @@ -0,0 +1,192 @@ +/* -*- 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 <MultipleChartConverters.hxx> + +#include "SchWhichPairs.hxx" +#include <AxisItemConverter.hxx> +#include <StatisticsItemConverter.hxx> +#include <GraphicPropertyItemConverter.hxx> +#include <DataPointItemConverter.hxx> +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <Diagram.hxx> +#include <DataSeries.hxx> +#include <TitleHelper.hxx> +#include <TitleItemConverter.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <com/sun/star/chart2/XTitle.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart::wrapper { + +AllAxisItemConverter::AllAxisItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const awt::Size* pRefSize ) + : MultipleItemConverter( rItemPool ) +{ + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + const std::vector< rtl::Reference< Axis > > aElementList = AxisHelper::getAllAxesOfDiagram( xDiagram ); + for( rtl::Reference< Axis > const & axis : aElementList ) + { + uno::Reference< beans::XPropertySet > xObjectProperties(axis); + m_aConverters.emplace_back( new ::chart::wrapper::AxisItemConverter( + xObjectProperties, rItemPool, rDrawModel, + xChartModel, nullptr, nullptr, + pRefSize)); + } +} + +AllAxisItemConverter::~AllAxisItemConverter() +{ +} + +const WhichRangesContainer& AllAxisItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nAllAxisWhichPairs; +} + +AllGridItemConverter::AllGridItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) + : MultipleItemConverter( rItemPool ) +{ + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + const Sequence< Reference< beans::XPropertySet > > aElementList( AxisHelper::getAllGrids( xDiagram ) ); + for( Reference< beans::XPropertySet > const & xObjectProperties : aElementList ) + { + m_aConverters.emplace_back( new ::chart::wrapper::GraphicPropertyItemConverter( + xObjectProperties, rItemPool, rDrawModel, xNamedPropertyContainerFactory, + ::chart::wrapper::GraphicObjectType::LineProperties ) ); + } +} + +AllGridItemConverter::~AllGridItemConverter() +{ +} + +const WhichRangesContainer& AllGridItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nGridWhichPairs; +} + +AllDataLabelItemConverter::AllDataLabelItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) + : MultipleItemConverter( rItemPool ) +{ + std::vector< rtl::Reference< DataSeries > > aSeriesList = + ::chart::ChartModelHelper::getDataSeries( xChartModel ); + + for (auto const& series : aSeriesList) + { + uno::Reference< uno::XComponentContext> xContext;//do not need Context for label properties + + sal_Int32 nNumberFormat=ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( series ); + sal_Int32 nPercentNumberFormat=ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + series,xChartModel); + + m_aConverters.emplace_back( + new ::chart::wrapper::DataPointItemConverter( + xChartModel, xContext, series, series, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, GraphicObjectType::FilledDataPoint, + nullptr, true, false, 0, true, nNumberFormat, nPercentNumberFormat)); + } +} + +AllDataLabelItemConverter::~AllDataLabelItemConverter() +{ +} + +const WhichRangesContainer& AllDataLabelItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nDataLabelWhichPairs; +} + +AllTitleItemConverter::AllTitleItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) + : MultipleItemConverter( rItemPool ) +{ + for(sal_Int32 nTitle = TitleHelper::TITLE_BEGIN; nTitle < TitleHelper::NORMAL_TITLE_END; nTitle++ ) + { + uno::Reference< chart2::XTitle > xTitle( TitleHelper::getTitle( TitleHelper::eTitleType(nTitle), xChartModel ) ); + if(!xTitle.is()) + continue; + uno::Reference< beans::XPropertySet > xObjectProperties( xTitle, uno::UNO_QUERY); + m_aConverters.emplace_back( + new ::chart::wrapper::TitleItemConverter( + xObjectProperties, rItemPool, rDrawModel, xNamedPropertyContainerFactory, nullptr)); + } +} + +AllTitleItemConverter::~AllTitleItemConverter() +{ +} + +const WhichRangesContainer& AllTitleItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nTitleWhichPairs; +} + +AllSeriesStatisticsConverter::AllSeriesStatisticsConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool ) + : MultipleItemConverter( rItemPool ) +{ + std::vector< rtl::Reference< DataSeries > > aSeriesList = + ::chart::ChartModelHelper::getDataSeries( xChartModel ); + + for (auto const& series : aSeriesList) + { + m_aConverters.emplace_back( new ::chart::wrapper::StatisticsItemConverter( + xChartModel, series, rItemPool )); + } +} + +AllSeriesStatisticsConverter::~AllSeriesStatisticsConverter() +{} + +const WhichRangesContainer& AllSeriesStatisticsConverter::GetWhichPairs() const +{ + // must span all used items! + return nStatWhichPairs; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/MultipleItemConverter.cxx b/chart2/source/controller/itemsetwrapper/MultipleItemConverter.cxx new file mode 100644 index 000000000..5937575cc --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/MultipleItemConverter.cxx @@ -0,0 +1,72 @@ +/* -*- 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 <MultipleItemConverter.hxx> + +#include <memory> + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +MultipleItemConverter::MultipleItemConverter( SfxItemPool& rItemPool ) + : ItemConverter( nullptr, rItemPool ) +{ +} +MultipleItemConverter::~MultipleItemConverter() +{ +} + +void MultipleItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + auto aIter = m_aConverters.begin(); + auto aEnd = m_aConverters.end(); + if( aIter != aEnd ) + { + (*aIter)->FillItemSet( rOutItemSet ); + ++aIter; + } + for( ; aIter != aEnd; ++aIter ) + { + SfxItemSet aSet = CreateEmptyItemSet(); + (*aIter)->FillItemSet( aSet ); + InvalidateUnequalItems( rOutItemSet, aSet ); + } + // no own items +} + +bool MultipleItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // no own items + return bResult; +} + +bool MultipleItemConverter::GetItemProperty( tWhichIdType /*nWhichId*/, tPropertyNameWithMemberId & /*rOutProperty*/ ) const +{ + return false; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx b/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx new file mode 100644 index 000000000..5683b468c --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.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 <RegressionCurveHelper.hxx> +#include <RegressionCurveModel.hxx> +#include <RegressionCurveItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <GraphicPropertyItemConverter.hxx> +#include <DataSeries.hxx> + +#include <com/sun/star/chart2/XRegressionCurve.hpp> +#include <osl/diagnose.h> + +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> + +using namespace ::com::sun::star; + +namespace +{ +template <class T, class D> +bool lclConvertToPropertySet(const SfxItemSet& rItemSet, sal_uInt16 nWhichId, const uno::Reference<beans::XPropertySet>& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + T aValue = static_cast<T>(static_cast<const D&>(rItemSet.Get( nWhichId )).GetValue()); + T aOldValue = aValue; + bool aSuccess = xProperties->getPropertyValue( aPropertyID ) >>= aOldValue; + if (!aSuccess || aOldValue != aValue) + { + xProperties->setPropertyValue( aPropertyID , uno::Any( aValue )); + return true; + } + } + return false; +} + +template <class T, class D> +void lclConvertToItemSet(SfxItemSet& rItemSet, sal_uInt16 nWhichId, const uno::Reference<beans::XPropertySet>& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + T aValue = static_cast<T>(static_cast<const D&>(rItemSet.Get( nWhichId )).GetValue()); + if(xProperties->getPropertyValue( aPropertyID ) >>= aValue) + { + rItemSet.Put(D( nWhichId, aValue )); + } + } +} + +void lclConvertToItemSetDouble(SfxItemSet& rItemSet, TypedWhichId<SvxDoubleItem> nWhichId, const uno::Reference<beans::XPropertySet>& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + double aValue = rItemSet.Get( nWhichId ).GetValue(); + if(xProperties->getPropertyValue( aPropertyID ) >>= aValue) + { + rItemSet.Put(SvxDoubleItem( aValue, nWhichId )); + } + } +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +RegressionCurveItemConverter::RegressionCurveItemConverter( + const uno::Reference< beans::XPropertySet >& rPropertySet, + const rtl::Reference< DataSeries >& xContainer, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) : + ItemConverter( rPropertySet, rItemPool ), + m_spGraphicConverter( std::make_shared<GraphicPropertyItemConverter>( + rPropertySet, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, + GraphicObjectType::LineProperties )), + m_xCurveContainer( xContainer ) +{} + +RegressionCurveItemConverter::~RegressionCurveItemConverter() +{} + +void RegressionCurveItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + m_spGraphicConverter->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool RegressionCurveItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = m_spGraphicConverter->ApplyItemSet( rItemSet ); + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& RegressionCurveItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nRegressionCurveWhichPairs; +} + +bool RegressionCurveItemConverter::GetItemProperty( + tWhichIdType /* nWhichId */, tPropertyNameWithMemberId & /* rOutProperty */ ) const +{ + // No own (non-special) properties + return false; +} + +bool RegressionCurveItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + uno::Reference< chart2::XRegressionCurve > xCurve( GetPropertySet(), uno::UNO_QUERY ); + bool bChanged = false; + + OSL_ASSERT(xCurve.is()); + if(!xCurve.is()) + return false; + + switch( nWhichId ) + { + case SCHATTR_REGRESSION_TYPE: + { + SvxChartRegress eRegress = RegressionCurveHelper::getRegressionType(xCurve); + SvxChartRegress eNewRegress = static_cast< const SvxChartRegressItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( eRegress != eNewRegress ) + { + // note that changing the regression type changes the object + // for which this converter was created. Not optimal, but + // currently the only way to handle the type in the + // regression curve properties dialog + xCurve = RegressionCurveHelper::changeRegressionCurveType( + eNewRegress, + m_xCurveContainer, + xCurve); + uno::Reference<beans::XPropertySet> xProperties( xCurve, uno::UNO_QUERY ); + resetPropertySet( xProperties ); + bChanged = true; + } + } + break; + + case SCHATTR_REGRESSION_DEGREE: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet<sal_Int32, SfxInt32Item>(rItemSet, nWhichId, xProperties, "PolynomialDegree"); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet<sal_Int32, SfxInt32Item>(rItemSet, nWhichId, xProperties, "MovingAveragePeriod"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet<double, SvxDoubleItem>(rItemSet, nWhichId, xProperties, "ExtrapolateForward"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet<double, SvxDoubleItem>(rItemSet, nWhichId, xProperties, "ExtrapolateBackward"); + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet<bool, SfxBoolItem>(rItemSet, nWhichId, xProperties, "ForceIntercept"); + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet<double, SvxDoubleItem>(rItemSet, nWhichId, xProperties, "InterceptValue"); + } + break; + + case SCHATTR_REGRESSION_CURVE_NAME: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet<OUString, SfxStringItem>(rItemSet, nWhichId, xProperties, "CurveName"); + } + break; + + case SCHATTR_REGRESSION_MOVING_TYPE: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet<sal_Int32, SfxInt32Item>(rItemSet, nWhichId, xProperties, "MovingAverageType"); + } + break; + + case SCHATTR_REGRESSION_SHOW_EQUATION: + { + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + bChanged = lclConvertToPropertySet<bool, SfxBoolItem>(rItemSet, nWhichId, xEqProp, "ShowEquation"); + } + break; + + case SCHATTR_REGRESSION_XNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + bChanged = lclConvertToPropertySet<OUString, SfxStringItem>(rItemSet, nWhichId, xEqProp, "XName"); + } + break; + + case SCHATTR_REGRESSION_YNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + bChanged = lclConvertToPropertySet<OUString, SfxStringItem>(rItemSet, nWhichId, xEqProp, "YName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_COEFF: + { + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + bChanged = lclConvertToPropertySet<bool, SfxBoolItem>(rItemSet, nWhichId, xEqProp, "ShowCorrelationCoefficient"); + } + break; + + } + return bChanged; +} + +void RegressionCurveItemConverter::FillSpecialItem(sal_uInt16 nWhichId, SfxItemSet& rOutItemSet ) const +{ + uno::Reference<chart2::XRegressionCurve> xCurve(GetPropertySet(), uno::UNO_QUERY); + OSL_ASSERT(xCurve.is()); + if(!xCurve.is()) + return; + + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + + switch( nWhichId ) + { + case SCHATTR_REGRESSION_TYPE: + { + SvxChartRegress eRegress = RegressionCurveHelper::getRegressionType(xCurve); + rOutItemSet.Put( SvxChartRegressItem( eRegress, SCHATTR_REGRESSION_TYPE )); + } + break; + + case SCHATTR_REGRESSION_DEGREE: + { + lclConvertToItemSet<sal_Int32, SfxInt32Item>(rOutItemSet, nWhichId, xProperties, "PolynomialDegree"); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + lclConvertToItemSet<sal_Int32, SfxInt32Item>(rOutItemSet, nWhichId, xProperties, "MovingAveragePeriod"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD, xProperties, "ExtrapolateForward"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD, xProperties, "ExtrapolateBackward"); + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + lclConvertToItemSet<bool, SfxBoolItem>(rOutItemSet, nWhichId, xProperties, "ForceIntercept"); + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_INTERCEPT_VALUE, xProperties, "InterceptValue"); + } + break; + + case SCHATTR_REGRESSION_CURVE_NAME: + { + lclConvertToItemSet<OUString, SfxStringItem>(rOutItemSet, nWhichId, xProperties, "CurveName"); + } + break; + + case SCHATTR_REGRESSION_MOVING_TYPE: + { + lclConvertToItemSet<sal_Int32, SfxInt32Item>(rOutItemSet, nWhichId, xProperties, "MovingAverageType"); + } + break; + + case SCHATTR_REGRESSION_SHOW_EQUATION: + { + lclConvertToItemSet<bool, SfxBoolItem>(rOutItemSet, nWhichId, xCurve->getEquationProperties(), "ShowEquation"); + } + break; + + case SCHATTR_REGRESSION_XNAME: + { + lclConvertToItemSet<OUString, SfxStringItem>(rOutItemSet, nWhichId, xCurve->getEquationProperties(), "XName"); + } + break; + + case SCHATTR_REGRESSION_YNAME: + { + lclConvertToItemSet<OUString, SfxStringItem>(rOutItemSet, nWhichId, xCurve->getEquationProperties(), "YName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_COEFF: + { + lclConvertToItemSet<bool, SfxBoolItem>(rOutItemSet, nWhichId, xCurve->getEquationProperties(), "ShowCorrelationCoefficient"); + } + break; + } +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/RegressionEquationItemConverter.cxx b/chart2/source/controller/itemsetwrapper/RegressionEquationItemConverter.cxx new file mode 100644 index 000000000..22fc379b2 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/RegressionEquationItemConverter.cxx @@ -0,0 +1,149 @@ +/* -*- 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 <RegressionEquationItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <ItemPropertyMap.hxx> +#include <GraphicPropertyItemConverter.hxx> +#include <CharacterPropertyItemConverter.hxx> +#include <unonames.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <svl/intitem.hxx> + +#include <memory> + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetEquationPropertyMap() +{ + static ItemPropertyMapType aEquationPropertyMap; + + return aEquationPropertyMap; +}; + +} // anonymous namespace + +RegressionEquationItemConverter::RegressionEquationItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const awt::Size* pRefSize ) : + ItemConverter( rPropertySet, rItemPool ) +{ + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, + GraphicObjectType::LineAndFillProperties )); + + m_aConverters.emplace_back( + new CharacterPropertyItemConverter(rPropertySet, rItemPool, pRefSize, "ReferencePageSize")); +} + +RegressionEquationItemConverter::~RegressionEquationItemConverter() +{ +} + +void RegressionEquationItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool RegressionEquationItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ); + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& RegressionEquationItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nRegEquationWhichPairs; +} + +bool RegressionEquationItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetEquationPropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +bool RegressionEquationItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SID_ATTR_NUMBERFORMAT_VALUE: + { + uno::Any aValue( static_cast< sal_Int32 >( + static_cast< const SfxUInt32Item & >( + rItemSet.Get( nWhichId )).GetValue())); + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) != aValue) + { + GetPropertySet()->setPropertyValue(CHART_UNONAME_NUMFMT, aValue); + bChanged = true; + } + } + break; + } + + return bChanged; +} + +void RegressionEquationItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SID_ATTR_NUMBERFORMAT_VALUE: + { + sal_Int32 nFormatKey = 0; + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormatKey) + { + rOutItemSet.Put( SfxUInt32Item( nWhichId, nFormatKey )); + } + } + break; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx b/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx new file mode 100644 index 000000000..3c1387009 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx @@ -0,0 +1,174 @@ +/* -*- 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 <svl/whichranges.hxx> +#include <svx/svxids.hrc> +#include <svx/xdef.hxx> +#include <svx/svddef.hxx> +#include <editeng/eeitem.hxx> + +#include <chartview/ChartSfxItemIds.hxx> + +const WhichRangesContainer nTitleWhichPairs(svl::Items< + SCHATTR_TEXT_START, SCHATTR_TEXT_END, + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1018 - 1046 svx/xdef.hxx + SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST, // 1067 - 1078 svx/svddef.hxx + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nAxisWhichPairs(svl::Items< + SCHATTR_TEXT_START, SCHATTR_TEXT_END, + SCHATTR_AXIS_START, SCHATTR_AXIS_END, + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_VALUE, // 10585 - 10585 svx/svxids.hrc + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, // 11432 svx/svxids.hrc + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nAllAxisWhichPairs(svl::Items< + SCHATTR_TEXT_START, SCHATTR_TEXT_END, + SCHATTR_AXIS_LABEL_START, SCHATTR_AXIS_LABEL_END, + XATTR_LINE_FIRST, XATTR_LINE_LAST, + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nGridWhichPairs(svl::Items< + XATTR_LINE_FIRST, XATTR_LINE_LAST // 1000 - 1016 svx/xdef.hxx +>); + +const WhichRangesContainer nLegendWhichPairs(svl::Items< + SCHATTR_LEGEND_START, SCHATTR_LEGEND_END, // 3 - 3 sch/schattr.hxx + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1018 - 1046 svx/xdef.hxx + SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST, // 1067 - 1078 svx/svddef.hxx + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nDataLabelWhichPairs(svl::Items< + SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, + SCHATTR_TEXT_DEGREES,SCHATTR_TEXT_DEGREES, + EE_PARA_WRITINGDIR,EE_PARA_WRITINGDIR, + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, /* 10585 - 10585 svx/svxids.hrc */ + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE /* 11432 svx/svxids.hrc */ +>); + +const WhichRangesContainer nDataPointWhichPairs(svl::Items< + SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, /* 1 - 2 sch/schattr.hxx*/ + SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES, + SCHATTR_STYLE_START,SCHATTR_STYLE_END, /* 59 - 68 sch/schattr.hxx*/ + SCHATTR_SYMBOL_BRUSH,SCHATTR_SYMBOL_BRUSH, /* 94 sch/schattr.hxx*/ + SCHATTR_SYMBOL_SIZE,SCHATTR_SYMBOL_SIZE, /* 97 sch/schattr.hxx*/ + SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, + XATTR_LINE_FIRST, XATTR_LINE_LAST, /* 1000 - 1016 svx/xdef.hxx */ + XATTR_FILL_FIRST, XATTR_FILL_LAST, /* 1018 - 1046 svx/xdef.hxx */ + SDRATTR_3D_FIRST, SDRATTR_3D_LAST, /* 1244 - 1334 svx/svddef.hxx */ + EE_ITEMS_START, EE_ITEMS_END, /* 3994 - 4037 editeng/eeitem.hxx */ + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, /* 10585 - 10585 svx/svxids.hrc */ + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432 svx/svxids.hrc */ + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING +>); + +const WhichRangesContainer nTextLabelWhichPairs(svl::Items< + SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, + SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES, + SCHATTR_STYLE_SYMBOL, SCHATTR_STYLE_SYMBOL, + SCHATTR_SYMBOL_BRUSH, SCHATTR_SYMBOL_BRUSH, + SCHATTR_SYMBOL_SIZE, SCHATTR_SYMBOL_SIZE, + XATTR_LINESTYLE, XATTR_LINECOLOR, + XATTR_LINETRANSPARENCE, XATTR_LINETRANSPARENCE, + EE_ITEMS_START, EE_ITEMS_END, + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING +>); + +const WhichRangesContainer nSeriesOptionsWhichPairs(svl::Items< + SCHATTR_AXIS,SCHATTR_AXIS, /* 69 sch/schattr.hxx*/ + SCHATTR_BAR_OVERLAP,SCHATTR_BAR_CONNECT, /* 98 - 100 (incl. SCHATTR_GAPWIDTH) */ + SCHATTR_GROUP_BARS_PER_AXIS,SCHATTR_AXIS_FOR_ALL_SERIES +>); + +// nDataPointWhichPairs + nSeriesOptionsWhichPairs +const WhichRangesContainer nRowWhichPairs(svl::Items< + SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, /* 1 - 2 sch/schattr.hxx*/ + SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES, + SCHATTR_STYLE_START,SCHATTR_STYLE_END, /* 59 - 68 sch/schattr.hxx*/ + SCHATTR_AXIS,SCHATTR_AXIS, /* 69 sch/schattr.hxx*/ + SCHATTR_SYMBOL_BRUSH,SCHATTR_SYMBOL_BRUSH, /* 94 sch/schattr.hxx*/ + SCHATTR_SYMBOL_SIZE,SCHATTR_SYMBOL_SIZE, /* 97 sch/schattr.hxx*/ + SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, + SCHATTR_BAR_OVERLAP,SCHATTR_BAR_CONNECT, /* 98 - 100 (incl. SCHATTR_GAPWIDTH) */ + SCHATTR_GROUP_BARS_PER_AXIS,SCHATTR_AXIS_FOR_ALL_SERIES, + XATTR_LINE_FIRST, XATTR_LINE_LAST, /* 1000 - 1016 svx/xdef.hxx */ + XATTR_FILL_FIRST, XATTR_FILL_LAST, /* 1018 - 1046 svx/xdef.hxx */ + SDRATTR_3D_FIRST, SDRATTR_3D_LAST, /* 1244 - 1334 svx/svddef.hxx */ + EE_ITEMS_START, EE_ITEMS_END, /* 3994 - 4037 editeng/eeitem.hxx */ + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, /* 10585 - 10585 svx/svxids.hrc */ + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432 svx/svxids.hrc */ + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING +>); + +const WhichRangesContainer nStatWhichPairs(svl::Items< + SCHATTR_STAT_START, SCHATTR_STAT_END, // 45 - 52 sch/schattr.hxx + SCHATTR_REGRESSION_START, SCHATTR_REGRESSION_END // 108 - 109 +>); + +const WhichRangesContainer nErrorBarWhichPairs(svl::Items< + SCHATTR_STAT_START, SCHATTR_STAT_END, // 45 - 52 sch/schattr.hxx + XATTR_LINE_FIRST, XATTR_LINE_LAST // 1000 - 1016 svx/xdef.hxx +>); + +// for CharacterProperties + +const WhichRangesContainer nCharacterPropertyWhichPairs(svl::Items< + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nLinePropertyWhichPairs(svl::Items< + XATTR_LINE_FIRST, XATTR_LINE_LAST // 1000 - 1016 svx/xdef.hxx +>); + +const WhichRangesContainer nLineAndFillPropertyWhichPairs(svl::Items< + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1000 - 1016 svx/xdef.hxx + SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST // 1067 - 1078 svx/svddef.hxx +>); + +const WhichRangesContainer nRegressionCurveWhichPairs(svl::Items< + SCHATTR_REGRESSION_START, SCHATTR_REGRESSION_END, // 108 - 109 + XATTR_LINE_FIRST, XATTR_LINE_LAST // 1000 - 1016 svx/xdef.hxx +>); + +const WhichRangesContainer nRegEquationWhichPairs(svl::Items< + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1018 - 1046 svx/xdef.hxx + SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST, // 1067 - 1078 svx/svddef.hxx + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_VALUE, // 10585 - 10585 svx/svxids.hrc + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/SeriesOptionsItemConverter.cxx b/chart2/source/controller/itemsetwrapper/SeriesOptionsItemConverter.cxx new file mode 100644 index 000000000..2f84084a1 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/SeriesOptionsItemConverter.cxx @@ -0,0 +1,435 @@ +/* -*- 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 <SeriesOptionsItemConverter.hxx> +#include "SchWhichPairs.hxx" + +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ChartTypeHelper.hxx> +#include <DataSeriesHelper.hxx> +#include <ChartModel.hxx> +#include <BaseCoordinateSystem.hxx> + +#include <com/sun/star/chart2/XDataSeries.hpp> + +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/ilstitem.hxx> +#include <svx/sdangitm.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart::wrapper +{ + +SeriesOptionsItemConverter::SeriesOptionsItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel + , const uno::Reference< uno::XComponentContext > & xContext + , const uno::Reference< beans::XPropertySet >& xPropertySet + , SfxItemPool& rItemPool ) + : ItemConverter( xPropertySet, rItemPool ) + , m_xChartModel(xChartModel) + , m_xCC(xContext) + , m_bAttachToMainAxis(true) + , m_bSupportingOverlapAndGapWidthProperties(false) + , m_bSupportingBarConnectors(false) + , m_nBarOverlap(0) + , m_nGapWidth(100) + , m_bConnectBars(false) + , m_bSupportingAxisSideBySide(false) + , m_bGroupBarsPerAxis(true) + , m_bSupportingStartingAngle(false) + , m_nStartingAngle(90) + , m_bClockwise(false) + , m_nMissingValueTreatment(0) + , m_bSupportingPlottingOfHiddenCells(false) + , m_bIncludeHiddenCells(true) + , m_bHideLegendEntry(false) +{ + try + { + uno::Reference< XDataSeries > xDataSeries( xPropertySet, uno::UNO_QUERY ); + + m_bAttachToMainAxis = DiagramHelper::isSeriesAttachedToMainAxis( xDataSeries ); + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram(xChartModel) ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram , xDataSeries ) ); + + m_xCooSys = DataSeriesHelper::getCoordinateSystemOfSeries( xDataSeries, xDiagram ); + if( m_xCooSys.is() ) + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 1, 0, m_xCooSys ); + chart2::ScaleData aScale( xAxis->getScaleData() ); + m_bClockwise = (aScale.Orientation == chart2::AxisOrientation_REVERSE); + } + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + m_bSupportingOverlapAndGapWidthProperties = ChartTypeHelper::isSupportingOverlapAndGapWidthProperties( xChartType, nDimensionCount ); + + if( m_bSupportingOverlapAndGapWidthProperties ) + { + + sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + + uno::Sequence< sal_Int32 > aBarPositionSequence; + if( xChartType.is() ) + { + if( xChartType->getPropertyValue( "OverlapSequence" ) >>= aBarPositionSequence ) + { + if( nAxisIndex >= 0 && nAxisIndex < aBarPositionSequence.getLength() ) + m_nBarOverlap = aBarPositionSequence[nAxisIndex]; + } + if( xChartType->getPropertyValue( "GapwidthSequence" ) >>= aBarPositionSequence ) + { + if( nAxisIndex >= 0 && nAxisIndex < aBarPositionSequence.getLength() ) + m_nGapWidth = aBarPositionSequence[nAxisIndex]; + } + } + } + + m_bSupportingBarConnectors = ChartTypeHelper::isSupportingBarConnectors( xChartType, nDimensionCount ); + if( m_bSupportingBarConnectors && xDiagram.is() ) + { + xDiagram->getPropertyValue( "ConnectBars" ) >>= m_bConnectBars; + } + + m_bSupportingAxisSideBySide = ChartTypeHelper::isSupportingAxisSideBySide( xChartType, nDimensionCount ); + if( m_bSupportingAxisSideBySide && xDiagram.is() ) + { + xDiagram->getPropertyValue( "GroupBarsPerAxis" ) >>= m_bGroupBarsPerAxis; + } + + m_bSupportingStartingAngle = ChartTypeHelper::isSupportingStartingAngle( xChartType ); + if( m_bSupportingStartingAngle ) + { + xDiagram->getPropertyValue( "StartingAngle" ) >>= m_nStartingAngle; + } + + m_aSupportedMissingValueTreatments = ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ); + m_nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( + ChartModelHelper::findDiagram(m_xChartModel), xChartType ); + + uno::Reference< beans::XPropertySet > xProp( m_xChartModel->getDataProvider(), uno::UNO_QUERY ); + if( xProp.is() ) + { + try + { + //test whether the data provider offers this property + xProp->getPropertyValue( "IncludeHiddenCells" ); + //if not exception is thrown the property is offered + m_bSupportingPlottingOfHiddenCells = true; + xDiagram->getPropertyValue( "IncludeHiddenCells" ) >>= m_bIncludeHiddenCells; + } + catch( const beans::UnknownPropertyException& ) + { + } + } + + m_bHideLegendEntry = !xPropertySet->getPropertyValue("ShowLegendEntry").get<bool>(); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +SeriesOptionsItemConverter::~SeriesOptionsItemConverter() +{ +} + +const WhichRangesContainer& SeriesOptionsItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nSeriesOptionsWhichPairs; +} + +bool SeriesOptionsItemConverter::GetItemProperty( tWhichIdType /*nWhichId*/, tPropertyNameWithMemberId & /*rOutProperty*/ ) const +{ + return false; +} + +bool SeriesOptionsItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + switch( nWhichId ) + { + case SCHATTR_AXIS: + { + sal_Int32 nItemValue = static_cast< const SfxInt32Item & >( + rItemSet.Get( nWhichId )).GetValue(); + bool bAttachToMainAxis = nItemValue == CHART_AXIS_PRIMARY_Y; + if( bAttachToMainAxis != m_bAttachToMainAxis ) + { + //change model: + bChanged = DiagramHelper::attachSeriesToAxis( bAttachToMainAxis, uno::Reference< XDataSeries >::query( GetPropertySet() ) + , ChartModelHelper::findDiagram(m_xChartModel), m_xCC ); + + if( bChanged ) + m_bAttachToMainAxis = bAttachToMainAxis; + } + } + break; + + case SCHATTR_BAR_OVERLAP: + case SCHATTR_BAR_GAPWIDTH: + { + if( m_bSupportingOverlapAndGapWidthProperties ) + { + sal_Int32& rBarPosition = ( nWhichId == SCHATTR_BAR_OVERLAP ) ? m_nBarOverlap : m_nGapWidth; + rBarPosition = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue(); + + OUString aPropName("GapwidthSequence" ); + if( nWhichId == SCHATTR_BAR_OVERLAP ) + aPropName = "OverlapSequence"; + + uno::Reference< XDataSeries > xDataSeries( GetPropertySet(), uno::UNO_QUERY ); + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram(m_xChartModel) ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram , xDataSeries ) ); + if( xChartType.is() ) + { + sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + uno::Sequence< sal_Int32 > aBarPositionSequence; + if( xChartType->getPropertyValue( aPropName ) >>= aBarPositionSequence ) + { + bool bGroupBarsPerAxis = rItemSet.Get( SCHATTR_GROUP_BARS_PER_AXIS ).GetValue(); + if(!bGroupBarsPerAxis) + { + //set the same value for all axes + for( auto & pos : asNonConstRange(aBarPositionSequence) ) + pos = rBarPosition; + } + else if( nAxisIndex >= 0 && nAxisIndex < aBarPositionSequence.getLength() ) + aBarPositionSequence.getArray()[nAxisIndex] = rBarPosition; + + xChartType->setPropertyValue( aPropName, uno::Any(aBarPositionSequence) ); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_BAR_CONNECT: + { + m_bConnectBars = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( m_bSupportingBarConnectors ) + { + bool bOldConnectBars = false; + rtl::Reference< Diagram > xDiagramProperties( ChartModelHelper::findDiagram(m_xChartModel), uno::UNO_QUERY ); + if( xDiagramProperties.is() && + (xDiagramProperties->getPropertyValue( "ConnectBars" ) >>= bOldConnectBars) && + bOldConnectBars != m_bConnectBars ) + { + xDiagramProperties->setPropertyValue( "ConnectBars" , uno::Any(m_bConnectBars) ); + bChanged = true; + } + } + } + break; + + case SCHATTR_GROUP_BARS_PER_AXIS: + { + m_bGroupBarsPerAxis = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( m_bSupportingAxisSideBySide ) + { + bool bOldGroupBarsPerAxis = true; + rtl::Reference< Diagram > xDiagramProperties( ChartModelHelper::findDiagram(m_xChartModel), uno::UNO_QUERY ); + if( xDiagramProperties.is() && + (xDiagramProperties->getPropertyValue( "GroupBarsPerAxis" ) >>= bOldGroupBarsPerAxis) && + bOldGroupBarsPerAxis != m_bGroupBarsPerAxis ) + { + xDiagramProperties->setPropertyValue( "GroupBarsPerAxis" , uno::Any(m_bGroupBarsPerAxis) ); + bChanged = true; + } + } + } + break; + + case SCHATTR_STARTING_ANGLE: + { + if( m_bSupportingStartingAngle ) + { + m_nStartingAngle = static_cast< const SdrAngleItem & >( rItemSet.Get( nWhichId )).GetValue().get() / 100; + rtl::Reference< Diagram > xDiagramProperties( ChartModelHelper::findDiagram(m_xChartModel), uno::UNO_QUERY ); + if( xDiagramProperties.is() ) + { + xDiagramProperties->setPropertyValue( "StartingAngle" , uno::Any(m_nStartingAngle) ); + bChanged = true; + } + } + } + break; + + case SCHATTR_CLOCKWISE: + { + bool bClockwise = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( m_xCooSys.is() ) + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 1, 0, m_xCooSys ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + aScaleData.Orientation = bClockwise ? chart2::AxisOrientation_REVERSE : chart2::AxisOrientation_MATHEMATICAL; + xAxis->setScaleData( aScaleData ); + bChanged = true; + } + } + } + break; + + case SCHATTR_MISSING_VALUE_TREATMENT: + { + if( m_aSupportedMissingValueTreatments.hasElements() ) + { + sal_Int32 nNew = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue(); + if( m_nMissingValueTreatment != nNew ) + { + try + { + rtl::Reference< Diagram > xDiagramProperties( ChartModelHelper::findDiagram(m_xChartModel), uno::UNO_QUERY ); + if( xDiagramProperties.is() ) + { + xDiagramProperties->setPropertyValue( "MissingValueTreatment" , uno::Any( nNew )); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } + } + break; + case SCHATTR_INCLUDE_HIDDEN_CELLS: + { + if( m_bSupportingPlottingOfHiddenCells ) + { + bool bIncludeHiddenCells = static_cast<const SfxBoolItem &>(rItemSet.Get(nWhichId)).GetValue(); + if (bIncludeHiddenCells != m_bIncludeHiddenCells) + { + if (m_xChartModel) + bChanged = ChartModelHelper::setIncludeHiddenCells( bIncludeHiddenCells, *m_xChartModel ); + } + } + } + break; + case SCHATTR_HIDE_LEGEND_ENTRY: + { + bool bHideLegendEntry = static_cast<const SfxBoolItem &>(rItemSet.Get(nWhichId)).GetValue(); + if (bHideLegendEntry != m_bHideLegendEntry) + { + GetPropertySet()->setPropertyValue("ShowLegendEntry", css::uno::Any(!bHideLegendEntry)); + } + } + break; + } + return bChanged; +} + +void SeriesOptionsItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_AXIS: + { + sal_Int32 nItemValue = m_bAttachToMainAxis ? CHART_AXIS_PRIMARY_Y : CHART_AXIS_SECONDARY_Y; + rOutItemSet.Put( SfxInt32Item(nWhichId,nItemValue ) ); + break; + } + case SCHATTR_BAR_OVERLAP: + { + if( m_bSupportingOverlapAndGapWidthProperties ) + rOutItemSet.Put( SfxInt32Item(nWhichId,m_nBarOverlap) ); + break; + } + case SCHATTR_BAR_GAPWIDTH: + { + if( m_bSupportingOverlapAndGapWidthProperties ) + rOutItemSet.Put( SfxInt32Item(nWhichId,m_nGapWidth) ); + break; + } + case SCHATTR_BAR_CONNECT: + { + if( m_bSupportingBarConnectors ) + rOutItemSet.Put( SfxBoolItem(nWhichId,m_bConnectBars)); + break; + } + case SCHATTR_GROUP_BARS_PER_AXIS: + { + if( m_bSupportingAxisSideBySide ) + rOutItemSet.Put( SfxBoolItem(nWhichId,m_bGroupBarsPerAxis) ); + break; + } + case SCHATTR_AXIS_FOR_ALL_SERIES: + { + break; + } + case SCHATTR_STARTING_ANGLE: + { + if( m_bSupportingStartingAngle ) + rOutItemSet.Put( SdrAngleItem(SCHATTR_STARTING_ANGLE, Degree100(m_nStartingAngle*100)) ); + break; + } + case SCHATTR_CLOCKWISE: + { + rOutItemSet.Put( SfxBoolItem(nWhichId,m_bClockwise) ); + break; + } + case SCHATTR_MISSING_VALUE_TREATMENT: + { + if( m_aSupportedMissingValueTreatments.hasElements() ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_nMissingValueTreatment )); + break; + } + case SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS: + { + rOutItemSet.Put( SfxIntegerListItem( nWhichId, m_aSupportedMissingValueTreatments ) ); + break; + } + case SCHATTR_INCLUDE_HIDDEN_CELLS: + { + if( m_bSupportingPlottingOfHiddenCells ) + rOutItemSet.Put( SfxBoolItem(nWhichId, m_bIncludeHiddenCells) ); + break; + } + case SCHATTR_HIDE_LEGEND_ENTRY: + { + rOutItemSet.Put(SfxBoolItem(nWhichId, m_bHideLegendEntry)); + break; + } + default: + break; + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx b/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx new file mode 100644 index 000000000..5e230a434 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx @@ -0,0 +1,858 @@ +/* -*- 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 <StatisticsItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <RegressionCurveHelper.hxx> +#include <RegressionCurveModel.hxx> +#include <ErrorBar.hxx> +#include <StatisticsHelper.hxx> +#include <ChartModel.hxx> +#include <unonames.hxx> + +#include <svl/stritem.hxx> +#include <svx/chrtitem.hxx> +#include <svl/intitem.hxx> +#include <rtl/math.hxx> + +#include <com/sun/star/chart2/XInternalDataProvider.hpp> +#include <com/sun/star/chart2/XRegressionCurveContainer.hpp> +#include <com/sun/star/chart/ErrorBarStyle.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; + +namespace +{ + +uno::Reference< beans::XPropertySet > lcl_GetErrorBar( + const uno::Reference< beans::XPropertySet > & xProp, bool bYError ) +{ + uno::Reference< beans::XPropertySet > xResult; + + if( xProp.is()) + try + { + ( xProp->getPropertyValue( bYError ? OUString(CHART_UNONAME_ERRORBAR_Y) : OUString(CHART_UNONAME_ERRORBAR_X) ) >>= xResult ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +uno::Reference< beans::XPropertySet > lcl_GetDefaultErrorBar() +{ + return uno::Reference< beans::XPropertySet >( new ::chart::ErrorBar ); +} + +void lcl_getErrorValues( const uno::Reference< beans::XPropertySet > & xErrorBarProp, + double & rOutPosError, double & rOutNegError ) +{ + if( ! xErrorBarProp.is()) + return; + + try + { + xErrorBarProp->getPropertyValue( "PositiveError" ) >>= rOutPosError; + xErrorBarProp->getPropertyValue( "NegativeError" ) >>= rOutNegError; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void lcl_getErrorIndicatorValues( + const uno::Reference< beans::XPropertySet > & xErrorBarProp, + bool & rOutShowPosError, bool & rOutShowNegError ) +{ + if( ! xErrorBarProp.is()) + return; + + try + { + xErrorBarProp->getPropertyValue( "ShowPositiveError" ) >>= rOutShowPosError; + xErrorBarProp->getPropertyValue( "ShowNegativeError" ) >>= rOutShowNegError; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +uno::Reference< beans::XPropertySet > lcl_getEquationProperties( + const uno::Reference< beans::XPropertySet > & xSeriesPropSet, const SfxItemSet * pItemSet ) +{ + bool bEquationExists = true; + + // ensure that a trendline is on + if( pItemSet ) + { + if( const SvxChartRegressItem* pRegressionItem = pItemSet->GetItemIfSet( SCHATTR_REGRESSION_TYPE ) ) + { + SvxChartRegress eRegress = pRegressionItem->GetValue(); + bEquationExists = ( eRegress != SvxChartRegress::NONE ); + } + } + + if( bEquationExists ) + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropSet, uno::UNO_QUERY ); + rtl::Reference< ::chart::RegressionCurveModel > xCurve = + ::chart::RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCnt ); + if( xCurve.is()) + { + return xCurve->getEquationProperties(); + } + } + + return uno::Reference< beans::XPropertySet >(); +} + +uno::Reference< beans::XPropertySet > lcl_getCurveProperties( + const uno::Reference< beans::XPropertySet > & xSeriesPropSet, const SfxItemSet * pItemSet ) +{ + bool bExists = true; + + // ensure that a trendline is on + if( pItemSet ) + { + if( const SvxChartRegressItem* pRegressionItem = pItemSet->GetItemIfSet( SCHATTR_REGRESSION_TYPE ) ) + { + SvxChartRegress eRegress = pRegressionItem->GetValue(); + bExists = ( eRegress != SvxChartRegress::NONE ); + } + } + + if( bExists ) + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropSet, uno::UNO_QUERY ); + uno::Reference< chart2::XRegressionCurve > xCurve( + ::chart::RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCnt )); + if( xCurve.is()) + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + return xProperties; + } + } + + return uno::Reference< beans::XPropertySet >(); +} + +template <class T, class D> +bool lclConvertToPropertySet(const SfxItemSet& rItemSet, sal_uInt16 nWhichId, const uno::Reference<beans::XPropertySet>& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + T aValue = static_cast<T>(static_cast<const D&>(rItemSet.Get( nWhichId )).GetValue()); + T aOldValue = aValue; + bool aSuccess = xProperties->getPropertyValue( aPropertyID ) >>= aOldValue; + if (!aSuccess || aOldValue != aValue) + { + xProperties->setPropertyValue( aPropertyID , uno::Any( aValue )); + return true; + } + } + return false; +} + +template <class T, class D> +void lclConvertToItemSet(SfxItemSet& rItemSet, sal_uInt16 nWhichId, const uno::Reference<beans::XPropertySet>& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + T aValue = static_cast<T>(static_cast<const D&>(rItemSet.Get( nWhichId )).GetValue()); + if(xProperties->getPropertyValue( aPropertyID ) >>= aValue) + { + rItemSet.Put(D( nWhichId, aValue )); + } + } +} + +void lclConvertToItemSetDouble(SfxItemSet& rItemSet, TypedWhichId<SvxDoubleItem> nWhichId, const uno::Reference<beans::XPropertySet>& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + double aValue = rItemSet.Get( nWhichId ).GetValue(); + if(xProperties->getPropertyValue( aPropertyID ) >>= aValue) + { + rItemSet.Put(SvxDoubleItem( aValue, nWhichId )); + } + } +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +StatisticsItemConverter::StatisticsItemConverter( + const rtl::Reference<::chart::ChartModel> & xModel, + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ) : + ItemConverter( rPropertySet, rItemPool ), + m_xModel( xModel ) +{ +} + +StatisticsItemConverter::~StatisticsItemConverter() +{ +} + +const WhichRangesContainer& StatisticsItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nStatWhichPairs; +} + +bool StatisticsItemConverter::GetItemProperty( + tWhichIdType /* nWhichId */, + tPropertyNameWithMemberId & /* rOutProperty */ ) const +{ + return false; +} + +bool StatisticsItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SCHATTR_STAT_AVERAGE: + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( + GetPropertySet(), uno::UNO_QUERY ); + bool bOldHasMeanValueLine = RegressionCurveHelper::hasMeanValueLine( xRegCnt ); + + bool bNewHasMeanValueLine = + static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue(); + + if( bOldHasMeanValueLine != bNewHasMeanValueLine ) + { + if( ! bNewHasMeanValueLine ) + RegressionCurveHelper::removeMeanValueLine( xRegCnt ); + else + RegressionCurveHelper::addMeanValueLine( xRegCnt, GetPropertySet() ); + bChanged = true; + } + } + break; + + // Attention !!! This case must be passed before SCHATTR_STAT_PERCENT, + // SCHATTR_STAT_BIGERROR, SCHATTR_STAT_CONSTPLUS, + // SCHATTR_STAT_CONSTMINUS and SCHATTR_STAT_INDICATE + case SCHATTR_STAT_KIND_ERROR: + { + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(), bYError )); + + SvxChartKindError eErrorKind = + static_cast< const SvxChartKindErrorItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + if( !xErrorBarProp.is() && eErrorKind == SvxChartKindError::NONE) + { + //nothing to do + } + else + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + + switch( eErrorKind ) + { + case SvxChartKindError::NONE: + nStyle = css::chart::ErrorBarStyle::NONE; break; + case SvxChartKindError::Variant: + nStyle = css::chart::ErrorBarStyle::VARIANCE; break; + case SvxChartKindError::Sigma: + nStyle = css::chart::ErrorBarStyle::STANDARD_DEVIATION; break; + case SvxChartKindError::Percent: + nStyle = css::chart::ErrorBarStyle::RELATIVE; break; + case SvxChartKindError::BigError: + nStyle = css::chart::ErrorBarStyle::ERROR_MARGIN; break; + case SvxChartKindError::Const: + nStyle = css::chart::ErrorBarStyle::ABSOLUTE; break; + case SvxChartKindError::StdError: + nStyle = css::chart::ErrorBarStyle::STANDARD_ERROR; break; + case SvxChartKindError::Range: + nStyle = css::chart::ErrorBarStyle::FROM_DATA; break; + } + + if( !xErrorBarProp.is() ) + { + xErrorBarProp = lcl_GetDefaultErrorBar(); + GetPropertySet()->setPropertyValue( bYError ? OUString(CHART_UNONAME_ERRORBAR_Y) : OUString(CHART_UNONAME_ERRORBAR_X), + uno::Any( xErrorBarProp )); + } + + xErrorBarProp->setPropertyValue( "ErrorBarStyle" , uno::Any( nStyle )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_PERCENT: + case SCHATTR_STAT_BIGERROR: + { + OSL_FAIL( "Deprecated item" ); + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(), bYError)); + bool bOldHasErrorBar = xErrorBarProp.is(); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( bOldHasErrorBar && + ! ( ::rtl::math::approxEqual( fPos, fValue ) && + ::rtl::math::approxEqual( fNeg, fValue ))) + { + xErrorBarProp->setPropertyValue( "PositiveError" , uno::Any( fValue )); + xErrorBarProp->setPropertyValue( "NegativeError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_CONSTPLUS: + { + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(),bYError)); + bool bOldHasErrorBar = xErrorBarProp.is(); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( bOldHasErrorBar && + ! ::rtl::math::approxEqual( fPos, fValue )) + { + xErrorBarProp->setPropertyValue( "PositiveError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_CONSTMINUS: + { + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(),bYError)); + bool bOldHasErrorBar = xErrorBarProp.is(); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( bOldHasErrorBar && + ! ::rtl::math::approxEqual( fNeg, fValue )) + { + xErrorBarProp->setPropertyValue( "NegativeError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_REGRESSION_TYPE: + { + SvxChartRegress eRegress = + static_cast< const SvxChartRegressItem& >( + rItemSet.Get( nWhichId )).GetValue(); + + uno::Reference< chart2::XRegressionCurve > xCurve( GetPropertySet(), uno::UNO_QUERY ); + uno::Reference< chart2::XRegressionCurveContainer > xContainer( GetPropertySet(), uno::UNO_QUERY ); + + if( eRegress == SvxChartRegress::NONE ) + { + if ( xContainer.is() ) + { + xContainer->removeRegressionCurve( xCurve ); + bChanged = true; + } + } + else + { + if ( xCurve.is() ) + { + SvxChartRegress eOldRegress( + RegressionCurveHelper::getRegressionType(xCurve)); + + if( eOldRegress != eRegress ) + { + xCurve = RegressionCurveHelper::changeRegressionCurveType( + eRegress, + xContainer, + xCurve); + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + resetPropertySet( xProperties ); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_REGRESSION_DEGREE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<sal_Int32, SfxInt32Item>(rItemSet, nWhichId, xProperties, "PolynomialDegree"); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<sal_Int32, SfxInt32Item>(rItemSet, nWhichId, xProperties, "MovingAveragePeriod"); + } + break; + + case SCHATTR_REGRESSION_MOVING_TYPE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<sal_Int32, SfxInt32Item>(rItemSet, nWhichId, xProperties, "MovingAverageType"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<double, SvxDoubleItem>(rItemSet, nWhichId, xProperties, "ExtrapolateForward"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<double, SvxDoubleItem>(rItemSet, nWhichId, xProperties, "ExtrapolateBackward"); + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<bool, SfxBoolItem>(rItemSet, nWhichId, xProperties, "ForceIntercept"); + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<double, SvxDoubleItem>(rItemSet, nWhichId, xProperties, "InterceptValue"); + } + break; + + case SCHATTR_REGRESSION_CURVE_NAME: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<OUString, SfxStringItem>(rItemSet, nWhichId, xProperties, "CurveName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_EQUATION: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<bool, SfxBoolItem>(rItemSet, nWhichId, xEqProp, "ShowEquation"); + } + break; + + case SCHATTR_REGRESSION_XNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<OUString, SfxStringItem>(rItemSet, nWhichId, xEqProp, "XName"); + } + break; + + case SCHATTR_REGRESSION_YNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<OUString, SfxStringItem>(rItemSet, nWhichId, xEqProp, "YName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_COEFF: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet<bool, SfxBoolItem>(rItemSet, nWhichId, xEqProp, "ShowCorrelationCoefficient"); + } + break; + + case SCHATTR_STAT_INDICATE: + { + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(),bYError)); + bool bOldHasErrorBar = xErrorBarProp.is(); + + SvxChartIndicate eIndicate = + static_cast< const SvxChartIndicateItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + bool bNewIndPos = (eIndicate == SvxChartIndicate::Both || eIndicate == SvxChartIndicate::Up ); + bool bNewIndNeg = (eIndicate == SvxChartIndicate::Both || eIndicate == SvxChartIndicate::Down ); + + bool bShowPos(false), bShowNeg(false); + lcl_getErrorIndicatorValues( xErrorBarProp, bShowPos, bShowNeg ); + + if( bOldHasErrorBar && + ( bShowPos != bNewIndPos || + bShowNeg != bNewIndNeg )) + { + xErrorBarProp->setPropertyValue( "ShowPositiveError" , uno::Any( bNewIndPos )); + xErrorBarProp->setPropertyValue( "ShowNegativeError" , uno::Any( bNewIndNeg )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_RANGE_POS: + case SCHATTR_STAT_RANGE_NEG: + { + const bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< chart2::data::XDataSource > xErrorBarSource( lcl_GetErrorBar( GetPropertySet(), bYError), + uno::UNO_QUERY ); + uno::Reference< chart2::data::XDataProvider > xDataProvider; + + if( m_xModel.is()) + xDataProvider.set( m_xModel->getDataProvider()); + if( xErrorBarSource.is() && xDataProvider.is()) + { + OUString aNewRange( static_cast< const SfxStringItem & >( rItemSet.Get( nWhichId )).GetValue()); + bool bApplyNewRange = false; + + bool bIsPositiveValue( nWhichId == SCHATTR_STAT_RANGE_POS ); + if( m_xModel->hasInternalDataProvider()) + { + if( !aNewRange.isEmpty()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, bIsPositiveValue, bYError )); + if( ! xSeq.is()) + { + // no data range for error bars yet => create + uno::Reference< chart2::XInternalDataProvider > xIntDataProvider( xDataProvider, uno::UNO_QUERY ); + OSL_ASSERT( xIntDataProvider.is()); + if( xIntDataProvider.is()) + { + xIntDataProvider->appendSequence(); + aNewRange = "last"; + bApplyNewRange = true; + } + } + } + } + else + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, bIsPositiveValue, bYError )); + bApplyNewRange = + ! ( xSeq.is() && (aNewRange == xSeq->getSourceRangeRepresentation())); + } + + if( bApplyNewRange ) + StatisticsHelper::setErrorDataSequence( + xErrorBarSource, xDataProvider, aNewRange, bIsPositiveValue, bYError ); + } + } + break; + } + + return bChanged; +} + +void StatisticsItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_STAT_AVERAGE: + rOutItemSet.Put( + SfxBoolItem( nWhichId, + RegressionCurveHelper::hasMeanValueLine( + uno::Reference< chart2::XRegressionCurveContainer >( + GetPropertySet(), uno::UNO_QUERY )))); + break; + + case SCHATTR_STAT_KIND_ERROR: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + SvxChartKindError eErrorKind = SvxChartKindError::NONE; + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(), bYError)); + if( xErrorBarProp.is() ) + { + sal_Int32 nStyle = 0; + if( xErrorBarProp->getPropertyValue( "ErrorBarStyle" ) >>= nStyle ) + { + switch( nStyle ) + { + case css::chart::ErrorBarStyle::NONE: + break; + case css::chart::ErrorBarStyle::VARIANCE: + eErrorKind = SvxChartKindError::Variant; break; + case css::chart::ErrorBarStyle::STANDARD_DEVIATION: + eErrorKind = SvxChartKindError::Sigma; break; + case css::chart::ErrorBarStyle::ABSOLUTE: + eErrorKind = SvxChartKindError::Const; break; + case css::chart::ErrorBarStyle::RELATIVE: + eErrorKind = SvxChartKindError::Percent; break; + case css::chart::ErrorBarStyle::ERROR_MARGIN: + eErrorKind = SvxChartKindError::BigError; break; + case css::chart::ErrorBarStyle::STANDARD_ERROR: + eErrorKind = SvxChartKindError::StdError; break; + case css::chart::ErrorBarStyle::FROM_DATA: + eErrorKind = SvxChartKindError::Range; break; + } + } + } + rOutItemSet.Put( SvxChartKindErrorItem( eErrorKind, SCHATTR_STAT_KIND_ERROR )); + } + break; + + case SCHATTR_STAT_PERCENT: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + if( xErrorBarProp.is()) + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, SCHATTR_STAT_PERCENT )); + } + } + break; + + case SCHATTR_STAT_BIGERROR: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + if( xErrorBarProp.is()) + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, SCHATTR_STAT_BIGERROR )); + } + } + break; + + case SCHATTR_STAT_CONSTPLUS: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + if( xErrorBarProp.is()) + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( fPos, SCHATTR_STAT_CONSTPLUS )); + } + } + break; + + case SCHATTR_STAT_CONSTMINUS: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + if( xErrorBarProp.is()) + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( fNeg, SCHATTR_STAT_CONSTMINUS )); + } + } + break; + + case SCHATTR_REGRESSION_TYPE: + { + SvxChartRegress eRegress = + RegressionCurveHelper::getFirstRegressTypeNotMeanValueLine( + uno::Reference< chart2::XRegressionCurveContainer >( + GetPropertySet(), uno::UNO_QUERY ) ); + rOutItemSet.Put( SvxChartRegressItem( eRegress, SCHATTR_REGRESSION_TYPE )); + } + break; + + case SCHATTR_REGRESSION_DEGREE: + { + + uno::Reference<beans::XPropertySet> xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<sal_Int32, SfxInt32Item>(rOutItemSet, nWhichId, xProperties, "PolynomialDegree"); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<sal_Int32, SfxInt32Item>(rOutItemSet, nWhichId, xProperties, "MovingAveragePeriod"); + } + break; + + case SCHATTR_REGRESSION_MOVING_TYPE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<sal_Int32, SfxInt32Item>(rOutItemSet, nWhichId, xProperties, "MovingAverageType"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD, xProperties, "ExtrapolateForward"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD, xProperties, "ExtrapolateBackward"); + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<bool, SfxBoolItem>(rOutItemSet, nWhichId, xProperties, "ForceIntercept"); + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_INTERCEPT_VALUE, xProperties, "InterceptValue"); + } + break; + + case SCHATTR_REGRESSION_CURVE_NAME: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<OUString, SfxStringItem>(rOutItemSet, nWhichId, xProperties, "CurveName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_EQUATION: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<bool, SfxBoolItem>(rOutItemSet, nWhichId, xEqProp, "ShowEquation"); + } + break; + + case SCHATTR_REGRESSION_XNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<OUString, SfxStringItem>(rOutItemSet, nWhichId, xEqProp, "XName"); + } + break; + + case SCHATTR_REGRESSION_YNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<OUString, SfxStringItem>(rOutItemSet, nWhichId, xEqProp, "YName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_COEFF: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet<bool, SfxBoolItem>(rOutItemSet, nWhichId, xEqProp, "ShowCorrelationCoefficient"); + } + break; + + case SCHATTR_STAT_INDICATE: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + SvxChartIndicate eIndicate = SvxChartIndicate::Both; + if( xErrorBarProp.is()) + { + bool bShowPos(false), bShowNeg(false); + lcl_getErrorIndicatorValues( xErrorBarProp, bShowPos, bShowNeg ); + + if( bShowPos ) + { + if( bShowNeg ) + eIndicate = SvxChartIndicate::Both; + else + eIndicate = SvxChartIndicate::Up; + } + else + { + if( bShowNeg ) + eIndicate = SvxChartIndicate::Down; + else + eIndicate = SvxChartIndicate::NONE; + } + } + rOutItemSet.Put( SvxChartIndicateItem( eIndicate, SCHATTR_STAT_INDICATE )); + } + break; + + case SCHATTR_STAT_RANGE_POS: + case SCHATTR_STAT_RANGE_NEG: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< chart2::data::XDataSource > xErrorBarSource( lcl_GetErrorBar( GetPropertySet(),bYError), + uno::UNO_QUERY ); + if( xErrorBarSource.is()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, (nWhichId == SCHATTR_STAT_RANGE_POS), bYError )); + if( xSeq.is()) + rOutItemSet.Put( SfxStringItem( nWhichId, xSeq->getSourceRangeRepresentation())); + } + } + break; + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx b/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx new file mode 100644 index 000000000..644d8d80c --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx @@ -0,0 +1,723 @@ +/* -*- 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 <TextLabelItemConverter.hxx> +#include <CharacterPropertyItemConverter.hxx> +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ItemPropertyMap.hxx> +#include "SchWhichPairs.hxx" +#include <unonames.hxx> + +#include <editeng/brushitem.hxx> +#include <editeng/sizeitem.hxx> +#include <svl/eitem.hxx> +#include <svl/ilstitem.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svx/tabline.hxx> +#include <svx/sdangitm.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/graph.hxx> +#include <rtl/math.hxx> + +#include <com/sun/star/chart/DataLabelPlacement.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <com/sun/star/chart2/Symbol.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <memory> + +using namespace com::sun::star; +using namespace com::sun::star::chart2; +using com::sun::star::uno::Reference; + +namespace chart::wrapper { + +namespace { + +const ItemPropertyMapType& getTextLabelPropertyMap() +{ + static ItemPropertyMapType aMap{ + {XATTR_LINESTYLE, {CHART_UNONAME_LABEL_BORDER_STYLE, 0}}, + {XATTR_LINEWIDTH, {CHART_UNONAME_LABEL_BORDER_WIDTH, 0}}, + {XATTR_LINEDASH, {CHART_UNONAME_LABEL_BORDER_DASH, 0}}, + {XATTR_LINECOLOR, {CHART_UNONAME_LABEL_BORDER_COLOR, 0}}, + {XATTR_LINETRANSPARENCE, {CHART_UNONAME_LABEL_BORDER_TRANS, 0}}}; + return aMap; +}; + +sal_Int32 getSymbolStyleForSymbol( const chart2::Symbol& rSymbol ) +{ + sal_Int32 nStyle = SVX_SYMBOLTYPE_UNKNOWN; + switch (rSymbol.Style) + { + case chart2::SymbolStyle_NONE: + nStyle = SVX_SYMBOLTYPE_NONE; + break; + case chart2::SymbolStyle_AUTO: + nStyle = SVX_SYMBOLTYPE_AUTO; + break; + case chart2::SymbolStyle_GRAPHIC: + nStyle = SVX_SYMBOLTYPE_BRUSHITEM; + break; + case chart2::SymbolStyle_STANDARD: + nStyle = rSymbol.StandardSymbol; + break; + case chart2::SymbolStyle_POLYGON: + default: + ; + } + return nStyle; +} + +bool numberFormatFromItemToPropertySet( + sal_uInt16 nWhichId, const SfxItemSet& rItemSet, const uno::Reference<beans::XPropertySet>& xPropertySet, + bool bOverwriteDataPoints ) +{ + bool bChanged = false; + if (!xPropertySet.is()) + return bChanged; + + OUString aPropertyName = (nWhichId == SID_ATTR_NUMBERFORMAT_VALUE) ? OUString(CHART_UNONAME_NUMFMT) : OUString("PercentageNumberFormat"); + sal_uInt16 nSourceWhich = (nWhichId == SID_ATTR_NUMBERFORMAT_VALUE) ? SID_ATTR_NUMBERFORMAT_SOURCE : SCHATTR_PERCENT_NUMBERFORMAT_SOURCE; + + if (rItemSet.GetItemState(nSourceWhich) != SfxItemState::SET) + return bChanged; + + uno::Any aValue; + bool bUseSourceFormat = static_cast<const SfxBoolItem&>(rItemSet.Get(nSourceWhich)).GetValue(); + if (!bUseSourceFormat) + { + SfxItemState aState = rItemSet.GetItemState(nWhichId); + if (aState == SfxItemState::SET) + { + sal_Int32 nFmt = static_cast<sal_Int32>( + static_cast<const SfxUInt32Item&>( + rItemSet.Get(nWhichId)).GetValue()); + aValue <<= nFmt; + } + else + return bChanged; + } + + uno::Any aOldValue = xPropertySet->getPropertyValue(aPropertyName); + if (bOverwriteDataPoints) + { + Reference<chart2::XDataSeries> xSeries(xPropertySet, uno::UNO_QUERY); + if (aValue != aOldValue || + ::chart::DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, aPropertyName, aOldValue)) + { + ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, aPropertyName, aValue); + bChanged = true; + } + } + else if (aOldValue != aValue) + { + xPropertySet->setPropertyValue(aPropertyName, aValue); + bChanged = true; + } + return bChanged; +} + +bool useSourceFormatFromItemToPropertySet( + sal_uInt16 nWhichId, const SfxItemSet& rItemSet, const uno::Reference<beans::XPropertySet>& xPropertySet, + bool bOverwriteDataPoints ) +{ + bool bChanged = false; + if (!xPropertySet.is()) + return bChanged; + OUString aPropertyName = (nWhichId == SID_ATTR_NUMBERFORMAT_SOURCE) ? OUString(CHART_UNONAME_NUMFMT) : OUString("PercentageNumberFormat"); + sal_uInt16 nFormatWhich = (nWhichId == SID_ATTR_NUMBERFORMAT_SOURCE) ? SID_ATTR_NUMBERFORMAT_VALUE : SCHATTR_PERCENT_NUMBERFORMAT_VALUE; + + if (rItemSet.GetItemState(nWhichId) != SfxItemState::SET) + return bChanged; + + uno::Any aNewValue; + bool bUseSourceFormat = static_cast<const SfxBoolItem&>( + rItemSet.Get(nWhichId)).GetValue(); + xPropertySet->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(bUseSourceFormat)); + if (!bUseSourceFormat) + { + SfxItemState aState = rItemSet.GetItemState(nFormatWhich); + if (aState == SfxItemState::SET) + { + sal_Int32 nFormatKey = static_cast<sal_Int32>( + static_cast<const SfxUInt32Item&>( + rItemSet.Get(nFormatWhich)).GetValue()); + aNewValue <<= nFormatKey; + } + else + return bChanged; + } + + uno::Any aOldValue(xPropertySet->getPropertyValue(aPropertyName)); + if (bOverwriteDataPoints) + { + Reference<chart2::XDataSeries> xSeries(xPropertySet, uno::UNO_QUERY); + if (aNewValue != aOldValue || + ::chart::DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, aPropertyName, aOldValue)) + { + ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, aPropertyName, aNewValue); + bChanged = true; + } + } + else if (aOldValue != aNewValue) + { + xPropertySet->setPropertyValue(aPropertyName, aNewValue); + bChanged = true; + } + + return bChanged; +} + +} // anonymous namespace + +TextLabelItemConverter::TextLabelItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const uno::Reference<beans::XPropertySet>& rPropertySet, + const rtl::Reference<DataSeries>& xSeries, + SfxItemPool& rItemPool, const awt::Size* pRefSize, + bool bDataSeries, sal_Int32 nNumberFormat, sal_Int32 nPercentNumberFormat ) : + ItemConverter(rPropertySet, rItemPool), + mnNumberFormat(nNumberFormat), + mnPercentNumberFormat(nPercentNumberFormat), + mbDataSeries(bDataSeries), + mbForbidPercentValue(true), + m_xSeries(xSeries) +{ + maConverters.emplace_back(new CharacterPropertyItemConverter(rPropertySet, rItemPool, pRefSize, "ReferencePageSize")); + + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xChartModel)); + rtl::Reference< ChartType > xChartType(DiagramHelper::getChartTypeOfSeries(xDiagram, xSeries)); + bool bFound = false; + bool bAmbiguous = false; + bool bSwapXAndY = DiagramHelper::getVertical(xDiagram, bFound, bAmbiguous); + maAvailableLabelPlacements = ChartTypeHelper::getSupportedLabelPlacements(xChartType, bSwapXAndY, xSeries); + + mbForbidPercentValue = ChartTypeHelper::getAxisType(xChartType, 0) != AxisType::CATEGORY; +} + +TextLabelItemConverter::~TextLabelItemConverter() +{ +} + +void TextLabelItemConverter::FillItemSet( SfxItemSet& rOutItemSet ) const +{ + for( const auto& pConv : maConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet(rOutItemSet); +} + +bool TextLabelItemConverter::ApplyItemSet( const SfxItemSet& rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv: maConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet(rItemSet) || bResult; +} + +const WhichRangesContainer& TextLabelItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nTextLabelWhichPairs; +} + +bool TextLabelItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId& rOutProperty ) const +{ + const ItemPropertyMapType& rMap = getTextLabelPropertyMap(); + ItemPropertyMapType::const_iterator it = rMap.find(nWhichId); + + if (it == rMap.end()) + return false; + + rOutProperty = it->second; + return true; +} + +bool TextLabelItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet& rItemSet ) +{ + bool bChanged = false; + + switch (nWhichId) + { + case SCHATTR_DATADESCR_SHOW_NUMBER: + case SCHATTR_DATADESCR_SHOW_PERCENTAGE: + case SCHATTR_DATADESCR_SHOW_CATEGORY: + case SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME: + case SCHATTR_DATADESCR_SHOW_SYMBOL: + { + const SfxBoolItem& rItem = static_cast<const SfxBoolItem&>(rItemSet.Get(nWhichId)); + + uno::Any aOldValue = GetPropertySet()->getPropertyValue(CHART_UNONAME_LABEL); + chart2::DataPointLabel aLabel; + if (aOldValue >>= aLabel) + { + sal_Bool& rValue = (nWhichId == SCHATTR_DATADESCR_SHOW_NUMBER) ? aLabel.ShowNumber : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_PERCENTAGE) ? aLabel.ShowNumberInPercent : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_CATEGORY) ? aLabel.ShowCategoryName : + (nWhichId == SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME) ? aLabel.ShowSeriesName : aLabel.ShowLegendSymbol)); + bool bOldValue = rValue; + rValue = rItem.GetValue(); + if (mbDataSeries) + { + Reference<chart2::XDataSeries> xSeries(GetPropertySet(), uno::UNO_QUERY); + if (bOldValue != bool(rValue) || + DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, CHART_UNONAME_LABEL, aOldValue)) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, CHART_UNONAME_LABEL, uno::Any(aLabel)); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any()); + bChanged = true; + } + } + else if (bOldValue != bool(rValue)) + { + GetPropertySet()->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabel)); + bChanged = true; + } + } + } + break; + case SID_ATTR_NUMBERFORMAT_VALUE: + case SCHATTR_PERCENT_NUMBERFORMAT_VALUE: //fall through intended + { + bChanged = numberFormatFromItemToPropertySet(nWhichId, rItemSet, GetPropertySet(), mbDataSeries); + } + break; + case SID_ATTR_NUMBERFORMAT_SOURCE: + case SCHATTR_PERCENT_NUMBERFORMAT_SOURCE: //fall through intended + { + bChanged = useSourceFormatFromItemToPropertySet(nWhichId, rItemSet, GetPropertySet(), mbDataSeries); + } + break; + case SCHATTR_DATADESCR_SEPARATOR: + { + OUString aNewValue = static_cast<const SfxStringItem&>(rItemSet.Get(nWhichId)).GetValue(); + try + { + OUString aOldValue; + GetPropertySet()->getPropertyValue("LabelSeparator") >>= aOldValue; + if (mbDataSeries) + { + Reference<chart2::XDataSeries> xSeries(GetPropertySet(), uno::UNO_QUERY); + if (aOldValue != aNewValue || + DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, "LabelSeparator", uno::Any(aOldValue))) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, "LabelSeparator", uno::Any(aNewValue)); + bChanged = true; + } + } + else if (aOldValue != aNewValue) + { + GetPropertySet()->setPropertyValue("LabelSeparator", uno::Any(aNewValue)); + bChanged = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + case SCHATTR_DATADESCR_WRAP_TEXT: + { + + try + { + bool bNew = static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue(); + bool bOld = false; + GetPropertySet()->getPropertyValue( "TextWordWrap" ) >>= bOld; + if( mbDataSeries ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( bOld!=bNew || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, "TextWordWrap", uno::Any( bOld ) ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "TextWordWrap", uno::Any( bNew ) ); + bChanged = true; + } + } + else if( bOld!=bNew ) + { + GetPropertySet()->setPropertyValue( "TextWordWrap", uno::Any( bNew )); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_DATADESCR_PLACEMENT: + { + try + { + sal_Int32 nNew = static_cast<const SfxInt32Item&>(rItemSet.Get(nWhichId)).GetValue(); + sal_Int32 nOld = -1; + RelativePosition aCustomLabelPosition; + GetPropertySet()->getPropertyValue("LabelPlacement") >>= nOld; + if (mbDataSeries) + { + Reference<chart2::XDataSeries> xSeries(GetPropertySet(), uno::UNO_QUERY); + if (nOld != nNew || + DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, "LabelPlacement", uno::Any(nOld))) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, "LabelPlacement", uno::Any(nNew)); + bChanged = true; + } + } + else if (nOld != nNew || (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition)) + { + GetPropertySet()->setPropertyValue("LabelPlacement", uno::Any(nNew)); + GetPropertySet()->setPropertyValue("CustomLabelPosition", uno::Any()); + bChanged = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_STYLE_SYMBOL: + { + sal_Int32 nStyle = + static_cast<const SfxInt32Item&>( + rItemSet.Get(nWhichId)).GetValue(); + chart2::Symbol aSymbol; + + GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol; + sal_Int32 nOldStyle = getSymbolStyleForSymbol(aSymbol); + + if (nStyle != nOldStyle) + { + bool bDeleteSymbol = false; + switch (nStyle) + { + case SVX_SYMBOLTYPE_NONE: + aSymbol.Style = chart2::SymbolStyle_NONE; + break; + case SVX_SYMBOLTYPE_AUTO: + aSymbol.Style = chart2::SymbolStyle_AUTO; + break; + case SVX_SYMBOLTYPE_BRUSHITEM: + aSymbol.Style = chart2::SymbolStyle_GRAPHIC; + break; + case SVX_SYMBOLTYPE_UNKNOWN: + bDeleteSymbol = true; + break; + + default: + aSymbol.Style = chart2::SymbolStyle_STANDARD; + aSymbol.StandardSymbol = nStyle; + } + + if (bDeleteSymbol) + GetPropertySet()->setPropertyValue("Symbol", uno::Any()); + else + GetPropertySet()->setPropertyValue("Symbol", uno::Any(aSymbol)); + bChanged = true; + } + } + break; + case SCHATTR_SYMBOL_SIZE: + { + Size aSize = static_cast<const SvxSizeItem&>( + rItemSet.Get(nWhichId)).GetSize(); + chart2::Symbol aSymbol; + + GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol; + if (aSize.getWidth() != aSymbol.Size.Width || + aSize.getHeight() != aSymbol.Size.Height) + { + aSymbol.Size.Width = aSize.getWidth(); + aSymbol.Size.Height = aSize.getHeight(); + + GetPropertySet()->setPropertyValue("Symbol", uno::Any(aSymbol)); + bChanged = true; + } + } + break; + case SCHATTR_SYMBOL_BRUSH: + { + const SvxBrushItem& rBrshItem(static_cast<const SvxBrushItem&>( + rItemSet.Get(nWhichId))); + uno::Any aXGraphicAny; + const Graphic* pGraphic(rBrshItem.GetGraphic()); + if (pGraphic) + { + uno::Reference<graphic::XGraphic> xGraphic(pGraphic->GetXGraphic()); + if (xGraphic.is()) + { + aXGraphicAny <<= xGraphic; + chart2::Symbol aSymbol; + GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol; + if (aSymbol.Graphic != xGraphic) + { + aSymbol.Graphic = xGraphic; + GetPropertySet()->setPropertyValue("Symbol", uno::Any(aSymbol)); + bChanged = true; + } + } + } + } + break; + case SCHATTR_TEXT_DEGREES: + { + double fValue = static_cast<double>( + static_cast<const SdrAngleItem&>( + rItemSet.Get(nWhichId)).GetValue().get()) / 100.0; + double fOldValue = 0.0; + bool bPropExisted = + (GetPropertySet()->getPropertyValue("TextRotation") >>= fOldValue); + + if (!bPropExisted || fOldValue != fValue) + { + GetPropertySet()->setPropertyValue("TextRotation", uno::Any(fValue)); + bChanged = true; + } + } + break; + case SCHATTR_DATADESCR_CUSTOM_LEADER_LINES: + { + try + { + bool bNew = static_cast<const SfxBoolItem&>(rItemSet.Get(nWhichId)).GetValue(); + bool bOld = true; + if( (m_xSeries->getPropertyValue("ShowCustomLeaderLines") >>= bOld) && bOld != bNew ) + { + m_xSeries->setPropertyValue("ShowCustomLeaderLines", uno::Any(bNew)); + bChanged = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + } + + return bChanged; +} + +void TextLabelItemConverter::FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet& rOutItemSet ) const +{ + switch (nWhichId) + { + case SCHATTR_DATADESCR_SHOW_NUMBER: + case SCHATTR_DATADESCR_SHOW_PERCENTAGE: + case SCHATTR_DATADESCR_SHOW_CATEGORY: + case SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME: + case SCHATTR_DATADESCR_SHOW_SYMBOL: + { + chart2::DataPointLabel aLabel; + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel) + { + bool bValue = (nWhichId == SCHATTR_DATADESCR_SHOW_NUMBER) ? aLabel.ShowNumber : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_PERCENTAGE) ? aLabel.ShowNumberInPercent : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_CATEGORY) ? aLabel.ShowCategoryName : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME) ? aLabel.ShowSeriesName : aLabel.ShowLegendSymbol))); + + rOutItemSet.Put(SfxBoolItem(nWhichId, bValue)); + + if (mbDataSeries) + { + if (DataSeriesHelper::hasAttributedDataPointDifferentValue( + Reference<chart2::XDataSeries>(GetPropertySet(), uno::UNO_QUERY), CHART_UNONAME_LABEL, uno::Any(aLabel))) + { + rOutItemSet.InvalidateItem(nWhichId); + } + } + } + } + break; + case SID_ATTR_NUMBERFORMAT_VALUE: + { + sal_Int32 nKey = 0; + if (!(GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nKey)) + nKey = mnNumberFormat; + rOutItemSet.Put(SfxUInt32Item(nWhichId, nKey)); + } + break; + case SCHATTR_PERCENT_NUMBERFORMAT_VALUE: + { + sal_Int32 nKey = 0; + if (!(GetPropertySet()->getPropertyValue("PercentageNumberFormat") >>= nKey)) + nKey = mnPercentNumberFormat; + rOutItemSet.Put(SfxUInt32Item(nWhichId, nKey)); + } + break; + case SID_ATTR_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = false; + try + { + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bUseSourceFormat; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT).hasValue() && !bUseSourceFormat; + rOutItemSet.Put(SfxBoolItem(nWhichId, !bNumberFormatIsSet)); + } + break; + case SCHATTR_PERCENT_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = false; + try + { + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bUseSourceFormat; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue("PercentageNumberFormat").hasValue() && !bUseSourceFormat; + rOutItemSet.Put(SfxBoolItem(nWhichId, !bNumberFormatIsSet)); + } + break; + case SCHATTR_DATADESCR_SEPARATOR: + { + try + { + OUString aValue; + GetPropertySet()->getPropertyValue("LabelSeparator") >>= aValue; + rOutItemSet.Put(SfxStringItem(nWhichId, aValue)); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_DATADESCR_WRAP_TEXT: + { + try + { + bool bValue = false; + GetPropertySet()->getPropertyValue( "TextWordWrap" ) >>= bValue; + rOutItemSet.Put( SfxBoolItem( nWhichId, bValue )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_DATADESCR_PLACEMENT: + { + try + { + sal_Int32 nPlacement = 0; + RelativePosition aCustomLabelPosition; + if (!mbDataSeries && (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition)) + rOutItemSet.Put(SfxInt32Item(nWhichId, css::chart::DataLabelPlacement::CUSTOM)); + else if (GetPropertySet()->getPropertyValue("LabelPlacement") >>= nPlacement) + rOutItemSet.Put(SfxInt32Item(nWhichId, nPlacement)); + else if (maAvailableLabelPlacements.hasElements()) + rOutItemSet.Put(SfxInt32Item(nWhichId, maAvailableLabelPlacements[0])); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS: + { + rOutItemSet.Put(SfxIntegerListItem(nWhichId, maAvailableLabelPlacements)); + } + break; + case SCHATTR_DATADESCR_NO_PERCENTVALUE: + { + rOutItemSet.Put(SfxBoolItem(nWhichId, mbForbidPercentValue)); + } + break; + case SCHATTR_DATADESCR_CUSTOM_LEADER_LINES: + { + try + { + bool bValue = true; + if( m_xSeries->getPropertyValue( "ShowCustomLeaderLines" ) >>= bValue ) + rOutItemSet.Put(SfxBoolItem(nWhichId, bValue)); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + case SCHATTR_STYLE_SYMBOL: + { + chart2::Symbol aSymbol; + if (GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol) + rOutItemSet.Put(SfxInt32Item(nWhichId, getSymbolStyleForSymbol(aSymbol))); + } + break; + case SCHATTR_SYMBOL_SIZE: + { + chart2::Symbol aSymbol; + if (GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol) + rOutItemSet.Put( + SvxSizeItem(nWhichId, Size(aSymbol.Size.Width, aSymbol.Size.Height))); + } + break; + case SCHATTR_SYMBOL_BRUSH: + { + chart2::Symbol aSymbol; + if ((GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol) + && aSymbol.Graphic.is()) + { + rOutItemSet.Put( + SvxBrushItem(Graphic(aSymbol.Graphic), GPOS_MM, SCHATTR_SYMBOL_BRUSH)); + } + } + break; + case SCHATTR_TEXT_DEGREES: + { + double fValue = 0; + + if (GetPropertySet()->getPropertyValue("TextRotation") >>= fValue) + { + rOutItemSet.Put( + SdrAngleItem(SCHATTR_TEXT_DEGREES, Degree100(static_cast<sal_Int32>(rtl::math::round(fValue * 100.0))))); + } + } + break; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/TitleItemConverter.cxx b/chart2/source/controller/itemsetwrapper/TitleItemConverter.cxx new file mode 100644 index 000000000..7a3f57af5 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/TitleItemConverter.cxx @@ -0,0 +1,210 @@ +/* -*- 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 <TitleItemConverter.hxx> +#include "SchWhichPairs.hxx" +#include <ItemPropertyMap.hxx> +#include <GraphicPropertyItemConverter.hxx> +#include <CharacterPropertyItemConverter.hxx> +#include <MultipleItemConverter.hxx> +#include <svx/sdangitm.hxx> +#include <rtl/math.hxx> + +#include <com/sun/star/chart2/XTitle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <memory> + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetTitlePropertyMap() +{ + static ItemPropertyMapType aTitlePropertyMap{ + {SCHATTR_TEXT_STACKED, {"StackCharacters", 0}}}; + return aTitlePropertyMap; +}; + +class FormattedStringsConverter : public MultipleItemConverter +{ +public: + FormattedStringsConverter( + const uno::Sequence< uno::Reference< chart2::XFormattedString > > & aStrings, + SfxItemPool & rItemPool, + const awt::Size* pRefSize, + const uno::Reference< beans::XPropertySet > & xParentProp ); + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +} // anonymous namespace + +FormattedStringsConverter::FormattedStringsConverter( + const uno::Sequence< uno::Reference< chart2::XFormattedString > > & aStrings, + SfxItemPool & rItemPool, + const awt::Size* pRefSize, + const uno::Reference< beans::XPropertySet > & xParentProp ) : + MultipleItemConverter( rItemPool ) +{ + bool bHasRefSize = (pRefSize && xParentProp.is()); + for( uno::Reference< chart2::XFormattedString > const & formattedStr : aStrings ) + { + uno::Reference< beans::XPropertySet > xProp( formattedStr, uno::UNO_QUERY ); + if( xProp.is()) + { + if( bHasRefSize ) + m_aConverters.emplace_back( + new CharacterPropertyItemConverter( + xProp, rItemPool, pRefSize, "ReferencePageSize", xParentProp)); + else + m_aConverters.emplace_back( new CharacterPropertyItemConverter( xProp, rItemPool )); + } + } +} + +const WhichRangesContainer& FormattedStringsConverter::GetWhichPairs() const +{ + return nCharacterPropertyWhichPairs; +} + +TitleItemConverter::TitleItemConverter( + const uno::Reference<beans::XPropertySet> & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const awt::Size* pRefSize ) : + ItemConverter( rPropertySet, rItemPool ) +{ + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, + GraphicObjectType::LineAndFillProperties )); + + // CharacterProperties are not at the title but at its contained XFormattedString objects + // take the first formatted string in the sequence + uno::Reference< chart2::XTitle > xTitle( rPropertySet, uno::UNO_QUERY ); + if( xTitle.is()) + { + uno::Sequence< uno::Reference< chart2::XFormattedString > > aStringSeq( xTitle->getText()); + if( aStringSeq.hasElements() ) + { + m_aConverters.emplace_back( + new FormattedStringsConverter( aStringSeq, rItemPool, pRefSize, rPropertySet )); + } + } +} + +TitleItemConverter::~TitleItemConverter() +{ +} + +void TitleItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool TitleItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& TitleItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nTitleWhichPairs; +} + +bool TitleItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetTitlePropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +bool TitleItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SCHATTR_TEXT_DEGREES: + { + // convert int to double (divided by 100) + double fVal = static_cast< double >( + static_cast< const SdrAngleItem & >( + rItemSet.Get( nWhichId )).GetValue().get()) / 100.0; + double fOldVal = 0.0; + bool bPropExisted = + ( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fOldVal ); + + if( ! bPropExisted || fOldVal != fVal ) + { + GetPropertySet()->setPropertyValue( "TextRotation" , uno::Any( fVal )); + bChanged = true; + } + } + break; + } + + return bChanged; +} + +void TitleItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_TEXT_DEGREES: + { + // convert double to int (times 100) + double fVal = 0; + + if( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fVal ) + { + rOutItemSet.Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, Degree100(static_cast< sal_Int32 >( + ::rtl::math::round( fVal * 100.0 ) ) ))); + } + } + break; + } +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController.cxx b/chart2/source/controller/main/ChartController.cxx new file mode 100644 index 000000000..9174ef885 --- /dev/null +++ b/chart2/source/controller/main/ChartController.cxx @@ -0,0 +1,1688 @@ +/* -*- 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 <sal/config.h> + +#include <config_wasm_strip.h> +#include <ChartController.hxx> +#include <servicenames.hxx> +#include <ResId.hxx> +#include <dlg_DataSource.hxx> +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include "ControllerCommandDispatch.hxx" +#include <DataSeries.hxx> +#include <Diagram.hxx> +#include <strings.hrc> +#include <chartview/ExplicitValueProvider.hxx> +#include <ChartViewHelper.hxx> + +#include <ChartWindow.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <DrawViewWrapper.hxx> +#include <ObjectIdentifier.hxx> +#include <DiagramHelper.hxx> +#include <ControllerLockGuard.hxx> +#include "UndoGuard.hxx" +#include "ChartDropTargetHelper.hxx" + +#include <dlg_ChartType.hxx> +#if !ENABLE_WASM_STRIP_ACCESSIBILITY +#include <AccessibleChartView.hxx> +#endif +#include "DrawCommandDispatch.hxx" +#include "ShapeController.hxx" +#include "UndoActions.hxx" +#include <ViewElementListProvider.hxx> + +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/servicehelper.hxx> +#include <BaseCoordinateSystem.hxx> + +#include <com/sun/star/awt/XWindowPeer.hpp> +#include <com/sun/star/frame/XController2.hpp> +#include <com/sun/star/util/CloseVetoException.hpp> +#include <com/sun/star/util/XModeChangeBroadcaster.hpp> +#include <com/sun/star/frame/LayoutManagerEvents.hpp> +#include <com/sun/star/frame/XLayoutManagerEventBroadcaster.hpp> +#include <com/sun/star/ui/XSidebar.hpp> +#include <com/sun/star/chart2/XDataProviderAccess.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> + +#include <sal/log.hxx> +#include <tools/debug.hxx> +#include <svx/sidebar/SelectionChangeHandler.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <osl/mutex.hxx> +#include <comphelper/lok.hxx> + +#include <sfx2/sidebar/SidebarController.hxx> + +#include <com/sun/star/frame/XLayoutManager.hpp> + +// this is needed to properly destroy the unique_ptr to the AcceleratorExecute +// object in the DTOR +#include <svtools/acceleratorexecute.hxx> +#include <svx/ActionDescriptionProvider.hxx> +#include <tools/diagnose_ex.h> + +// enable the following define to let the controller listen to model changes and +// react on this by rebuilding the view +#define TEST_ENABLE_MODIFY_LISTENER + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +ChartController::ChartController(uno::Reference<uno::XComponentContext> const & xContext) : + m_aLifeTimeManager( nullptr ), + m_bSuspended( false ), + m_xCC(xContext), + m_aModel( nullptr, m_aModelMutex ), + m_eDragMode(SdrDragMode::Move), + m_aDoubleClickTimer("chart2 ChartController m_aDoubleClickTimer"), + m_bWaitingForDoubleClick(false), + m_bWaitingForMouseUp(false), + m_bFieldButtonDown(false), + m_bConnectingToView(false), + m_bDisposed(false), + m_aDispatchContainer( m_xCC ), + m_eDrawMode( CHARTDRAW_SELECT ), + mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler( + [this]() { return this->GetContextName(); }, + this, vcl::EnumContext::Context::Cell)) +{ + m_aDoubleClickTimer.SetInvokeHandler( LINK( this, ChartController, DoubleClickWaitingHdl ) ); +} + +ChartController::~ChartController() +{ + stopDoubleClickWaiting(); +} + +ChartController::TheModel::TheModel( const rtl::Reference<::chart::ChartModel> & xModel ) : + m_xModel( xModel ), + m_bOwnership( true ) +{ +} + +ChartController::TheModel::~TheModel() +{ +} + +void ChartController::TheModel::addListener( ChartController* pController ) +{ + if(m_xModel) + { + //if you need to be able to veto against the destruction of the model + // you must add as a close listener + + //otherwise you 'can' add as closelistener or 'must' add as dispose event listener + + m_xModel->addCloseListener( + static_cast<util::XCloseListener*>(pController) ); + } +} + +void ChartController::TheModel::removeListener( ChartController* pController ) +{ + if(m_xModel) + m_xModel->removeCloseListener( + static_cast<util::XCloseListener*>(pController) ); +} + +void ChartController::TheModel::tryTermination() +{ + if(!m_bOwnership) + return; + + try + { + if(m_xModel.is()) + { + try + { + //@todo ? are we allowed to use sal_True here if we have the explicit ownership? + //I think yes, because there might be other CloseListeners later in the list which might be interested still + //but make sure that we do not throw the CloseVetoException here ourselves + //so stop listening before trying to terminate or check the source of queryclosing event + m_xModel->close(true); + + m_bOwnership = false; + } + catch( const util::CloseVetoException& ) + { + //since we have indicated to give up the ownership with parameter true in close call + //the one who has thrown the CloseVetoException is the new owner + + SAL_WARN_IF( m_bOwnership, "chart2.main", "a well known owner has caught a CloseVetoException after calling close(true)"); + m_bOwnership = false; + return; + } + + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "chart2", "Termination of model failed" ); + } +} + +ChartController::TheModelRef::TheModelRef( TheModel* pTheModel, osl::Mutex& rMutex ) : + m_rModelMutex(rMutex) +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel = pTheModel; +} +ChartController::TheModelRef::TheModelRef( const TheModelRef& rTheModel, ::osl::Mutex& rMutex ) : + m_rModelMutex(rMutex) +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel = rTheModel.m_xTheModel; +} +ChartController::TheModelRef& ChartController::TheModelRef::operator=(TheModel* pTheModel) +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel = pTheModel; + return *this; +} +ChartController::TheModelRef& ChartController::TheModelRef::operator=(const TheModelRef& rTheModel) +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel = rTheModel.operator->(); + return *this; +} +ChartController::TheModelRef::~TheModelRef() +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel.clear(); +} +bool ChartController::TheModelRef::is() const +{ + return m_xTheModel.is(); +} + +namespace { + +rtl::Reference<ChartType> getChartType(const rtl::Reference<ChartModel>& xChartDoc) +{ + rtl::Reference<Diagram > xDiagram = xChartDoc->getFirstChartDiagram(); + if (!xDiagram.is()) + return nullptr; + + const std::vector< rtl::Reference< BaseCoordinateSystem > > & xCooSysSequence( xDiagram->getBaseCoordinateSystems()); + if (xCooSysSequence.empty()) + return nullptr; + + return xCooSysSequence[0]->getChartTypes2()[0]; +} + +} + +OUString ChartController::GetContextName() +{ + if (m_bDisposed) + return OUString(); + + uno::Any aAny = getSelection(); + if (!aAny.hasValue()) + return "Chart"; + + OUString aCID; + aAny >>= aCID; + + if (aCID.isEmpty()) + return "Chart"; + + ObjectType eObjectID = ObjectIdentifier::getObjectType(aCID); + switch (eObjectID) + { + case OBJECTTYPE_DATA_SERIES: + return "Series"; + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + return "ErrorBar"; + case OBJECTTYPE_AXIS: + return "Axis"; + case OBJECTTYPE_GRID: + return "Grid"; + case OBJECTTYPE_DIAGRAM: + { + rtl::Reference<ChartType> xChartType = getChartType(getChartModel()); + if (xChartType.is() && xChartType->getChartType() == "com.sun.star.chart2.PieChartType") + return "ChartElements"; + break; + } + case OBJECTTYPE_DATA_CURVE: + case OBJECTTYPE_DATA_AVERAGE_LINE: + return "Trendline"; + default: + break; + } + + return "Chart"; +} + +// private methods + +bool ChartController::impl_isDisposedOrSuspended() const +{ + if( m_aLifeTimeManager.impl_isDisposed() ) + return true; + + if( m_bSuspended ) + { + OSL_FAIL( "This Controller is suspended" ); + return true; + } + return false; +} + +// lang::XServiceInfo + +OUString SAL_CALL ChartController::getImplementationName() +{ + return CHART_CONTROLLER_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartController::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartController::getSupportedServiceNames() +{ + return { + CHART_CONTROLLER_SERVICE_NAME, + "com.sun.star.frame.Controller" + //// @todo : add additional services if you support any further + }; +} + +namespace { + +uno::Reference<ui::XSidebar> getSidebarFromModel(const uno::Reference<frame::XModel>& xModel) +{ + uno::Reference<container::XChild> xChild(xModel, uno::UNO_QUERY); + if (!xChild.is()) + return nullptr; + + uno::Reference<frame::XModel> xParent (xChild->getParent(), uno::UNO_QUERY); + if (!xParent.is()) + return nullptr; + + uno::Reference<frame::XController2> xController(xParent->getCurrentController(), uno::UNO_QUERY); + if (!xController.is()) + return nullptr; + + uno::Reference<ui::XSidebarProvider> xSidebarProvider = xController->getSidebar(); + if (!xSidebarProvider.is()) + return nullptr; + + return xSidebarProvider->getSidebar(); +} + +} + +// XController + +void SAL_CALL ChartController::attachFrame( + const uno::Reference<frame::XFrame>& xFrame ) +{ + SolarMutexGuard aGuard; + + if( impl_isDisposedOrSuspended() ) //@todo? allow attaching the frame while suspended? + return; //behave passive if already disposed or suspended + + if(m_xFrame.is()) //what happens, if we do have a Frame already?? + { + //@todo? throw exception? + OSL_FAIL( "there is already a frame attached to the controller" ); + return; + } + + //--attach frame + m_xFrame = xFrame; //the frameloader is responsible to call xFrame->setComponent + + // Only notify after setting the frame, otherwise notification will fail + mpSelectionChangeHandler->Connect(); + + uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getChartModel()); + if (xSidebar.is()) + { + auto pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get()); + assert(pSidebar); + sfx2::sidebar::SidebarController::registerSidebarForFrame(pSidebar, this); + pSidebar->updateModel(getChartModel()); + css::lang::EventObject aEvent; + mpSelectionChangeHandler->selectionChanged(aEvent); + } + + //add as disposelistener to the frame (due to persistent reference) ??...: + + //the frame is considered to be owner of this controller and will live longer than we do + //the frame or the disposer of the frame has the duty to call suspend and dispose on this object + //so we do not need to add as lang::XEventListener for DisposingEvents right? + + //@todo nothing right??? + + //create view @todo is this the correct place here?? + + vcl::Window* pParent = nullptr; + //get the window parent from the frame to use as parent for our new window + if(xFrame.is()) + { + uno::Reference<awt::XWindow> xContainerWindow = xFrame->getContainerWindow(); + if (xContainerWindow) + xContainerWindow->setVisible(true); + pParent = VCLUnoHelper::GetWindow( xContainerWindow ); + } + + { + // calls to VCL + SolarMutexGuard aSolarGuard; + auto pChartWindow = VclPtr<ChartWindow>::Create(this,pParent,pParent?pParent->GetStyle():0); + pChartWindow->SetBackground();//no Background + m_xViewWindow.set( pChartWindow->GetComponentInterface(), uno::UNO_QUERY ); + pChartWindow->Show(); + m_apDropTargetHelper.reset( + new ChartDropTargetHelper( pChartWindow->GetDropTarget(), getChartModel())); + + impl_createDrawViewController(); + } + + //create the menu + { + uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + try + { + uno::Reference< css::frame::XLayoutManager > xLayoutManager; + xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager; + if ( xLayoutManager.is() ) + { + xLayoutManager->lock(); + xLayoutManager->requestElement( "private:resource/menubar/menubar" ); + //@todo: createElement should become unnecessary, remove when #i79198# is fixed + xLayoutManager->createElement( "private:resource/toolbar/standardbar" ); + xLayoutManager->requestElement( "private:resource/toolbar/standardbar" ); + //@todo: createElement should become unnecessary, remove when #i79198# is fixed + xLayoutManager->createElement( "private:resource/toolbar/toolbar" ); + xLayoutManager->requestElement( "private:resource/toolbar/toolbar" ); + + // #i12587# support for shapes in chart + xLayoutManager->createElement( "private:resource/toolbar/drawbar" ); + xLayoutManager->requestElement( "private:resource/toolbar/drawbar" ); + + xLayoutManager->requestElement( "private:resource/statusbar/statusbar" ); + xLayoutManager->unlock(); + + // add as listener to get notified when + m_xLayoutManagerEventBroadcaster.set( xLayoutManager, uno::UNO_QUERY ); + if( m_xLayoutManagerEventBroadcaster.is()) + m_xLayoutManagerEventBroadcaster->addLayoutManagerEventListener( this ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } +} + +//XModeChangeListener +void SAL_CALL ChartController::modeChanged( const util::ModeChangeEvent& rEvent ) +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + //adjust controller to view status changes + + if( rEvent.NewMode == "dirty" ) + { + //the view has become dirty, we should repaint it if we have a window + if( pChartWindow ) + pChartWindow->ForceInvalidate(); + } + else if( rEvent.NewMode == "invalid" ) + { + //the view is about to become invalid so end all actions on it + impl_invalidateAccessible(); + if( m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() ) + this->EndTextEdit(); + if( m_pDrawViewWrapper ) + { + m_pDrawViewWrapper->UnmarkAll(); + m_pDrawViewWrapper->HideSdrPage(); + } + } + else + { + //the view was rebuild so we can start some actions on it again + if( !m_bConnectingToView ) + { + if(pChartWindow && m_aModel.is() ) + { + m_bConnectingToView = true; + + GetDrawModelWrapper(); + if(m_pDrawModelWrapper) + { + { + if( m_pDrawViewWrapper ) + m_pDrawViewWrapper->ReInit(); + } + + //reselect object + if( m_aSelection.hasSelection() ) + this->impl_selectObjectAndNotiy(); + else + ChartModelHelper::triggerRangeHighlighting( getChartModel() ); + + impl_initializeAccessible(); + + { + if( pChartWindow ) + pChartWindow->Invalidate(); + } + } + + m_bConnectingToView = false; + } + } + } +} + +sal_Bool SAL_CALL ChartController::attachModel( const uno::Reference< frame::XModel > & xModel ) +{ + impl_invalidateAccessible(); + + //is called to attach the controller to a new model. + //return true if attach was successfully, false otherwise (e.g. if you do not work with a model) + + SolarMutexResettableGuard aGuard; + if( impl_isDisposedOrSuspended() ) //@todo? allow attaching a new model while suspended? + return false; //behave passive if already disposed or suspended + aGuard.clear(); + + ::chart::ChartModel* pChartModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pChartModel); + + TheModelRef aNewModelRef( new TheModel(pChartModel), m_aModelMutex); + TheModelRef aOldModelRef(m_aModel,m_aModelMutex); + m_aModel = aNewModelRef; + + //--handle relations to the old model if any + if( aOldModelRef.is() ) + { + uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY ); + if( xViewBroadcaster.is() ) + xViewBroadcaster->removeModeChangeListener(this); + m_pDrawModelWrapper.reset(); + + aOldModelRef->removeListener( this ); + #ifdef TEST_ENABLE_MODIFY_LISTENER + if( aOldModelRef->getModel().is()) + aOldModelRef->getModel()->removeModifyListener( this ); +#endif + } + + //--handle relations to the new model + aNewModelRef->addListener( this ); + + aGuard.reset(); // lock for m_aDispatchContainer access + // set new model at dispatchers + m_aDispatchContainer.setModel( aNewModelRef->getModel()); + rtl::Reference<ControllerCommandDispatch> pDispatch = new ControllerCommandDispatch( m_xCC, this, &m_aDispatchContainer ); + pDispatch->initialize(); + + // the dispatch container will return "this" for all commands returned by + // impl_getAvailableCommands(). That means, for those commands dispatch() + // is called here at the ChartController. + m_aDispatchContainer.setChartDispatch( pDispatch, o3tl::sorted_vector(impl_getAvailableCommands()) ); + + rtl::Reference<DrawCommandDispatch> pDrawDispatch = new DrawCommandDispatch( m_xCC, this ); + pDrawDispatch->initialize(); + m_aDispatchContainer.setDrawCommandDispatch( pDrawDispatch.get() ); + + rtl::Reference<ShapeController> pShapeController = new ShapeController( m_xCC, this ); + pShapeController->initialize(); + m_aDispatchContainer.setShapeController( pShapeController.get() ); + aGuard.clear(); + +#ifdef TEST_ENABLE_MODIFY_LISTENER + if( aNewModelRef->getModel().is()) + aNewModelRef->getModel()->addModifyListener( this ); +#endif + + // #i119999# Do not do this per default to allow the user to deselect the chart OLE with a single press to ESC + // select chart area per default: + // select( uno::Any( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) ); + + rtl::Reference< ChartModel > xFact = getChartModel(); + if( xFact.is()) + { + m_xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME ); + GetDrawModelWrapper(); + uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY ); + if( xViewBroadcaster.is() ) + xViewBroadcaster->addModeChangeListener(this); + } + + //the frameloader is responsible to call xModel->connectController + { + SolarMutexGuard aGuard2; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + pChartWindow->Invalidate(); + } + + m_xUndoManager.set( getChartModel()->getUndoManager(), uno::UNO_SET_THROW ); + + return true; +} + +uno::Reference< frame::XFrame > SAL_CALL ChartController::getFrame() +{ + //provides access to owner frame of this controller + //return the frame containing this controller + + return m_xFrame; +} + +uno::Reference< frame::XModel > SAL_CALL ChartController::getModel() +{ + return getChartModel(); +} + +rtl::Reference<::chart::ChartModel> ChartController::getChartModel() +{ + //provides access to currently attached model + //returns the currently attached model + + //return nothing, if you do not have a model + TheModelRef aModelRef( m_aModel, m_aModelMutex); + if(aModelRef.is()) + return aModelRef->getModel(); + + return nullptr; +} + +rtl::Reference<::chart::Diagram> ChartController::getFirstDiagram() +{ + return ChartModelHelper::findDiagram( getChartModel() ); +} + +uno::Any SAL_CALL ChartController::getViewData() +{ + //provides access to current view status + //set of data that can be used to restore the current view status at later time + // by using XController::restoreViewData() + + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() ) + return uno::Any(); //behave passive if already disposed or suspended //@todo? or throw an exception?? + + //-- collect current view state + uno::Any aRet; + //// @todo integrate specialized implementation + + return aRet; +} + +void SAL_CALL ChartController::restoreViewData( + const uno::Any& /* Value */ ) +{ + //restores the view status using the data gotten from a previous call to XController::getViewData() + + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() ) + return; //behave passive if already disposed or suspended //@todo? or throw an exception?? + + //// @todo integrate specialized implementation +} + +sal_Bool SAL_CALL ChartController::suspend( sal_Bool bSuspend ) +{ + //is called to prepare the controller for closing the view + //bSuspend==true: force the controller to suspend his work + //bSuspend==false try to reactivate the controller + //returns true if request was accepted and of course successfully finished, false otherwise + + //we may show dialogs here to ask the user for saving changes ... @todo? + + SolarMutexGuard aGuard; + if( m_aLifeTimeManager.impl_isDisposed() ) + return false; //behave passive if already disposed, return false because request was not accepted //@todo? correct + + if(bool(bSuspend) == m_bSuspended) + { + OSL_FAIL( "new suspend mode equals old suspend mode" ); + return true; + } + + //change suspend mode + m_bSuspended = bSuspend; + return true; +} + +void ChartController::impl_createDrawViewController() +{ + SolarMutexGuard aGuard; + if(!m_pDrawViewWrapper) + { + if( m_pDrawModelWrapper ) + { + bool bLokCalcGlobalRTL = false; + if(comphelper::LibreOfficeKit::isActive() && AllSettings::GetLayoutRTL()) + { + rtl::Reference< ChartModel > xChartModel = getChartModel(); + if (xChartModel.is()) + { + uno::Reference<css::sheet::XSpreadsheetDocument> xSSDoc(xChartModel->getParent(), uno::UNO_QUERY); + if (xSSDoc.is()) + bLokCalcGlobalRTL = true; + } + } + + m_pDrawViewWrapper.reset( new DrawViewWrapper(m_pDrawModelWrapper->getSdrModel(),GetChartWindow()->GetOutDev()) ); + m_pDrawViewWrapper->SetNegativeX(bLokCalcGlobalRTL); + m_pDrawViewWrapper->attachParentReferenceDevice( getChartModel() ); + } + } +} + +void ChartController::impl_deleteDrawViewController() +{ + if( m_pDrawViewWrapper ) + { + SolarMutexGuard aGuard; + if( m_pDrawViewWrapper->IsTextEdit() ) + this->EndTextEdit(); + m_pDrawViewWrapper.reset(); + } +} + +// XComponent (base of XController) + +void SAL_CALL ChartController::dispose() +{ + m_bDisposed = true; + + mpSelectionChangeHandler->selectionChanged(css::lang::EventObject()); + mpSelectionChangeHandler->Disconnect(); + + if (getModel().is()) + { + uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getChartModel()); + if (sfx2::sidebar::SidebarController* pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get())) + { + sfx2::sidebar::SidebarController::unregisterSidebarForFrame(pSidebar, this); + } + } + + try + { + //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; + +// OSL_ENSURE( m_bSuspended, "dispose was called but controller is not suspended" ); + + this->stopDoubleClickWaiting(); + + //end range highlighting + if( m_aModel.is()) + { + uno::Reference< view::XSelectionChangeListener > xSelectionChangeListener; + rtl::Reference< ChartModel > xDataReceiver = getChartModel(); + if( xDataReceiver.is() ) + xSelectionChangeListener.set( xDataReceiver->getRangeHighlighter(), uno::UNO_QUERY ); + if( xSelectionChangeListener.is() ) + { + uno::Reference< frame::XController > xController( this ); + lang::EventObject aEvent( xController ); + xSelectionChangeListener->disposing( aEvent ); + } + } + + //--release all resources and references + { + uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY ); + if( xViewBroadcaster.is() ) + xViewBroadcaster->removeModeChangeListener(this); + + impl_invalidateAccessible(); + SolarMutexGuard aSolarGuard; + impl_deleteDrawViewController(); + m_pDrawModelWrapper.reset(); + + m_apDropTargetHelper.reset(); + + //the accessible view is disposed within window destructor of m_pChartWindow + if(m_xViewWindow.is()) + m_xViewWindow->dispose(); //ChartWindow is deleted via UNO due to dispose of m_xViewWindow (triggered by Framework (Controller pretends to be XWindow also)) + m_xChartView.clear(); + } + + // remove as listener to layout manager events + if( m_xLayoutManagerEventBroadcaster.is()) + { + m_xLayoutManagerEventBroadcaster->removeLayoutManagerEventListener( this ); + m_xLayoutManagerEventBroadcaster.set( nullptr ); + } + + m_xFrame.clear(); + m_xUndoManager.clear(); + + TheModelRef aModelRef( m_aModel, m_aModelMutex); + m_aModel = nullptr; + + if( aModelRef.is()) + { + uno::Reference< frame::XModel > xModel( aModelRef->getModel() ); + if(xModel.is()) + xModel->disconnectController( uno::Reference< frame::XController >( this )); + + aModelRef->removeListener( this ); +#ifdef TEST_ENABLE_MODIFY_LISTENER + try + { + if( aModelRef->getModel().is()) + aModelRef->getModel()->removeModifyListener( this ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +#endif + aModelRef->tryTermination(); + } + + //// @todo integrate specialized implementation + //e.g. release further resources and references + + SolarMutexGuard g; + m_aDispatchContainer.DisposeAndClear(); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + assert(!m_xChartView.is()); + } + } + +void SAL_CALL ChartController::addEventListener( + const uno::Reference<lang::XEventListener>& xListener ) +{ + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode? + return; //behave passive if already disposed or suspended + + //--add listener + m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(), xListener ); +} + +void SAL_CALL ChartController::removeEventListener( + const uno::Reference<lang::XEventListener>& xListener ) +{ + SolarMutexGuard aGuard; + if( m_aLifeTimeManager.impl_isDisposed(false) ) + return; //behave passive if already disposed or suspended + + //--remove listener + m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), xListener ); +} + +// util::XCloseListener +void SAL_CALL ChartController::queryClosing( + const lang::EventObject& rSource, + sal_Bool /*bGetsOwnership*/ ) +{ + //do not use the m_aControllerMutex here because this call is not allowed to block + + TheModelRef aModelRef( m_aModel, m_aModelMutex); + + if( !aModelRef.is() ) + return; + + if( uno::Reference<XInterface>(static_cast<cppu::OWeakObject*>(aModelRef->getModel().get())) != rSource.Source ) + { + OSL_FAIL( "queryClosing was called on a controller from an unknown source" ); + return; + } + + //@ todo prepare to closing model -> don't start any further hindering actions +} + +void SAL_CALL ChartController::notifyClosing( + const lang::EventObject& rSource ) +{ + //Listener should deregister himself and release all references to the closing object. + + TheModelRef aModelRef( m_aModel, m_aModelMutex); + if( !impl_releaseThisModel( rSource.Source ) ) + return; + + //--stop listening to the closing model + aModelRef->removeListener( this ); + + // #i79087# If the model using this controller is closed, the frame is + // expected to be closed as well + Reference< util::XCloseable > xFrameCloseable( m_xFrame, uno::UNO_QUERY ); + if( xFrameCloseable.is()) + { + try + { + xFrameCloseable->close( false /* DeliverOwnership */ ); + m_xFrame.clear(); + } + catch( const util::CloseVetoException & ) + { + // closing was vetoed + } + } +} + +bool ChartController::impl_releaseThisModel( + const uno::Reference< uno::XInterface > & xModel ) +{ + bool bReleaseModel = false; + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aModelMutex ); + if( m_aModel.is() && uno::Reference< uno::XInterface >(static_cast<cppu::OWeakObject*>(m_aModel->getModel().get())) == xModel ) + { + m_aModel = nullptr; + m_xUndoManager.clear(); + bReleaseModel = true; + } + } + if( bReleaseModel ) + { + SolarMutexGuard g; + m_aDispatchContainer.setModel( nullptr ); + } + return bReleaseModel; +} + +// util::XEventListener (base of XCloseListener) +void SAL_CALL ChartController::disposing( + const lang::EventObject& rSource ) +{ + if( !impl_releaseThisModel( rSource.Source )) + { + if( rSource.Source == m_xLayoutManagerEventBroadcaster ) + m_xLayoutManagerEventBroadcaster.set( nullptr ); + } +} + +void SAL_CALL ChartController::layoutEvent( + const lang::EventObject& aSource, + sal_Int16 eLayoutEvent, + const uno::Any& /* aInfo */ ) +{ + if( eLayoutEvent == frame::LayoutManagerEvents::MERGEDMENUBAR ) + { + Reference< frame::XLayoutManager > xLM( aSource.Source, uno::UNO_QUERY ); + if( xLM.is()) + { + xLM->createElement( "private:resource/statusbar/statusbar" ); + xLM->requestElement( "private:resource/statusbar/statusbar" ); + } + } +} + +// XDispatchProvider (required interface) + +namespace +{ + +bool lcl_isFormatObjectCommand( std::u16string_view aCommand ) +{ + return aCommand == u"MainTitle" + || aCommand == u"SubTitle" + || aCommand == u"XTitle" + || aCommand == u"YTitle" + || aCommand == u"ZTitle" + || aCommand == u"SecondaryXTitle" + || aCommand == u"SecondaryYTitle" + || aCommand == u"AllTitles" + || aCommand == u"DiagramAxisX" + || aCommand == u"DiagramAxisY" + || aCommand == u"DiagramAxisZ" + || aCommand == u"DiagramAxisA" + || aCommand == u"DiagramAxisB" + || aCommand == u"DiagramAxisAll" + || aCommand == u"DiagramGridXMain" + || aCommand == u"DiagramGridYMain" + || aCommand == u"DiagramGridZMain" + || aCommand == u"DiagramGridXHelp" + || aCommand == u"DiagramGridYHelp" + || aCommand == u"DiagramGridZHelp" + || aCommand == u"DiagramGridAll" + + || aCommand == u"DiagramWall" + || aCommand == u"DiagramFloor" + || aCommand == u"DiagramArea" + || aCommand == u"Legend" + + || aCommand == u"FormatWall" + || aCommand == u"FormatFloor" + || aCommand == u"FormatChartArea" + || aCommand == u"FormatLegend" + + || aCommand == u"FormatTitle" + || aCommand == u"FormatAxis" + || aCommand == u"FormatDataSeries" + || aCommand == u"FormatDataPoint" + || aCommand == u"FormatDataLabels" + || aCommand == u"FormatDataLabel" + || aCommand == u"FormatXErrorBars" + || aCommand == u"FormatYErrorBars" + || aCommand == u"FormatMeanValue" + || aCommand == u"FormatTrendline" + || aCommand == u"FormatTrendlineEquation" + || aCommand == u"FormatStockLoss" + || aCommand == u"FormatStockGain" + || aCommand == u"FormatMajorGrid" + || aCommand == u"FormatMinorGrid"; +} + +} // anonymous namespace + +uno::Reference<frame::XDispatch> SAL_CALL + ChartController::queryDispatch( + const util::URL& rURL, + const OUString& rTargetFrameName, + sal_Int32 /* nSearchFlags */) +{ + SolarMutexGuard aGuard; + + if ( !m_aLifeTimeManager.impl_isDisposed() && getModel().is() ) + { + if( !rTargetFrameName.isEmpty() && rTargetFrameName == "_self" ) + return m_aDispatchContainer.getDispatchForURL( rURL ); + } + return uno::Reference< frame::XDispatch > (); +} + +uno::Sequence<uno::Reference<frame::XDispatch > > + ChartController::queryDispatches( + const uno::Sequence<frame::DispatchDescriptor>& xDescripts ) +{ + SolarMutexGuard g; + + if ( !m_aLifeTimeManager.impl_isDisposed() ) + { + return m_aDispatchContainer.getDispatchesForURLs( xDescripts ); + } + return uno::Sequence<uno::Reference<frame::XDispatch > > (); +} + +// frame::XDispatch + +void SAL_CALL ChartController::dispatch( + const util::URL& rURL, + const uno::Sequence< beans::PropertyValue >& rArgs ) +{ + OUString aCommand = rURL.Path; + + if(aCommand == "LOKSetTextSelection") + { + if (rArgs.getLength() == 3) + { + sal_Int32 nType = -1; + rArgs[0].Value >>= nType; + sal_Int32 nX = 0; + rArgs[1].Value >>= nX; + sal_Int32 nY = 0; + rArgs[2].Value >>= nY; + executeDispatch_LOKSetTextSelection(nType, nX, nY); + } + } + else if (aCommand == "LOKTransform") + { + if (rArgs[0].Name == "Action") + { + OUString sAction; + if ((rArgs[0].Value >>= sAction) && sAction == "PieSegmentDragging") + { + if (rArgs[1].Name == "Offset") + { + sal_Int32 nOffset; + if (rArgs[1].Value >>= nOffset) + { + this->executeDispatch_LOKPieSegmentDragging(nOffset); + } + } + } + } + else + { + this->executeDispatch_PositionAndSize(&rArgs); + } + } + else if(aCommand == "FillColor") + { + if (rArgs.getLength() > 0) + { + sal_uInt32 nColor; + if (rArgs[0].Value >>= nColor) + this->executeDispatch_FillColor(nColor); + } + } + else if(aCommand == "XLineColor") + { + if (rArgs.getLength() > 0) + { + sal_Int32 nColor = -1; + rArgs[0].Value >>= nColor; + this->executeDispatch_LineColor(nColor); + } + } + else if(aCommand == "LineWidth") + { + if (rArgs.getLength() > 0) + { + sal_Int32 nWidth = -1; + rArgs[0].Value >>= nWidth; + this->executeDispatch_LineWidth(nWidth); + } + } + else if(aCommand.startsWith("FillGradient")) + { + this->executeDispatch_FillGradient(aCommand.copy(aCommand.indexOf('=') + 1)); + } + else if(aCommand == "Paste") + this->executeDispatch_Paste(); + else if(aCommand == "Copy" ) + this->executeDispatch_Copy(); + else if(aCommand == "Cut" ) + this->executeDispatch_Cut(); + else if(aCommand == "DataRanges" ) + this->executeDispatch_SourceData(); + else if(aCommand == "Update" ) //Update Chart + { + ChartViewHelper::setViewToDirtyState( getChartModel() ); + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + pChartWindow->Invalidate(); + } + else if(aCommand == "DiagramData" ) + this->executeDispatch_EditData(); + //insert objects + else if( aCommand == "InsertTitles" + || aCommand == "InsertMenuTitles") + this->executeDispatch_InsertTitles(); + else if( aCommand == "InsertMenuLegend" ) + this->executeDispatch_OpenLegendDialog(); + else if( aCommand == "InsertLegend" ) + this->executeDispatch_InsertLegend(); + else if( aCommand == "DeleteLegend" ) + this->executeDispatch_DeleteLegend(); + else if( aCommand == "InsertMenuDataLabels" ) + this->executeDispatch_InsertMenu_DataLabels(); + else if( aCommand == "InsertMenuAxes" + || aCommand == "InsertRemoveAxes" ) + this->executeDispatch_InsertAxes(); + else if( aCommand == "InsertMenuGrids" ) + this->executeDispatch_InsertGrid(); + else if( aCommand == "InsertMenuTrendlines" ) + this->executeDispatch_InsertMenu_Trendlines(); + else if( aCommand == "InsertMenuMeanValues" ) + this->executeDispatch_InsertMenu_MeanValues(); + else if( aCommand == "InsertMenuXErrorBars" ) + this->executeDispatch_InsertErrorBars(false); + else if( aCommand == "InsertMenuYErrorBars" ) + this->executeDispatch_InsertErrorBars(true); + else if( aCommand == "InsertSymbol" ) + this->executeDispatch_InsertSpecialCharacter(); + else if( aCommand == "InsertTrendline" ) + this->executeDispatch_InsertTrendline(); + else if( aCommand == "DeleteTrendline" ) + this->executeDispatch_DeleteTrendline(); + else if( aCommand == "InsertMeanValue" ) + this->executeDispatch_InsertMeanValue(); + else if( aCommand == "DeleteMeanValue" ) + this->executeDispatch_DeleteMeanValue(); + else if( aCommand == "InsertXErrorBars" ) + this->executeDispatch_InsertErrorBars(false); + else if( aCommand == "InsertYErrorBars" ) + this->executeDispatch_InsertErrorBars(true); + else if( aCommand == "DeleteXErrorBars" ) + this->executeDispatch_DeleteErrorBars(false); + else if( aCommand == "DeleteYErrorBars" ) + this->executeDispatch_DeleteErrorBars(true); + else if( aCommand == "InsertTrendlineEquation" ) + this->executeDispatch_InsertTrendlineEquation(); + else if( aCommand == "DeleteTrendlineEquation" ) + this->executeDispatch_DeleteTrendlineEquation(); + else if( aCommand == "InsertTrendlineEquationAndR2" ) + this->executeDispatch_InsertTrendlineEquation( true ); + else if( aCommand == "InsertR2Value" ) + this->executeDispatch_InsertR2Value(); + else if( aCommand == "DeleteR2Value") + this->executeDispatch_DeleteR2Value(); + else if( aCommand == "InsertDataLabels" ) + this->executeDispatch_InsertDataLabels(); + else if( aCommand == "InsertDataLabel" ) + this->executeDispatch_InsertDataLabel(); + else if( aCommand == "DeleteDataLabels") + this->executeDispatch_DeleteDataLabels(); + else if( aCommand == "DeleteDataLabel" ) + this->executeDispatch_DeleteDataLabel(); + else if( aCommand == "ResetAllDataPoints" ) + this->executeDispatch_ResetAllDataPoints(); + else if( aCommand == "ResetDataPoint" ) + this->executeDispatch_ResetDataPoint(); + else if( aCommand == "InsertAxis" ) + this->executeDispatch_InsertAxis(); + else if( aCommand == "InsertMajorGrid" ) + this->executeDispatch_InsertMajorGrid(); + else if( aCommand == "InsertMinorGrid" ) + this->executeDispatch_InsertMinorGrid(); + else if( aCommand == "InsertAxisTitle" ) + this->executeDispatch_InsertAxisTitle(); + else if( aCommand == "DeleteAxis" ) + this->executeDispatch_DeleteAxis(); + else if( aCommand == "DeleteMajorGrid") + this->executeDispatch_DeleteMajorGrid(); + else if( aCommand == "DeleteMinorGrid" ) + this->executeDispatch_DeleteMinorGrid(); + //format objects + else if( aCommand == "FormatSelection" ) + this->executeDispatch_ObjectProperties(); + else if( aCommand == "TransformDialog" ) + { + if ( isShapeContext() ) + { + this->impl_ShapeControllerDispatch( rURL, rArgs ); + } + else + { + this->executeDispatch_PositionAndSize(); + } + } + else if( lcl_isFormatObjectCommand(aCommand) ) + this->executeDispatch_FormatObject(rURL.Path); + //more format + else if( aCommand == "DiagramType" ) + this->executeDispatch_ChartType(); + else if( aCommand == "View3D" ) + this->executeDispatch_View3D(); + else if ( aCommand == "Forward" ) + { + if ( isShapeContext() ) + { + this->impl_ShapeControllerDispatch( rURL, rArgs ); + } + else + { + this->executeDispatch_MoveSeries( true ); + } + } + else if ( aCommand == "Backward" ) + { + if ( isShapeContext() ) + { + this->impl_ShapeControllerDispatch( rURL, rArgs ); + } + else + { + this->executeDispatch_MoveSeries( false ); + } + } + else if( aCommand == "NewArrangement") + this->executeDispatch_NewArrangement(); + else if( aCommand == "ToggleLegend" ) + this->executeDispatch_ToggleLegend(); + else if( aCommand == "ToggleGridHorizontal" ) + this->executeDispatch_ToggleGridHorizontal(); + else if( aCommand == "ToggleGridVertical" ) + this->executeDispatch_ToggleGridVertical(); + else if( aCommand == "ScaleText" ) + this->executeDispatch_ScaleText(); + else if( aCommand == "StatusBarVisible" ) + { + // workaround: this should not be necessary. + uno::Reference< beans::XPropertySet > xPropSet( m_xFrame, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + uno::Reference< css::frame::XLayoutManager > xLayoutManager; + xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager; + if ( xLayoutManager.is() ) + { + bool bIsVisible( xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" )); + if( bIsVisible ) + { + xLayoutManager->hideElement( "private:resource/statusbar/statusbar" ); + xLayoutManager->destroyElement( "private:resource/statusbar/statusbar" ); + } + else + { + xLayoutManager->createElement( "private:resource/statusbar/statusbar" ); + xLayoutManager->showElement( "private:resource/statusbar/statusbar" ); + } + // @todo: update menu state (checkmark next to "Statusbar"). + } + } + } +} + +void SAL_CALL ChartController::addStatusListener( + const uno::Reference<frame::XStatusListener >& /* xControl */, + const util::URL& /* aURL */ ) +{ + //@todo +} + +void SAL_CALL ChartController::removeStatusListener( + const uno::Reference<frame::XStatusListener >& /* xControl */, + const util::URL& /* aURL */ ) +{ + //@todo +} + +// XContextMenuInterception (optional interface) +void SAL_CALL ChartController::registerContextMenuInterceptor( + const uno::Reference< ui::XContextMenuInterceptor >& /* xInterceptor */) +{ + //@todo +} + +void SAL_CALL ChartController::releaseContextMenuInterceptor( + const uno::Reference< ui::XContextMenuInterceptor > & /* xInterceptor */) +{ + //@todo +} + +// ____ XEmbeddedClient ____ +// implementation see: ChartController_EditData.cxx + +void ChartController::executeDispatch_ChartType() +{ + UndoLiveUpdateGuard aUndoGuard( + SchResId( STR_ACTION_EDIT_CHARTTYPE ), m_xUndoManager ); + + SolarMutexGuard aSolarGuard; + //prepare and open dialog + ChartTypeDialog aDlg(GetChartFrame(), getChartModel()); + if (aDlg.run() == RET_OK) + { + impl_adaptDataSeriesAutoResize(); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_SourceData() +{ + //convert properties to ItemSet + rtl::Reference< ::chart::ChartModel > xChartDoc = getChartModel(); + OSL_ENSURE( xChartDoc.is(), "Invalid XChartDocument" ); + if( !xChartDoc.is() ) + return; + + // If there is a data table we should ask user if we really want to destroy it + // and switch to data ranges. + ChartModel& rModel = *xChartDoc; + if ( rModel.hasInternalDataProvider() ) + { + // Check if we will able to create data provider later + css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc( + rModel.getParent(), uno::UNO_QUERY); + if (!xCreatorDoc.is()) + return; + + SolarMutexGuard aSolarGuard; + + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetChartFrame(), + VclMessageType::Question, VclButtonsType::YesNo, SchResId(STR_DLG_REMOVE_DATA_TABLE))); + // If "No" then just return + if (xQueryBox->run() == RET_NO) + return; + + // Remove data table + rModel.removeDataProviders(); + + // Ask parent document to create new data provider + + uno::Reference< data::XDataProvider > xDataProvider = xCreatorDoc->createDataProvider(); + SAL_WARN_IF( !xDataProvider.is(), "chart2.main", "Data provider was not created" ); + if (xDataProvider.is()) + { + rModel.attachDataProvider(xDataProvider); + } + } + + UndoLiveUpdateGuard aUndoGuard( + SchResId(STR_ACTION_EDIT_DATA_RANGES), m_xUndoManager); + + SolarMutexGuard aSolarGuard; + ::chart::DataSourceDialog aDlg(GetChartFrame(), xChartDoc); + if (aDlg.run() == RET_OK) + { + impl_adaptDataSeriesAutoResize(); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_MoveSeries( bool bForward ) +{ + ControllerLockGuardUNO aCLGuard( getChartModel() ); + + //get selected series + OUString aObjectCID(m_aSelection.getSelectedCID()); + rtl::Reference< DataSeries > xGivenDataSeries = ObjectIdentifier::getDataSeriesForCID( //yyy todo also legend entries and labels? + aObjectCID, getChartModel() ); + + UndoGuardWithSelection aUndoGuard( + ActionDescriptionProvider::createDescription( + (bForward ? ActionDescriptionProvider::ActionType::MoveToTop : ActionDescriptionProvider::ActionType::MoveToBottom), + SchResId(STR_OBJECT_DATASERIES)), + m_xUndoManager ); + + bool bChanged = DiagramHelper::moveSeries( getFirstDiagram(), xGivenDataSeries, bForward ); + if( bChanged ) + { + m_aSelection.setSelection( ObjectIdentifier::getMovedSeriesCID( aObjectCID, bForward ) ); + aUndoGuard.commit(); + } +} + +// ____ XMultiServiceFactory ____ +uno::Reference< uno::XInterface > SAL_CALL + ChartController::createInstance( const OUString& aServiceSpecifier ) +{ + uno::Reference< uno::XInterface > xResult; + +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + if( aServiceSpecifier == CHART_ACCESSIBLE_TEXT_SERVICE_NAME ) + xResult.set( impl_createAccessibleTextContext()); +#else + (void)aServiceSpecifier; +#endif + + return xResult; +} + +uno::Reference< uno::XInterface > SAL_CALL + ChartController::createInstanceWithArguments( + const OUString& ServiceSpecifier, + const uno::Sequence< uno::Any >& /* Arguments */ ) +{ + // ignore Arguments + return createInstance( ServiceSpecifier ); +} + +uno::Sequence< OUString > SAL_CALL + ChartController::getAvailableServiceNames() +{ + uno::Sequence< OUString > aServiceNames { CHART_ACCESSIBLE_TEXT_SERVICE_NAME }; + return aServiceNames; +} + +// ____ XModifyListener ____ +void SAL_CALL ChartController::modified( + const lang::EventObject& /* aEvent */ ) +{ + // the source can also be a subobject of the ChartModel + // @todo: change the source in ChartModel to always be the model itself ? + //todo? update menu states ? +} + +void ChartController::NotifyUndoActionHdl( std::unique_ptr<SdrUndoAction> pUndoAction ) +{ + ENSURE_OR_RETURN_VOID( pUndoAction, "invalid Undo action" ); + + OUString aObjectCID = m_aSelection.getSelectedCID(); + if ( !aObjectCID.isEmpty() ) + return; + + try + { + rtl::Reference< ChartModel > xSuppUndo = getChartModel(); + const Reference< document::XUndoManager > xUndoManager( xSuppUndo->getUndoManager(), uno::UNO_SET_THROW ); + const Reference< document::XUndoAction > xAction( new impl::ShapeUndoElement( std::move(pUndoAction) ) ); + xUndoManager->addUndoAction( xAction ); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +DrawModelWrapper* ChartController::GetDrawModelWrapper() +{ + if( !m_pDrawModelWrapper ) + { + ExplicitValueProvider* pProvider = comphelper::getFromUnoTunnel<ExplicitValueProvider>( m_xChartView ); + if( pProvider ) + m_pDrawModelWrapper = pProvider->getDrawModelWrapper(); + if ( m_pDrawModelWrapper ) + { + m_pDrawModelWrapper->getSdrModel().SetNotifyUndoActionHdl( + std::bind(&ChartController::NotifyUndoActionHdl, this, std::placeholders::_1) ); + } + } + return m_pDrawModelWrapper.get(); +} + +DrawViewWrapper* ChartController::GetDrawViewWrapper() +{ + if ( !m_pDrawViewWrapper ) + { + impl_createDrawViewController(); + } + return m_pDrawViewWrapper.get(); +} + + +ChartWindow* ChartController::GetChartWindow() const +{ + // clients getting the naked VCL Window from UNO should always have the + // solar mutex (and keep it over the lifetime of this ptr), as VCL might + // might deinit otherwise + DBG_TESTSOLARMUTEX(); + if(!m_xViewWindow.is()) + return nullptr; + return dynamic_cast<ChartWindow*>(VCLUnoHelper::GetWindow(m_xViewWindow)); +} + +weld::Window* ChartController::GetChartFrame() +{ + // clients getting the naked VCL Window from UNO should always have the + // solar mutex (and keep it over the lifetime of this ptr), as VCL might + // might deinit otherwise + DBG_TESTSOLARMUTEX(); + return Application::GetFrameWeld(m_xViewWindow); +} + +bool ChartController::isAdditionalShapeSelected() const +{ + return m_aSelection.isAdditionalShapeSelected(); +} + +void ChartController::SetAndApplySelection(const Reference<drawing::XShape>& rxShape) +{ + if(rxShape.is()) + { + m_aSelection.setSelection(rxShape); + m_aSelection.applySelection(GetDrawViewWrapper()); + } +} + + + +uno::Reference< XAccessible > ChartController::CreateAccessible() +{ +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + uno::Reference< XAccessible > xResult = new AccessibleChartView( GetDrawViewWrapper() ); + impl_initializeAccessible( uno::Reference< lang::XInitialization >( xResult, uno::UNO_QUERY ) ); + return xResult; +#else + return uno::Reference< XAccessible >(); +#endif +} + +void ChartController::impl_invalidateAccessible() +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + { + Reference< lang::XInitialization > xInit( pChartWindow->GetAccessible(false), uno::UNO_QUERY ); + if(xInit.is()) + { + uno::Sequence< uno::Any > aArguments(3);//empty arguments -> invalid accessible + xInit->initialize(aArguments); + } + } +} +void ChartController::impl_initializeAccessible() +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + this->impl_initializeAccessible( Reference< lang::XInitialization >( pChartWindow->GetAccessible(false), uno::UNO_QUERY ) ); +} +void ChartController::impl_initializeAccessible( const uno::Reference< lang::XInitialization >& xInit ) +{ + if(!xInit.is()) + return; + + uno::Reference< XAccessible > xParent; + { + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + { + vcl::Window* pParentWin( pChartWindow->GetAccessibleParentWindow()); + if( pParentWin ) + xParent.set( pParentWin->GetAccessible()); + } + } + uno::Sequence< uno::Any > aArguments{ uno::Any(uno::Reference<view::XSelectionSupplier>(this)), + uno::Any(getModel()), + uno::Any(m_xChartView), + uno::Any(xParent), + uno::Any(m_xViewWindow) }; + + xInit->initialize(aArguments); +} + +const o3tl::sorted_vector< OUString >& ChartController::impl_getAvailableCommands() +{ + static const o3tl::sorted_vector< OUString > s_AvailableCommands { + // commands for container forward + "AddDirect", "NewDoc", "Open", + "Save", "SaveAs", "SendMail", + "EditDoc", "ExportDirectToPDF", "PrintDefault", + + // own commands + "Cut", "Copy", "Paste", + "DataRanges", "DiagramData", + // insert objects + "InsertMenuTitles", "InsertTitles", + "InsertMenuLegend", "InsertLegend", "DeleteLegend", + "InsertMenuDataLabels", + "InsertMenuAxes", "InsertRemoveAxes", "InsertMenuGrids", + "InsertSymbol", + "InsertTrendlineEquation", "InsertTrendlineEquationAndR2", + "InsertR2Value", "DeleteR2Value", + "InsertMenuTrendlines", "InsertTrendline", + "InsertMenuMeanValues", "InsertMeanValue", + "InsertMenuXErrorBars", "InsertXErrorBars", + "InsertMenuYErrorBars", "InsertYErrorBars", + "InsertDataLabels", "InsertDataLabel", + "DeleteTrendline", "DeleteMeanValue", "DeleteTrendlineEquation", + "DeleteXErrorBars", "DeleteYErrorBars", + "DeleteDataLabels", "DeleteDataLabel", + //format objects + "FormatSelection", "TransformDialog", + "DiagramType", "View3D", + "Forward", "Backward", + "MainTitle", "SubTitle", + "XTitle", "YTitle", "ZTitle", + "SecondaryXTitle", "SecondaryYTitle", + "AllTitles", "Legend", + "DiagramAxisX", "DiagramAxisY", "DiagramAxisZ", + "DiagramAxisA", "DiagramAxisB", "DiagramAxisAll", + "DiagramGridXMain", "DiagramGridYMain", "DiagramGridZMain", + "DiagramGridXHelp", "DiagramGridYHelp", "DiagramGridZHelp", + "DiagramGridAll", + "DiagramWall", "DiagramFloor", "DiagramArea", + + //context menu - format objects entries + "FormatWall", "FormatFloor", "FormatChartArea", + "FormatLegend", + + "FormatAxis", "FormatTitle", + "FormatDataSeries", "FormatDataPoint", + "ResetAllDataPoints", "ResetDataPoint", + "FormatDataLabels", "FormatDataLabel", + "FormatMeanValue", "FormatTrendline", "FormatTrendlineEquation", + "FormatXErrorBars", "FormatYErrorBars", + "FormatStockLoss", "FormatStockGain", + + "FormatMajorGrid", "InsertMajorGrid", "DeleteMajorGrid", + "FormatMinorGrid", "InsertMinorGrid", "DeleteMinorGrid", + "InsertAxis", "DeleteAxis", "InsertAxisTitle", + + // toolbar commands + "ToggleGridHorizontal", "ToggleGridVertical", "ToggleLegend", "ScaleText", + "NewArrangement", "Update", + "DefaultColors", "BarWidth", "NumberOfLines", + "ArrangeRow", + "StatusBarVisible", + "ChartElementSelector"}; + return s_AvailableCommands; +} + +ViewElementListProvider ChartController::getViewElementListProvider() +{ + return ViewElementListProvider(m_pDrawModelWrapper.get()); +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartController_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new chart::ChartController(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_EditData.cxx b/chart2/source/controller/main/ChartController_EditData.cxx new file mode 100644 index 000000000..c766c51cc --- /dev/null +++ b/chart2/source/controller/main/ChartController_EditData.cxx @@ -0,0 +1,54 @@ +/* -*- 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 <ChartController.hxx> +#include <ChartModel.hxx> + +#include <dlg_DataEditor.hxx> +#include "UndoGuard.hxx" +#include <ResId.hxx> +#include <strings.hrc> + +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +void ChartController::executeDispatch_EditData() +{ + rtl::Reference<::chart::ChartModel> xChartDoc( getChartModel(), uno::UNO_QUERY ); + if (xChartDoc.is()) + { + SolarMutexGuard aSolarGuard; + UndoLiveUpdateGuardWithData aUndoGuard( + SchResId( STR_ACTION_EDIT_CHART_DATA ), + m_xUndoManager ); + DataEditor aDataEditorDialog(GetChartFrame(), xChartDoc, m_xCC); + aDataEditorDialog.run(); + aUndoGuard.commit(); + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Insert.cxx b/chart2/source/controller/main/ChartController_Insert.cxx new file mode 100644 index 000000000..4f39f1068 --- /dev/null +++ b/chart2/source/controller/main/ChartController_Insert.cxx @@ -0,0 +1,869 @@ +/* -*- 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 <ChartController.hxx> + +#include <dlg_InsertAxis_Grid.hxx> +#include <dlg_InsertDataLabel.hxx> +#include <dlg_InsertLegend.hxx> +#include <dlg_InsertErrorBars.hxx> +#include <dlg_InsertTitle.hxx> +#include <dlg_ObjectProperties.hxx> + +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <TitleHelper.hxx> +#include <DataSeries.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <chartview/ChartSfxItemIds.hxx> +#include <NumberFormatterWrapper.hxx> +#include <ViewElementListProvider.hxx> +#include <MultipleChartConverters.hxx> +#include <ControllerLockGuard.hxx> +#include "UndoGuard.hxx" +#include <ResId.hxx> +#include <strings.hrc> +#include <ReferenceSizeProvider.hxx> +#include <ObjectIdentifier.hxx> +#include <RegressionCurveHelper.hxx> +#include <RegressionCurveItemConverter.hxx> +#include <StatisticsHelper.hxx> +#include <ErrorBarItemConverter.hxx> +#include <DataSeriesHelper.hxx> +#include <ObjectNameProvider.hxx> +#include <Legend.hxx> +#include <LegendHelper.hxx> +#include <RegressionCurveModel.hxx> + +#include <com/sun/star/chart2/XRegressionCurve.hpp> +#include <com/sun/star/chart/ErrorBarStyle.hpp> +#include <svx/ActionDescriptionProvider.hxx> + +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +void lcl_InsertMeanValueLine( const rtl::Reference< ::chart::DataSeries > & xSeries ) +{ + if( xSeries.is()) + { + ::chart::RegressionCurveHelper::addMeanValueLine( + xSeries, xSeries); + } +} + +} // anonymous namespace + +namespace chart +{ + +void ChartController::executeDispatch_InsertAxes() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AXES )), + m_xUndoManager ); + + try + { + InsertAxisOrGridDialogData aDialogInput; + rtl::Reference< Diagram > xDiagram = getFirstDiagram(); + AxisHelper::getAxisOrGridExistence( aDialogInput.aExistenceList, xDiagram ); + AxisHelper::getAxisOrGridPossibilities( aDialogInput.aPossibilityList, xDiagram ); + + SolarMutexGuard aGuard; + SchAxisDlg aDlg(GetChartFrame(), aDialogInput); + if (aDlg.run() == RET_OK) + { + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + + InsertAxisOrGridDialogData aDialogOutput; + aDlg.getResult(aDialogOutput); + std::unique_ptr< ReferenceSizeProvider > pRefSizeProvider( + impl_createReferenceSizeProvider()); + bool bChanged = AxisHelper::changeVisibilityOfAxes( xDiagram + , aDialogInput.aExistenceList, aDialogOutput.aExistenceList, m_xCC + , pRefSizeProvider.get() ); + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRIDS )), + m_xUndoManager ); + + try + { + InsertAxisOrGridDialogData aDialogInput; + rtl::Reference< Diagram > xDiagram = getFirstDiagram(); + AxisHelper::getAxisOrGridExistence( aDialogInput.aExistenceList, xDiagram, false ); + AxisHelper::getAxisOrGridPossibilities( aDialogInput.aPossibilityList, xDiagram, false ); + + SolarMutexGuard aGuard; + SchGridDlg aDlg(GetChartFrame(), aDialogInput);//aItemSet, b3D, bNet, bSecondaryX, bSecondaryY ); + if (aDlg.run() == RET_OK) + { + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + InsertAxisOrGridDialogData aDialogOutput; + aDlg.getResult( aDialogOutput ); + bool bChanged = AxisHelper::changeVisibilityOfGrids( xDiagram + , aDialogInput.aExistenceList, aDialogOutput.aExistenceList ); + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertTitles() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_TITLES )), + m_xUndoManager ); + + try + { + TitleDialogData aDialogInput; + aDialogInput.readFromModel( getChartModel() ); + + SolarMutexGuard aGuard; + SchTitleDlg aDlg(GetChartFrame(), aDialogInput); + if (aDlg.run() == RET_OK) + { + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + TitleDialogData aDialogOutput(impl_createReferenceSizeProvider()); + aDlg.getResult(aDialogOutput); + bool bChanged = aDialogOutput.writeDifferenceToModel( getChartModel(), m_xCC, &aDialogInput ); + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_DeleteLegend() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_LEGEND )), + m_xUndoManager ); + + LegendHelper::hideLegend(*getChartModel()); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_InsertLegend() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_LEGEND )), + m_xUndoManager ); + + LegendHelper::showLegend(*getChartModel(), m_xCC); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_OpenLegendDialog() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_LEGEND )), + m_xUndoManager ); + + try + { + //prepare and open dialog + SolarMutexGuard aGuard; + SchLegendDlg aDlg(GetChartFrame(), m_xCC); + aDlg.init( getChartModel() ); + if (aDlg.run() == RET_OK) + { + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + aDlg.writeToModel( getChartModel() ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertMenu_DataLabels() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_DATALABELS )), + m_xUndoManager ); + + //if a series is selected insert labels for that series only: + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel()); + if( xSeries.is() ) + { + // add labels + DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints( xSeries ); + + OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" ); + OUString aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticles( + ObjectIdentifier::getSeriesParticleFromCID(m_aSelection.getSelectedCID()), aChildParticle ); + + bool bSuccess = ChartController::executeDlg_ObjectProperties_withoutUndoGuard( aObjectCID, true ); + if( bSuccess ) + aUndoGuard.commit(); + return; + } + + try + { + wrapper::AllDataLabelItemConverter aItemConverter( + getChartModel(), + m_pDrawModelWrapper->GetItemPool(), + m_pDrawModelWrapper->getSdrModel(), + getChartModel() ); + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemConverter.FillItemSet( aItemSet ); + + //prepare and open dialog + SolarMutexGuard aGuard; + + //get number formatter + NumberFormatterWrapper aNumberFormatterWrapper( getChartModel() ); + SvNumberFormatter* pNumberFormatter = aNumberFormatterWrapper.getSvNumberFormatter(); + + DataLabelsDialog aDlg(GetChartFrame(), aItemSet, pNumberFormatter); + + if (aDlg.run() == RET_OK) + { + SfxItemSet aOutItemSet = aItemConverter.CreateEmptyItemSet(); + aDlg.FillItemSet(aOutItemSet); + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + bool bChanged = aItemConverter.ApplyItemSet( aOutItemSet );//model should be changed now + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertMeanValue() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AVERAGE_LINE )), + m_xUndoManager ); + lcl_InsertMeanValueLine( ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), + getChartModel() ) ); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_InsertMenu_MeanValues() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AVERAGE_LINE )), + m_xUndoManager ); + + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + { + //if a series is selected insert mean value only for that series: + lcl_InsertMeanValueLine( xSeries ); + } + else + { + std::vector< rtl::Reference< DataSeries > > aSeries = + DiagramHelper::getDataSeriesFromDiagram( getFirstDiagram()); + + for( const auto& xSrs : aSeries ) + lcl_InsertMeanValueLine( xSrs ); + } + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_InsertMenu_Trendlines() +{ + OUString aCID = m_aSelection.getSelectedCID(); + + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( aCID, getChartModel() ); + + if( !xSeries.is() ) + return; + + executeDispatch_InsertTrendline(); +} + +void ChartController::executeDispatch_InsertTrendline() +{ + rtl::Reference< DataSeries > xRegressionCurveContainer = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel()); + + if( !xRegressionCurveContainer.is() ) + return; + + UndoLiveUpdateGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE )), + m_xUndoManager ); + + rtl::Reference< RegressionCurveModel > xCurve = + RegressionCurveHelper::addRegressionCurve( + SvxChartRegress::Linear, + xRegressionCurveContainer ); + + if( !xCurve.is()) + return; + + wrapper::RegressionCurveItemConverter aItemConverter( + xCurve, xRegressionCurveContainer, m_pDrawModelWrapper->getSdrModel().GetItemPool(), + m_pDrawModelWrapper->getSdrModel(), + getChartModel() ); + + // open dialog + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemConverter.FillItemSet( aItemSet ); + ObjectPropertiesDialogParameter aDialogParameter( + ObjectIdentifier::createDataCurveCID( + ObjectIdentifier::getSeriesParticleFromCID( m_aSelection.getSelectedCID()), + RegressionCurveHelper::getRegressionCurveIndex( xRegressionCurveContainer, xCurve ), false )); + aDialogParameter.init( getChartModel() ); + ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get()); + SolarMutexGuard aGuard; + SchAttribTabDlg aDialog( + GetChartFrame(), &aItemSet, &aDialogParameter, + &aViewElementListProvider, + getChartModel() ); + + // note: when a user pressed "OK" but didn't change any settings in the + // dialog, the SfxTabDialog returns "Cancel" + if( aDialog.run() == RET_OK || aDialog.DialogWasClosedWithOK()) + { + const SfxItemSet* pOutItemSet = aDialog.GetOutputItemSet(); + if( pOutItemSet ) + { + ControllerLockGuardUNO aCLGuard( getChartModel() ); + aItemConverter.ApplyItemSet( *pOutItemSet ); + } + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_InsertErrorBars( bool bYError ) +{ + ObjectType objType = bYError ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X; + + //if a series is selected insert error bars for that series only: + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + + if( xSeries.is()) + { + UndoLiveUpdateGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, + SchResId( bYError ? STR_OBJECT_ERROR_BARS_Y : STR_OBJECT_ERROR_BARS_X )), + m_xUndoManager ); + + // add error bars with standard deviation + uno::Reference< beans::XPropertySet > xErrorBarProp( + StatisticsHelper::addErrorBars( xSeries, + css::chart::ErrorBarStyle::STANDARD_DEVIATION, + bYError)); + + // get an appropriate item converter + wrapper::ErrorBarItemConverter aItemConverter( + getChartModel(), xErrorBarProp, m_pDrawModelWrapper->getSdrModel().GetItemPool(), + m_pDrawModelWrapper->getSdrModel(), + getChartModel() ); + + // open dialog + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemSet.Put(SfxBoolItem(SCHATTR_STAT_ERRORBAR_TYPE,bYError)); + aItemConverter.FillItemSet( aItemSet ); + ObjectPropertiesDialogParameter aDialogParameter( + ObjectIdentifier::createClassifiedIdentifierWithParent( + objType, u"", m_aSelection.getSelectedCID())); + aDialogParameter.init( getChartModel() ); + ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get()); + SolarMutexGuard aGuard; + SchAttribTabDlg aDlg( + GetChartFrame(), &aItemSet, &aDialogParameter, + &aViewElementListProvider, + getChartModel() ); + aDlg.SetAxisMinorStepWidthForErrorBarDecimals( + InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getChartModel(), + m_xChartView, m_aSelection.getSelectedCID())); + + // note: when a user pressed "OK" but didn't change any settings in the + // dialog, the SfxTabDialog returns "Cancel" + if (aDlg.run() == RET_OK || aDlg.DialogWasClosedWithOK()) + { + const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet(); + if( pOutItemSet ) + { + ControllerLockGuardUNO aCLGuard( getChartModel() ); + aItemConverter.ApplyItemSet( *pOutItemSet ); + } + aUndoGuard.commit(); + } + } + else + { + //if no series is selected insert error bars for all series + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, + ObjectNameProvider::getName_ObjectForAllSeries( objType ) ), + m_xUndoManager ); + + try + { + wrapper::AllSeriesStatisticsConverter aItemConverter( + getChartModel(), m_pDrawModelWrapper->GetItemPool() ); + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemConverter.FillItemSet( aItemSet ); + + //prepare and open dialog + SolarMutexGuard aGuard; + InsertErrorBarsDialog aDlg( + GetChartFrame(), aItemSet, + getChartModel(), + bYError ? ErrorBarResources::ERROR_BAR_Y : ErrorBarResources::ERROR_BAR_X); + + aDlg.SetAxisMinorStepWidthForErrorBarDecimals( + InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getChartModel(), m_xChartView, OUString() ) ); + + if (aDlg.run() == RET_OK) + { + SfxItemSet aOutItemSet = aItemConverter.CreateEmptyItemSet(); + aDlg.FillItemSet( aOutItemSet ); + + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + bool bChanged = aItemConverter.ApplyItemSet( aOutItemSet );//model should be changed now + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } +} + +void ChartController::executeDispatch_InsertTrendlineEquation( bool bInsertR2 ) +{ + uno::Reference< chart2::XRegressionCurve > xRegCurve( + ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ), uno::UNO_QUERY ); + if( !xRegCurve.is() ) + { + rtl::Reference< DataSeries > xRegCurveCnt = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + xRegCurve.set( RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCurveCnt ) ); + } + if( !xRegCurve.is()) + return; + + uno::Reference< beans::XPropertySet > xEqProp( xRegCurve->getEquationProperties()); + if( xEqProp.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + xEqProp->setPropertyValue( "ShowEquation", uno::Any( true )); + xEqProp->setPropertyValue( "XName", uno::Any( OUString("x") )); + xEqProp->setPropertyValue( "YName", uno::Any( OUString("f(x)") )); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( bInsertR2 )); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_InsertR2Value() +{ + uno::Reference< beans::XPropertySet > xEqProp = + ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ); + if( xEqProp.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( true )); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteR2Value() +{ + uno::Reference< beans::XPropertySet > xEqProp = + ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ); + if( xEqProp.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( false )); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteMeanValue() +{ + rtl::Reference< DataSeries > xRegCurveCnt = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xRegCurveCnt.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AVERAGE_LINE )), + m_xUndoManager ); + RegressionCurveHelper::removeMeanValueLine( xRegCurveCnt ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteTrendline() +{ + rtl::Reference< DataSeries > xRegCurveCnt = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xRegCurveCnt.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )), + m_xUndoManager ); + RegressionCurveHelper::removeAllExceptMeanValueLine( xRegCurveCnt ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteTrendlineEquation() +{ + rtl::Reference< DataSeries > xRegCurveCnt = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xRegCurveCnt.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + RegressionCurveHelper::removeEquations( xRegCurveCnt ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteErrorBars( bool bYError ) +{ + rtl::Reference< DataSeries > xDataSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xDataSeries.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )), + m_xUndoManager ); + StatisticsHelper::removeErrorBars( xDataSeries, bYError ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_InsertDataLabels() +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + { + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Insert, + SchResId( STR_OBJECT_DATALABELS )), + m_xUndoManager ); + DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints( xSeries ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_InsertDataLabel() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Insert, + SchResId( STR_OBJECT_LABEL )), + m_xUndoManager ); + DataSeriesHelper::insertDataLabelToPoint( ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ) ); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_DeleteDataLabels() +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + { + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Delete, + SchResId( STR_OBJECT_DATALABELS )), + m_xUndoManager ); + DataSeriesHelper::deleteDataLabelsFromSeriesAndAllPoints( xSeries ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteDataLabel() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Delete, + SchResId( STR_OBJECT_LABEL )), + m_xUndoManager ); + DataSeriesHelper::deleteDataLabelsFromPoint( ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ) ); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_ResetAllDataPoints() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Format, + SchResId( STR_OBJECT_DATAPOINTS )), + m_xUndoManager ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + xSeries->resetAllDataPoints(); + aUndoGuard.commit(); +} +void ChartController::executeDispatch_ResetDataPoint() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Format, + SchResId( STR_OBJECT_DATAPOINT )), + m_xUndoManager ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + { + sal_Int32 nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( m_aSelection.getSelectedCID() ); + xSeries->resetDataPoint( nPointIndex ); + } + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_InsertAxisTitle() +{ + try + { + uno::Reference< XTitle > xTitle; + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_TITLE )), + m_xUndoManager ); + + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + sal_Int32 nDimensionIndex = -1; + sal_Int32 nCooSysIndex = -1; + sal_Int32 nAxisIndex = -1; + AxisHelper::getIndicesForAxis( xAxis, getFirstDiagram(), nCooSysIndex, nDimensionIndex, nAxisIndex ); + + TitleHelper::eTitleType eTitleType = TitleHelper::X_AXIS_TITLE; + if( nDimensionIndex==0 ) + eTitleType = nAxisIndex==0 ? TitleHelper::X_AXIS_TITLE : TitleHelper::SECONDARY_X_AXIS_TITLE; + else if( nDimensionIndex==1 ) + eTitleType = nAxisIndex==0 ? TitleHelper::Y_AXIS_TITLE : TitleHelper::SECONDARY_Y_AXIS_TITLE; + else + eTitleType = TitleHelper::Z_AXIS_TITLE; + + std::unique_ptr< ReferenceSizeProvider > apRefSizeProvider( impl_createReferenceSizeProvider()); + xTitle = TitleHelper::createTitle( eTitleType, ObjectNameProvider::getTitleNameByType(eTitleType), getChartModel(), m_xCC, apRefSizeProvider.get() ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertAxis() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AXIS )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + AxisHelper::makeAxisVisible( xAxis ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_DeleteAxis() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AXIS )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + AxisHelper::makeAxisInvisible( xAxis ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertMajorGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRID )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + AxisHelper::makeGridVisible( xAxis->getGridProperties() ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_DeleteMajorGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_GRID )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + AxisHelper::makeGridInvisible( xAxis->getGridProperties() ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertMinorGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRID )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( Reference< beans::XPropertySet > const & props : aSubGrids) + AxisHelper::makeGridVisible( props ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_DeleteMinorGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId(STR_OBJECT_GRID)), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( Reference< beans::XPropertySet > const & props : aSubGrids) + AxisHelper::makeGridInvisible( props ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Position.cxx b/chart2/source/controller/main/ChartController_Position.cxx new file mode 100644 index 000000000..dc8941587 --- /dev/null +++ b/chart2/source/controller/main/ChartController_Position.cxx @@ -0,0 +1,202 @@ +/* -*- 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 <ChartController.hxx> + +#include <DrawViewWrapper.hxx> +#include <PositionAndSizeHelper.hxx> +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include "UndoGuard.hxx" +#include <ObjectNameProvider.hxx> +#include <DiagramHelper.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <CommonConverters.hxx> +#include <svx/ActionDescriptionProvider.hxx> + +#include <comphelper/servicehelper.hxx> +#include <svx/svxids.hrc> +#include <svx/rectenum.hxx> +#include <svl/intitem.hxx> +#include <svx/svxdlg.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <memory> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +static void lcl_getPositionAndSizeFromItemSet( const SfxItemSet& rItemSet, awt::Rectangle& rPosAndSize, const awt::Size& rOriginalSize ) +{ + tools::Long nPosX(0); + tools::Long nPosY(0); + tools::Long nSizX(0); + tools::Long nSizY(0); + + RectPoint eRP = RectPoint::LT; + + //read position + if (const SfxInt32Item* pPosXItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_POS_X)) + nPosX = pPosXItem->GetValue(); + if (const SfxInt32Item* pPosYItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_POS_Y)) + nPosY = pPosYItem->GetValue(); + //read size + if (const SfxUInt32Item* pWidthItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_WIDTH)) + nSizX = pWidthItem->GetValue(); + if (const SfxUInt32Item* pHeightItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_HEIGHT)) + nSizY = pHeightItem->GetValue(); + if (const SfxUInt16Item* pSizeItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_SIZE_POINT)) + eRP=static_cast<RectPoint>(pSizeItem->GetValue()); + + switch( eRP ) + { + case RectPoint::LT: + break; + case RectPoint::MT: + nPosX += ( rOriginalSize.Width - nSizX ) / 2; + break; + case RectPoint::RT: + nPosX += rOriginalSize.Width - nSizX; + break; + case RectPoint::LM: + nPosY += ( rOriginalSize.Height - nSizY ) / 2; + break; + case RectPoint::MM: + nPosX += ( rOriginalSize.Width - nSizX ) / 2; + nPosY += ( rOriginalSize.Height - nSizY ) / 2; + break; + case RectPoint::RM: + nPosX += rOriginalSize.Width - nSizX; + nPosY += ( rOriginalSize.Height - nSizY ) / 2; + break; + case RectPoint::LB: + nPosY += rOriginalSize.Height - nSizY; + break; + case RectPoint::MB: + nPosX += ( rOriginalSize.Width - nSizX ) / 2; + nPosY += rOriginalSize.Height - nSizY; + break; + case RectPoint::RB: + nPosX += rOriginalSize.Width - nSizX; + nPosY += rOriginalSize.Height - nSizY; + break; + default: + break; + } + + rPosAndSize = awt::Rectangle(nPosX,nPosY,nSizX,nSizY); +} + +void ChartController::executeDispatch_PositionAndSize(const ::css::uno::Sequence< ::css::beans::PropertyValue >* pArgs) +{ + const OUString aCID( m_aSelection.getSelectedCID() ); + + if( aCID.isEmpty() ) + return; + + ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID ); + + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::PosSize, + ObjectNameProvider::getName( eObjectType)), + m_xUndoManager ); + + try + { + SfxItemSet aItemSet = m_pDrawViewWrapper->getPositionAndSizeItemSetFromMarkedObject(); + const SfxItemSet* pOutItemSet = nullptr; + if (!pArgs) + { + //prepare and open dialog + SdrView* pSdrView = m_pDrawViewWrapper.get(); + bool bResizePossible = m_aSelection.isResizeableObjectSelected(); + + SolarMutexGuard aGuard; + SvxAbstractDialogFactory * pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSchTransformTabDialog( + GetChartFrame(), &aItemSet, pSdrView, bResizePossible)); + + if( pDlg->Execute() == RET_OK ) + { + pOutItemSet = pDlg->GetOutputItemSet(); + if (pOutItemSet) + aItemSet.Put(*pOutItemSet);//overwrite old values with new values (-> all items are set) + } + } + else + { + const SfxItemPool* pPool = aItemSet.GetPool(); + if (!pPool) + return; + + for (const auto& aProp: *pArgs) + { + sal_Int32 nValue = 0; + aProp.Value >>= nValue; + if (aProp.Name == "TransformPosX") { + aItemSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_X, nValue)); + } + else if (aProp.Name == "TransformPosY") { + aItemSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_Y, nValue)); + } + else if (aProp.Name == "TransformWidth") { + aItemSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_WIDTH, static_cast<sal_uInt32>(nValue))); + } + else if (aProp.Name == "TransformHeight") { + aItemSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_HEIGHT, static_cast<sal_uInt32>(nValue))); + } + } + } + + if(pOutItemSet || pArgs) + { + awt::Rectangle aOldObjectRect; + ExplicitValueProvider* pProvider(comphelper::getFromUnoTunnel<ExplicitValueProvider>( m_xChartView )); + if( pProvider ) + aOldObjectRect = pProvider->getRectangleOfObject(aCID); + + awt::Rectangle aNewObjectRect; + lcl_getPositionAndSizeFromItemSet( aItemSet, aNewObjectRect, ToSize(aOldObjectRect) ); + awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) ); + awt::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height ); + + bool bChanged = false; + if ( eObjectType == OBJECTTYPE_LEGEND ) + { + bChanged = DiagramHelper::switchDiagramPositioningToExcludingPositioning(*getChartModel(), false , true); + } + + bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID(), getChartModel() + , aNewObjectRect, aOldObjectRect, aPageRect ); + if( bMoved || bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Properties.cxx b/chart2/source/controller/main/ChartController_Properties.cxx new file mode 100644 index 000000000..1b72833f9 --- /dev/null +++ b/chart2/source/controller/main/ChartController_Properties.cxx @@ -0,0 +1,826 @@ +/* -*- 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 <ChartController.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <chartview/ChartSfxItemIds.hxx> +#include <ObjectIdentifier.hxx> +#include <chartview/ExplicitScaleValues.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <dlg_ObjectProperties.hxx> +#include <dlg_View3D.hxx> +#include <dlg_InsertErrorBars.hxx> +#include <ViewElementListProvider.hxx> +#include <DataPointItemConverter.hxx> +#include <TextLabelItemConverter.hxx> +#include <AxisItemConverter.hxx> +#include <MultipleChartConverters.hxx> +#include <TitleItemConverter.hxx> +#include <LegendItemConverter.hxx> +#include <RegressionCurveItemConverter.hxx> +#include <RegressionEquationItemConverter.hxx> +#include <ErrorBarItemConverter.hxx> +#include <ChartModelHelper.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <TitleHelper.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <ChartModel.hxx> +#include <ColorPerPointHelper.hxx> +#include <DataSeries.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ControllerLockGuard.hxx> +#include "UndoGuard.hxx" +#include <ObjectNameProvider.hxx> +#include <ResId.hxx> +#include <strings.hrc> +#include <ReferenceSizeProvider.hxx> +#include <RegressionCurveHelper.hxx> +#include <RegressionCurveModel.hxx> +#include <com/sun/star/util/CloseVetoException.hpp> +#include <comphelper/servicehelper.hxx> +#include <o3tl/string_view.hxx> + +#include <memory> + +#include <vcl/svapp.hxx> +#include <svx/ActionDescriptionProvider.hxx> +#include <tools/diagnose_ex.h> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +namespace +{ + +wrapper::ItemConverter* createItemConverter( + const OUString & aObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel, + const uno::Reference<uno::XComponentContext>& xContext, SdrModel& rDrawModel, + ExplicitValueProvider* pExplicitValueProvider, ReferenceSizeProvider const * pRefSizeProvider ) +{ + wrapper::ItemConverter* pItemConverter=nullptr; + + //get type of selected object + ObjectType eObjectType = ObjectIdentifier::getObjectType( aObjectCID ); + if( eObjectType==OBJECTTYPE_UNKNOWN ) + { + OSL_FAIL("unknown ObjectType"); + return nullptr; + } + + std::u16string_view aParticleID = ObjectIdentifier::getParticleID( aObjectCID ); + bool bAffectsMultipleObjects = aParticleID == u"ALLELEMENTS"; + if( !bAffectsMultipleObjects ) + { + uno::Reference< beans::XPropertySet > xObjectProperties = + ObjectIdentifier::getObjectPropertySet( aObjectCID, xChartModel ); + if(!xObjectProperties.is()) + return nullptr; + //create itemconverter for a single object + switch(eObjectType) + { + case OBJECTTYPE_PAGE: + pItemConverter = new wrapper::GraphicPropertyItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel, + wrapper::GraphicObjectType::LineAndFillProperties ); + break; + case OBJECTTYPE_TITLE: + { + std::unique_ptr<awt::Size> pRefSize; + if (pRefSizeProvider) + pRefSize.reset(new awt::Size(pRefSizeProvider->getPageSize())); + + pItemConverter = new wrapper::TitleItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), rDrawModel, + xChartModel, + pRefSize.get()); + } + break; + case OBJECTTYPE_LEGEND: + { + std::unique_ptr<awt::Size> pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + pItemConverter = new wrapper::LegendItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), rDrawModel, + xChartModel, + pRefSize.get()); + } + break; + case OBJECTTYPE_LEGEND_ENTRY: + break; + case OBJECTTYPE_DIAGRAM: + break; + case OBJECTTYPE_DIAGRAM_WALL: + case OBJECTTYPE_DIAGRAM_FLOOR: + pItemConverter = new wrapper::GraphicPropertyItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel, + wrapper::GraphicObjectType::LineAndFillProperties ); + break; + case OBJECTTYPE_AXIS: + { + std::unique_ptr<awt::Size> pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + // the second property set contains the property CoordinateOrigin + // nOriginIndex is the index of the corresponding index of the + // origin (x=0, y=1, z=2) + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + if( pExplicitValueProvider ) + pExplicitValueProvider->getExplicitValuesForAxis( + uno::Reference< XAxis >( xObjectProperties, uno::UNO_QUERY ), + aExplicitScale, aExplicitIncrement ); + + pItemConverter = new wrapper::AxisItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, + xChartModel, + &aExplicitScale, &aExplicitIncrement, + pRefSize.get() ); + } + break; + case OBJECTTYPE_AXIS_UNITLABEL: + break; + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + { + std::unique_ptr<awt::Size> pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + rtl::Reference<DataSeries> xSeries = ObjectIdentifier::getDataSeriesForCID(aObjectCID, xChartModel); + + bool bDataSeries = eObjectType == OBJECTTYPE_DATA_LABELS; + + sal_Int32 nNumberFormat = ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( xObjectProperties ); + sal_Int32 nPercentNumberFormat = ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + xObjectProperties, xChartModel); + + pItemConverter = new wrapper::TextLabelItemConverter( + xChartModel, xObjectProperties, xSeries, + rDrawModel.GetItemPool(), pRefSize.get(), bDataSeries, + nNumberFormat, nPercentNumberFormat); + } + break; + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_DATA_POINT: + { + std::unique_ptr<awt::Size> pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + wrapper::GraphicObjectType eMapTo = + wrapper::GraphicObjectType::FilledDataPoint; + + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( aObjectCID, xChartModel ); + rtl::Reference< ChartType > xChartType = ChartModelHelper::getChartTypeOfSeries( xChartModel, xSeries ); + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + if( !ChartTypeHelper::isSupportingAreaProperties( xChartType, nDimensionCount ) ) + eMapTo = wrapper::GraphicObjectType::LineDataPoint; + + bool bDataSeries = eObjectType == OBJECTTYPE_DATA_SERIES; + + //special color for pie chart: + bool bUseSpecialFillColor = false; + sal_Int32 nSpecialFillColor =0; + sal_Int32 nPointIndex = -1; /*-1 for whole series*/ + if(!bDataSeries) + { + nPointIndex = o3tl::toInt32(aParticleID); + bool bVaryColorsByPoint = false; + if( xSeries.is() && + (xSeries->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint) && + bVaryColorsByPoint ) + { + if( !ColorPerPointHelper::hasPointOwnColor( xSeries, nPointIndex, xObjectProperties ) ) + { + bUseSpecialFillColor = true; + OSL_ASSERT( xDiagram.is()); + uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme() ); + if( xColorScheme.is()) + nSpecialFillColor = xColorScheme->getColorByIndex( nPointIndex ); + } + } + } + sal_Int32 nNumberFormat=ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( xObjectProperties ); + sal_Int32 nPercentNumberFormat=ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + xObjectProperties, xChartModel); + + pItemConverter = new wrapper::DataPointItemConverter( xChartModel, xContext, + xObjectProperties, xSeries, rDrawModel.GetItemPool(), rDrawModel, + xChartModel, + eMapTo, pRefSize.get(), bDataSeries, bUseSpecialFillColor, nSpecialFillColor, true, + nNumberFormat, nPercentNumberFormat, nPointIndex ); + break; + } + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + case OBJECTTYPE_DATA_AVERAGE_LINE: + pItemConverter = new wrapper::GraphicPropertyItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel, + wrapper::GraphicObjectType::LineProperties ); + break; + + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + pItemConverter = new wrapper::ErrorBarItemConverter( + xChartModel, xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel); + break; + + case OBJECTTYPE_DATA_CURVE: + pItemConverter = new wrapper::RegressionCurveItemConverter( + xObjectProperties, + ObjectIdentifier::getDataSeriesForCID( aObjectCID, xChartModel ), + rDrawModel.GetItemPool(), rDrawModel, + xChartModel); + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + { + std::unique_ptr<awt::Size> pRefSize; + if (pRefSizeProvider) + pRefSize.reset(new awt::Size(pRefSizeProvider->getPageSize())); + + pItemConverter = new wrapper::RegressionEquationItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), rDrawModel, + xChartModel, + pRefSize.get()); + break; + } + case OBJECTTYPE_DATA_STOCK_RANGE: + break; + case OBJECTTYPE_DATA_STOCK_LOSS: + case OBJECTTYPE_DATA_STOCK_GAIN: + pItemConverter = new wrapper::GraphicPropertyItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel, + wrapper::GraphicObjectType::LineAndFillProperties ); + break; + default: //OBJECTTYPE_UNKNOWN + break; + } + } + else + { + //create itemconverter for all objects of given type + switch(eObjectType) + { + case OBJECTTYPE_TITLE: + pItemConverter = new wrapper::AllTitleItemConverter( xChartModel, rDrawModel.GetItemPool(), + rDrawModel, xChartModel); + break; + case OBJECTTYPE_AXIS: + { + std::unique_ptr<awt::Size> pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + pItemConverter = new wrapper::AllAxisItemConverter( + xChartModel, rDrawModel.GetItemPool(), + rDrawModel, pRefSize.get()); + } + break; + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + pItemConverter = new wrapper::AllGridItemConverter( xChartModel, rDrawModel.GetItemPool(), + rDrawModel, xChartModel); + break; + default: //for this type it is not supported to change all elements at once + break; + } + + } + return pItemConverter; +} + +OUString lcl_getTitleCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel> & xChartModel ) +{ + if( rDispatchCommand == "AllTitles") + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_TITLE, u"ALLELEMENTS" ); + + TitleHelper::eTitleType nTitleType( TitleHelper::MAIN_TITLE ); + if( rDispatchCommand == "SubTitle" ) + nTitleType = TitleHelper::SUB_TITLE; + else if( rDispatchCommand == "XTitle" ) + nTitleType = TitleHelper::X_AXIS_TITLE; + else if( rDispatchCommand == "YTitle" ) + nTitleType = TitleHelper::Y_AXIS_TITLE; + else if( rDispatchCommand == "ZTitle" ) + nTitleType = TitleHelper::Z_AXIS_TITLE; + else if( rDispatchCommand == "SecondaryXTitle" ) + nTitleType = TitleHelper::SECONDARY_X_AXIS_TITLE; + else if( rDispatchCommand == "SecondaryYTitle" ) + nTitleType = TitleHelper::SECONDARY_Y_AXIS_TITLE; + + uno::Reference< XTitle > xTitle( TitleHelper::getTitle( nTitleType, xChartModel ) ); + return ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, xChartModel ); +} + +OUString lcl_getAxisCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + if( rDispatchCommand == "DiagramAxisAll") + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_AXIS, u"ALLELEMENTS" ); + + sal_Int32 nDimensionIndex=0; + bool bMainAxis=true; + if( rDispatchCommand == "DiagramAxisX") + { + nDimensionIndex=0; bMainAxis=true; + } + else if( rDispatchCommand == "DiagramAxisY") + { + nDimensionIndex=1; bMainAxis=true; + } + else if( rDispatchCommand == "DiagramAxisZ") + { + nDimensionIndex=2; bMainAxis=true; + } + else if( rDispatchCommand == "DiagramAxisA") + { + nDimensionIndex=0; bMainAxis=false; + } + else if( rDispatchCommand == "DiagramAxisB") + { + nDimensionIndex=1; bMainAxis=false; + } + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ); + return ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartModel ); +} + +OUString lcl_getGridCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + + if( rDispatchCommand == "DiagramGridAll") + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_GRID, u"ALLELEMENTS" ); + + sal_Int32 nDimensionIndex=0; + bool bMainGrid=true; + + //x and y is swapped in the commands + + if( rDispatchCommand == "DiagramGridYMain") + { + nDimensionIndex=0; bMainGrid=true; + } + else if( rDispatchCommand == "DiagramGridXMain") + { + nDimensionIndex=1; bMainGrid=true; + } + else if( rDispatchCommand == "DiagramGridZMain") + { + nDimensionIndex=2; bMainGrid=true; + } + else if( rDispatchCommand == "DiagramGridYHelp") + { + nDimensionIndex=0; bMainGrid=false; + } + else if( rDispatchCommand == "DiagramGridXHelp") + { + nDimensionIndex=1; bMainGrid=false; + } + else if( rDispatchCommand == "DiagramGridZHelp") + { + nDimensionIndex=2; bMainGrid=false; + } + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, true/*bMainAxis*/, xDiagram ); + + sal_Int32 nSubGridIndex= bMainGrid ? -1 : 0; + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel, nSubGridIndex ) ); + return aCID; +} + +OUString lcl_getErrorCIDForCommand( const ObjectType eDispatchType, const ObjectType &eSelectedType, const OUString &rSelectedCID) +{ + if( eSelectedType == eDispatchType ) + return rSelectedCID; + + return ObjectIdentifier::createClassifiedIdentifierWithParent( eDispatchType, u"", rSelectedCID ); +} + +OUString lcl_getObjectCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel> & xChartDocument, const OUString& rSelectedCID ) +{ + ObjectType eObjectType = OBJECTTYPE_UNKNOWN; + + const ObjectType eSelectedType = ObjectIdentifier::getObjectType( rSelectedCID ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rSelectedCID, xChartDocument ); + + //legend + if( rDispatchCommand == "Legend" || rDispatchCommand == "FormatLegend" ) + { + eObjectType = OBJECTTYPE_LEGEND; + //@todo set particular aParticleID if we have more than one legend + } + //wall floor area + else if( rDispatchCommand == "DiagramWall" || rDispatchCommand == "FormatWall" ) + { + //OBJECTTYPE_DIAGRAM; + eObjectType = OBJECTTYPE_DIAGRAM_WALL; + //@todo set particular aParticleID if we have more than one diagram + } + else if( rDispatchCommand == "DiagramFloor" || rDispatchCommand == "FormatFloor" ) + { + eObjectType = OBJECTTYPE_DIAGRAM_FLOOR; + //@todo set particular aParticleID if we have more than one diagram + } + else if( rDispatchCommand == "DiagramArea" || rDispatchCommand == "FormatChartArea" ) + { + eObjectType = OBJECTTYPE_PAGE; + } + //title + else if( rDispatchCommand == "MainTitle" + || rDispatchCommand == "SubTitle" + || rDispatchCommand == "XTitle" + || rDispatchCommand == "YTitle" + || rDispatchCommand == "ZTitle" + || rDispatchCommand == "SecondaryXTitle" + || rDispatchCommand == "SecondaryYTitle" + || rDispatchCommand == "AllTitles" + ) + { + return lcl_getTitleCIDForCommand( rDispatchCommand, xChartDocument ); + } + //axis + else if( rDispatchCommand == "DiagramAxisX" + || rDispatchCommand == "DiagramAxisY" + || rDispatchCommand == "DiagramAxisZ" + || rDispatchCommand == "DiagramAxisA" + || rDispatchCommand == "DiagramAxisB" + || rDispatchCommand == "DiagramAxisAll" + ) + { + return lcl_getAxisCIDForCommand( rDispatchCommand, xChartDocument ); + } + //grid + else if( rDispatchCommand == "DiagramGridYMain" + || rDispatchCommand == "DiagramGridXMain" + || rDispatchCommand == "DiagramGridZMain" + || rDispatchCommand == "DiagramGridYHelp" + || rDispatchCommand == "DiagramGridXHelp" + || rDispatchCommand == "DiagramGridZHelp" + || rDispatchCommand == "DiagramGridAll" + ) + { + return lcl_getGridCIDForCommand( rDispatchCommand, xChartDocument ); + } + //data series + else if( rDispatchCommand == "FormatDataSeries" ) + { + if( eSelectedType == OBJECTTYPE_DATA_SERIES ) + return rSelectedCID; + else + return ObjectIdentifier::createClassifiedIdentifier( + OBJECTTYPE_DATA_SERIES, ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ) ); + } + //data point + else if( rDispatchCommand == "FormatDataPoint" ) + { + return rSelectedCID; + } + //data labels + else if( rDispatchCommand == "FormatDataLabels" ) + { + if( eSelectedType == OBJECTTYPE_DATA_LABELS ) + return rSelectedCID; + else + return ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_LABELS, u"", rSelectedCID ); + } + //data labels + else if( rDispatchCommand == "FormatDataLabel" ) + { + if( eSelectedType == OBJECTTYPE_DATA_LABEL ) + return rSelectedCID; + else + { + sal_Int32 nPointIndex = o3tl::toInt32(ObjectIdentifier::getParticleID( rSelectedCID )); + if( nPointIndex>=0 ) + { + OUString aSeriesParticle = ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ); + OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" ); + OUString aLabelsCID = ObjectIdentifier::createClassifiedIdentifierForParticles( aSeriesParticle, aChildParticle ); + OUString aLabelCID_Stub = ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_LABEL, u"", aLabelsCID ); + + return ObjectIdentifier::createPointCID( aLabelCID_Stub, nPointIndex ); + } + } + } + //mean value line + else if( rDispatchCommand == "FormatMeanValue" ) + { + if( eSelectedType == OBJECTTYPE_DATA_AVERAGE_LINE ) + return rSelectedCID; + else + return ObjectIdentifier::createDataCurveCID( + ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ), + RegressionCurveHelper::getRegressionCurveIndex( xSeries, + RegressionCurveHelper::getMeanValueLine( xSeries ) ), true ); + } + //trend line + else if( rDispatchCommand == "FormatTrendline" ) + { + if( eSelectedType == OBJECTTYPE_DATA_CURVE ) + return rSelectedCID; + else + return ObjectIdentifier::createDataCurveCID( + ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ), + RegressionCurveHelper::getRegressionCurveIndex( xSeries, + RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries ) ), false ); + } + //trend line equation + else if( rDispatchCommand == "FormatTrendlineEquation" ) + { + if( eSelectedType == OBJECTTYPE_DATA_CURVE_EQUATION ) + return rSelectedCID; + else + return ObjectIdentifier::createDataCurveEquationCID( + ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ), + RegressionCurveHelper::getRegressionCurveIndex( xSeries, + RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries ) ) ); + } + // y error bars + else if( rDispatchCommand == "FormatXErrorBars" ) + { + return lcl_getErrorCIDForCommand(OBJECTTYPE_DATA_ERRORS_X, eSelectedType, rSelectedCID ); + } + // y error bars + else if( rDispatchCommand == "FormatYErrorBars" ) + { + return lcl_getErrorCIDForCommand(OBJECTTYPE_DATA_ERRORS_Y, eSelectedType, rSelectedCID ); + } + // axis + else if( rDispatchCommand == "FormatAxis" ) + { + if( eSelectedType == OBJECTTYPE_AXIS ) + return rSelectedCID; + else + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument ); + return ObjectIdentifier::createClassifiedIdentifierForObject( xAxis , xChartDocument ); + } + } + // major grid + else if( rDispatchCommand == "FormatMajorGrid" ) + { + if( eSelectedType == OBJECTTYPE_GRID ) + return rSelectedCID; + else + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument ); + return ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDocument ); + } + + } + // minor grid + else if( rDispatchCommand == "FormatMinorGrid" ) + { + if( eSelectedType == OBJECTTYPE_SUBGRID ) + return rSelectedCID; + else + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument ); + return ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDocument, 0 /*sub grid index*/ ); + } + } + // title + else if( rDispatchCommand == "FormatTitle" ) + { + if( eSelectedType == OBJECTTYPE_TITLE ) + return rSelectedCID; + } + // stock loss + else if( rDispatchCommand == "FormatStockLoss" ) + { + if( eSelectedType == OBJECTTYPE_DATA_STOCK_LOSS ) + return rSelectedCID; + else + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DATA_STOCK_LOSS, u""); + } + // stock gain + else if( rDispatchCommand == "FormatStockGain" ) + { + if( eSelectedType == OBJECTTYPE_DATA_STOCK_GAIN ) + return rSelectedCID; + else + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DATA_STOCK_GAIN, u"" ); + } + + return ObjectIdentifier::createClassifiedIdentifier( + eObjectType, + u"" ); // aParticleID +} + +} +// anonymous namespace + +void ChartController::executeDispatch_FormatObject(std::u16string_view rDispatchCommand) +{ + rtl::Reference<::chart::ChartModel> xChartDocument( getChartModel() ); + OString aCommand( OUStringToOString( rDispatchCommand, RTL_TEXTENCODING_ASCII_US ) ); + OUString rObjectCID = lcl_getObjectCIDForCommand( aCommand, xChartDocument, m_aSelection.getSelectedCID() ); + executeDlg_ObjectProperties( rObjectCID ); +} + +void ChartController::executeDispatch_ObjectProperties() +{ + executeDlg_ObjectProperties( m_aSelection.getSelectedCID() ); +} + +namespace +{ + +OUString lcl_getFormatCIDforSelectedCID( const OUString& rSelectedCID ) +{ + OUString aFormatCID(rSelectedCID); + + //get type of selected object + ObjectType eObjectType = ObjectIdentifier::getObjectType( aFormatCID ); + + // some legend entries are handled as if they were data series + if( eObjectType==OBJECTTYPE_LEGEND_ENTRY ) + { + std::u16string_view aParentParticle( ObjectIdentifier::getFullParentParticle( rSelectedCID ) ); + aFormatCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle ); + } + + // treat diagram as wall + if( eObjectType==OBJECTTYPE_DIAGRAM ) + aFormatCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ); + + return aFormatCID; +} + +}//end anonymous namespace + +void ChartController::executeDlg_ObjectProperties( const OUString& rSelectedObjectCID ) +{ + OUString aObjectCID = lcl_getFormatCIDforSelectedCID( rSelectedObjectCID ); + + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Format, + ObjectNameProvider::getName( ObjectIdentifier::getObjectType( aObjectCID ))), + m_xUndoManager ); + + bool bSuccess = ChartController::executeDlg_ObjectProperties_withoutUndoGuard( aObjectCID, false ); + if( bSuccess ) + aUndoGuard.commit(); +} + +bool ChartController::executeDlg_ObjectProperties_withoutUndoGuard( + const OUString& rObjectCID, bool bSuccessOnUnchanged ) +{ + //return true if the properties were changed successfully + bool bRet = false; + if( rObjectCID.isEmpty() ) + { + return bRet; + } + try + { + //get type of object + ObjectType eObjectType = ObjectIdentifier::getObjectType( rObjectCID ); + if( eObjectType==OBJECTTYPE_UNKNOWN ) + { + return bRet; + } + if( eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR ) + { + if( !DiagramHelper::isSupportingFloorAndWall( getFirstDiagram() ) ) + return bRet; + } + + //convert properties to ItemSet + + std::unique_ptr<ReferenceSizeProvider> pRefSizeProv(impl_createReferenceSizeProvider()); + + std::unique_ptr<wrapper::ItemConverter> pItemConverter( + createItemConverter( rObjectCID, getChartModel(), m_xCC, + m_pDrawModelWrapper->getSdrModel(), + comphelper::getFromUnoTunnel<ExplicitValueProvider>(m_xChartView), + pRefSizeProv.get())); + + if (!pItemConverter) + return bRet; + + SfxItemSet aItemSet = pItemConverter->CreateEmptyItemSet(); + + if ( eObjectType == OBJECTTYPE_DATA_ERRORS_X || eObjectType == OBJECTTYPE_DATA_ERRORS_Y ) + aItemSet.Put(SfxBoolItem(SCHATTR_STAT_ERRORBAR_TYPE, eObjectType == OBJECTTYPE_DATA_ERRORS_Y )); + + pItemConverter->FillItemSet(aItemSet); + + //prepare dialog + ObjectPropertiesDialogParameter aDialogParameter( rObjectCID ); + aDialogParameter.init( getChartModel() ); + ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get() ); + + SolarMutexGuard aGuard; + SchAttribTabDlg aDlg( + GetChartFrame(), &aItemSet, &aDialogParameter, + &aViewElementListProvider, + getChartModel() ); + + if(aDialogParameter.HasSymbolProperties()) + { + uno::Reference< beans::XPropertySet > xObjectProperties = + ObjectIdentifier::getObjectPropertySet( rObjectCID, getChartModel() ); + wrapper::DataPointItemConverter aSymbolItemConverter( getChartModel(), m_xCC + , xObjectProperties, ObjectIdentifier::getDataSeriesForCID( rObjectCID, getChartModel() ) + , m_pDrawModelWrapper->getSdrModel().GetItemPool() + , m_pDrawModelWrapper->getSdrModel() + , getChartModel() + , wrapper::GraphicObjectType::FilledDataPoint ); + + SfxItemSet aSymbolShapeProperties(aSymbolItemConverter.CreateEmptyItemSet() ); + aSymbolItemConverter.FillItemSet( aSymbolShapeProperties ); + + sal_Int32 const nStandardSymbol=0;//@todo get from somewhere + std::unique_ptr<Graphic> pAutoSymbolGraphic(new Graphic( aViewElementListProvider.GetSymbolGraphic( nStandardSymbol, &aSymbolShapeProperties ) )); + // note: the dialog takes the ownership of pSymbolShapeProperties and pAutoSymbolGraphic + aDlg.setSymbolInformation( std::move(aSymbolShapeProperties), std::move(pAutoSymbolGraphic) ); + } + if( aDialogParameter.HasStatisticProperties() ) + { + aDlg.SetAxisMinorStepWidthForErrorBarDecimals( + InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getChartModel(), m_xChartView, rObjectCID ) ); + } + + //open the dialog + if (aDlg.run() == RET_OK || (bSuccessOnUnchanged && aDlg.DialogWasClosedWithOK())) + { + const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet(); + if(pOutItemSet) + { + ControllerLockGuardUNO aCLGuard( getChartModel()); + (void)pItemConverter->ApplyItemSet(*pOutItemSet); //model should be changed now + bRet = true; + } + } + } + catch( const util::CloseVetoException& ) + { + } + catch( const uno::RuntimeException& ) + { + } + return bRet; +} + +void ChartController::executeDispatch_View3D() +{ + try + { + UndoLiveUpdateGuard aUndoGuard( + SchResId( STR_ACTION_EDIT_3D_VIEW ), + m_xUndoManager ); + + //open dialog + SolarMutexGuard aSolarGuard; + View3DDialog aDlg(GetChartFrame(), getChartModel()); + if (aDlg.run() == RET_OK) + aUndoGuard.commit(); + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_TextEdit.cxx b/chart2/source/controller/main/ChartController_TextEdit.cxx new file mode 100644 index 000000000..8d56429e3 --- /dev/null +++ b/chart2/source/controller/main/ChartController_TextEdit.cxx @@ -0,0 +1,234 @@ +/* -*- 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 <config_wasm_strip.h> + +#include <ChartController.hxx> + +#include <ResId.hxx> +#include "UndoGuard.hxx" +#include <DrawViewWrapper.hxx> +#include <ChartWindow.hxx> +#include <ChartModel.hxx> +#include <TitleHelper.hxx> +#include <ObjectIdentifier.hxx> +#include <ControllerLockGuard.hxx> +#if !ENABLE_WASM_STRIP_ACCESSIBILITY +#include <AccessibleTextHelper.hxx> +#endif +#include <strings.hrc> +#include <chartview/DrawModelWrapper.hxx> +#include <osl/diagnose.h> + +#include <svx/svdoutl.hxx> +#include <svx/svxdlg.hxx> +#include <svx/svxids.hrc> +#include <editeng/editids.hrc> +#include <vcl/svapp.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart2/XTitle.hpp> +#include <svl/stritem.hxx> +#include <editeng/fontitem.hxx> +#include <memory> + +namespace chart +{ +using namespace ::com::sun::star; + +void ChartController::executeDispatch_EditText( const Point* pMousePixel ) +{ + StartTextEdit( pMousePixel ); +} + +void ChartController::StartTextEdit( const Point* pMousePixel ) +{ + //the first marked object will be edited + + SolarMutexGuard aGuard; + SdrObject* pTextObj = m_pDrawViewWrapper->getTextEditObject(); + if(!pTextObj) + return; + + OSL_PRECOND(!m_pTextActionUndoGuard, + "ChartController::StartTextEdit: already have a TextUndoGuard!?"); + m_pTextActionUndoGuard.reset( new UndoGuard( + SchResId( STR_ACTION_EDIT_TEXT ), m_xUndoManager ) ); + SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner(); + + //#i77362 change notification for changes on additional shapes are missing + uno::Reference< beans::XPropertySet > xChartViewProps( m_xChartView, uno::UNO_QUERY ); + if( xChartViewProps.is() ) + xChartViewProps->setPropertyValue( "SdrViewIsInEditMode", uno::Any(true) ); + + auto pChartWindow(GetChartWindow()); + + bool bEdit = m_pDrawViewWrapper->SdrBeginTextEdit( pTextObj + , m_pDrawViewWrapper->GetPageView() + , pChartWindow + , false //bIsNewObj + , pOutliner + , nullptr //pOutlinerView + , true //bDontDeleteOutliner + , true //bOnlyOneView + ); + if(!bEdit) + return; + + m_pDrawViewWrapper->SetEditMode(); + + // #i12587# support for shapes in chart + if ( pMousePixel ) + { + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + if ( pOutlinerView ) + { + MouseEvent aEditEvt( *pMousePixel, 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0 ); + pOutlinerView->MouseButtonDown( aEditEvt ); + pOutlinerView->MouseButtonUp( aEditEvt ); + } + } + + if (pChartWindow) + { + //we invalidate the outliner region because the outliner has some + //paint problems (some characters are painted twice a little bit shifted) + pChartWindow->Invalidate( m_pDrawViewWrapper->GetMarkedObjBoundRect() ); + } +} + +bool ChartController::EndTextEdit() +{ + m_pDrawViewWrapper->SdrEndTextEdit(); + + //#i77362 change notification for changes on additional shapes are missing + uno::Reference< beans::XPropertySet > xChartViewProps( m_xChartView, uno::UNO_QUERY ); + if( xChartViewProps.is() ) + xChartViewProps->setPropertyValue( "SdrViewIsInEditMode", uno::Any(false) ); + + SdrObject* pTextObject = m_pDrawViewWrapper->getTextEditObject(); + if(!pTextObject) + return false; + + SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner(); + OutlinerParaObject* pParaObj = pTextObject->GetOutlinerParaObject(); + if( !pParaObj || !pOutliner ) + return true; + + pOutliner->SetText( *pParaObj ); + + OUString aString = pOutliner->GetText( + pOutliner->GetParagraph( 0 ), + pOutliner->GetParagraphCount() ); + + OUString aObjectCID = m_aSelection.getSelectedCID(); + if ( !aObjectCID.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xPropSet = + ObjectIdentifier::getObjectPropertySet( aObjectCID, getChartModel() ); + + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + + TitleHelper::setCompleteString( aString, uno::Reference< + css::chart2::XTitle >::query( xPropSet ), m_xCC ); + + OSL_ENSURE(m_pTextActionUndoGuard, "ChartController::EndTextEdit: no TextUndoGuard!"); + if (m_pTextActionUndoGuard) + m_pTextActionUndoGuard->commit(); + } + m_pTextActionUndoGuard.reset(); + return true; +} + +void ChartController::executeDispatch_InsertSpecialCharacter() +{ + SolarMutexGuard aGuard; + if( !m_pDrawViewWrapper) + { + OSL_ENSURE( m_pDrawViewWrapper, "No DrawViewWrapper for ChartController" ); + return; + } + if( !m_pDrawViewWrapper->IsTextEdit() ) + StartTextEdit(); + + SvxAbstractDialogFactory * pFact = SvxAbstractDialogFactory::Create(); + + SfxAllItemSet aSet( m_pDrawModelWrapper->GetItemPool() ); + aSet.Put( SfxBoolItem( FN_PARAM_1, false ) ); + + //set fixed current font + aSet.Put( SfxBoolItem( FN_PARAM_2, true ) ); //maybe not necessary in future + + vcl::Font aCurFont = m_pDrawViewWrapper->getOutliner()->GetRefDevice()->GetFont(); + aSet.Put( SvxFontItem( aCurFont.GetFamilyType(), aCurFont.GetFamilyName(), aCurFont.GetStyleName(), aCurFont.GetPitch(), aCurFont.GetCharSet(), SID_ATTR_CHAR_FONT ) ); + + ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateCharMapDialog(GetChartFrame(), aSet, nullptr)); + if( pDlg->Execute() != RET_OK ) + return; + + const SfxItemSet* pSet = pDlg->GetOutputItemSet(); + OUString aString; + if (pSet) + if (const SfxStringItem* pCharMapItem = pSet->GetItemIfSet(SID_CHARMAP)) + aString = pCharMapItem->GetValue(); + + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner(); + + if(!pOutliner || !pOutlinerView) + return; + + // insert string to outliner + + // prevent flicker + pOutlinerView->HideCursor(); + pOutliner->SetUpdateLayout(false); + + // delete current selection by inserting empty String, so current + // attributes become unique (sel. has to be erased anyway) + pOutlinerView->InsertText(OUString()); + + pOutlinerView->InsertText(aString, true); + + ESelection aSel = pOutlinerView->GetSelection(); + aSel.nStartPara = aSel.nEndPara; + aSel.nStartPos = aSel.nEndPos; + pOutlinerView->SetSelection(aSel); + + // show changes + pOutliner->SetUpdateLayout(true); + pOutlinerView->ShowCursor(); +} + +uno::Reference< css::accessibility::XAccessibleContext > + ChartController::impl_createAccessibleTextContext() +{ +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + uno::Reference< css::accessibility::XAccessibleContext > xResult( + new AccessibleTextHelper( m_pDrawViewWrapper.get() )); + + return xResult; +#else + return uno::Reference< css::accessibility::XAccessibleContext >(); +#endif +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Tools.cxx b/chart2/source/controller/main/ChartController_Tools.cxx new file mode 100644 index 000000000..40da1941e --- /dev/null +++ b/chart2/source/controller/main/ChartController_Tools.cxx @@ -0,0 +1,1107 @@ +/* -*- 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 <ChartController.hxx> +#include <ChartWindow.hxx> +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <TitleHelper.hxx> +#include <ThreeDHelper.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include "UndoGuard.hxx" +#include <ControllerLockGuard.hxx> +#include <ResId.hxx> +#include <strings.hrc> +#include <ObjectIdentifier.hxx> +#include <ReferenceSizeProvider.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include "ChartTransferable.hxx" +#include <DrawViewWrapper.hxx> +#include <Legend.hxx> +#include <LegendHelper.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <RegressionCurveModel.hxx> +#include <RegressionCurveHelper.hxx> +#include "ShapeController.hxx" +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ObjectNameProvider.hxx> +#include <unonames.hxx> + +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/chart/ErrorBarStyle.hpp> +#include <com/sun/star/chart2/XRegressionCurveContainer.hpp> + +#include <editeng/editview.hxx> +#include <editeng/outliner.hxx> +#include <svx/ActionDescriptionProvider.hxx> +#include <vcl/transfer.hxx> +#include <sot/storage.hxx> +#include <vcl/graph.hxx> +#include <vcl/TypeSerializer.hxx> +#include <svx/unomodel.hxx> +#include <svx/svdmodel.hxx> +#include <unotools/streamwrap.hxx> +#include <vcl/svapp.hxx> +#include <svx/dialmgr.hxx> +#include <svx/strings.hrc> +#include <svx/svditer.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdundo.hxx> +#include <svx/unoapi.hxx> +#include <svx/unopage.hxx> +#include <svx/unoshape.hxx> +#include <svx/xgrad.hxx> +#include <PropertyHelper.hxx> + +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/UnitConversion.hxx> + +#include <memory> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +namespace +{ + +bool lcl_deleteDataSeries( + const OUString & rCID, + const rtl::Reference<::chart::ChartModel> & xModel, + const Reference< document::XUndoManager > & xUndoManager ) +{ + bool bResult = false; + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rCID, xModel ); + if( xSeries.is() && xModel.is()) + { + rtl::Reference< ::chart::ChartType > xChartType = + DataSeriesHelper::getChartTypeOfSeries( xSeries, xModel->getFirstChartDiagram()); + if( xChartType.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_DATASERIES )), + xUndoManager ); + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + rtl::Reference< Axis > xAxis = DiagramHelper::getAttachedAxis( xSeries, xDiagram ); + + DataSeriesHelper::deleteSeries( xSeries, xChartType ); + + AxisHelper::hideAxisIfNoDataIsAttached( xAxis, xDiagram ); + + bResult = true; + aUndoGuard.commit(); + } + } + return bResult; +} + +bool lcl_deleteDataCurve( + const OUString & rCID, + const rtl::Reference<::chart::ChartModel> & xModel, + const Reference< document::XUndoManager > & xUndoManager ) +{ + bool bResult = false; + + uno::Reference< beans::XPropertySet > xProperties( + ObjectIdentifier::getObjectPropertySet( rCID, xModel)); + + uno::Reference< chart2::XRegressionCurve > xRegressionCurve( xProperties, uno::UNO_QUERY ); + + if( xRegressionCurve.is()) + { + uno::Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( + ObjectIdentifier::getObjectPropertySet( + OUString(ObjectIdentifier::getFullParentParticle( rCID )), xModel), uno::UNO_QUERY ); + + if( xRegressionCurveContainer.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )), + xUndoManager ); + + xRegressionCurveContainer->removeRegressionCurve( xRegressionCurve ); + + bResult = true; + aUndoGuard.commit(); + } + } + return bResult; +} + +} // anonymous namespace + +std::unique_ptr<ReferenceSizeProvider> ChartController::impl_createReferenceSizeProvider() +{ + awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) ); + + return std::make_unique<ReferenceSizeProvider>(aPageSize, getChartModel()); +} + +void ChartController::impl_adaptDataSeriesAutoResize() +{ + std::unique_ptr<ReferenceSizeProvider> pRefSizeProvider(impl_createReferenceSizeProvider()); + if (pRefSizeProvider) + pRefSizeProvider->setValuesAtAllDataSeries(); +} + +void ChartController::executeDispatch_NewArrangement() +{ + // remove manual positions at titles, legend and the diagram, remove manual + // size at the diagram + + try + { + rtl::Reference<::chart::ChartModel> xModel( getChartModel() ); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + if( xDiagram.is()) + { + UndoGuard aUndoGuard( + SchResId( STR_ACTION_REARRANGE_CHART ), + m_xUndoManager ); + ControllerLockGuardUNO aCtlLockGuard( xModel ); + + // diagram + xDiagram->setPropertyToDefault( "RelativeSize"); + xDiagram->setPropertyToDefault( "RelativePosition"); + xDiagram->setPropertyToDefault( "PosSizeExcludeAxes"); + + // 3d rotation + ThreeDHelper::set3DSettingsToDefault( xDiagram ); + + // legend + Reference< beans::XPropertyState > xLegendState( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xLegendState.is()) + { + xLegendState->setPropertyToDefault( "RelativePosition"); + xLegendState->setPropertyToDefault( "RelativeSize"); + xLegendState->setPropertyToDefault( "AnchorPosition"); + } + + // titles + for( sal_Int32 eType = TitleHelper::TITLE_BEGIN; + eType < TitleHelper::NORMAL_TITLE_END; + ++eType ) + { + Reference< beans::XPropertyState > xTitleState( + TitleHelper::getTitle( + static_cast< TitleHelper::eTitleType >( eType ), xModel ), uno::UNO_QUERY ); + if( xTitleState.is()) + xTitleState->setPropertyToDefault( "RelativePosition"); + } + + // regression curve equations + std::vector< rtl::Reference< RegressionCurveModel > > aRegressionCurves = + RegressionCurveHelper::getAllRegressionCurvesNotMeanValueLine( xDiagram ); + + // reset equation position + for( const auto& xCurve : aRegressionCurves ) + RegressionCurveHelper::resetEquationPosition( xCurve ); + + aUndoGuard.commit(); + } + } + catch( const uno::RuntimeException & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartController::executeDispatch_ScaleText() +{ + SolarMutexGuard aSolarGuard; + UndoGuard aUndoGuard( + SchResId( STR_ACTION_SCALE_TEXT ), + m_xUndoManager ); + ControllerLockGuardUNO aCtlLockGuard( getChartModel() ); + + std::unique_ptr<ReferenceSizeProvider> pRefSizeProv(impl_createReferenceSizeProvider()); + OSL_ASSERT(pRefSizeProv); + if (pRefSizeProv) + pRefSizeProv->toggleAutoResizeState(); + + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_Paste() +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( !pChartWindow ) + return; + + Graphic aGraphic; + // paste location: center of window + Point aPos = pChartWindow->PixelToLogic( tools::Rectangle( {}, pChartWindow->GetSizePixel()).Center()); + + // handle different formats + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pChartWindow )); + if( aDataHelper.GetTransferable().is()) + { + if ( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) ) + { + tools::SvRef<SotTempStream> xStm; + if ( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStm ) ) + { + xStm->Seek( 0 ); + Reference< io::XInputStream > xInputStream( new utl::OInputStreamWrapper( *xStm ) ); + + std::unique_ptr< SdrModel > spModel( + new SdrModel()); + + if ( SvxDrawingLayerImport( spModel.get(), xInputStream ) ) + { + impl_PasteShapes( spModel.get() ); + } + } + } + else if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) ) + { + // graphic exchange format (graphic manager bitmap format?) + tools::SvRef<SotTempStream> xStm; + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm )) + { + TypeSerializer aSerializer(*xStm); + aSerializer.readGraphic(aGraphic); + } + } + else if( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE )) + { + // meta file + GDIMetaFile aMetafile; + if( aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMetafile )) + aGraphic = Graphic( aMetafile ); + } + else if( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP )) + { + // bitmap (non-graphic-manager) + BitmapEx aBmpEx; + if( aDataHelper.GetBitmapEx( SotClipboardFormatId::BITMAP, aBmpEx )) + aGraphic = Graphic( aBmpEx ); + } + else if( aDataHelper.HasFormat( SotClipboardFormatId::STRING )) + { + OUString aString; + if( aDataHelper.GetString( SotClipboardFormatId::STRING, aString ) && m_pDrawModelWrapper ) + { + if( m_pDrawViewWrapper ) + { + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + if( pOutlinerView )//in case of edit mode insert into edited string + pOutlinerView->InsertText( aString ); + else + { + impl_PasteStringAsTextShape( aString, awt::Point( 0, 0 ) ); + } + } + } + } + } + + if( aGraphic.GetType() != GraphicType::NONE ) + { + Reference< graphic::XGraphic > xGraphic( aGraphic.GetXGraphic()); + if( xGraphic.is()) + impl_PasteGraphic( xGraphic, aPos ); + } +} + +// note: aPosition is ignored for now. The object is always pasted centered to +// the page +void ChartController::impl_PasteGraphic( + uno::Reference< graphic::XGraphic > const & xGraphic, + const ::Point & /* aPosition */ ) +{ + DBG_TESTSOLARMUTEX(); + // note: the XPropertySet of the model is the old API. Also the property + // "AdditionalShapes" that is used there. + rtl::Reference< ChartModel > xModel = getChartModel(); + DrawModelWrapper * pDrawModelWrapper( GetDrawModelWrapper()); + if( ! (xGraphic.is() && xModel.is())) + return; + rtl::Reference<SvxGraphicObject> xGraphicShape = new SvxGraphicObject(nullptr); + xGraphicShape->setShapeKind(SdrObjKind::Graphic); + + uno::Reference< drawing::XShapes > xPage = pDrawModelWrapper->getMainDrawPage(); + if( xPage.is()) + { + xPage->add( xGraphicShape ); + //need to change the model state manually + xModel->setModified( true ); + //select new shape + m_aSelection.setSelection( xGraphicShape ); + m_aSelection.applySelection( m_pDrawViewWrapper.get() ); + } + xGraphicShape->SvxShape::setPropertyValue( "Graphic", uno::Any( xGraphic )); + + awt::Size aGraphicSize( 1000, 1000 ); + auto pChartWindow(GetChartWindow()); + // first try size in 100th mm, then pixel size + if( ! ( xGraphicShape->SvxShape::getPropertyValue( "Size100thMM") >>= aGraphicSize ) && + ( ( xGraphicShape->SvxShape::getPropertyValue( "SizePixel") >>= aGraphicSize ) && pChartWindow )) + { + ::Size aVCLSize( pChartWindow->PixelToLogic( Size( aGraphicSize.Width, aGraphicSize.Height ))); + aGraphicSize.Width = aVCLSize.getWidth(); + aGraphicSize.Height = aVCLSize.getHeight(); + } + xGraphicShape->setSize( aGraphicSize ); + xGraphicShape->setPosition( awt::Point( 0, 0 ) ); +} + +void ChartController::impl_PasteShapes( SdrModel* pModel ) +{ + DrawModelWrapper* pDrawModelWrapper( GetDrawModelWrapper() ); + if ( !(pDrawModelWrapper && m_pDrawViewWrapper) ) + return; + + Reference< drawing::XDrawPage > xDestPage( pDrawModelWrapper->getMainDrawPage() ); + SdrPage* pDestPage = GetSdrPageFromXDrawPage( xDestPage ); + if ( !pDestPage ) + return; + + Reference< drawing::XShape > xSelShape; + m_pDrawViewWrapper->BegUndo( SvxResId( RID_SVX_3D_UNDO_EXCHANGE_PASTE ) ); + sal_uInt16 nCount = pModel->GetPageCount(); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + const SdrPage* pPage = pModel->GetPage( i ); + SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); + while ( aIter.IsMore() ) + { + SdrObject* pObj(aIter.Next()); + // Clone to new SdrModel + SdrObject* pNewObj(pObj ? pObj->CloneSdrObject(pDrawModelWrapper->getSdrModel()) : nullptr); + + if ( pNewObj ) + { + // set position + Reference< drawing::XShape > xShape( pNewObj->getUnoShape(), uno::UNO_QUERY ); + if ( xShape.is() ) + { + xShape->setPosition( awt::Point( 0, 0 ) ); + } + + pDestPage->InsertObject( pNewObj ); + m_pDrawViewWrapper->AddUndo( std::make_unique<SdrUndoInsertObj>( *pNewObj ) ); + xSelShape = xShape; + } + } + } + + rtl::Reference< ChartModel > xModifiable = getChartModel(); + if ( xModifiable.is() ) + { + xModifiable->setModified( true ); + } + + // select last inserted shape + m_aSelection.setSelection( xSelShape ); + m_aSelection.applySelection( m_pDrawViewWrapper.get() ); + + m_pDrawViewWrapper->EndUndo(); + + impl_switchDiagramPositioningToExcludingPositioning(); +} + +void ChartController::impl_PasteStringAsTextShape( const OUString& rString, const awt::Point& rPosition ) +{ + DrawModelWrapper* pDrawModelWrapper( GetDrawModelWrapper() ); + if ( !(pDrawModelWrapper && m_pDrawViewWrapper) ) + return; + + const Reference< drawing::XDrawPage >& xDrawPage( pDrawModelWrapper->getMainDrawPage() ); + OSL_ASSERT( xDrawPage.is() ); + + if ( !xDrawPage ) + return; + + try + { + rtl::Reference<SvxShapeText> xTextShape = new SvxShapeText(nullptr); + xTextShape->setShapeKind(SdrObjKind::Text); + xDrawPage->add( xTextShape ); + + xTextShape->setString( rString ); + + float fCharHeight = 10.0; + xTextShape->SvxShape::setPropertyValue( "TextAutoGrowHeight", uno::Any( true ) ); + xTextShape->SvxShape::setPropertyValue( "TextAutoGrowWidth", uno::Any( true ) ); + xTextShape->SvxShape::setPropertyValue( "CharHeight", uno::Any( fCharHeight ) ); + xTextShape->SvxShape::setPropertyValue( "CharHeightAsian", uno::Any( fCharHeight ) ); + xTextShape->SvxShape::setPropertyValue( "CharHeightComplex", uno::Any( fCharHeight ) ); + xTextShape->SvxShape::setPropertyValue( "TextVerticalAdjust", uno::Any( drawing::TextVerticalAdjust_CENTER ) ); + xTextShape->SvxShape::setPropertyValue( "TextHorizontalAdjust", uno::Any( drawing::TextHorizontalAdjust_CENTER ) ); + xTextShape->SvxShape::setPropertyValue( "CharFontName", uno::Any( OUString("Albany") ) ); + + xTextShape->setPosition( rPosition ); + + m_aSelection.setSelection( xTextShape ); + m_aSelection.applySelection( m_pDrawViewWrapper.get() ); + + SdrObject* pObj = DrawViewWrapper::getSdrObject( xTextShape ); + if ( pObj ) + { + m_pDrawViewWrapper->BegUndo( SvxResId( RID_SVX_3D_UNDO_EXCHANGE_PASTE ) ); + m_pDrawViewWrapper->AddUndo( std::make_unique<SdrUndoInsertObj>( *pObj ) ); + m_pDrawViewWrapper->EndUndo(); + + impl_switchDiagramPositioningToExcludingPositioning(); + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartController::executeDispatch_Copy() +{ + SolarMutexGuard aSolarGuard; + if (!m_pDrawViewWrapper) + return; + + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + if (pOutlinerView) + pOutlinerView->Copy(); + else + { + SdrObject* pSelectedObj = nullptr; + ObjectIdentifier aSelOID(m_aSelection.getSelectedOID()); + + if (aSelOID.isAutoGeneratedObject()) + pSelectedObj = m_pDrawModelWrapper->getNamedSdrObject( aSelOID.getObjectCID() ); + else if (aSelOID.isAdditionalShape()) + pSelectedObj = DrawViewWrapper::getSdrObject( aSelOID.getAdditionalShape() ); + + if (pSelectedObj) + { + Reference<datatransfer::clipboard::XClipboard> xClipboard(GetChartWindow()->GetClipboard()); + if (xClipboard.is()) + { + Reference< datatransfer::XTransferable > xTransferable( + new ChartTransferable(m_pDrawModelWrapper->getSdrModel(), + pSelectedObj, aSelOID.isAdditionalShape())); + xClipboard->setContents(xTransferable, Reference< datatransfer::clipboard::XClipboardOwner >()); + } + } + } +} + +void ChartController::executeDispatch_Cut() +{ + executeDispatch_Copy(); + executeDispatch_Delete(); +} + +bool ChartController::isObjectDeleteable( const uno::Any& rSelection ) +{ + ObjectIdentifier aSelOID( rSelection ); + if ( aSelOID.isAutoGeneratedObject() ) + { + const OUString& aSelObjCID( aSelOID.getObjectCID() ); + ObjectType aObjectType(ObjectIdentifier::getObjectType( aSelObjCID )); + + switch(aObjectType) + { + case OBJECTTYPE_TITLE: + case OBJECTTYPE_LEGEND: + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_LEGEND_ENTRY: + case OBJECTTYPE_DATA_CURVE_EQUATION: + case OBJECTTYPE_DATA_CURVE: + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_AXIS: + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + return true; + default: + break; + } + } + else if ( aSelOID.isAdditionalShape() ) + { + return true; + } + + return false; +} + +bool ChartController::isShapeContext() const +{ + return m_aSelection.isAdditionalShapeSelected() || + ( m_pDrawViewWrapper && m_pDrawViewWrapper->AreObjectsMarked() && + ( m_pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Text ) ); +} + +void ChartController::impl_ClearSelection() +{ + if( m_aSelection.hasSelection()) + { + m_aSelection.clearSelection(); + impl_notifySelectionChangeListeners(); + } +} + +bool ChartController::executeDispatch_Delete() +{ + bool bReturn = false; + + // remove the selected object + OUString aCID( m_aSelection.getSelectedCID() ); + if( !aCID.isEmpty() ) + { + if( !isObjectDeleteable( uno::Any( aCID ) ) ) + return false; + + //remove chart object + rtl::Reference< ChartModel > xChartDoc = getChartModel(); + if( !xChartDoc.is() ) + return false; + + ObjectType aObjectType( ObjectIdentifier::getObjectType( aCID )); + switch( aObjectType ) + { + case OBJECTTYPE_TITLE: + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_TITLE )), + m_xUndoManager ); + TitleHelper::removeTitle( + ObjectIdentifier::getTitleTypeForCID( aCID ), getChartModel() ); + bReturn = true; + aUndoGuard.commit(); + break; + } + case OBJECTTYPE_LEGEND: + { + rtl::Reference< Diagram > xDiagram( xChartDoc->getFirstChartDiagram()); + if( xDiagram.is()) + { + uno::Reference< beans::XPropertySet > xLegendProp( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xLegendProp.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_LEGEND )), + m_xUndoManager ); + xLegendProp->setPropertyValue( "Show", uno::Any( false )); + bReturn = true; + aUndoGuard.commit(); + } + } + break; + } + + case OBJECTTYPE_DATA_SERIES: + bReturn = lcl_deleteDataSeries( aCID, getChartModel(), m_xUndoManager ); + break; + + case OBJECTTYPE_LEGEND_ENTRY: + { + ObjectType eParentObjectType = ObjectIdentifier::getObjectType( + ObjectIdentifier::getFullParentParticle( aCID )); + if( eParentObjectType == OBJECTTYPE_DATA_SERIES ) + { + bReturn = lcl_deleteDataSeries( aCID, getChartModel(), m_xUndoManager ); + } + else if( eParentObjectType == OBJECTTYPE_DATA_CURVE ) + { + sal_Int32 nEndPos = aCID.lastIndexOf(':'); + OUString aParentCID = aCID.copy(0, nEndPos); + + bReturn = lcl_deleteDataCurve(aParentCID, getChartModel(), m_xUndoManager ); + } + else if( eParentObjectType == OBJECTTYPE_DATA_AVERAGE_LINE ) + { + executeDispatch_DeleteMeanValue(); + bReturn = true; + } + break; + } + + case OBJECTTYPE_DATA_AVERAGE_LINE: + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt( + ObjectIdentifier::getObjectPropertySet( + OUString(ObjectIdentifier::getFullParentParticle( aCID )), getChartModel()), uno::UNO_QUERY ); + if( xRegCurveCnt.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AVERAGE_LINE )), + m_xUndoManager ); + RegressionCurveHelper::removeMeanValueLine( xRegCurveCnt ); + bReturn = true; + aUndoGuard.commit(); + } + } + break; + + case OBJECTTYPE_DATA_CURVE: + { + bReturn = lcl_deleteDataCurve( aCID, getChartModel(), m_xUndoManager ); + } + break; + + case OBJECTTYPE_DATA_CURVE_EQUATION: + { + uno::Reference< beans::XPropertySet > xEqProp( + ObjectIdentifier::getObjectPropertySet( aCID, getChartModel())); + + if( xEqProp.is()) + { + rtl::Reference<::chart::ChartModel> xModel( getChartModel() ); + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + { + ControllerLockGuardUNO aCtlLockGuard( xModel ); + xEqProp->setPropertyValue( "ShowEquation", uno::Any( false )); + xEqProp->setPropertyValue( "XName", uno::Any( OUString("x") )); + xEqProp->setPropertyValue( "YName", uno::Any( OUString("f(x)") )); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( false )); + } + bReturn = true; + aUndoGuard.commit(); + } + } + break; + + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + { + uno::Reference< beans::XPropertySet > xErrorBarProp( + ObjectIdentifier::getObjectPropertySet( aCID, getChartModel() )); + if( xErrorBarProp.is()) + { + TranslateId pId; + + if ( aObjectType == OBJECTTYPE_DATA_ERRORS_X ) + pId = STR_OBJECT_ERROR_BARS_X; + else if ( aObjectType == OBJECTTYPE_DATA_ERRORS_Y ) + pId = STR_OBJECT_ERROR_BARS_Y; + else + pId = STR_OBJECT_ERROR_BARS_Z; + + rtl::Reference<::chart::ChartModel> xModel( getChartModel() ); + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId(pId)), + m_xUndoManager); + { + ControllerLockGuardUNO aCtlLockGuard( xModel ); + xErrorBarProp->setPropertyValue( + "ErrorBarStyle", + uno::Any( css::chart::ErrorBarStyle::NONE )); + } + bReturn = true; + aUndoGuard.commit(); + } + break; + } + + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + { + uno::Reference< beans::XPropertySet > xObjectProperties = + ObjectIdentifier::getObjectPropertySet( aCID, getChartModel() ); + if( xObjectProperties.is() ) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, + SchResId( aObjectType == OBJECTTYPE_DATA_LABEL ? STR_OBJECT_LABEL : STR_OBJECT_DATALABELS )), + m_xUndoManager ); + chart2::DataPointLabel aLabel; + xObjectProperties->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel; + aLabel.ShowNumber = false; + aLabel.ShowNumberInPercent = false; + aLabel.ShowCategoryName = false; + aLabel.ShowLegendSymbol = false; + aLabel.ShowCustomLabel = false; + aLabel.ShowSeriesName = false; + if( aObjectType == OBJECTTYPE_DATA_LABELS ) + { + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( aCID, getChartModel() ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_LABEL, uno::Any(aLabel) ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any() ); + } + else + { + xObjectProperties->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabel)); + xObjectProperties->setPropertyValue(CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any()); + } + bReturn = true; + aUndoGuard.commit(); + } + break; + } + case OBJECTTYPE_AXIS: + { + executeDispatch_DeleteAxis(); + bReturn = true; + break; + } + case OBJECTTYPE_GRID: + { + executeDispatch_DeleteMajorGrid(); + bReturn = true; + break; + } + case OBJECTTYPE_SUBGRID: + { + executeDispatch_DeleteMinorGrid(); + bReturn = true; + break; + } + + default: + { + break; + } + } + } + else + { + //remove additional shape + impl_ClearSelection(); + { + SolarMutexGuard aSolarGuard; + if ( m_pDrawViewWrapper ) + { + m_pDrawViewWrapper->DeleteMarked(); + bReturn = true; + } + } + } + return bReturn; +} + +void ChartController::executeDispatch_ToggleLegend() +{ + rtl::Reference< ChartModel > xModel = getChartModel(); + UndoGuard aUndoGuard( + SchResId( STR_ACTION_TOGGLE_LEGEND ), m_xUndoManager ); + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*xModel); + bool bChanged = false; + if( xLegendProp.is()) + { + try + { + bool bShow = false; + if( xLegendProp->getPropertyValue( "Show") >>= bShow ) + { + xLegendProp->setPropertyValue( "Show", uno::Any( ! bShow )); + bChanged = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + xLegendProp = LegendHelper::getLegend(*xModel, m_xCC, true); + if( xLegendProp.is()) + bChanged = true; + } + + if( bChanged ) + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_ToggleGridHorizontal() +{ + UndoGuard aUndoGuard( + SchResId( STR_ACTION_TOGGLE_GRID_HORZ ), m_xUndoManager ); + rtl::Reference< Diagram > xDiagram( getFirstDiagram() ); + if( !xDiagram.is()) + return; + + sal_Int32 nDimensionIndex = 1; + sal_Int32 nCooSysIndex = 0; + + bool bHasMajorYGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true, xDiagram ); + bool bHasMinorYGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false, xDiagram ); + + if( bHasMajorYGrid ) + { + if ( bHasMinorYGrid ) + { + AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, true, xDiagram ); + AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, false, xDiagram ); + } + else + { + AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, false, xDiagram ); + } + } + else + { + AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, true, xDiagram ); + } + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_ToggleGridVertical() +{ + UndoGuard aUndoGuard( + SchResId( STR_ACTION_TOGGLE_GRID_VERTICAL ), m_xUndoManager ); + rtl::Reference< Diagram > xDiagram( getFirstDiagram() ); + if( !xDiagram.is()) + return; + + sal_Int32 nDimensionIndex = 0; + sal_Int32 nCooSysIndex = 0; + + bool bHasMajorXGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true, xDiagram ); + bool bHasMinorXGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false, xDiagram ); + if( bHasMajorXGrid ) + { + if (bHasMinorXGrid) + { + AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, true, xDiagram ); + AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, false, xDiagram ); + } + else + { + AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, false, xDiagram ); + } + } + else + { + AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, true, xDiagram ); + } + + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_FillColor(sal_uInt32 nColor) +{ + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPointProperties( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + if( xPointProperties.is() ) + xPointProperties->setPropertyValue( "FillColor", uno::Any( nColor ) ); + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "chart2" ); + } +} + +void ChartController::executeDispatch_FillGradient(OUString sJSONGradient) +{ + XGradient aXGradient = XGradient::fromJSON(sJSONGradient); + css::awt::Gradient aGradient = aXGradient.toGradientUNO(); + + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPropSet( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + + if( xPropSet.is() ) + { + OUString aPrefferedName = OUString::number(static_cast<sal_Int32>(aXGradient.GetStartColor())) + + OUString::number(static_cast<sal_Int32>(aXGradient.GetEndColor())) + + OUString::number(static_cast<sal_Int32>(aXGradient.GetAngle().get())); + + OUString aNewName = PropertyHelper::addGradientUniqueNameToTable(css::uno::Any(aGradient), + xChartModel, + aPrefferedName); + + xPropSet->setPropertyValue("FillGradientName", css::uno::Any(aNewName)); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_LineColor(sal_uInt32 nColor) +{ + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPropSet( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference<css::chart2::XDiagram> xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (xDiagram.is()) + xPropSet.set(xDiagram->getWall()); + } + + if( xPropSet.is() ) + xPropSet->setPropertyValue( "LineColor", css::uno::Any( Color(ColorTransparency, nColor) ) ); + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "chart2" ); + } +} + +void ChartController::executeDispatch_LineWidth(sal_uInt32 nWidth) +{ + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPropSet( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference<css::chart2::XDiagram> xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (xDiagram.is()) + xPropSet.set(xDiagram->getWall()); + } + + if( xPropSet.is() ) + xPropSet->setPropertyValue( "LineWidth", css::uno::Any( nWidth ) ); + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "chart2" ); + } +} + +void ChartController::executeDispatch_LOKSetTextSelection(int nType, int nX, int nY) +{ + if (!m_pDrawViewWrapper) + return; + + if (!m_pDrawViewWrapper->IsTextEdit()) + return; + + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + if (!pOutlinerView) + return; + + EditView& rEditView = pOutlinerView->GetEditView(); + Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY)); + switch (nType) + { + case LOK_SETTEXTSELECTION_START: + rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false); + break; + case LOK_SETTEXTSELECTION_END: + rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false); + break; + case LOK_SETTEXTSELECTION_RESET: + rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true); + break; + default: + assert(false); + break; + } +} + +void ChartController::executeDispatch_LOKPieSegmentDragging( int nOffset ) +{ + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPointProperties( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + if( xPointProperties.is() ) + xPointProperties->setPropertyValue( "Offset", uno::Any( nOffset / 100.0 ) ); + } + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::impl_ShapeControllerDispatch( const util::URL& rURL, const Sequence< beans::PropertyValue >& rArgs ) +{ + Reference< frame::XDispatch > xDispatch( m_aDispatchContainer.getShapeController() ); + if ( xDispatch.is() ) + { + xDispatch->dispatch( rURL, rArgs ); + } +} + +void ChartController::impl_switchDiagramPositioningToExcludingPositioning() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::PosSize, + ObjectNameProvider::getName( OBJECTTYPE_DIAGRAM)), + m_xUndoManager ); + if (DiagramHelper::switchDiagramPositioningToExcludingPositioning(*getChartModel(), true, true)) + aUndoGuard.commit(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Window.cxx b/chart2/source/controller/main/ChartController_Window.cxx new file mode 100644 index 000000000..c50749c42 --- /dev/null +++ b/chart2/source/controller/main/ChartController_Window.cxx @@ -0,0 +1,2103 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <ChartController.hxx> +#include <PositionAndSizeHelper.hxx> +#include <ObjectIdentifier.hxx> +#include <ChartWindow.hxx> +#include <ResId.hxx> +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include <ChartType.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <TitleHelper.hxx> +#include "UndoGuard.hxx" +#include <ControllerLockGuard.hxx> +#include <ObjectNameProvider.hxx> +#include <strings.hrc> +#include "DragMethod_PieSegment.hxx" +#include "DragMethod_RotateDiagram.hxx" +#include <ObjectHierarchy.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <RelativePositionHelper.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <RegressionCurveHelper.hxx> +#include <RegressionCurveModel.hxx> +#include <StatisticsHelper.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <LegendHelper.hxx> +#include <servicenames_charttypes.hxx> +#include "DrawCommandDispatch.hxx" +#include <PopupRequest.hxx> +#include "ControllerCommandDispatch.hxx" + +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/RelativeSize.hpp> +#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> + +#include <com/sun/star/awt/PopupMenuDirection.hpp> +#include <com/sun/star/frame/DispatchHelper.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XPopupMenuController.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/awt/Rectangle.hpp> + +#include <comphelper/lok.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> + +#include <sfx2/viewsh.hxx> +#include <svx/ActionDescriptionProvider.hxx> +#include <svx/obj3d.hxx> +#include <svx/scene3d.hxx> +#include <svx/svddrgmt.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/weld.hxx> +#include <vcl/ptrstyle.hxx> +#include <svtools/acceleratorexecute.hxx> +#include <tools/diagnose_ex.h> +#include <toolkit/awt/vclxmenu.hxx> +#include <sal/log.hxx> +#include <o3tl/string_view.hxx> + +#include <boost/property_tree/json_parser.hpp> +#include <sfx2/dispatch.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> + +#define DRGPIX 2 // Drag MinMove in Pixel + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +namespace +{ +bool lcl_GrowAndShiftLogic( + RelativePosition & rInOutRelPos, + RelativeSize & rInOutRelSize, + const awt::Size & rRefSize, + double fGrowLogicX, + double fGrowLogicY ) +{ + if( rRefSize.Width == 0 || + rRefSize.Height == 0 ) + return false; + + double fRelativeGrowX = fGrowLogicX / rRefSize.Width; + double fRelativeGrowY = fGrowLogicY / rRefSize.Height; + + return ::chart::RelativePositionHelper::centerGrow( + rInOutRelPos, rInOutRelSize, + fRelativeGrowX, fRelativeGrowY ); +} + +bool lcl_MoveObjectLogic( + RelativePosition & rInOutRelPos, + RelativeSize const & rObjectSize, + const awt::Size & rRefSize, + double fShiftLogicX, + double fShiftLogicY ) +{ + if( rRefSize.Width == 0 || + rRefSize.Height == 0 ) + return false; + + double fRelativeShiftX = fShiftLogicX / rRefSize.Width; + double fRelativeShiftY = fShiftLogicY / rRefSize.Height; + + return ::chart::RelativePositionHelper::moveObject( + rInOutRelPos, rObjectSize, + fRelativeShiftX, fRelativeShiftY ); +} + +void lcl_insertMenuCommand( + const uno::Reference< awt::XPopupMenu > & xMenu, + sal_Int16 nId, const OUString & rCommand ) +{ + xMenu->insertItem( nId, "", 0, -1 ); + xMenu->setCommand( nId, rCommand ); +} + +OUString lcl_getFormatCommandForObjectCID( std::u16string_view rCID ) +{ + OUString aDispatchCommand( ".uno:FormatSelection" ); + + ObjectType eObjectType = ObjectIdentifier::getObjectType( rCID ); + + switch(eObjectType) + { + case OBJECTTYPE_DIAGRAM: + case OBJECTTYPE_DIAGRAM_WALL: + aDispatchCommand = ".uno:FormatWall"; + break; + case OBJECTTYPE_DIAGRAM_FLOOR: + aDispatchCommand = ".uno:FormatFloor"; + break; + case OBJECTTYPE_PAGE: + aDispatchCommand = ".uno:FormatChartArea"; + break; + case OBJECTTYPE_LEGEND: + aDispatchCommand = ".uno:FormatLegend"; + break; + case OBJECTTYPE_TITLE: + aDispatchCommand = ".uno:FormatTitle"; + break; + case OBJECTTYPE_LEGEND_ENTRY: + aDispatchCommand = ".uno:FormatDataSeries"; + break; + case OBJECTTYPE_AXIS: + case OBJECTTYPE_AXIS_UNITLABEL: + aDispatchCommand = ".uno:FormatAxis"; + break; + case OBJECTTYPE_GRID: + aDispatchCommand = ".uno:FormatMajorGrid"; + break; + case OBJECTTYPE_SUBGRID: + aDispatchCommand = ".uno:FormatMinorGrid"; + break; + case OBJECTTYPE_DATA_LABELS: + aDispatchCommand = ".uno:FormatDataLabels"; + break; + case OBJECTTYPE_DATA_SERIES: + aDispatchCommand = ".uno:FormatDataSeries"; + break; + case OBJECTTYPE_DATA_LABEL: + aDispatchCommand = ".uno:FormatDataLabel"; + break; + case OBJECTTYPE_DATA_POINT: + aDispatchCommand = ".uno:FormatDataPoint"; + break; + case OBJECTTYPE_DATA_AVERAGE_LINE: + aDispatchCommand = ".uno:FormatMeanValue"; + break; + case OBJECTTYPE_DATA_ERRORS_X: + aDispatchCommand = ".uno:FormatXErrorBars"; + break; + case OBJECTTYPE_DATA_ERRORS_Y: + aDispatchCommand = ".uno:FormatYErrorBars"; + break; + case OBJECTTYPE_DATA_ERRORS_Z: + aDispatchCommand = ".uno:FormatZErrorBars"; + break; + case OBJECTTYPE_DATA_CURVE: + aDispatchCommand = ".uno:FormatTrendline"; + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + aDispatchCommand = ".uno:FormatTrendlineEquation"; + break; + case OBJECTTYPE_DATA_STOCK_RANGE: + aDispatchCommand = ".uno:FormatSelection"; + break; + case OBJECTTYPE_DATA_STOCK_LOSS: + aDispatchCommand = ".uno:FormatStockLoss"; + break; + case OBJECTTYPE_DATA_STOCK_GAIN: + aDispatchCommand = ".uno:FormatStockGain"; + break; + default: //OBJECTTYPE_UNKNOWN + break; + } + return aDispatchCommand; +} + +} // anonymous namespace + +// awt::XWindow +void SAL_CALL ChartController::setPosSize( + sal_Int32 X, + sal_Int32 Y, + sal_Int32 Width, + sal_Int32 Height, + sal_Int16 Flags ) +{ + SolarMutexGuard aGuard; + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + auto pChartWindow(GetChartWindow()); + + if(!(xWindow.is() && pChartWindow)) + return; + + Size aLogicSize = pChartWindow->PixelToLogic( Size( Width, Height ), MapMode( MapUnit::Map100thMM ) ); + + //todo: for standalone chart: detect whether we are standalone + //change map mode to fit new size + awt::Size aModelPageSize = ChartModelHelper::getPageSize( getChartModel() ); + sal_Int32 nScaleXNumerator = aLogicSize.Width(); + sal_Int32 nScaleXDenominator = aModelPageSize.Width; + sal_Int32 nScaleYNumerator = aLogicSize.Height(); + sal_Int32 nScaleYDenominator = aModelPageSize.Height; + MapMode aNewMapMode( + MapUnit::Map100thMM, + Point(0,0), + Fraction(nScaleXNumerator, nScaleXDenominator), + Fraction(nScaleYNumerator, nScaleYDenominator) ); + pChartWindow->SetMapMode(aNewMapMode); + pChartWindow->setPosSizePixel( X, Y, Width, Height, static_cast<PosSizeFlags>(Flags) ); + + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + uno::Reference< beans::XPropertySet > xProp( m_xChartView, uno::UNO_QUERY ); + if( xProp.is() ) + { + auto aZoomFactors(::comphelper::InitPropertySequence({ + { "ScaleXNumerator", uno::Any( nScaleXNumerator ) }, + { "ScaleXDenominator", uno::Any( nScaleXDenominator ) }, + { "ScaleYNumerator", uno::Any( nScaleYNumerator ) }, + { "ScaleYDenominator", uno::Any( nScaleYDenominator ) } + })); + xProp->setPropertyValue( "ZoomFactors", uno::Any( aZoomFactors )); + } + + //a correct work area is at least necessary for correct values in the position and size dialog and for dragging area + if(m_pDrawViewWrapper) + { + tools::Rectangle aRect(Point(0,0), pChartWindow->GetOutDev()->GetOutputSize()); + m_pDrawViewWrapper->SetWorkArea( aRect ); + } + pChartWindow->Invalidate(); +} + +awt::Rectangle SAL_CALL ChartController::getPosSize() +{ + //@todo + awt::Rectangle aRet(0, 0, 0, 0); + + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + if(xWindow.is()) + aRet = xWindow->getPosSize(); + + return aRet; +} + +void SAL_CALL ChartController::setVisible( sal_Bool Visible ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->setVisible( Visible ); +} + +void SAL_CALL ChartController::setEnable( sal_Bool Enable ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->setEnable( Enable ); +} + +void SAL_CALL ChartController::setFocus() +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->setFocus(); +} + +void SAL_CALL ChartController::addWindowListener( + const uno::Reference< awt::XWindowListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addWindowListener( xListener ); +} + +void SAL_CALL ChartController::removeWindowListener( + const uno::Reference< awt::XWindowListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeWindowListener( xListener ); +} + +void SAL_CALL ChartController::addFocusListener( + const uno::Reference< awt::XFocusListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addFocusListener( xListener ); +} + +void SAL_CALL ChartController::removeFocusListener( + const uno::Reference< awt::XFocusListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeFocusListener( xListener ); +} + +void SAL_CALL ChartController::addKeyListener( + const uno::Reference< awt::XKeyListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addKeyListener( xListener ); +} + +void SAL_CALL ChartController::removeKeyListener( + const uno::Reference< awt::XKeyListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeKeyListener( xListener ); +} + +void SAL_CALL ChartController::addMouseListener( + const uno::Reference< awt::XMouseListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addMouseListener( xListener ); +} + +void SAL_CALL ChartController::removeMouseListener( + const uno::Reference< awt::XMouseListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeMouseListener( xListener ); +} + +void SAL_CALL ChartController::addMouseMotionListener( + const uno::Reference< awt::XMouseMotionListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addMouseMotionListener( xListener ); +} + +void SAL_CALL ChartController::removeMouseMotionListener( + const uno::Reference< awt::XMouseMotionListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeMouseMotionListener( xListener ); +} + +void SAL_CALL ChartController::addPaintListener( + const uno::Reference< awt::XPaintListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addPaintListener( xListener ); +} + +void SAL_CALL ChartController::removePaintListener( + const uno::Reference< awt::XPaintListener >& xListener ) +{ + //@todo + uno::Reference<awt::XWindow> xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removePaintListener( xListener ); +} + +// impl vcl window controller methods +void ChartController::PrePaint() +{ + // forward VCLs PrePaint window event to DrawingLayer + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + + if (pDrawViewWrapper) + { + pDrawViewWrapper->PrePaint(); + } +} + +void ChartController::execute_Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + try + { + rtl::Reference<ChartModel> xModel(getChartModel()); + //OSL_ENSURE( xModel.is(), "ChartController::execute_Paint: have no model to paint"); + if (!xModel.is()) + return; + + //better performance for big data + uno::Reference<beans::XPropertySet> xProp(m_xChartView, uno::UNO_QUERY); + if (xProp.is()) + { + awt::Size aResolution(1000, 1000); + { + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if (pChartWindow) + { + aResolution.Width = pChartWindow->GetSizePixel().Width(); + aResolution.Height = pChartWindow->GetSizePixel().Height(); + } + } + xProp->setPropertyValue( "Resolution", uno::Any( aResolution )); + } + + uno::Reference< util::XUpdatable > xUpdatable( m_xChartView, uno::UNO_QUERY ); + if (xUpdatable.is()) + xUpdatable->update(); + + { + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + if (pDrawViewWrapper) + pDrawViewWrapper->CompleteRedraw(&rRenderContext, vcl::Region(rRect)); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + catch( ... ) + { + } +} + +static bool isDoubleClick( const MouseEvent& rMEvt ) +{ + return rMEvt.GetClicks() == 2 && rMEvt.IsLeft() && + !rMEvt.IsMod1() && !rMEvt.IsMod2() && !rMEvt.IsShift(); +} + +void ChartController::startDoubleClickWaiting() +{ + SolarMutexGuard aGuard; + + m_bWaitingForDoubleClick = true; + + sal_uInt64 nDblClkTime = 500; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + { + const MouseSettings& rMSettings = pChartWindow->GetSettings().GetMouseSettings(); + nDblClkTime = rMSettings.GetDoubleClickTime(); + } + m_aDoubleClickTimer.SetTimeout( nDblClkTime ); + m_aDoubleClickTimer.Start(); +} + +void ChartController::stopDoubleClickWaiting() +{ + m_aDoubleClickTimer.Stop(); + m_bWaitingForDoubleClick = false; +} + +IMPL_LINK_NOARG(ChartController, DoubleClickWaitingHdl, Timer *, void) +{ + m_bWaitingForDoubleClick = false; + + if( m_bWaitingForMouseUp || !m_aSelection.maybeSwitchSelectionAfterSingleClickWasEnsured() ) + return; + + impl_selectObjectAndNotiy(); + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + { + vcl::Window::PointerState aPointerState( pChartWindow->GetPointerState() ); + MouseEvent aMouseEvent( + aPointerState.maPos, + 1/*nClicks*/, + MouseEventModifiers::NONE, + static_cast< sal_uInt16 >( aPointerState.mnState )/*nButtons*/, + 0/*nModifier*/ ); + impl_SetMousePointer( aMouseEvent ); + } +} + +void ChartController::execute_MouseButtonDown( const MouseEvent& rMEvt ) +{ + SolarMutexGuard aGuard; + + m_bWaitingForMouseUp = true; + m_bFieldButtonDown = false; + + if( isDoubleClick(rMEvt) ) + stopDoubleClickWaiting(); + else + startDoubleClickWaiting(); + + m_aSelection.remindSelectionBeforeMouseDown(); + + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + auto pChartWindow(GetChartWindow()); + if(!pChartWindow || !pDrawViewWrapper ) + return; + + Point aMPos = pChartWindow->PixelToLogic(rMEvt.GetPosPixel()); + + // Check if button was clicked + SdrObject* pObject = pDrawViewWrapper->getHitObject(aMPos); + if (pObject) + { + OUString aCID = pObject->GetName(); + if (aCID.startsWith("FieldButton")) + { + m_bFieldButtonDown = true; + return; // Don't take any action if button was clicked + } + } + + if ( rMEvt.GetButtons() == MOUSE_LEFT ) + { + pChartWindow->GrabFocus(); + pChartWindow->CaptureMouse(); + } + + if( pDrawViewWrapper->IsTextEdit() ) + { + SdrViewEvent aVEvt; + if ( pDrawViewWrapper->IsTextEditHit( aMPos ) || + // #i12587# support for shapes in chart + ( rMEvt.IsRight() && pDrawViewWrapper->PickAnything( rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt ) == SdrHitKind::MarkedObject ) ) + { + pDrawViewWrapper->MouseButtonDown(rMEvt, pChartWindow->GetOutDev()); + return; + } + else + { + EndTextEdit(); + } + } + + //abort running action + if( pDrawViewWrapper->IsAction() ) + { + if( rMEvt.IsRight() ) + pDrawViewWrapper->BckAction(); + return; + } + + if( isDoubleClick(rMEvt) ) //do not change selection if double click + return;//double click is handled further in mousebutton up + + SdrHdl* pHitSelectionHdl = nullptr; + //switch from move to resize if handle is hit on a resizable object + if( m_aSelection.isResizeableObjectSelected() ) + pHitSelectionHdl = pDrawViewWrapper->PickHandle( aMPos ); + //only change selection if no selection handles are hit + if( !pHitSelectionHdl ) + { + // #i12587# support for shapes in chart + if ( m_eDrawMode == CHARTDRAW_INSERT && + ( !pDrawViewWrapper->IsMarkedHit( aMPos ) || !m_aSelection.isDragableObjectSelected() ) ) + { + if ( m_aSelection.hasSelection() ) + { + m_aSelection.clearSelection(); + } + if ( !pDrawViewWrapper->IsAction() ) + { + if ( pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Caption ) + { + Size aCaptionSize( 2268, 1134 ); + pDrawViewWrapper->BegCreateCaptionObj( aMPos, aCaptionSize ); + } + else + { + pDrawViewWrapper->BegCreateObj( aMPos); + } + SdrObject* pObj = pDrawViewWrapper->GetCreateObj(); + DrawCommandDispatch* pDrawCommandDispatch = m_aDispatchContainer.getDrawCommandDispatch(); + if ( pObj && m_pDrawModelWrapper && pDrawCommandDispatch ) + { + SfxItemSet aSet( m_pDrawModelWrapper->GetItemPool() ); + pDrawCommandDispatch->setAttributes( pObj ); + pDrawCommandDispatch->setLineEnds( aSet ); + pObj->SetMergedItemSet( aSet ); + } + } + impl_SetMousePointer( rMEvt ); + return; + } + + m_aSelection.adaptSelectionToNewPos( + aMPos, + pDrawViewWrapper, + rMEvt.IsRight(), + m_bWaitingForDoubleClick ); + + if( !m_aSelection.isRotateableObjectSelected( getChartModel() ) ) + { + m_eDragMode = SdrDragMode::Move; + pDrawViewWrapper->SetDragMode(m_eDragMode); + } + + m_aSelection.applySelection(pDrawViewWrapper); + } + if( m_aSelection.isDragableObjectSelected() + && !rMEvt.IsRight() ) + { + //start drag + sal_uInt16 nDrgLog = static_cast<sal_uInt16>(pChartWindow->PixelToLogic(Size(DRGPIX,0)).Width()); + SdrDragMethod* pDragMethod = nullptr; + + //change selection to 3D scene if rotate mode + SdrDragMode eDragMode = pDrawViewWrapper->GetDragMode(); + if( eDragMode==SdrDragMode::Rotate ) + { + E3dScene* pScene = SelectionHelper::getSceneToRotate( pDrawViewWrapper->getNamedSdrObject( m_aSelection.getSelectedCID() ) ); + if( pScene ) + { + DragMethod_RotateDiagram::RotationDirection eRotationDirection(DragMethod_RotateDiagram::ROTATIONDIRECTION_FREE); + if(pHitSelectionHdl) + { + SdrHdlKind eKind = pHitSelectionHdl->GetKind(); + if( eKind==SdrHdlKind::Upper || eKind==SdrHdlKind::Lower ) + eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_X; + else if( eKind==SdrHdlKind::Left || eKind==SdrHdlKind::Right ) + eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_Y; + else if( eKind==SdrHdlKind::UpperLeft || eKind==SdrHdlKind::UpperRight || eKind==SdrHdlKind::LowerLeft || eKind==SdrHdlKind::LowerRight ) + eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_Z; + } + pDragMethod = new DragMethod_RotateDiagram( *pDrawViewWrapper, m_aSelection.getSelectedCID(), getChartModel(), eRotationDirection ); + } + } + else + { + std::u16string_view aDragMethodServiceName( ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) ); + if( aDragMethodServiceName == ObjectIdentifier::getPieSegmentDragMethodServiceName() ) + pDragMethod = new DragMethod_PieSegment( *pDrawViewWrapper, m_aSelection.getSelectedCID(), getChartModel() ); + } + pDrawViewWrapper->SdrView::BegDragObj(aMPos, nullptr, pHitSelectionHdl, nDrgLog, pDragMethod); + } + + impl_SetMousePointer( rMEvt ); +} + +void ChartController::execute_MouseMove( const MouseEvent& rMEvt ) +{ + SolarMutexGuard aGuard; + + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + auto pChartWindow(GetChartWindow()); + if(!pChartWindow || !pDrawViewWrapper) + return; + + if( m_pDrawViewWrapper->IsTextEdit() ) + { + if( m_pDrawViewWrapper->MouseMove(rMEvt,pChartWindow->GetOutDev()) ) + return; + } + + if(pDrawViewWrapper->IsAction()) + { + pDrawViewWrapper->MovAction( pChartWindow->PixelToLogic( rMEvt.GetPosPixel() ) ); + } + + impl_SetMousePointer( rMEvt ); +} + +void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt ) +{ + ControllerLockGuardUNO aCLGuard( getChartModel() ); + bool bMouseUpWithoutMouseDown = !m_bWaitingForMouseUp; + m_bWaitingForMouseUp = false; + bool bNotifySelectionChange = false; + { + SolarMutexGuard aGuard; + + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + auto pChartWindow(GetChartWindow()); + if(!pChartWindow || !pDrawViewWrapper) + return; + + Point aMPos = pChartWindow->PixelToLogic(rMEvt.GetPosPixel()); + + // Check if button was clicked + if (m_bFieldButtonDown) + { + m_bFieldButtonDown = false; + SdrObject* pObject = pDrawViewWrapper->getHitObject(aMPos); + if (pObject) + { + OUString aCID = pObject->GetName(); + if (aCID.startsWith("FieldButton")) + { + sendPopupRequest(aCID, pObject->GetCurrentBoundRect()); + return; + } + } + } + + if(pDrawViewWrapper->IsTextEdit()) + { + if( pDrawViewWrapper->MouseButtonUp(rMEvt,pChartWindow->GetOutDev()) ) + return; + } + + // #i12587# support for shapes in chart + if ( m_eDrawMode == CHARTDRAW_INSERT && pDrawViewWrapper->IsCreateObj() ) + { + pDrawViewWrapper->EndCreateObj( SdrCreateCmd::ForceEnd ); + { + HiddenUndoContext aUndoContext( m_xUndoManager ); + // don't want the positioning Undo action to appear in the UI + impl_switchDiagramPositioningToExcludingPositioning(); + } + if ( pDrawViewWrapper->AreObjectsMarked() ) + { + if ( pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Text ) + { + executeDispatch_EditText(); + } + else + { + SdrObject* pObj = pDrawViewWrapper->getSelectedObject(); + if ( pObj ) + { + uno::Reference< drawing::XShape > xShape( pObj->getUnoShape(), uno::UNO_QUERY ); + if ( xShape.is() ) + { + m_aSelection.setSelection( xShape ); + m_aSelection.applySelection( pDrawViewWrapper ); + } + } + } + } + else + { + m_aSelection.adaptSelectionToNewPos( aMPos, pDrawViewWrapper, rMEvt.IsRight(), m_bWaitingForDoubleClick ); + m_aSelection.applySelection( pDrawViewWrapper ); + setDrawMode( CHARTDRAW_SELECT ); + } + } + else if ( pDrawViewWrapper->IsDragObj() ) + { + bool bDraggingDone = false; + SdrDragMethod* pDragMethod = pDrawViewWrapper->SdrView::GetDragMethod(); + bool bIsMoveOnly = pDragMethod && pDragMethod->getMoveOnly(); + DragMethod_Base* pChartDragMethod = dynamic_cast< DragMethod_Base* >(pDragMethod); + if( pChartDragMethod ) + { + UndoGuard aUndoGuard( pChartDragMethod->getUndoDescription(), + m_xUndoManager ); + + if( pDrawViewWrapper->EndDragObj() ) + { + bDraggingDone = true; + aUndoGuard.commit(); + } + } + + if( !bDraggingDone && pDrawViewWrapper->EndDragObj() ) + { + try + { + //end move or size + SdrObject* pObj = pDrawViewWrapper->getSelectedObject(); + if( pObj ) + { + tools::Rectangle aObjectRect = pObj->GetSnapRect(); + tools::Rectangle aOldObjectRect = pObj->GetLastBoundRect(); + awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) ); + tools::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height ); + + const E3dObject* pE3dObject(dynamic_cast< const E3dObject*>(pObj)); + if(nullptr != pE3dObject) + { + E3dScene* pScene(pE3dObject->getRootE3dSceneFromE3dObject()); + if(nullptr != pScene) + { + aObjectRect = pScene->GetSnapRect(); + } + } + + ActionDescriptionProvider::ActionType eActionType(ActionDescriptionProvider::ActionType::Move); + if( !bIsMoveOnly && m_aSelection.isResizeableObjectSelected() ) + eActionType = ActionDescriptionProvider::ActionType::Resize; + + ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() ); + + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( eActionType, ObjectNameProvider::getName( eObjectType)), + m_xUndoManager ); + + bool bChanged = false; + rtl::Reference< ChartModel > xModel = getChartModel(); + if ( eObjectType == OBJECTTYPE_LEGEND ) + bChanged = DiagramHelper::switchDiagramPositioningToExcludingPositioning( *xModel, false , true ); + + bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID() + , xModel + , awt::Rectangle(aObjectRect.Left(),aObjectRect.Top(),aObjectRect.getWidth(),aObjectRect.getHeight()) + , awt::Rectangle(aOldObjectRect.Left(), aOldObjectRect.Top(), 0, 0) + , awt::Rectangle(aPageRect.Left(),aPageRect.Top(),aPageRect.getWidth(),aPageRect.getHeight()) ); + + if( bMoved || bChanged ) + { + bDraggingDone = true; + aUndoGuard.commit(); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + //all wanted model changes will take effect + //and all unwanted view modifications are cleaned + } + + if( !bDraggingDone ) //mouse wasn't moved while dragging + { + bool bClickedTwiceOnDragableObject = SelectionHelper::isDragableObjectHitTwice( aMPos, m_aSelection.getSelectedCID(), *pDrawViewWrapper ); + bool bIsRotateable = m_aSelection.isRotateableObjectSelected( getChartModel() ); + + //toggle between move and rotate + if( bIsRotateable && bClickedTwiceOnDragableObject && m_eDragMode==SdrDragMode::Move ) + m_eDragMode=SdrDragMode::Rotate; + else + m_eDragMode=SdrDragMode::Move; + + pDrawViewWrapper->SetDragMode(m_eDragMode); + + if( !m_bWaitingForDoubleClick && m_aSelection.maybeSwitchSelectionAfterSingleClickWasEnsured() ) + { + impl_selectObjectAndNotiy(); + } + } + else + m_aSelection.resetPossibleSelectionAfterSingleClickWasEnsured(); + } + + //@todo ForcePointer(&rMEvt); + pChartWindow->ReleaseMouse(); + + // In tiled rendering drag mode could be not yet over on the call + // that should handle the double-click, so better to perform this check + // always. + if( isDoubleClick(rMEvt) && !bMouseUpWithoutMouseDown /*#i106966#*/ ) + { + Point aMousePixel = rMEvt.GetPosPixel(); + execute_DoubleClick( &aMousePixel ); + } + + if( m_aSelection.isSelectionDifferentFromBeforeMouseDown() ) + bNotifySelectionChange = true; + } + + impl_SetMousePointer( rMEvt ); + + if(bNotifySelectionChange) + impl_notifySelectionChangeListeners(); +} + +void ChartController::execute_DoubleClick( const Point* pMousePixel ) +{ + const SfxViewShell* pViewShell = SfxViewShell::Current(); + bool isMobilePhone = pViewShell && pViewShell->isLOKMobilePhone(); + if (isMobilePhone) + return; + + bool bEditText = false; + if ( m_aSelection.hasSelection() ) + { + OUString aCID( m_aSelection.getSelectedCID() ); + if ( !aCID.isEmpty() ) + { + ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID ); + if ( eObjectType == OBJECTTYPE_TITLE ) + { + bEditText = true; + } + } + else + { + // #i12587# support for shapes in chart + SdrObject* pObj = DrawViewWrapper::getSdrObject( m_aSelection.getSelectedAdditionalShape() ); + if ( dynamic_cast< const SdrTextObj* >(pObj) != nullptr ) + { + bEditText = true; + } + } + } + + if ( bEditText ) + { + executeDispatch_EditText( pMousePixel ); + } + else + { + executeDispatch_ObjectProperties(); + } +} + +void ChartController::execute_Resize() +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if(pChartWindow) + pChartWindow->Invalidate(); +} + +void ChartController::execute_Command( const CommandEvent& rCEvt ) +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + bool bIsAction = false; + { + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + if(!pChartWindow || !pDrawViewWrapper) + return; + bIsAction = m_pDrawViewWrapper->IsAction(); + } + + // pop-up menu + if(rCEvt.GetCommand() == CommandEventId::ContextMenu && !bIsAction) + { + { + if(pChartWindow) + pChartWindow->ReleaseMouse(); + } + + if( m_aSelection.isSelectionDifferentFromBeforeMouseDown() ) + impl_notifySelectionChangeListeners(); + + rtl::Reference< VCLXPopupMenu > xPopupMenu = new VCLXPopupMenu(); + + Point aPos( rCEvt.GetMousePosPixel() ); + if( !rCEvt.IsMouseEvent() ) + { + if(pChartWindow) + aPos = pChartWindow->GetPointerState().maPos; + } + + OUString aMenuName; + if ( isShapeContext() ) + // #i12587# support for shapes in chart + aMenuName = m_pDrawViewWrapper->IsTextEdit() ? std::u16string_view( u"drawtext" ) : std::u16string_view( u"draw" ); + else + { + // todo: the context menu should be specified by an xml file in uiconfig + sal_Int16 nUniqueId = 1; + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Cut" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Copy" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Paste" ); + xPopupMenu->insertSeparator( -1 ); + + ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() ); + rtl::Reference< Diagram > xDiagram = getFirstDiagram(); + + OUString aFormatCommand( lcl_getFormatCommandForObjectCID( m_aSelection.getSelectedCID() ) ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, aFormatCommand ); + + //some commands for dataseries and points: + + if( eObjectType == OBJECTTYPE_DATA_SERIES || eObjectType == OBJECTTYPE_DATA_POINT ) + { + bool bIsPoint = ( eObjectType == OBJECTTYPE_DATA_POINT ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + rtl::Reference< RegressionCurveModel > xTrendline = RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries ); + bool bHasEquation = RegressionCurveHelper::hasEquation( xTrendline ); + rtl::Reference< RegressionCurveModel > xMeanValue = RegressionCurveHelper::getMeanValueLine( xSeries ); + bool bHasYErrorBars = StatisticsHelper::hasErrorBars( xSeries ); + bool bHasXErrorBars = StatisticsHelper::hasErrorBars( xSeries, false ); + bool bHasDataLabelsAtSeries = DataSeriesHelper::hasDataLabelsAtSeries( xSeries ); + bool bHasDataLabelsAtPoints = DataSeriesHelper::hasDataLabelsAtPoints( xSeries ); + bool bHasDataLabelAtPoint = false; + sal_Int32 nPointIndex = -1; + if( bIsPoint ) + { + nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( m_aSelection.getSelectedCID() ); + bHasDataLabelAtPoint = DataSeriesHelper::hasDataLabelAtPoint( xSeries, nPointIndex ); + } + bool bSelectedPointIsFormatted = false; + bool bHasFormattedDataPointsOtherThanSelected = false; + + if( xSeries.is() ) + { + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + if( aAttributedDataPointIndexList.hasElements() ) + { + if( bIsPoint ) + { + auto aIt = std::find( std::as_const(aAttributedDataPointIndexList).begin(), std::as_const(aAttributedDataPointIndexList).end(), nPointIndex ); + if( aIt != std::as_const(aAttributedDataPointIndexList).end()) + bSelectedPointIsFormatted = true; + else + bHasFormattedDataPointsOtherThanSelected = true; + } + else + bHasFormattedDataPointsOtherThanSelected = true; + } + } + } + + if( bIsPoint ) + { + if( bHasDataLabelAtPoint ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataLabel" ); + if( !bHasDataLabelAtPoint ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertDataLabel" ); + else + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteDataLabel" ); + if( bSelectedPointIsFormatted ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:ResetDataPoint" ); + + xPopupMenu->insertSeparator( -1 ); + + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataSeries" ); + } + + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) ); + if( xChartType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + try + { + bool bJapaneseStyle = false; + xChartType->getPropertyValue( "Japanese" ) >>= bJapaneseStyle; + + if( bJapaneseStyle ) + { + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockLoss" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockGain" ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if( bHasDataLabelsAtSeries ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataLabels" ); + if( bHasEquation ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatTrendlineEquation" ); + if( xMeanValue.is() ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMeanValue" ); + if( bHasXErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatXErrorBars" ); + if( bHasYErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatYErrorBars" ); + + xPopupMenu->insertSeparator( -1 ); + + if( !bHasDataLabelsAtSeries ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertDataLabels" ); + + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendline" ); + + if( !xMeanValue.is() ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMeanValue" ); + if( !bHasXErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertXErrorBars" ); + if( !bHasYErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertYErrorBars" ); + if( bHasDataLabelsAtSeries || ( bHasDataLabelsAtPoints && bHasFormattedDataPointsOtherThanSelected ) ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteDataLabels" ); + if( bHasEquation ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendlineEquation" ); + if( xMeanValue.is() ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMeanValue" ); + if( bHasXErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteXErrorBars" ); + if( bHasYErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteYErrorBars" ); + + if( bHasFormattedDataPointsOtherThanSelected ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:ResetAllDataPoints" ); + + xPopupMenu->insertSeparator( -1 ); + + lcl_insertMenuCommand( xPopupMenu, nUniqueId, ".uno:ArrangeRow" ); + rtl::Reference< VCLXPopupMenu > xArrangePopupMenu = new VCLXPopupMenu(); + sal_Int16 nSubId = nUniqueId + 1; + lcl_insertMenuCommand( xArrangePopupMenu, nSubId++, ".uno:Forward" ); + lcl_insertMenuCommand( xArrangePopupMenu, nSubId, ".uno:Backward" ); + xPopupMenu->setPopupMenu( nUniqueId, xArrangePopupMenu ); + nUniqueId = nSubId; + ++nUniqueId; + } + else if( eObjectType == OBJECTTYPE_DATA_CURVE ) + { + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendline" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatTrendlineEquation" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendlineEquation" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendlineEquationAndR2" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertR2Value" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendlineEquation" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteR2Value" ); + } + else if( eObjectType == OBJECTTYPE_DATA_CURVE_EQUATION ) + { + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertR2Value" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteR2Value" ); + } + + //some commands for axes: and grids + + else if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_GRID || eObjectType == OBJECTTYPE_SUBGRID ) + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() && xDiagram.is() ) + { + sal_Int32 nDimensionIndex = -1; + sal_Int32 nCooSysIndex = -1; + sal_Int32 nAxisIndex = -1; + AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ); + bool bIsSecondaryAxis = nAxisIndex!=0; + bool bIsAxisVisible = AxisHelper::isAxisVisible( xAxis ); + bool bIsMajorGridVisible = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true /*bMainGrid*/, xDiagram ); + bool bIsMinorGridVisible = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false /*bMainGrid*/, xDiagram ); + bool bHasTitle = !TitleHelper::getCompleteString( xAxis->getTitleObject() ).isEmpty(); + + if( eObjectType != OBJECTTYPE_AXIS && bIsAxisVisible ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatAxis" ); + if( eObjectType != OBJECTTYPE_GRID && bIsMajorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMajorGrid" ); + if( eObjectType != OBJECTTYPE_SUBGRID && bIsMinorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMinorGrid" ); + + xPopupMenu->insertSeparator( -1 ); + + if( eObjectType != OBJECTTYPE_AXIS && !bIsAxisVisible ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertAxis" ); + if( eObjectType != OBJECTTYPE_GRID && !bIsMajorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMajorGrid" ); + if( eObjectType != OBJECTTYPE_SUBGRID && !bIsMinorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMinorGrid" ); + if( !bHasTitle ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertAxisTitle" ); + + if( bIsAxisVisible ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteAxis" ); + if( bIsMajorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMajorGrid" ); + if( bIsMinorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMinorGrid" ); + } + } + + if( eObjectType == OBJECTTYPE_DATA_STOCK_LOSS ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockGain" ); + else if( eObjectType == OBJECTTYPE_DATA_STOCK_GAIN ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockLoss" ); + + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:TransformDialog" ); + + if( eObjectType == OBJECTTYPE_PAGE || eObjectType == OBJECTTYPE_DIAGRAM + || eObjectType == OBJECTTYPE_DIAGRAM_WALL + || eObjectType == OBJECTTYPE_DIAGRAM_FLOOR + || eObjectType == OBJECTTYPE_UNKNOWN ) + { + if( eObjectType != OBJECTTYPE_UNKNOWN ) + xPopupMenu->insertSeparator( -1 ); + bool bHasLegend = LegendHelper::hasLegend( xDiagram ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTitles" ); + if( !bHasLegend ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertLegend" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertRemoveAxes" ); + if( bHasLegend ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteLegend" ); + } + + xPopupMenu->insertSeparator( -1 ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DiagramType" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DataRanges" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DiagramData" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:View3D" ); + } + + css::uno::Sequence< css::uno::Any > aArgs{ + css::uno::Any(comphelper::makePropertyValue( "IsContextMenu", true )), + css::uno::Any(comphelper::makePropertyValue( "Frame", m_xFrame )), + css::uno::Any(comphelper::makePropertyValue( "Value", aMenuName )) + }; + + css::uno::Reference< css::frame::XPopupMenuController > xPopupController( + m_xCC->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.framework.ResourceMenuController", aArgs, m_xCC ), css::uno::UNO_QUERY ); + + if ( !xPopupController.is() || !xPopupMenu.is() ) + return; + + xPopupController->setPopupMenu( xPopupMenu ); + + if (comphelper::LibreOfficeKit::isActive()) + { + if (SfxViewShell* pViewShell = SfxViewShell::Current()) + { + ControllerCommandDispatch* pCommandDispatch = dynamic_cast<ControllerCommandDispatch*>(m_aDispatchContainer.getChartDispatcher().get()); + if (pCommandDispatch) + { + for (int nPos = 0, nCount = xPopupMenu->getItemCount(); nPos < nCount; ++nPos) + { + auto nItemId = xPopupMenu->getItemId(nPos); + OUString aCommandURL = xPopupMenu->getCommand(nItemId); + if (!pCommandDispatch->commandAvailable(aCommandURL)) + xPopupMenu->enableItem(nItemId, false); + } + } + + boost::property_tree::ptree aMenu = SfxDispatcher::fillPopupMenu(xPopupMenu); + boost::property_tree::ptree aRoot; + aRoot.add_child("menu", aMenu); + + std::stringstream aStream; + boost::property_tree::write_json(aStream, aRoot, true); + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, aStream.str().c_str()); + } + } + else + { + xPopupMenu->execute( css::uno::Reference< css::awt::XWindowPeer >( m_xFrame->getContainerWindow(), css::uno::UNO_QUERY ), + css::awt::Rectangle( aPos.X(), aPos.Y(), 0, 0 ), + css::awt::PopupMenuDirection::EXECUTE_DEFAULT ); + } + + css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + } + else if( ( rCEvt.GetCommand() == CommandEventId::StartExtTextInput ) || + ( rCEvt.GetCommand() == CommandEventId::ExtTextInput ) || + ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput ) || + ( rCEvt.GetCommand() == CommandEventId::InputContextChange ) ) + { + //#i84417# enable editing with IME + m_pDrawViewWrapper->Command( rCEvt, pChartWindow ); + } +} + +bool ChartController::execute_KeyInput( const KeyEvent& rKEvt ) +{ + SolarMutexGuard aGuard; + bool bReturn=false; + + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + auto pChartWindow(GetChartWindow()); + if (!pChartWindow || !pDrawViewWrapper) + return bReturn; + + // handle accelerators + if (!m_apAccelExecute && m_xFrame.is() && m_xCC.is()) + { + m_apAccelExecute = ::svt::AcceleratorExecute::createAcceleratorHelper(); + OSL_ASSERT(m_apAccelExecute); + if (m_apAccelExecute) + m_apAccelExecute->init( m_xCC, m_xFrame ); + } + + vcl::KeyCode aKeyCode( rKEvt.GetKeyCode()); + sal_uInt16 nCode = aKeyCode.GetCode(); + bool bAlternate = aKeyCode.IsMod2(); + bool bCtrl = aKeyCode.IsMod1(); + + if (m_apAccelExecute) + bReturn = m_apAccelExecute->execute( aKeyCode ); + if( bReturn ) + return bReturn; + + { + if( pDrawViewWrapper->IsTextEdit() ) + { + if( pDrawViewWrapper->KeyInput(rKEvt, pChartWindow) ) + { + bReturn = true; + if( nCode == KEY_ESCAPE ) + { + EndTextEdit(); + } + } + } + } + + // keyboard accessibility + ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() ); + if( ! bReturn ) + { + // Navigation (Tab/F3/Home/End) + rtl::Reference<::chart::ChartModel> xChartDoc( getChartModel() ); + ObjectKeyNavigation aObjNav( m_aSelection.getSelectedOID(), xChartDoc, comphelper::getFromUnoTunnel<ExplicitValueProvider>( m_xChartView )); + awt::KeyEvent aKeyEvent( ::svt::AcceleratorExecute::st_VCLKey2AWTKey( aKeyCode )); + bReturn = aObjNav.handleKeyEvent( aKeyEvent ); + if( bReturn ) + { + const ObjectIdentifier& aNewOID = aObjNav.getCurrentSelection(); + uno::Any aNewSelection; + if ( aNewOID.isValid() && !ObjectHierarchy::isRootNode( aNewOID ) ) + { + aNewSelection = aNewOID.getAny(); + } + if ( m_eDragMode == SdrDragMode::Rotate && !SelectionHelper::isRotateableObject( aNewOID.getObjectCID(), getChartModel() ) ) + { + m_eDragMode = SdrDragMode::Move; + } + bReturn = select( aNewSelection ); + } + } + + // Position and Size (+/-/arrow-keys) or pie segment dragging + if( ! bReturn ) + { + // pie segment dragging + // note: could also be done for data series + if( eObjectType == OBJECTTYPE_DATA_POINT && + ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) == + ObjectIdentifier::getPieSegmentDragMethodServiceName()) + { + bool bDrag = false; + bool bDragInside = false; + if( nCode == KEY_ADD || + nCode == KEY_SUBTRACT ) + { + bDrag = true; + bDragInside = ( nCode == KEY_SUBTRACT ); + } + else if( + nCode == KEY_LEFT || + nCode == KEY_RIGHT || + nCode == KEY_UP || + nCode == KEY_DOWN ) + { + bDrag = true; + std::u16string_view aParameter( ObjectIdentifier::getDragParameterString( m_aSelection.getSelectedCID() )); + sal_Int32 nOffsetPercentDummy( 0 ); + awt::Point aMinimumPosition( 0, 0 ); + awt::Point aMaximumPosition( 0, 0 ); + ObjectIdentifier::parsePieSegmentDragParameterString( + aParameter, nOffsetPercentDummy, aMinimumPosition, aMaximumPosition ); + aMaximumPosition.Y -= aMinimumPosition.Y; + aMaximumPosition.X -= aMinimumPosition.X; + + bDragInside = + (nCode == KEY_RIGHT && (aMaximumPosition.X < 0)) || + (nCode == KEY_LEFT && (aMaximumPosition.X > 0)) || + (nCode == KEY_DOWN && (aMaximumPosition.Y < 0)) || + (nCode == KEY_UP && (aMaximumPosition.Y > 0)); + } + + if( bDrag ) + { + double fAmount = bAlternate ? 0.01 : 0.05; + if( bDragInside ) + fAmount *= -1.0; + + bReturn = impl_DragDataPoint( m_aSelection.getSelectedCID(), fAmount ); + } + } + else + { + // size + if( nCode == KEY_ADD || + nCode == KEY_SUBTRACT ) + { + if( eObjectType == OBJECTTYPE_DIAGRAM ) + { + // default 1 mm in each direction + double fGrowAmountX = 200.0; + double fGrowAmountY = 200.0; + if (bAlternate) + { + // together with Alt-key: 1 px in each direction + Size aPixelSize = pChartWindow->PixelToLogic( Size( 2, 2 )); + fGrowAmountX = static_cast< double >( aPixelSize.Width()); + fGrowAmountY = static_cast< double >( aPixelSize.Height()); + } + if( nCode == KEY_SUBTRACT ) + { + fGrowAmountX = -fGrowAmountX; + fGrowAmountY = -fGrowAmountY; + } + bReturn = impl_moveOrResizeObject( + m_aSelection.getSelectedCID(), CENTERED_RESIZE_OBJECT, fGrowAmountX, fGrowAmountY ); + } + } + // position + else if( nCode == KEY_LEFT || + nCode == KEY_RIGHT || + nCode == KEY_UP || + nCode == KEY_DOWN ) + { + if( m_aSelection.isDragableObjectSelected() ) + { + // default 1 mm + double fShiftAmountX = 100.0; + double fShiftAmountY = 100.0; + if (bAlternate) + { + // together with Alt-key: 1 px + Size aPixelSize = pChartWindow->PixelToLogic( Size( 1, 1 )); + fShiftAmountX = static_cast< double >( aPixelSize.Width()); + fShiftAmountY = static_cast< double >( aPixelSize.Height()); + } + switch( nCode ) + { + case KEY_LEFT: + fShiftAmountX = -fShiftAmountX; + fShiftAmountY = 0.0; + break; + case KEY_RIGHT: + fShiftAmountY = 0.0; + break; + case KEY_UP: + fShiftAmountX = 0.0; + fShiftAmountY = -fShiftAmountY; + break; + case KEY_DOWN: + fShiftAmountX = 0.0; + break; + } + if( !m_aSelection.getSelectedCID().isEmpty() ) + { + //move chart objects + if (eObjectType == OBJECTTYPE_DATA_LABEL) + { + SdrObject* pObj = pDrawViewWrapper->getSelectedObject(); + if (pObj) + { + tools::Rectangle aRect = pObj->GetSnapRect(); + awt::Size aPageSize(ChartModelHelper::getPageSize(getChartModel())); + if ((fShiftAmountX > 0.0 && (aRect.Right() + fShiftAmountX > aPageSize.Width)) || + (fShiftAmountX < 0.0 && (aRect.Left() + fShiftAmountX < 0)) || + (fShiftAmountY > 0.0 && (aRect.Bottom() + fShiftAmountY > aPageSize.Height)) || + (fShiftAmountY < 0.0 && (aRect.Top() + fShiftAmountY < 0))) + bReturn = false; + else + bReturn = PositionAndSizeHelper::moveObject( + m_aSelection.getSelectedCID(), getChartModel(), + awt::Rectangle(aRect.Left() + fShiftAmountX, aRect.Top() + fShiftAmountY, aRect.getWidth(), aRect.getHeight()), + awt::Rectangle(aRect.Left(), aRect.Top(), 0, 0), + awt::Rectangle(0, 0, aPageSize.Width, aPageSize.Height)); + } + } + else + bReturn = impl_moveOrResizeObject( + m_aSelection.getSelectedCID(), MOVE_OBJECT, fShiftAmountX, fShiftAmountY ); + } + else + { + //move additional shapes + uno::Reference< drawing::XShape > xShape( m_aSelection.getSelectedAdditionalShape() ); + if( xShape.is() ) + { + awt::Point aPos( xShape->getPosition() ); + awt::Size aSize( xShape->getSize() ); + awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) ); + aPos.X = static_cast< tools::Long >( static_cast< double >( aPos.X ) + fShiftAmountX ); + aPos.Y = static_cast< tools::Long >( static_cast< double >( aPos.Y ) + fShiftAmountY ); + if( aPos.X + aSize.Width > aPageSize.Width ) + aPos.X = aPageSize.Width - aSize.Width; + if( aPos.X < 0 ) + aPos.X = 0; + if( aPos.Y + aSize.Height > aPageSize.Height ) + aPos.Y = aPageSize.Height - aSize.Height; + if( aPos.Y < 0 ) + aPos.Y = 0; + + xShape->setPosition( aPos ); + } + } + } + } + } + } + + // dumping the shape + if( !bReturn && bCtrl && nCode == KEY_F12) + { + rtl::Reference< ChartModel > xChartModel = getChartModel(); + if(xChartModel.is()) + { + OUString aDump = xChartModel->dump(); + SAL_WARN("chart2", aDump); + } + } + + // text edit + if( ! bReturn && + nCode == KEY_F2 ) + { + if( eObjectType == OBJECTTYPE_TITLE ) + { + executeDispatch_EditText(); + bReturn = true; + } + } + + // deactivate inplace mode (this code should be unnecessary, but + // unfortunately is not) + if( ! bReturn && + nCode == KEY_ESCAPE ) + { + uno::Reference< frame::XDispatchHelper > xDispatchHelper( frame::DispatchHelper::create(m_xCC) ); + uno::Sequence< beans::PropertyValue > aArgs; + xDispatchHelper->executeDispatch( + uno::Reference< frame::XDispatchProvider >( m_xFrame, uno::UNO_QUERY ), + ".uno:TerminateInplaceActivation", + "_parent", + frame::FrameSearchFlag::PARENT, + aArgs ); + bReturn = true; + } + + if( ! bReturn && + (nCode == KEY_DELETE || nCode == KEY_BACKSPACE )) + { + bReturn = executeDispatch_Delete(); + if( ! bReturn ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pChartWindow->GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SchResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + } + + return bReturn; +} + +bool ChartController::requestQuickHelp( + ::Point aAtLogicPosition, + bool bIsBalloonHelp, + OUString & rOutQuickHelpText, + awt::Rectangle & rOutEqualRect ) +{ + rtl::Reference<::chart::ChartModel> xChartModel; + if( m_aModel.is()) + xChartModel = getChartModel(); + if( !xChartModel.is()) + return false; + + // help text + OUString aCID; + if( m_pDrawViewWrapper ) + { + aCID = SelectionHelper::getHitObjectCID( + aAtLogicPosition, *m_pDrawViewWrapper ); + } + bool bResult( !aCID.isEmpty()); + + if( bResult ) + { + // get help text + rOutQuickHelpText = ObjectNameProvider::getHelpText( aCID, xChartModel, bIsBalloonHelp /* bVerbose */ ); + + // set rectangle + ExplicitValueProvider * pValueProvider( + comphelper::getFromUnoTunnel<ExplicitValueProvider>( m_xChartView )); + if( pValueProvider ) + rOutEqualRect = pValueProvider->getRectangleOfObject( aCID, true ); + } + + return bResult; +} + +// XSelectionSupplier (optional interface) +sal_Bool SAL_CALL ChartController::select( const uno::Any& rSelection ) +{ + bool bSuccess = false; + + if ( rSelection.hasValue() ) + { + const uno::Type& rType = rSelection.getValueType(); + if ( rType == cppu::UnoType< OUString >::get() ) + { + OUString aNewCID; + if ( ( rSelection >>= aNewCID ) && m_aSelection.setSelection( aNewCID ) ) + { + bSuccess = true; + } + } + else if ( rType == cppu::UnoType<drawing::XShape>::get() ) + { + uno::Reference< drawing::XShape > xShape; + if ( ( rSelection >>= xShape ) && m_aSelection.setSelection( xShape ) ) + { + bSuccess = true; + } + } + } + else + { + if ( m_aSelection.hasSelection() ) + { + m_aSelection.clearSelection(); + bSuccess = true; + } + } + + if ( bSuccess ) + { + SolarMutexGuard aGuard; + if ( m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() ) + { + EndTextEdit(); + } + impl_selectObjectAndNotiy(); + auto pChartWindow(GetChartWindow()); + if ( pChartWindow ) + { + pChartWindow->Invalidate(); + } + return true; + } + + return false; +} + +uno::Any SAL_CALL ChartController::getSelection() +{ + uno::Any aReturn; + if ( m_aSelection.hasSelection() ) + { + OUString aCID( m_aSelection.getSelectedCID() ); + if ( !aCID.isEmpty() ) + { + aReturn <<= aCID; + } + else + { + // #i12587# support for shapes in chart + aReturn <<= m_aSelection.getSelectedAdditionalShape(); + } + } + return aReturn; +} + +void SAL_CALL ChartController::addSelectionChangeListener( const uno::Reference<view::XSelectionChangeListener> & xListener ) +{ + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode? + return; //behave passive if already disposed or suspended + + //--add listener + m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType<view::XSelectionChangeListener>::get(), xListener ); +} + +void SAL_CALL ChartController::removeSelectionChangeListener( const uno::Reference<view::XSelectionChangeListener> & xListener ) +{ + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() ) //@todo? allow removing of listeners in suspend mode? + return; //behave passive if already disposed or suspended + + //--remove listener + m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType<view::XSelectionChangeListener>::get(), xListener ); +} + +void ChartController::impl_notifySelectionChangeListeners() +{ + ::comphelper::OInterfaceContainerHelper2* pIC = m_aLifeTimeManager.m_aListenerContainer + .getContainer( cppu::UnoType<view::XSelectionChangeListener>::get() ); + if( pIC ) + { + uno::Reference< view::XSelectionSupplier > xSelectionSupplier(this); + lang::EventObject aEvent( xSelectionSupplier ); + ::comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + static_cast< view::XSelectionChangeListener* >( aIt.next() )->selectionChanged( aEvent ); + } + } +} + +void ChartController::impl_selectObjectAndNotiy() +{ + { + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + if( pDrawViewWrapper ) + { + pDrawViewWrapper->SetDragMode( m_eDragMode ); + m_aSelection.applySelection( m_pDrawViewWrapper.get() ); + } + } + impl_notifySelectionChangeListeners(); +} + +bool ChartController::impl_moveOrResizeObject( + const OUString & rCID, + eMoveOrResizeType eType, + double fAmountLogicX, + double fAmountLogicY ) +{ + bool bResult = false; + bool bNeedResize = ( eType == CENTERED_RESIZE_OBJECT ); + + rtl::Reference<::chart::ChartModel> xChartModel( getChartModel() ); + uno::Reference< beans::XPropertySet > xObjProp( + ObjectIdentifier::getObjectPropertySet( rCID, xChartModel )); + if( xObjProp.is()) + { + awt::Size aRefSize = ChartModelHelper::getPageSize( xChartModel ); + + chart2::RelativePosition aRelPos; + chart2::RelativeSize aRelSize; + bool bDeterminePos = !(xObjProp->getPropertyValue( "RelativePosition") >>= aRelPos); + bool bDetermineSize = !bNeedResize || !(xObjProp->getPropertyValue( "RelativeSize") >>= aRelSize); + + if( ( bDeterminePos || bDetermineSize ) && + ( aRefSize.Width > 0 && aRefSize.Height > 0 ) ) + { + ExplicitValueProvider * pValueProvider( + comphelper::getFromUnoTunnel<ExplicitValueProvider>( m_xChartView )); + if( pValueProvider ) + { + awt::Rectangle aRect( pValueProvider->getRectangleOfObject( rCID )); + double fWidth = static_cast< double >( aRefSize.Width ); + double fHeight = static_cast< double >( aRefSize.Height ); + if( bDetermineSize ) + { + aRelSize.Primary = static_cast< double >( aRect.Width ) / fWidth; + aRelSize.Secondary = static_cast< double >( aRect.Height ) / fHeight; + } + if( bDeterminePos ) + { + if( bNeedResize && aRelSize.Primary > 0.0 && aRelSize.Secondary > 0.0 ) + { + aRelPos.Primary = (static_cast< double >( aRect.X ) / fWidth) + + (aRelSize.Primary / 2.0); + aRelPos.Secondary = (static_cast< double >( aRect.Y ) / fHeight) + + (aRelSize.Secondary / 2.0); + aRelPos.Anchor = drawing::Alignment_CENTER; + } + else + { + aRelPos.Primary = static_cast< double >( aRect.X ) / fWidth; + aRelPos.Secondary = static_cast< double >( aRect.Y ) / fHeight; + aRelPos.Anchor = drawing::Alignment_TOP_LEFT; + } + } + } + } + + if( eType == CENTERED_RESIZE_OBJECT ) + bResult = lcl_GrowAndShiftLogic( aRelPos, aRelSize, aRefSize, fAmountLogicX, fAmountLogicY ); + else if( eType == MOVE_OBJECT ) + bResult = lcl_MoveObjectLogic( aRelPos, aRelSize, aRefSize, fAmountLogicX, fAmountLogicY ); + + if( bResult ) + { + ActionDescriptionProvider::ActionType eActionType(ActionDescriptionProvider::ActionType::Move); + if( bNeedResize ) + eActionType = ActionDescriptionProvider::ActionType::Resize; + + ObjectType eObjectType = ObjectIdentifier::getObjectType( rCID ); + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( + eActionType, ObjectNameProvider::getName( eObjectType )), m_xUndoManager ); + { + ControllerLockGuardUNO aCLGuard( xChartModel ); + xObjProp->setPropertyValue( "RelativePosition", uno::Any( aRelPos )); + if( bNeedResize || (eObjectType == OBJECTTYPE_DIAGRAM) )//Also set an explicit size at the diagram when an explicit position is set + xObjProp->setPropertyValue( "RelativeSize", uno::Any( aRelSize )); + } + aUndoGuard.commit(); + } + } + return bResult; +} + +bool ChartController::impl_DragDataPoint( const OUString & rCID, double fAdditionalOffset ) +{ + bool bResult = false; + if( fAdditionalOffset < -1.0 || fAdditionalOffset > 1.0 || fAdditionalOffset == 0.0 ) + return bResult; + + sal_Int32 nDataPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( rCID ); + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( rCID, getChartModel() ); + if( xSeries.is()) + { + try + { + uno::Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex( nDataPointIndex )); + double fOffset = 0.0; + if( xPointProp.is() && + (xPointProp->getPropertyValue( "Offset" ) >>= fOffset ) && + (( fAdditionalOffset > 0.0 && fOffset < 1.0 ) || (fOffset > 0.0)) ) + { + fOffset += fAdditionalOffset; + if( fOffset > 1.0 ) + fOffset = 1.0; + else if( fOffset < 0.0 ) + fOffset = 0.0; + xPointProp->setPropertyValue( "Offset", uno::Any( fOffset )); + bResult = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return bResult; +} + +void ChartController::impl_SetMousePointer( const MouseEvent & rEvent ) +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + + if (!m_pDrawViewWrapper || !pChartWindow) + return; + + Point aMousePos( pChartWindow->PixelToLogic( rEvent.GetPosPixel())); + sal_uInt16 nModifier = rEvent.GetModifier(); + bool bLeftDown = rEvent.IsLeft(); + + // Check if object is for field button and set the normal arrow pointer in this case + SdrObject* pObject = m_pDrawViewWrapper->getHitObject(aMousePos); + if (pObject && pObject->GetName().startsWith("FieldButton")) + { + pChartWindow->SetPointer(PointerStyle::Arrow); + return; + } + + if ( m_pDrawViewWrapper->IsTextEdit() ) + { + if( m_pDrawViewWrapper->IsTextEditHit( aMousePos ) ) + { + pChartWindow->SetPointer( m_pDrawViewWrapper->GetPreferredPointer( + aMousePos, pChartWindow->GetOutDev(), nModifier, bLeftDown ) ); + return; + } + } + else if( m_pDrawViewWrapper->IsAction() ) + { + return;//don't change pointer during running action + } + + SdrHdl* pHitSelectionHdl = nullptr; + if( m_aSelection.isResizeableObjectSelected() ) + pHitSelectionHdl = m_pDrawViewWrapper->PickHandle( aMousePos ); + + if( pHitSelectionHdl ) + { + PointerStyle aPointer = m_pDrawViewWrapper->GetPreferredPointer( + aMousePos, pChartWindow->GetOutDev(), nModifier, bLeftDown ); + bool bForceArrowPointer = false; + + ObjectIdentifier aOID( m_aSelection.getSelectedOID() ); + + switch( aPointer) + { + case PointerStyle::NSize: + case PointerStyle::SSize: + case PointerStyle::WSize: + case PointerStyle::ESize: + case PointerStyle::NWSize: + case PointerStyle::NESize: + case PointerStyle::SWSize: + case PointerStyle::SESize: + if( ! m_aSelection.isResizeableObjectSelected() ) + bForceArrowPointer = true; + break; + case PointerStyle::Move: + if ( !aOID.isDragableObject() ) + bForceArrowPointer = true; + break; + case PointerStyle::MovePoint: + case PointerStyle::MoveBezierWeight: + // there is no point-editing in a chart + // the PointerStyle::MoveBezierWeight appears in 3d data points + bForceArrowPointer = true; + break; + default: + break; + } + + if( bForceArrowPointer ) + pChartWindow->SetPointer( PointerStyle::Arrow ); + else + pChartWindow->SetPointer( aPointer ); + + return; + } + + // #i12587# support for shapes in chart + if ( m_eDrawMode == CHARTDRAW_INSERT && + ( !m_pDrawViewWrapper->IsMarkedHit( aMousePos ) || !m_aSelection.isDragableObjectSelected() ) ) + { + PointerStyle ePointerStyle = PointerStyle::DrawRect; + SdrObjKind eKind = m_pDrawViewWrapper->GetCurrentObjIdentifier(); + switch ( eKind ) + { + case SdrObjKind::Line: + { + ePointerStyle = PointerStyle::DrawLine; + } + break; + case SdrObjKind::Rectangle: + case SdrObjKind::CustomShape: + { + ePointerStyle = PointerStyle::DrawRect; + } + break; + case SdrObjKind::CircleOrEllipse: + { + ePointerStyle = PointerStyle::DrawEllipse; + } + break; + case SdrObjKind::FreehandLine: + { + ePointerStyle = PointerStyle::DrawPolygon; + } + break; + case SdrObjKind::Text: + { + ePointerStyle = PointerStyle::DrawText; + } + break; + case SdrObjKind::Caption: + { + ePointerStyle = PointerStyle::DrawCaption; + } + break; + default: + { + ePointerStyle = PointerStyle::DrawRect; + } + break; + } + pChartWindow->SetPointer( ePointerStyle ); + return; + } + + OUString aHitObjectCID( + SelectionHelper::getHitObjectCID( + aMousePos, *m_pDrawViewWrapper, true /*bGetDiagramInsteadOf_Wall*/ )); + + if( m_pDrawViewWrapper->IsTextEdit() ) + { + if( aHitObjectCID == m_aSelection.getSelectedCID() ) + { + pChartWindow->SetPointer( PointerStyle::Arrow ); + return; + } + } + + if( aHitObjectCID.isEmpty() ) + { + //additional shape was hit + pChartWindow->SetPointer( PointerStyle::Move ); + } + else if( ObjectIdentifier::isDragableObject( aHitObjectCID ) ) + { + if( (m_eDragMode == SdrDragMode::Rotate) + && SelectionHelper::isRotateableObject( aHitObjectCID + , getChartModel() ) ) + pChartWindow->SetPointer( PointerStyle::Rotate ); + else + { + ObjectType eHitObjectType = ObjectIdentifier::getObjectType( aHitObjectCID ); + if( eHitObjectType == OBJECTTYPE_DATA_POINT ) + { + if( !ObjectIdentifier::areSiblings(aHitObjectCID,m_aSelection.getSelectedCID()) + && !ObjectIdentifier::areIdenticalObjects(aHitObjectCID,m_aSelection.getSelectedCID()) ) + { + pChartWindow->SetPointer( PointerStyle::Arrow ); + return; + } + } + pChartWindow->SetPointer( PointerStyle::Move ); + } + } + else + pChartWindow->SetPointer( PointerStyle::Arrow ); +} + +css::uno::Reference<css::uno::XInterface> const & ChartController::getChartView() const +{ + return m_xChartView; +} + +void ChartController::sendPopupRequest(OUString const & rCID, tools::Rectangle aRectangle) +{ + ChartModel* pChartModel = m_aModel->getModel().get(); + if (!pChartModel) + return; + + uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider; + xPivotTableDataProvider.set(pChartModel->getDataProvider(), uno::UNO_QUERY); + if (!xPivotTableDataProvider.is()) + return; + + OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName(); + + css::uno::Reference<css::awt::XRequestCallback> xPopupRequest = pChartModel->getPopupRequest(); + PopupRequest* pPopupRequest = dynamic_cast<PopupRequest*>(xPopupRequest.get()); + if (!pPopupRequest) + return; + + // Get dimension index from CID + sal_Int32 nStartPos = rCID.lastIndexOf('.'); + nStartPos++; + sal_Int32 nEndPos = rCID.getLength(); + std::u16string_view sDimensionIndex = rCID.subView(nStartPos, nEndPos - nStartPos); + sal_Int32 nDimensionIndex = o3tl::toInt32(sDimensionIndex); + + awt::Rectangle xRectangle { + sal_Int32(aRectangle.Left()), + sal_Int32(aRectangle.Top()), + sal_Int32(aRectangle.GetWidth()), + sal_Int32(aRectangle.GetHeight()) + }; + + uno::Sequence<beans::PropertyValue> aCallbackData = comphelper::InitPropertySequence( + { + {"Rectangle", uno::Any(xRectangle)}, + {"DimensionIndex", uno::Any(sal_Int32(nDimensionIndex))}, + {"PivotTableName", uno::Any(sPivotTableName)}, + }); + + pPopupRequest->getCallback()->notify(uno::Any(aCallbackData)); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartDropTargetHelper.cxx b/chart2/source/controller/main/ChartDropTargetHelper.cxx new file mode 100644 index 000000000..b1dfc35d4 --- /dev/null +++ b/chart2/source/controller/main/ChartDropTargetHelper.cxx @@ -0,0 +1,177 @@ +/* -*- 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 "ChartDropTargetHelper.hxx" +#include <DataSource.hxx> +#include <DataSourceHelper.hxx> +#include <ChartModel.hxx> +#include <Diagram.hxx> + +#include <com/sun/star/chart2/data/XDataProvider.hpp> + +#include <sot/formats.hxx> +#include <vector> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +std::vector< OUString > lcl_getStringsFromByteSequence( + const Sequence< sal_Int8 > & aByteSequence ) +{ + std::vector< OUString > aResult; + const sal_Int32 nLength = aByteSequence.getLength(); + const char * pBytes( reinterpret_cast< const char* >( aByteSequence.getConstArray())); + sal_Int32 nStartPos = 0; + for( sal_Int32 nPos=0; nPos<nLength; ++nPos ) + { + if( pBytes[nPos] == '\0' ) + { + aResult.emplace_back( pBytes + nStartPos, (nPos - nStartPos), RTL_TEXTENCODING_ASCII_US ); + nStartPos = nPos + 1; + } + } + return aResult; +} + +} // anonymous namespace + +namespace chart +{ + +ChartDropTargetHelper::ChartDropTargetHelper( + const Reference< datatransfer::dnd::XDropTarget >& rxDropTarget, + const rtl::Reference<::chart::ChartModel> & xChartDocument ) : + DropTargetHelper( rxDropTarget ), + m_xChartDocument( xChartDocument ) +{} + +ChartDropTargetHelper::~ChartDropTargetHelper() +{} + +bool ChartDropTargetHelper::satisfiesPrerequisites() const +{ + return ( m_xChartDocument.is() && + ! m_xChartDocument->hasInternalDataProvider()); +} + +sal_Int8 ChartDropTargetHelper::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + sal_Int8 nResult = DND_ACTION_NONE; + + if( ( rEvt.mnAction == DND_ACTION_COPY || + rEvt.mnAction == DND_ACTION_MOVE ) && + satisfiesPrerequisites() && + IsDropFormatSupported( SotClipboardFormatId::LINK ) ) + { + // @todo: check if the data is suitable. Is this possible without XTransferable? + nResult = rEvt.mnAction; + } + + return nResult; +} + +sal_Int8 ChartDropTargetHelper::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + sal_Int8 nResult = DND_ACTION_NONE; + + if( ( rEvt.mnAction == DND_ACTION_COPY || + rEvt.mnAction == DND_ACTION_MOVE ) && + rEvt.maDropEvent.Transferable.is() && + satisfiesPrerequisites()) + { + TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable ); + if( aDataHelper.HasFormat( SotClipboardFormatId::LINK )) + { + Sequence<sal_Int8> aBytes = aDataHelper.GetSequence(SotClipboardFormatId::LINK, OUString()); + if (aBytes.hasElements()) + { + std::vector< OUString > aStrings( lcl_getStringsFromByteSequence( aBytes )); + if( aStrings.size() >= 3 && aStrings[0] == "soffice" ) + { + OUString aRangeString( aStrings[2] ); + if( m_xChartDocument.is()) + { + Reference< frame::XModel > xParentModel( m_xChartDocument->getParent(), uno::UNO_QUERY ); + if( xParentModel.is() && + m_xChartDocument.is()) + { + // @todo: get the title somehow and compare it to + // aDocName if successful (the document is the + // parent) + rtl::Reference< Diagram > xDiagram = m_xChartDocument->getFirstChartDiagram(); + Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider()); + if( xDataProvider.is() && xDiagram.is() && + DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument )) + { + rtl::Reference< DataSource > xDataSource1 = + DataSourceHelper::pressUsedDataIntoRectangularFormat( m_xChartDocument ); + Sequence< beans::PropertyValue > aArguments( + xDataProvider->detectArguments( xDataSource1 )); + + OUString aOldRange; + beans::PropertyValue * pCellRange = nullptr; + for( sal_Int32 i=0; i<aArguments.getLength(); ++i ) + { + if ( aArguments[i].Name == "CellRangeRepresentation" ) + { + pCellRange = (aArguments.getArray() + i); + aArguments[i].Value >>= aOldRange; + break; + } + } + if( pCellRange ) + { + // copy means add ranges, move means replace + if( rEvt.mnAction == DND_ACTION_COPY ) + { + // @todo: using implicit knowledge that ranges can be + // merged with ";". This should be done more general + pCellRange->Value <<= aOldRange + ";" + aRangeString; + } + // move means replace range + else + { + pCellRange->Value <<= aRangeString; + } + + Reference< chart2::data::XDataSource > xDataSource2 = + xDataProvider->createDataSource( aArguments ); + xDiagram->setDiagramData( xDataSource2, aArguments ); + + // always return copy state to avoid deletion of the dragged range + nResult = DND_ACTION_COPY; + } + } + } + } + } + } + } + } + return nResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartDropTargetHelper.hxx b/chart2/source/controller/main/ChartDropTargetHelper.hxx new file mode 100644 index 000000000..4955d6eae --- /dev/null +++ b/chart2/source/controller/main/ChartDropTargetHelper.hxx @@ -0,0 +1,56 @@ +/* -*- 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 <vcl/transfer.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + } +} + +namespace chart +{ +class ChartModel; + +class ChartDropTargetHelper : public DropTargetHelper +{ +public: + ChartDropTargetHelper() = delete; + explicit ChartDropTargetHelper( + const css::uno::Reference< css::datatransfer::dnd::XDropTarget >& rxDropTarget, + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + virtual ~ChartDropTargetHelper() override; + +protected: + + virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override; + virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override; + +private: + bool satisfiesPrerequisites() const; + + rtl::Reference<::chart::ChartModel> m_xChartDocument; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartFrameloader.cxx b/chart2/source/controller/main/ChartFrameloader.cxx new file mode 100644 index 000000000..0ba17d338 --- /dev/null +++ b/chart2/source/controller/main/ChartFrameloader.cxx @@ -0,0 +1,194 @@ +/* -*- 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 "ChartFrameloader.hxx" +#include <servicenames.hxx> +#include <MediaDescriptorHelper.hxx> +#include <ChartController.hxx> +#include <ChartModel.hxx> +#include <unotools/mediadescriptor.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/frame/XLoadable.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <tools/diagnose_ex.h> + +namespace chart +{ + +using namespace ::com::sun::star; + +ChartFrameLoader::ChartFrameLoader( + uno::Reference<uno::XComponentContext> const & xContext) + : m_bCancelRequired( false ) +{ + m_xCC = xContext; + m_oCancelFinished.reset(); +} + +ChartFrameLoader::~ChartFrameLoader() +{ +} + +bool ChartFrameLoader::impl_checkCancel() +{ + if(m_bCancelRequired) + { + m_oCancelFinished.set(); + return true; + } + return false; +} + +// lang::XServiceInfo + +OUString SAL_CALL ChartFrameLoader::getImplementationName() +{ + return CHART_FRAMELOADER_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartFrameLoader::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartFrameLoader::getSupportedServiceNames() +{ + return { CHART_FRAMELOADER_SERVICE_NAME }; +} + +// frame::XFrameLoader + +sal_Bool SAL_CALL ChartFrameLoader::load( const uno::Sequence< beans::PropertyValue >& rMediaDescriptor, const uno::Reference<frame::XFrame >& xFrame ) +{ + //@todo ? need to add as terminate listener to desktop? + + uno::Reference< frame::XModel > xModel; + bool bHaveLoadedModel = false; + + utl::MediaDescriptor aMediaDescriptor(rMediaDescriptor); + { + utl::MediaDescriptor::const_iterator aIt( aMediaDescriptor.find( utl::MediaDescriptor::PROP_MODEL)); + if( aIt != aMediaDescriptor.end()) + { + xModel.set( (*aIt).second.get< uno::Reference< frame::XModel > >()); + bHaveLoadedModel = true; + } + } + + //create and initialize the model + if( ! xModel.is()) + { + //@todo?? load mechanism to cancel during loading of document + xModel = new ChartModel(m_xCC); + + if( impl_checkCancel() ) + return false; + } + + //create the controller(+XWindow) + rtl::Reference< ChartController > xController = new ChartController(m_xCC); + + //!!!it is a special characteristic of the example application + //that the controller simultaneously provides the XWindow controller functionality + uno::Reference< awt::XWindow > xComponentWindow = xController; + + if( impl_checkCancel() ) + return false; + + //connect frame, controller and model one to each other: + if(xModel.is()) + { + xModel->connectController(xController); + xModel->setCurrentController(xController); + xController->attachModel(xModel); + if(xFrame.is()) + xFrame->setComponent(xComponentWindow,xController); + //creates the view and menu + //for correct menu creation the initialized component must be already set into the frame + xController->attachFrame(xFrame); + } + + // call initNew() or load() at XLoadable + if(bHaveLoadedModel) + return true; + + try + { + utl::MediaDescriptor::const_iterator aIt( aMediaDescriptor.find( utl::MediaDescriptor::PROP_URL)); + if( aIt != aMediaDescriptor.end()) + { + OUString aURL( (*aIt).second.get< OUString >()); + if( aURL.startsWith( "private:factory/schart" ) ) + { + // create new file + uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW ); + xLoadable->initNew(); + } + else + { + // use the URL as BaseURL, similar to what SfxBaseModel effectively does + if (!aURL.isEmpty()) + { + aMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTBASEURL] <<= aURL; + } + aMediaDescriptor.addInputStream(); + uno::Sequence< beans::PropertyValue > aCompleteMediaDescriptor; + aMediaDescriptor >> aCompleteMediaDescriptor; + apphelper::MediaDescriptorHelper aMDHelper( aCompleteMediaDescriptor ); + + // load file + // @todo: replace: aMediaDescriptorHelper.getReducedForModel() + uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW ); + xLoadable->load( aCompleteMediaDescriptor ); + + //resize standalone files to get correct size: + if( aMDHelper.ISSET_FilterName && aMDHelper.FilterName == "StarChart 5.0" ) + { + awt::Rectangle aRect( xComponentWindow->getPosSize() ); + xComponentWindow->setPosSize( aRect.X, aRect.Y, aRect.Width, aRect.Height, 0 ); + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return true; +} + +void SAL_CALL ChartFrameLoader::cancel() +{ + m_oCancelFinished.reset(); + m_bCancelRequired = true; + m_oCancelFinished.wait(); + m_bCancelRequired = false; +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartFrameLoader_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new chart::ChartFrameLoader(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartFrameloader.hxx b/chart2/source/controller/main/ChartFrameloader.hxx new file mode 100644 index 000000000..99f0ffd06 --- /dev/null +++ b/chart2/source/controller/main/ChartFrameloader.hxx @@ -0,0 +1,67 @@ +/* -*- 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 <osl/conditn.hxx> +#include <com/sun/star/frame/XSynchronousFrameLoader.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ + +class ChartFrameLoader : public ::cppu::WeakImplHelper< + css::frame::XSynchronousFrameLoader + , css::lang::XServiceInfo + > +{ +private: + css::uno::Reference< css::uno::XComponentContext> m_xCC; + bool m_bCancelRequired; + ::osl::Condition m_oCancelFinished; + +private: + bool impl_checkCancel(); + +public: + ChartFrameLoader() = delete; + + explicit ChartFrameLoader(css::uno::Reference< css::uno::XComponentContext > const & xContext); + virtual ~ChartFrameLoader() override; + + // css::lang::XServiceInfo + 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; + + // css::frame::XFrameLoader + + virtual sal_Bool SAL_CALL + load( const css::uno::Sequence< css::beans::PropertyValue >& rMediaDescriptor + ,const css::uno::Reference< css::frame::XFrame >& xFrame ) override; + + virtual void SAL_CALL + cancel() override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartModelClone.cxx b/chart2/source/controller/main/ChartModelClone.cxx new file mode 100644 index 000000000..d84945274 --- /dev/null +++ b/chart2/source/controller/main/ChartModelClone.cxx @@ -0,0 +1,231 @@ +/* -*- 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 "ChartModelClone.hxx" +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <DataSource.hxx> +#include <DataSourceHelper.hxx> + +#include <com/sun/star/chart2/XAnyDescriptionAccess.hpp> +#include <com/sun/star/chart2/XInternalDataProvider.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/chart2/XTitled.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/chart2/data/XLabeledDataSequence.hpp> + +#include <comphelper/property.hxx> +#include <tools/diagnose_ex.h> + +namespace chart +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::util::XCloneable; + using ::com::sun::star::chart2::XChartDocument; + using ::com::sun::star::chart2::XInternalDataProvider; + using ::com::sun::star::chart2::XAnyDescriptionAccess; + using ::com::sun::star::view::XSelectionSupplier; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::chart2::XTitled; + using ::com::sun::star::util::XModifiable; + using ::com::sun::star::chart2::data::XDataSource; + using ::com::sun::star::chart2::data::XLabeledDataSequence; + + // = helper + namespace + { + rtl::Reference<::chart::ChartModel> lcl_cloneModel( const rtl::Reference<::chart::ChartModel> & xModel ) + { + try + { + return new ChartModel(*xModel); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nullptr; + } + + } + + // = ChartModelClone + ChartModelClone::ChartModelClone( const rtl::Reference<::chart::ChartModel>& i_model, const ModelFacet i_facet ) + { + m_xModelClone = lcl_cloneModel( i_model ); + + try + { + if ( i_facet == E_MODEL_WITH_DATA ) + { + ENSURE_OR_THROW( m_xModelClone && m_xModelClone->hasInternalDataProvider(), "invalid chart model" ); + + const Reference< XCloneable > xCloneable( m_xModelClone->getDataProvider(), UNO_QUERY_THROW ); + m_xDataClone.set( xCloneable->createClone(), UNO_QUERY_THROW ); + } + + if ( i_facet == E_MODEL_WITH_SELECTION ) + { + const Reference< XSelectionSupplier > xSelSupp( m_xModelClone->getCurrentController(), UNO_QUERY_THROW ); + m_aSelection = xSelSupp->getSelection(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + ChartModelClone::~ChartModelClone() + { + if ( !impl_isDisposed() ) + dispose(); + } + + void ChartModelClone::dispose() + { + if ( impl_isDisposed() ) + return; + + m_xModelClone.clear(); + m_xDataClone.clear(); + m_aSelection.clear(); + } + + ModelFacet ChartModelClone::getFacet() const + { + if ( m_aSelection.hasValue() ) + return E_MODEL_WITH_SELECTION; + if ( m_xDataClone.is() ) + return E_MODEL_WITH_DATA; + return E_MODEL; + } + + void ChartModelClone::applyToModel( const rtl::Reference<::chart::ChartModel>& i_model ) const + { + applyModelContentToModel( i_model, m_xModelClone, m_xDataClone ); + + if ( m_aSelection.hasValue() ) + { + try + { + Reference< XSelectionSupplier > xCurrentSelectionSuppl( i_model->getCurrentController(), UNO_QUERY_THROW ); + xCurrentSelectionSuppl->select( m_aSelection ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + + namespace + { + void ImplApplyDataToModel( const Reference< XModel >& i_model, const Reference< XInternalDataProvider > & i_data ) + { + Reference< XChartDocument > xDoc( i_model, UNO_QUERY ); + OSL_ASSERT( xDoc.is() && xDoc->hasInternalDataProvider() ); + + // copy data from stored internal data provider + if( xDoc.is() && xDoc->hasInternalDataProvider()) + { + Reference< XAnyDescriptionAccess > xCurrentData( xDoc->getDataProvider(), UNO_QUERY ); + Reference< XAnyDescriptionAccess > xSavedData( i_data, UNO_QUERY ); + if ( xCurrentData.is() && xSavedData.is() ) + { + xCurrentData->setData( xSavedData->getData() ); + xCurrentData->setAnyRowDescriptions( xSavedData->getAnyRowDescriptions()); + xCurrentData->setAnyColumnDescriptions( xSavedData->getAnyColumnDescriptions()); + } + } + } + } + + void ChartModelClone::applyModelContentToModel( const rtl::Reference<::chart::ChartModel>& i_model, + const rtl::Reference<::chart::ChartModel>& i_modelToCopyFrom, + const Reference< XInternalDataProvider >& i_data ) + { + ENSURE_OR_RETURN_VOID( i_model.is(), "ChartModelElement::applyModelContentToModel: invalid source model!" ); + ENSURE_OR_RETURN_VOID( i_modelToCopyFrom.is(), "ChartModelElement::applyModelContentToModel: invalid source model!" ); + try + { + // locked controllers of destination + ControllerLockGuardUNO aLockedControllers( i_model ); + + // propagate the correct flag for plotting of hidden values to the data provider and all used sequences + ChartModelHelper::setIncludeHiddenCells(ChartModelHelper::isIncludeHiddenCells( i_modelToCopyFrom ), *i_model); + + // diagram + i_model->setFirstDiagram( i_modelToCopyFrom->getFirstDiagram() ); + + // main title + i_model->setTitleObject( i_modelToCopyFrom->getTitleObject() ); + + // page background + ::comphelper::copyProperties( + i_modelToCopyFrom->getPageBackground(), + i_model->getPageBackground() ); + + // apply data (not applied in standard Undo) + if ( i_data.is() ) + ImplApplyDataToModel( i_model, i_data ); + + // register all sequences at the internal data provider to get adapted + // indexes when columns are added/removed + if ( i_model->hasInternalDataProvider() ) + { + Reference< XInternalDataProvider > xNewDataProvider( i_model->getDataProvider(), UNO_QUERY ); + rtl::Reference< DataSource > xUsedData = DataSourceHelper::getUsedData( *i_model ); + if ( xUsedData.is() && xNewDataProvider.is() ) + { + const Sequence< Reference< XLabeledDataSequence > > aData( xUsedData->getDataSequences() ); + for( Reference< XLabeledDataSequence > const & labeledDataSeq : aData ) + { + xNewDataProvider->registerDataSequenceForChanges( labeledDataSeq->getValues() ); + xNewDataProvider->registerDataSequenceForChanges( labeledDataSeq->getLabel() ); + } + } + } + + // restore modify status + if ( !i_modelToCopyFrom->isModified() ) + { + i_model->setModified( false ); + } + // \-- locked controllers of destination + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartModelClone.hxx b/chart2/source/controller/main/ChartModelClone.hxx new file mode 100644 index 000000000..41cf7fc10 --- /dev/null +++ b/chart2/source/controller/main/ChartModelClone.hxx @@ -0,0 +1,75 @@ +/* -*- 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/uno/Any.hxx> +#include <com/sun/star/uno/Reference.h> +#include <rtl/ref.hxx> + +namespace com::sun::star::chart2 { class XInternalDataProvider; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class ChartModel; + + enum ModelFacet + { + E_MODEL, + E_MODEL_WITH_DATA, + E_MODEL_WITH_SELECTION + }; + + class ChartModelClone + { + public: + ChartModelClone( + const rtl::Reference<::chart::ChartModel>& i_model, + const ModelFacet i_facet + ); + + ~ChartModelClone(); + + ChartModelClone(const ChartModelClone&) = delete; + const ChartModelClone& operator=(const ChartModelClone&) = delete; + + ModelFacet getFacet() const; + + void applyToModel( const rtl::Reference<::chart::ChartModel>& i_model ) const; + + static void applyModelContentToModel( + const rtl::Reference<::chart::ChartModel> & i_model, + const rtl::Reference<::chart::ChartModel> & i_modelToCopyFrom, + const css::uno::Reference< css::chart2::XInternalDataProvider > & i_data ); + + void dispose(); + + private: + bool impl_isDisposed() const { return !m_xModelClone.is(); } + + private: + rtl::Reference<::chart::ChartModel> m_xModelClone; + css::uno::Reference< css::chart2::XInternalDataProvider > m_xDataClone; + css::uno::Any m_aSelection; + }; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartTransferable.cxx b/chart2/source/controller/main/ChartTransferable.cxx new file mode 100644 index 000000000..322e73be3 --- /dev/null +++ b/chart2/source/controller/main/ChartTransferable.cxx @@ -0,0 +1,162 @@ +/* -*- 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 <sal/config.h> + +#include <memory> + +#include "ChartTransferable.hxx" + +#include <sot/exchange.hxx> +#include <sot/storage.hxx> +#include <unotools/streamwrap.hxx> +#include <vcl/graph.hxx> +#include <svl/itempool.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <svx/svditer.hxx> +#include <svx/svdmodel.hxx> +#include <svx/unomodel.hxx> +#include <svx/svdview.hxx> +#include <osl/diagnose.h> + +constexpr sal_uInt32 CHARTTRANSFER_OBJECTTYPE_DRAWMODEL = 1; + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +ChartTransferable::ChartTransferable( + SdrModel& rSdrModel, + SdrObject* pSelectedObj, + bool bDrawing) +: m_pMarkedObjModel( nullptr ) + ,m_bDrawing( bDrawing ) +{ + std::unique_ptr<SdrExchangeView> pExchgView(std::make_unique<SdrView>( rSdrModel )); + SdrPageView* pPv = pExchgView->ShowSdrPage( rSdrModel.GetPage( 0 )); + if( pSelectedObj ) + pExchgView->MarkObj( pSelectedObj, pPv ); + else + pExchgView->MarkAllObj( pPv ); + Graphic aGraphic( pExchgView->GetMarkedObjMetaFile(true)); + m_xMetaFileGraphic.set( aGraphic.GetXGraphic()); + if ( m_bDrawing ) + { + m_pMarkedObjModel = pExchgView->CreateMarkedObjModel().release(); + } +} + +ChartTransferable::~ChartTransferable() +{} + +void ChartTransferable::AddSupportedFormats() +{ + if ( m_bDrawing ) + { + AddFormat( SotClipboardFormatId::DRAWING ); + } + AddFormat( SotClipboardFormatId::GDIMETAFILE ); + AddFormat( SotClipboardFormatId::PNG ); + AddFormat( SotClipboardFormatId::BITMAP ); +} + +bool ChartTransferable::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ ) +{ + SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor ); + bool bResult = false; + + if( HasFormat( nFormat )) + { + if ( nFormat == SotClipboardFormatId::DRAWING ) + { + bResult = SetObject( m_pMarkedObjModel, CHARTTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor ); + } + else if ( nFormat == SotClipboardFormatId::GDIMETAFILE ) + { + Graphic aGraphic( m_xMetaFileGraphic ); + bResult = SetGDIMetaFile( aGraphic.GetGDIMetaFile() ); + } + else if( nFormat == SotClipboardFormatId::BITMAP ) + { + Graphic aGraphic( m_xMetaFileGraphic ); + bResult = SetBitmapEx( aGraphic.GetBitmapEx(), rFlavor ); + } + } + + return bResult; +} + +bool ChartTransferable::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, + const datatransfer::DataFlavor& /* rFlavor */ ) +{ + // called from SetObject, put data into stream + + bool bRet = false; + switch ( nUserObjectId ) + { + case CHARTTRANSFER_OBJECTTYPE_DRAWMODEL: + { + SdrModel* pMarkedObjModel = static_cast< SdrModel* >( pUserObject ); + if ( pMarkedObjModel ) + { + rxOStm->SetBufferSize( 0xff00 ); + + // for the changed pool defaults from drawing layer pool set those + // attributes as hard attributes to preserve them for saving + const SfxItemPool& rItemPool = pMarkedObjModel->GetItemPool(); + const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem( EE_CHAR_FONTHEIGHT ); + sal_uInt16 nCount = pMarkedObjModel->GetPageCount(); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + const SdrPage* pPage = pMarkedObjModel->GetPage( i ); + SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); + while ( aIter.IsMore() ) + { + SdrObject* pObj = aIter.Next(); + const SvxFontHeightItem& rItem = pObj->GetMergedItem( EE_CHAR_FONTHEIGHT ); + if ( rItem.GetHeight() == rDefaultFontHeight.GetHeight() ) + { + pObj->SetMergedItem( rDefaultFontHeight ); + } + } + } + + Reference< io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( *rxOStm ) ); + SvxDrawingLayerExport( pMarkedObjModel, xDocOut ); + + bRet = ( rxOStm->GetError() == ERRCODE_NONE ); + } + } + break; + default: + { + OSL_FAIL( "ChartTransferable::WriteObject: unknown object id" ); + } + break; + } + return bRet; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartTransferable.hxx b/chart2/source/controller/main/ChartTransferable.hxx new file mode 100644 index 000000000..34567dceb --- /dev/null +++ b/chart2/source/controller/main/ChartTransferable.hxx @@ -0,0 +1,60 @@ +/* -*- 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 <vcl/transfer.hxx> + +namespace com::sun::star { + namespace graphic { + class XGraphic; + } +} + +class SdrModel; +class SdrObject; + +namespace chart +{ + +class ChartTransferable : public TransferableHelper +{ +public: + explicit ChartTransferable( + SdrModel& rSdrModel, + SdrObject* pSelectedObj, + bool bDrawing ); + virtual ~ChartTransferable() override; + +protected: + + // implementation of TransferableHelper methods + virtual void AddSupportedFormats() override; + virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override; + virtual bool WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, + const css::datatransfer::DataFlavor& rFlavor ) override; + +private: + css::uno::Reference< css::graphic::XGraphic > m_xMetaFileGraphic; + SdrModel* m_pMarkedObjModel; + bool m_bDrawing; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartWindow.cxx b/chart2/source/controller/main/ChartWindow.cxx new file mode 100644 index 000000000..3085f65da --- /dev/null +++ b/chart2/source/controller/main/ChartWindow.cxx @@ -0,0 +1,403 @@ +/* -*- 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 <config_wasm_strip.h> +#include <ChartWindow.hxx> +#include <ChartController.hxx> +#include <helpids.h> +#include <uiobject.hxx> + +#include <vcl/help.hxx> +#include <vcl/settings.hxx> + +#include <sfx2/ipclient.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/lokhelper.hxx> +#include <comphelper/lok.hxx> + +using namespace ::com::sun::star; + +namespace +{ +::tools::Rectangle lcl_AWTRectToVCLRect( const css::awt::Rectangle & rAWTRect ) +{ + ::tools::Rectangle aResult(rAWTRect.X, rAWTRect.Y); + aResult.setWidth( rAWTRect.Width ); + aResult.setHeight( rAWTRect.Height ); + return aResult; +} +} // anonymous namespace + +namespace chart +{ + +ChartWindow::ChartWindow( ChartController* pController, vcl::Window* pParent, WinBits nStyle ) + : Window(pParent, nStyle) + , m_pWindowController( pController ) + , m_bInPaint(false) + , m_pViewShellWindow( nullptr ) +{ + set_id("chart_window"); + SetHelpId( HID_SCH_WIN_DOCUMENT ); + SetMapMode( MapMode(MapUnit::Map100thMM) ); + adjustHighContrastMode(); + // chart does not depend on exact pixel painting => enable antialiased drawing + GetOutDev()->SetAntialiasing( AntialiasingFlags::Enable | GetOutDev()->GetAntialiasing() ); + EnableRTL( false ); + if( pParent ) + pParent->EnableRTL( false );// #i96215# necessary for a correct position of the context menu in rtl mode +} + +ChartWindow::~ChartWindow() +{ + disposeOnce(); +} + +void ChartWindow::dispose() +{ + m_pWindowController = nullptr; + m_pViewShellWindow.clear(); + vcl::Window::dispose(); +} + +void ChartWindow::PrePaint(vcl::RenderContext& ) +{ + // forward VCLs PrePaint window event to DrawingLayer + if (m_pWindowController) + { + m_pWindowController->PrePaint(); + } +} + +void ChartWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + if (comphelper::LibreOfficeKit::isActive() && !rRenderContext.IsVirtual()) + return; + + m_bInPaint = true; + if (m_pWindowController) + { + m_pWindowController->execute_Paint(rRenderContext, rRect); + } + else + { + Window::Paint(rRenderContext, rRect); + } + m_bInPaint = false; +} + +void ChartWindow::MouseButtonDown(const MouseEvent& rMEvt) +{ + if( m_pWindowController ) + m_pWindowController->execute_MouseButtonDown(rMEvt); + else + Window::MouseButtonDown(rMEvt); +} + +void ChartWindow::MouseMove( const MouseEvent& rMEvt ) +{ + if( m_pWindowController ) + m_pWindowController->execute_MouseMove( rMEvt ); + else + Window::MouseMove( rMEvt ); +} + +void ChartWindow::Tracking( const TrackingEvent& rTEvt ) +{ + if( !m_pWindowController ) + Window::Tracking( rTEvt ); +} + +void ChartWindow::MouseButtonUp( const MouseEvent& rMEvt ) +{ + if( m_pWindowController ) + m_pWindowController->execute_MouseButtonUp( rMEvt ); + else + Window::MouseButtonUp( rMEvt ); +} + +void ChartWindow::Resize() +{ + if( m_pWindowController ) + m_pWindowController->execute_Resize(); + else + Window::Resize(); +} + +void ChartWindow::Activate() +{ + if( !m_pWindowController ) + Window::Activate(); +} +void ChartWindow::Deactivate() +{ + if( !m_pWindowController ) + Window::Deactivate(); +} +void ChartWindow::GetFocus() +{ + if( !m_pWindowController ) + Window::GetFocus(); +} +void ChartWindow::LoseFocus() +{ + if( !m_pWindowController ) + Window::LoseFocus(); +} + +void ChartWindow::Command( const CommandEvent& rCEvt ) +{ + if( m_pWindowController ) + m_pWindowController->execute_Command( rCEvt ); + else + Window::Command( rCEvt ); +} + +void ChartWindow::KeyInput( const KeyEvent& rKEvt ) +{ + if( m_pWindowController ) + { + if( !m_pWindowController->execute_KeyInput(rKEvt) ) + Window::KeyInput(rKEvt); + } + else + Window::KeyInput( rKEvt ); +} + +uno::Reference< css::accessibility::XAccessible > ChartWindow::CreateAccessible() +{ +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + if( m_pWindowController ) + return m_pWindowController->CreateAccessible(); + else + return Window::CreateAccessible(); +#else + return uno::Reference< css::accessibility::XAccessible >(); +#endif +} + +void ChartWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + vcl::Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + adjustHighContrastMode(); + } +} + +void ChartWindow::RequestHelp( const HelpEvent& rHEvt ) +{ + bool bHelpHandled = false; + if( ( rHEvt.GetMode() & HelpEventMode::QUICK ) && + m_pWindowController ) + { + Point aLogicHitPos = PixelToLogic( GetPointerPosPixel()); + OUString aQuickHelpText; + awt::Rectangle aHelpRect; + bool bIsBalloonHelp( Help::IsBalloonHelpEnabled() ); + bHelpHandled = m_pWindowController->requestQuickHelp( aLogicHitPos, bIsBalloonHelp, aQuickHelpText, aHelpRect ); + + if( bHelpHandled ) + { + tools::Rectangle aPixelRect(LogicToPixel(lcl_AWTRectToVCLRect(aHelpRect))); + tools::Rectangle aScreenRect(OutputToScreenPixel(aPixelRect.TopLeft()), + OutputToScreenPixel(aPixelRect.BottomRight())); + + if( bIsBalloonHelp ) + Help::ShowBalloon(this, rHEvt.GetMousePosPixel(), aScreenRect, aQuickHelpText); + else + Help::ShowQuickHelp(this, aScreenRect, aQuickHelpText); + } + } + + if( !bHelpHandled ) + vcl::Window::RequestHelp( rHEvt ); +} + +void ChartWindow::LogicMouseButtonDown(const MouseEvent& rEvent) +{ + MouseButtonDown(rEvent); +} + +void ChartWindow::LogicMouseButtonUp(const MouseEvent& rEvent) +{ + MouseButtonUp(rEvent); +} + +void ChartWindow::LogicMouseMove(const MouseEvent& rEvent) +{ + MouseMove(rEvent); +} + +void ChartWindow::adjustHighContrastMode() +{ + static const DrawModeFlags nContrastMode = + DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | + DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient; + + bool bUseContrast = GetSettings().GetStyleSettings().GetHighContrastMode(); + GetOutDev()->SetDrawMode( bUseContrast ? nContrastMode : DrawModeFlags::Default ); +} + +void ChartWindow::ForceInvalidate() +{ + vcl::Window::Invalidate(); +} +void ChartWindow::Invalidate( InvalidateFlags nFlags ) +{ + if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts" + return; + vcl::Window::Invalidate( nFlags ); +} +void ChartWindow::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags ) +{ + if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts" + return; + vcl::Window::Invalidate( rRect, nFlags ); +} +void ChartWindow::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags ) +{ + if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts" + return; + vcl::Window::Invalidate( rRegion, nFlags ); +} + +void ChartWindow::LogicInvalidate(const tools::Rectangle* pRectangle) +{ + SfxViewShell* pCurrentShell = SfxViewShell::Current(); + if ( nullptr == pCurrentShell ) + return; + tools::Rectangle aResultRectangle; + if (!pRectangle) + { + // we have to invalidate the whole chart area not the whole document + aResultRectangle = GetBoundingBox(); + } + else + { + tools::Rectangle aRectangle(*pRectangle); + // When dragging shapes the map mode is disabled. + if (IsMapModeEnabled()) + { + if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM) + { + aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip); + } + } + else + { + aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip)); + } + + vcl::Window* pEditWin = GetParentEditWin(); + if (pEditWin) + { + MapMode aCWMapMode = GetMapMode(); + constexpr auto p = o3tl::getConversionMulDiv(o3tl::Length::px, o3tl::Length::twip); + const auto& scaleX = aCWMapMode.GetScaleX(); + const auto& scaleY = aCWMapMode.GetScaleY(); + const auto nXNum = p.first * scaleX.GetDenominator(); + const auto nXDen = p.second * scaleX.GetNumerator(); + const auto nYNum = p.first * scaleY.GetDenominator(); + const auto nYDen = p.second * scaleY.GetNumerator(); + + if (!IsMapModeEnabled()) + { + aRectangle = aRectangle.scale(scaleX.GetDenominator(), scaleX.GetNumerator(), + scaleY.GetDenominator(), scaleY.GetNumerator()); + } + + Point aOffset = this->GetOffsetPixelFrom(*pEditWin).scale(nXNum, nXDen, nYNum, nYDen); + + aRectangle = tools::Rectangle(aRectangle.TopLeft() + aOffset, aRectangle.GetSize()); + } + + aResultRectangle = aRectangle; + } + SfxLokHelper::notifyInvalidation(pCurrentShell, &aResultRectangle); +} + +FactoryFunction ChartWindow::GetUITestFactory() const +{ + return ChartWindowUIObject::create; +} + +ChartController* ChartWindow::GetController() +{ + return m_pWindowController; +} + +vcl::Window* ChartWindow::GetParentEditWin() +{ + if (m_pViewShellWindow) + return m_pViewShellWindow.get(); + + // So, you are thinking, why do not invoke pCurrentShell->GetWindow() ? + // Because in Impress the parent edit win is not view shell window. + SfxViewShell* pCurrentShell = SfxViewShell::Current(); + if( pCurrentShell ) + { + SfxInPlaceClient* pIPClient = pCurrentShell->GetIPClient(); + if (pIPClient) + { + vcl::Window* pRootWin = pIPClient->GetEditWin(); + if(pRootWin && pRootWin->IsAncestorOf(*this)) + { + m_pViewShellWindow = pRootWin; + return m_pViewShellWindow.get(); + } + } + } + return nullptr; +} + +tools::Rectangle ChartWindow::GetBoundingBox() +{ + tools::Rectangle aBBox; + + vcl::Window* pRootWin = GetParentEditWin(); + if (pRootWin) + { + // In all cases, the following code fragment + // returns the chart bounding box in twips. + MapMode aCWMapMode = GetMapMode(); + constexpr auto p = o3tl::getConversionMulDiv(o3tl::Length::px, o3tl::Length::twip); + const auto& scaleX = aCWMapMode.GetScaleX(); + const auto& scaleY = aCWMapMode.GetScaleY(); + const auto nXNum = p.first * scaleX.GetDenominator(); + const auto nXDen = p.second * scaleX.GetNumerator(); + const auto nYNum = p.first * scaleY.GetDenominator(); + const auto nYDen = p.second * scaleY.GetNumerator(); + + Point aOffset = GetOffsetPixelFrom(*pRootWin); + aOffset.setX( o3tl::convert(aOffset.X(), nXNum, nXDen) ); + aOffset.setY( o3tl::convert(aOffset.Y(), nYNum, nYDen) ); + Size aSize = GetSizePixel(); + aSize.setWidth( o3tl::convert(aSize.Width(), nXNum, nXDen) ); + aSize.setHeight( o3tl::convert(aSize.Height(), nYNum, nYDen) ); + aBBox = tools::Rectangle(aOffset, aSize); + } + return aBBox; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/CommandDispatch.cxx b/chart2/source/controller/main/CommandDispatch.cxx new file mode 100644 index 000000000..9a16fbb73 --- /dev/null +++ b/chart2/source/controller/main/CommandDispatch.cxx @@ -0,0 +1,157 @@ +/* -*- 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 "CommandDispatch.hxx" +#include <com/sun/star/util/URLTransformer.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +CommandDispatch::CommandDispatch( + const Reference< uno::XComponentContext > & xContext ) : + impl::CommandDispatch_Base( m_aMutex ), + m_xContext( xContext ) +{ +} + +CommandDispatch::~CommandDispatch() +{} + +void CommandDispatch::initialize() +{} + +// ____ WeakComponentImplHelperBase ____ +/// is called when this is disposed +void SAL_CALL CommandDispatch::disposing() +{ + Reference< uno::XInterface > xEventSource(static_cast< cppu::OWeakObject* >( this )); + for( auto& rElement : m_aListeners ) + { + if( rElement.second ) + { + rElement.second->disposeAndClear( xEventSource ); + rElement.second.reset(); + } + } + m_aListeners.clear(); +} + +// ____ XDispatch ____ +void SAL_CALL CommandDispatch::dispatch( const util::URL& /* URL */, const Sequence< beans::PropertyValue >& /* Arguments */ ) +{} + +void SAL_CALL CommandDispatch::addStatusListener( const Reference< frame::XStatusListener >& Control, const util::URL& URL ) +{ + tListenerMap::iterator aIt( m_aListeners.find( URL.Complete )); + if( aIt == m_aListeners.end()) + { + aIt = m_aListeners.insert( + m_aListeners.begin(), + tListenerMap::value_type( URL.Complete, new ::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener>( m_aMutex ))); + } + OSL_ASSERT( aIt != m_aListeners.end()); + + aIt->second->addInterface( Control ); + fireStatusEvent( URL.Complete, Control ); +} + +void SAL_CALL CommandDispatch::removeStatusListener( const Reference< frame::XStatusListener >& Control, const util::URL& URL ) +{ + tListenerMap::iterator aIt( m_aListeners.find( URL.Complete )); + if( aIt != m_aListeners.end()) + (*aIt).second->removeInterface( Control ); +} + +// ____ XModifyListener ____ +void SAL_CALL CommandDispatch::modified( const lang::EventObject& /* aEvent */ ) +{ + fireAllStatusEvents( nullptr ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL CommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{} + +void CommandDispatch::fireAllStatusEvents( + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) +{ + fireStatusEvent( OUString(), xSingleListener ); +} + +void CommandDispatch::fireStatusEventForURL( + const OUString & rURL, + const uno::Any & rState, + bool bEnabled, + const Reference< frame::XStatusListener > & xSingleListener /* = 0 */) +{ + // prepare event to send + util::URL aURL; + aURL.Complete = rURL; + if( !m_xURLTransformer.is()) + { + m_xURLTransformer.set( util::URLTransformer::create(m_xContext) ); + } + m_xURLTransformer->parseStrict( aURL ); + + frame::FeatureStateEvent aEventToSend( + static_cast< cppu::OWeakObject* >( this ), // Source + aURL, // FeatureURL + OUString(), // FeatureDescriptor + bEnabled, // IsEnabled + false, // Requery + rState // State + ); + + // send event either to single listener or all registered ones + if( xSingleListener.is()) + xSingleListener->statusChanged( aEventToSend ); + else + { + tListenerMap::iterator aIt( m_aListeners.find( aURL.Complete )); + if( aIt != m_aListeners.end()) + { + if( aIt->second ) + { + ::comphelper::OInterfaceIteratorHelper3 aIntfIt( *((*aIt).second) ); + + while( aIntfIt.hasMoreElements()) + { + try + { + aIntfIt.next()->statusChanged( aEventToSend ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/CommandDispatch.hxx b/chart2/source/controller/main/CommandDispatch.hxx new file mode 100644 index 000000000..16e0b5ab7 --- /dev/null +++ b/chart2/source/controller/main/CommandDispatch.hxx @@ -0,0 +1,133 @@ +/* -*- 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/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/util/XModifyListener.hpp> + +#include <map> +#include <memory> + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { class XURLTransformer; } + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakComponentImplHelper< + css::frame::XDispatch, + css::util::XModifyListener > + CommandDispatch_Base; +} + +/** This is the base class for an XDispatch. + */ +class CommandDispatch : + public cppu::BaseMutex, + public impl::CommandDispatch_Base +{ +public: + explicit CommandDispatch( const css::uno::Reference< css::uno::XComponentContext > & xContext ); + virtual ~CommandDispatch() override; + + // late initialisation, especially for adding as listener + virtual void initialize(); + +protected: + /** sends a status event for a specific command to all registered listeners + or only the one given when set. + + This method should be overridden. The implementation should call + fireStatusEventForURL and pass the xSingleListener argument to this + method unchanged. + + @param rURL + If empty, all available status events must be fired, otherwise only + the one for the given command. + + @param xSingleListener + If set, the event is only sent to this listener rather than to all + registered ones. Whenever a listener adds itself, this method is + called with this parameter set to give an initial state. + */ + virtual void fireStatusEvent( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) = 0; + + /** calls fireStatusEvent( OUString, xSingleListener ) + */ + void fireAllStatusEvents( + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ); + + /** sends a status event for a specific command to all registered listeners + or only the one given when set. + + @param xSingleListener + If set, the event is only sent to this listener rather than to all + registered ones. Whenever a listener adds itself, this method is + called with this parameter set to give an initial state. + */ + void fireStatusEventForURL( + const OUString & rURL, + const css::uno::Any & rState, + bool bEnabled, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ); + + // ____ XDispatch ____ + virtual void SAL_CALL dispatch( + const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + virtual void SAL_CALL addStatusListener( + const css::uno::Reference< css::frame::XStatusListener >& Control, + const css::util::URL& URL ) override; + virtual void SAL_CALL removeStatusListener( + const css::uno::Reference< css::frame::XStatusListener >& Control, + const css::util::URL& URL ) override; + + // ____ WeakComponentImplHelperBase ____ + /// is called when this is disposed + virtual void SAL_CALL disposing() 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; + +private: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::util::XURLTransformer > m_xURLTransformer; + + typedef std::map< OUString, std::unique_ptr<::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener>> > + tListenerMap; + + tListenerMap m_aListeners; + +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/CommandDispatchContainer.cxx b/chart2/source/controller/main/CommandDispatchContainer.cxx new file mode 100644 index 000000000..d42936ce7 --- /dev/null +++ b/chart2/source/controller/main/CommandDispatchContainer.cxx @@ -0,0 +1,200 @@ +/* -*- 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 <CommandDispatchContainer.hxx> +#include "UndoCommandDispatch.hxx" +#include "StatusBarCommandDispatch.hxx" +#include <DisposeHelper.hxx> +#include "DrawCommandDispatch.hxx" +#include "ShapeController.hxx" +#include <ChartModel.hxx> + +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <rtl/ref.hxx> + +#include <o3tl/sorted_vector.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +CommandDispatchContainer::CommandDispatchContainer( + const Reference< uno::XComponentContext > & xContext ) + :m_xContext( xContext ) + ,m_pDrawCommandDispatch( nullptr ) + ,m_pShapeController( nullptr ) +{ +} + +void CommandDispatchContainer::setModel( + const rtl::Reference<::chart::ChartModel> & xModel ) +{ + // remove all existing dispatcher that base on the old model + m_aCachedDispatches.clear(); + DisposeHelper::DisposeAllElements( m_aToBeDisposedDispatches ); + m_aToBeDisposedDispatches.clear(); + m_xModel = xModel.get(); +} + +void CommandDispatchContainer::setChartDispatch( + const Reference< frame::XDispatch >& rChartDispatch, + o3tl::sorted_vector< OUString > && rChartCommands ) +{ + OSL_ENSURE(rChartDispatch.is(),"Invalid fall back dispatcher!"); + m_xChartDispatcher.set( rChartDispatch ); + m_aChartCommands = std::move(rChartCommands); + m_aToBeDisposedDispatches.push_back( m_xChartDispatcher ); +} + +Reference< frame::XDispatch > CommandDispatchContainer::getDispatchForURL( + const util::URL & rURL ) +{ + static const o3tl::sorted_vector< OUString > s_aContainerDocumentCommands { + "AddDirect", "NewDoc", "Open", + "Save", "SaveAs", "SendMail", + "EditDoc", "ExportDirectToPDF", "PrintDefault"}; + + Reference< frame::XDispatch > xResult; + tDispatchMap::const_iterator aIt( m_aCachedDispatches.find( rURL.Complete )); + if( aIt != m_aCachedDispatches.end()) + { + xResult.set( (*aIt).second ); + } + else + { + rtl::Reference< ::chart::ChartModel > xModel( m_xModel ); + + if( xModel.is() && ( rURL.Path == "Undo" || rURL.Path == "Redo" || + rURL.Path == "GetUndoStrings" || rURL.Path == "GetRedoStrings" ) ) + { + rtl::Reference<CommandDispatch> pDispatch = new UndoCommandDispatch( m_xContext, xModel ); + xResult.set( pDispatch ); + pDispatch->initialize(); + m_aCachedDispatches[ ".uno:Undo" ].set( xResult ); + m_aCachedDispatches[ ".uno:Redo" ].set( xResult ); + m_aCachedDispatches[ ".uno:GetUndoStrings" ].set( xResult ); + m_aCachedDispatches[ ".uno:GetRedoStrings" ].set( xResult ); + m_aToBeDisposedDispatches.push_back( xResult ); + } + else if( xModel.is() && ( rURL.Path == "Context" || rURL.Path == "ModifiedStatus" ) ) + { + Reference< view::XSelectionSupplier > xSelSupp( xModel->getCurrentController(), uno::UNO_QUERY ); + rtl::Reference<CommandDispatch> pDispatch = new StatusBarCommandDispatch( m_xContext, xModel, xSelSupp ); + xResult.set( pDispatch ); + pDispatch->initialize(); + m_aCachedDispatches[ ".uno:Context" ].set( xResult ); + m_aCachedDispatches[ ".uno:ModifiedStatus" ].set( xResult ); + m_aToBeDisposedDispatches.push_back( xResult ); + } + else if( xModel.is() && + (s_aContainerDocumentCommands.find( rURL.Path ) != s_aContainerDocumentCommands.end()) ) + { + xResult.set( getContainerDispatchForURL( xModel->getCurrentController(), rURL )); + // ToDo: can those dispatches be cached? + m_aCachedDispatches[ rURL.Complete ].set( xResult ); + } + else if( m_xChartDispatcher.is() && + (m_aChartCommands.find( rURL.Path ) != m_aChartCommands.end()) ) + { + xResult.set( m_xChartDispatcher ); + m_aCachedDispatches[ rURL.Complete ].set( xResult ); + } + // #i12587# support for shapes in chart + // Note, that the chart dispatcher must be queried first, because + // the chart dispatcher is the default dispatcher for all context + // sensitive commands. + else if ( m_pDrawCommandDispatch && m_pDrawCommandDispatch->isFeatureSupported( rURL.Complete ) ) + { + xResult.set( m_pDrawCommandDispatch ); + m_aCachedDispatches[ rURL.Complete ].set( xResult ); + } + else if ( m_pShapeController && m_pShapeController->isFeatureSupported( rURL.Complete ) ) + { + xResult.set( m_pShapeController ); + m_aCachedDispatches[ rURL.Complete ].set( xResult ); + } + } + + return xResult; +} + +Sequence< Reference< frame::XDispatch > > CommandDispatchContainer::getDispatchesForURLs( + const Sequence< frame::DispatchDescriptor > & aDescriptors ) +{ + sal_Int32 nCount = aDescriptors.getLength(); + uno::Sequence< uno::Reference< frame::XDispatch > > aRet( nCount ); + auto aRetRange = asNonConstRange(aRet); + + for( sal_Int32 nPos = 0; nPos < nCount; ++nPos ) + { + if ( aDescriptors[ nPos ].FrameName == "_self" ) + aRetRange[ nPos ] = getDispatchForURL( aDescriptors[ nPos ].FeatureURL ); + } + return aRet; +} + +void CommandDispatchContainer::DisposeAndClear() +{ + m_aCachedDispatches.clear(); + DisposeHelper::DisposeAllElements( m_aToBeDisposedDispatches ); + m_aToBeDisposedDispatches.clear(); + m_xChartDispatcher.clear(); + m_aChartCommands.clear(); + m_pDrawCommandDispatch = nullptr; + m_pShapeController = nullptr; +} + +Reference< frame::XDispatch > CommandDispatchContainer::getContainerDispatchForURL( + const Reference< frame::XController > & xChartController, + const util::URL & rURL ) +{ + Reference< frame::XDispatch > xResult; + if( xChartController.is()) + { + Reference< frame::XFrame > xFrame( xChartController->getFrame()); + if( xFrame.is()) + { + Reference< frame::XDispatchProvider > xDispProv( xFrame->getCreator(), uno::UNO_QUERY ); + if( xDispProv.is()) + xResult.set( xDispProv->queryDispatch( rURL, "_self", 0 )); + } + } + return xResult; +} + +void CommandDispatchContainer::setDrawCommandDispatch( DrawCommandDispatch* pDispatch ) +{ + m_pDrawCommandDispatch = pDispatch; + m_aToBeDisposedDispatches.emplace_back( pDispatch ); +} + +void CommandDispatchContainer::setShapeController( ShapeController* pController ) +{ + m_pShapeController = pController; + m_aToBeDisposedDispatches.emplace_back( pController ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ConfigurationAccess.cxx b/chart2/source/controller/main/ConfigurationAccess.cxx new file mode 100644 index 000000000..f6dfecc60 --- /dev/null +++ b/chart2/source/controller/main/ConfigurationAccess.cxx @@ -0,0 +1,93 @@ +/* -*- 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 <ConfigurationAccess.hxx> + +#include <unotools/syslocale.hxx> +#include <unotools/configitem.hxx> +#include <unotools/localedatawrapper.hxx> + +namespace chart +{ +using namespace ::com::sun::star; + +namespace +{ +bool lcl_IsMetric() +{ + SvtSysLocale aSysLocale; + MeasurementSystem eSys = aSysLocale.GetLocaleData().getMeasurementSystemEnum(); + + return ( eSys == MeasurementSystem::Metric ); +} + +class CalcConfigItem : public ::utl::ConfigItem +{ +private: + virtual void ImplCommit() override; + +public: + CalcConfigItem(); + + FieldUnit getFieldUnit(); + virtual void Notify( const uno::Sequence<OUString>& aPropertyNames) override; +}; + +}//end anonymous namespace + +CalcConfigItem::CalcConfigItem() + : ConfigItem( "Office.Calc/Layout" ) +{ +} + +void CalcConfigItem::ImplCommit() {} +void CalcConfigItem::Notify( const uno::Sequence<OUString>& ) {} + +FieldUnit CalcConfigItem::getFieldUnit() +{ + FieldUnit eResult( FieldUnit::CM ); + + uno::Sequence< OUString > aNames; + if( lcl_IsMetric() ) + aNames = { "Other/MeasureUnit/Metric" }; + else + aNames = { "Other/MeasureUnit/NonMetric" }; + + uno::Sequence< uno::Any > aResult( GetProperties( aNames )); + sal_Int32 nValue = 0; + if( aResult[ 0 ] >>= nValue ) + eResult = static_cast< FieldUnit >( nValue ); + + return eResult; +} + +namespace ConfigurationAccess +{ + FieldUnit getFieldUnit() + { + //a CalcConfigItem Singleton + static CalcConfigItem SINGLETON; + FieldUnit aUnit( SINGLETON.getFieldUnit() ); + return aUnit; + } +} //namespace ConfigurationAccess + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ControllerCommandDispatch.cxx b/chart2/source/controller/main/ControllerCommandDispatch.cxx new file mode 100644 index 000000000..e5035b4f0 --- /dev/null +++ b/chart2/source/controller/main/ControllerCommandDispatch.cxx @@ -0,0 +1,826 @@ +/* -*- 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 "ControllerCommandDispatch.hxx" +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <TitleHelper.hxx> +#include <LegendHelper.hxx> +#include <ObjectIdentifier.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <ChartController.hxx> +#include <RegressionCurveHelper.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <StatisticsHelper.hxx> +#include <ReferenceSizeProvider.hxx> +#include "ShapeController.hxx" + +#include <vcl/svapp.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/lok.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/objsh.hxx> + +#include <com/sun/star/chart2/XRegressionCurve.hpp> +#include <com/sun/star/chart2/XDataProviderAccess.hpp> + +// only needed until #i68864# is fixed +#include <com/sun/star/frame/XLayoutManager.hpp> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +bool lcl_isStatusBarVisible( const Reference< frame::XController > & xController ) +{ + bool bIsStatusBarVisible = false; + // Status-Bar visible, workaround: this should not be necessary. @todo: + // remove when Issue #i68864# is fixed + if( xController.is()) + { + Reference< beans::XPropertySet > xPropSet( xController->getFrame(), uno::UNO_QUERY ); + if( xPropSet.is() ) + { + uno::Reference< css::frame::XLayoutManager > xLayoutManager; + xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager; + if ( xLayoutManager.is() ) + bIsStatusBarVisible = xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" ); + } + } + return bIsStatusBarVisible; +} + +} // anonymous namespace + +namespace chart +{ + +namespace impl +{ + +/// Constants for moving the series. +namespace { + bool const MOVE_SERIES_FORWARD = true; + bool const MOVE_SERIES_BACKWARD = false; +} + +/** Represents the current state of the controller (needed for issue 63017). + + You can set the state by calling update(). After this call the state is + preserved in this class until the next call to update(). + + This is useful, not to say necessary, for enabling and disabling of menu + entries (e.g. format>arrangement). As the status requests are sent very + frequently it would be impossible, from a performance point of view, to + query the current status every time directly at the model. So this class + serves as a cache for the state. +*/ +struct ControllerState +{ + ControllerState(); + + void update( const Reference< frame::XController > & xController, + const rtl::Reference<::chart::ChartModel> & xModel ); + + // -- State variables ------- + bool bHasSelectedObject; + bool bIsPositionableObject; + bool bIsTextObject; + bool bIsDeleteableObjectSelected; + bool bIsFormateableObjectSelected; + + // May the selected series be moved forward or backward (cf + // format>arrangement). + bool bMayMoveSeriesForward; + bool bMayMoveSeriesBackward; + + // trendlines + bool bMayAddMenuTrendline; + bool bMayAddTrendline; + bool bMayAddTrendlineEquation; + bool bMayAddR2Value; + bool bMayAddMeanValue; + bool bMayAddXErrorBars; + bool bMayAddYErrorBars; + + bool bMayDeleteTrendline; + bool bMayDeleteTrendlineEquation; + bool bMayDeleteR2Value; + bool bMayDeleteMeanValue; + bool bMayDeleteXErrorBars; + bool bMayDeleteYErrorBars; + + bool bMayFormatTrendline; + bool bMayFormatTrendlineEquation; + bool bMayFormatMeanValue; + bool bMayFormatXErrorBars; + bool bMayFormatYErrorBars; +}; + +ControllerState::ControllerState() : + bHasSelectedObject( false ), + bIsPositionableObject( false ), + bIsTextObject(false), + bIsDeleteableObjectSelected(false), + bIsFormateableObjectSelected(false), + bMayMoveSeriesForward( false ), + bMayMoveSeriesBackward( false ), + bMayAddMenuTrendline( false ), + bMayAddTrendline( false ), + bMayAddTrendlineEquation( false ), + bMayAddR2Value( false ), + bMayAddMeanValue( false ), + bMayAddXErrorBars( false ), + bMayAddYErrorBars( false ), + bMayDeleteTrendline( false ), + bMayDeleteTrendlineEquation( false ), + bMayDeleteR2Value( false ), + bMayDeleteMeanValue( false ), + bMayDeleteXErrorBars( false ), + bMayDeleteYErrorBars( false ), + bMayFormatTrendline( false ), + bMayFormatTrendlineEquation( false ), + bMayFormatMeanValue( false ), + bMayFormatXErrorBars( false ), + bMayFormatYErrorBars( false ) +{} + +void ControllerState::update( + const Reference< frame::XController > & xController, + const rtl::Reference<::chart::ChartModel> & xModel ) +{ + Reference< view::XSelectionSupplier > xSelectionSupplier( + xController, uno::UNO_QUERY ); + + // Update ControllerState variables. + if( !xSelectionSupplier.is()) + return; + + uno::Any aSelObj( xSelectionSupplier->getSelection() ); + ObjectIdentifier aSelOID( aSelObj ); + OUString aSelObjCID( aSelOID.getObjectCID() ); + + bHasSelectedObject = aSelOID.isValid(); + + ObjectType aObjectType(ObjectIdentifier::getObjectType( aSelObjCID )); + + bIsPositionableObject = (aObjectType != OBJECTTYPE_DATA_POINT) && aSelOID.isDragableObject(); + bIsTextObject = aObjectType == OBJECTTYPE_TITLE; + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + bIsFormateableObjectSelected = bHasSelectedObject && aSelOID.isAutoGeneratedObject(); + if( aObjectType==OBJECTTYPE_DIAGRAM || aObjectType==OBJECTTYPE_DIAGRAM_WALL || aObjectType==OBJECTTYPE_DIAGRAM_FLOOR ) + bIsFormateableObjectSelected = DiagramHelper::isSupportingFloorAndWall( xDiagram ); + + rtl::Reference< DataSeries > xGivenDataSeries = + ObjectIdentifier::getDataSeriesForCID( + aSelObjCID, xModel ); + + bIsDeleteableObjectSelected = ChartController::isObjectDeleteable( aSelObj ); + + bMayMoveSeriesForward = (aObjectType!=OBJECTTYPE_DATA_POINT) && DiagramHelper::isSeriesMoveable( + ChartModelHelper::findDiagram( xModel ), + xGivenDataSeries, + MOVE_SERIES_FORWARD ); + + bMayMoveSeriesBackward = (aObjectType!=OBJECTTYPE_DATA_POINT) && DiagramHelper::isSeriesMoveable( + ChartModelHelper::findDiagram( xModel ), + xGivenDataSeries, + MOVE_SERIES_BACKWARD ); + + bMayAddMenuTrendline = false; + bMayAddTrendline = false; + bMayAddTrendlineEquation = false; + bMayAddR2Value = false; + bMayAddMeanValue = false; + bMayAddXErrorBars = false; + bMayAddYErrorBars = false; + bMayDeleteTrendline = false; + bMayDeleteTrendlineEquation = false; + bMayDeleteR2Value = false; + bMayDeleteMeanValue = false; + bMayDeleteXErrorBars = false; + bMayDeleteYErrorBars = false; + bMayFormatTrendline = false; + bMayFormatTrendlineEquation = false; + bMayFormatMeanValue = false; + bMayFormatXErrorBars = false; + bMayFormatYErrorBars = false; + if( !bHasSelectedObject ) + return; + + if( xGivenDataSeries.is()) + { + bMayAddMenuTrendline = true; + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + rtl::Reference< ::chart::ChartType > xFirstChartType( + DataSeriesHelper::getChartTypeOfSeries( xGivenDataSeries, xDiagram )); + + // trend lines/mean value line + if( (aObjectType == OBJECTTYPE_DATA_SERIES || aObjectType == OBJECTTYPE_DATA_POINT) + && ChartTypeHelper::isSupportingRegressionProperties( xFirstChartType, nDimensionCount )) + { + // Trendline + bMayAddTrendline = true; + + // Mean Value + bMayFormatMeanValue = bMayDeleteMeanValue = RegressionCurveHelper::hasMeanValueLine( xGivenDataSeries ); + bMayAddMeanValue = ! bMayDeleteMeanValue; + } + + // error bars + if( (aObjectType == OBJECTTYPE_DATA_SERIES || aObjectType == OBJECTTYPE_DATA_POINT) + && ChartTypeHelper::isSupportingStatisticProperties( xFirstChartType, nDimensionCount )) + { + bMayFormatXErrorBars = bMayDeleteXErrorBars = StatisticsHelper::hasErrorBars( xGivenDataSeries, false ); + bMayAddXErrorBars = ! bMayDeleteXErrorBars; + + bMayFormatYErrorBars = bMayDeleteYErrorBars = StatisticsHelper::hasErrorBars( xGivenDataSeries ); + bMayAddYErrorBars = ! bMayDeleteYErrorBars; + } + } + + if( aObjectType == OBJECTTYPE_DATA_AVERAGE_LINE ) + bMayFormatMeanValue = true; + + if( aObjectType == OBJECTTYPE_DATA_ERRORS_X) + bMayFormatXErrorBars = true; + + if( aObjectType == OBJECTTYPE_DATA_ERRORS_Y ) + bMayFormatYErrorBars = true; + + if( aObjectType == OBJECTTYPE_DATA_CURVE ) + { + bMayFormatTrendline = true; + bMayDeleteTrendline = true; + uno::Reference< chart2::XRegressionCurve > xRegCurve( + ObjectIdentifier::getObjectPropertySet( aSelObjCID, xModel ), uno::UNO_QUERY ); + + // Trendline Equation + bMayFormatTrendlineEquation = bMayDeleteTrendlineEquation = RegressionCurveHelper::hasEquation( xRegCurve ); + bMayAddTrendlineEquation = !bMayDeleteTrendlineEquation; + } + else if( aObjectType == OBJECTTYPE_DATA_CURVE_EQUATION ) + { + bMayFormatTrendlineEquation = true; + bool bHasR2Value = false; + try + { + uno::Reference< beans::XPropertySet > xEquationProperties = + ObjectIdentifier::getObjectPropertySet( aSelObjCID, xModel ); + if( xEquationProperties.is() ) + xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient" ) >>= bHasR2Value; + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + bMayAddR2Value = !bHasR2Value; + bMayDeleteR2Value = bHasR2Value; + } +} + +/** Represents the current state of the model. + + You can set the state by calling update(). After this call the state is + preserved in this class until the next call to update(). + + This is useful, not to say necessary, for enabling and disabling of menu + entries and toolbar icons. As the status requests are sent very frequently + it would be impossible, from a performance point of view, to query the + current status every time directly at the model. So this class serves as a + cache for the state. + */ +struct ModelState +{ + ModelState(); + + void update( const rtl::Reference<::chart::ChartModel> & xModel ); + + bool HasAnyAxis() const; + bool HasAnyGrid() const; + bool HasAnyTitle() const; + + bool bIsReadOnly; + bool bIsThreeD; + bool bHasOwnData; + bool bHasDataFromPivotTable; + + bool bHasMainTitle; + bool bHasSubTitle; + bool bHasXAxisTitle; + bool bHasYAxisTitle; + bool bHasZAxisTitle; + bool bHasSecondaryXAxisTitle; + bool bHasSecondaryYAxisTitle; + + bool bHasXAxis; + bool bHasYAxis; + bool bHasZAxis; + bool bHasAAxis; + bool bHasBAxis; + + bool bHasMainXGrid; + bool bHasMainYGrid; + bool bHasMainZGrid; + bool bHasHelpXGrid; + bool bHasHelpYGrid; + bool bHasHelpZGrid; + + bool bHasAutoScaledText; + bool bHasLegend; + bool bHasWall; + bool bHasFloor; + + bool bSupportsStatistics; + bool bSupportsAxes; +}; + +ModelState::ModelState() : + bIsReadOnly(true), + bIsThreeD(false), + bHasOwnData(false), + bHasDataFromPivotTable(false), + bHasMainTitle(false), + bHasSubTitle(false), + bHasXAxisTitle(false), + bHasYAxisTitle(false), + bHasZAxisTitle(false), + bHasSecondaryXAxisTitle(false), + bHasSecondaryYAxisTitle(false), + bHasXAxis(false), + bHasYAxis(false), + bHasZAxis(false), + bHasAAxis(false), + bHasBAxis(false), + bHasMainXGrid(false), + bHasMainYGrid(false), + bHasMainZGrid(false), + bHasHelpXGrid(false), + bHasHelpYGrid(false), + bHasHelpZGrid(false), + bHasAutoScaledText(false), + bHasLegend(false), + bHasWall(false), + bHasFloor(false), + bSupportsStatistics(false), + bSupportsAxes(false) +{} + +void ModelState::update( const rtl::Reference<::chart::ChartModel> & xModel ) +{ + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + + bIsReadOnly = xModel->isReadonly(); + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + + rtl::Reference< ChartType > xFirstChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + bSupportsStatistics = ChartTypeHelper::isSupportingStatisticProperties( xFirstChartType, nDimensionCount ); + bSupportsAxes = ChartTypeHelper::isSupportingMainAxis( xFirstChartType, nDimensionCount, 0 ); + + bIsThreeD = (nDimensionCount == 3); + if (xModel.is()) + { + bHasOwnData = xModel->hasInternalDataProvider(); + bHasDataFromPivotTable = !bHasOwnData && xModel->isDataFromPivotTable(); + } + + bHasMainTitle = TitleHelper::getTitle( TitleHelper::MAIN_TITLE, xModel ).is(); + bHasSubTitle = TitleHelper::getTitle( TitleHelper::SUB_TITLE, xModel ).is(); + bHasXAxisTitle = TitleHelper::getTitle( TitleHelper::X_AXIS_TITLE, xModel ).is(); + bHasYAxisTitle = TitleHelper::getTitle( TitleHelper::Y_AXIS_TITLE, xModel ).is(); + bHasZAxisTitle = TitleHelper::getTitle( TitleHelper::Z_AXIS_TITLE, xModel ).is(); + bHasSecondaryXAxisTitle = TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, xModel ).is(); + bHasSecondaryYAxisTitle = TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, xModel ).is(); + + bHasXAxis = bSupportsAxes && AxisHelper::getAxis( 0, true, xDiagram ).is(); + bHasYAxis = bSupportsAxes && AxisHelper::getAxis( 1, true, xDiagram ).is(); + bHasZAxis = bSupportsAxes && AxisHelper::getAxis( 2, true, xDiagram ).is(); + bHasAAxis = bSupportsAxes && AxisHelper::getAxis( 0, false, xDiagram ).is(); + bHasBAxis = bSupportsAxes && AxisHelper::getAxis( 1, false, xDiagram ).is(); + + bHasMainXGrid = bSupportsAxes && AxisHelper::isGridShown( 0, 0, true, xDiagram ); + bHasMainYGrid = bSupportsAxes && AxisHelper::isGridShown( 1, 0, true, xDiagram ); + bHasMainZGrid = bSupportsAxes && AxisHelper::isGridShown( 2, 0, true, xDiagram ); + bHasHelpXGrid = bSupportsAxes && AxisHelper::isGridShown( 0, 0, false, xDiagram ); + bHasHelpYGrid = bSupportsAxes && AxisHelper::isGridShown( 1, 0, false, xDiagram ); + bHasHelpZGrid = bSupportsAxes && AxisHelper::isGridShown( 2, 0, false, xDiagram ); + + bHasAutoScaledText = + (ReferenceSizeProvider::getAutoResizeState( xModel ) == + ReferenceSizeProvider::AUTO_RESIZE_YES); + + bHasLegend = LegendHelper::hasLegend( xDiagram ); + bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram ); + bHasFloor = bHasWall && bIsThreeD; +} + +bool ModelState::HasAnyAxis() const +{ + return bHasXAxis || bHasYAxis || bHasZAxis || bHasAAxis || bHasBAxis; +} + +bool ModelState::HasAnyGrid() const +{ + return bHasMainXGrid || bHasMainYGrid || bHasMainZGrid || + bHasHelpXGrid || bHasHelpYGrid || bHasHelpZGrid; +} + +bool ModelState::HasAnyTitle() const +{ + return bHasMainTitle || bHasSubTitle || bHasXAxisTitle || bHasYAxisTitle || bHasZAxisTitle || bHasSecondaryXAxisTitle || bHasSecondaryYAxisTitle; +} + +} // namespace impl + +ControllerCommandDispatch::ControllerCommandDispatch( + const Reference< uno::XComponentContext > & xContext, + ChartController* pController, CommandDispatchContainer* pContainer ) : + impl::ControllerCommandDispatch_Base( xContext ), + m_xChartController( pController ), + m_xSelectionSupplier( Reference< view::XSelectionSupplier >( pController ) ), + m_xDispatch( Reference< frame::XDispatch >( pController ) ), + m_apModelState( new impl::ModelState() ), + m_apControllerState( new impl::ControllerState() ), + m_pDispatchContainer( pContainer ) +{ +} + +ControllerCommandDispatch::~ControllerCommandDispatch() +{ +} + +void ControllerCommandDispatch::initialize() +{ + if( !m_xChartController.is()) + return; + + rtl::Reference<::chart::ChartModel> xModel( m_xChartController->getChartModel()); + OSL_ASSERT( xModel.is()); + if( xModel.is()) + xModel->addModifyListener( this ); + + // Listen selection modifications (Arrangement feature - issue 63017). + if( m_xSelectionSupplier.is() ) + m_xSelectionSupplier->addSelectionChangeListener( this ); + + if( m_apModelState && xModel.is()) + m_apModelState->update( xModel ); + + if( m_apControllerState && xModel.is()) + m_apControllerState->update( m_xChartController, xModel ); + + updateCommandAvailability(); +} + +void ControllerCommandDispatch::fireStatusEventForURLImpl( + const OUString & rURL, + const Reference< frame::XStatusListener > & xSingleListener ) +{ + std::map< OUString, uno::Any >::const_iterator aArgIt( m_aCommandArguments.find( rURL )); + if( aArgIt != m_aCommandArguments.end()) + fireStatusEventForURL( rURL, aArgIt->second, commandAvailable( rURL ), xSingleListener ); + else + fireStatusEventForURL( rURL, uno::Any(), commandAvailable( rURL ), xSingleListener ); +} + +void ControllerCommandDispatch::updateCommandAvailability() +{ + bool bModelStateIsValid = (m_apModelState != nullptr); + bool bControllerStateIsValid = (m_apControllerState != nullptr); + // Model and controller states exist. + OSL_ASSERT( bModelStateIsValid ); + OSL_ASSERT( bControllerStateIsValid ); + + // read-only + bool bIsWritable = bModelStateIsValid && (! m_apModelState->bIsReadOnly); + bool bShapeContext = m_xChartController.is() && m_xChartController->isShapeContext(); + + bool bEnableDataTableDialog = false; + bool bCanCreateDataProvider = false; + + if ( m_xChartController.is() ) + { + Reference< beans::XPropertySet > xProps( m_xChartController->getModel(), uno::UNO_QUERY ); + if ( xProps.is() ) + { + try + { + xProps->getPropertyValue("EnableDataTableDialog") >>= bEnableDataTableDialog; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + + rtl::Reference< ChartModel > xChartModel = m_xChartController->getChartModel(); + OSL_ENSURE(xChartModel.is(), "Invalid XChartDocument"); + if ( xChartModel.is() ) + { + css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc(xChartModel->getParent(), uno::UNO_QUERY); + bCanCreateDataProvider = xCreatorDoc.is(); + } + } + + // edit commands + m_aCommandAvailability[ ".uno:Cut" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsDeleteableObjectSelected; + m_aCommandAvailability[ ".uno:Copy" ] = bControllerStateIsValid && m_apControllerState->bHasSelectedObject; + m_aCommandAvailability[ ".uno:Paste" ] = bIsWritable; + + // toolbar commands + m_aCommandAvailability[ ".uno:ToggleGridHorizontal" ] = bIsWritable; + m_aCommandArguments[ ".uno:ToggleGridHorizontal" ] <<= bModelStateIsValid && m_apModelState->bHasMainYGrid; + m_aCommandAvailability[ ".uno:ToggleGridVertical" ] = bIsWritable; + m_aCommandArguments[ ".uno:ToggleGridVertical" ] <<= bModelStateIsValid && m_apModelState->bHasMainXGrid; + + m_aCommandAvailability[ ".uno:ToggleLegend" ] = bIsWritable; + m_aCommandArguments[ ".uno:ToggleLegend" ] <<= bModelStateIsValid && m_apModelState->bHasLegend; + + m_aCommandAvailability[ ".uno:NewArrangement" ] = bIsWritable; + m_aCommandAvailability[ ".uno:Update" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DefaultColors" ] = bIsWritable; + m_aCommandAvailability[ ".uno:BarWidth" ] = bIsWritable; + m_aCommandAvailability[ ".uno:NumberOfLines" ] = bIsWritable; + m_aCommandAvailability[ ".uno:ArrangeRow" ] = + bShapeContext || ( bIsWritable && bControllerStateIsValid && ( m_apControllerState->bMayMoveSeriesForward || m_apControllerState->bMayMoveSeriesBackward ) ); + + // insert objects + m_aCommandAvailability[ ".uno:InsertTitles" ] = m_aCommandAvailability[ ".uno:InsertMenuTitles" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertLegend" ] = m_aCommandAvailability[ ".uno:InsertMenuLegend" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteLegend" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertMenuDataLabels" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertRemoveAxes" ] = m_aCommandAvailability[ ".uno:InsertMenuAxes" ] = bIsWritable && m_apModelState->bSupportsAxes; + m_aCommandAvailability[ ".uno:InsertMenuGrids" ] = bIsWritable && m_apModelState->bSupportsAxes; + m_aCommandAvailability[ ".uno:InsertMenuTrendlines" ] = bIsWritable && m_apModelState->bSupportsStatistics && bControllerStateIsValid && m_apControllerState->bMayAddMenuTrendline; + m_aCommandAvailability[ ".uno:InsertMenuMeanValues" ] = bIsWritable && m_apModelState->bSupportsStatistics; + m_aCommandAvailability[ ".uno:InsertMenuXErrorBars" ] = bIsWritable && m_apModelState->bSupportsStatistics; + m_aCommandAvailability[ ".uno:InsertMenuYErrorBars" ] = bIsWritable && m_apModelState->bSupportsStatistics; + m_aCommandAvailability[ ".uno:InsertSymbol" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsTextObject; + + // format objects + bool bFormatObjectAvailable = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsFormateableObjectSelected; + m_aCommandAvailability[ ".uno:FormatSelection" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatAxis" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatTitle" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatDataSeries" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatDataPoint" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatDataLabels" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatDataLabel" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatXErrorBars; + m_aCommandAvailability[ ".uno:FormatYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatYErrorBars; + m_aCommandAvailability[ ".uno:FormatMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatMeanValue; + m_aCommandAvailability[ ".uno:FormatTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatTrendline; + m_aCommandAvailability[ ".uno:FormatTrendlineEquation" ] = bFormatObjectAvailable && bControllerStateIsValid && m_apControllerState->bMayFormatTrendlineEquation; + m_aCommandAvailability[ ".uno:FormatStockLoss" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatStockGain" ] = bFormatObjectAvailable; + + m_aCommandAvailability[ ".uno:DiagramType" ] = bIsWritable; + m_aCommandAvailability[ ".uno:Legend" ] = bIsWritable && m_apModelState->bHasLegend; + m_aCommandAvailability[ ".uno:DiagramWall" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasWall; + m_aCommandAvailability[ ".uno:DiagramArea" ] = bIsWritable; + + m_aCommandAvailability[ ".uno:TransformDialog" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bHasSelectedObject && m_apControllerState->bIsPositionableObject; + + // 3d commands + m_aCommandAvailability[ ".uno:View3D" ] = bIsWritable && bModelStateIsValid && m_apModelState->bIsThreeD; + m_aCommandAvailability[ ".uno:DiagramFloor" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasFloor; + + //some more format commands with different ui text + m_aCommandAvailability[ ".uno:FormatWall" ] = m_aCommandAvailability[ ".uno:DiagramWall" ]; + m_aCommandAvailability[ ".uno:FormatFloor" ] = m_aCommandAvailability[ ".uno:DiagramFloor" ]; + m_aCommandAvailability[ ".uno:FormatChartArea" ] = m_aCommandAvailability[ ".uno:DiagramArea" ]; + m_aCommandAvailability[ ".uno:FormatLegend" ] = m_aCommandAvailability[ ".uno:Legend" ]; + + // depending on own data and ability to create new data provider + m_aCommandAvailability[".uno:DataRanges"] = bIsWritable && bModelStateIsValid && !m_apModelState->bHasDataFromPivotTable + && ((m_apModelState->bHasOwnData && bCanCreateDataProvider) || !m_apModelState->bHasOwnData); + m_aCommandAvailability[ ".uno:DiagramData" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasOwnData && bEnableDataTableDialog; + + // titles + m_aCommandAvailability[ ".uno:MainTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainTitle; + m_aCommandAvailability[ ".uno:SubTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSubTitle; + m_aCommandAvailability[ ".uno:XTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasXAxisTitle; + m_aCommandAvailability[ ".uno:YTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasYAxisTitle; + m_aCommandAvailability[ ".uno:ZTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasZAxisTitle; + m_aCommandAvailability[ ".uno:SecondaryXTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSecondaryXAxisTitle; + m_aCommandAvailability[ ".uno:SecondaryYTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSecondaryYAxisTitle; + m_aCommandAvailability[ ".uno:AllTitles" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyTitle(); + + // text + m_aCommandAvailability[ ".uno:ScaleText" ] = bIsWritable && bModelStateIsValid ; + m_aCommandArguments[ ".uno:ScaleText" ] <<= bModelStateIsValid && m_apModelState->bHasAutoScaledText; + + // axes + m_aCommandAvailability[ ".uno:DiagramAxisX" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasXAxis; + m_aCommandAvailability[ ".uno:DiagramAxisY" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasYAxis; + m_aCommandAvailability[ ".uno:DiagramAxisZ" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasZAxis; + m_aCommandAvailability[ ".uno:DiagramAxisA" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasAAxis; + m_aCommandAvailability[ ".uno:DiagramAxisB" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasBAxis; + m_aCommandAvailability[ ".uno:DiagramAxisAll" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyAxis(); + + // grids + // note: x and y are swapped in the commands! + m_aCommandAvailability[ ".uno:DiagramGridYMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainXGrid; + m_aCommandAvailability[ ".uno:DiagramGridXMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainYGrid; + m_aCommandAvailability[ ".uno:DiagramGridZMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainZGrid; + m_aCommandAvailability[ ".uno:DiagramGridYHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpXGrid; + m_aCommandAvailability[ ".uno:DiagramGridXHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpYGrid; + m_aCommandAvailability[ ".uno:DiagramGridZHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpZGrid; + m_aCommandAvailability[ ".uno:DiagramGridAll" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyGrid(); + + // series arrangement + m_aCommandAvailability[ ".uno:Forward" ] = ( bShapeContext ? isShapeControllerCommandAvailable( ".uno:Forward" ) : + ( bIsWritable && bControllerStateIsValid && m_apControllerState->bMayMoveSeriesForward && bEnableDataTableDialog ) ); + m_aCommandAvailability[ ".uno:Backward" ] = ( bShapeContext ? isShapeControllerCommandAvailable( ".uno:Backward" ) : + ( bIsWritable && bControllerStateIsValid && m_apControllerState->bMayMoveSeriesBackward && bEnableDataTableDialog ) ); + + m_aCommandAvailability[ ".uno:InsertDataLabels" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertDataLabel" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddMeanValue; + m_aCommandAvailability[ ".uno:InsertTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddTrendline; + m_aCommandAvailability[ ".uno:InsertTrendlineEquation" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddTrendlineEquation; + m_aCommandAvailability[ ".uno:InsertTrendlineEquationAndR2" ] = m_aCommandAvailability[ ".uno:InsertTrendlineEquation" ]; + m_aCommandAvailability[ ".uno:InsertR2Value" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddR2Value; + m_aCommandAvailability[ ".uno:DeleteR2Value" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteR2Value; + + m_aCommandAvailability[ ".uno:InsertXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddXErrorBars; + m_aCommandAvailability[ ".uno:InsertYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddYErrorBars; + + m_aCommandAvailability[ ".uno:DeleteDataLabels" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteDataLabel" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteTrendline; + m_aCommandAvailability[ ".uno:DeleteTrendlineEquation" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteTrendlineEquation; + m_aCommandAvailability[ ".uno:DeleteMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteMeanValue; + m_aCommandAvailability[ ".uno:DeleteXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteXErrorBars; + m_aCommandAvailability[ ".uno:DeleteYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteYErrorBars; + + m_aCommandAvailability[ ".uno:ResetDataPoint" ] = bIsWritable; + m_aCommandAvailability[ ".uno:ResetAllDataPoints" ] = bIsWritable; + + m_aCommandAvailability[ ".uno:InsertAxis" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteAxis" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertAxisTitle" ] = bIsWritable; + m_aCommandAvailability[ ".uno:FormatMajorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertMajorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteMajorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:FormatMinorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertMinorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteMinorGrid" ] = bIsWritable; +} + +bool ControllerCommandDispatch::commandAvailable( const OUString & rCommand ) +{ + std::map< OUString, bool >::const_iterator aIt( m_aCommandAvailability.find( rCommand )); + if( aIt != m_aCommandAvailability.end()) + return aIt->second; + SAL_WARN("chart2", "commandAvailable: command not in availability map:" << rCommand); + return false; +} + +bool ControllerCommandDispatch::isShapeControllerCommandAvailable( const OUString& rCommand ) +{ + ShapeController* pShapeController(nullptr); + { + SolarMutexGuard g; + if (m_pDispatchContainer) + pShapeController = m_pDispatchContainer->getShapeController(); + } + if ( pShapeController ) + { + FeatureState aState( pShapeController->getState( rCommand ) ); + return aState.bEnabled; + } + return false; +} + +void ControllerCommandDispatch::fireStatusEvent( + const OUString & rURL, + const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ ) +{ + bool bIsChartSelectorURL = rURL == ".uno:ChartElementSelector"; + if( rURL.isEmpty() || bIsChartSelectorURL ) + { + uno::Any aArg; + aArg <<= Reference< frame::XController >(m_xChartController); + fireStatusEventForURL( ".uno:ChartElementSelector", aArg, true, xSingleListener ); + } + + if( rURL.isEmpty() ) + { + for (auto const& elem : m_aCommandAvailability) + fireStatusEventForURLImpl( elem.first, xSingleListener ); + } + else if( !bIsChartSelectorURL ) + fireStatusEventForURLImpl( rURL, xSingleListener ); + + // statusbar. Should be handled by base implementation + // @todo: remove if Issue 68864 is fixed + if( rURL.isEmpty() || rURL == ".uno:StatusBarVisible" ) + { + bool bIsStatusBarVisible( lcl_isStatusBarVisible( m_xChartController )); + fireStatusEventForURL( ".uno:StatusBarVisible", uno::Any( bIsStatusBarVisible ), true, xSingleListener ); + } +} + +// ____ XDispatch ____ +void SAL_CALL ControllerCommandDispatch::dispatch( + const util::URL& URL, + const Sequence< beans::PropertyValue >& Arguments ) +{ + if( commandAvailable( URL.Complete )) + m_xDispatch->dispatch( URL, Arguments ); +} + +// ____ WeakComponentImplHelperBase ____ +/// is called when this is disposed +void SAL_CALL ControllerCommandDispatch::disposing() +{ + m_xChartController.clear(); + m_xDispatch.clear(); + m_xSelectionSupplier.clear(); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL ControllerCommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{ + m_xChartController.clear(); + m_xDispatch.clear(); + m_xSelectionSupplier.clear(); +} + +// ____ XModifyListener ____ +void SAL_CALL ControllerCommandDispatch::modified( const lang::EventObject& aEvent ) +{ + bool bUpdateCommandAvailability = false; + + // Update the "ModelState" Struct. + if( m_apModelState && m_xChartController.is()) + { + m_apModelState->update( m_xChartController->getChartModel()); + bUpdateCommandAvailability = true; + } + + // Update the "ControllerState" Struct. + if( m_apControllerState && m_xChartController.is()) + { + m_apControllerState->update( m_xChartController, m_xChartController->getChartModel()); + bUpdateCommandAvailability = true; + } + + if( bUpdateCommandAvailability ) + updateCommandAvailability(); + + if (comphelper::LibreOfficeKit::isActive()) + { + if (SfxViewShell* pViewShell = SfxViewShell::Current()) + if (SfxObjectShell* pObjSh = pViewShell->GetObjectShell()) + pObjSh->SetModified(); + } + + CommandDispatch::modified( aEvent ); +} + +// ____ XSelectionChangeListener ____ +void SAL_CALL ControllerCommandDispatch::selectionChanged( const lang::EventObject& aEvent ) +{ + // Update the "ControllerState" Struct. + if( m_apControllerState && m_xChartController.is()) + { + m_apControllerState->update( m_xChartController, m_xChartController->getChartModel()); + updateCommandAvailability(); + } + + CommandDispatch::modified( aEvent ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ControllerCommandDispatch.hxx b/chart2/source/controller/main/ControllerCommandDispatch.hxx new file mode 100644 index 000000000..38b00c48d --- /dev/null +++ b/chart2/source/controller/main/ControllerCommandDispatch.hxx @@ -0,0 +1,119 @@ +/* -*- 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 "CommandDispatch.hxx" +#include <com/sun/star/view/XSelectionChangeListener.hpp> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> + +#include <memory> + +namespace com::sun::star::view { class XSelectionSupplier; } + +namespace chart +{ + +class ChartController; +class CommandDispatchContainer; + +namespace impl +{ +struct ModelState; +struct ControllerState; + +// #i63017# : need to implement the XSelectionChangeListener in order +// to update the ControllerState when the selection changes. +typedef ::cppu::ImplInheritanceHelper< + CommandDispatch, + css::view::XSelectionChangeListener > + ControllerCommandDispatch_Base; +} + +/** This class is a CommandDispatch that is responsible for all commands that + the ChartController supports. + + This class determines which commands are currently available (via the model + state) and if an available command is called forwards it to the + ChartController. + */ +class ControllerCommandDispatch : public impl::ControllerCommandDispatch_Base +{ +public: + explicit ControllerCommandDispatch( + const css::uno::Reference< css::uno::XComponentContext > & xContext, + ChartController* pController, CommandDispatchContainer* pContainer ); + virtual ~ControllerCommandDispatch() override; + + // late initialisation, especially for adding as listener + virtual void initialize() override; + + bool commandAvailable( const OUString & rCommand ); + +protected: + // ____ XDispatch ____ + virtual void SAL_CALL dispatch( + const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + + // ____ WeakComponentImplHelperBase ____ + /// is called when this is disposed + virtual void SAL_CALL disposing() override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + virtual void fireStatusEvent( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XSelectionChangeListener ____ + virtual void SAL_CALL selectionChanged( + const css::lang::EventObject& aEvent ) override; + +private: + void fireStatusEventForURLImpl( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ); + + void updateCommandAvailability(); + + bool isShapeControllerCommandAvailable( const OUString& rCommand ); + + rtl::Reference<ChartController> m_xChartController; + css::uno::Reference< css::view::XSelectionSupplier > m_xSelectionSupplier; + css::uno::Reference< css::frame::XDispatch > m_xDispatch; + + std::unique_ptr< impl::ModelState > m_apModelState; + std::unique_ptr< impl::ControllerState > m_apControllerState; + + mutable std::map< OUString, bool > m_aCommandAvailability; + mutable std::map< OUString, css::uno::Any > m_aCommandArguments; + + CommandDispatchContainer* m_pDispatchContainer; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_Base.cxx b/chart2/source/controller/main/DragMethod_Base.cxx new file mode 100644 index 000000000..e617acd34 --- /dev/null +++ b/chart2/source/controller/main/DragMethod_Base.cxx @@ -0,0 +1,76 @@ +/* -*- 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 "DragMethod_Base.hxx" +#include <DrawViewWrapper.hxx> +#include <ChartModel.hxx> +#include <ObjectNameProvider.hxx> +#include <ObjectIdentifier.hxx> + +#include <svx/ActionDescriptionProvider.hxx> +#include <vcl/ptrstyle.hxx> + +namespace chart +{ + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::WeakReference; + +DragMethod_Base::DragMethod_Base( DrawViewWrapper& rDrawViewWrapper + , const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , ActionDescriptionProvider::ActionType eActionType ) + : SdrDragMethod( rDrawViewWrapper ) + , m_rDrawViewWrapper(rDrawViewWrapper) + , m_aObjectCID(rObjectCID) + , m_eActionType( eActionType ) + , m_xChartModel( xChartModel.get() ) +{ + setMoveOnly(true); +} +DragMethod_Base::~DragMethod_Base() +{ +} + +rtl::Reference<::chart::ChartModel> DragMethod_Base::getChartModel() const +{ + return m_xChartModel.get(); +} + +OUString DragMethod_Base::getUndoDescription() const +{ + return ActionDescriptionProvider::createDescription( + m_eActionType, + ObjectNameProvider::getName( ObjectIdentifier::getObjectType( m_aObjectCID ))); +} +OUString DragMethod_Base::GetSdrDragComment() const +{ + return getUndoDescription(); +} +PointerStyle DragMethod_Base::GetSdrDragPointer() const +{ + if( IsDraggingPoints() || IsDraggingGluePoints() ) + return PointerStyle::MovePoint; + else + return PointerStyle::Move; +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_Base.hxx b/chart2/source/controller/main/DragMethod_Base.hxx new file mode 100644 index 000000000..497b31f6e --- /dev/null +++ b/chart2/source/controller/main/DragMethod_Base.hxx @@ -0,0 +1,59 @@ +/* -*- 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 <svx/ActionDescriptionProvider.hxx> +#include <svx/svddrgmt.hxx> +#include <unotools/weakref.hxx> + +namespace chart { class DrawViewWrapper; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class ChartModel; + +class DragMethod_Base : public SdrDragMethod +{ +public: + DragMethod_Base( DrawViewWrapper& rDrawViewWrapper, const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , ActionDescriptionProvider::ActionType eActionType = ActionDescriptionProvider::ActionType::Move ); + virtual ~DragMethod_Base() override; + + OUString getUndoDescription() const; + + virtual OUString GetSdrDragComment() const override; + virtual PointerStyle GetSdrDragPointer() const override; + +protected: + rtl::Reference<::chart::ChartModel> getChartModel() const; + +protected: + DrawViewWrapper& m_rDrawViewWrapper; + OUString m_aObjectCID; + ActionDescriptionProvider::ActionType m_eActionType; + +private: + unotools::WeakReference<::chart::ChartModel> m_xChartModel; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_PieSegment.cxx b/chart2/source/controller/main/DragMethod_PieSegment.cxx new file mode 100644 index 000000000..002c54ec0 --- /dev/null +++ b/chart2/source/controller/main/DragMethod_PieSegment.cxx @@ -0,0 +1,151 @@ +/* -*- 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 "DragMethod_PieSegment.hxx" +#include <DrawViewWrapper.hxx> +#include <ChartModel.hxx> +#include <strings.hrc> +#include <ResId.hxx> +#include <ObjectIdentifier.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <tools/diagnose_ex.h> + +namespace chart +{ + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::basegfx::B2DVector; + +DragMethod_PieSegment::DragMethod_PieSegment( DrawViewWrapper& rDrawViewWrapper + , const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) + : DragMethod_Base( rDrawViewWrapper, rObjectCID, xChartModel ) + , m_aStartVector(100.0,100.0) + , m_fInitialOffset(0.0) + , m_fAdditionalOffset(0.0) + , m_aDragDirection(1000.0,1000.0) + , m_fDragRange( 1.0 ) +{ + std::u16string_view aParameter( ObjectIdentifier::getDragParameterString( m_aObjectCID ) ); + + sal_Int32 nOffsetPercent(0); + awt::Point aMinimumPosition(0,0); + awt::Point aMaximumPosition(0,0); + + ObjectIdentifier::parsePieSegmentDragParameterString( + aParameter, nOffsetPercent, aMinimumPosition, aMaximumPosition ); + + m_fInitialOffset = nOffsetPercent / 100.0; + if( m_fInitialOffset < 0.0 ) + m_fInitialOffset = 0.0; + if( m_fInitialOffset > 1.0 ) + m_fInitialOffset = 1.0; + B2DVector aMinVector( aMinimumPosition.X, aMinimumPosition.Y ); + B2DVector aMaxVector( aMaximumPosition.X, aMaximumPosition.Y ); + m_aDragDirection = aMaxVector - aMinVector; + m_fDragRange = m_aDragDirection.scalar( m_aDragDirection ); + if( m_fDragRange == 0.0 ) + m_fDragRange = 1.0; +} +DragMethod_PieSegment::~DragMethod_PieSegment() +{ +} +OUString DragMethod_PieSegment::GetSdrDragComment() const +{ + OUString aStr = SchResId(STR_STATUS_PIE_SEGMENT_EXPLODED); + aStr = aStr.replaceFirst( "%PERCENTVALUE", OUString::number( static_cast<sal_Int32>((m_fAdditionalOffset+m_fInitialOffset)*100.0) )); + return aStr; +} +bool DragMethod_PieSegment::BeginSdrDrag() +{ + Point aStart( DragStat().GetStart() ); + m_aStartVector = B2DVector( aStart.X(), aStart.Y() ); + Show(); + return true; +} +void DragMethod_PieSegment::MoveSdrDrag(const Point& rPnt) +{ + if( !DragStat().CheckMinMoved(rPnt) ) + return; + + //calculate new offset + B2DVector aShiftVector( B2DVector( rPnt.X(), rPnt.Y() ) - m_aStartVector ); + m_fAdditionalOffset = m_aDragDirection.scalar( aShiftVector )/m_fDragRange; // projection + + if( m_fAdditionalOffset < -m_fInitialOffset ) + m_fAdditionalOffset = -m_fInitialOffset; + else if( m_fAdditionalOffset > (1.0-m_fInitialOffset) ) + m_fAdditionalOffset = 1.0 - m_fInitialOffset; + + B2DVector aNewPosVector = m_aStartVector + (m_aDragDirection * m_fAdditionalOffset); + Point aNewPos( static_cast<tools::Long>(aNewPosVector.getX()), static_cast<tools::Long>(aNewPosVector.getY()) ); + if( aNewPos != DragStat().GetNow() ) + { + Hide(); + DragStat().NextMove( aNewPos ); + Show(); + } +} +bool DragMethod_PieSegment::EndSdrDrag(bool /*bCopy*/) +{ + Hide(); + + try + { + rtl::Reference<::chart::ChartModel> xChartModel( getChartModel() ); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPointProperties( + ObjectIdentifier::getObjectPropertySet( m_aObjectCID, xChartModel ) ); + if( xPointProperties.is() ) + xPointProperties->setPropertyValue( "Offset", uno::Any( m_fAdditionalOffset+m_fInitialOffset )); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return true; +} +basegfx::B2DHomMatrix DragMethod_PieSegment::getCurrentTransformation() const +{ + basegfx::B2DHomMatrix aRetval; + + aRetval.translate(DragStat().GetDX(), DragStat().GetDY()); + + return aRetval; +} +void DragMethod_PieSegment::createSdrDragEntries() +{ + SdrObject* pObj = m_rDrawViewWrapper.getSelectedObject(); + SdrPageView* pPV = m_rDrawViewWrapper.GetPageView(); + + if( pObj && pPV ) + { + const basegfx::B2DPolyPolygon aNewPolyPolygon(pObj->TakeXorPoly()); + addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aNewPolyPolygon))); + } +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_PieSegment.hxx b/chart2/source/controller/main/DragMethod_PieSegment.hxx new file mode 100644 index 000000000..8cb498373 --- /dev/null +++ b/chart2/source/controller/main/DragMethod_PieSegment.hxx @@ -0,0 +1,54 @@ +/* -*- 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 "DragMethod_Base.hxx" +#include <basegfx/vector/b2dvector.hxx> + +namespace chart +{ + +class DragMethod_PieSegment : public DragMethod_Base +{ +public: + DragMethod_PieSegment( DrawViewWrapper& rDrawViewWrapper, const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + virtual ~DragMethod_PieSegment() override; + + virtual OUString GetSdrDragComment() const override; + virtual bool BeginSdrDrag() override; + virtual void MoveSdrDrag(const Point& rPnt) override; + virtual bool EndSdrDrag(bool bCopy) override; + + virtual basegfx::B2DHomMatrix getCurrentTransformation() const override; + +protected: + virtual void createSdrDragEntries() override; + +private: + ::basegfx::B2DVector m_aStartVector; + double m_fInitialOffset; + double m_fAdditionalOffset; + ::basegfx::B2DVector m_aDragDirection; + double m_fDragRange; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_RotateDiagram.cxx b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx new file mode 100644 index 000000000..34efccfd9 --- /dev/null +++ b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx @@ -0,0 +1,228 @@ +/* -*- 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 "DragMethod_RotateDiagram.hxx" +#include <DrawViewWrapper.hxx> + +#include <SelectionHelper.hxx> +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <ThreeDHelper.hxx> +#include <defines.hxx> +#include <svx/sdr/overlay/overlaypolypolygon.hxx> + +#include <svx/scene3d.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <svx/sdr/contact/viewcontactofe3dscene.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> + +namespace chart +{ + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +DragMethod_RotateDiagram::DragMethod_RotateDiagram( DrawViewWrapper& rDrawViewWrapper + , const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , RotationDirection eRotationDirection ) + : DragMethod_Base( rDrawViewWrapper, rObjectCID, xChartModel, ActionDescriptionProvider::ActionType::Rotate ) + , m_pScene(nullptr) + , m_aReferenceRect(100,100,100,100) + , m_aStartPos(0,0) + , m_fInitialXAngleRad(0.0) + , m_fInitialYAngleRad(0.0) + , m_fInitialZAngleRad(0.0) + , m_fAdditionalXAngleRad(0.0) + , m_fAdditionalYAngleRad(0.0) + , m_fAdditionalZAngleRad(0.0) + , m_nInitialHorizontalAngleDegree(0) + , m_nInitialVerticalAngleDegree(0) + , m_nAdditionalHorizontalAngleDegree(0) + , m_nAdditionalVerticalAngleDegree(0) + , m_eRotationDirection(eRotationDirection) + , m_bRightAngledAxes(false) +{ + m_pScene = SelectionHelper::getSceneToRotate( rDrawViewWrapper.getNamedSdrObject( rObjectCID ) ); + SdrObject* pObj = rDrawViewWrapper.getSelectedObject(); + if(!(pObj && m_pScene)) + return; + + m_aReferenceRect = pObj->GetLogicRect(); + + m_aWireframePolyPolygon = m_pScene->CreateWireframe(); + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(getChartModel()); + if( !xDiagram.is() ) + return; + + ThreeDHelper::getRotationFromDiagram( xDiagram + , m_nInitialHorizontalAngleDegree, m_nInitialVerticalAngleDegree ); + + ThreeDHelper::getRotationAngleFromDiagram( xDiagram + , m_fInitialXAngleRad, m_fInitialYAngleRad, m_fInitialZAngleRad ); + + if( ChartTypeHelper::isSupportingRightAngledAxes( + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) ) + xDiagram->getPropertyValue("RightAngledAxes") >>= m_bRightAngledAxes; + if(m_bRightAngledAxes) + { + if( m_eRotationDirection==ROTATIONDIRECTION_Z ) + m_eRotationDirection=ROTATIONDIRECTION_FREE; + ThreeDHelper::adaptRadAnglesForRightAngledAxes( m_fInitialXAngleRad, m_fInitialYAngleRad ); + } +} +DragMethod_RotateDiagram::~DragMethod_RotateDiagram() +{ +} +OUString DragMethod_RotateDiagram::GetSdrDragComment() const +{ + return OUString(); +} +bool DragMethod_RotateDiagram::BeginSdrDrag() +{ + m_aStartPos = DragStat().GetStart(); + Show(); + return true; +} +void DragMethod_RotateDiagram::MoveSdrDrag(const Point& rPnt) +{ + if( !DragStat().CheckMinMoved(rPnt) ) + return; + + Hide(); + + //calculate new angle + double fX = M_PI_2 * static_cast<double>(rPnt.Y() - m_aStartPos.Y()) + / (m_aReferenceRect.GetHeight() > 0 ? static_cast<double>(m_aReferenceRect.GetHeight()) : 1.0); + double fY = M_PI * static_cast<double>(rPnt.X() - m_aStartPos.X()) + / (m_aReferenceRect.GetWidth() > 0 ? static_cast<double>(m_aReferenceRect.GetWidth()) : 1.0); + + if( m_eRotationDirection != ROTATIONDIRECTION_Y ) + m_fAdditionalYAngleRad = fY; + else + m_fAdditionalYAngleRad = 0.0; + if( m_eRotationDirection != ROTATIONDIRECTION_X ) + m_fAdditionalXAngleRad = fX; + else + m_fAdditionalXAngleRad = 0.0; + m_fAdditionalZAngleRad = 0.0; + + if( m_eRotationDirection == ROTATIONDIRECTION_Z ) + { + m_fAdditionalXAngleRad = 0.0; + m_fAdditionalYAngleRad = 0.0; + + double fCx = m_aReferenceRect.Center().X(); + double fCy = m_aReferenceRect.Center().Y(); + + m_fAdditionalZAngleRad = atan((fCx - m_aStartPos.X())/(m_aStartPos.Y()-fCy)) + + atan((fCx - rPnt.X())/(fCy-rPnt.Y())); + } + + m_nAdditionalHorizontalAngleDegree = static_cast<sal_Int32>(basegfx::rad2deg(m_fAdditionalXAngleRad)); + m_nAdditionalVerticalAngleDegree = -static_cast<sal_Int32>(basegfx::rad2deg(m_fAdditionalYAngleRad)); + + DragStat().NextMove(rPnt); + Show(); +} +bool DragMethod_RotateDiagram::EndSdrDrag(bool /*bCopy*/) +{ + Hide(); + + if( m_bRightAngledAxes || m_eRotationDirection==ROTATIONDIRECTION_Z ) + { + double fResultX = m_fInitialXAngleRad + m_fAdditionalXAngleRad; + double fResultY = m_fInitialYAngleRad + m_fAdditionalYAngleRad; + double fResultZ = m_fInitialZAngleRad + m_fAdditionalZAngleRad; + + if(m_bRightAngledAxes) + ThreeDHelper::adaptRadAnglesForRightAngledAxes( fResultX, fResultY ); + + ThreeDHelper::setRotationAngleToDiagram( ChartModelHelper::findDiagram( getChartModel() ) + , fResultX, fResultY, fResultZ ); + } + else + { + ThreeDHelper::setRotationToDiagram( ChartModelHelper::findDiagram( getChartModel() ) + , m_nInitialHorizontalAngleDegree+m_nAdditionalHorizontalAngleDegree, m_nInitialVerticalAngleDegree+m_nAdditionalVerticalAngleDegree ); + } + + return true; +} +void DragMethod_RotateDiagram::CreateOverlayGeometry( + sdr::overlay::OverlayManager& rOverlayManager, + const sdr::contact::ObjectContact& rObjectContact) +{ + ::basegfx::B3DHomMatrix aCurrentTransform; + aCurrentTransform.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 ); + + double fResultX = m_fInitialXAngleRad + m_fAdditionalXAngleRad; + double fResultY = m_fInitialYAngleRad + m_fAdditionalYAngleRad; + double fResultZ = m_fInitialZAngleRad + m_fAdditionalZAngleRad; + + if(!m_bRightAngledAxes) + { + if( m_eRotationDirection!=ROTATIONDIRECTION_Z ) + { + ThreeDHelper::convertElevationRotationDegToXYZAngleRad( + m_nInitialHorizontalAngleDegree+m_nAdditionalHorizontalAngleDegree, -(m_nInitialVerticalAngleDegree+m_nAdditionalVerticalAngleDegree) + , fResultX, fResultY, fResultZ ); + } + aCurrentTransform.rotate( fResultX, fResultY, fResultZ ); + } + else + { + ThreeDHelper::adaptRadAnglesForRightAngledAxes( fResultX, fResultY ); + aCurrentTransform.shearXY(fResultY,-fResultX); + } + + if(!(m_aWireframePolyPolygon.count() && m_pScene)) + return; + + const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(m_pScene->GetViewContact()); + const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D()); + const basegfx::B3DHomMatrix aWorldToView(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection() * aViewInfo3D.getOrientation()); + const basegfx::B3DHomMatrix aTransform(aWorldToView * aCurrentTransform); + + // transform to relative scene coordinates + basegfx::B2DPolyPolygon aPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(m_aWireframePolyPolygon, aTransform)); + + // transform to 2D view coordinates + aPolyPolygon.transform(rVCScene.getObjectTransformation()); + + std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew( + new sdr::overlay::OverlayPolyPolygonStripedAndFilled( + aPolyPolygon)); + + insertNewlyCreatedOverlayObjectForSdrDragMethod( + std::move(pNew), + rObjectContact, + rOverlayManager); +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_RotateDiagram.hxx b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx new file mode 100644 index 000000000..69e9050ee --- /dev/null +++ b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx @@ -0,0 +1,86 @@ +/* -*- 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 "DragMethod_Base.hxx" + +#include <basegfx/polygon/b3dpolypolygon.hxx> + +class E3dScene; +namespace chart { class DrawViewWrapper; } + +namespace chart +{ + +class DragMethod_RotateDiagram : public DragMethod_Base +{ +public: + enum RotationDirection + { + ROTATIONDIRECTION_FREE, + ROTATIONDIRECTION_X, + ROTATIONDIRECTION_Y, + ROTATIONDIRECTION_Z + }; + + DragMethod_RotateDiagram( DrawViewWrapper& rDrawViewWrapper + , const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , RotationDirection eRotationDirection + ); + virtual ~DragMethod_RotateDiagram() override; + + virtual OUString GetSdrDragComment() const override; + + virtual bool BeginSdrDrag() override; + virtual void MoveSdrDrag(const Point& rPnt) override; + virtual bool EndSdrDrag(bool bCopy) override; + + virtual void CreateOverlayGeometry( + sdr::overlay::OverlayManager& rOverlayManager, + const sdr::contact::ObjectContact& rObjectContact) override; + +private: + E3dScene* m_pScene; + + tools::Rectangle m_aReferenceRect; + Point m_aStartPos; + basegfx::B3DPolyPolygon m_aWireframePolyPolygon; + + double m_fInitialXAngleRad; + double m_fInitialYAngleRad; + double m_fInitialZAngleRad; + + double m_fAdditionalXAngleRad; + double m_fAdditionalYAngleRad; + double m_fAdditionalZAngleRad; + + sal_Int32 m_nInitialHorizontalAngleDegree; + sal_Int32 m_nInitialVerticalAngleDegree; + + sal_Int32 m_nAdditionalHorizontalAngleDegree; + sal_Int32 m_nAdditionalVerticalAngleDegree; + + RotationDirection m_eRotationDirection; + bool m_bRightAngledAxes; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DrawCommandDispatch.cxx b/chart2/source/controller/main/DrawCommandDispatch.cxx new file mode 100644 index 000000000..c5cea4c5b --- /dev/null +++ b/chart2/source/controller/main/DrawCommandDispatch.cxx @@ -0,0 +1,614 @@ +/* -*- 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 "DrawCommandDispatch.hxx" +#include "DrawCommandDispatch.h" +#include <ChartController.hxx> +#include <DrawViewWrapper.hxx> +#include <chartview/DrawModelWrapper.hxx> + +#include <com/sun/star/frame/CommandGroup.hpp> +#include <o3tl/unsafe_downcast.hxx> +#include <o3tl/string_view.hxx> +#include <vcl/svapp.hxx> +#include <svl/itempool.hxx> +#include <editeng/eeitem.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <svx/fmmodel.hxx> +#include <svx/gallery.hxx> +#include <svx/svdoashp.hxx> +#include <svx/svdocapt.hxx> +#include <svx/svdopath.hxx> +#include <svx/svdpage.hxx> +#include <svx/unoapi.hxx> +#include <svx/xlnedit.hxx> +#include <svx/xlnedwit.hxx> +#include <svx/xlnwtit.hxx> +#include <svx/xtable.hxx> +#include <svx/sdtagitm.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::frame; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + + +namespace chart +{ + +DrawCommandDispatch::DrawCommandDispatch( const Reference< uno::XComponentContext >& rxContext, + ChartController* pController ) + :FeatureCommandDispatchBase( rxContext ) + ,m_pChartController( pController ) +{ +} + +DrawCommandDispatch::~DrawCommandDispatch() +{ +} + +bool DrawCommandDispatch::isFeatureSupported( const OUString& rCommandURL ) +{ + sal_uInt16 nFeatureId = 0; + OUString aBaseCommand; + OUString aCustomShapeType; + return parseCommandURL( rCommandURL, &nFeatureId, &aBaseCommand, &aCustomShapeType ); +} + +static ::basegfx::B2DPolyPolygon getPolygon(TranslateId pResId, const SdrModel& rModel) +{ + ::basegfx::B2DPolyPolygon aReturn; + XLineEndListRef pLineEndList = rModel.GetLineEndList(); + if ( pLineEndList.is() ) + { + OUString aName(SvxResId(pResId)); + tools::Long nCount = pLineEndList->Count(); + for ( tools::Long nIndex = 0; nIndex < nCount; ++nIndex ) + { + const XLineEndEntry* pEntry = pLineEndList->GetLineEnd(nIndex); + if ( pEntry->GetName() == aName ) + { + aReturn = pEntry->GetLineEnd(); + break; + } + } + } + return aReturn; +} + +void DrawCommandDispatch::setAttributes( SdrObject* pObj ) +{ + if ( !m_pChartController ) + return; + + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pDrawModelWrapper && pDrawViewWrapper && pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::CustomShape) ) + return; + + bool bAttributesAppliedFromGallery = false; + if ( GalleryExplorer::GetSdrObjCount( GALLERY_THEME_POWERPOINT ) ) + { + std::vector< OUString > aObjList; + if ( GalleryExplorer::FillObjListTitle( GALLERY_THEME_POWERPOINT, aObjList ) ) + { + for ( size_t i = 0; i < aObjList.size(); ++i ) + { + if ( aObjList[ i ].equalsIgnoreAsciiCase( m_aCustomShapeType ) ) + { + FmFormModel aModel; + SfxItemPool& rPool(aModel.GetItemPool()); + rPool.FreezeIdRanges(); + + if ( GalleryExplorer::GetSdrObj( GALLERY_THEME_POWERPOINT, i, &aModel ) ) + { + const SdrObject* pSourceObj = aModel.GetPage( 0 )->GetObj( 0 ); + if ( pSourceObj ) + { + const SfxItemSet& rSource = pSourceObj->GetMergedItemSet(); + SfxItemSetFixed< + // Ranges from SdrAttrObj: + SDRATTR_START, SDRATTR_SHADOW_LAST, + SDRATTR_MISC_FIRST, + SDRATTR_MISC_LAST, + SDRATTR_TEXTDIRECTION, + SDRATTR_TEXTDIRECTION, + // Graphic attributes, 3D + // properties, CustomShape + // properties: + SDRATTR_GRAF_FIRST, + SDRATTR_CUSTOMSHAPE_LAST, + // Range from SdrTextObj: + EE_ITEMS_START, EE_ITEMS_END> + aDest(pObj->getSdrModelFromSdrObject().GetItemPool()); + aDest.Set( rSource ); + pObj->SetMergedItemSet( aDest ); + Degree100 nAngle = pSourceObj->GetRotateAngle(); + if ( nAngle ) + pObj->NbcRotate( pObj->GetSnapRect().Center(), nAngle ); + bAttributesAppliedFromGallery = true; + } + } + break; + } + } + } + } + if ( !bAttributesAppliedFromGallery ) + { + pObj->SetMergedItem( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) ); + pObj->SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_BLOCK ) ); + pObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( false ) ); + + o3tl::unsafe_downcast< SdrObjCustomShape* >( pObj )->MergeDefaultAttributes( &m_aCustomShapeType ); + } +} + +void DrawCommandDispatch::setLineEnds( SfxItemSet& rAttr ) +{ + if ( !(m_nFeatureId == COMMAND_ID_LINE_ARROW_END && m_pChartController) ) + return; + + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pDrawModelWrapper && pDrawViewWrapper) ) + return; + + ::basegfx::B2DPolyPolygon aArrow( getPolygon( RID_SVXSTR_ARROW, pDrawModelWrapper->getSdrModel() ) ); + if ( !aArrow.count() ) + { + ::basegfx::B2DPolygon aNewArrow; + aNewArrow.append( ::basegfx::B2DPoint( 10.0, 0.0 ) ); + aNewArrow.append( ::basegfx::B2DPoint( 0.0, 30.0) ); + aNewArrow.append( ::basegfx::B2DPoint( 20.0, 30.0 ) ); + aNewArrow.setClosed( true ); + aArrow.append( aNewArrow ); + } + + SfxItemSet aSet( pDrawViewWrapper->GetModel()->GetItemPool() ); + pDrawViewWrapper->GetAttributes( aSet ); + + tools::Long nWidth = 300; // (1/100th mm) + if ( aSet.GetItemState( XATTR_LINEWIDTH ) != SfxItemState::DONTCARE ) + { + tools::Long nValue = aSet.Get( XATTR_LINEWIDTH ).GetValue(); + if ( nValue > 0 ) + { + nWidth = nValue * 3; + } + } + + rAttr.Put( XLineEndItem( SvxResId( RID_SVXSTR_ARROW ), aArrow ) ); + rAttr.Put( XLineEndWidthItem( nWidth ) ); +} + +// WeakComponentImplHelperBase +void DrawCommandDispatch::disposing() +{ +} + +// XEventListener +void DrawCommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{ +} + +FeatureState DrawCommandDispatch::getState( const OUString& rCommand ) +{ + FeatureState aReturn; + aReturn.bEnabled = false; + aReturn.aState <<= false; + + sal_uInt16 nFeatureId = 0; + OUString aBaseCommand; + OUString aCustomShapeType; + if ( parseCommandURL( rCommand, &nFeatureId, &aBaseCommand, &aCustomShapeType ) ) + { + switch ( nFeatureId ) + { + case COMMAND_ID_OBJECT_SELECT: + case COMMAND_ID_DRAW_LINE: + case COMMAND_ID_LINE_ARROW_END: + case COMMAND_ID_DRAW_RECT: + case COMMAND_ID_DRAW_ELLIPSE: + case COMMAND_ID_DRAW_FREELINE_NOFILL: + case COMMAND_ID_DRAW_TEXT: + case COMMAND_ID_DRAW_CAPTION: + case COMMAND_ID_DRAWTBX_CS_BASIC: + case COMMAND_ID_DRAWTBX_CS_SYMBOL: + case COMMAND_ID_DRAWTBX_CS_ARROW: + case COMMAND_ID_DRAWTBX_CS_FLOWCHART: + case COMMAND_ID_DRAWTBX_CS_CALLOUT: + case COMMAND_ID_DRAWTBX_CS_STAR: + { + aReturn.bEnabled = true; + aReturn.aState <<= false; + } + break; + default: + { + aReturn.bEnabled = false; + aReturn.aState <<= false; + } + break; + } + } + + return aReturn; +} + +void DrawCommandDispatch::execute( const OUString& rCommand, const Sequence< beans::PropertyValue>& rArgs ) +{ + ChartDrawMode eDrawMode = CHARTDRAW_SELECT; + SdrObjKind eKind = SdrObjKind::NONE; + + sal_uInt16 nFeatureId = 0; + OUString aBaseCommand; + OUString aCustomShapeType; + if ( !parseCommandURL( rCommand, &nFeatureId, &aBaseCommand, &aCustomShapeType ) ) + return; + + bool bCreate = false; + m_nFeatureId = nFeatureId; + m_aCustomShapeType = aCustomShapeType; + + switch ( nFeatureId ) + { + case COMMAND_ID_OBJECT_SELECT: + { + eDrawMode = CHARTDRAW_SELECT; + eKind = SdrObjKind::NONE; + } + break; + case COMMAND_ID_DRAW_LINE: + case COMMAND_ID_LINE_ARROW_END: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::Line; + } + break; + case COMMAND_ID_DRAW_RECT: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::Rectangle; + } + break; + case COMMAND_ID_DRAW_ELLIPSE: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::CircleOrEllipse; + } + break; + case COMMAND_ID_DRAW_FREELINE_NOFILL: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::FreehandLine; + } + break; + case COMMAND_ID_DRAW_TEXT: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::Text; + bCreate = true; + } + break; + case COMMAND_ID_DRAW_CAPTION: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::Caption; + } + break; + case COMMAND_ID_DRAWTBX_CS_BASIC: + case COMMAND_ID_DRAWTBX_CS_SYMBOL: + case COMMAND_ID_DRAWTBX_CS_ARROW: + case COMMAND_ID_DRAWTBX_CS_FLOWCHART: + case COMMAND_ID_DRAWTBX_CS_CALLOUT: + case COMMAND_ID_DRAWTBX_CS_STAR: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::CustomShape; + } + break; + default: + { + eDrawMode = CHARTDRAW_SELECT; + eKind = SdrObjKind::NONE; + } + break; + } + + if ( !m_pChartController ) + return; + + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !pDrawViewWrapper ) + return; + + SolarMutexGuard aGuard; + m_pChartController->setDrawMode( eDrawMode ); + setInsertObj(eKind); + if ( bCreate ) + { + pDrawViewWrapper->SetCreateMode(); + } + + const beans::PropertyValue* pIter = rArgs.getConstArray(); + const beans::PropertyValue* pEnd = pIter + rArgs.getLength(); + const beans::PropertyValue* pKeyModifier = std::find_if(pIter, pEnd, + [](const beans::PropertyValue& lhs) + {return lhs.Name == "KeyModifier";} ); + sal_Int16 nKeyModifier = 0; + if ( !(pKeyModifier != pEnd && ( pKeyModifier->Value >>= nKeyModifier ) && nKeyModifier == KEY_MOD1) ) + return; + + if ( eDrawMode != CHARTDRAW_INSERT ) + return; + + SdrObject* pObj = createDefaultObject( nFeatureId ); + if ( pObj ) + { + SdrPageView* pPageView = pDrawViewWrapper->GetSdrPageView(); + if (pDrawViewWrapper->InsertObjectAtView(pObj, *pPageView)) + m_pChartController->SetAndApplySelection(Reference<drawing::XShape>(pObj->getUnoShape(), uno::UNO_QUERY)); + if ( nFeatureId == COMMAND_ID_DRAW_TEXT ) + { + m_pChartController->StartTextEdit(); + } + } +} + +void DrawCommandDispatch::describeSupportedFeatures() +{ + implDescribeSupportedFeature( ".uno:SelectObject", COMMAND_ID_OBJECT_SELECT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:Line", COMMAND_ID_DRAW_LINE, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:LineArrowEnd", COMMAND_ID_LINE_ARROW_END, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:Rect", COMMAND_ID_DRAW_RECT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:Ellipse", COMMAND_ID_DRAW_ELLIPSE, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:Freeline_Unfilled", COMMAND_ID_DRAW_FREELINE_NOFILL, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DrawText", COMMAND_ID_DRAW_TEXT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DrawCaption", COMMAND_ID_DRAW_CAPTION, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:BasicShapes", COMMAND_ID_DRAWTBX_CS_BASIC, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:SymbolShapes", COMMAND_ID_DRAWTBX_CS_SYMBOL, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:ArrowShapes", COMMAND_ID_DRAWTBX_CS_ARROW, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:FlowChartShapes", COMMAND_ID_DRAWTBX_CS_FLOWCHART, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:CalloutShapes", COMMAND_ID_DRAWTBX_CS_CALLOUT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:StarShapes", COMMAND_ID_DRAWTBX_CS_STAR, CommandGroup::INSERT ); +} + +void DrawCommandDispatch::setInsertObj(SdrObjKind eObj) +{ + DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr ); + if ( pDrawViewWrapper ) + { + pDrawViewWrapper->SetCurrentObj( eObj /*, Inventor */); + } +} + +SdrObject* DrawCommandDispatch::createDefaultObject( const sal_uInt16 nID ) +{ + SdrObject* pObj = nullptr; + DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr ); + DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr ); + + if ( pDrawViewWrapper && pDrawModelWrapper ) + { + Reference< drawing::XDrawPage > xDrawPage( pDrawModelWrapper->getMainDrawPage() ); + SdrPage* pPage = GetSdrPageFromXDrawPage( xDrawPage ); + if ( pPage ) + { + SolarMutexGuard aGuard; + + pObj = SdrObjFactory::MakeNewObject( + pDrawModelWrapper->getSdrModel(), + pDrawViewWrapper->GetCurrentObjInventor(), + pDrawViewWrapper->GetCurrentObjIdentifier()); + + if ( pObj ) + { + Size aObjectSize( 4000, 2500 ); + tools::Rectangle aPageRect( tools::Rectangle( Point( 0, 0 ), pPage->GetSize() ) ); + Point aObjectPos = aPageRect.Center(); + aObjectPos.AdjustX( -(aObjectSize.Width() / 2) ); + aObjectPos.AdjustY( -(aObjectSize.Height() / 2) ); + tools::Rectangle aRect( aObjectPos, aObjectSize ); + + switch ( nID ) + { + case COMMAND_ID_DRAW_LINE: + case COMMAND_ID_LINE_ARROW_END: + { + if ( auto const pathObj = dynamic_cast<SdrPathObj*>( pObj) ) + { + Point aStart = aRect.TopLeft(); + Point aEnd = aRect.BottomRight(); + sal_Int32 nYMiddle( ( aRect.Top() + aRect.Bottom() ) / 2 ); + basegfx::B2DPolygon aPoly; + aPoly.append( basegfx::B2DPoint( aStart.X(), nYMiddle ) ); + aPoly.append( basegfx::B2DPoint( aEnd.X(), nYMiddle ) ); + pathObj->SetPathPoly(basegfx::B2DPolyPolygon(aPoly)); + SfxItemSet aSet( pDrawModelWrapper->GetItemPool() ); + setLineEnds( aSet ); + pObj->SetMergedItemSet( aSet ); + } + } + break; + case COMMAND_ID_DRAW_FREELINE_NOFILL: + { + if ( auto const pathObj = dynamic_cast<SdrPathObj*>( pObj) ) + { + basegfx::B2DPolygon aInnerPoly; + aInnerPoly.append( basegfx::B2DPoint( aRect.Left(), aRect.Bottom() ) ); + aInnerPoly.appendBezierSegment( + basegfx::B2DPoint( aRect.Left(), aRect.Top() ), + basegfx::B2DPoint( aRect.Center().X(), aRect.Top() ), + basegfx::B2DPoint( aRect.Center().X(), aRect.Center().Y() ) ); + aInnerPoly.appendBezierSegment( + basegfx::B2DPoint( aRect.Center().X(), aRect.Bottom() ), + basegfx::B2DPoint( aRect.Right(), aRect.Bottom() ), + basegfx::B2DPoint( aRect.Right(), aRect.Top() ) ); + basegfx::B2DPolyPolygon aPoly; + aPoly.append( aInnerPoly ); + pathObj->SetPathPoly(aPoly); + } + } + break; + case COMMAND_ID_DRAW_TEXT: + case COMMAND_ID_DRAW_TEXT_VERTICAL: + { + if ( SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( pObj) ) + { + pTextObj->SetLogicRect( aRect ); + bool bVertical = ( nID == COMMAND_ID_DRAW_TEXT_VERTICAL ); + pTextObj->SetVerticalWriting( bVertical ); + if ( bVertical ) + { + SfxItemSet aSet( pDrawModelWrapper->GetItemPool() ); + aSet.Put( makeSdrTextAutoGrowWidthItem( true ) ); + aSet.Put( makeSdrTextAutoGrowHeightItem( false ) ); + aSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_TOP ) ); + aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_RIGHT ) ); + pTextObj->SetMergedItemSet( aSet ); + } + } + } + break; + case COMMAND_ID_DRAW_CAPTION: + case COMMAND_ID_DRAW_CAPTION_VERTICAL: + { + if ( SdrCaptionObj* pCaptionObj = dynamic_cast<SdrCaptionObj*>( pObj) ) + { + bool bIsVertical( nID == COMMAND_ID_DRAW_CAPTION_VERTICAL ); + pCaptionObj->SetVerticalWriting( bIsVertical ); + if ( bIsVertical ) + { + SfxItemSet aSet( pObj->GetMergedItemSet() ); + aSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) ); + aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_RIGHT ) ); + pObj->SetMergedItemSet( aSet ); + } + pCaptionObj->SetLogicRect( aRect ); + pCaptionObj->SetTailPos( + aRect.TopLeft() - Point( aRect.GetWidth() / 2, aRect.GetHeight() / 2 ) ); + } + } + break; + default: + { + pObj->SetLogicRect( aRect ); + SfxItemSet aSet( pDrawModelWrapper->GetItemPool() ); + setAttributes( pObj ); + pObj->SetMergedItemSet( aSet ); + } + break; + } + } + } + } + + return pObj; +} + +bool DrawCommandDispatch::parseCommandURL( const OUString& rCommandURL, sal_uInt16* pnFeatureId, + OUString* pBaseCommand, OUString* pCustomShapeType ) +{ + bool bFound = true; + sal_uInt16 nFeatureId = 0; + OUString aBaseCommand; + OUString aType; + + sal_Int32 nIndex = std::min(sal_Int32(1), rCommandURL.getLength()); + std::u16string_view aToken = o3tl::getToken(rCommandURL, 0, '.', nIndex ); + if ( nIndex == -1 || aToken.empty() ) + { + aBaseCommand = rCommandURL; + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( aBaseCommand ); + if ( aIter != m_aSupportedFeatures.end() ) + { + nFeatureId = aIter->second.nFeatureId; + + switch ( nFeatureId ) + { + case COMMAND_ID_DRAWTBX_CS_BASIC: + { + aType = "diamond"; + } + break; + case COMMAND_ID_DRAWTBX_CS_SYMBOL: + { + aType = "smiley"; + } + break; + case COMMAND_ID_DRAWTBX_CS_ARROW: + { + aType = "left-right-arrow"; + } + break; + case COMMAND_ID_DRAWTBX_CS_FLOWCHART: + { + aType = "flowchart-internal-storage"; + } + break; + case COMMAND_ID_DRAWTBX_CS_CALLOUT: + { + aType = "round-rectangular-callout"; + } + break; + case COMMAND_ID_DRAWTBX_CS_STAR: + { + aType = "star5"; + } + break; + default: + { + } + break; + } + } + else + { + bFound = false; + } + } + else + { + aBaseCommand = rCommandURL.copy( 0, nIndex - 1 ); + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( aBaseCommand ); + if ( aIter != m_aSupportedFeatures.end() ) + { + nFeatureId = aIter->second.nFeatureId; + aType = rCommandURL.getToken( 0, '.', nIndex ); + } + else + { + bFound = false; + } + } + + *pnFeatureId = nFeatureId; + *pBaseCommand = aBaseCommand; + *pCustomShapeType = aType; + + return bFound; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DrawCommandDispatch.h b/chart2/source/controller/main/DrawCommandDispatch.h new file mode 100644 index 000000000..faf70bde1 --- /dev/null +++ b/chart2/source/controller/main/DrawCommandDispatch.h @@ -0,0 +1,42 @@ +/* -*- 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 . + */ +#ifndef CHART_DRAWCOMMANDDISPATCH_HRC +#define CHART_DRAWCOMMANDDISPATCH_HRC + +//Command Ids: +#define COMMAND_ID_OBJECT_SELECT 1 +#define COMMAND_ID_DRAW_LINE 2 +#define COMMAND_ID_LINE_ARROW_END 3 +#define COMMAND_ID_DRAW_RECT 4 +#define COMMAND_ID_DRAW_ELLIPSE 5 +#define COMMAND_ID_DRAW_FREELINE_NOFILL 6 +#define COMMAND_ID_DRAW_TEXT 7 +#define COMMAND_ID_DRAW_TEXT_VERTICAL 8 +#define COMMAND_ID_DRAW_CAPTION 9 +#define COMMAND_ID_DRAW_CAPTION_VERTICAL 10 +#define COMMAND_ID_DRAWTBX_CS_BASIC 11 +#define COMMAND_ID_DRAWTBX_CS_SYMBOL 12 +#define COMMAND_ID_DRAWTBX_CS_ARROW 13 +#define COMMAND_ID_DRAWTBX_CS_FLOWCHART 14 +#define COMMAND_ID_DRAWTBX_CS_CALLOUT 15 +#define COMMAND_ID_DRAWTBX_CS_STAR 16 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DrawCommandDispatch.hxx b/chart2/source/controller/main/DrawCommandDispatch.hxx new file mode 100644 index 000000000..febfa8338 --- /dev/null +++ b/chart2/source/controller/main/DrawCommandDispatch.hxx @@ -0,0 +1,73 @@ +/* -*- 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 <svx/svdobjkind.hxx> +#include "FeatureCommandDispatchBase.hxx" + +class SfxItemSet; +class SdrObject; + +namespace chart +{ + +class ChartController; + +/** This is a CommandDispatch implementation for drawing objects. + */ +class DrawCommandDispatch: public FeatureCommandDispatchBase +{ +public: + DrawCommandDispatch( const css::uno::Reference< css::uno::XComponentContext >& rxContext, ChartController* pController ); + virtual ~DrawCommandDispatch() override; + + virtual bool isFeatureSupported( const OUString& rCommandURL ) override; + + void setAttributes( SdrObject* pObj ); + void setLineEnds( SfxItemSet& rAttr ); + +protected: + // WeakComponentImplHelperBase + virtual void SAL_CALL disposing() override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // state of a feature + virtual FeatureState getState( const OUString& rCommand ) override; + + // execute a feature + virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) override; + + // all the features which should be handled by this class + virtual void describeSupportedFeatures() override; + +private: + void setInsertObj(SdrObjKind eObj); + SdrObject* createDefaultObject( const sal_uInt16 nID ); + + bool parseCommandURL( const OUString& rCommandURL, sal_uInt16* pnFeatureId, OUString* pBaseCommand, OUString* pCustomShapeType ); + + ChartController* m_pChartController; + OUString m_aCustomShapeType; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ElementSelector.cxx b/chart2/source/controller/main/ElementSelector.cxx new file mode 100644 index 000000000..d538108ae --- /dev/null +++ b/chart2/source/controller/main/ElementSelector.cxx @@ -0,0 +1,319 @@ +/* -*- 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 "ElementSelector.hxx" +#include <ObjectNameProvider.hxx> +#include <ObjectHierarchy.hxx> +#include <servicenames.hxx> +#include <DrawViewWrapper.hxx> +#include <ResId.hxx> +#include <strings.hrc> +#include <ObjectIdentifier.hxx> +#include <ChartController.hxx> +#include <ChartModel.hxx> + +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/safeint.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/svapp.hxx> + +namespace chart { class ExplicitValueProvider; } + +namespace chart +{ + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +constexpr OUStringLiteral lcl_aServiceName + = u"com.sun.star.comp.chart.ElementSelectorToolbarController"; +} + +SelectorListBox::SelectorListBox(vcl::Window* pParent) + : InterimItemWindow(pParent, "modules/schart/ui/combobox.ui", "ComboBox") + , m_xWidget(m_xBuilder->weld_combo_box("combobox")) + , m_bReleaseFocus(true) +{ + InitControlBase(m_xWidget.get()); + + m_xWidget->connect_key_press(LINK(this, SelectorListBox, KeyInputHdl)); + m_xWidget->connect_changed(LINK(this, SelectorListBox, SelectHdl)); + m_xWidget->connect_focus_out(LINK(this, SelectorListBox, FocusOutHdl)); + + ::Size aLogicalSize(75, 0); + ::Size aPixelSize = LogicToPixel(aLogicalSize, MapMode(MapUnit::MapAppFont)); + m_xWidget->set_size_request(aPixelSize.Width(), -1); + SetSizePixel(m_xContainer->get_preferred_size()); +} + +void SelectorListBox::dispose() +{ + m_xWidget.reset(); + InterimItemWindow::dispose(); +} + +SelectorListBox::~SelectorListBox() +{ + disposeOnce(); +} + +static void lcl_addObjectsToList( const ObjectHierarchy& rHierarchy, const ObjectIdentifier & rParent, std::vector< ListBoxEntryData >& rEntries + , const sal_Int32 nHierarchyDepth, const rtl::Reference<::chart::ChartModel>& xChartDoc ) +{ + ObjectHierarchy::tChildContainer aChildren( rHierarchy.getChildren(rParent) ); + for (auto const& child : aChildren) + { + ListBoxEntryData aEntry; + aEntry.OID = child; + aEntry.UIName = ObjectNameProvider::getNameForCID( child.getObjectCID(), xChartDoc ); + aEntry.nHierarchyDepth = nHierarchyDepth; + rEntries.push_back(aEntry); + lcl_addObjectsToList( rHierarchy, child, rEntries, nHierarchyDepth+1, xChartDoc ); + } +} + +void SelectorListBox::SetChartController( const rtl::Reference< ::chart::ChartController >& xChartController ) +{ + m_xChartController = xChartController.get(); +} + +void SelectorListBox::UpdateChartElementsListAndSelection() +{ + m_xWidget->clear(); + m_aEntries.clear(); + + rtl::Reference< ::chart::ChartController > xChartController = m_xChartController.get(); + if( xChartController.is() ) + { + ObjectIdentifier aSelectedOID( xChartController->getSelection() ); + OUString aSelectedCID = aSelectedOID.getObjectCID(); + + rtl::Reference<::chart::ChartModel> xChartDoc = xChartController->getChartModel(); + ObjectType eType( aSelectedOID.getObjectType() ); + bool bAddSelectionToList = false; + if ( eType == OBJECTTYPE_DATA_POINT || eType == OBJECTTYPE_DATA_LABEL || eType == OBJECTTYPE_SHAPE ) + bAddSelectionToList = true; + + Reference< uno::XInterface > xChartView; + rtl::Reference< ChartModel > xFact = xChartController->getChartModel(); + if( xFact.is() ) + xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME ); + ExplicitValueProvider* pExplicitValueProvider = nullptr; //ExplicitValueProvider::getExplicitValueProvider(xChartView); this creates all visible data points, that's too much + ObjectHierarchy aHierarchy( xChartDoc, pExplicitValueProvider, true /*bFlattenDiagram*/, true /*bOrderingForElementSelector*/ ); + lcl_addObjectsToList( aHierarchy, ::chart::ObjectHierarchy::getRootNodeOID(), m_aEntries, 0, xChartDoc ); + + if( bAddSelectionToList ) + { + if ( aSelectedOID.isAutoGeneratedObject() ) + { + OUString aSeriesCID = ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::getSeriesParticleFromCID( aSelectedCID ) ); + std::vector< ListBoxEntryData >::iterator aIt = std::find_if(m_aEntries.begin(), m_aEntries.end(), + [&aSeriesCID](const ListBoxEntryData& rEntry) { return rEntry.OID.getObjectCID().match(aSeriesCID); }); + if (aIt != m_aEntries.end()) + { + ListBoxEntryData aEntry; + aEntry.UIName = ObjectNameProvider::getNameForCID( aSelectedCID, xChartDoc ); + aEntry.OID = aSelectedOID; + ++aIt; + if( aIt != m_aEntries.end() ) + m_aEntries.insert(aIt, aEntry); + else + m_aEntries.push_back( aEntry ); + } + } + else if ( aSelectedOID.isAdditionalShape() ) + { + ListBoxEntryData aEntry; + SdrObject* pSelectedObj = DrawViewWrapper::getSdrObject( aSelectedOID.getAdditionalShape() ); + OUString aName = pSelectedObj ? pSelectedObj->GetName() : OUString(); + aEntry.UIName = ( aName.isEmpty() ? SchResId( STR_OBJECT_SHAPE ) : aName ); + aEntry.OID = aSelectedOID; + m_aEntries.push_back( aEntry ); + } + } + + m_xWidget->freeze(); + sal_uInt16 nEntryPosToSelect = 0; bool bSelectionFound = false; + sal_uInt16 nN=0; + for (auto const& entry : m_aEntries) + { + // tdf#152087 strip any newlines from the entry + m_xWidget->append_text(entry.UIName.replaceAll("\n", " ")); + if ( !bSelectionFound && aSelectedOID == entry.OID ) + { + nEntryPosToSelect = nN; + bSelectionFound = true; + } + ++nN; + } + m_xWidget->thaw(); + + if( bSelectionFound ) + m_xWidget->set_active(nEntryPosToSelect); + } + m_xWidget->save_value(); //remind current selection pos +} + +void SelectorListBox::ReleaseFocus_Impl() +{ + if ( !m_bReleaseFocus ) + { + m_bReleaseFocus = true; + return; + } + + rtl::Reference< ::chart::ChartController > xController = m_xChartController.get(); + Reference< frame::XFrame > xFrame( xController->getFrame() ); + if ( xFrame.is() && xFrame->getContainerWindow().is() ) + xFrame->getContainerWindow()->setFocus(); +} + +IMPL_LINK(SelectorListBox, SelectHdl, weld::ComboBox&, rComboBox, void) +{ + if (rComboBox.changed_by_direct_pick()) + { + const sal_Int32 nPos = rComboBox.get_active(); + if (o3tl::make_unsigned(nPos) < m_aEntries.size()) + { + ObjectIdentifier aOID = m_aEntries[nPos].OID; + rtl::Reference< ::chart::ChartController > xController = m_xChartController.get(); + if( xController.is() ) + xController->select( aOID.getAny() ); + } + ReleaseFocus_Impl(); + } +} + +IMPL_LINK(SelectorListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled = false; + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + switch ( nCode ) + { + case KEY_RETURN: + case KEY_TAB: + { + if ( nCode == KEY_TAB ) + m_bReleaseFocus = false; + else + bHandled = true; + SelectHdl(*m_xWidget); + break; + } + + case KEY_ESCAPE: + m_xWidget->set_active_text(m_xWidget->get_saved_value()); //restore saved selection + ReleaseFocus_Impl(); + break; + } + + return bHandled || ChildKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(SelectorListBox, FocusOutHdl, weld::Widget&, void) +{ + if (m_xWidget && !m_xWidget->has_focus()) // comboboxes can be comprised of multiple widgets, ensure all have lost focus + m_xWidget->set_active_text(m_xWidget->get_saved_value()); +} + +OUString SAL_CALL ElementSelectorToolbarController::getImplementationName() +{ + return lcl_aServiceName; +} + +sal_Bool SAL_CALL ElementSelectorToolbarController::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ElementSelectorToolbarController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} +ElementSelectorToolbarController::ElementSelectorToolbarController() +{ +} +ElementSelectorToolbarController::~ElementSelectorToolbarController() +{ +} +// XInterface +Any SAL_CALL ElementSelectorToolbarController::queryInterface( const Type& _rType ) +{ + Any aReturn = ToolboxController::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ElementSelectorToolbarController_BASE::queryInterface(_rType); + return aReturn; +} +void SAL_CALL ElementSelectorToolbarController::acquire() noexcept +{ + ToolboxController::acquire(); +} +void SAL_CALL ElementSelectorToolbarController::release() noexcept +{ + ToolboxController::release(); +} +void SAL_CALL ElementSelectorToolbarController::statusChanged( const frame::FeatureStateEvent& rEvent ) +{ + if( m_apSelectorListBox ) + { + SolarMutexGuard aSolarMutexGuard; + if ( rEvent.FeatureURL.Path == "ChartElementSelector" ) + { + Reference< frame::XController > xChartController; + rEvent.State >>= xChartController; + ::chart::ChartController* pController = dynamic_cast<::chart::ChartController*>(xChartController.get()); + assert(!xChartController || pController); + m_apSelectorListBox->SetChartController( pController ); + m_apSelectorListBox->UpdateChartElementsListAndSelection(); + } + } +} +uno::Reference< awt::XWindow > SAL_CALL ElementSelectorToolbarController::createItemWindow( const uno::Reference< awt::XWindow >& xParent ) +{ + uno::Reference< awt::XWindow > xItemWindow; + if( !m_apSelectorListBox ) + { + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent ); + if( pParent ) + { + m_apSelectorListBox.reset(VclPtr<SelectorListBox>::Create(pParent)); + } + } + if( m_apSelectorListBox ) + xItemWindow = VCLUnoHelper::GetInterface( m_apSelectorListBox.get() ); + return xItemWindow; +} + +} // chart2 + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_ElementSelectorToolbarController_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new chart::ElementSelectorToolbarController ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ElementSelector.hxx b/chart2/source/controller/main/ElementSelector.hxx new file mode 100644 index 000000000..fb1e4e052 --- /dev/null +++ b/chart2/source/controller/main/ElementSelector.hxx @@ -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 . + */ +#pragma once + +#include <ObjectIdentifier.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase1.hxx> +#include <svtools/toolboxcontroller.hxx> + +#include <vcl/InterimItemWindow.hxx> +#include <unotools/weakref.hxx> + +namespace chart +{ +class ChartController; + +struct ListBoxEntryData +{ + OUString UIName; + ObjectIdentifier OID; + sal_Int32 nHierarchyDepth; + + ListBoxEntryData() : nHierarchyDepth(0) + { + } +}; + +class SelectorListBox final : public InterimItemWindow +{ +public: + SelectorListBox(vcl::Window* pParent); + virtual void dispose() override; + virtual ~SelectorListBox() override; + + void ReleaseFocus_Impl(); + + void SetChartController( const rtl::Reference< ::chart::ChartController >& xChartController ); + void UpdateChartElementsListAndSelection(); + +private: + unotools::WeakReference<::chart::ChartController> m_xChartController; + std::unique_ptr<weld::ComboBox> m_xWidget; + + std::vector<ListBoxEntryData> m_aEntries; + + bool m_bReleaseFocus; + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(SelectHdl, weld::ComboBox&, void); + DECL_LINK(FocusOutHdl, weld::Widget&, void); +}; + +typedef ::cppu::ImplHelper1 < css::lang::XServiceInfo> ElementSelectorToolbarController_BASE; + +class ElementSelectorToolbarController : public ::svt::ToolboxController + , public ElementSelectorToolbarController_BASE +{ +public: + explicit ElementSelectorToolbarController(); + virtual ~ElementSelectorToolbarController() override; + + // XServiceInfo + 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; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override; + // XToolbarController + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override; + +private: + VclPtr< SelectorListBox > m_apSelectorListBox; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/FeatureCommandDispatchBase.cxx b/chart2/source/controller/main/FeatureCommandDispatchBase.cxx new file mode 100644 index 000000000..90dcf77b2 --- /dev/null +++ b/chart2/source/controller/main/FeatureCommandDispatchBase.cxx @@ -0,0 +1,94 @@ +/* -*- 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 "FeatureCommandDispatchBase.hxx" + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +FeatureCommandDispatchBase::FeatureCommandDispatchBase( const Reference< uno::XComponentContext >& rxContext ) + :CommandDispatch( rxContext ) + ,m_nFeatureId( 0 ) +{ +} + +FeatureCommandDispatchBase::~FeatureCommandDispatchBase() +{ +} + +void FeatureCommandDispatchBase::initialize() +{ + CommandDispatch::initialize(); + describeSupportedFeatures(); +} + +bool FeatureCommandDispatchBase::isFeatureSupported( const OUString& rCommandURL ) +{ + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommandURL ); + return aIter != m_aSupportedFeatures.end(); +} + +void FeatureCommandDispatchBase::fireStatusEvent( const OUString& rURL, + const Reference< frame::XStatusListener >& xSingleListener /* = 0 */ ) +{ + if ( rURL.isEmpty() ) + { + for (auto const& elem : m_aSupportedFeatures) + { + FeatureState aFeatureState( getState(elem.first) ); + fireStatusEventForURL( elem.first, aFeatureState.aState, aFeatureState.bEnabled, xSingleListener ); + } + } + else + { + FeatureState aFeatureState( getState( rURL ) ); + fireStatusEventForURL( rURL, aFeatureState.aState, aFeatureState.bEnabled, xSingleListener ); + } +} + +// XDispatch +void FeatureCommandDispatchBase::dispatch( const util::URL& URL, + const Sequence< beans::PropertyValue >& Arguments ) +{ + OUString aCommand( URL.Complete ); + if ( getState( aCommand ).bEnabled ) + { + execute( aCommand, Arguments ); + } +} + +void FeatureCommandDispatchBase::implDescribeSupportedFeature( const char* pAsciiCommandURL, + sal_uInt16 nId, sal_Int16 nGroup ) +{ + ControllerFeature aFeature; + aFeature.Command = OUString::createFromAscii( pAsciiCommandURL ); + aFeature.nFeatureId = nId; + aFeature.GroupId = nGroup; + + m_aSupportedFeatures[ aFeature.Command ] = aFeature; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/FeatureCommandDispatchBase.hxx b/chart2/source/controller/main/FeatureCommandDispatchBase.hxx new file mode 100644 index 000000000..0c291a684 --- /dev/null +++ b/chart2/source/controller/main/FeatureCommandDispatchBase.hxx @@ -0,0 +1,97 @@ +/* -*- 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 "CommandDispatch.hxx" + +#include <com/sun/star/frame/DispatchInformation.hpp> + +namespace chart +{ + +struct ControllerFeature: public css::frame::DispatchInformation +{ + sal_uInt16 nFeatureId; +}; + +typedef std::map< OUString, + ControllerFeature > SupportedFeatures; + +struct FeatureState +{ + bool bEnabled; + css::uno::Any aState; + + FeatureState() : bEnabled( false ) { } +}; + +/** This is a base class for CommandDispatch implementations with feature support. + */ +class FeatureCommandDispatchBase: public CommandDispatch +{ +public: + explicit FeatureCommandDispatchBase( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~FeatureCommandDispatchBase() override; + + // late initialisation, especially for adding as listener + virtual void initialize() override; + + virtual bool isFeatureSupported( const OUString& rCommandURL ); + +protected: + // XDispatch + virtual void SAL_CALL dispatch( const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + + virtual void fireStatusEvent( const OUString& rURL, + const css::uno::Reference< css::frame::XStatusListener >& xSingleListener ) override; + + // state of a feature + virtual FeatureState getState( const OUString& rCommand ) = 0; + + // execute a feature + virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) = 0; + + // all the features which should be handled by this class + virtual void describeSupportedFeatures() = 0; + + /** describes a feature supported by the controller + + Must not be called outside <member>describeSupportedFeatures</member>. + + @param pAsciiCommandURL + the URL of the feature command + @param nId + the id of the feature. Later references to this feature usually happen by id, not by + URL. + @param nGroup + the command group of the feature. This is important for configuring the controller UI + by the user, see also <type scope="css::frame">CommandGroup</type>. + */ + void implDescribeSupportedFeature( const char* pAsciiCommandURL, sal_uInt16 nId, + sal_Int16 nGroup ); + + mutable SupportedFeatures m_aSupportedFeatures; + + sal_uInt16 m_nFeatureId; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ObjectHierarchy.cxx b/chart2/source/controller/main/ObjectHierarchy.cxx new file mode 100644 index 000000000..5a04b7ae4 --- /dev/null +++ b/chart2/source/controller/main/ObjectHierarchy.cxx @@ -0,0 +1,718 @@ +/* -*- 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 <ObjectHierarchy.hxx> +#include <ObjectIdentifier.hxx> +#include <ChartModelHelper.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <RegressionCurveHelper.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <chartview/ExplicitValueProvider.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <ChartModel.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <LegendHelper.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <unonames.hxx> +#include <BaseCoordinateSystem.hxx> + +#include <map> +#include <algorithm> +#include <cstddef> + +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/chart/ErrorBarStyle.hpp> + +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/awt/Key.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +void lcl_getChildOIDs( + ::chart::ObjectHierarchy::tChildContainer& rOutChildren, + const Reference< container::XIndexAccess >& xShapes ) +{ + if( !xShapes.is()) + return; + + sal_Int32 nCount = xShapes->getCount(); + for( sal_Int32 i=0; i<nCount; ++i) + { + Reference< beans::XPropertySet > xShapeProp( xShapes->getByIndex( i ), uno::UNO_QUERY ); + if( xShapeProp.is()) + { + Reference< beans::XPropertySetInfo > xInfo( xShapeProp->getPropertySetInfo()); + OUString aName; + if( xInfo.is() && + xInfo->hasPropertyByName( "Name") && + (xShapeProp->getPropertyValue( "Name") >>= aName ) && + !aName.isEmpty() && + ::chart::ObjectIdentifier::isCID( aName )) + { + rOutChildren.emplace_back( aName ); + } + Reference< container::XIndexAccess > xNewShapes( xShapeProp, uno::UNO_QUERY ); + if( xNewShapes.is()) + lcl_getChildOIDs( rOutChildren, xNewShapes ); + } + } +} + +void lcl_addAxisTitle( const rtl::Reference< ::chart::Axis >& xAxis, ::chart::ObjectHierarchy::tChildContainer& rContainer, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + if( xAxis.is()) + { + Reference< XTitle > xAxisTitle( xAxis->getTitleObject()); + if( xAxisTitle.is()) + rContainer.emplace_back( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xAxisTitle, xChartModel ) ); + } +} + +} // anonymous namespace + +namespace chart +{ + +void ObjectHierarchy::createTree( const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + m_aChildMap = tChildMap();//clear tree + + if( !xChartDocument.is() ) + return; + + //@todo: change ObjectIdentifier to take an XChartDocument rather than XModel + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartDocument ); + ObjectIdentifier aDiaOID; + if( xDiagram.is() ) + aDiaOID = ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( static_cast<cppu::OWeakObject*>(xDiagram.get()), xChartDocument ) ); + ObjectHierarchy::tChildContainer aTopLevelContainer; + + // First Level + + // Chart Area + if( m_bOrderingForElementSelector ) + { + aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) ); + if( xDiagram.is() ) + { + aTopLevelContainer.push_back( aDiaOID ); + createWallAndFloor( aTopLevelContainer, xDiagram ); + createLegendTree( aTopLevelContainer, xChartDocument, xDiagram ); + } + } + + // Main Title + Reference< XTitle > xMainTitle( xChartDocument->getTitleObject()); + if( xMainTitle.is()) + aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xMainTitle, xChartDocument ) ); + + if( xDiagram.is()) + { + // Sub Title. Note: This is interpreted of being top level + Reference< XTitle > xSubTitle( xDiagram->getTitleObject()); + if( xSubTitle.is()) + aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xSubTitle, xChartDocument ) ); + + if( !m_bOrderingForElementSelector ) + { + // Axis Titles. Note: These are interpreted of being top level + const std::vector< rtl::Reference< Axis > > aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram ); + for( rtl::Reference< Axis > const & axis : aAxes ) + lcl_addAxisTitle( axis, aTopLevelContainer, xChartDocument ); + + // Diagram + aTopLevelContainer.push_back( aDiaOID ); + } + + if( m_bFlattenDiagram ) + createDiagramTree( aTopLevelContainer, xChartDocument, xDiagram ); + else + { + ObjectHierarchy::tChildContainer aSubContainer; + createDiagramTree( aSubContainer, xChartDocument, xDiagram ); + if( !aSubContainer.empty() ) + m_aChildMap[ aDiaOID ] = aSubContainer; + } + + if( !m_bOrderingForElementSelector ) + createLegendTree( aTopLevelContainer, xChartDocument, xDiagram ); + } + + // #i12587# support for shapes in chart + if ( !m_bOrderingForElementSelector ) + { + createAdditionalShapesTree( aTopLevelContainer ); + } + + // Chart Area + if( !m_bOrderingForElementSelector ) + aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) ); + + if( ! aTopLevelContainer.empty()) + m_aChildMap[ ObjectHierarchy::getRootNodeOID() ] = aTopLevelContainer; +} + +void ObjectHierarchy::createLegendTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< Diagram > & xDiagram ) +{ + if( !(xDiagram.is() && LegendHelper::hasLegend( xDiagram )) ) + return; + + ObjectIdentifier aLegendOID( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram->getLegend(), xChartDoc ) ) ); + rContainer.push_back( aLegendOID ); + + // iterate over child shapes of legend and search for matching CIDs + if( m_pExplicitValueProvider ) + { + rtl::Reference< SvxShapeGroupAnyD > xLegendShapeContainer = + dynamic_cast<SvxShapeGroupAnyD*>( + m_pExplicitValueProvider->getShapeForCID( aLegendOID.getObjectCID() ).get() ); + ObjectHierarchy::tChildContainer aLegendEntryOIDs; + lcl_getChildOIDs( aLegendEntryOIDs, xLegendShapeContainer ); + + m_aChildMap[ aLegendOID ] = aLegendEntryOIDs; + } +} + +void ObjectHierarchy::createAxesTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< Diagram > & xDiagram ) +{ + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + bool bSupportsAxesGrids = ChartTypeHelper::isSupportingMainAxis( xChartType, nDimensionCount, 0 ); + if( !bSupportsAxesGrids ) + return; + + std::vector< rtl::Reference< Axis > > aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ true ); + if( !m_bOrderingForElementSelector ) + { + for (const auto & rAxis : std::as_const(aAxes)) + rContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForObject( rAxis, xChartDoc ) ); + } + + // get all axes, also invisible ones + aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram ); + // Grids + for( rtl::Reference< Axis > const & xAxis : aAxes ) + { + if(!xAxis.is()) + continue; + + sal_Int32 nCooSysIndex = 0; + sal_Int32 nDimensionIndex = 0; + sal_Int32 nAxisIndex = 0; + AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ); + if( nAxisIndex>0 && !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ) ) + continue; + + if( m_bOrderingForElementSelector ) + { + // axis + if( AxisHelper::isAxisVisible( xAxis ) ) + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartDoc ) ); + + // axis title + lcl_addAxisTitle( xAxis, rContainer, xChartDoc ); + } + + Reference< beans::XPropertySet > xGridProperties( xAxis->getGridProperties() ); + if( AxisHelper::isGridVisible( xGridProperties ) ) + { + //main grid + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDoc ) ); + } + + Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + sal_Int32 nSubGrid = 0; + for( nSubGrid = 0; nSubGrid < aSubGrids.getLength(); ++nSubGrid ) + { + Reference< beans::XPropertySet > xSubGridProperties( aSubGrids[nSubGrid] ); + if( AxisHelper::isGridVisible( xSubGridProperties ) ) + { + //sub grid + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDoc, nSubGrid ) ); + } + } + } +} + +void ObjectHierarchy::createWallAndFloor( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference< Diagram > & xDiagram ) +{ + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + bool bIsThreeD = ( nDimensionCount == 3 ); + bool bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram ); + if( bHasWall && bIsThreeD ) + { + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) ); + + Reference< beans::XPropertySet > xFloor( xDiagram->getFloor()); + if( xFloor.is()) + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, u"" ) ); + } + +} + +void ObjectHierarchy::createDiagramTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< Diagram > & xDiagram ) +{ + if( !m_bOrderingForElementSelector ) + { + createDataSeriesTree( rContainer, xDiagram ); + createAxesTree( rContainer, xChartDoc, xDiagram ); + createWallAndFloor( rContainer, xDiagram ); + } + else + { + createAxesTree( rContainer, xChartDoc, xDiagram ); + createDataSeriesTree( rContainer, xDiagram ); + } +} + +void ObjectHierarchy::createDataSeriesTree( + ObjectHierarchy::tChildContainer & rOutDiagramSubContainer, + const rtl::Reference< Diagram > & xDiagram ) +{ + try + { + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysSeq( + xDiagram->getBaseCoordinateSystems()); + for( std::size_t nCooSysIdx=0; nCooSysIdx<aCooSysSeq.size(); ++nCooSysIdx ) + { + std::vector< rtl::Reference< ChartType > > aChartTypeSeq( aCooSysSeq[nCooSysIdx]->getChartTypes2()); + for( std::size_t nCTIdx=0; nCTIdx<aChartTypeSeq.size(); ++nCTIdx ) + { + rtl::Reference< ChartType > xChartType( aChartTypeSeq[nCTIdx] ); + std::vector< rtl::Reference< DataSeries > > aSeriesSeq( xChartType->getDataSeries2() ); + const sal_Int32 nNumberOfSeries = + ChartTypeHelper::getNumberOfDisplayedSeries( xChartType, aSeriesSeq.size()); + + for( sal_Int32 nSeriesIdx=0; nSeriesIdx<nNumberOfSeries; ++nSeriesIdx ) + { + OUString aSeriesParticle( + ObjectIdentifier::createParticleForSeries( + 0, nCooSysIdx, nCTIdx, nSeriesIdx )); + ObjectIdentifier aSeriesOID( + ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForParticle( aSeriesParticle ) ) ); + rOutDiagramSubContainer.push_back( aSeriesOID ); + + ObjectHierarchy::tChildContainer aSeriesSubContainer; + + rtl::Reference< DataSeries > const & xSeries = aSeriesSeq[nSeriesIdx]; + + // data labels + if( DataSeriesHelper::hasDataLabelsAtSeries( xSeries ) ) + { + OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" ); + aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForParticles( aSeriesParticle, aChildParticle ) ); + } + + // Statistics + if( ChartTypeHelper::isSupportingStatisticProperties( xChartType, nDimensionCount ) ) + { + Sequence< Reference< chart2::XRegressionCurve > > aCurves( xSeries->getRegressionCurves()); + for( sal_Int32 nCurveIdx=0; nCurveIdx<aCurves.getLength(); ++nCurveIdx ) + { + bool bIsAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[nCurveIdx] ); + aSeriesSubContainer.emplace_back( ObjectIdentifier::createDataCurveCID( aSeriesParticle, nCurveIdx, bIsAverageLine ) ); + if( RegressionCurveHelper::hasEquation( aCurves[nCurveIdx] ) ) + { + aSeriesSubContainer.emplace_back( ObjectIdentifier::createDataCurveEquationCID( aSeriesParticle, nCurveIdx ) ); + } + } + Reference< beans::XPropertySet > xErrorBarProp; + if( (xSeries->getPropertyValue( CHART_UNONAME_ERRORBAR_Y) >>= xErrorBarProp) && + xErrorBarProp.is()) + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + if( ( xErrorBarProp->getPropertyValue( "ErrorBarStyle") >>= nStyle ) && + ( nStyle != css::chart::ErrorBarStyle::NONE ) ) + { + aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_ERRORS_Y, u"", aSeriesParticle ) ); + } + } + + if( (xSeries->getPropertyValue(CHART_UNONAME_ERRORBAR_X) >>= xErrorBarProp) && + xErrorBarProp.is()) + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + if( ( xErrorBarProp->getPropertyValue( "ErrorBarStyle") >>= nStyle ) && + ( nStyle != css::chart::ErrorBarStyle::NONE ) ) + { + aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_ERRORS_X, u"", aSeriesParticle ) ); + } + } + } + + // Data Points + // iterate over child shapes of legend and search for matching CIDs + if( m_pExplicitValueProvider ) + { + rtl::Reference< SvxShapeGroupAnyD > xSeriesShapeContainer = + dynamic_cast<SvxShapeGroupAnyD*>( + m_pExplicitValueProvider->getShapeForCID( aSeriesOID.getObjectCID() ).get() ); + lcl_getChildOIDs( aSeriesSubContainer, xSeriesShapeContainer ); + } + + if( ! aSeriesSubContainer.empty()) + m_aChildMap[ aSeriesOID ] = aSeriesSubContainer; + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ObjectHierarchy::createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer ) +{ + try + { + if ( m_pExplicitValueProvider ) + { + rtl::Reference<SvxDrawPage> xDrawPage( m_pExplicitValueProvider->getDrawModelWrapper()->getMainDrawPage() ); + Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); + sal_Int32 nCount = xDrawPage->getCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< drawing::XShape > xShape; + if ( xDrawPage->getByIndex( i ) >>= xShape ) + { + if ( xShape.is() && xShape != xChartRoot ) + { + rContainer.emplace_back( xShape ); + } + } + } + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool ObjectHierarchy::hasChildren( const ObjectIdentifier& rParent ) const +{ + if ( rParent.isValid() ) + { + tChildMap::const_iterator aIt( m_aChildMap.find( rParent )); + if( aIt != m_aChildMap.end()) + return ! (aIt->second.empty()); + } + return false; +} + +const ObjectHierarchy::tChildContainer & ObjectHierarchy::getChildren( const ObjectIdentifier& rParent ) const +{ + if ( rParent.isValid() ) + { + tChildMap::const_iterator aIt( m_aChildMap.find( rParent )); + if( aIt != m_aChildMap.end()) + return aIt->second; + } + static const ObjectHierarchy::tChildContainer EMPTY; + return EMPTY; +} + +const ObjectHierarchy::tChildContainer & ObjectHierarchy::getSiblings( const ObjectIdentifier& rNode ) const +{ + if ( rNode.isValid() && !ObjectHierarchy::isRootNode( rNode ) ) + { + for (auto const& child : m_aChildMap) + { + ObjectHierarchy::tChildContainer::const_iterator aElemIt( + std::find( child.second.begin(), child.second.end(), rNode )); + if( aElemIt != child.second.end()) + return child.second; + } + } + static const ObjectHierarchy::tChildContainer EMPTY; + return EMPTY; +} + +ObjectIdentifier ObjectHierarchy::getParentImpl( + const ObjectIdentifier & rParentOID, + const ObjectIdentifier & rOID ) const +{ + // search children + ObjectHierarchy::tChildContainer aChildren( getChildren( rParentOID )); + ObjectHierarchy::tChildContainer::const_iterator aIt( + std::find( aChildren.begin(), aChildren.end(), rOID )); + // recursion end + if( aIt != aChildren.end()) + return rParentOID; + + for (auto const& child : aChildren) + { + // recursion + ObjectIdentifier aTempParent( getParentImpl( child, rOID )); + if ( aTempParent.isValid() ) + { + // exit on success + return aTempParent; + } + } + + // exit on fail + return ObjectIdentifier(); +} + +ObjectIdentifier ObjectHierarchy::getParent( + const ObjectIdentifier & rOID ) const +{ + return getParentImpl( ObjectHierarchy::getRootNodeOID(), rOID ); +} + +ObjectHierarchy::ObjectHierarchy( + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ExplicitValueProvider * pExplicitValueProvider /* = 0 */, + bool bFlattenDiagram /* = false */, + bool bOrderingForElementSelector /* = false */) : + m_pExplicitValueProvider( pExplicitValueProvider ), + m_bFlattenDiagram( bFlattenDiagram ), + m_bOrderingForElementSelector( bOrderingForElementSelector ) +{ + createTree( xChartDocument ); + // don't remember this helper to avoid access after lifetime + m_pExplicitValueProvider = nullptr; +} + +ObjectHierarchy::~ObjectHierarchy() +{} + +ObjectIdentifier ObjectHierarchy::getRootNodeOID() +{ + return ObjectIdentifier( "ROOT" ); +} + +bool ObjectHierarchy::isRootNode( const ObjectIdentifier& rOID ) +{ + return ( rOID == ObjectHierarchy::getRootNodeOID() ); +} + +const ObjectHierarchy::tChildContainer & ObjectHierarchy::getTopLevelChildren() const +{ + return getChildren( ObjectHierarchy::getRootNodeOID()); +} + +sal_Int32 ObjectHierarchy::getIndexInParent( + const ObjectIdentifier& rNode ) const +{ + ObjectIdentifier aParentOID( getParent( rNode )); + const tChildContainer & aChildren( getChildren( aParentOID ) ); + sal_Int32 nIndex = 0; + for (auto const& child : aChildren) + { + if ( child == rNode ) + return nIndex; + ++nIndex; + } + return -1; +} + +ObjectKeyNavigation::ObjectKeyNavigation( + const ObjectIdentifier & rCurrentOID, + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ExplicitValueProvider * pExplicitValueProvider /* = 0 */ ) : + m_aCurrentOID( rCurrentOID ), + m_xChartDocument( xChartDocument ), + m_pExplicitValueProvider( pExplicitValueProvider ) +{ + if ( !m_aCurrentOID.isValid() ) + { + setCurrentSelection( ObjectHierarchy::getRootNodeOID() ); + } +} + +bool ObjectKeyNavigation::handleKeyEvent( + const awt::KeyEvent & rEvent ) +{ + bool bResult = false; + + switch( rEvent.KeyCode ) + { + case awt::Key::TAB: + if( rEvent.Modifiers & awt::KeyModifier::SHIFT ) + bResult = previous(); + else + bResult = next(); + break; + case awt::Key::HOME: + bResult = first(); + break; + case awt::Key::END: + bResult = last(); + break; + case awt::Key::F3: + if( rEvent.Modifiers & awt::KeyModifier::SHIFT ) + bResult = up(); + else + bResult = down(); + break; + case awt::Key::ESCAPE: + setCurrentSelection( ObjectIdentifier() ); + bResult = true; + break; + default: + bResult = false; + break; + } + return bResult; +} + +void ObjectKeyNavigation::setCurrentSelection( const ObjectIdentifier& rOID ) +{ + m_aCurrentOID = rOID; +} + +bool ObjectKeyNavigation::first() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); + bool bResult = !aSiblings.empty(); + if( bResult ) + setCurrentSelection( aSiblings.front()); + else + bResult = veryFirst(); + return bResult; +} + +bool ObjectKeyNavigation::last() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); + bool bResult = !aSiblings.empty(); + if( bResult ) + setCurrentSelection( aSiblings.back()); + else + bResult = veryLast(); + return bResult; +} + +bool ObjectKeyNavigation::next() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); + bool bResult = !aSiblings.empty(); + if( bResult ) + { + ObjectHierarchy::tChildContainer::const_iterator aIt( + std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection())); + assert(aIt != aSiblings.end()); + if( ++aIt == aSiblings.end()) + aIt = aSiblings.begin(); + setCurrentSelection( *aIt ); + } + else + bResult = veryFirst(); + + return bResult; +} + +bool ObjectKeyNavigation::previous() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection())); + bool bResult = !aSiblings.empty(); + if( bResult ) + { + ObjectHierarchy::tChildContainer::const_iterator aIt( + std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection())); + OSL_ASSERT( aIt != aSiblings.end()); + if( aIt == aSiblings.begin()) + aIt = aSiblings.end(); + --aIt; + setCurrentSelection( *aIt ); + } + else + bResult = veryLast(); + return bResult; +} + +bool ObjectKeyNavigation::up() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + bool bResult = !ObjectHierarchy::isRootNode( getCurrentSelection()); + if( bResult ) + setCurrentSelection( aHierarchy.getParent( getCurrentSelection())); + return bResult; +} + +bool ObjectKeyNavigation::down() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + bool bResult = aHierarchy.hasChildren( getCurrentSelection()); + if( bResult ) + { + ObjectHierarchy::tChildContainer aChildren = aHierarchy.getChildren( getCurrentSelection()); + OSL_ASSERT( !aChildren.empty()); + setCurrentSelection( aChildren.front()); + } + return bResult; +} + +bool ObjectKeyNavigation::veryFirst() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren()); + bool bResult = !aChildren.empty(); + if( bResult ) + setCurrentSelection( aChildren.front()); + return bResult; +} + +bool ObjectKeyNavigation::veryLast() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren()); + bool bResult = !aChildren.empty(); + if( bResult ) + setCurrentSelection( aChildren.back()); + return bResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/PositionAndSizeHelper.cxx b/chart2/source/controller/main/PositionAndSizeHelper.cxx new file mode 100644 index 000000000..ca8a4549a --- /dev/null +++ b/chart2/source/controller/main/PositionAndSizeHelper.cxx @@ -0,0 +1,179 @@ +/* -*- 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 <PositionAndSizeHelper.hxx> +#include <ControllerLockGuard.hxx> +#include <com/sun/star/chart/ChartLegendExpansion.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/RelativeSize.hpp> +#include <tools/gen.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <ChartModel.hxx> +#include <Diagram.hxx> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +bool PositionAndSizeHelper::moveObject( ObjectType eObjectType + , const uno::Reference< beans::XPropertySet >& xObjectProp + , const awt::Rectangle& rNewPositionAndSize + , const awt::Rectangle& rOldPositionAndSize + , const awt::Rectangle& rPageRectangle + ) +{ + if(!xObjectProp.is()) + return false; + tools::Rectangle aObjectRect( Point(rNewPositionAndSize.X,rNewPositionAndSize.Y), Size(rNewPositionAndSize.Width,rNewPositionAndSize.Height) ); + tools::Rectangle aPageRect( Point(rPageRectangle.X,rPageRectangle.Y), Size(rPageRectangle.Width,rPageRectangle.Height) ); + + // every following branch divides by width and height + if (aPageRect.getWidth() == 0 || aPageRect.getHeight() == 0) + return false; + + if( eObjectType==OBJECTTYPE_TITLE ) + { + //@todo decide whether x is primary or secondary + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_CENTER; + //the anchor point at the title object is top/middle + Point aPos = aObjectRect.TopLeft(); + aRelativePosition.Primary = (double(aPos.X())+double(aObjectRect.getWidth())/2.0)/double(aPageRect.getWidth()); + aRelativePosition.Secondary = (double(aPos.Y())+double(aObjectRect.getHeight())/2.0)/double(aPageRect.getHeight()); + xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + } + else if( eObjectType == OBJECTTYPE_DATA_LABEL ) + { + RelativePosition aAbsolutePosition; + RelativePosition aCustomLabelPosition; + aAbsolutePosition.Primary = double(rOldPositionAndSize.X) / double(aPageRect.getWidth()); + aAbsolutePosition.Secondary = double(rOldPositionAndSize.Y) / double(aPageRect.getHeight()); + + if( xObjectProp->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition ) + { + aAbsolutePosition.Primary -= aCustomLabelPosition.Primary; + aAbsolutePosition.Secondary -= aCustomLabelPosition.Secondary; + } + + //the anchor point at the data label object is top/left + Point aPos = aObjectRect.TopLeft(); + double fRotation = 0.0; + xObjectProp->getPropertyValue("TextRotation") >>= fRotation; + if( fRotation == 90.0 ) + aPos = aObjectRect.BottomLeft(); + else if( fRotation == 270.0 ) + aPos = aObjectRect.TopRight(); + + aCustomLabelPosition.Primary = double(aPos.X()) / double(aPageRect.getWidth()) - aAbsolutePosition.Primary; + aCustomLabelPosition.Secondary = double(aPos.Y()) / double(aPageRect.getHeight()) - aAbsolutePosition.Secondary; + xObjectProp->setPropertyValue("CustomLabelPosition", uno::Any(aCustomLabelPosition)); + } + else if( eObjectType==OBJECTTYPE_DATA_CURVE_EQUATION ) + { + //@todo decide whether x is primary or secondary + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT; + //the anchor point at the title object is top/middle + Point aPos = aObjectRect.TopLeft(); + aRelativePosition.Primary = double(aPos.X())/double(aPageRect.getWidth()); + aRelativePosition.Secondary = double(aPos.Y())/double(aPageRect.getHeight()); + xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + } + else if(eObjectType==OBJECTTYPE_LEGEND) + { + xObjectProp->setPropertyValue( "Expansion", uno::Any(css::chart::ChartLegendExpansion_CUSTOM)); + chart2::RelativePosition aRelativePosition; + chart2::RelativeSize aRelativeSize; + Point aAnchor = aObjectRect.TopLeft(); + + aRelativePosition.Primary = + static_cast< double >( aAnchor.X()) / + static_cast< double >( aPageRect.getWidth() ); + aRelativePosition.Secondary = + static_cast< double >( aAnchor.Y()) / + static_cast< double >( aPageRect.getHeight()); + + xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + + aRelativeSize.Primary = + static_cast< double >( aObjectRect.getWidth()) / + static_cast< double >( aPageRect.getWidth() ); + if (aRelativeSize.Primary > 1.0) + aRelativeSize.Primary = 1.0; + aRelativeSize.Secondary = + static_cast< double >( aObjectRect.getHeight()) / + static_cast< double >( aPageRect.getHeight()); + if (aRelativeSize.Secondary > 1.0) + aRelativeSize.Secondary = 1.0; + + xObjectProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) ); + } + else if(eObjectType==OBJECTTYPE_DIAGRAM || eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR) + { + //@todo decide whether x is primary or secondary + + //set position: + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_CENTER; + + Point aPos = aObjectRect.Center(); + aRelativePosition.Primary = double(aPos.X())/double(aPageRect.getWidth()); + aRelativePosition.Secondary = double(aPos.Y())/double(aPageRect.getHeight()); + xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + + //set size: + RelativeSize aRelativeSize; + //the anchor points for the diagram are in the middle of the diagram + //and in the middle of the page + aRelativeSize.Primary = double(aObjectRect.getWidth())/double(aPageRect.getWidth()); + aRelativeSize.Secondary = double(aObjectRect.getHeight())/double(aPageRect.getHeight()); + xObjectProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) ); + } + else + return false; + return true; +} + +bool PositionAndSizeHelper::moveObject( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , const awt::Rectangle& rNewPositionAndSize + , const awt::Rectangle& rOldPositionAndSize + , const awt::Rectangle& rPageRectangle + ) +{ + ControllerLockGuardUNO aLockedControllers( xChartModel ); + + awt::Rectangle aNewPositionAndSize( rNewPositionAndSize ); + + uno::Reference< beans::XPropertySet > xObjectProp = ObjectIdentifier::getObjectPropertySet( rObjectCID, xChartModel ); + ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) ); + if(eObjectType==OBJECTTYPE_DIAGRAM || eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR) + { + xObjectProp = ObjectIdentifier::getDiagramForCID( rObjectCID, xChartModel ); + if(!xObjectProp.is()) + return false; + } + return moveObject( eObjectType, xObjectProp, aNewPositionAndSize, rOldPositionAndSize, rPageRectangle ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/SelectionHelper.cxx b/chart2/source/controller/main/SelectionHelper.cxx new file mode 100644 index 000000000..177d7acf5 --- /dev/null +++ b/chart2/source/controller/main/SelectionHelper.cxx @@ -0,0 +1,652 @@ +/* -*- 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 <SelectionHelper.hxx> +#include <ObjectIdentifier.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> + +#include <svx/svdpage.hxx> +#include <svx/svditer.hxx> +#include <svx/obj3d.hxx> +#include <svx/svdopath.hxx> +#include <vcl/svapp.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <osl/diagnose.h> + +namespace chart +{ +using namespace ::com::sun::star; + +namespace +{ + +OUString lcl_getObjectName( SdrObject const * pObj ) +{ + if(pObj) + return pObj->GetName(); + return OUString(); +} + +void impl_selectObject( SdrObject* pObjectToSelect, DrawViewWrapper& rDrawViewWrapper ) +{ + SolarMutexGuard aSolarGuard; + + if(pObjectToSelect) + { + SelectionHelper aSelectionHelper( pObjectToSelect ); + SdrObject* pMarkObj = aSelectionHelper.getObjectToMark(); + rDrawViewWrapper.setMarkHandleProvider(&aSelectionHelper); + rDrawViewWrapper.MarkObject(pMarkObj); + rDrawViewWrapper.setMarkHandleProvider(nullptr); + } +} + +}//anonymous namespace + +bool Selection::hasSelection() const +{ + return m_aSelectedOID.isValid(); +} + +OUString const & Selection::getSelectedCID() const +{ + return m_aSelectedOID.getObjectCID(); +} + +uno::Reference< drawing::XShape > const & Selection::getSelectedAdditionalShape() const +{ + return m_aSelectedOID.getAdditionalShape(); +} + +bool Selection::setSelection( const OUString& rCID ) +{ + if ( rCID != m_aSelectedOID.getObjectCID() ) + { + m_aSelectedOID = ObjectIdentifier( rCID ); + return true; + } + return false; +} + +bool Selection::setSelection( const uno::Reference< drawing::XShape >& xShape ) +{ + if ( !( xShape == m_aSelectedOID.getAdditionalShape() ) ) + { + clearSelection(); + m_aSelectedOID = ObjectIdentifier( xShape ); + return true; + } + return false; +} + +void Selection::clearSelection() +{ + m_aSelectedOID = ObjectIdentifier(); + m_aSelectedOID_beforeMouseDown = ObjectIdentifier(); + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); +} + +bool Selection::maybeSwitchSelectionAfterSingleClickWasEnsured() +{ + if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() + && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing != m_aSelectedOID ) + { + m_aSelectedOID = m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing; + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); + return true; + } + return false; +} + +void Selection::resetPossibleSelectionAfterSingleClickWasEnsured() +{ + if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() ) + { + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); + } +} + +void Selection::remindSelectionBeforeMouseDown() +{ + m_aSelectedOID_beforeMouseDown = m_aSelectedOID; +} + +bool Selection::isSelectionDifferentFromBeforeMouseDown() const +{ + return ( m_aSelectedOID != m_aSelectedOID_beforeMouseDown ); +} + +void Selection::applySelection( DrawViewWrapper* pDrawViewWrapper ) +{ + if( !pDrawViewWrapper ) + return; + + { + SolarMutexGuard aSolarGuard; + pDrawViewWrapper->UnmarkAll(); + } + SdrObject* pObjectToSelect = nullptr; + if ( m_aSelectedOID.isAutoGeneratedObject() ) + { + pObjectToSelect = pDrawViewWrapper->getNamedSdrObject( m_aSelectedOID.getObjectCID() ); + } + else if( m_aSelectedOID.isAdditionalShape() ) + { + pObjectToSelect = DrawViewWrapper::getSdrObject( m_aSelectedOID.getAdditionalShape() ); + } + + impl_selectObject( pObjectToSelect, *pDrawViewWrapper ); +} + +void Selection::adaptSelectionToNewPos( const Point& rMousePos, DrawViewWrapper const * pDrawViewWrapper + , bool bIsRightMouse, bool bWaitingForDoubleClick ) +{ + if( !pDrawViewWrapper ) + return; + + //do not toggle multiclick selection if right clicked on the selected object or waiting for double click + bool bAllowMultiClickSelectionChange = !bIsRightMouse && !bWaitingForDoubleClick; + + ObjectIdentifier aLastSelectedObject( m_aSelectedOID ); + + SolarMutexGuard aSolarGuard; + + //bAllowMultiClickSelectionChange==true -> a second click on the same object can lead to a changed selection (e.g. series -> single data point) + + //get object to select: + { + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); + + //the search for the object to select starts with the hit object deepest in the grouping hierarchy (a leaf in the tree) + //further we travel along the grouping hierarchy from child to parent + SdrObject* pNewObj = pDrawViewWrapper->getHitObject(rMousePos); + m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );//name of pNewObj + + //ignore handle only objects for hit test + while( pNewObj && m_aSelectedOID.getObjectCID().match( "HandlesOnly" ) ) + { + pNewObj->SetMarkProtect(true); + pNewObj = pDrawViewWrapper->getHitObject(rMousePos); + m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) ); + } + + //accept only named objects while searching for the object to select + //this call may change m_aSelectedOID + if ( SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, true ) ) + { + //if the so far found object is a multi click object further steps are necessary + while( ObjectIdentifier::isMultiClickObject( m_aSelectedOID.getObjectCID() ) ) + { + bool bSameObjectAsLastSelected = ( aLastSelectedObject == m_aSelectedOID ); + if( bSameObjectAsLastSelected ) + { + //if the same child is clicked again don't go up further + break; + } + if ( ObjectIdentifier::areSiblings( aLastSelectedObject.getObjectCID(), m_aSelectedOID.getObjectCID() ) ) + { + //if a sibling of the last selected object is clicked don't go up further + break; + } + ObjectIdentifier aLastChild = m_aSelectedOID; + if ( !SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, false ) ) + { + //take the one found so far + break; + } + //if the last selected object is found don't go up further + //but take the last child if selection change is allowed + if ( aLastSelectedObject == m_aSelectedOID ) + { + if( bAllowMultiClickSelectionChange ) + { + m_aSelectedOID = aLastChild; + } + else + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = aLastChild; + break; + } + } + + OSL_ENSURE(m_aSelectedOID.isValid(), "somehow lost selected object"); + } + else + { + //maybe an additional shape was hit + if ( pNewObj ) + { + m_aSelectedOID = ObjectIdentifier( uno::Reference< drawing::XShape >( pNewObj->getUnoShape(), uno::UNO_QUERY ) ); + } + else + { + m_aSelectedOID = ObjectIdentifier(); + } + } + + if ( !m_aSelectedOID.isAdditionalShape() ) + { + OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );//@todo read CID from model + + if ( !m_aSelectedOID.isAutoGeneratedObject() ) + { + m_aSelectedOID = ObjectIdentifier( aPageCID ); + } + + //check whether the diagram was hit but not selected (e.g. because it has no filling): + OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ); + OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model + bool bBackGroundHit = m_aSelectedOID.getObjectCID() == aPageCID || m_aSelectedOID.getObjectCID() == aWallCID || !m_aSelectedOID.isAutoGeneratedObject(); + if( bBackGroundHit ) + { + //todo: if more than one diagram is available in future do check the list of all diagrams here + SdrObject* pDiagram = pDrawViewWrapper->getNamedSdrObject( aDiagramCID ); + if( pDiagram ) + { + if( DrawViewWrapper::IsObjectHit( pDiagram, rMousePos ) ) + { + m_aSelectedOID = ObjectIdentifier( aDiagramCID ); + } + } + } + //check whether the legend was hit but not selected (e.g. because it has no filling): + if( bBackGroundHit || m_aSelectedOID.getObjectCID() == aDiagramCID ) + { + OUString aLegendCID( ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::createParticleForLegend(nullptr) ) );//@todo read CID from model + SdrObject* pLegend = pDrawViewWrapper->getNamedSdrObject( aLegendCID ); + if( pLegend ) + { + if( DrawViewWrapper::IsObjectHit( pLegend, rMousePos ) ) + { + m_aSelectedOID = ObjectIdentifier( aLegendCID ); + } + } + } + } + } + + if ( bIsRightMouse && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() ) + { + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); + } +} + +bool Selection::isResizeableObjectSelected() const +{ + ObjectType eObjectType = m_aSelectedOID.getObjectType(); + switch( eObjectType ) + { + case OBJECTTYPE_DIAGRAM: + case OBJECTTYPE_DIAGRAM_WALL: + case OBJECTTYPE_SHAPE: + case OBJECTTYPE_LEGEND: + return true; + default: + return false; + } +} + +bool Selection::isRotateableObjectSelected( const rtl::Reference<::chart::ChartModel>& xChartModel ) const +{ + return SelectionHelper::isRotateableObject( m_aSelectedOID.getObjectCID(), xChartModel ); +} + +bool Selection::isDragableObjectSelected() const +{ + return m_aSelectedOID.isDragableObject(); +} + +bool Selection::isAdditionalShapeSelected() const +{ + return m_aSelectedOID.isAdditionalShape(); +} + +bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject + , OUString& rOutName + , bool bGivenObjectMayBeResult ) +{ + SolarMutexGuard aSolarGuard; + //find the deepest named group + SdrObject* pObj = pInOutObject; + OUString aName; + if( bGivenObjectMayBeResult ) + aName = lcl_getObjectName( pObj ); + + while( pObj && !ObjectIdentifier::isCID( aName ) ) + { + SdrObjList* pObjList = pObj->getParentSdrObjListFromSdrObject(); + if( !pObjList ) + return false; + SdrObject* pOwner = pObjList->getSdrObjectFromSdrObjList(); + if( !pOwner ) + return false; + pObj = pOwner; + aName = lcl_getObjectName( pObj ); + } + + if(!pObj) + return false; + if(aName.isEmpty()) + return false; + + pInOutObject = pObj; + rOutName = aName; + return true; +} + +bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject + , ObjectIdentifier& rOutObject + , bool bGivenObjectMayBeResult ) +{ + OUString aName; + if ( findNamedParent( pInOutObject, aName, bGivenObjectMayBeResult ) ) + { + rOutObject = ObjectIdentifier( aName ); + return true; + } + return false; +} + +bool SelectionHelper::isDragableObjectHitTwice( const Point& rMPos + , const OUString& rNameOfSelectedObject + , const DrawViewWrapper& rDrawViewWrapper ) +{ + if(rNameOfSelectedObject.isEmpty()) + return false; + if( !ObjectIdentifier::isDragableObject(rNameOfSelectedObject) ) + return false; + SolarMutexGuard aSolarGuard; + SdrObject* pObj = rDrawViewWrapper.getNamedSdrObject( rNameOfSelectedObject ); + return DrawViewWrapper::IsObjectHit( pObj, rMPos ); +} + +OUString SelectionHelper::getHitObjectCID( + const Point& rMPos, + DrawViewWrapper const & rDrawViewWrapper, + bool bGetDiagramInsteadOf_Wall ) +{ + SolarMutexGuard aSolarGuard; + OUString aRet; + + SdrObject* pNewObj = rDrawViewWrapper.getHitObject(rMPos); + aRet = lcl_getObjectName( pNewObj );//name of pNewObj + + //ignore handle only objects for hit test + while( pNewObj && aRet.match("HandlesOnly") ) + { + pNewObj->SetMarkProtect(true); + pNewObj = rDrawViewWrapper.getHitObject(rMPos); + aRet = lcl_getObjectName( pNewObj ); + } + + //accept only named objects while searching for the object to select + if( !findNamedParent( pNewObj, aRet, true ) ) + { + aRet.clear(); + } + + OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );//@todo read CID from model + //get page when nothing was hit + if( aRet.isEmpty() && !pNewObj ) + { + aRet = aPageCID; + } + + //get diagram instead wall or page if hit inside diagram + if( !aRet.isEmpty() ) + { + if( aRet == aPageCID ) + { + OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ); + //todo: if more than one diagram is available in future do check the list of all diagrams here + SdrObject* pDiagram = rDrawViewWrapper.getNamedSdrObject( aDiagramCID ); + if( pDiagram ) + { + if( DrawViewWrapper::IsObjectHit( pDiagram, rMPos ) ) + { + aRet = aDiagramCID; + } + } + } + else if( bGetDiagramInsteadOf_Wall ) + { + OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model + + if( aRet == aWallCID ) + { + OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ); + aRet = aDiagramCID; + } + } + } + + return aRet; + // \\- solar mutex +} + +bool SelectionHelper::isRotateableObject( std::u16string_view rCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + if( !ObjectIdentifier::isRotateableObject( rCID ) ) + return false; + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( ChartModelHelper::findDiagram( xChartModel ) ); + + return nDimensionCount == 3; +} + +SelectionHelper::SelectionHelper( SdrObject* pSelectedObj ) + : m_pSelectedObj( pSelectedObj ), m_pMarkObj(nullptr) +{ + +} +SelectionHelper::~SelectionHelper() +{ +} + +bool SelectionHelper::getFrameDragSingles() +{ + //true == green == surrounding handles + return dynamic_cast<const E3dObject*>( m_pSelectedObj) == nullptr; +} + +SdrObject* SelectionHelper::getMarkHandlesObject( SdrObject* pObj ) +{ + if(!pObj) + return nullptr; + OUString aName( lcl_getObjectName( pObj ) ); + if( aName.match("MarkHandles") || aName.match("HandlesOnly") ) + return pObj; + if( !aName.isEmpty() )//don't get the markhandles of a different object + return nullptr; + + //search for a child with name "MarkHandles" or "HandlesOnly" + SolarMutexGuard aSolarGuard; + SdrObjList* pSubList = pObj->GetSubList(); + if(pSubList) + { + SdrObjListIter aIterator(pSubList, SdrIterMode::Flat); + while (aIterator.IsMore()) + { + SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() ); + if( pMarkHandles ) + return pMarkHandles; + } + } + return nullptr; +} + +SdrObject* SelectionHelper::getObjectToMark() +{ + //return the selected object itself + //or a specific other object if that exists + SdrObject* pObj = m_pSelectedObj; + m_pMarkObj = pObj; + + //search for a child with name "MarkHandles" or "HandlesOnly" + if(pObj) + { + SolarMutexGuard aSolarGuard; + SdrObjList* pSubList = pObj->GetSubList(); + if(pSubList) + { + SdrObjListIter aIterator(pSubList, SdrIterMode::Flat); + while (aIterator.IsMore()) + { + SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() ); + if( pMarkHandles ) + { + m_pMarkObj = pMarkHandles; + break; + } + } + } + } + return m_pMarkObj; +} + +E3dScene* SelectionHelper::getSceneToRotate( SdrObject* pObj ) +{ + //search whether the object or one of its children is a 3D object + //if so, return the accessory 3DScene + + E3dObject* pRotateable = nullptr; + + if(pObj) + { + pRotateable = dynamic_cast<E3dObject*>(pObj); + if( !pRotateable ) + { + SolarMutexGuard aSolarGuard; + SdrObjList* pSubList = pObj->GetSubList(); + if(pSubList) + { + SdrObjListIter aIterator(pSubList, SdrIterMode::DeepWithGroups); + while( aIterator.IsMore() && !pRotateable ) + { + SdrObject* pSubObj = aIterator.Next(); + pRotateable = dynamic_cast<E3dObject*>(pSubObj); + } + } + } + } + + E3dScene* pScene(nullptr); + + if(pRotateable) + { + SolarMutexGuard aSolarGuard; + pScene = pRotateable->getRootE3dSceneFromE3dObject(); + } + + return pScene; +} + +bool SelectionHelper::getMarkHandles( SdrHdlList& rHdlList ) +{ + SolarMutexGuard aSolarGuard; + + //@todo -> more flexible handle creation + //2 scenarios possible: + //1. add an additional invisible shape as a child to the selected object + //this child needs to be named somehow and handles need to be generated there from... + //or 2. offer a central service per view where renderer and so can register for handle creation for a special shape + //.. or 3. feature from drawinglayer to create handles for each shape... (bad performance... ?) ? + + //scenario 1 is now used: + //if a child with name MarkHandles exists + //this child is marked instead of the logical selected object + +/* + //if a special mark object was found + //that object should be used for marking only + if( m_pMarkObj != m_pSelectedObj) + return false; +*/ + //if a special mark object was found + //that object should be used to create handles from + if( m_pMarkObj && m_pMarkObj != m_pSelectedObj) + { + rHdlList.Clear(); + if( auto pPathObj = dynamic_cast<const SdrPathObj*>( m_pMarkObj) ) + { + //if th object is a polygon + //from each point a handle is generated + const ::basegfx::B2DPolyPolygon& rPolyPolygon = pPathObj->GetPathPoly(); + for( sal_uInt32 nN = 0; nN < rPolyPolygon.count(); nN++) + { + const ::basegfx::B2DPolygon& aPolygon(rPolyPolygon.getB2DPolygon(nN)); + for( sal_uInt32 nM = 0; nM < aPolygon.count(); nM++) + { + const ::basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(nM)); + rHdlList.AddHdl(std::make_unique<SdrHdl>(Point(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY())), SdrHdlKind::Poly)); + } + } + return true; + } + else + return false; //use the special MarkObject for marking + } + + //@todo: + //add and document good marking defaults ... + + rHdlList.Clear(); + + SdrObject* pObj = m_pSelectedObj; + if(!pObj) + return false; + SdrObjList* pSubList = pObj->GetSubList(); + if( !pSubList )//no group object !pObj->IsGroupObject() + return false; + + OUString aName( lcl_getObjectName( pObj ) ); + ObjectType eObjectType( ObjectIdentifier::getObjectType( aName ) ); + if( eObjectType == OBJECTTYPE_DATA_POINT + || eObjectType == OBJECTTYPE_DATA_LABEL + || eObjectType == OBJECTTYPE_LEGEND_ENTRY + || eObjectType == OBJECTTYPE_AXIS_UNITLABEL ) + { + return false; + } + + SdrObjListIter aIterator(pSubList, SdrIterMode::Flat); + + while (aIterator.IsMore()) + { + SdrObject* pSubObj = aIterator.Next(); + if( eObjectType == OBJECTTYPE_DATA_SERIES ) + { + OUString aSubName( lcl_getObjectName( pSubObj ) ); + ObjectType eSubObjectType( ObjectIdentifier::getObjectType( aSubName ) ); + if( eSubObjectType!=OBJECTTYPE_DATA_POINT ) + return false; + } + + Point aPos = pSubObj->GetCurrentBoundRect().Center(); + rHdlList.AddHdl(std::make_unique<SdrHdl>(aPos,SdrHdlKind::Poly)); + } + return true; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ShapeController.cxx b/chart2/source/controller/main/ShapeController.cxx new file mode 100644 index 000000000..3dae73fd8 --- /dev/null +++ b/chart2/source/controller/main/ShapeController.cxx @@ -0,0 +1,671 @@ +/* -*- 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 "ShapeController.hxx" +#include <ShapeController.h> +#include <ChartController.hxx> +#include <ViewElementListProvider.hxx> +#include <dlg_ShapeFont.hxx> +#include <dlg_ShapeParagraph.hxx> +#include <ChartModel.hxx> +#include <chartview/DrawModelWrapper.hxx> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/frame/CommandGroup.hpp> + +#include <vcl/svapp.hxx> +#include <editeng/formatbreakitem.hxx> +#include <editeng/editids.hrc> +#include <editeng/eeitem.hxx> +#include <editeng/hyphenzoneitem.hxx> +#include <editeng/orphitem.hxx> +#include <editeng/spltitem.hxx> +#include <svx/svxdlg.hxx> +#include <editeng/widwitem.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::frame; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +ShapeController::ShapeController( const Reference< uno::XComponentContext >& rxContext, + ChartController* pController ) + :FeatureCommandDispatchBase( rxContext ) + ,m_pChartController( pController ) +{ +} + +ShapeController::~ShapeController() +{ +} + +// WeakComponentImplHelperBase +void ShapeController::disposing() +{ +} + +// XEventListener +void ShapeController::disposing( const lang::EventObject& /* Source */ ) +{ +} + +FeatureState ShapeController::getState( const OUString& rCommand ) +{ + FeatureState aReturn; + aReturn.bEnabled = false; + aReturn.aState <<= false; + + bool bWritable = false; + if ( m_pChartController ) + { + rtl::Reference< ChartModel > xStorable = m_pChartController->getChartModel(); + if ( xStorable.is() ) + { + bWritable = !xStorable->isReadonly(); + } + } + + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommand ); + if ( aIter != m_aSupportedFeatures.end() ) + { + sal_uInt16 nFeatureId = aIter->second.nFeatureId; + switch ( nFeatureId ) + { + case COMMAND_ID_FORMAT_LINE: + case COMMAND_ID_FORMAT_AREA: + case COMMAND_ID_TEXT_ATTRIBUTES: + case COMMAND_ID_TRANSFORM_DIALOG: + case COMMAND_ID_OBJECT_TITLE_DESCRIPTION: + case COMMAND_ID_RENAME_OBJECT: + { + aReturn.bEnabled = bWritable; + aReturn.aState <<= false; + } + break; + case COMMAND_ID_BRING_TO_FRONT: + case COMMAND_ID_FORWARD: + { + aReturn.bEnabled = ( bWritable && isForwardPossible() ); + aReturn.aState <<= false; + } + break; + case COMMAND_ID_BACKWARD: + case COMMAND_ID_SEND_TO_BACK: + { + + aReturn.bEnabled = ( bWritable && isBackwardPossible() ); + aReturn.aState <<= false; + } + break; + case COMMAND_ID_FONT_DIALOG: + case COMMAND_ID_PARAGRAPH_DIALOG: + { + aReturn.bEnabled = bWritable; + aReturn.aState <<= false; + } + break; + default: + { + aReturn.bEnabled = false; + aReturn.aState <<= false; + } + break; + } + } + + return aReturn; +} + +void ShapeController::execute( const OUString& rCommand, const Sequence< beans::PropertyValue>& ) +{ + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommand ); + if ( aIter == m_aSupportedFeatures.end() ) + return; + + sal_uInt16 nFeatureId = aIter->second.nFeatureId; + switch ( nFeatureId ) + { + case COMMAND_ID_FORMAT_LINE: + { + executeDispatch_FormatLine(); + } + break; + case COMMAND_ID_FORMAT_AREA: + { + executeDispatch_FormatArea(); + } + break; + case COMMAND_ID_TEXT_ATTRIBUTES: + { + executeDispatch_TextAttributes(); + } + break; + case COMMAND_ID_TRANSFORM_DIALOG: + { + executeDispatch_TransformDialog(); + } + break; + case COMMAND_ID_OBJECT_TITLE_DESCRIPTION: + { + executeDispatch_ObjectTitleDescription(); + } + break; + case COMMAND_ID_RENAME_OBJECT: + { + executeDispatch_RenameObject(); + } + break; + case COMMAND_ID_BRING_TO_FRONT: + case COMMAND_ID_FORWARD: + case COMMAND_ID_BACKWARD: + case COMMAND_ID_SEND_TO_BACK: + { + executeDispatch_ChangeZOrder( nFeatureId ); + } + break; + case COMMAND_ID_FONT_DIALOG: + { + executeDispatch_FontDialog(); + } + break; + case COMMAND_ID_PARAGRAPH_DIALOG: + { + executeDispatch_ParagraphDialog(); + } + break; + default: + { + } + break; + } +} + +void ShapeController::describeSupportedFeatures() +{ + implDescribeSupportedFeature( ".uno:FormatLine", COMMAND_ID_FORMAT_LINE, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:FormatArea", COMMAND_ID_FORMAT_AREA, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:TextAttributes", COMMAND_ID_TEXT_ATTRIBUTES, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:TransformDialog", COMMAND_ID_TRANSFORM_DIALOG, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:ObjectTitleDescription", COMMAND_ID_OBJECT_TITLE_DESCRIPTION, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:RenameObject", COMMAND_ID_RENAME_OBJECT, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:BringToFront", COMMAND_ID_BRING_TO_FRONT, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:Forward", COMMAND_ID_FORWARD, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:Backward", COMMAND_ID_BACKWARD, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:SendToBack", COMMAND_ID_SEND_TO_BACK, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:FontDialog", COMMAND_ID_FONT_DIALOG, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:ParagraphDialog", COMMAND_ID_PARAGRAPH_DIALOG, CommandGroup::EDIT ); +} + +IMPL_LINK( ShapeController, CheckNameHdl, AbstractSvxObjectNameDialog&, rDialog, bool ) +{ + OUString aName; + rDialog.GetName( aName ); + + if ( !aName.isEmpty() ) + { + DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr ); + if ( pDrawViewWrapper && pDrawViewWrapper->getNamedSdrObject( aName ) ) + { + return false; + } + } + return true; +} + +void ShapeController::executeDispatch_FormatLine() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawModelWrapper && pDrawViewWrapper) ) + return; + + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() ); + bool bHasMarked = pDrawViewWrapper->AreObjectsMarked(); + if ( bHasMarked ) + { + pDrawViewWrapper->MergeAttrFromMarked( aAttr, false ); + } + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< SfxAbstractTabDialog > pDlg( + pFact->CreateSvxLineTabDialog(pChartWindow, &aAttr, &pDrawModelWrapper->getSdrModel(), + pSelectedObj, bHasMarked)); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + if ( bHasMarked ) + { + pDrawViewWrapper->SetAttrToMarked( *pOutAttr, false ); + } + else + { + pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false ); + } + } +} + +void ShapeController::executeDispatch_FormatArea() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawModelWrapper && pDrawViewWrapper) ) + return; + + SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() ); + bool bHasMarked = pDrawViewWrapper->AreObjectsMarked(); + if ( bHasMarked ) + { + pDrawViewWrapper->MergeAttrFromMarked( aAttr, false ); + } + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< AbstractSvxAreaTabDialog > pDlg( + pFact->CreateSvxAreaTabDialog(pChartWindow, &aAttr, &pDrawModelWrapper->getSdrModel(), true, false)); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + if ( bHasMarked ) + { + pDrawViewWrapper->SetAttrToMarked( *pOutAttr, false ); + } + else + { + pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false ); + } + } +} + +void ShapeController::executeDispatch_TextAttributes() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawViewWrapper) ) + return; + + SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() ); + bool bHasMarked = pDrawViewWrapper->AreObjectsMarked(); + if ( bHasMarked ) + { + pDrawViewWrapper->MergeAttrFromMarked( aAttr, false ); + } + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< SfxAbstractTabDialog > pDlg( + pFact->CreateTextTabDialog(pChartWindow, &aAttr, pDrawViewWrapper)); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + if ( bHasMarked ) + { + pDrawViewWrapper->SetAttributes( *pOutAttr ); + } + else + { + pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false ); + } + } +} + +void ShapeController::executeDispatch_TransformDialog() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawViewWrapper) ) + return; + + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + if ( pSelectedObj && pSelectedObj->GetObjIdentifier() == SdrObjKind::Caption ) + { + // item set for caption + SfxItemSet aAttr( pDrawViewWrapper->GetModel()->GetItemPool() ); + pDrawViewWrapper->GetAttributes( aAttr ); + // item set for position and size + SfxItemSet aGeoAttr( pDrawViewWrapper->GetGeoAttrFromMarked() ); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< SfxAbstractTabDialog > pDlg( + pFact->CreateCaptionDialog(pChartWindow, pDrawViewWrapper)); + const WhichRangesContainer& pRange = pDlg->GetInputRanges( *aAttr.GetPool() ); + SfxItemSet aCombAttr( *aAttr.GetPool(), pRange ); + aCombAttr.Put( aAttr ); + aCombAttr.Put( aGeoAttr ); + pDlg->SetInputSet( &aCombAttr ); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + pDrawViewWrapper->SetAttributes( *pOutAttr ); + pDrawViewWrapper->SetGeoAttrToMarked( *pOutAttr ); + } + } + else + { + SfxItemSet aGeoAttr( pDrawViewWrapper->GetGeoAttrFromMarked() ); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< SfxAbstractTabDialog > pDlg( + pFact->CreateSvxTransformTabDialog(pChartWindow, &aGeoAttr, pDrawViewWrapper)); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + pDrawViewWrapper->SetGeoAttrToMarked( *pOutAttr ); + } + } +} + +void ShapeController::executeDispatch_ObjectTitleDescription() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pDrawViewWrapper && pDrawViewWrapper->GetMarkedObjectCount() == 1) ) + return; + + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + if ( !pSelectedObj ) + return; + + OUString aTitle( pSelectedObj->GetTitle() ); + OUString aDescription( pSelectedObj->GetDescription() ); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + ScopedVclPtr< AbstractSvxObjectTitleDescDialog > pDlg( + pFact->CreateSvxObjectTitleDescDialog(pChartWindow, aTitle, aDescription)); + if ( pDlg->Execute() == RET_OK ) + { + pDlg->GetTitle( aTitle ); + pDlg->GetDescription( aDescription ); + pSelectedObj->SetTitle( aTitle ); + pSelectedObj->SetDescription( aDescription ); + } +} + +void ShapeController::executeDispatch_RenameObject() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pDrawViewWrapper && pDrawViewWrapper->GetMarkedObjectCount() == 1) ) + return; + + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + if ( !pSelectedObj ) + return; + + OUString aName = pSelectedObj->GetName(); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + ScopedVclPtr< AbstractSvxObjectNameDialog > pDlg( + pFact->CreateSvxObjectNameDialog(pChartWindow, aName)); + pDlg->SetCheckNameHdl( LINK( this, ShapeController, CheckNameHdl ) ); + if ( pDlg->Execute() == RET_OK ) + { + pDlg->GetName(aName); + if (pSelectedObj->GetName() == aName) + { + pSelectedObj->SetName( aName ); + } + } +} + +void ShapeController::executeDispatch_ChangeZOrder( sal_uInt16 nId ) +{ + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr ); + if ( !pDrawViewWrapper ) + return; + + switch ( nId ) + { + case COMMAND_ID_BRING_TO_FRONT: + { + if ( isForwardPossible() ) + { + pDrawViewWrapper->PutMarkedToTop(); + } + } + break; + case COMMAND_ID_FORWARD: + { + if ( isForwardPossible() ) + { + pDrawViewWrapper->MovMarkedToTop(); + } + } + break; + case COMMAND_ID_BACKWARD: + { + if ( isBackwardPossible() ) + { + pDrawViewWrapper->MovMarkedToBtm(); + } + } + break; + case COMMAND_ID_SEND_TO_BACK: + { + if ( isBackwardPossible() ) + { + SdrObject* pFirstObj = getFirstAdditionalShape(); + pDrawViewWrapper->PutMarkedBehindObj( pFirstObj ); + } + } + break; + default: + { + } + break; + } +} + +void ShapeController::executeDispatch_FontDialog() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( pChartWindow && pDrawModelWrapper && pDrawViewWrapper ) + { + SfxItemSet aAttr( pDrawViewWrapper->GetModel()->GetItemPool() ); + pDrawViewWrapper->GetAttributes( aAttr ); + ViewElementListProvider aViewElementListProvider( pDrawModelWrapper ); + ShapeFontDialog aDlg(pChartWindow, &aAttr, &aViewElementListProvider); + if (aDlg.run() == RET_OK) + { + const SfxItemSet* pOutAttr = aDlg.GetOutputItemSet(); + pDrawViewWrapper->SetAttributes( *pOutAttr ); + } + } +} + +void ShapeController::executeDispatch_ParagraphDialog() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawViewWrapper) ) + return; + + SfxItemPool& rPool = pDrawViewWrapper->GetModel()->GetItemPool(); + SfxItemSet aAttr( rPool ); + pDrawViewWrapper->GetAttributes( aAttr ); + + SfxItemSetFixed< + EE_ITEMS_START, EE_ITEMS_END, + SID_ATTR_PARA_PAGEBREAK, SID_ATTR_PARA_WIDOWS> aNewAttr(rPool); + aNewAttr.Put( aAttr ); + aNewAttr.Put( SvxHyphenZoneItem( false, SID_ATTR_PARA_HYPHENZONE ) ); + aNewAttr.Put( SvxFormatBreakItem( SvxBreak::NONE, SID_ATTR_PARA_PAGEBREAK ) ); + aNewAttr.Put( SvxFormatSplitItem( true, SID_ATTR_PARA_SPLIT) ); + aNewAttr.Put( SvxWidowsItem( 0, SID_ATTR_PARA_WIDOWS) ); + aNewAttr.Put( SvxOrphansItem( 0, SID_ATTR_PARA_ORPHANS) ); + + ShapeParagraphDialog aDlg(pChartWindow, &aNewAttr); + if (aDlg.run() == RET_OK) + { + const SfxItemSet* pOutAttr = aDlg.GetOutputItemSet(); + pDrawViewWrapper->SetAttributes( *pOutAttr ); + } +} + +SdrObject* ShapeController::getFirstAdditionalShape() +{ + SdrObject* pFirstObj = nullptr; + + try + { + DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr ); + if ( pDrawModelWrapper ) + { + Reference< drawing::XShape > xFirstShape; + rtl::Reference<SvxDrawPage> xDrawPage( pDrawModelWrapper->getMainDrawPage() ); + Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); + sal_Int32 nCount = xDrawPage->getCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< drawing::XShape > xShape; + if ( xDrawPage->getByIndex( i ) >>= xShape ) + { + if ( xShape.is() && xShape != xChartRoot ) + { + xFirstShape = xShape; + break; + } + } + } + if ( xFirstShape.is() ) + { + pFirstObj = DrawViewWrapper::getSdrObject( xFirstShape ); + } + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return pFirstObj; +} + +SdrObject* ShapeController::getLastAdditionalShape() +{ + SdrObject* pLastObj = nullptr; + + try + { + DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr ); + if ( pDrawModelWrapper ) + { + Reference< drawing::XShape > xLastShape; + rtl::Reference<SvxDrawPage> xDrawPage( pDrawModelWrapper->getMainDrawPage() ); + Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); + sal_Int32 nCount = xDrawPage->getCount(); + for ( sal_Int32 i = nCount - 1; i >= 0; --i ) + { + Reference< drawing::XShape > xShape; + if ( xDrawPage->getByIndex( i ) >>= xShape ) + { + if ( xShape.is() && xShape != xChartRoot ) + { + xLastShape = xShape; + break; + } + } + } + if ( xLastShape.is() ) + { + pLastObj = DrawViewWrapper::getSdrObject( xLastShape ); + } + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return pLastObj; +} + +bool ShapeController::isBackwardPossible() +{ + if ( m_pChartController && m_pChartController->isAdditionalShapeSelected() ) + { + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( pDrawViewWrapper ) + { + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + SdrObject* pFirstObj = getFirstAdditionalShape(); + if ( pSelectedObj && pFirstObj && pSelectedObj != pFirstObj ) + { + return true; + } + } + } + return false; +} + +bool ShapeController::isForwardPossible() +{ + if ( m_pChartController && m_pChartController->isAdditionalShapeSelected() ) + { + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( pDrawViewWrapper ) + { + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + SdrObject* pLastObj = getLastAdditionalShape(); + if ( pSelectedObj && pLastObj && pSelectedObj != pLastObj ) + { + return true; + } + } + } + return false; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ShapeController.hxx b/chart2/source/controller/main/ShapeController.hxx new file mode 100644 index 000000000..3d65c49e5 --- /dev/null +++ b/chart2/source/controller/main/ShapeController.hxx @@ -0,0 +1,81 @@ +/* -*- 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 "FeatureCommandDispatchBase.hxx" +#include <tools/link.hxx> + +class AbstractSvxObjectNameDialog; +class SdrObject; + +namespace chart +{ + +class ChartController; + +/** This is a CommandDispatch implementation for shapes. + */ +class ShapeController: public FeatureCommandDispatchBase +{ + friend class ControllerCommandDispatch; + +public: + ShapeController( const css::uno::Reference< css::uno::XComponentContext >& rxContext, ChartController* pController ); + virtual ~ShapeController() override; + +protected: + // WeakComponentImplHelperBase + virtual void SAL_CALL disposing() override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // state of a feature + virtual FeatureState getState( const OUString& rCommand ) override; + + // execute a feature + virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) override; + + // all the features which should be handled by this class + virtual void describeSupportedFeatures() override; + +private: + DECL_LINK( CheckNameHdl, AbstractSvxObjectNameDialog&, bool); + + void executeDispatch_FormatLine(); + void executeDispatch_FormatArea(); + void executeDispatch_TextAttributes(); + void executeDispatch_TransformDialog(); + void executeDispatch_ObjectTitleDescription(); + void executeDispatch_RenameObject(); + void executeDispatch_ChangeZOrder( sal_uInt16 nId ); + void executeDispatch_FontDialog(); + void executeDispatch_ParagraphDialog(); + + SdrObject* getFirstAdditionalShape(); + SdrObject* getLastAdditionalShape(); + bool isBackwardPossible(); + bool isForwardPossible(); + + ChartController* m_pChartController; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/StatusBarCommandDispatch.cxx b/chart2/source/controller/main/StatusBarCommandDispatch.cxx new file mode 100644 index 000000000..440bd9885 --- /dev/null +++ b/chart2/source/controller/main/StatusBarCommandDispatch.cxx @@ -0,0 +1,126 @@ +/* -*- 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 "StatusBarCommandDispatch.hxx" +#include <ObjectNameProvider.hxx> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <ChartModel.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +StatusBarCommandDispatch::StatusBarCommandDispatch( + const Reference< uno::XComponentContext > & xContext, + const rtl::Reference<::chart::ChartModel> & xModel, + const Reference< view::XSelectionSupplier > & xSelSupp ) : + impl::StatusBarCommandDispatch_Base( xContext ), + m_xChartModel( xModel ), + m_xSelectionSupplier( xSelSupp ), + m_bIsModified( false ) +{} + +StatusBarCommandDispatch::~StatusBarCommandDispatch() +{} + +void StatusBarCommandDispatch::initialize() +{ + if( m_xChartModel.is()) + { + m_xChartModel->addModifyListener( this ); + } + + if( m_xSelectionSupplier.is()) + { + m_xSelectionSupplier->addSelectionChangeListener( this ); + } +} + +void StatusBarCommandDispatch::fireStatusEvent( + const OUString & rURL, + const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ ) +{ + bool bFireAll( rURL.isEmpty() ); + bool bFireContext( bFireAll || rURL == ".uno:Context" ); + bool bFireModified( bFireAll || rURL == ".uno:ModifiedStatus" ); + + if( bFireContext && m_xChartModel.is()) + { + uno::Any aArg; + aArg <<= ObjectNameProvider::getSelectedObjectText( m_aSelectedOID.getObjectCID(), m_xChartModel ); + fireStatusEventForURL( ".uno:Context", aArg, true, xSingleListener ); + } + if( bFireModified ) + { + uno::Any aArg; + if( m_bIsModified ) + aArg <<= OUString("*"); + fireStatusEventForURL( ".uno:ModifiedStatus", aArg, true, xSingleListener ); + } +} + +// ____ XDispatch ____ +void SAL_CALL StatusBarCommandDispatch::dispatch( + const util::URL& /* URL */, + const Sequence< beans::PropertyValue >& /* Arguments */ ) +{ + // nothing to do here +} + +// ____ WeakComponentImplHelperBase ____ +/// is called when this is disposed +void SAL_CALL StatusBarCommandDispatch::disposing() +{ + m_xChartModel.clear(); + m_xSelectionSupplier.clear(); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL StatusBarCommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{ + m_xChartModel.clear(); + m_xSelectionSupplier.clear(); +} + +// ____ XModifyListener ____ +void SAL_CALL StatusBarCommandDispatch::modified( const lang::EventObject& aEvent ) +{ + if( m_xChartModel.is()) + m_bIsModified = m_xChartModel->isModified(); + + CommandDispatch::modified( aEvent ); +} + +// ____ XSelectionChangeListener ____ +void SAL_CALL StatusBarCommandDispatch::selectionChanged( const lang::EventObject& /* aEvent */ ) +{ + if( m_xSelectionSupplier.is()) + m_aSelectedOID = ObjectIdentifier( m_xSelectionSupplier->getSelection() ); + else + m_aSelectedOID = ObjectIdentifier(); + fireAllStatusEvents( nullptr ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/StatusBarCommandDispatch.hxx b/chart2/source/controller/main/StatusBarCommandDispatch.hxx new file mode 100644 index 000000000..c123475c0 --- /dev/null +++ b/chart2/source/controller/main/StatusBarCommandDispatch.hxx @@ -0,0 +1,94 @@ +/* -*- 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 "CommandDispatch.hxx" +#include <ObjectIdentifier.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/view/XSelectionChangeListener.hpp> +#include <rtl/ref.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::util { class XModifiable; } +namespace com::sun::star::view { class XSelectionSupplier; } + +namespace chart +{ + +/** This is a CommandDispatch implementation for all commands the status bar offers + + This class reads the information needed from the XModel passed here. + */ + +namespace impl +{ +typedef ::cppu::ImplInheritanceHelper< + CommandDispatch, + css::view::XSelectionChangeListener > + StatusBarCommandDispatch_Base; +} + +class StatusBarCommandDispatch : public impl::StatusBarCommandDispatch_Base +{ +public: + explicit StatusBarCommandDispatch( + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const rtl::Reference<::chart::ChartModel> & xModel, + const css::uno::Reference< css::view::XSelectionSupplier > & xSelSupp ); + virtual ~StatusBarCommandDispatch() override; + + // late initialisation, especially for adding as listener + virtual void initialize() override; + +protected: + // ____ XDispatch ____ + virtual void SAL_CALL dispatch( + const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + + // ____ WeakComponentImplHelperBase ____ + /// is called when this is disposed + virtual void SAL_CALL disposing() override; + + // ____ XModifyListener (override from CommandDispatch) ____ + 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; + + virtual void fireStatusEvent( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override; + + // ____ XSelectionChangeListener ____ + virtual void SAL_CALL selectionChanged( + const css::lang::EventObject& aEvent ) override; + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + css::uno::Reference< css::view::XSelectionSupplier > m_xSelectionSupplier; + bool m_bIsModified; + ObjectIdentifier m_aSelectedOID; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ToolbarController.cxx b/chart2/source/controller/main/ToolbarController.cxx new file mode 100644 index 000000000..17df7c7c8 --- /dev/null +++ b/chart2/source/controller/main/ToolbarController.cxx @@ -0,0 +1,121 @@ +/* -*- 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 <ChartToolbarController.hxx> + +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XFramesSupplier.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart { + +ChartToolbarController::ChartToolbarController(const css::uno::Sequence<css::uno::Any>& rProperties) +{ + for (const auto& rProperty : rProperties) + { + css::beans::PropertyValue aPropValue; + rProperty >>= aPropValue; + if (aPropValue.Name == "Frame") + { + mxFramesSupplier.set(aPropValue.Value, css::uno::UNO_QUERY); + break; + } + } +} + +ChartToolbarController::~ChartToolbarController() +{ +} + +void ChartToolbarController::execute(sal_Int16 /*nKeyModifier*/) +{ +} + +void ChartToolbarController::click() +{ + css::uno::Reference<css::frame::XFrame> xActiveFrame = mxFramesSupplier->getActiveFrame(); + if (!xActiveFrame.is()) + return; + + css::uno::Reference<css::frame::XController> xActiveController = xActiveFrame->getController(); + if (!xActiveController.is()) + return; + + css::uno::Reference<css::frame::XDispatch> xDispatch(xActiveController, css::uno::UNO_QUERY); + if (!xDispatch.is()) + return; + + css::util::URL aURL; + aURL.Path = "FormatSelection"; + xDispatch->dispatch(aURL, css::uno::Sequence<css::beans::PropertyValue>()); +} + +void ChartToolbarController::doubleClick() +{ + SAL_INFO("chart2", "double clicked"); +} + + +css::uno::Reference<css::awt::XWindow> ChartToolbarController::createPopupWindow() +{ + return css::uno::Reference<css::awt::XWindow>(); +} + +css::uno::Reference<css::awt::XWindow> ChartToolbarController::createItemWindow( + const css::uno::Reference<css::awt::XWindow>& /*rParent*/) +{ + return css::uno::Reference<css::awt::XWindow>(); +} + +void ChartToolbarController::statusChanged(const css::frame::FeatureStateEvent& /*rEvent*/) +{ + +} + +void ChartToolbarController::disposing(const css::lang::EventObject& /*rSource*/) +{ +} + +void ChartToolbarController::initialize(const css::uno::Sequence<css::uno::Any>& /*rAny*/) +{ +} + +void ChartToolbarController::update() +{ +} + + +OUString ChartToolbarController::getImplementationName() +{ + return "org.libreoffice.chart2.Chart2ToolboxController"; +} + +sal_Bool ChartToolbarController::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> ChartToolbarController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_chart2_Chart2ToolboxController(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const & rProperties) +{ + return cppu::acquire(new ::chart::ChartToolbarController(rProperties)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoActions.cxx b/chart2/source/controller/main/UndoActions.cxx new file mode 100644 index 000000000..6d043137d --- /dev/null +++ b/chart2/source/controller/main/UndoActions.cxx @@ -0,0 +1,116 @@ +/* -*- 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 "UndoActions.hxx" +#include "ChartModelClone.hxx" +#include <ChartModel.hxx> + +#include <com/sun/star/lang/DisposedException.hpp> + +#include <svx/svdundo.hxx> + +#include <memory> + +using namespace ::com::sun::star; + +namespace chart::impl +{ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::lang::DisposedException; + +UndoElement::UndoElement( const OUString& i_actionString, const rtl::Reference<::chart::ChartModel>& i_documentModel, const std::shared_ptr< ChartModelClone >& i_modelClone ) + :m_sActionString( i_actionString ) + ,m_xDocumentModel( i_documentModel ) + ,m_pModelClone( i_modelClone ) +{ +} + +UndoElement::~UndoElement() +{ +} + +void UndoElement::disposing(std::unique_lock<std::mutex>&) +{ + if ( m_pModelClone ) + m_pModelClone->dispose(); + m_pModelClone.reset(); + m_xDocumentModel.clear(); +} + +OUString SAL_CALL UndoElement::getTitle() +{ + return m_sActionString; +} + +void UndoElement::impl_toggleModelState() +{ + // get a snapshot of the current state of our model + auto pNewClone = std::make_shared<ChartModelClone>( m_xDocumentModel, m_pModelClone->getFacet() ); + // apply the previous snapshot to our model + m_pModelClone->applyToModel( m_xDocumentModel ); + // remember the new snapshot, for the next toggle + m_pModelClone = pNewClone; +} + +void SAL_CALL UndoElement::undo( ) +{ + impl_toggleModelState(); +} + +void SAL_CALL UndoElement::redo( ) +{ + impl_toggleModelState(); +} + +// = ShapeUndoElement + +ShapeUndoElement::ShapeUndoElement( std::unique_ptr<SdrUndoAction> xSdrUndoAction ) + :m_xAction( std::move(xSdrUndoAction) ) +{ +} + +ShapeUndoElement::~ShapeUndoElement() +{ +} + +OUString SAL_CALL ShapeUndoElement::getTitle() +{ + if ( !m_xAction ) + throw DisposedException( OUString(), *this ); + return m_xAction->GetComment(); +} + +void SAL_CALL ShapeUndoElement::undo( ) +{ + if ( !m_xAction ) + throw DisposedException( OUString(), *this ); + m_xAction->Undo(); +} + +void SAL_CALL ShapeUndoElement::redo( ) +{ + if ( !m_xAction ) + throw DisposedException( OUString(), *this ); + m_xAction->Redo(); +} + +} // namespace chart::impl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoActions.hxx b/chart2/source/controller/main/UndoActions.hxx new file mode 100644 index 000000000..3291a72be --- /dev/null +++ b/chart2/source/controller/main/UndoActions.hxx @@ -0,0 +1,101 @@ +/* -*- 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/XUndoAction.hpp> + +#include <rtl/ref.hxx> +#include <rtl/ustring.hxx> +#include <comphelper/compbase.hxx> + +#include <memory> + +namespace com::sun::star::frame { class XModel; } + +class SdrUndoAction; + +namespace chart +{ +class ChartModel; +class ChartModelClone; + +namespace impl +{ + +typedef comphelper::WeakComponentImplHelper< css::document::XUndoAction > UndoElement_TBase; + +class UndoElement final : public UndoElement_TBase +{ +public: + /** creates a new undo action + + @param i_actionString + is the title of the Undo action + @param i_documentModel + is the actual document model which the undo actions operates on + @param i_modelClone + is the cloned model from before the changes, which the Undo action represents, have been applied. + Upon <member>invoking</member>, the clone model is applied to the document model. + */ + UndoElement( const OUString & i_actionString, + const rtl::Reference<::chart::ChartModel>& i_documentModel, + const std::shared_ptr< ChartModelClone >& i_modelClone + ); + virtual ~UndoElement() override; + + UndoElement(const UndoElement&) = delete; + const UndoElement& operator=(const UndoElement&) = delete; + + // XUndoAction + virtual OUString SAL_CALL getTitle() override; + virtual void SAL_CALL undo( ) override; + virtual void SAL_CALL redo( ) override; + + // WeakComponentImplHelper + virtual void disposing(std::unique_lock<std::mutex>&) override; + +private: + void impl_toggleModelState(); + +private: + OUString m_sActionString; + rtl::Reference<::chart::ChartModel> m_xDocumentModel; + std::shared_ptr< ChartModelClone > m_pModelClone; +}; + +typedef comphelper::WeakComponentImplHelper< css::document::XUndoAction > ShapeUndoElement_TBase; +class ShapeUndoElement final : public ShapeUndoElement_TBase +{ +public: + explicit ShapeUndoElement( std::unique_ptr<SdrUndoAction> xSdrUndoAction ); + virtual ~ShapeUndoElement() override; + + // XUndoAction + virtual OUString SAL_CALL getTitle() override; + virtual void SAL_CALL undo( ) override; + virtual void SAL_CALL redo( ) override; + +private: + std::unique_ptr<SdrUndoAction> m_xAction; +}; + +} // namespace impl +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoCommandDispatch.cxx b/chart2/source/controller/main/UndoCommandDispatch.cxx new file mode 100644 index 000000000..03897adf3 --- /dev/null +++ b/chart2/source/controller/main/UndoCommandDispatch.cxx @@ -0,0 +1,145 @@ +/* -*- 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 "UndoCommandDispatch.hxx" +#include <ChartModel.hxx> + +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/document/UndoFailedException.hpp> + +#include <vcl/svapp.hxx> +#include <tools/diagnose_ex.h> + +#include <svtools/strings.hrc> +#include <svtools/svtresid.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +UndoCommandDispatch::UndoCommandDispatch( + const Reference< uno::XComponentContext > & xContext, + const rtl::Reference<::chart::ChartModel> & xModel ) : + CommandDispatch( xContext ), + m_xModel( xModel ) +{ + m_xUndoManager.set( m_xModel->getUndoManager(), uno::UNO_SET_THROW ); +} + +UndoCommandDispatch::~UndoCommandDispatch() +{} + +void UndoCommandDispatch::initialize() +{ + Reference< util::XModifyBroadcaster > xBroadcaster( m_xUndoManager, uno::UNO_QUERY ); + ENSURE_OR_RETURN_VOID( xBroadcaster.is(), "UndoCommandDispatch::initialize: missing modification broadcaster interface!" ); + xBroadcaster->addModifyListener( this ); +} + +void UndoCommandDispatch::fireStatusEvent( + const OUString & rURL, + const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ ) +{ + if( !m_xUndoManager.is() ) + return; + + const bool bFireAll = rURL.isEmpty(); + uno::Any aUndoState, aRedoState, aUndoStrings, aRedoStrings; + if( m_xUndoManager->isUndoPossible()) + aUndoState <<= SvtResId( STR_UNDO ) + m_xUndoManager->getCurrentUndoActionTitle(); + if( m_xUndoManager->isRedoPossible()) + aRedoState <<= SvtResId( STR_REDO ) + m_xUndoManager->getCurrentRedoActionTitle(); + + aUndoStrings <<= m_xUndoManager->getAllUndoActionTitles(); + aRedoStrings <<= m_xUndoManager->getAllRedoActionTitles(); + + if( bFireAll || rURL == ".uno:Undo" ) + fireStatusEventForURL( ".uno:Undo", aUndoState, m_xUndoManager->isUndoPossible(), xSingleListener ); + if( bFireAll || rURL == ".uno:Redo" ) + fireStatusEventForURL( ".uno:Redo", aRedoState, m_xUndoManager->isRedoPossible(), xSingleListener ); + if( bFireAll || rURL == ".uno:GetUndoStrings" ) + fireStatusEventForURL( ".uno:GetUndoStrings", aUndoStrings, true, xSingleListener ); + if( bFireAll || rURL == ".uno:GetRedoStrings" ) + fireStatusEventForURL( ".uno:GetRedoStrings", aRedoStrings, true, xSingleListener ); +} + +// ____ XDispatch ____ +void SAL_CALL UndoCommandDispatch::dispatch( + const util::URL& URL, + const Sequence< beans::PropertyValue >& Arguments ) +{ + if( !m_xUndoManager.is() ) + return; + + // why is it necessary to lock the solar mutex here? + SolarMutexGuard aSolarGuard; + try + { + sal_Int16 nCount( 1 ); + if ( Arguments.hasElements() && Arguments[0].Name == URL.Path ) + Arguments[0].Value >>= nCount; + + while ( nCount-- ) + { + if ( URL.Path == "Undo" ) + m_xUndoManager->undo(); + else + m_xUndoManager->redo(); + } + } + catch( const document::UndoFailedException& ) + { + // silently ignore + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + // \-- +} + +// ____ WeakComponentImplHelperBase ____ +/// is called when this is disposed +void SAL_CALL UndoCommandDispatch::disposing() +{ + Reference< util::XModifyBroadcaster > xBroadcaster( m_xUndoManager, uno::UNO_QUERY ); + OSL_ENSURE( xBroadcaster.is(), "UndoCommandDispatch::initialize: missing modification broadcaster interface!" ); + if( xBroadcaster.is() ) + { + xBroadcaster->removeModifyListener( this ); + } + + m_xUndoManager.clear(); + m_xModel.clear(); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL UndoCommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{ + m_xUndoManager.clear(); + m_xModel.clear(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoCommandDispatch.hxx b/chart2/source/controller/main/UndoCommandDispatch.hxx new file mode 100644 index 000000000..7be241a5f --- /dev/null +++ b/chart2/source/controller/main/UndoCommandDispatch.hxx @@ -0,0 +1,69 @@ +/* -*- 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 "CommandDispatch.hxx" +#include <rtl/ref.hxx> + +namespace com::sun::star::document { class XUndoManager; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class ChartModel; + +/** This is a CommandDispatch implementation for Undo and Redo. + */ +class UndoCommandDispatch : public CommandDispatch +{ +public: + explicit UndoCommandDispatch( + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const rtl::Reference<::chart::ChartModel> & xModel ); + virtual ~UndoCommandDispatch() override; + + // late initialisation, especially for adding as listener + virtual void initialize() override; + +protected: + // ____ XDispatch ____ + virtual void SAL_CALL dispatch( + const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + + // ____ WeakComponentImplHelperBase ____ + /// is called when this is disposed + virtual void SAL_CALL disposing() override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + virtual void fireStatusEvent( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override; + +private: + rtl::Reference<::chart::ChartModel> m_xModel; + css::uno::Reference< css::document::XUndoManager > m_xUndoManager; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoGuard.cxx b/chart2/source/controller/main/UndoGuard.cxx new file mode 100644 index 000000000..85cb8bcc9 --- /dev/null +++ b/chart2/source/controller/main/UndoGuard.cxx @@ -0,0 +1,151 @@ +/* -*- 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 "UndoGuard.hxx" +#include "ChartModelClone.hxx" +#include "UndoActions.hxx" +#include <ChartModel.hxx> + +#include <com/sun/star/document/XUndoManager.hpp> + +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +UndoGuard::UndoGuard( const OUString& i_undoString, const uno::Reference< document::XUndoManager > & i_undoManager, + const ModelFacet i_facet ) + :m_xUndoManager( i_undoManager ) + ,m_aUndoString( i_undoString ) + ,m_bActionPosted( false ) +{ + m_xChartModel = dynamic_cast<::chart::ChartModel*>(i_undoManager->getParent().get()); + assert(m_xChartModel); + m_pDocumentSnapshot = std::make_shared<ChartModelClone>( m_xChartModel, i_facet ); +} + +UndoGuard::~UndoGuard() +{ + if ( m_pDocumentSnapshot ) + discardSnapshot(); +} + +void UndoGuard::commit() +{ + if ( !m_bActionPosted && m_pDocumentSnapshot ) + { + try + { + const Reference< document::XUndoAction > xAction( new impl::UndoElement( m_aUndoString, m_xChartModel, m_pDocumentSnapshot ) ); + m_pDocumentSnapshot.reset(); // don't dispose, it's data went over to the UndoElement + m_xUndoManager->addUndoAction( xAction ); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + m_bActionPosted = true; +} + +void UndoGuard::rollback() +{ + ENSURE_OR_RETURN_VOID( !!m_pDocumentSnapshot, "no snapshot!" ); + m_pDocumentSnapshot->applyToModel( m_xChartModel ); + discardSnapshot(); +} + +void UndoGuard::discardSnapshot() +{ + ENSURE_OR_RETURN_VOID( !!m_pDocumentSnapshot, "no snapshot!" ); + m_pDocumentSnapshot->dispose(); + m_pDocumentSnapshot.reset(); +} + +UndoLiveUpdateGuard::UndoLiveUpdateGuard( const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager ) + :UndoGuard( i_undoString, i_undoManager, E_MODEL ) +{ +} + +UndoLiveUpdateGuard::~UndoLiveUpdateGuard() +{ + if ( !isActionPosted() ) + rollback(); +} + +UndoLiveUpdateGuardWithData::UndoLiveUpdateGuardWithData( + const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager ) + :UndoGuard( i_undoString, i_undoManager, E_MODEL_WITH_DATA ) +{ +} + +UndoLiveUpdateGuardWithData::~UndoLiveUpdateGuardWithData() +{ + if ( !isActionPosted() ) + rollback(); +} + +UndoGuardWithSelection::UndoGuardWithSelection( + const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager ) + :UndoGuard( i_undoString, i_undoManager, E_MODEL_WITH_SELECTION ) +{ +} + +UndoGuardWithSelection::~UndoGuardWithSelection() +{ + if ( !isActionPosted() ) + rollback(); +} + +HiddenUndoContext::HiddenUndoContext( const Reference< document::XUndoManager > & i_undoManager ) + :m_xUndoManager( i_undoManager ) +{ + ENSURE_OR_THROW( m_xUndoManager.is(), "invalid undo manager!" ); + try + { + m_xUndoManager->enterHiddenUndoContext(); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + m_xUndoManager.clear(); + // prevents the leaveUndoContext in the dtor + } +} + +HiddenUndoContext::~HiddenUndoContext() +{ + try + { + if ( m_xUndoManager.is() ) + m_xUndoManager->leaveUndoContext(); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoGuard.hxx b/chart2/source/controller/main/UndoGuard.hxx new file mode 100644 index 000000000..9808da8bc --- /dev/null +++ b/chart2/source/controller/main/UndoGuard.hxx @@ -0,0 +1,115 @@ +/* -*- 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 "ChartModelClone.hxx" + +#include <rtl/ustring.hxx> + +#include <memory> + +namespace com::sun::star::document { class XUndoManager; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ + +/** A guard which does nothing, unless you explicitly call commitAction. In particular, in its destructor, it + does neither auto-commit nor auto-rollback the model changes. + */ +class UndoGuard +{ +public: + explicit UndoGuard( + const OUString& i_undoMessage, + const css::uno::Reference< css::document::XUndoManager > & i_undoManager, + const ModelFacet i_facet = E_MODEL + ); + ~UndoGuard(); + + void commit(); + void rollback(); + +protected: + bool isActionPosted() const { return m_bActionPosted; } + +private: + void discardSnapshot(); + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + const css::uno::Reference< css::document::XUndoManager > m_xUndoManager; + + std::shared_ptr< ChartModelClone > m_pDocumentSnapshot; + OUString m_aUndoString; + bool m_bActionPosted; +}; + +/** A guard which, in its destructor, restores the model state it found in the constructor. If + <member>commitAction</member> is called inbetween, the restoration is not performed. + */ +class UndoLiveUpdateGuard : public UndoGuard +{ +public: + explicit UndoLiveUpdateGuard( + const OUString& i_undoMessage, + const css::uno::Reference< css::document::XUndoManager > & i_undoManager + ); + ~UndoLiveUpdateGuard(); +}; + +/** Same as UndoLiveUpdateGuard but with additional storage of the chart's data. + Only use this if the data has internal data. + */ +class UndoLiveUpdateGuardWithData : + public UndoGuard +{ +public: + explicit UndoLiveUpdateGuardWithData( + const OUString& i_undoMessage, + const css::uno::Reference< css::document::XUndoManager > & i_undoManager + ); + ~UndoLiveUpdateGuardWithData(); +}; + +class UndoGuardWithSelection : public UndoGuard +{ +public: + explicit UndoGuardWithSelection( + const OUString& i_undoMessage, + const css::uno::Reference< css::document::XUndoManager > & i_undoManager + ); + virtual ~UndoGuardWithSelection(); +}; + +class HiddenUndoContext +{ +public: + explicit HiddenUndoContext( + const css::uno::Reference< css::document::XUndoManager > & i_undoManager + ); + ~HiddenUndoContext(); + +private: + css::uno::Reference< css::document::XUndoManager > m_xUndoManager; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/Chart2PanelFactory.cxx b/chart2/source/controller/sidebar/Chart2PanelFactory.cxx new file mode 100644 index 000000000..081322b09 --- /dev/null +++ b/chart2/source/controller/sidebar/Chart2PanelFactory.cxx @@ -0,0 +1,147 @@ +/* -*- 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 "Chart2PanelFactory.hxx" + +#include <sfx2/sidebar/SidebarPanelBase.hxx> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <vcl/weldutils.hxx> + +#include "ChartElementsPanel.hxx" +#include "ChartTypePanel.hxx" +#include "ChartSeriesPanel.hxx" +#include <ChartController.hxx> +#include "ChartAxisPanel.hxx" +#include "ChartErrorBarPanel.hxx" +#include "ChartAreaPanel.hxx" +#include "ChartLinePanel.hxx" + +using namespace css::uno; + +namespace chart::sidebar { + +ChartPanelFactory::ChartPanelFactory() +{ +} + +ChartPanelFactory::~ChartPanelFactory() +{ +} + +Reference<css::ui::XUIElement> SAL_CALL ChartPanelFactory::createUIElement ( + const OUString& rsResourceURL, + const ::css::uno::Sequence<css::beans::PropertyValue>& rArguments) +{ + Reference<css::ui::XUIElement> xElement; + + try + { + const ::comphelper::NamedValueCollection aArguments (rArguments); + Reference<css::frame::XFrame> xFrame (aArguments.getOrDefault("Frame", Reference<css::frame::XFrame>())); + Reference<css::awt::XWindow> xParentWindow (aArguments.getOrDefault("ParentWindow", Reference<css::awt::XWindow>())); + Reference<css::frame::XController> xController (aArguments.getOrDefault("Controller", Reference<css::frame::XController>())); + + weld::Widget* pParent(nullptr); + if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xParentWindow.get())) + pParent = pTunnel->getWidget(); + + if (!pParent) + throw RuntimeException( + "PanelFactory::createUIElement called without ParentWindow", + nullptr); + if ( ! xFrame.is()) + throw RuntimeException( + "PanelFactory::createUIElement called without Frame", + nullptr); + if (!xController.is()) + throw RuntimeException( + "ChartPanelFactory::createUIElement called without Controller", + nullptr); + + ChartController* pController = dynamic_cast<ChartController*>(xController.get()); + if (!pController) + throw RuntimeException( + "ChartPanelFactory::createUIElement called without valid ChartController", + nullptr); + + std::unique_ptr<PanelLayout> xPanel; + if (rsResourceURL.endsWith("/ElementsPanel")) + xPanel = ChartElementsPanel::Create( pParent, pController ); + else if (rsResourceURL.endsWith("/TypePanel")) + xPanel = std::make_unique<ChartTypePanel>(pParent, pController); + else if (rsResourceURL.endsWith("/SeriesPanel")) + xPanel = ChartSeriesPanel::Create(pParent, pController); + else if (rsResourceURL.endsWith("/AxisPanel")) + xPanel = ChartAxisPanel::Create(pParent, pController); + else if (rsResourceURL.endsWith("/ErrorBarPanel")) + xPanel = ChartErrorBarPanel::Create(pParent, pController); + else if (rsResourceURL.endsWith("/AreaPanel")) + xPanel = ChartAreaPanel::Create(pParent, xFrame, pController); + else if (rsResourceURL.endsWith("/LinePanel")) + xPanel = ChartLinePanel::Create(pParent, xFrame, pController); + + if (xPanel) + xElement = sfx2::sidebar::SidebarPanelBase::Create( + rsResourceURL, + xFrame, + std::move(xPanel), + css::ui::LayoutSize(-1,-1,-1)); + } + catch (const css::uno::RuntimeException &) + { + throw; + } + catch (const css::uno::Exception&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "ChartPanelFactory::createUIElement exception", + nullptr, anyEx ); + } + + return xElement; +} + +OUString ChartPanelFactory::getImplementationName() +{ + return "org.libreoffice.comp.chart2.sidebar.ChartPanelFactory"; +} + +sal_Bool ChartPanelFactory::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> ChartPanelFactory::getSupportedServiceNames() +{ + return { "com.sun.star.ui.UIElementFactory" }; +} + +} // end of namespace chart::sidebar + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_chart2_sidebar_ChartPanelFactory(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ::chart::sidebar::ChartPanelFactory()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/Chart2PanelFactory.hxx b/chart2/source/controller/sidebar/Chart2PanelFactory.hxx new file mode 100644 index 000000000..87619f647 --- /dev/null +++ b/chart2/source/controller/sidebar/Chart2PanelFactory.hxx @@ -0,0 +1,56 @@ +/* -*- 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 <comphelper/compbase.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/ui/XUIElementFactory.hpp> + + +namespace chart::sidebar { + +typedef comphelper::WeakComponentImplHelper < + css::ui::XUIElementFactory, css::lang::XServiceInfo + > PanelFactoryInterfaceBase; + +class ChartPanelFactory final + : public PanelFactoryInterfaceBase +{ +public: + ChartPanelFactory(); + virtual ~ChartPanelFactory() override; + + ChartPanelFactory(const ChartPanelFactory&) = delete; + const ChartPanelFactory& operator=(const ChartPanelFactory&) = delete; + + // XUIElementFactory + virtual css::uno::Reference<css::ui::XUIElement> SAL_CALL createUIElement( + const OUString& rsResourceURL, + const ::css::uno::Sequence<css::beans::PropertyValue>& rArguments) override; + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; +}; + +} // end of namespace chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartAreaPanel.cxx b/chart2/source/controller/sidebar/ChartAreaPanel.cxx new file mode 100644 index 000000000..b8bd8198b --- /dev/null +++ b/chart2/source/controller/sidebar/ChartAreaPanel.cxx @@ -0,0 +1,551 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include "ChartAreaPanel.hxx" + +#include <ChartController.hxx> +#include <ChartModel.hxx> +#include <ViewElementListProvider.hxx> +#include <PropertyHelper.hxx> + +#include <chartview/DrawModelWrapper.hxx> +#include <com/sun/star/chart2/XDiagram.hpp> + +#include <sfx2/weldutils.hxx> +#include <svx/xfltrit.hxx> +#include <svx/xflftrit.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/unomid.hxx> +#include <vcl/svapp.hxx> + +#include <svx/tbcontrl.hxx> + +namespace chart::sidebar { + +namespace { + +SvxColorToolBoxControl* getColorToolBoxControl(const ToolbarUnoDispatcher& rColorDispatch) +{ + css::uno::Reference<css::frame::XToolbarController> xController = rColorDispatch.GetControllerForCommand(".uno:FillColor"); + SvxColorToolBoxControl* pToolBoxColorControl = dynamic_cast<SvxColorToolBoxControl*>(xController.get()); + return pToolBoxColorControl; +} + +OUString getCID(const rtl::Reference<::chart::ChartModel>& xModel) +{ + css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController()); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + css::uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + { + // if no selection, default to diagram wall so sidebar can show some editable properties + ChartController* pController = dynamic_cast<ChartController*>(xController.get()); + if (pController) + { + pController->select( css::uno::Any( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) ) ); + xSelectionSupplier = css::uno::Reference<css::view::XSelectionSupplier>(xController, css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + aAny = xSelectionSupplier->getSelection(); + } + + if (!aAny.hasValue()) + return OUString(); + } + + OUString aCID; + aAny >>= aCID; + + return aCID; +} + +css::uno::Reference<css::beans::XPropertySet> getPropSet( + const rtl::Reference<::chart::ChartModel>& xModel) +{ + OUString aCID = getCID(xModel); + css::uno::Reference<css::beans::XPropertySet> xPropSet = + ObjectIdentifier::getObjectPropertySet(aCID, xModel); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference<css::chart2::XDiagram> xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (!xDiagram.is()) + return xPropSet; + + xPropSet.set(xDiagram->getWall()); + } + + return xPropSet; +} + +ChartController* getController(const css::uno::Reference<css::frame::XModel>& xModel) +{ + css::uno::Reference<css::frame::XController>xController = xModel->getCurrentController(); + if (!xController.is()) + throw std::exception(); + + ChartController* pController = dynamic_cast<ChartController*>(xController.get()); + if (!pController) + throw std::exception(); + + return pController; +} + +ViewElementListProvider getViewElementListProvider( const css::uno::Reference<css::frame::XModel>& xModel) +{ + ChartController* pController = getController(xModel); + ViewElementListProvider aProvider = pController->getViewElementListProvider(); + return aProvider; +} + +DrawModelWrapper* getDrawModelWrapper(const css::uno::Reference<css::frame::XModel>& xModel) +{ + ChartController* pController = getController(xModel); + return pController->GetDrawModelWrapper(); +} + +XFillGradientItem getXGradientForName(const css::uno::Reference<css::frame::XModel>& xModel, + const OUString& rName) +{ + css::uno::Reference<css::lang::XMultiServiceFactory> xFact(xModel, css::uno::UNO_QUERY); + css::uno::Reference<css::container::XNameAccess> xNameAccess( + xFact->createInstance("com.sun.star.drawing.GradientTable"), css::uno::UNO_QUERY); + if (!xNameAccess.is()) + return XFillGradientItem(); + + if (!xNameAccess->hasByName(rName)) + return XFillGradientItem(); + + css::uno::Any aAny = xNameAccess->getByName(rName); + + XFillGradientItem aItem; + aItem.SetName(rName); + aItem.PutValue(aAny, MID_FILLGRADIENT); + + return aItem; + +} + +XFillFloatTransparenceItem getXTransparencyGradientForName(const css::uno::Reference<css::frame::XModel>& xModel, + const OUString& rName) +{ + css::uno::Reference<css::lang::XMultiServiceFactory> xFact(xModel, css::uno::UNO_QUERY); + css::uno::Reference<css::container::XNameAccess> xNameAccess( + xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), css::uno::UNO_QUERY); + if (!xNameAccess.is()) + return XFillFloatTransparenceItem(); + + if (!xNameAccess->hasByName(rName)) + return XFillFloatTransparenceItem(); + + css::uno::Any aAny = xNameAccess->getByName(rName); + + XFillFloatTransparenceItem aItem; + aItem.SetName(rName); + aItem.PutValue(aAny, MID_FILLGRADIENT); + aItem.SetEnabled(true); + + return aItem; +} + +XHatch getXHatchFromName(const css::uno::Reference<css::frame::XModel>& xModel, + OUString& rName) +{ + try + { + ViewElementListProvider aProvider = getViewElementListProvider(xModel); + XHatchListRef aRef = aProvider.GetHatchList(); + size_t n = aRef->Count(); + for (size_t i = 0; i < n; ++i) + { + const XHatchEntry* pHatch = aRef->GetHatch(i); + if (!pHatch) + continue; + + if (pHatch->GetName().equalsIgnoreAsciiCase(rName)) + { + // we need to update the hatch name + rName = pHatch->GetName(); + return pHatch->GetHatch(); + } + } + } + catch (...) + { + // ignore exception + } + + return XHatch(); +} + +GraphicObject getXBitmapFromName(const css::uno::Reference<css::frame::XModel>& xModel, + std::u16string_view rName) +{ + try + { + ViewElementListProvider aProvider = getViewElementListProvider(xModel); + XBitmapListRef aBmpRef = aProvider.GetBitmapList(); + XPatternListRef aPatRef = aProvider.GetPatternList(); + + size_t n = aBmpRef->Count(); + for (size_t i = 0; i < n; ++i) + { + const XBitmapEntry* pBitmap = aBmpRef->GetBitmap(i); + if (!pBitmap) + continue; + + if (pBitmap->GetName().equalsIgnoreAsciiCase(rName)) + { + return pBitmap->GetGraphicObject(); + } + } + + // perhaps it's a pattern + size_t m = aPatRef->Count(); + for (size_t i = 0; i < m; ++i) + { + const XBitmapEntry* pBitmap = aPatRef->GetBitmap(i); + if (!pBitmap) + continue; + + if (pBitmap->GetName().equalsIgnoreAsciiCase(rName)) + { + return pBitmap->GetGraphicObject(); + } + } + } + catch (...) + { + // ignore exception + } + + return GraphicObject(); +} + +class PreventUpdate +{ +public: + explicit PreventUpdate(bool& bUpdate): + mbUpdate(bUpdate) + { + mbUpdate = false; + } + + ~PreventUpdate() + { + mbUpdate = true; + } + +private: + bool& mbUpdate; +}; + +} + +std::unique_ptr<PanelLayout> ChartAreaPanel::Create( + weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController) +{ + if (pParent == nullptr) + throw css::lang::IllegalArgumentException("no parent Window given to ChartAxisPanel::Create", nullptr, 0); + if (!rxFrame.is()) + throw css::lang::IllegalArgumentException("no XFrame given to ChartAxisPanel::Create", nullptr, 1); + + return std::make_unique<ChartAreaPanel>(pParent, rxFrame, pController); +} + +ChartAreaPanel::ChartAreaPanel(weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController): + svx::sidebar::AreaPropertyPanelBase(pParent, rxFrame), + mxModel(pController->getChartModel()), + mxListener(new ChartSidebarModifyListener(this)), + mxSelectionListener(new ChartSidebarSelectionListener(this)), + mbUpdate(true), + mbModelValid(true), + maFillColorWrapper(mxModel, getColorToolBoxControl(*mxColorDispatch), "FillColor") +{ + std::vector<ObjectType> aAcceptedTypes { OBJECTTYPE_PAGE, OBJECTTYPE_DIAGRAM, + OBJECTTYPE_DATA_SERIES, OBJECTTYPE_DATA_POINT, + OBJECTTYPE_TITLE, OBJECTTYPE_LEGEND}; + mxSelectionListener->setAcceptedTypes(std::move(aAcceptedTypes)); + Initialize(); +} + +ChartAreaPanel::~ChartAreaPanel() +{ + doUpdateModel(nullptr); +} + +void ChartAreaPanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + SvxColorToolBoxControl* pToolBoxColor = getColorToolBoxControl(*mxColorDispatch); + pToolBoxColor->setColorSelectFunction(maFillColorWrapper); + + updateData(); +} + +void ChartAreaPanel::setFillTransparence(const XFillTransparenceItem& rItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + xPropSet->setPropertyValue("FillTransparence", css::uno::Any(rItem.GetValue())); +} + +void ChartAreaPanel::setFillFloatTransparence( + const XFillFloatTransparenceItem& rItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (!rItem.IsEnabled()) + { + xPropSet->setPropertyValue("FillTransparenceGradientName", css::uno::Any(OUString())); + return; + } + + const OUString& aName = rItem.GetName(); + css::uno::Any aGradientVal; + rItem.QueryValue(aGradientVal, MID_FILLGRADIENT); + OUString aNewName = PropertyHelper::addTransparencyGradientUniqueNameToTable(aGradientVal, mxModel, aName); + xPropSet->setPropertyValue("FillTransparenceGradientName", css::uno::Any(aNewName)); +} + +void ChartAreaPanel::setFillStyle(const XFillStyleItem& rItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + xPropSet->setPropertyValue("FillStyle", css::uno::Any(rItem.GetValue())); +} + +void ChartAreaPanel::setFillStyleAndColor(const XFillStyleItem* pStyleItem, + const XFillColorItem& rColorItem) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (pStyleItem) + xPropSet->setPropertyValue("FillStyle", css::uno::Any(pStyleItem->GetValue())); + xPropSet->setPropertyValue("FillColor", css::uno::Any(rColorItem.GetValue())); +} + +void ChartAreaPanel::setFillStyleAndGradient(const XFillStyleItem* pStyleItem, + const XFillGradientItem& rGradientItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (pStyleItem) + xPropSet->setPropertyValue("FillStyle", css::uno::Any(pStyleItem->GetValue())); + + const OUString& aName = rGradientItem.GetName(); + css::uno::Any aGradientVal; + rGradientItem.QueryValue(aGradientVal, MID_FILLGRADIENT); + OUString aNewName = PropertyHelper::addGradientUniqueNameToTable(aGradientVal, mxModel, aName); + xPropSet->setPropertyValue("FillGradientName", css::uno::Any(aNewName)); +} + +void ChartAreaPanel::setFillStyleAndHatch(const XFillStyleItem* pStyleItem, + const XFillHatchItem& rHatchItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (pStyleItem) + xPropSet->setPropertyValue("FillStyle", css::uno::Any(pStyleItem->GetValue())); + xPropSet->setPropertyValue("FillHatchName", css::uno::Any(rHatchItem.GetValue())); +} + +void ChartAreaPanel::setFillStyleAndBitmap(const XFillStyleItem* pStyleItem, + const XFillBitmapItem& rBitmapItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (pStyleItem) + xPropSet->setPropertyValue("FillStyle", css::uno::Any(pStyleItem->GetValue())); + + css::uno::Any aBitmap; + rBitmapItem.QueryValue(aBitmap, MID_BITMAP); + const OUString& aPreferredName = rBitmapItem.GetName(); + aBitmap <<= PropertyHelper::addBitmapUniqueNameToTable(aBitmap, mxModel, aPreferredName); + xPropSet->setPropertyValue("FillBitmapName", aBitmap); +} + +void ChartAreaPanel::setFillUseBackground(const XFillStyleItem* pStyleItem, + const XFillUseSlideBackgroundItem& /*rItem*/) +{ + setFillStyle(*pStyleItem); +} + +void ChartAreaPanel::updateData() +{ + if (!mbUpdate || !mbModelValid) + return; + + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + css::uno::Reference<css::beans::XPropertySetInfo> xInfo(xPropSet->getPropertySetInfo()); + if (!xInfo.is()) + return; + + SolarMutexGuard aGuard; + if (xInfo->hasPropertyByName("FillStyle")) + { + css::drawing::FillStyle eFillStyle = css::drawing::FillStyle_SOLID; + xPropSet->getPropertyValue("FillStyle") >>= eFillStyle; + XFillStyleItem aFillStyleItem(eFillStyle); + updateFillStyle(false, true, &aFillStyleItem); + } + + if (xInfo->hasPropertyByName("FillTransparence")) + { + sal_uInt16 nFillTransparence = 0; + xPropSet->getPropertyValue("FillTransparence") >>= nFillTransparence; + SfxUInt16Item aTransparenceItem(0, nFillTransparence); + updateFillTransparence(false, true, &aTransparenceItem); + } + + if (xInfo->hasPropertyByName("FillGradientName")) + { + OUString aGradientName; + xPropSet->getPropertyValue("FillGradientName") >>= aGradientName; + XFillGradientItem aGradientItem = getXGradientForName(mxModel, aGradientName); + updateFillGradient(false, true, &aGradientItem); + } + + if (xInfo->hasPropertyByName("FillHatchName")) + { + OUString aHatchName; + xPropSet->getPropertyValue("FillHatchName") >>= aHatchName; + XHatch aHatch = getXHatchFromName(mxModel, aHatchName); + XFillHatchItem aHatchItem(aHatchName, aHatch); + updateFillHatch(false, true, &aHatchItem); + } + + if (xInfo->hasPropertyByName("FillBitmapName")) + { + OUString aBitmapName; + xPropSet->getPropertyValue("FillBitmapName") >>= aBitmapName; + GraphicObject aBitmap = getXBitmapFromName(mxModel, aBitmapName); + XFillBitmapItem aBitmapItem(aBitmapName, aBitmap); + std::unique_ptr<XFillBitmapItem> pBitmapItem; + try + { + DrawModelWrapper* pModelWrapper = getDrawModelWrapper(mxModel); + if (pModelWrapper) + { + pBitmapItem = aBitmapItem.checkForUniqueItem(&pModelWrapper->getSdrModel()); + } + } + catch (...) + { + } + updateFillBitmap(false, true, pBitmapItem ? pBitmapItem.get() : &aBitmapItem); + } + + if (xInfo->hasPropertyByName("FillTransparenceGradientName")) + { + OUString aFillFloatTransparenceName; + xPropSet->getPropertyValue("FillTransparenceGradientName") >>= aFillFloatTransparenceName; + XFillFloatTransparenceItem aFillFloatTransparenceItem = getXTransparencyGradientForName(mxModel, aFillFloatTransparenceName); + updateFillFloatTransparence(false, true, &aFillFloatTransparenceItem); + + maFillColorWrapper.updateData(); + } + + if (xInfo->hasPropertyByName("FillColor")) + { + sal_uInt32 nFillColor = 0; + xPropSet->getPropertyValue("FillColor") >>= nFillColor; + XFillColorItem aFillColorItem("", Color(ColorTransparency, nFillColor)); + updateFillColor(true, &aFillColorItem); + } +} + +void ChartAreaPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartAreaPanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +void ChartAreaPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + + css::uno::Reference<css::view::XSelectionSupplier> oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxListener); + + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartAreaPanel::updateModel( css::uno::Reference<css::frame::XModel> xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartAreaPanel.hxx b/chart2/source/controller/sidebar/ChartAreaPanel.hxx new file mode 100644 index 000000000..75caf8d0d --- /dev/null +++ b/chart2/source/controller/sidebar/ChartAreaPanel.hxx @@ -0,0 +1,86 @@ +/* -*- 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/. + */ + +#pragma once + +#include <sfx2/sidebar/SidebarModelUpdate.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xbtmpit.hxx> + +#include <svx/sidebar/AreaPropertyPanelBase.hxx> + +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" +#include "ChartColorWrapper.hxx" + +class XFillFloatTransparenceItem; +class XFillTransparenceItem; +class XFillColorItem; + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartAreaPanel : public svx::sidebar::AreaPropertyPanelBase, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static std::unique_ptr<PanelLayout> Create( + weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController); + + // constructor/destructor + ChartAreaPanel( + weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController); + + virtual ~ChartAreaPanel() override; + + virtual void setFillTransparence(const XFillTransparenceItem& rItem) override; + virtual void setFillFloatTransparence(const XFillFloatTransparenceItem& rItem) override; + virtual void setFillStyle(const XFillStyleItem& rItem) override; + virtual void setFillStyleAndColor(const XFillStyleItem* pStyleItem, const XFillColorItem& rColorItem) override; + virtual void setFillStyleAndGradient(const XFillStyleItem* pStyleItem, const XFillGradientItem& rGradientItem) override; + virtual void setFillStyleAndHatch(const XFillStyleItem* pStyleItem, const XFillHatchItem& rHatchItem) override; + virtual void setFillStyleAndBitmap(const XFillStyleItem* pStyleItem, const XFillBitmapItem& rBitmapItem) override; + virtual void setFillUseBackground(const XFillStyleItem* pStyleItem, const XFillUseSlideBackgroundItem& rItem) override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void selectionChanged(bool bCorrectType) override; + + virtual void updateModel(css::uno::Reference<css::frame::XModel> xModel) override; + +private: + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference<css::util::XModifyListener> mxListener; + rtl::Reference<ChartSidebarSelectionListener> mxSelectionListener; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + bool mbUpdate; + bool mbModelValid; + + ChartColorWrapper maFillColorWrapper; +}; + +} } // end of namespace svx::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartAxisPanel.cxx b/chart2/source/controller/sidebar/ChartAxisPanel.cxx new file mode 100644 index 000000000..acc4a8add --- /dev/null +++ b/chart2/source/controller/sidebar/ChartAxisPanel.cxx @@ -0,0 +1,373 @@ +/* -*- 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 <com/sun/star/chart/ChartAxisLabelPosition.hpp> +#include <com/sun/star/chart2/AxisOrientation.hpp> + +#include <vcl/svapp.hxx> +#include <sal/log.hxx> + +#include "ChartAxisPanel.hxx" +#include <ChartController.hxx> +#include <ChartModel.hxx> +#include <Axis.hxx> + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +bool isLabelShown(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< ::chart::Axis > xAxis = ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return false; + + uno::Any aAny = xAxis->getPropertyValue("DisplayLabels"); + if (!aAny.hasValue()) + return false; + + bool bVisible = false; + aAny >>= bVisible; + return bVisible; +} + +void setLabelShown(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bVisible) +{ + rtl::Reference< ::chart::Axis > xAxis = ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return; + + xAxis->setPropertyValue("DisplayLabels", css::uno::Any(bVisible)); +} + +struct AxisLabelPosMap +{ + sal_Int32 nPos; + css::chart::ChartAxisLabelPosition ePos; +}; + +AxisLabelPosMap const aLabelPosMap[] = { + { 0, css::chart::ChartAxisLabelPosition_NEAR_AXIS }, + { 1, css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE }, + { 2, css::chart::ChartAxisLabelPosition_OUTSIDE_START }, + { 3, css::chart::ChartAxisLabelPosition_OUTSIDE_END } +}; + +sal_Int32 getLabelPosition(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< ::chart::Axis > xAxis = ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return 0; + + uno::Any aAny = xAxis->getPropertyValue("LabelPosition"); + if (!aAny.hasValue()) + return 0; + + css::chart::ChartAxisLabelPosition ePos; + aAny >>= ePos; + for (AxisLabelPosMap const & i : aLabelPosMap) + { + if (i.ePos == ePos) + return i.nPos; + } + + return 0; +} + +void setLabelPosition(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, sal_Int32 nPos) +{ + rtl::Reference< ::chart::Axis > xAxis = ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return; + + css::chart::ChartAxisLabelPosition ePos; + for (AxisLabelPosMap const & i : aLabelPosMap) + { + if (i.nPos == nPos) + ePos = i.ePos; + } + + xAxis->setPropertyValue("LabelPosition", css::uno::Any(ePos)); +} + +bool isReverse(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< Axis > xAxis = + ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return false; + + css::chart2::ScaleData aData = xAxis->getScaleData(); + + return aData.Orientation == css::chart2::AxisOrientation_REVERSE; +} + +void setReverse(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bReverse) +{ + rtl::Reference< Axis > xAxis = + ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return; + + css::chart2::ScaleData aData = xAxis->getScaleData(); + if (bReverse) + aData.Orientation = css::chart2::AxisOrientation_REVERSE; + else + aData.Orientation = css::chart2::AxisOrientation_MATHEMATICAL; + + xAxis->setScaleData(aData); +} + +OUString getCID(const css::uno::Reference<css::frame::XModel>& xModel) +{ + css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController()); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + uno::Any aAny = xSelectionSupplier->getSelection(); + assert(aAny.hasValue()); + OUString aCID; + aAny >>= aCID; +#if defined DBG_UTIL && !defined NDEBUG + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if(eType != OBJECTTYPE_AXIS) + SAL_WARN("chart2","Selected item is not an axis"); +#endif + + return aCID; +} + +void setAxisRotation(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, double nVal) +{ + rtl::Reference< ::chart::Axis > xAxis = + ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return; + + xAxis->setPropertyValue("TextRotation", css::uno::Any(nVal)); +} + +double getAxisRotation(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< ::chart::Axis > xAxis = + ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return 0; + + css::uno::Any aAny = xAxis->getPropertyValue("TextRotation"); + double nVal = 0; + aAny >>= nVal; + return nVal; +} + +} + +ChartAxisPanel::ChartAxisPanel( + weld::Widget* pParent, + ChartController* pController) + : PanelLayout(pParent, "ChartAxisPanel", "modules/schart/ui/sidebaraxis.ui") + , mxCBShowLabel(m_xBuilder->weld_check_button("checkbutton_show_label")) + , mxCBReverse(m_xBuilder->weld_check_button("checkbutton_reverse")) + , mxLBLabelPos(m_xBuilder->weld_combo_box("comboboxtext_label_position")) + , mxGridLabel(m_xBuilder->weld_widget("label_props")) + , mxNFRotation(m_xBuilder->weld_metric_spin_button("spinbutton1", FieldUnit::DEGREE)) + , mxModel(pController->getChartModel()) + , mxModifyListener(new ChartSidebarModifyListener(this)) + , mxSelectionListener(new ChartSidebarSelectionListener(this, OBJECTTYPE_AXIS)) + , mbModelValid(true) +{ + Initialize(); +} + +ChartAxisPanel::~ChartAxisPanel() +{ + doUpdateModel(nullptr); + + mxCBShowLabel.reset(); + mxCBReverse.reset(); + + mxLBLabelPos.reset(); + mxGridLabel.reset(); + + mxNFRotation.reset(); +} + +void ChartAxisPanel::Initialize() +{ + mxModel->addModifyListener(mxModifyListener); + + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + updateData(); + + Link<weld::Toggleable&,void> aLink = LINK(this, ChartAxisPanel, CheckBoxHdl); + mxCBShowLabel->connect_toggled(aLink); + mxCBReverse->connect_toggled(aLink); + + Link<weld::MetricSpinButton&, void> aSpinButtonLink = LINK(this, ChartAxisPanel, TextRotationHdl); + mxNFRotation->connect_value_changed(aSpinButtonLink); + + mxLBLabelPos->connect_changed(LINK(this, ChartAxisPanel, ListBoxHdl)); +} + +void ChartAxisPanel::updateData() +{ + if (!mbModelValid) + return; + + OUString aCID = getCID(mxModel); + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType!=OBJECTTYPE_AXIS) + return; + + SolarMutexGuard aGuard; + + mxCBShowLabel->set_active(isLabelShown(mxModel, aCID)); + mxCBReverse->set_active(isReverse(mxModel, aCID)); + + mxLBLabelPos->set_active(getLabelPosition(mxModel, aCID)); + mxNFRotation->set_value(getAxisRotation(mxModel, aCID), FieldUnit::DEGREE); +} + +std::unique_ptr<PanelLayout> ChartAxisPanel::Create ( + weld::Widget* pParent, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartAxisPanel::Create", nullptr, 0); + return std::make_unique<ChartAxisPanel>(pParent, pController); +} + +void ChartAxisPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartAxisPanel::HandleContextChange( + const vcl::EnumContext& ) +{ + updateData(); +} + +void ChartAxisPanel::NotifyItemUpdate( + sal_uInt16 /*nSID*/, + SfxItemState /*eState*/, + const SfxPoolItem* /*pState*/ ) +{ +} + +void ChartAxisPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartAxisPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxModifyListener); + + css::uno::Reference<css::view::XSelectionSupplier> oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxModifyListener); + + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartAxisPanel::updateModel(css::uno::Reference<css::frame::XModel> xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +void ChartAxisPanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +IMPL_LINK(ChartAxisPanel, CheckBoxHdl, weld::Toggleable&, rCheckbox, void) +{ + OUString aCID = getCID(mxModel); + bool bChecked = rCheckbox.get_active(); + + if (&rCheckbox == mxCBShowLabel.get()) + { + mxGridLabel->set_sensitive(bChecked); + setLabelShown(mxModel, aCID, bChecked); + } + else if (&rCheckbox == mxCBReverse.get()) + setReverse(mxModel, aCID, bChecked); +} + +IMPL_LINK_NOARG(ChartAxisPanel, ListBoxHdl, weld::ComboBox&, void) +{ + OUString aCID = getCID(mxModel); + sal_Int32 nPos = mxLBLabelPos->get_active(); + + setLabelPosition(mxModel, aCID, nPos); +} + +IMPL_LINK(ChartAxisPanel, TextRotationHdl, weld::MetricSpinButton&, rMetricField, void) +{ + OUString aCID = getCID(mxModel); + double nVal = rMetricField.get_value(FieldUnit::DEGREE); + setAxisRotation(mxModel, aCID, nVal); +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartAxisPanel.hxx b/chart2/source/controller/sidebar/ChartAxisPanel.hxx new file mode 100644 index 000000000..32f3c0b33 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartAxisPanel.hxx @@ -0,0 +1,93 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <sfx2/sidebar/ControllerItem.hxx> +#include <sfx2/sidebar/IContextChangeReceiver.hxx> +#include <sfx2/sidebar/SidebarModelUpdate.hxx> +#include <sfx2/sidebar/PanelLayout.hxx> +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" + +namespace com::sun::star::util { class XModifyListener; } +namespace com::sun::star::view { class XSelectionChangeListener; } + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartAxisPanel : public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static std::unique_ptr<PanelLayout> Create( + weld::Widget* pParent, + ChartController* pController); + + virtual void DataChanged( + const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange( + const vcl::EnumContext& rContext) override; + + virtual void NotifyItemUpdate( + const sal_uInt16 nSId, + const SfxItemState eState, + const SfxPoolItem* pState) override; + + virtual void GetControlState( + const sal_uInt16 /*nSId*/, + boost::property_tree::ptree& /*rState*/) override {}; + + // constructor/destructor + ChartAxisPanel( + weld::Widget* pParent, + ChartController* pController); + virtual ~ChartAxisPanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void selectionChanged(bool bCorrectType) override; + + virtual void updateModel(css::uno::Reference<css::frame::XModel> xModel) override; + +private: + //ui controls + std::unique_ptr<weld::CheckButton> mxCBShowLabel; + std::unique_ptr<weld::CheckButton> mxCBReverse; + std::unique_ptr<weld::ComboBox> mxLBLabelPos; + std::unique_ptr<weld::Widget> mxGridLabel; + std::unique_ptr<weld::MetricSpinButton> mxNFRotation; + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference<css::util::XModifyListener> mxModifyListener; + css::uno::Reference<css::view::XSelectionChangeListener> mxSelectionListener; + + bool mbModelValid; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + DECL_LINK(CheckBoxHdl, weld::Toggleable&, void); + DECL_LINK(ListBoxHdl, weld::ComboBox&, void); + DECL_LINK(TextRotationHdl, weld::MetricSpinButton&, void); +}; + +} } // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartColorWrapper.cxx b/chart2/source/controller/sidebar/ChartColorWrapper.cxx new file mode 100644 index 000000000..47df22d6e --- /dev/null +++ b/chart2/source/controller/sidebar/ChartColorWrapper.cxx @@ -0,0 +1,233 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include "ChartColorWrapper.hxx" +#include <ChartModel.hxx> + +#include <ObjectIdentifier.hxx> +#include <PropertyHelper.hxx> +#include <com/sun/star/chart2/XDiagram.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/frame/XController.hpp> + +#include <svx/linectrl.hxx> +#include <svx/tbcontrl.hxx> +#include <svx/xlndsit.hxx> +#include <svx/unomid.hxx> + +#include <comphelper/lok.hxx> +#include <sal/log.hxx> +#include <sfx2/viewsh.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> + +namespace chart::sidebar { + +namespace { + +OUString getCID(const css::uno::Reference<css::frame::XModel>& xModel) +{ + css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController()); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + css::uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + return OUString(); + + OUString aCID; + aAny >>= aCID; + + return aCID; +} + +css::uno::Reference<css::beans::XPropertySet> getPropSet( + const rtl::Reference<::chart::ChartModel>& xModel) +{ + OUString aCID = getCID(xModel); + css::uno::Reference<css::beans::XPropertySet> xPropSet = + ObjectIdentifier::getObjectPropertySet(aCID, xModel); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference<css::chart2::XDiagram> xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (!xDiagram.is()) + return xPropSet; + + xPropSet.set(xDiagram->getWall()); + } + + return xPropSet; +} + +} + +ChartColorWrapper::ChartColorWrapper( + rtl::Reference<::chart::ChartModel> const & xModel, + SvxColorToolBoxControl* pControl, + const OUString& rName): + mxModel(xModel), + mpControl(pControl), + maPropertyName(rName) +{ +} + +void ChartColorWrapper::operator()([[maybe_unused]] const OUString& , const svx::NamedThemedColor& rColor) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + + if (!xPropSet.is()) + { + SAL_WARN("chart2", "Invalid reference to xPropSet"); + return; + } + + xPropSet->setPropertyValue(maPropertyName, css::uno::Any(rColor.m_aColor)); +} + +void ChartColorWrapper::updateModel(const rtl::Reference<::chart::ChartModel>& xModel) +{ + mxModel = xModel; +} + +void ChartColorWrapper::updateData() +{ + static constexpr OUStringLiteral aLineColor = u"LineColor"; + static const std::u16string_view aCommands[2] = {u".uno:XLineColor", u".uno:FillColor"}; + + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + css::util::URL aUrl; + aUrl.Complete = (maPropertyName == aLineColor) ? aCommands[0] : aCommands[1]; + + css::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aUrl; + aEvent.IsEnabled = true; + aEvent.State = xPropSet->getPropertyValue(maPropertyName); + mpControl->statusChanged(aEvent); + + SfxViewShell* pViewShell = SfxViewShell::Current(); + if (comphelper::LibreOfficeKit::isActive() && pViewShell && (maPropertyName == aLineColor)) + { + std::string sCommand = OUStringToOString(aUrl.Complete, RTL_TEXTENCODING_ASCII_US).getStr(); + sal_Int32 nColor = -1; + aEvent.State >>= nColor; + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, + (sCommand + "=" + std::to_string(nColor)).c_str()); + } +} + +ChartLineStyleWrapper::ChartLineStyleWrapper( + rtl::Reference<::chart::ChartModel> const & xModel, + SvxLineStyleToolBoxControl* pControl) + : mxModel(xModel) + , mpControl(pControl) +{ +} + +void ChartLineStyleWrapper::updateModel(const rtl::Reference<::chart::ChartModel>& xModel) +{ + mxModel = xModel; +} + +namespace +{ + css::uno::Any getLineDash( + const css::uno::Reference<css::frame::XModel>& xModel, const OUString& rDashName) + { + css::uno::Reference<css::lang::XMultiServiceFactory> xFact(xModel, css::uno::UNO_QUERY); + css::uno::Reference<css::container::XNameAccess> xNameAccess( + xFact->createInstance("com.sun.star.drawing.DashTable"), + css::uno::UNO_QUERY ); + if(xNameAccess.is()) + { + if (!xNameAccess->hasByName(rDashName)) + return css::uno::Any(); + + return xNameAccess->getByName(rDashName); + } + + return css::uno::Any(); + } +} + +void ChartLineStyleWrapper::updateData() +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + css::util::URL aUrl; + aUrl.Complete = ".uno:XLineStyle"; + + css::frame::FeatureStateEvent aEvent; + aEvent.IsEnabled = true; + + aEvent.FeatureURL = aUrl; + aEvent.State = xPropSet->getPropertyValue("LineStyle"); + mpControl->statusChanged(aEvent); + + aUrl.Complete = ".uno:LineDash"; + + auto aLineDashName = xPropSet->getPropertyValue("LineDashName"); + OUString aDashName; + aLineDashName >>= aDashName; + css::uno::Any aLineDash = getLineDash(mxModel, aDashName); + XLineDashItem aDashItem; + aDashItem.PutValue(aLineDash, MID_LINEDASH); + + aEvent.FeatureURL = aUrl; + aDashItem.QueryValue(aEvent.State); + mpControl->statusChanged(aEvent); +} + +bool ChartLineStyleWrapper::operator()(std::u16string_view rCommand, const css::uno::Any& rValue) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + + if (!xPropSet.is()) + { + SAL_WARN("chart2", "Invalid reference to xPropSet"); + return false; + } + + if (rCommand == u".uno:XLineStyle") + { + xPropSet->setPropertyValue("LineStyle", rValue); + return true; + } + else if (rCommand == u".uno:LineDash") + { + XLineDashItem aDashItem; + aDashItem.PutValue(rValue, 0); + css::uno::Any aAny; + aDashItem.QueryValue(aAny, MID_LINEDASH); + OUString aDashName = PropertyHelper::addLineDashUniqueNameToTable(aAny, + mxModel, + ""); + xPropSet->setPropertyValue("LineDash", aAny); + xPropSet->setPropertyValue("LineDashName", css::uno::Any(aDashName)); + return true; + } + return false; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartColorWrapper.hxx b/chart2/source/controller/sidebar/ChartColorWrapper.hxx new file mode 100644 index 000000000..5237bc9c3 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartColorWrapper.hxx @@ -0,0 +1,68 @@ +/* -*- 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/. + */ + +#pragma once + +#include <ChartModel.hxx> + +#include <svx/Palette.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace chart { class ChartModel; } +class SvxColorToolBoxControl; +class SvxLineStyleToolBoxControl; + +namespace chart::sidebar { + +class ChartColorWrapper +{ +public: + ChartColorWrapper(rtl::Reference<::chart::ChartModel> const & xModel, + SvxColorToolBoxControl* pControl, + const OUString& rPropertyName); + + void operator()(const OUString& rCommand, const svx::NamedThemedColor& rColor); + // ColorSelectFunction signature + + void updateModel(const rtl::Reference<::chart::ChartModel>& xModel); + + void updateData(); + +private: + + rtl::Reference<::chart::ChartModel> mxModel; + + SvxColorToolBoxControl* mpControl; + + OUString maPropertyName; +}; + +class ChartLineStyleWrapper +{ +public: + ChartLineStyleWrapper(rtl::Reference<::chart::ChartModel> const & xModel, + SvxLineStyleToolBoxControl* pControl); + + bool operator()(std::u16string_view rCommand, const css::uno::Any& rValue); + + void updateModel(const rtl::Reference<::chart::ChartModel>& xModel); + + void updateData(); + +private: + + rtl::Reference<::chart::ChartModel> mxModel; + + SvxLineStyleToolBoxControl* mpControl; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartElementsPanel.cxx b/chart2/source/controller/sidebar/ChartElementsPanel.cxx new file mode 100644 index 000000000..75dc7ed96 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartElementsPanel.cxx @@ -0,0 +1,662 @@ +/* -*- 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 <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart/ChartLegendExpansion.hpp> + +#include <vcl/svapp.hxx> + +#include "ChartElementsPanel.hxx" +#include <ChartController.hxx> +#include <comphelper/processfactory.hxx> + +#include <Legend.hxx> +#include <LegendHelper.hxx> +#include <ChartModelHelper.hxx> +#include <AxisHelper.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ChartType.hxx> +#include <ChartTypeHelper.hxx> +#include <ChartModel.hxx> +#include <BaseCoordinateSystem.hxx> + + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +enum class GridType +{ + VERT_MAJOR, + VERT_MINOR, + HOR_MAJOR, + HOR_MINOR +}; + +enum class AxisType +{ + X_MAIN, + Y_MAIN, + Z_MAIN, + X_SECOND, + Y_SECOND +}; + +ChartModel* getChartModel(const css::uno::Reference<css::frame::XModel>& xModel) +{ + ChartModel* pModel = dynamic_cast<ChartModel*>(xModel.get()); + + return pModel; +} + +bool isLegendVisible(const css::uno::Reference<css::frame::XModel>& xModel) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return false; + + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*pModel); + if( xLegendProp.is()) + { + try + { + bool bShow = false; + if( xLegendProp->getPropertyValue( "Show") >>= bShow ) + { + return bShow; + } + } + catch(const uno::Exception &) + { + } + } + + return false; +} + +void setLegendVisible(const css::uno::Reference<css::frame::XModel>& xModel, bool bVisible) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return; + + if (bVisible) + LegendHelper::showLegend(*pModel, comphelper::getProcessComponentContext()); + else + LegendHelper::hideLegend(*pModel); +} + +bool isLegendOverlay(const css::uno::Reference<css::frame::XModel>& xModel) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return false; + + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*pModel); + if( xLegendProp.is()) + { + try + { + bool bOverlay = false; + if(xLegendProp->getPropertyValue("Overlay") >>= bOverlay) + { + return bOverlay; + } + } + catch(const uno::Exception &) + { + } + } + + return false; +} + +void setLegendOverlay(const css::uno::Reference<css::frame::XModel>& xModel, bool bOverlay) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return; + + rtl::Reference<Legend> xLegendProp = LegendHelper::getLegend(*pModel); + if (!xLegendProp.is()) + return; + + xLegendProp->setPropertyValue("Overlay", css::uno::Any(bOverlay)); +} + +bool isTitleVisible(const rtl::Reference<::chart::ChartModel>& xModel, TitleHelper::eTitleType eTitle) +{ + css::uno::Reference<css::uno::XInterface> xTitle = TitleHelper::getTitle(eTitle, xModel); + if (!xTitle.is()) + return false; + + css::uno::Reference<css::beans::XPropertySet> xPropSet(xTitle, css::uno::UNO_QUERY_THROW); + css::uno::Any aAny = xPropSet->getPropertyValue("Visible"); + bool bVisible = aAny.get<bool>(); + return bVisible; +} + +bool isGridVisible(const rtl::Reference<::chart::ChartModel>& xModel, GridType eType) +{ + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xModel)); + if(xDiagram.is()) + { + sal_Int32 nDimensionIndex = 0; + if (eType == GridType::HOR_MAJOR || eType == GridType::HOR_MINOR) + nDimensionIndex = 1; + + bool bMajor = (eType == GridType::HOR_MAJOR || eType == GridType::VERT_MAJOR); + + bool bHasGrid = AxisHelper::isGridShown(nDimensionIndex, 0, bMajor, xDiagram); + return bHasGrid; + } + return false; +} + +void setGridVisible(const rtl::Reference<::chart::ChartModel>& xModel, GridType eType, bool bVisible) +{ + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xModel)); + if(!xDiagram.is()) + return; + + sal_Int32 nDimensionIndex = 0; + if (eType == GridType::HOR_MAJOR || eType == GridType::HOR_MINOR) + nDimensionIndex = 1; + sal_Int32 nCooSysIndex = 0; + + bool bMajor = (eType == GridType::HOR_MAJOR || eType == GridType::VERT_MAJOR); + + if (bVisible) + AxisHelper::showGrid(nDimensionIndex, nCooSysIndex, bMajor, + xDiagram); + else + AxisHelper::hideGrid(nDimensionIndex, nCooSysIndex, bMajor, xDiagram); +} + +bool isAxisVisible(const rtl::Reference<::chart::ChartModel>& xModel, AxisType eType) +{ + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xModel)); + if(xDiagram.is()) + { + sal_Int32 nDimensionIndex = 0; + if (eType == AxisType::Y_MAIN || eType == AxisType::Y_SECOND) + nDimensionIndex = 1; + else if (eType == AxisType::Z_MAIN) + nDimensionIndex = 2; + + bool bMajor = (eType != AxisType::X_SECOND && eType != AxisType::Y_SECOND); + + bool bHasAxis = AxisHelper::isAxisShown(nDimensionIndex, bMajor, xDiagram); + return bHasAxis; + } + return false; +} + +void setAxisVisible(const rtl::Reference<::chart::ChartModel>& xModel, AxisType eType, bool bVisible) +{ + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xModel)); + if(!xDiagram.is()) + return; + + sal_Int32 nDimensionIndex = 0; + if (eType == AxisType::Y_MAIN || eType == AxisType::Y_SECOND) + nDimensionIndex = 1; + else if (eType == AxisType::Z_MAIN) + nDimensionIndex = 2; + + bool bMajor = (eType != AxisType::X_SECOND && eType != AxisType::Y_SECOND); + + if (bVisible) + AxisHelper::showAxis(nDimensionIndex, bMajor, xDiagram, comphelper::getProcessComponentContext()); + else + AxisHelper::hideAxis(nDimensionIndex, bMajor, xDiagram); +} + +sal_Int32 getLegendPos(const css::uno::Reference<css::frame::XModel>& xModel) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return -1; + + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*pModel); + if (!xLegendProp.is()) + return -1; + + chart2::LegendPosition eLegendPos = chart2::LegendPosition_LINE_END; + xLegendProp->getPropertyValue("AnchorPosition") >>= eLegendPos; + switch(eLegendPos) + { + case chart2::LegendPosition_LINE_START: + return 3; + case chart2::LegendPosition_LINE_END: + return 0; + case chart2::LegendPosition_PAGE_START: + return 1; + case chart2::LegendPosition_PAGE_END: + return 2; + default: + return -1; + } +} + +void setLegendPos(const css::uno::Reference<css::frame::XModel>& xModel, sal_Int32 nPos) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return; + + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*pModel); + if (!xLegendProp.is()) + return; + + chart2::LegendPosition eLegendPos = chart2::LegendPosition_LINE_END; + css::chart::ChartLegendExpansion eExpansion = css::chart::ChartLegendExpansion_HIGH; + switch(nPos) + { + case 1: + eLegendPos = chart2::LegendPosition_PAGE_START; + eExpansion = css::chart::ChartLegendExpansion_WIDE; + break; + case 3: + eLegendPos = chart2::LegendPosition_LINE_START; + break; + case 0: + eLegendPos = chart2::LegendPosition_LINE_END; + break; + case 2: + eLegendPos = chart2::LegendPosition_PAGE_END; + eExpansion = css::chart::ChartLegendExpansion_WIDE; + break; + default: + assert(false); + } + + xLegendProp->setPropertyValue("AnchorPosition", css::uno::Any(eLegendPos)); + xLegendProp->setPropertyValue("Expansion", css::uno::Any(eExpansion)); + xLegendProp->setPropertyValue("RelativePosition", uno::Any()); +} + +} + +ChartElementsPanel::ChartElementsPanel( + weld::Widget* pParent, ChartController* pController) + : PanelLayout(pParent, "ChartElementsPanel", "modules/schart/ui/sidebarelements.ui") + , mxCBTitle(m_xBuilder->weld_check_button("checkbutton_title")) + , mxEditTitle(m_xBuilder->weld_entry("edit_title")) + , mxCBSubtitle(m_xBuilder->weld_check_button("checkbutton_subtitle")) + , mxEditSubtitle(m_xBuilder->weld_entry("edit_subtitle")) + , mxCBXAxis(m_xBuilder->weld_check_button("checkbutton_x_axis")) + , mxCBXAxisTitle(m_xBuilder->weld_check_button("checkbutton_x_axis_title")) + , mxCBYAxis(m_xBuilder->weld_check_button("checkbutton_y_axis")) + , mxCBYAxisTitle(m_xBuilder->weld_check_button("checkbutton_y_axis_title")) + , mxCBZAxis(m_xBuilder->weld_check_button("checkbutton_z_axis")) + , mxCBZAxisTitle(m_xBuilder->weld_check_button("checkbutton_z_axis_title")) + , mxCB2ndXAxis(m_xBuilder->weld_check_button("checkbutton_2nd_x_axis")) + , mxCB2ndXAxisTitle(m_xBuilder->weld_check_button("checkbutton_2nd_x_axis_title")) + , mxCB2ndYAxis(m_xBuilder->weld_check_button("checkbutton_2nd_y_axis")) + , mxCB2ndYAxisTitle(m_xBuilder->weld_check_button("checkbutton_2nd_y_axis_title")) + , mxCBLegend(m_xBuilder->weld_check_button("checkbutton_legend")) + , mxCBLegendNoOverlay(m_xBuilder->weld_check_button("checkbutton_no_overlay")) + , mxCBGridVerticalMajor(m_xBuilder->weld_check_button("checkbutton_gridline_vertical_major")) + , mxCBGridHorizontalMajor(m_xBuilder->weld_check_button("checkbutton_gridline_horizontal_major")) + , mxCBGridVerticalMinor(m_xBuilder->weld_check_button("checkbutton_gridline_vertical_minor")) + , mxCBGridHorizontalMinor(m_xBuilder->weld_check_button("checkbutton_gridline_horizontal_minor")) + , mxTextTitle(m_xBuilder->weld_label("text_title")) + , mxTextSubTitle(m_xBuilder->weld_label("text_subtitle")) + , mxLBAxis(m_xBuilder->weld_label("label_axes")) + , mxLBGrid(m_xBuilder->weld_label("label_gri")) + , mxLBLegendPosition(m_xBuilder->weld_combo_box("comboboxtext_legend")) + , mxBoxLegend(m_xBuilder->weld_widget("box_legend")) + , mxModel(pController->getChartModel()) + , mxListener(new ChartSidebarModifyListener(this)) + , mbModelValid(true) +{ + maTextTitle = mxTextTitle->get_label(); + maTextSubTitle = mxTextSubTitle->get_label(); + + Initialize(); +} + +ChartElementsPanel::~ChartElementsPanel() +{ + doUpdateModel(nullptr); + + mxCBTitle.reset(); + mxEditTitle.reset(); + mxCBSubtitle.reset(); + mxEditSubtitle.reset(); + mxCBXAxis.reset(); + mxCBXAxisTitle.reset(); + mxCBYAxis.reset(); + mxCBYAxisTitle.reset(); + mxCBZAxis.reset(); + mxCBZAxisTitle.reset(); + mxCB2ndXAxis.reset(); + mxCB2ndXAxisTitle.reset(); + mxCB2ndYAxis.reset(); + mxCB2ndYAxisTitle.reset(); + mxCBLegend.reset(); + mxCBLegendNoOverlay.reset(); + mxCBGridVerticalMajor.reset(); + mxCBGridHorizontalMajor.reset(); + mxCBGridVerticalMinor.reset(); + mxCBGridHorizontalMinor.reset(); + + mxLBLegendPosition.reset(); + mxBoxLegend.reset(); + + mxLBAxis.reset(); + mxLBGrid.reset(); + + mxTextTitle.reset(); + mxTextSubTitle.reset(); +} + +void ChartElementsPanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + updateData(); + + Link<weld::Toggleable&,void> aLink = LINK(this, ChartElementsPanel, CheckBoxHdl); + mxCBTitle->connect_toggled(aLink); + mxCBSubtitle->connect_toggled(aLink); + mxCBXAxis->connect_toggled(aLink); + mxCBXAxisTitle->connect_toggled(aLink); + mxCBYAxis->connect_toggled(aLink); + mxCBYAxisTitle->connect_toggled(aLink); + mxCBZAxis->connect_toggled(aLink); + mxCBZAxisTitle->connect_toggled(aLink); + mxCB2ndXAxis->connect_toggled(aLink); + mxCB2ndXAxisTitle->connect_toggled(aLink); + mxCB2ndYAxis->connect_toggled(aLink); + mxCB2ndYAxisTitle->connect_toggled(aLink); + mxCBLegend->connect_toggled(aLink); + mxCBLegendNoOverlay->connect_toggled(aLink); + mxCBGridVerticalMajor->connect_toggled(aLink); + mxCBGridHorizontalMajor->connect_toggled(aLink); + mxCBGridVerticalMinor->connect_toggled(aLink); + mxCBGridHorizontalMinor->connect_toggled(aLink); + + mxLBLegendPosition->connect_changed(LINK(this, ChartElementsPanel, LegendPosHdl)); + + Link<weld::Entry&, void> aEditLink = LINK(this, ChartElementsPanel, EditHdl); + mxEditTitle->connect_changed(aEditLink); + mxEditSubtitle->connect_changed(aEditLink); +} + +namespace { + +rtl::Reference<ChartType> getChartType(const rtl::Reference<ChartModel>& xModel) +{ + rtl::Reference<Diagram > xDiagram = xModel->getFirstChartDiagram(); + if (!xDiagram.is()) + return nullptr; + + const std::vector<rtl::Reference<BaseCoordinateSystem>> & xCooSysSequence(xDiagram->getBaseCoordinateSystems()); + + if (xCooSysSequence.empty()) + return nullptr; + + const std::vector<rtl::Reference<ChartType>> & xChartTypeSequence(xCooSysSequence[0]->getChartTypes2()); + + if (xChartTypeSequence.empty()) + return nullptr; + + return xChartTypeSequence[0]; +} + +} + +void ChartElementsPanel::updateData() +{ + if (!mbModelValid) + return; + + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(mxModel)); + sal_Int32 nDimension = DiagramHelper::getDimension(xDiagram); + SolarMutexGuard aGuard; + + mxCBLegend->set_active(isLegendVisible(mxModel)); + mxCBLegendNoOverlay->set_sensitive(isLegendVisible(mxModel)); + mxCBLegendNoOverlay->set_active(!isLegendOverlay(mxModel)); + mxBoxLegend->set_sensitive(isLegendVisible(mxModel)); + + bool hasTitle = isTitleVisible(mxModel, TitleHelper::MAIN_TITLE); + mxCBTitle->set_active(hasTitle); + + OUString title = mxEditTitle->get_text(); + OUString newTitle = TitleHelper::getCompleteString(TitleHelper::getTitle(TitleHelper::MAIN_TITLE, mxModel)); + if (title != newTitle) + mxEditTitle->set_text(newTitle); + if (mxEditTitle->get_sensitive() != hasTitle) + mxEditTitle->set_sensitive(hasTitle); + + bool hasSubtitle = isTitleVisible(mxModel, TitleHelper::SUB_TITLE); + mxCBSubtitle->set_active(hasSubtitle); + + OUString subtitle = mxEditSubtitle->get_text(); + OUString newSubtitle = TitleHelper::getCompleteString(TitleHelper::getTitle(TitleHelper::SUB_TITLE, mxModel)); + if (subtitle != newSubtitle) + mxEditSubtitle->set_text(newSubtitle); + if (mxEditSubtitle->get_sensitive() != hasSubtitle) + mxEditSubtitle->set_sensitive(hasSubtitle); + + mxCBXAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::X_AXIS_TITLE)); + mxCBYAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::Y_AXIS_TITLE)); + mxCBZAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::Z_AXIS_TITLE)); + mxCB2ndXAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::SECONDARY_X_AXIS_TITLE)); + mxCB2ndYAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::SECONDARY_Y_AXIS_TITLE)); + mxCBGridVerticalMajor->set_active(isGridVisible(mxModel, GridType::VERT_MAJOR)); + mxCBGridHorizontalMajor->set_active(isGridVisible(mxModel, GridType::HOR_MAJOR)); + mxCBGridVerticalMinor->set_active(isGridVisible(mxModel, GridType::VERT_MINOR)); + mxCBGridHorizontalMinor->set_active(isGridVisible(mxModel, GridType::HOR_MINOR)); + mxCBXAxis->set_active(isAxisVisible(mxModel, AxisType::X_MAIN)); + mxCBYAxis->set_active(isAxisVisible(mxModel, AxisType::Y_MAIN)); + mxCBZAxis->set_active(isAxisVisible(mxModel, AxisType::Z_MAIN)); + mxCB2ndXAxis->set_active(isAxisVisible(mxModel, AxisType::X_SECOND)); + mxCB2ndYAxis->set_active(isAxisVisible(mxModel, AxisType::Y_SECOND)); + + bool bSupportsMainAxis = ChartTypeHelper::isSupportingMainAxis( + getChartType(mxModel), 0, 0); + if (bSupportsMainAxis) + { + mxCBXAxis->show(); + mxCBYAxis->show(); + mxCBZAxis->show(); + mxCBXAxisTitle->show(); + mxCBYAxisTitle->show(); + mxCBZAxisTitle->show(); + mxCBGridVerticalMajor->show(); + mxCBGridVerticalMinor->show(); + mxCBGridHorizontalMajor->show(); + mxCBGridHorizontalMinor->show(); + mxLBAxis->show(); + mxLBGrid->show(); + } + else + { + mxCBXAxis->hide(); + mxCBYAxis->hide(); + mxCBZAxis->hide(); + mxCBXAxisTitle->hide(); + mxCBYAxisTitle->hide(); + mxCBZAxisTitle->hide(); + mxCBGridVerticalMajor->hide(); + mxCBGridVerticalMinor->hide(); + mxCBGridHorizontalMajor->hide(); + mxCBGridHorizontalMinor->hide(); + mxLBAxis->hide(); + mxLBGrid->hide(); + } + + if (nDimension == 3) + { + mxCBZAxis->set_sensitive(true); + mxCBZAxisTitle->set_sensitive(true); + } + else + { + mxCBZAxis->set_sensitive(false); + mxCBZAxisTitle->set_sensitive(false); + } + + mxLBLegendPosition->set_active(getLegendPos(mxModel)); +} + +std::unique_ptr<PanelLayout> ChartElementsPanel::Create ( + weld::Widget* pParent, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartElementsPanel::Create", nullptr, 0); + return std::make_unique<ChartElementsPanel>(pParent, pController); +} + +void ChartElementsPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartElementsPanel::HandleContextChange( + const vcl::EnumContext& rContext) +{ + if(maContext == rContext) + { + // Nothing to do. + return; + } + + maContext = rContext; + updateData(); +} + +void ChartElementsPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartElementsPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxListener); +} + +void ChartElementsPanel::updateModel(css::uno::Reference<css::frame::XModel> xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +IMPL_LINK(ChartElementsPanel, CheckBoxHdl, weld::Toggleable&, rCheckBox, void) +{ + bool bChecked = rCheckBox.get_active(); + if (&rCheckBox == mxCBTitle.get()) + setTitleVisible(TitleHelper::MAIN_TITLE, bChecked); + else if (&rCheckBox == mxCBSubtitle.get()) + setTitleVisible(TitleHelper::SUB_TITLE, bChecked); + else if (&rCheckBox == mxCBXAxis.get()) + setAxisVisible(mxModel, AxisType::X_MAIN, bChecked); + else if (&rCheckBox == mxCBXAxisTitle.get()) + setTitleVisible(TitleHelper::X_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCBYAxis.get()) + setAxisVisible(mxModel, AxisType::Y_MAIN, bChecked); + else if (&rCheckBox == mxCBYAxisTitle.get()) + setTitleVisible(TitleHelper::Y_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCBZAxis.get()) + setAxisVisible(mxModel, AxisType::Z_MAIN, bChecked); + else if (&rCheckBox == mxCBZAxisTitle.get()) + setTitleVisible(TitleHelper::Z_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCB2ndXAxis.get()) + setAxisVisible(mxModel, AxisType::X_SECOND, bChecked); + else if (&rCheckBox == mxCB2ndXAxisTitle.get()) + setTitleVisible(TitleHelper::SECONDARY_X_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCB2ndYAxis.get()) + setAxisVisible(mxModel, AxisType::Y_SECOND, bChecked); + else if (&rCheckBox == mxCB2ndYAxisTitle.get()) + setTitleVisible(TitleHelper::SECONDARY_Y_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCBLegend.get()) + { + mxBoxLegend->set_sensitive(bChecked); + mxCBLegendNoOverlay->set_sensitive(bChecked); + setLegendVisible(mxModel, bChecked); + } + else if (&rCheckBox == mxCBLegendNoOverlay.get()) + setLegendOverlay(mxModel, !bChecked); + else if (&rCheckBox == mxCBGridVerticalMajor.get()) + setGridVisible(mxModel, GridType::VERT_MAJOR, bChecked); + else if (&rCheckBox == mxCBGridHorizontalMajor.get()) + setGridVisible(mxModel, GridType::HOR_MAJOR, bChecked); + else if (&rCheckBox == mxCBGridVerticalMinor.get()) + setGridVisible(mxModel, GridType::VERT_MINOR, bChecked); + else if (&rCheckBox == mxCBGridHorizontalMinor.get()) + setGridVisible(mxModel, GridType::HOR_MINOR, bChecked); + + updateData(); +} + +IMPL_LINK(ChartElementsPanel, EditHdl, weld::Entry&, rEdit, void) +{ + // title or subtitle? + TitleHelper::eTitleType aTitleType = TitleHelper::MAIN_TITLE; + if (&rEdit == mxEditSubtitle.get()) + aTitleType = TitleHelper::SUB_TITLE; + + // set it + OUString aText(rEdit.get_text()); + TitleHelper::setCompleteString(aText, TitleHelper::getTitle(aTitleType, mxModel), comphelper::getProcessComponentContext()); +} + +IMPL_LINK_NOARG(ChartElementsPanel, LegendPosHdl, weld::ComboBox&, void) +{ + sal_Int32 nPos = mxLBLegendPosition->get_active(); + setLegendPos(mxModel, nPos); +} + +void ChartElementsPanel::setTitleVisible(TitleHelper::eTitleType eTitle, bool bVisible) +{ + if (bVisible) + { + OUString aText = eTitle == TitleHelper::SUB_TITLE ? maTextSubTitle : maTextTitle; + TitleHelper::createOrShowTitle(eTitle, aText, mxModel, comphelper::getProcessComponentContext()); + } + else + { + TitleHelper::hideTitle(eTitle, mxModel); + } +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartElementsPanel.hxx b/chart2/source/controller/sidebar/ChartElementsPanel.hxx new file mode 100644 index 000000000..07c7ee19c --- /dev/null +++ b/chart2/source/controller/sidebar/ChartElementsPanel.hxx @@ -0,0 +1,116 @@ +/* -*- 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 <sfx2/sidebar/IContextChangeReceiver.hxx> +#include <sfx2/sidebar/SidebarModelUpdate.hxx> +#include <sfx2/sidebar/PanelLayout.hxx> +#include <vcl/EnumContext.hxx> +#include "ChartSidebarModifyListener.hxx" +#include <TitleHelper.hxx> + +namespace com::sun::star::util { class XModifyListener; } + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartElementsPanel : public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent +{ +public: + static std::unique_ptr<PanelLayout> Create( + weld::Widget* pParent, + ChartController* pController); + + virtual void DataChanged( + const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange( + const vcl::EnumContext& rContext) override; + + // constructor/destructor + ChartElementsPanel( + weld::Widget* pParent, + ChartController* pController); + + virtual ~ChartElementsPanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void updateModel(css::uno::Reference<css::frame::XModel> xModel) override; + +private: + //ui controls + std::unique_ptr<weld::CheckButton> mxCBTitle; + std::unique_ptr<weld::Entry> mxEditTitle; + std::unique_ptr<weld::CheckButton> mxCBSubtitle; + std::unique_ptr<weld::Entry> mxEditSubtitle; + std::unique_ptr<weld::CheckButton> mxCBXAxis; + std::unique_ptr<weld::CheckButton> mxCBXAxisTitle; + std::unique_ptr<weld::CheckButton> mxCBYAxis; + std::unique_ptr<weld::CheckButton> mxCBYAxisTitle; + std::unique_ptr<weld::CheckButton> mxCBZAxis; + std::unique_ptr<weld::CheckButton> mxCBZAxisTitle; + std::unique_ptr<weld::CheckButton> mxCB2ndXAxis; + std::unique_ptr<weld::CheckButton> mxCB2ndXAxisTitle; + std::unique_ptr<weld::CheckButton> mxCB2ndYAxis; + std::unique_ptr<weld::CheckButton> mxCB2ndYAxisTitle; + std::unique_ptr<weld::CheckButton> mxCBLegend; + std::unique_ptr<weld::CheckButton> mxCBLegendNoOverlay; + std::unique_ptr<weld::CheckButton> mxCBGridVerticalMajor; + std::unique_ptr<weld::CheckButton> mxCBGridHorizontalMajor; + std::unique_ptr<weld::CheckButton> mxCBGridVerticalMinor; + std::unique_ptr<weld::CheckButton> mxCBGridHorizontalMinor; + std::unique_ptr<weld::Label> mxTextTitle; + std::unique_ptr<weld::Label> mxTextSubTitle; + std::unique_ptr<weld::Label> mxLBAxis; + std::unique_ptr<weld::Label> mxLBGrid; + + std::unique_ptr<weld::ComboBox> mxLBLegendPosition; + std::unique_ptr<weld::Widget> mxBoxLegend; + + vcl::EnumContext maContext; + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference<css::util::XModifyListener> mxListener; + + bool mbModelValid; + + OUString maTextTitle; + OUString maTextSubTitle; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + void setTitleVisible(TitleHelper::eTitleType eTitle, bool bVisible); + + DECL_LINK(CheckBoxHdl, weld::Toggleable&, void); + DECL_LINK(EditHdl, weld::Entry&, void); + DECL_LINK(LegendPosHdl, weld::ComboBox&, void); +}; + +} } // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartErrorBarPanel.cxx b/chart2/source/controller/sidebar/ChartErrorBarPanel.cxx new file mode 100644 index 000000000..e86fdf0fe --- /dev/null +++ b/chart2/source/controller/sidebar/ChartErrorBarPanel.cxx @@ -0,0 +1,425 @@ +/* -*- 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 <com/sun/star/chart/ErrorBarStyle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include "ChartErrorBarPanel.hxx" +#include <ChartController.hxx> +#include <ChartModel.hxx> +#include <vcl/svapp.hxx> +#include <sal/log.hxx> + + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +enum class ErrorBarDirection +{ + POSITIVE, + NEGATIVE +}; + +css::uno::Reference<css::beans::XPropertySet> getErrorBarPropSet( + const rtl::Reference<::chart::ChartModel>& xModel, const OUString& rCID) +{ + return ObjectIdentifier::getObjectPropertySet(rCID, xModel); +} + +bool showPositiveError(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return false; + + css::uno::Any aAny = xPropSet->getPropertyValue("ShowPositiveError"); + + if (!aAny.hasValue()) + return false; + + bool bShow = false; + aAny >>= bShow; + return bShow; +} + +bool showNegativeError(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return false; + + css::uno::Any aAny = xPropSet->getPropertyValue("ShowNegativeError"); + + if (!aAny.hasValue()) + return false; + + bool bShow = false; + aAny >>= bShow; + return bShow; +} + +void setShowPositiveError(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bShow) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return; + + xPropSet->setPropertyValue("ShowPositiveError", css::uno::Any(bShow)); +} + +void setShowNegativeError(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bShow) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return; + + xPropSet->setPropertyValue("ShowNegativeError", css::uno::Any(bShow)); +} + +struct ErrorBarTypeMap +{ + sal_Int32 nPos; + sal_Int32 nApi; +}; + +ErrorBarTypeMap const aErrorBarType[] = { + { 0, css::chart::ErrorBarStyle::ABSOLUTE }, + { 1, css::chart::ErrorBarStyle::RELATIVE }, + { 2, css::chart::ErrorBarStyle::FROM_DATA }, + { 3, css::chart::ErrorBarStyle::STANDARD_DEVIATION }, + { 4, css::chart::ErrorBarStyle::STANDARD_ERROR }, + { 5, css::chart::ErrorBarStyle::VARIANCE}, + { 6, css::chart::ErrorBarStyle::ERROR_MARGIN }, +}; + +sal_Int32 getTypePos(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return 0; + + css::uno::Any aAny = xPropSet->getPropertyValue("ErrorBarStyle"); + + if (!aAny.hasValue()) + return 0; + + sal_Int32 nApi = 0; + aAny >>= nApi; + + for (ErrorBarTypeMap const & i : aErrorBarType) + { + if (i.nApi == nApi) + return i.nPos; + } + + return 0; +} + +void setTypePos(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, sal_Int32 nPos) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return; + + sal_Int32 nApi = 0; + for (ErrorBarTypeMap const & i : aErrorBarType) + { + if (i.nPos == nPos) + nApi = i.nApi; + } + + xPropSet->setPropertyValue("ErrorBarStyle", css::uno::Any(nApi)); +} + +double getValue(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, ErrorBarDirection eDir) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return 0; + + OUString aName = "PositiveError"; + if (eDir == ErrorBarDirection::NEGATIVE) + aName = "NegativeError"; + + css::uno::Any aAny = xPropSet->getPropertyValue(aName); + + if (!aAny.hasValue()) + return 0; + + double nVal = 0; + aAny >>= nVal; + + return nVal; +} + +void setValue(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, double nVal, ErrorBarDirection eDir) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return; + + OUString aName = "PositiveError"; + if (eDir == ErrorBarDirection::NEGATIVE) + aName = "NegativeError"; + + xPropSet->setPropertyValue(aName, css::uno::Any(nVal)); +} + +OUString getCID(const rtl::Reference<::chart::ChartModel>& xModel) +{ + css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController()); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + uno::Any aAny = xSelectionSupplier->getSelection(); + assert(aAny.hasValue()); + OUString aCID; + aAny >>= aCID; +#if defined DBG_UTIL && !defined NDEBUG + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType != OBJECTTYPE_DATA_ERRORS_X && + eType != OBJECTTYPE_DATA_ERRORS_Y && + eType != OBJECTTYPE_DATA_ERRORS_Z) + SAL_WARN("chart2","Selected item is not an error bar"); + +#endif + + return aCID; +} + +} + +ChartErrorBarPanel::ChartErrorBarPanel(weld::Widget* pParent, ChartController* pController) + : PanelLayout(pParent, "ChartErrorBarPanel", "modules/schart/ui/sidebarerrorbar.ui") + , mxRBPosAndNeg(m_xBuilder->weld_radio_button("radiobutton_positive_negative")) + , mxRBPos(m_xBuilder->weld_radio_button("radiobutton_positive")) + , mxRBNeg(m_xBuilder->weld_radio_button("radiobutton_negative")) + , mxLBType(m_xBuilder->weld_combo_box("comboboxtext_type")) + , mxMFPos(m_xBuilder->weld_spin_button("spinbutton_pos")) + , mxMFNeg(m_xBuilder->weld_spin_button("spinbutton_neg")) + , mxModel(pController->getChartModel()) + , mxListener(new ChartSidebarModifyListener(this)) + , mbModelValid(true) +{ + Initialize(); +} + +ChartErrorBarPanel::~ChartErrorBarPanel() +{ + doUpdateModel(nullptr); + + mxRBPosAndNeg.reset(); + mxRBPos.reset(); + mxRBNeg.reset(); + + mxLBType.reset(); + + mxMFPos.reset(); + mxMFNeg.reset(); +} + +void ChartErrorBarPanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + mxRBNeg->set_active(false); + mxRBPos->set_active(false); + mxRBPosAndNeg->set_active(false); + + updateData(); + + Link<weld::Toggleable&,void> aLink = LINK(this, ChartErrorBarPanel, RadioBtnHdl); + mxRBPosAndNeg->connect_toggled(aLink); + mxRBPos->connect_toggled(aLink); + mxRBNeg->connect_toggled(aLink); + + mxLBType->connect_changed(LINK(this, ChartErrorBarPanel, ListBoxHdl)); + + Link<weld::SpinButton&,void> aLink2 = LINK(this, ChartErrorBarPanel, NumericFieldHdl); + mxMFPos->connect_value_changed(aLink2); + mxMFNeg->connect_value_changed(aLink2); +} + +void ChartErrorBarPanel::updateData() +{ + if (!mbModelValid) + return; + + OUString aCID = getCID(mxModel); + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType != OBJECTTYPE_DATA_ERRORS_X && + eType != OBJECTTYPE_DATA_ERRORS_Y && + eType != OBJECTTYPE_DATA_ERRORS_Z) + return; + + bool bPos = showPositiveError(mxModel, aCID); + bool bNeg = showNegativeError(mxModel, aCID); + + SolarMutexGuard aGuard; + + if (bPos && bNeg) + mxRBPosAndNeg->set_active(true); + else if (bPos) + mxRBPos->set_active(true); + else if (bNeg) + mxRBNeg->set_active(true); + + sal_Int32 nTypePos = getTypePos(mxModel, aCID); + mxLBType->set_active(nTypePos); + + if (nTypePos <= 1) + { + if (bPos) + mxMFPos->set_sensitive(true); + else + mxMFPos->set_sensitive(false); + + if (bNeg) + mxMFNeg->set_sensitive(true); + else + mxMFNeg->set_sensitive(false); + + double nValPos = getValue(mxModel, aCID, ErrorBarDirection::POSITIVE); + double nValNeg = getValue(mxModel, aCID, ErrorBarDirection::NEGATIVE); + + mxMFPos->set_value(nValPos); + mxMFNeg->set_value(nValNeg); + } + else + { + mxMFPos->set_sensitive(false); + mxMFNeg->set_sensitive(false); + } +} + +std::unique_ptr<PanelLayout> ChartErrorBarPanel::Create ( + weld::Widget* pParent, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartErrorBarPanel::Create", nullptr, 0); + return std::make_unique<ChartErrorBarPanel>(pParent, pController); +} + +void ChartErrorBarPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartErrorBarPanel::HandleContextChange( + const vcl::EnumContext& ) +{ + updateData(); +} + +void ChartErrorBarPanel::NotifyItemUpdate( + sal_uInt16 /*nSID*/, + SfxItemState /*eState*/, + const SfxPoolItem* /*pState*/ ) +{ +} + +void ChartErrorBarPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartErrorBarPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxListener); +} + +void ChartErrorBarPanel::updateModel(css::uno::Reference<css::frame::XModel> xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +IMPL_LINK_NOARG(ChartErrorBarPanel, RadioBtnHdl, weld::Toggleable&, void) +{ + OUString aCID = getCID(mxModel); + bool bPos = mxRBPosAndNeg->get_active() || mxRBPos->get_active(); + bool bNeg = mxRBPosAndNeg->get_active() || mxRBNeg->get_active(); + + setShowPositiveError(mxModel, aCID, bPos); + setShowNegativeError(mxModel, aCID, bNeg); +} + +IMPL_LINK_NOARG(ChartErrorBarPanel, ListBoxHdl, weld::ComboBox&, void) +{ + OUString aCID = getCID(mxModel); + sal_Int32 nPos = mxLBType->get_active(); + + setTypePos(mxModel, aCID, nPos); +} + +IMPL_LINK(ChartErrorBarPanel, NumericFieldHdl, weld::SpinButton&, rMetricField, void) +{ + OUString aCID = getCID(mxModel); + double nVal = rMetricField.get_value(); + if (&rMetricField == mxMFPos.get()) + setValue(mxModel, aCID, nVal, ErrorBarDirection::POSITIVE); + else if (&rMetricField == mxMFNeg.get()) + setValue(mxModel, aCID, nVal, ErrorBarDirection::NEGATIVE); +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartErrorBarPanel.hxx b/chart2/source/controller/sidebar/ChartErrorBarPanel.hxx new file mode 100644 index 000000000..1613006b7 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartErrorBarPanel.hxx @@ -0,0 +1,91 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <sfx2/sidebar/ControllerItem.hxx> +#include <sfx2/sidebar/IContextChangeReceiver.hxx> +#include <sfx2/sidebar/SidebarModelUpdate.hxx> +#include <sfx2/sidebar/PanelLayout.hxx> +#include "ChartSidebarModifyListener.hxx" + +namespace com::sun::star::util { class XModifyListener; } + +namespace chart { + +class ChartController; +class ChartModel; + +namespace sidebar { + +class ChartErrorBarPanel : public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent +{ +public: + static std::unique_ptr<PanelLayout> Create( + weld::Widget* pParent, + ChartController* pController); + + virtual void DataChanged( + const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange( + const vcl::EnumContext& rContext) override; + + virtual void NotifyItemUpdate( + const sal_uInt16 nSId, + const SfxItemState eState, + const SfxPoolItem* pState) override; + + virtual void GetControlState( + const sal_uInt16 /*nSId*/, + boost::property_tree::ptree& /*rState*/) override {}; + + // constructor/destructor + ChartErrorBarPanel( + weld::Widget* pParent, + ChartController* pController); + virtual ~ChartErrorBarPanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void updateModel(css::uno::Reference<css::frame::XModel> xModel) override; + +private: + //ui controls + std::unique_ptr<weld::RadioButton> mxRBPosAndNeg; + std::unique_ptr<weld::RadioButton> mxRBPos; + std::unique_ptr<weld::RadioButton> mxRBNeg; + + std::unique_ptr<weld::ComboBox> mxLBType; + + std::unique_ptr<weld::SpinButton> mxMFPos; + std::unique_ptr<weld::SpinButton> mxMFNeg; + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference<css::util::XModifyListener> mxListener; + + bool mbModelValid; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + DECL_LINK(RadioBtnHdl, weld::Toggleable&, void); + DECL_LINK(ListBoxHdl, weld::ComboBox&, void); + DECL_LINK(NumericFieldHdl, weld::SpinButton&, void); +}; + +} } // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartLinePanel.cxx b/chart2/source/controller/sidebar/ChartLinePanel.cxx new file mode 100644 index 000000000..d9da9a298 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartLinePanel.cxx @@ -0,0 +1,293 @@ +/* -*- 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 "ChartLinePanel.hxx" + +#include <ChartController.hxx> +#include <ChartModel.hxx> + +#include <svx/xlnwtit.hxx> +#include <svx/xlinjoit.hxx> +#include <svx/xlntrit.hxx> + +#include <svx/linectrl.hxx> +#include <svx/tbcontrl.hxx> +#include <sfx2/weldutils.hxx> +#include <vcl/svapp.hxx> + +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/chart2/XDiagram.hpp> + +#include <comphelper/lok.hxx> +#include <sfx2/viewsh.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> + +namespace chart::sidebar { + +namespace { + +SvxLineStyleToolBoxControl* getLineStyleToolBoxControl(const ToolbarUnoDispatcher& rToolBoxColor) +{ + css::uno::Reference<css::frame::XToolbarController> xController = rToolBoxColor.GetControllerForCommand(".uno:XLineStyle"); + SvxLineStyleToolBoxControl* pToolBoxLineStyleControl = dynamic_cast<SvxLineStyleToolBoxControl*>(xController.get()); + return pToolBoxLineStyleControl; +} + +SvxColorToolBoxControl* getColorToolBoxControl(const ToolbarUnoDispatcher& rToolBoxLineStyle) +{ + css::uno::Reference<css::frame::XToolbarController> xController = rToolBoxLineStyle.GetControllerForCommand(".uno:XLineColor"); + SvxColorToolBoxControl* pToolBoxColorControl = dynamic_cast<SvxColorToolBoxControl*>(xController.get()); + return pToolBoxColorControl; +} + +OUString getCID(const rtl::Reference<::chart::ChartModel>& xModel) +{ + css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController()); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + css::uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + { + xSelectionSupplier->select(css::uno::Any(OUString("CID/Page="))); + aAny = xSelectionSupplier->getSelection(); + } + + OUString aCID; + aAny >>= aCID; + + return aCID; +} + +css::uno::Reference<css::beans::XPropertySet> getPropSet( + const rtl::Reference<::chart::ChartModel>& xModel) +{ + OUString aCID = getCID(xModel); + css::uno::Reference<css::beans::XPropertySet> xPropSet = + ObjectIdentifier::getObjectPropertySet(aCID, xModel); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference<css::chart2::XDiagram> xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (!xDiagram.is()) + return xPropSet; + + xPropSet.set(xDiagram->getWall()); + } + + return xPropSet; +} + +class PreventUpdate +{ +public: + explicit PreventUpdate(bool& bUpdate): + mbUpdate(bUpdate) + { + mbUpdate = false; + } + + ~PreventUpdate() + { + mbUpdate = true; + } + +private: + bool& mbUpdate; +}; + +} + +std::unique_ptr<PanelLayout> ChartLinePanel::Create( + weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController) +{ + if (pParent == nullptr) + throw css::lang::IllegalArgumentException("no parent Window given to ChartAxisPanel::Create", nullptr, 0); + if (!rxFrame.is()) + throw css::lang::IllegalArgumentException("no XFrame given to ChartAxisPanel::Create", nullptr, 1); + + return std::make_unique<ChartLinePanel>(pParent, rxFrame, pController); +} + +ChartLinePanel::ChartLinePanel(weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController): + svx::sidebar::LinePropertyPanelBase(pParent, rxFrame), + mxModel(pController->getChartModel()), + mxListener(new ChartSidebarModifyListener(this)), + mxSelectionListener(new ChartSidebarSelectionListener(this)), + mbUpdate(true), + mbModelValid(true), + maLineColorWrapper(mxModel, getColorToolBoxControl(*mxColorDispatch), "LineColor"), + maLineStyleWrapper(mxModel, getLineStyleToolBoxControl(*mxLineStyleDispatch)) +{ + disableArrowHead(); + std::vector<ObjectType> aAcceptedTypes { OBJECTTYPE_PAGE, OBJECTTYPE_DIAGRAM, + OBJECTTYPE_DATA_SERIES, OBJECTTYPE_DATA_POINT, + OBJECTTYPE_TITLE, OBJECTTYPE_LEGEND, OBJECTTYPE_DATA_CURVE, + OBJECTTYPE_DATA_AVERAGE_LINE, OBJECTTYPE_AXIS}; + mxSelectionListener->setAcceptedTypes(std::move(aAcceptedTypes)); + Initialize(); +} + +ChartLinePanel::~ChartLinePanel() +{ + doUpdateModel(nullptr); +} + +void ChartLinePanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + SvxColorToolBoxControl* pToolBoxColor = getColorToolBoxControl(*mxColorDispatch); + pToolBoxColor->setColorSelectFunction(maLineColorWrapper); + + SvxLineStyleToolBoxControl* pToolBoxLineStyle = getLineStyleToolBoxControl(*mxLineStyleDispatch); + pToolBoxLineStyle->setLineStyleSelectFunction(maLineStyleWrapper); + + setMapUnit(MapUnit::Map100thMM); + updateData(); +} + +void ChartLinePanel::updateData() +{ + if (!mbUpdate || !mbModelValid) + return; + + SolarMutexGuard aGuard; + css::uno::Reference<css::beans::XPropertySet> xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + sal_uInt16 nLineTransparence = 0; + xPropSet->getPropertyValue("LineTransparence") >>= nLineTransparence; + XLineTransparenceItem aLineTransparenceItem(nLineTransparence); + updateLineTransparence(false, true, &aLineTransparenceItem); + + sal_uInt32 nWidth = 0; + xPropSet->getPropertyValue("LineWidth") >>= nWidth; + XLineWidthItem aWidthItem(nWidth); + updateLineWidth(false, true, &aWidthItem); + + maLineStyleWrapper.updateData(); + maLineColorWrapper.updateData(); +} + +void ChartLinePanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartLinePanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +void ChartLinePanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + + css::uno::Reference<css::view::XSelectionSupplier> oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + maLineStyleWrapper.updateModel(mxModel); + maLineColorWrapper.updateModel(mxModel); + + mxModel->addModifyListener(mxListener); + + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartLinePanel::updateModel(css::uno::Reference<css::frame::XModel> xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +void ChartLinePanel::setLineJoint(const XLineJointItem* pItem) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getPropSet(mxModel); + + if (!xPropSet.is()) + return; + + PreventUpdate aPreventUpdate(mbUpdate); + if (pItem) + xPropSet->setPropertyValue("LineJoint", css::uno::Any(pItem->GetValue())); +} + +void ChartLinePanel::setLineCap(const XLineCapItem* /*pItem*/) +{ +} + +void ChartLinePanel::setLineTransparency(const XLineTransparenceItem& rItem) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getPropSet(mxModel); + + if (!xPropSet.is()) + return; + + PreventUpdate aPreventUpdate(mbUpdate); + xPropSet->setPropertyValue("LineTransparence", css::uno::Any(rItem.GetValue())); +} + +void ChartLinePanel::setLineWidth(const XLineWidthItem& rItem) +{ + css::uno::Reference<css::beans::XPropertySet> xPropSet = + getPropSet(mxModel); + + if (!xPropSet.is()) + return; + + PreventUpdate aPreventUpdate(mbUpdate); + xPropSet->setPropertyValue("LineWidth", css::uno::Any(rItem.GetValue())); +} + +void ChartLinePanel::updateLineWidth(bool bDisabled, bool bSetOrDefault, const SfxPoolItem* pItem) +{ + LinePropertyPanelBase::updateLineWidth(bDisabled, bSetOrDefault, pItem); + + SfxViewShell* pViewShell = SfxViewShell::Current(); + if (comphelper::LibreOfficeKit::isActive() && pViewShell) + { + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, + (".uno:LineWidth=" + std::to_string(mnWidthCoreValue)).c_str()); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartLinePanel.hxx b/chart2/source/controller/sidebar/ChartLinePanel.hxx new file mode 100644 index 000000000..10bfd5a4c --- /dev/null +++ b/chart2/source/controller/sidebar/ChartLinePanel.hxx @@ -0,0 +1,87 @@ +/* -*- 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/. + */ + +#pragma once + +#include <sfx2/sidebar/SidebarModelUpdate.hxx> +#include <svx/sidebar/LinePropertyPanelBase.hxx> + +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" +#include "ChartColorWrapper.hxx" + +class XLineCapItem; +class XLineDashItem; +class XLineEndItem; +class XLineJointItem; +class XLineStartItem; +class XLineStyleItem; +class XLineTransparenceItem; +class XLineWidthItem; + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartLinePanel : public svx::sidebar::LinePropertyPanelBase, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static std::unique_ptr<PanelLayout> Create( + weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController); + + // constructor/destructor + ChartLinePanel( + weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController); + + virtual ~ChartLinePanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void selectionChanged(bool bCorrectType) override; + + virtual void updateModel(css::uno::Reference<css::frame::XModel> xModel) override; + + virtual void setLineWidth(const XLineWidthItem& rItem) override; + +protected: + + virtual void setLineTransparency(const XLineTransparenceItem& rItem) override; + virtual void setLineJoint(const XLineJointItem* pItem) override; + virtual void setLineCap(const XLineCapItem* pItem) override; + + virtual void updateLineWidth(bool bDisabled, bool bSetOrDefault, const SfxPoolItem* pItem) override; + +private: + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference<css::util::XModifyListener> mxListener; + rtl::Reference<ChartSidebarSelectionListener> mxSelectionListener; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + bool mbUpdate; + bool mbModelValid; + ChartColorWrapper maLineColorWrapper; + ChartLineStyleWrapper maLineStyleWrapper; +}; + +} } // end of namespace svx::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSeriesPanel.cxx b/chart2/source/controller/sidebar/ChartSeriesPanel.cxx new file mode 100644 index 000000000..c5b21ed5a --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSeriesPanel.cxx @@ -0,0 +1,474 @@ +/* -*- 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 <com/sun/star/chart/ErrorBarStyle.hpp> +#include <com/sun/star/chart/DataLabelPlacement.hpp> + +#include <vcl/svapp.hxx> +#include <sal/log.hxx> + +#include "ChartSeriesPanel.hxx" +#include <ChartController.hxx> +#include <ChartModel.hxx> +#include <ChartType.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <RegressionCurveHelper.hxx> +#include <RegressionCurveModel.hxx> +#include <StatisticsHelper.hxx> +#include <BaseCoordinateSystem.hxx> + +#include <comphelper/processfactory.hxx> + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +bool isDataLabelVisible(const rtl::Reference<::chart::ChartModel>& xModel, const OUString& rCID) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return false; + + return DataSeriesHelper::hasDataLabelsAtSeries(xSeries); +} + +void setDataLabelVisible(const rtl::Reference<::chart::ChartModel>& xModel, const OUString& rCID, bool bVisible) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return; + + if (bVisible) + DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints(xSeries); + else + DataSeriesHelper::deleteDataLabelsFromSeriesAndAllPoints(xSeries); +} + +struct LabelPlacementMap +{ + sal_Int32 nPos; + sal_Int32 nApi; +}; + +LabelPlacementMap const aLabelPlacementMap[] = { + { 0, css::chart::DataLabelPlacement::TOP }, + { 1, css::chart::DataLabelPlacement::BOTTOM }, + { 2, css::chart::DataLabelPlacement::CENTER }, + { 3, css::chart::DataLabelPlacement::OUTSIDE }, + { 4, css::chart::DataLabelPlacement::INSIDE }, + { 5, css::chart::DataLabelPlacement::NEAR_ORIGIN } +}; + +sal_Int32 getDataLabelPlacement(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return 0; + + css::uno::Any aAny = xSeries->getPropertyValue("LabelPlacement"); + if (!aAny.hasValue()) + return 0; + + sal_Int32 nPlacement = 0; + aAny >>= nPlacement; + + for (LabelPlacementMap const & i : aLabelPlacementMap) + { + if (i.nApi == nPlacement) + return i.nPos; + } + + return 0; +} + +void setDataLabelPlacement(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, sal_Int32 nPos) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return; + + sal_Int32 nApi = 0; + for (LabelPlacementMap const & i : aLabelPlacementMap) + { + if (i.nPos == nPos) + { + nApi = i.nApi; + break; + } + } + + xSeries->setPropertyValue("LabelPlacement", css::uno::Any(nApi)); +} + +bool isTrendlineVisible(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< DataSeries > xRegressionCurveContainer = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xRegressionCurveContainer.is()) + return false; + + return xRegressionCurveContainer->getRegressionCurves().hasElements(); +} + +void setTrendlineVisible(const rtl::Reference<::chart::ChartModel>& + xModel, const OUString& rCID, bool bVisible) +{ + rtl::Reference< DataSeries > xRegressionCurveContainer = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xRegressionCurveContainer.is()) + return; + + if (bVisible) + { + RegressionCurveHelper::addRegressionCurve( + SvxChartRegress::Linear, + xRegressionCurveContainer); + } + else + RegressionCurveHelper::removeAllExceptMeanValueLine( + xRegressionCurveContainer ); + +} + +bool isErrorBarVisible(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bYError) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return false; + + return StatisticsHelper::hasErrorBars(xSeries, bYError); +} + +void setErrorBarVisible(const rtl::Reference<::chart::ChartModel>& + xModel, const OUString& rCID, bool bYError, bool bVisible) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return; + + if (bVisible) + { + StatisticsHelper::addErrorBars( xSeries, + css::chart::ErrorBarStyle::STANDARD_DEVIATION, + bYError); + } + else + { + StatisticsHelper::removeErrorBars( xSeries, bYError ); + } +} + +bool isPrimaryAxis(const rtl::Reference<::chart::ChartModel>& + xModel, const OUString& rCID) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return true; + + return DataSeriesHelper::getAttachedAxisIndex(xSeries) == 0; +} + +void setAttachedAxisType(const rtl::Reference<::chart::ChartModel>& + xModel, const OUString& rCID, bool bPrimary) +{ + const rtl::Reference<DataSeries> xDataSeries = ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xDataSeries.is()) + return; + + rtl::Reference<Diagram> xDiagram = xModel->getFirstChartDiagram(); + DiagramHelper::attachSeriesToAxis(bPrimary, xDataSeries, xDiagram, comphelper::getProcessComponentContext()); +} + +rtl::Reference<ChartType> getChartType( + const rtl::Reference<::chart::ChartModel>& xModel) +{ + rtl::Reference<Diagram> xDiagram = xModel->getFirstChartDiagram(); + const std::vector< rtl::Reference< BaseCoordinateSystem > > & xCooSysSequence( xDiagram->getBaseCoordinateSystems()); + return xCooSysSequence[0]->getChartTypes2()[0]; +} + +OUString getSeriesLabel(const rtl::Reference<::chart::ChartModel>& xModel, const OUString& rCID) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return OUString(); + + rtl::Reference<ChartType> xChartType = getChartType(xModel); + return DataSeriesHelper::getDataSeriesLabel(xSeries, xChartType->getRoleOfSequenceForSeriesLabel()); +} + +OUString getCID(const css::uno::Reference<css::frame::XModel>& xModel) +{ + css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController()); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + return OUString(); + + OUString aCID; + aAny >>= aCID; + + if (aCID.isEmpty()) + return OUString(); + +#if defined DBG_UTIL && !defined NDEBUG + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType != OBJECTTYPE_DATA_SERIES && + eType != OBJECTTYPE_DATA_POINT && + eType != OBJECTTYPE_DATA_CURVE) + SAL_WARN("chart2","Selected item is not a chart series"); +#endif + + return aCID; +} + +} + +ChartSeriesPanel::ChartSeriesPanel( + weld::Widget* pParent, + ChartController* pController) + : PanelLayout(pParent, "ChartSeriesPanel", "modules/schart/ui/sidebarseries.ui") + , mxCBLabel(m_xBuilder->weld_check_button("checkbutton_label")) + , mxCBTrendline(m_xBuilder->weld_check_button("checkbutton_trendline")) + , mxCBXError(m_xBuilder->weld_check_button("checkbutton_x_error")) + , mxCBYError(m_xBuilder->weld_check_button("checkbutton_y_error")) + , mxRBPrimaryAxis(m_xBuilder->weld_radio_button("radiobutton_primary_axis")) + , mxRBSecondaryAxis(m_xBuilder->weld_radio_button("radiobutton_secondary_axis")) + , mxBoxLabelPlacement(m_xBuilder->weld_widget("datalabel_box")) + , mxLBLabelPlacement(m_xBuilder->weld_combo_box("comboboxtext_label")) + , mxFTSeriesName(m_xBuilder->weld_label("label_series_name")) + , mxFTSeriesTemplate(m_xBuilder->weld_label("label_series_tmpl")) + , mxModel(pController->getChartModel()) + , mxListener(new ChartSidebarModifyListener(this)) + , mxSelectionListener(new ChartSidebarSelectionListener(this, OBJECTTYPE_DATA_SERIES)) + , mbModelValid(true) +{ + Initialize(); +} + +ChartSeriesPanel::~ChartSeriesPanel() +{ + doUpdateModel(nullptr); + + mxCBLabel.reset(); + mxCBTrendline.reset(); + mxCBXError.reset(); + mxCBYError.reset(); + + mxRBPrimaryAxis.reset(); + mxRBSecondaryAxis.reset(); + + mxBoxLabelPlacement.reset(); + mxLBLabelPlacement.reset(); + + mxFTSeriesName.reset(); + mxFTSeriesTemplate.reset(); +} + +void ChartSeriesPanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + updateData(); + + Link<weld::Toggleable&,void> aLink = LINK(this, ChartSeriesPanel, CheckBoxHdl); + mxCBLabel->connect_toggled(aLink); + mxCBTrendline->connect_toggled(aLink); + mxCBXError->connect_toggled(aLink); + mxCBYError->connect_toggled(aLink); + + Link<weld::Toggleable&,void> aLink2 = LINK(this, ChartSeriesPanel, RadioBtnHdl); + mxRBPrimaryAxis->connect_toggled(aLink2); + mxRBSecondaryAxis->connect_toggled(aLink2); + + mxLBLabelPlacement->connect_changed(LINK(this, ChartSeriesPanel, ListBoxHdl)); +} + +void ChartSeriesPanel::updateData() +{ + if (!mbModelValid) + return; + + OUString aCID = getCID(mxModel); + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType!=OBJECTTYPE_DATA_SERIES && + eType != OBJECTTYPE_DATA_POINT && + eType != OBJECTTYPE_DATA_CURVE) + return; + + SolarMutexGuard aGuard; + bool bLabelVisible = isDataLabelVisible(mxModel, aCID); + mxCBLabel->set_active(bLabelVisible); + mxCBTrendline->set_active(isTrendlineVisible(mxModel, aCID)); + mxCBXError->set_active(isErrorBarVisible(mxModel, aCID, false)); + mxCBYError->set_active(isErrorBarVisible(mxModel, aCID, true)); + + bool bPrimaryAxis = isPrimaryAxis(mxModel, aCID); + mxRBPrimaryAxis->set_active(bPrimaryAxis); + mxRBSecondaryAxis->set_active(!bPrimaryAxis); + + mxBoxLabelPlacement->set_sensitive(bLabelVisible); + mxLBLabelPlacement->set_active(getDataLabelPlacement(mxModel, aCID)); + + OUString aFrameLabel = mxFTSeriesTemplate->get_label(); + aFrameLabel = aFrameLabel.replaceFirst("%1", getSeriesLabel(mxModel, aCID)); + mxFTSeriesName->set_label(aFrameLabel); +} + +std::unique_ptr<PanelLayout> ChartSeriesPanel::Create ( + weld::Widget* pParent, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartSeriesPanel::Create", nullptr, 0); + + return std::make_unique<ChartSeriesPanel>(pParent, pController); +} + +void ChartSeriesPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartSeriesPanel::HandleContextChange( + const vcl::EnumContext& ) +{ + updateData(); +} + +void ChartSeriesPanel::NotifyItemUpdate( + sal_uInt16 /*nSID*/, + SfxItemState /*eState*/, + const SfxPoolItem* /*pState*/ ) +{ +} + +void ChartSeriesPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartSeriesPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + } + + css::uno::Reference<css::view::XSelectionSupplier> oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxListener); + + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartSeriesPanel::updateModel(css::uno::Reference<css::frame::XModel> xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +void ChartSeriesPanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +IMPL_LINK(ChartSeriesPanel, CheckBoxHdl, weld::Toggleable&, rCheckBox, void) +{ + bool bChecked = rCheckBox.get_active(); + OUString aCID = getCID(mxModel); + if (&rCheckBox == mxCBLabel.get()) + setDataLabelVisible(mxModel, aCID, bChecked); + else if (&rCheckBox == mxCBTrendline.get()) + setTrendlineVisible(mxModel, aCID, bChecked); + else if (&rCheckBox == mxCBXError.get()) + setErrorBarVisible(mxModel, aCID, false, bChecked); + else if (&rCheckBox == mxCBYError.get()) + setErrorBarVisible(mxModel, aCID, true, bChecked); +} + +IMPL_LINK_NOARG(ChartSeriesPanel, RadioBtnHdl, weld::Toggleable&, void) +{ + OUString aCID = getCID(mxModel); + bool bChecked = mxRBPrimaryAxis->get_active(); + + setAttachedAxisType(mxModel, aCID, bChecked); +} + +IMPL_LINK_NOARG(ChartSeriesPanel, ListBoxHdl, weld::ComboBox&, void) +{ + OUString aCID = getCID(mxModel); + + sal_Int32 nPos = mxLBLabelPlacement->get_active(); + setDataLabelPlacement(mxModel, aCID, nPos); +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSeriesPanel.hxx b/chart2/source/controller/sidebar/ChartSeriesPanel.hxx new file mode 100644 index 000000000..b457667ec --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSeriesPanel.hxx @@ -0,0 +1,110 @@ +/* -*- 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 <sfx2/sidebar/ControllerItem.hxx> +#include <sfx2/sidebar/IContextChangeReceiver.hxx> +#include <sfx2/sidebar/SidebarModelUpdate.hxx> +#include <sfx2/sidebar/PanelLayout.hxx> + +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" + +namespace com::sun::star::util { class XModifyListener; } +namespace com::sun::star::view { class XSelectionChangeListener; } + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartSeriesPanel : public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static std::unique_ptr<PanelLayout> Create( + weld::Widget* pParent, + ChartController* pController); + + virtual void DataChanged( + const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange( + const vcl::EnumContext& rContext) override; + + virtual void NotifyItemUpdate( + const sal_uInt16 nSId, + const SfxItemState eState, + const SfxPoolItem* pState) override; + + virtual void GetControlState( + const sal_uInt16 /*nSId*/, + boost::property_tree::ptree& /*rState*/) override {}; + + // constructor/destructor + ChartSeriesPanel( + weld::Widget* pParent, + ChartController* pController); + virtual ~ChartSeriesPanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void selectionChanged(bool bCorrectType) override; + + virtual void updateModel(css::uno::Reference<css::frame::XModel> xModel) override; + +private: + //ui controls + std::unique_ptr<weld::CheckButton> mxCBLabel; + std::unique_ptr<weld::CheckButton> mxCBTrendline; + std::unique_ptr<weld::CheckButton> mxCBXError; + std::unique_ptr<weld::CheckButton> mxCBYError; + + std::unique_ptr<weld::RadioButton> mxRBPrimaryAxis; + std::unique_ptr<weld::RadioButton> mxRBSecondaryAxis; + + std::unique_ptr<weld::Widget> mxBoxLabelPlacement; + std::unique_ptr<weld::ComboBox> mxLBLabelPlacement; + + std::unique_ptr<weld::Label> mxFTSeriesName; + std::unique_ptr<weld::Label> mxFTSeriesTemplate; + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference<css::util::XModifyListener> mxListener; + css::uno::Reference<css::view::XSelectionChangeListener> mxSelectionListener; + + bool mbModelValid; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + DECL_LINK(CheckBoxHdl, weld::Toggleable&, void); + DECL_LINK(RadioBtnHdl, weld::Toggleable&, void); + DECL_LINK(ListBoxHdl, weld::ComboBox&, void); +}; + +} } // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSidebarModifyListener.cxx b/chart2/source/controller/sidebar/ChartSidebarModifyListener.cxx new file mode 100644 index 000000000..adee06ddd --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSidebarModifyListener.cxx @@ -0,0 +1,39 @@ +/* -*- 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 "ChartSidebarModifyListener.hxx" + +namespace chart::sidebar +{ +ChartSidebarModifyListenerParent::~ChartSidebarModifyListenerParent() {} + +ChartSidebarModifyListener::ChartSidebarModifyListener(ChartSidebarModifyListenerParent* pParent) + : mpParent(pParent) +{ +} + +ChartSidebarModifyListener::~ChartSidebarModifyListener() {} + +void ChartSidebarModifyListener::modified(const css::lang::EventObject& /*rEvent*/) +{ + if (mpParent) + mpParent->updateData(); +} + +void ChartSidebarModifyListener::disposing(const css::lang::EventObject& /*rEvent*/) +{ + if (!mpParent) + return; + + mpParent->modelInvalid(); + mpParent = nullptr; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSidebarModifyListener.hxx b/chart2/source/controller/sidebar/ChartSidebarModifyListener.hxx new file mode 100644 index 000000000..afcbbdab5 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSidebarModifyListener.hxx @@ -0,0 +1,42 @@ +/* -*- 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/. + */ + +#pragma once + +#include <com/sun/star/util/XModifyListener.hpp> +#include <cppuhelper/implbase.hxx> + +namespace chart::sidebar +{ +class ChartSidebarModifyListenerParent +{ +public: + virtual ~ChartSidebarModifyListenerParent(); + + virtual void updateData() = 0; + + virtual void modelInvalid() = 0; +}; + +class ChartSidebarModifyListener : public cppu::WeakImplHelper<css::util::XModifyListener> +{ +public: + explicit ChartSidebarModifyListener(ChartSidebarModifyListenerParent* pParent); + virtual ~ChartSidebarModifyListener() override; + + virtual void SAL_CALL modified(const css::lang::EventObject& rEvent) override; + + virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; + +private: + ChartSidebarModifyListenerParent* mpParent; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSidebarSelectionListener.cxx b/chart2/source/controller/sidebar/ChartSidebarSelectionListener.cxx new file mode 100644 index 000000000..c3757a3b8 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSidebarSelectionListener.cxx @@ -0,0 +1,84 @@ +/* -*- 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 "ChartSidebarSelectionListener.hxx" + +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/frame/XController.hpp> + +#include <ObjectIdentifier.hxx> + +namespace chart::sidebar { + +ChartSidebarSelectionListenerParent::~ChartSidebarSelectionListenerParent() +{ +} + +ChartSidebarSelectionListener::ChartSidebarSelectionListener( + ChartSidebarSelectionListenerParent* pParent): + mpParent(pParent) +{ +} + +ChartSidebarSelectionListener::ChartSidebarSelectionListener( + ChartSidebarSelectionListenerParent* pParent, + ObjectType eType): + mpParent(pParent) +{ + maTypes.push_back(eType); +} + +ChartSidebarSelectionListener::~ChartSidebarSelectionListener() +{ +} + +void ChartSidebarSelectionListener::selectionChanged(const css::lang::EventObject& rEvent) +{ + if (!mpParent) + return; + + bool bCorrectObjectSelected = false; + + css::uno::Reference<css::frame::XController> xController(rEvent.Source, css::uno::UNO_QUERY); + if (xController.is()) + { + css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + { + css::uno::Any aAny = xSelectionSupplier->getSelection(); + if (aAny.hasValue()) + { + OUString aCID; + aAny >>= aCID; + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + bCorrectObjectSelected = std::any_of(maTypes.begin(), maTypes.end(), + [eType](const ObjectType& eTypeInVector) { return eType == eTypeInVector; }); + } + } + } + + mpParent->selectionChanged(bCorrectObjectSelected); +} + +void ChartSidebarSelectionListener::disposing(const css::lang::EventObject& /*rEvent*/) +{ + if (!mpParent) + return; + + mpParent = nullptr; +} + +void ChartSidebarSelectionListener::setAcceptedTypes(std::vector<ObjectType>&& aTypes) +{ + maTypes = std::move(aTypes); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSidebarSelectionListener.hxx b/chart2/source/controller/sidebar/ChartSidebarSelectionListener.hxx new file mode 100644 index 000000000..e8cea5003 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSidebarSelectionListener.hxx @@ -0,0 +1,52 @@ +/* -*- 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/. + */ + +#pragma once + +#include <com/sun/star/view/XSelectionChangeListener.hpp> +#include <cppuhelper/implbase.hxx> + +#include <ObjectIdentifier.hxx> + +#include <vector> + +namespace chart::sidebar +{ +class ChartSidebarSelectionListenerParent +{ +public: + virtual ~ChartSidebarSelectionListenerParent(); + + virtual void selectionChanged(bool bSelected) = 0; +}; + +class ChartSidebarSelectionListener + : public cppu::WeakImplHelper<css::view::XSelectionChangeListener> +{ +public: + // listen to all chart selection changes + explicit ChartSidebarSelectionListener(ChartSidebarSelectionListenerParent* pParent); + // only listen to the changes of eType + ChartSidebarSelectionListener(ChartSidebarSelectionListenerParent* pParent, ObjectType eType); + virtual ~ChartSidebarSelectionListener() override; + + virtual void SAL_CALL selectionChanged(const css::lang::EventObject& rEvent) override; + + virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; + + void setAcceptedTypes(std::vector<ObjectType>&& aTypes); + +private: + ChartSidebarSelectionListenerParent* mpParent; + + std::vector<ObjectType> maTypes; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartTypePanel.cxx b/chart2/source/controller/sidebar/ChartTypePanel.cxx new file mode 100644 index 000000000..9c5a7ba43 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartTypePanel.cxx @@ -0,0 +1,437 @@ +/* -*- 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 "ChartTypePanel.hxx" +#include <TimerTriggeredControllerLock.hxx> + +#include <ChartController.hxx> +#include <ChartModelHelper.hxx> +#include <ChartModel.hxx> +#include <ChartResourceGroups.hxx> +#include <ChartTypeDialogController.hxx> +#include <ChartTypeManager.hxx> +#include <ChartTypeTemplate.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <unonames.hxx> + +#include <svtools/valueset.hxx> +#include <tools/diagnose_ex.h> + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar +{ +ChartTypePanel::ChartTypePanel(weld::Widget* pParent, ::chart::ChartController* pController) + : PanelLayout(pParent, "ChartTypePanel", "modules/schart/ui/sidebartype.ui") + , mxListener(new ChartSidebarModifyListener(this)) + , mbModelValid(true) + , m_pDim3DLookResourceGroup(new Dim3DLookResourceGroup(m_xBuilder.get())) + , m_pStackingResourceGroup(new StackingResourceGroup(m_xBuilder.get())) + , m_pSplineResourceGroup( + new SplineResourceGroup(m_xBuilder.get(), pController->GetChartFrame())) + , m_pGeometryResourceGroup(new GeometryResourceGroup(m_xBuilder.get())) + , m_pSortByXValuesResourceGroup(new SortByXValuesResourceGroup(m_xBuilder.get())) + , m_xChartModel(pController->getChartModel()) + , m_aChartTypeDialogControllerList(0) + , m_pCurrentMainType(nullptr) + , m_nChangingCalls(0) + , m_aTimerTriggeredControllerLock(m_xChartModel) + , m_xMainTypeList(m_xBuilder->weld_combo_box("cmb_chartType")) + , m_xSubTypeList(new ValueSet(m_xBuilder->weld_scrolled_window("subtypewin", true))) + , m_xSubTypeListWin(new weld::CustomWeld(*m_xBuilder, "subtype", *m_xSubTypeList)) +{ + Size aSize(m_xSubTypeList->GetDrawingArea()->get_ref_device().LogicToPixel( + Size(120, 40), MapMode(MapUnit::MapAppFont))); + m_xSubTypeListWin->set_size_request(aSize.Width(), aSize.Height()); + + m_xMainTypeList->connect_changed(LINK(this, ChartTypePanel, SelectMainTypeHdl)); + m_xSubTypeList->SetSelectHdl(LINK(this, ChartTypePanel, SelectSubTypeHdl)); + + m_xSubTypeList->SetStyle(m_xSubTypeList->GetStyle() | WB_ITEMBORDER | WB_DOUBLEBORDER + | WB_NAMEFIELD | WB_FLATVALUESET | WB_3DLOOK); + m_xSubTypeList->SetColCount(4); + m_xSubTypeList->SetLineCount(1); + + bool bEnableComplexChartTypes = true; + uno::Reference<beans::XPropertySet> xProps(static_cast<cppu::OWeakObject*>(m_xChartModel.get()), + uno::UNO_QUERY); + if (xProps.is()) + { + try + { + xProps->getPropertyValue("EnableComplexChartTypes") >>= bEnableComplexChartTypes; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + + m_aChartTypeDialogControllerList.push_back(std::make_unique<ColumnChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<BarChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<PieChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<AreaChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<LineChartDialogController>()); + if (bEnableComplexChartTypes) + { + m_aChartTypeDialogControllerList.push_back(std::make_unique<XYChartDialogController>()); + m_aChartTypeDialogControllerList.push_back(std::make_unique<BubbleChartDialogController>()); + } + m_aChartTypeDialogControllerList.push_back(std::make_unique<NetChartDialogController>()); + if (bEnableComplexChartTypes) + { + m_aChartTypeDialogControllerList.push_back(std::make_unique<StockChartDialogController>()); + } + m_aChartTypeDialogControllerList.push_back( + std::make_unique<CombiColumnLineChartDialogController>()); + + for (auto const& elem : m_aChartTypeDialogControllerList) + { + m_xMainTypeList->append("", elem->getName(), elem->getImage()); + elem->setChangeListener(this); + } + + m_pDim3DLookResourceGroup->setChangeListener(this); + m_pStackingResourceGroup->setChangeListener(this); + m_pSplineResourceGroup->setChangeListener(this); + m_pGeometryResourceGroup->setChangeListener(this); + m_pSortByXValuesResourceGroup->setChangeListener(this); + + Initialize(); +} + +ChartTypePanel::~ChartTypePanel() +{ + doUpdateModel(nullptr); + + //delete all dialog controller + m_aChartTypeDialogControllerList.clear(); + + //delete all resource helpers + m_pDim3DLookResourceGroup.reset(); + m_pStackingResourceGroup.reset(); + m_pSplineResourceGroup.reset(); + m_pGeometryResourceGroup.reset(); + m_pSortByXValuesResourceGroup.reset(); + m_xSubTypeListWin.reset(); + m_xSubTypeList.reset(); + + m_xSubTypeListWin.reset(); + m_xSubTypeList.reset(); + m_xMainTypeList.reset(); +} + +IMPL_LINK_NOARG(ChartTypePanel, SelectMainTypeHdl, weld::ComboBox&, void) { selectMainType(); } + +IMPL_LINK_NOARG(ChartTypePanel, SelectSubTypeHdl, ValueSet*, void) +{ + if (m_pCurrentMainType) + { + ChartTypeParameter aParameter(getCurrentParameter()); + m_pCurrentMainType->adjustParameterToSubType(aParameter); + fillAllControls(aParameter, false); + commitToModel(aParameter); + } +} + +void ChartTypePanel::Initialize() +{ + if (!m_xChartModel.is()) + return; + rtl::Reference<::chart::ChartTypeManager> xChartTypeManager = m_xChartModel->getTypeManager(); + rtl::Reference<Diagram> xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + DiagramHelper::tTemplateWithServiceName aTemplate + = DiagramHelper::getTemplateForDiagram(xDiagram, xChartTypeManager); + OUString aServiceName(aTemplate.sServiceName); + + bool bFound = false; + + sal_uInt16 nM = 0; + for (auto const& elem : m_aChartTypeDialogControllerList) + { + if (elem->isSubType(aServiceName)) + { + bFound = true; + + m_xMainTypeList->set_active(nM); + showAllControls(*elem); + uno::Reference<beans::XPropertySet> xTemplateProps( + static_cast<cppu::OWeakObject*>(aTemplate.xChartTypeTemplate.get()), + uno::UNO_QUERY); + ChartTypeParameter aParameter + = elem->getChartTypeParameterForService(aServiceName, xTemplateProps); + m_pCurrentMainType = getSelectedMainType(); + + //set ThreeDLookScheme + aParameter.eThreeDLookScheme = ThreeDHelper::detectScheme(xDiagram); + if (!aParameter.b3DLook + && aParameter.eThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Realistic) + aParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) + >>= aParameter.bSortByXValues; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + fillAllControls(aParameter); + if (m_pCurrentMainType) + m_pCurrentMainType->fillExtraControls(m_xChartModel, xTemplateProps); + break; + } + ++nM; + } + + if (!bFound) + { + m_xSubTypeList->Hide(); + m_pDim3DLookResourceGroup->showControls(false); + m_pStackingResourceGroup->showControls(false); + m_pSplineResourceGroup->showControls(false); + m_pGeometryResourceGroup->showControls(false); + m_pSortByXValuesResourceGroup->showControls(false); + } +} + +void ChartTypePanel::updateData() +{ + // Chart Type related + if (!m_xChartModel.is()) + return; + rtl::Reference<::chart::ChartTypeManager> xChartTypeManager = m_xChartModel->getTypeManager(); + rtl::Reference<Diagram> xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + DiagramHelper::tTemplateWithServiceName aTemplate + = DiagramHelper::getTemplateForDiagram(xDiagram, xChartTypeManager); + OUString aServiceName(aTemplate.sServiceName); + + //sal_uInt16 nM = 0; + for (auto const& elem : m_aChartTypeDialogControllerList) + { + if (elem->isSubType(aServiceName)) + { + //m_pMainTypeList->SelectEntryPos(nM); + //m_pMainTypeList->select_entry_region(nM, nM); + break; + } + //++nM; + } +} + +void ChartTypePanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartTypePanel::HandleContextChange(const vcl::EnumContext& rContext) +{ + if (maContext == rContext) + { + // Nothing to do. + return; + } + + maContext = rContext; + updateData(); +} + +void ChartTypePanel::modelInvalid() { mbModelValid = false; } + +void ChartTypePanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + m_xChartModel->removeModifyListener(mxListener); + } + + m_xChartModel = xModel; + mbModelValid = m_xChartModel.is(); + + if (!mbModelValid) + return; + + m_xChartModel->addModifyListener(mxListener); +} + +void ChartTypePanel::updateModel(css::uno::Reference<css::frame::XModel> xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +rtl::Reference<::chart::ChartTypeTemplate> ChartTypePanel::getCurrentTemplate() const +{ + if (m_pCurrentMainType && m_xChartModel.is()) + { + ChartTypeParameter aParameter(getCurrentParameter()); + m_pCurrentMainType->adjustParameterToSubType(aParameter); + rtl::Reference<::chart::ChartTypeManager> xChartTypeManager + = m_xChartModel->getTypeManager(); + return m_pCurrentMainType->getCurrentTemplate(aParameter, xChartTypeManager); + } + return nullptr; +} + +ChartTypeDialogController* ChartTypePanel::getSelectedMainType() +{ + ChartTypeDialogController* pTypeController = nullptr; + auto nM = static_cast<std::vector<ChartTypeDialogController*>::size_type>( + m_xMainTypeList->get_active()); + if (nM < m_aChartTypeDialogControllerList.size()) + pTypeController = m_aChartTypeDialogControllerList[nM].get(); + return pTypeController; +} + +void ChartTypePanel::showAllControls(ChartTypeDialogController& rTypeController) +{ + m_xMainTypeList->show(); + m_xSubTypeList->Show(); + + bool bShow = rTypeController.shouldShow_3DLookControl(); + m_pDim3DLookResourceGroup->showControls(bShow); + bShow = rTypeController.shouldShow_StackingControl(); + m_pStackingResourceGroup->showControls(bShow); + bShow = rTypeController.shouldShow_SplineControl(); + m_pSplineResourceGroup->showControls(bShow); + bShow = rTypeController.shouldShow_GeometryControl(); + m_pGeometryResourceGroup->showControls(bShow); + bShow = rTypeController.shouldShow_SortByXValuesResourceGroup(); + m_pSortByXValuesResourceGroup->showControls(bShow); + rTypeController.showExtraControls(m_xBuilder.get()); +} + +void ChartTypePanel::fillAllControls(const ChartTypeParameter& rParameter, + bool bAlsoResetSubTypeList) +{ + m_nChangingCalls++; + if (m_pCurrentMainType && bAlsoResetSubTypeList) + { + m_pCurrentMainType->fillSubTypeList(*m_xSubTypeList, rParameter); + } + m_xSubTypeList->SelectItem(static_cast<sal_uInt16>(rParameter.nSubTypeIndex)); + m_pDim3DLookResourceGroup->fillControls(rParameter); + m_pStackingResourceGroup->fillControls(rParameter); + m_pSplineResourceGroup->fillControls(rParameter); + m_pGeometryResourceGroup->fillControls(rParameter); + m_pSortByXValuesResourceGroup->fillControls(rParameter); + m_nChangingCalls--; +} + +ChartTypeParameter ChartTypePanel::getCurrentParameter() const +{ + ChartTypeParameter aParameter; + aParameter.nSubTypeIndex = static_cast<sal_Int32>(m_xSubTypeList->GetSelectedItemId()); + m_pDim3DLookResourceGroup->fillParameter(aParameter); + m_pStackingResourceGroup->fillParameter(aParameter); + m_pSplineResourceGroup->fillParameter(aParameter); + m_pGeometryResourceGroup->fillParameter(aParameter); + m_pSortByXValuesResourceGroup->fillParameter(aParameter); + return aParameter; +} + +void ChartTypePanel::stateChanged() +{ + if (m_nChangingCalls) + return; + m_nChangingCalls++; + + ChartTypeParameter aParameter(getCurrentParameter()); + if (m_pCurrentMainType) + { + m_pCurrentMainType->adjustParameterToSubType(aParameter); + m_pCurrentMainType->adjustSubTypeAndEnableControls(aParameter); + } + commitToModel(aParameter); + + //detect the new ThreeDLookScheme + rtl::Reference<Diagram> xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + aParameter.eThreeDLookScheme = ThreeDHelper::detectScheme(xDiagram); + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + //the controls have to be enabled/disabled accordingly + fillAllControls(aParameter); + + m_nChangingCalls--; +} + +void ChartTypePanel::commitToModel(const ChartTypeParameter& rParameter) +{ + if (!m_pCurrentMainType) + return; + + m_aTimerTriggeredControllerLock.startTimer(); + m_pCurrentMainType->commitToModel(rParameter, m_xChartModel); +} + +void ChartTypePanel::selectMainType() +{ + ChartTypeParameter aParameter(getCurrentParameter()); + + if (m_pCurrentMainType) + { + m_pCurrentMainType->adjustParameterToSubType(aParameter); + m_pCurrentMainType->hideExtraControls(); + } + + m_pCurrentMainType = getSelectedMainType(); + if (!m_pCurrentMainType) + return; + + showAllControls(*m_pCurrentMainType); + + m_pCurrentMainType->adjustParameterToMainType(aParameter); + commitToModel(aParameter); + //detect the new ThreeDLookScheme + aParameter.eThreeDLookScheme + = ThreeDHelper::detectScheme(ChartModelHelper::findDiagram(m_xChartModel)); + if (!aParameter.b3DLook + && aParameter.eThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Realistic) + aParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + + rtl::Reference<Diagram> xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + fillAllControls(aParameter); + uno::Reference<beans::XPropertySet> xTemplateProps( + static_cast<cppu::OWeakObject*>(getCurrentTemplate().get()), uno::UNO_QUERY); + m_pCurrentMainType->fillExtraControls(m_xChartModel, xTemplateProps); +} +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartTypePanel.hxx b/chart2/source/controller/sidebar/ChartTypePanel.hxx new file mode 100644 index 000000000..5555eba2f --- /dev/null +++ b/chart2/source/controller/sidebar/ChartTypePanel.hxx @@ -0,0 +1,121 @@ +/* -*- 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 <sfx2/sidebar/IContextChangeReceiver.hxx> +#include <sfx2/sidebar/SidebarModelUpdate.hxx> +#include <sfx2/sidebar/PanelLayout.hxx> +#include <vcl/EnumContext.hxx> +#include "ChartSidebarModifyListener.hxx" +#include <ChartTypeDialogController.hxx> +#include <ChartTypeTemplateProvider.hxx> +#include <TimerTriggeredControllerLock.hxx> + +namespace com::sun::star::util +{ +class XModifyListener; +} + +namespace weld +{ +class CustomWeld; +} + +namespace chart +{ +class ChartController; +class Dim3DLookResourceGroup; +class StackingResourceGroup; +class SplineResourceGroup; +class GeometryResourceGroup; +class ChartTypeParameter; +class SortByXValuesResourceGroup; + +namespace sidebar +{ +class ChartTypePanel : public ResourceChangeListener, + public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartTypeTemplateProvider +{ +public: + virtual void DataChanged(const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange(const vcl::EnumContext& rContext) override; + + // constructor/destructor + ChartTypePanel(weld::Widget* pParent, ::chart::ChartController* pController); + + virtual ~ChartTypePanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void updateModel(css::uno::Reference<css::frame::XModel> xModel) override; + + virtual rtl::Reference<::chart::ChartTypeTemplate> getCurrentTemplate() const override; + +private: + ChartTypeDialogController* getSelectedMainType(); + void showAllControls(ChartTypeDialogController& rTypeController); + void fillAllControls(const ChartTypeParameter& rParameter, bool bAlsoResetSubTypeList = true); + ChartTypeParameter getCurrentParameter() const; + + virtual void stateChanged() override; + + void commitToModel(const ChartTypeParameter& rParameter); + void selectMainType(); + + DECL_LINK(SelectMainTypeHdl, weld::ComboBox&, void); + DECL_LINK(SelectSubTypeHdl, ValueSet*, void); + + vcl::EnumContext maContext; + + css::uno::Reference<css::util::XModifyListener> mxListener; + + bool mbModelValid; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + std::unique_ptr<Dim3DLookResourceGroup> m_pDim3DLookResourceGroup; + std::unique_ptr<StackingResourceGroup> m_pStackingResourceGroup; + std::unique_ptr<SplineResourceGroup> m_pSplineResourceGroup; + std::unique_ptr<GeometryResourceGroup> m_pGeometryResourceGroup; + std::unique_ptr<SortByXValuesResourceGroup> m_pSortByXValuesResourceGroup; + + rtl::Reference<::chart::ChartModel> m_xChartModel; + + std::vector<std::unique_ptr<ChartTypeDialogController>> m_aChartTypeDialogControllerList; + ChartTypeDialogController* m_pCurrentMainType; + + sal_Int32 m_nChangingCalls; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + std::unique_ptr<weld::ComboBox> m_xMainTypeList; + std::unique_ptr<ValueSet> m_xSubTypeList; + std::unique_ptr<weld::CustomWeld> m_xSubTypeListWin; +}; +} +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/uitest/uiobject.cxx b/chart2/source/controller/uitest/uiobject.cxx new file mode 100644 index 000000000..5081f00c7 --- /dev/null +++ b/chart2/source/controller/uitest/uiobject.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/. + */ + +#include <memory> +#include <uiobject.hxx> + +#include <ChartWindow.hxx> +#include <ChartController.hxx> +#include <ChartModel.hxx> +#include <ObjectHierarchy.hxx> +#include <chartview/ExplicitValueProvider.hxx> + +#include <comphelper/servicehelper.hxx> + +#include <vcl/svapp.hxx> + +#include <algorithm> +#include <iterator> + +ChartUIObject::ChartUIObject(const VclPtr<chart::ChartWindow>& xChartWindow, + const OUString& rCID): + maCID(rCID), + mxChartWindow(xChartWindow) +{ +} + +StringMap ChartUIObject::get_state() +{ + StringMap aMap; + aMap["CID"] = maCID; + + return aMap; +} + +void ChartUIObject::execute(const OUString& rAction, + const StringMap& rParameters) +{ + if (rAction == "SELECT") + { + std::unique_ptr<UIObject> pWindow = mxChartWindow->GetUITestFactory()(mxChartWindow.get()); + + StringMap aParams; + aParams["NAME"] = maCID; + pWindow->execute(rAction, aParams); + } + else if (rAction == "COMMAND") + { + // first select object + std::unique_ptr<UIObject> pWindow = mxChartWindow->GetUITestFactory()(mxChartWindow.get()); + + StringMap aParams; + aParams["NAME"] = maCID; + pWindow->execute("SELECT", aParams); + + auto itr = rParameters.find("COMMAND"); + if (itr == rParameters.end()) + throw css::uno::RuntimeException("missing COMMAND parameter"); + + maCommands.emplace_back(new OUString(itr->second)); + OUString* pCommand = maCommands.rbegin()->get(); + + Application::PostUserEvent(LINK(this, ChartUIObject, PostCommand), pCommand); + } +} + +IMPL_LINK(ChartUIObject, PostCommand, void*, pCommand, void) +{ + css::util::URL aURL; + aURL.Path = *static_cast<OUString*>(pCommand); + mxChartWindow->GetController()->dispatch(aURL, css::uno::Sequence<css::beans::PropertyValue>()); +} + +std::unique_ptr<UIObject> ChartUIObject::get_child(const OUString& rID) +{ + std::unique_ptr<UIObject> pWindow = mxChartWindow->GetUITestFactory()(mxChartWindow.get()); + + return pWindow->get_child(rID); +} + +std::set<OUString> ChartUIObject::get_children() const +{ + std::unique_ptr<UIObject> pWindow = mxChartWindow->GetUITestFactory()(mxChartWindow.get()); + + return pWindow->get_children(); +} + +OUString ChartUIObject::get_type() const +{ + return "ChartUIObject for type: "; +} + +ChartWindowUIObject::ChartWindowUIObject(const VclPtr<chart::ChartWindow>& xChartWindow): + WindowUIObject(xChartWindow), + mxChartWindow(xChartWindow) +{ +} + +StringMap ChartWindowUIObject::get_state() +{ + StringMap aMap = WindowUIObject::get_state(); + + chart::ChartController* pController = mxChartWindow->GetController(); + if (pController) + { + css::uno::Any aAny = pController->getSelection(); + OUString aSelectedObject; + aAny >>= aSelectedObject; + aMap["SelectedObject"] = aSelectedObject; + } + + return aMap; +} + +void ChartWindowUIObject::execute(const OUString& rAction, + const StringMap& rParameters) +{ + if (rAction == "SELECT") + { + auto itr = rParameters.find("NAME"); + if (itr == rParameters.end()) + throw css::uno::RuntimeException("Missing Parameter 'NAME' for action 'SELECT'"); + + + const OUString& rName = itr->second; + css::uno::Any aAny; + aAny <<= rName; + + chart::ChartController* pController = mxChartWindow->GetController(); + pController->select(aAny); + } + else + WindowUIObject::execute(rAction, rParameters); +} + +std::unique_ptr<UIObject> ChartWindowUIObject::get_child(const OUString& rID) +{ + if (chart::ObjectIdentifier::isCID(rID)) + return std::unique_ptr<UIObject>(new ChartUIObject(mxChartWindow, rID)); + + throw css::uno::RuntimeException("unknown child"); +} + +namespace { + +void recursiveAdd(chart::ObjectIdentifier const & rID, std::set<OUString>& rChildren, const chart::ObjectHierarchy& rHierarchy) +{ + std::vector<chart::ObjectIdentifier> aChildIdentifiers = rHierarchy.getChildren(rID); + std::transform(aChildIdentifiers.begin(), aChildIdentifiers.end(), std::inserter(rChildren, rChildren.begin()), + [](const chart::ObjectIdentifier& rObject) + { + return rObject.getObjectCID(); + } + ); + + for (const chart::ObjectIdentifier& ID: aChildIdentifiers) + recursiveAdd(ID, rChildren, rHierarchy); +} + +} + +std::set<OUString> ChartWindowUIObject::get_children() const +{ + std::set<OUString> aChildren; + + chart::ChartController* pController = mxChartWindow->GetController(); + if (!pController) + return aChildren; + + rtl::Reference<::chart::ChartModel> xChartDoc( pController->getChartModel() ); + + css::uno::Reference<css::uno::XInterface> xChartView = pController->getChartView(); + chart::ExplicitValueProvider* pValueProvider = comphelper::getFromUnoTunnel<chart::ExplicitValueProvider>( xChartView ); + chart::ObjectHierarchy aHierarchy(xChartDoc, pValueProvider); + chart::ObjectIdentifier aIdentifier = chart::ObjectHierarchy::getRootNodeOID(); + aChildren.insert(aIdentifier.getObjectCID()); + + recursiveAdd(aIdentifier, aChildren, aHierarchy); + + return aChildren; +} + +std::unique_ptr<UIObject> ChartWindowUIObject::create(vcl::Window* pWindow) +{ + chart::ChartWindow* pChartWindow = dynamic_cast<chart::ChartWindow*>(pWindow); + assert(pChartWindow); + + return std::unique_ptr<UIObject>(new ChartWindowUIObject(pChartWindow)); +} + +OUString ChartWindowUIObject::get_name() const +{ + return "ChartWindowUIObject"; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |