diff options
Diffstat (limited to 'toolkit/source/controls')
38 files changed, 23116 insertions, 0 deletions
diff --git a/toolkit/source/controls/accessiblecontrolcontext.cxx b/toolkit/source/controls/accessiblecontrolcontext.cxx new file mode 100644 index 000000000..219b4a610 --- /dev/null +++ b/toolkit/source/controls/accessiblecontrolcontext.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 <controls/accessiblecontrolcontext.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <com/sun/star/awt/XControl.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <vcl/svapp.hxx> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/window.hxx> + + +namespace toolkit +{ + + + using ::comphelper::OContextEntryGuard; + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::accessibility; + + + //= OAccessibleControlContext + + + OAccessibleControlContext::OAccessibleControlContext() + { + // nothing to do here, we have a late ctor + } + + + OAccessibleControlContext::~OAccessibleControlContext() + { + ensureDisposed(); + } + + + // (order matters: the first is the class name, the second is the class doing the ref counting) + IMPLEMENT_FORWARD_XINTERFACE3( OAccessibleControlContext, OAccessibleControlContext_Base, OAccessibleImplementationAccess, OAccessibleControlContext_IBase ) + css::uno::Sequence< css::uno::Type > SAL_CALL OAccessibleControlContext::getTypes() + { + return ::comphelper::concatSequences( + OAccessibleControlContext_Base::getTypes(), + OAccessibleImplementationAccess::getTypes(), + OAccessibleControlContext_IBase::getTypes() + ); + } + IMPLEMENT_GET_IMPLEMENTATION_ID( OAccessibleControlContext ) + + + void OAccessibleControlContext::Init( const Reference< XAccessible >& _rxCreator ) + { + OContextEntryGuard aGuard( this ); + + // retrieve the model of the control + OSL_ENSURE( !m_xControlModel.is(), "OAccessibleControlContext::Init: already know a control model...!???" ); + + Reference< awt::XControl > xControl( _rxCreator, UNO_QUERY ); + if ( xControl.is() ) + m_xControlModel.set(xControl->getModel(), css::uno::UNO_QUERY); + OSL_ENSURE( m_xControlModel.is(), "OAccessibleControlContext::Init: invalid creator (no control, or control without model!" ); + if ( !m_xControlModel.is() ) + throw DisposedException(); // caught by the caller (the create method) + + // start listening at the model + startModelListening(); + + // announce the XAccessible to our base class + OAccessibleControlContext_Base::lateInit( _rxCreator ); + } + + + rtl::Reference<OAccessibleControlContext> OAccessibleControlContext::create( const Reference< XAccessible >& _rxCreator ) + { + rtl::Reference<OAccessibleControlContext> pNew; + try + { + pNew = new OAccessibleControlContext; + pNew->Init( _rxCreator ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "toolkit", "OAccessibleControlContext::create: caught an exception from the late ctor!" ); + } + return pNew; + } + + + void OAccessibleControlContext::startModelListening( ) + { + Reference< XComponent > xModelComp( m_xControlModel, UNO_QUERY ); + OSL_ENSURE( xModelComp.is(), "OAccessibleControlContext::startModelListening: invalid model!" ); + if ( xModelComp.is() ) + xModelComp->addEventListener( this ); + } + + + void OAccessibleControlContext::stopModelListening( ) + { + Reference< XComponent > xModelComp( m_xControlModel, UNO_QUERY ); + OSL_ENSURE( xModelComp.is(), "OAccessibleControlContext::stopModelListening: invalid model!" ); + if ( xModelComp.is() ) + xModelComp->removeEventListener( this ); + } + + + sal_Int32 SAL_CALL OAccessibleControlContext::getAccessibleChildCount( ) + { + // we do not have children + return 0; + } + + + Reference< XAccessible > SAL_CALL OAccessibleControlContext::getAccessibleChild( sal_Int32 ) + { + // we do not have children + throw IndexOutOfBoundsException(); + } + + + Reference< XAccessible > SAL_CALL OAccessibleControlContext::getAccessibleParent( ) + { + return Reference< XAccessible >(); + } + + + sal_Int16 SAL_CALL OAccessibleControlContext::getAccessibleRole( ) + { + return AccessibleRole::SHAPE; + } + + + OUString SAL_CALL OAccessibleControlContext::getAccessibleDescription( ) + { + OContextEntryGuard aGuard( this ); + return getModelStringProperty( "HelpText" ); + } + + + OUString SAL_CALL OAccessibleControlContext::getAccessibleName( ) + { + OContextEntryGuard aGuard( this ); + return getModelStringProperty( "Name" ); + } + + + Reference< XAccessibleRelationSet > SAL_CALL OAccessibleControlContext::getAccessibleRelationSet( ) + { + return nullptr; + } + + + Reference< XAccessibleStateSet > SAL_CALL OAccessibleControlContext::getAccessibleStateSet( ) + { + ::osl::MutexGuard aGuard( GetMutex() ); + // no OContextEntryGuard here, as we do not want to throw an exception in case we're not alive anymore + + rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet; + if ( isAlive() ) + { + // no own states, only the ones which are foreign controlled + pStateSet = new ::utl::AccessibleStateSetHelper( 0 ); + } + else + { // only the DEFUNC state if we're already disposed + pStateSet = new ::utl::AccessibleStateSetHelper; + pStateSet->AddState( AccessibleStateType::DEFUNC ); + } + return pStateSet; + } + + + void SAL_CALL OAccessibleControlContext::disposing( const EventObject& _rSource ) + { + OSL_ENSURE( Reference< XPropertySet >( _rSource.Source, UNO_QUERY ).get() == m_xControlModel.get(), + "OAccessibleControlContext::disposing: where did this come from?" ); + + stopModelListening( ); + m_xControlModel.clear(); + m_xModelPropsInfo.clear(); + + OAccessibleControlContext_Base::disposing(); + } + + + OUString OAccessibleControlContext::getModelStringProperty( const char* _pPropertyName ) + { + OUString sReturn; + try + { + if ( !m_xModelPropsInfo.is() && m_xControlModel.is() ) + m_xModelPropsInfo = m_xControlModel->getPropertySetInfo(); + + OUString sPropertyName( OUString::createFromAscii( _pPropertyName ) ); + if ( m_xModelPropsInfo.is() && m_xModelPropsInfo->hasPropertyByName( sPropertyName ) ) + m_xControlModel->getPropertyValue( sPropertyName ) >>= sReturn; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "toolkit", "OAccessibleControlContext::getModelStringProperty" ); + } + return sReturn; + } + + + vcl::Window* OAccessibleControlContext::implGetWindow( Reference< awt::XWindow >* _pxUNOWindow ) const + { + Reference< awt::XControl > xControl( getAccessibleCreator(), UNO_QUERY ); + Reference< awt::XWindow > xWindow; + if ( xControl.is() ) + xWindow.set(xControl->getPeer(), css::uno::UNO_QUERY); + + vcl::Window* pWindow = xWindow.is() ? VCLUnoHelper::GetWindow( xWindow ) : nullptr; + + if ( _pxUNOWindow ) + *_pxUNOWindow = xWindow; + + return pWindow; + } + + + awt::Rectangle OAccessibleControlContext::implGetBounds( ) + { + SolarMutexGuard aSolarGuard; + // want to do some VCL stuff here ... + OContextEntryGuard aGuard( this ); + + OSL_FAIL( "OAccessibleControlContext::implGetBounds: performance issue: forced to calc the size myself!" ); + // In design mode (and this is what this class is for), the surrounding shape (if any) should handle this call + // The problem is that in design mode, our size may not be correct (in the drawing layer, controls are + // positioned/sized for painting only), and that calculation of our position is expensive + + // what we know (or can obtain from somewhere): + // * the PosSize of our peer, relative to its parent window + // * the parent window which the PosSize is relative to + // * our foreign controlled accessible parent + // from this info, we can determine the position of our peer relative to the foreign parent + + // our control + Reference< awt::XWindow > xWindow; + VclPtr< vcl::Window > pVCLWindow = implGetWindow( &xWindow ); + + awt::Rectangle aBounds( 0, 0, 0, 0 ); + if ( xWindow.is() ) + { + // ugly, but... though the XWindow has a getPosSize, it is impossible to determine the + // parent which this position/size is relative to. This means we must tunnel UNO and ask the + // implementation + vcl::Window* pVCLParent = pVCLWindow ? pVCLWindow->GetParent() : nullptr; + + // the relative location of the window + ::Point aWindowRelativePos( 0, 0); + if ( pVCLWindow ) + aWindowRelativePos = pVCLWindow->GetPosPixel(); + + // the screen position of the "window parent" of the control + ::Point aVCLParentScreenPos( 0, 0 ); + if ( pVCLParent ) + aVCLParentScreenPos = pVCLParent->GetPosPixel(); + + // now the size of the control + aBounds = xWindow->getPosSize(); + + // correct the pos + aBounds.X = aWindowRelativePos.X() + aVCLParentScreenPos.X(); + aBounds.Y = aWindowRelativePos.Y() + aVCLParentScreenPos.Y(); + } + + return aBounds; + } + + + Reference< XAccessible > SAL_CALL OAccessibleControlContext::getAccessibleAtPoint( const awt::Point& /* _rPoint */ ) + { + // no children at all + return nullptr; + } + + + void SAL_CALL OAccessibleControlContext::grabFocus( ) + { + OSL_FAIL( "OAccessibleControlContext::grabFocus: !isFocusTraversable, but grabFocus!" ); + } + + + sal_Int32 SAL_CALL OAccessibleControlContext::getForeground( ) + { + SolarMutexGuard aSolarGuard; + // want to do some VCL stuff here ... + OContextEntryGuard aGuard( this ); + + VclPtr< vcl::Window > pWindow = implGetWindow(); + Color nColor; + if ( pWindow ) + { + if ( pWindow->IsControlForeground() ) + nColor = pWindow->GetControlForeground(); + else + { + vcl::Font aFont; + if ( pWindow->IsControlFont() ) + aFont = pWindow->GetControlFont(); + else + aFont = pWindow->GetFont(); + nColor = aFont.GetColor(); + } + } + return sal_Int32(nColor); + } + + + sal_Int32 SAL_CALL OAccessibleControlContext::getBackground( ) + { + SolarMutexGuard aSolarGuard; + // want to do some VCL stuff here ... + OContextEntryGuard aGuard( this ); + + VclPtr< vcl::Window > pWindow = implGetWindow(); + Color nColor; + if ( pWindow ) + { + if ( pWindow->IsControlBackground() ) + nColor = pWindow->GetControlBackground(); + else + nColor = pWindow->GetBackground().GetColor(); + } + + return sal_Int32(nColor); + } + + +} //namespace toolkit + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/animatedimages.cxx b/toolkit/source/controls/animatedimages.cxx new file mode 100644 index 000000000..99fd5df85 --- /dev/null +++ b/toolkit/source/controls/animatedimages.cxx @@ -0,0 +1,491 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <controls/animatedimages.hxx> +#include <toolkit/helper/property.hxx> + +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/awt/VisualEffect.hpp> +#include <com/sun/star/awt/ImageScaleMode.hpp> +#include <com/sun/star/awt/XAnimation.hpp> +#include <com/sun/star/awt/XAnimatedImages.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/container/XContainerListener.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/XModifyListener.hpp> +#include <o3tl/safeint.hxx> +#include <toolkit/controls/unocontrolbase.hxx> +#include <toolkit/controls/unocontrolmodel.hxx> + +#include <cppuhelper/implbase2.hxx> + +#include <helper/unopropertyarrayhelper.hxx> + +using namespace css::awt; +using namespace css::container; +using namespace css::lang; +using namespace css::uno; + +namespace { + +typedef ::cppu::AggImplInheritanceHelper2 < UnoControlBase + , css::awt::XAnimation + , css::container::XContainerListener + > AnimatedImagesControl_Base; + +class AnimatedImagesControl : public AnimatedImagesControl_Base +{ +public: + AnimatedImagesControl(); + OUString GetComponentServiceName() const override; + + // XAnimation + virtual void SAL_CALL startAnimation( ) override; + virtual void SAL_CALL stopAnimation( ) override; + virtual sal_Bool SAL_CALL isAnimationRunning( ) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName( ) override; + css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XControl + sal_Bool SAL_CALL setModel( const css::uno::Reference< css::awt::XControlModel >& i_rModel ) override; + void SAL_CALL createPeer( const css::uno::Reference< css::awt::XToolkit >& i_toolkit, const css::uno::Reference< css::awt::XWindowPeer >& i_parentPeer ) override; + + + // XContainerListener + virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override; + virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override; + virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& i_event ) override; +}; + + AnimatedImagesControl::AnimatedImagesControl() + { + } + + + OUString AnimatedImagesControl::GetComponentServiceName() const + { + return "AnimatedImages"; + } + + + void SAL_CALL AnimatedImagesControl::startAnimation( ) + { + Reference< XAnimation > xAnimation( getPeer(), UNO_QUERY ); + if ( xAnimation.is() ) + xAnimation->startAnimation(); + } + + + void SAL_CALL AnimatedImagesControl::stopAnimation( ) + { + Reference< XAnimation > xAnimation( getPeer(), UNO_QUERY ); + if ( xAnimation.is() ) + xAnimation->stopAnimation(); + } + + + sal_Bool SAL_CALL AnimatedImagesControl::isAnimationRunning( ) + { + Reference< XAnimation > xAnimation( getPeer(), UNO_QUERY ); + if ( xAnimation.is() ) + return xAnimation->isAnimationRunning(); + return false; + } + + + OUString SAL_CALL AnimatedImagesControl::getImplementationName( ) + { + return "org.openoffice.comp.toolkit.AnimatedImagesControl"; + } + + + Sequence< OUString > SAL_CALL AnimatedImagesControl::getSupportedServiceNames() + { + Sequence< OUString > aServices( AnimatedImagesControl_Base::getSupportedServiceNames() ); + aServices.realloc( aServices.getLength() + 1 ); + aServices.getArray()[ aServices.getLength() - 1 ] = "com.sun.star.awt.AnimatedImagesControl"; + return aServices; + } + + void lcl_updatePeer( Reference< XWindowPeer > const& i_peer, Reference< XControlModel > const& i_model ) + { + const Reference< css::util::XModifyListener > xPeerModify( i_peer, UNO_QUERY ); + if ( xPeerModify.is() ) + { + EventObject aEvent; + aEvent.Source = i_model; + xPeerModify->modified( aEvent ); + } + } + + sal_Bool SAL_CALL AnimatedImagesControl::setModel( const Reference< XControlModel >& i_rModel ) + { + const Reference< XAnimatedImages > xOldContainer( getModel(), UNO_QUERY ); + const Reference< XAnimatedImages > xNewContainer( i_rModel, UNO_QUERY ); + + if ( !AnimatedImagesControl_Base::setModel( i_rModel ) ) + return false; + + if ( xOldContainer.is() ) + xOldContainer->removeContainerListener( this ); + + if ( xNewContainer.is() ) + xNewContainer->addContainerListener( this ); + + lcl_updatePeer( getPeer(), getModel() ); + + return true; + } + + + void SAL_CALL AnimatedImagesControl::createPeer( const Reference< XToolkit >& i_toolkit, const Reference< XWindowPeer >& i_parentPeer ) + { + AnimatedImagesControl_Base::createPeer( i_toolkit, i_parentPeer ); + + lcl_updatePeer( getPeer(), getModel() ); + } + + + void SAL_CALL AnimatedImagesControl::elementInserted( const ContainerEvent& i_event ) + { + const Reference< XContainerListener > xPeerListener( getPeer(), UNO_QUERY ); + if ( xPeerListener.is() ) + xPeerListener->elementInserted( i_event ); + } + + + void SAL_CALL AnimatedImagesControl::elementRemoved( const ContainerEvent& i_event ) + { + const Reference< XContainerListener > xPeerListener( getPeer(), UNO_QUERY ); + if ( xPeerListener.is() ) + xPeerListener->elementRemoved( i_event ); + } + + + void SAL_CALL AnimatedImagesControl::elementReplaced( const ContainerEvent& i_event ) + { + const Reference< XContainerListener > xPeerListener( getPeer(), UNO_QUERY ); + if ( xPeerListener.is() ) + xPeerListener->elementReplaced( i_event ); + } + + + void SAL_CALL AnimatedImagesControl::disposing( const EventObject& i_event ) + { + UnoControlBase::disposing( i_event ); + } + +} + +namespace toolkit { + + namespace + { + void lcl_checkIndex( const std::vector< css::uno::Sequence< OUString > > & rImageSets, const sal_Int32 i_index, const Reference< XInterface >& i_context, + const bool i_forInsert = false ) + { + if ( ( i_index < 0 ) || ( o3tl::make_unsigned( i_index ) > rImageSets.size() + ( i_forInsert ? 1 : 0 ) ) ) + throw IndexOutOfBoundsException( OUString(), i_context ); + } + + void lcl_notify( ::osl::ClearableMutexGuard& i_guard, ::cppu::OBroadcastHelper const & i_broadcaseHelper, + void ( SAL_CALL XContainerListener::*i_notificationMethod )( const ContainerEvent& ), + const sal_Int32 i_accessor, const Sequence< OUString >& i_imageURLs, const Reference< XInterface >& i_context ) + { + ::cppu::OInterfaceContainerHelper* pContainerListeners = i_broadcaseHelper.getContainer( cppu::UnoType<XContainerListener>::get() ); + if ( pContainerListeners == nullptr ) + return; + + ContainerEvent aEvent; + aEvent.Source = i_context; + aEvent.Accessor <<= i_accessor; + aEvent.Element <<= i_imageURLs; + + i_guard.clear(); + pContainerListeners->notifyEach( i_notificationMethod, aEvent ); + } + } + + + AnimatedImagesControlModel::AnimatedImagesControlModel( Reference< css::uno::XComponentContext > const & i_factory ) + :AnimatedImagesControlModel_Base( i_factory ) + { + ImplRegisterProperty( BASEPROPERTY_AUTO_REPEAT ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_IMAGE_SCALE_MODE ); + ImplRegisterProperty( BASEPROPERTY_STEP_TIME ); + } + + + AnimatedImagesControlModel::AnimatedImagesControlModel( const AnimatedImagesControlModel& i_copySource ) + :AnimatedImagesControlModel_Base( i_copySource ) + ,maImageSets( i_copySource.maImageSets ) + { + } + + + AnimatedImagesControlModel::~AnimatedImagesControlModel() + { + } + + + rtl::Reference<UnoControlModel> AnimatedImagesControlModel::Clone() const + { + return new AnimatedImagesControlModel( *this ); + } + + + Reference< css::beans::XPropertySetInfo > SAL_CALL AnimatedImagesControlModel::getPropertySetInfo( ) + { + static Reference< css::beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + + OUString SAL_CALL AnimatedImagesControlModel::getServiceName() + { + return "com.sun.star.awt.AnimatedImagesControlModel"; + } + + + OUString SAL_CALL AnimatedImagesControlModel::getImplementationName( ) + { + return "org.openoffice.comp.toolkit.AnimatedImagesControlModel"; + } + + + Sequence< OUString > SAL_CALL AnimatedImagesControlModel::getSupportedServiceNames() + { + return { "com.sun.star.awt.AnimatedImagesControlModel", "com.sun.star.awt.UnoControlModel" }; + } + + + void SAL_CALL AnimatedImagesControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 i_handle, const Any& i_value ) + { + switch ( i_handle ) + { + case BASEPROPERTY_IMAGE_SCALE_MODE: + { + sal_Int16 nImageScaleMode( ImageScaleMode::ANISOTROPIC ); + OSL_VERIFY( i_value >>= nImageScaleMode ); // convertFastPropertyValue ensures that this has the proper type + if ( ( nImageScaleMode != ImageScaleMode::NONE ) + && ( nImageScaleMode != ImageScaleMode::ISOTROPIC ) + && ( nImageScaleMode != ImageScaleMode::ANISOTROPIC ) + ) + throw IllegalArgumentException( OUString(), *this, 1 ); + } + break; + } + + AnimatedImagesControlModel_Base::setFastPropertyValue_NoBroadcast( i_handle, i_value ); + } + + + Any AnimatedImagesControlModel::ImplGetDefaultValue( sal_uInt16 i_propertyId ) const + { + switch ( i_propertyId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + return Any( OUString("com.sun.star.awt.AnimatedImagesControl") ); + + case BASEPROPERTY_BORDER: + return Any( css::awt::VisualEffect::NONE ); + + case BASEPROPERTY_STEP_TIME: + return Any( sal_Int32(100) ); + + case BASEPROPERTY_AUTO_REPEAT: + return Any( true ); + + case BASEPROPERTY_IMAGE_SCALE_MODE: + return Any( ImageScaleMode::NONE ); + + default: + return UnoControlModel::ImplGetDefaultValue( i_propertyId ); + } + } + + + ::cppu::IPropertyArrayHelper& SAL_CALL AnimatedImagesControlModel::getInfoHelper() + { + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; + } + + + ::sal_Int32 SAL_CALL AnimatedImagesControlModel::getStepTime() + { + sal_Int32 nStepTime( 100 ); + OSL_VERIFY( getPropertyValue( GetPropertyName( BASEPROPERTY_STEP_TIME ) ) >>= nStepTime ); + return nStepTime; + } + + + void SAL_CALL AnimatedImagesControlModel::setStepTime( ::sal_Int32 i_stepTime ) + { + setPropertyValue( GetPropertyName( BASEPROPERTY_STEP_TIME ), Any( i_stepTime ) ); + } + + + sal_Bool SAL_CALL AnimatedImagesControlModel::getAutoRepeat() + { + bool bAutoRepeat( true ); + OSL_VERIFY( getPropertyValue( GetPropertyName( BASEPROPERTY_AUTO_REPEAT ) ) >>= bAutoRepeat ); + return bAutoRepeat; + } + + + void SAL_CALL AnimatedImagesControlModel::setAutoRepeat( sal_Bool i_autoRepeat ) + { + setPropertyValue( GetPropertyName( BASEPROPERTY_AUTO_REPEAT ), Any( i_autoRepeat ) ); + } + + + ::sal_Int16 SAL_CALL AnimatedImagesControlModel::getScaleMode() + { + sal_Int16 nImageScaleMode( ImageScaleMode::ANISOTROPIC ); + OSL_VERIFY( getPropertyValue( GetPropertyName( BASEPROPERTY_IMAGE_SCALE_MODE ) ) >>= nImageScaleMode ); + return nImageScaleMode; + } + + + void SAL_CALL AnimatedImagesControlModel::setScaleMode( ::sal_Int16 i_scaleMode ) + { + setPropertyValue( GetPropertyName( BASEPROPERTY_IMAGE_SCALE_MODE ), Any( i_scaleMode ) ); + } + + + ::sal_Int32 SAL_CALL AnimatedImagesControlModel::getImageSetCount( ) + { + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose ) + throw DisposedException(); + + return maImageSets.size(); + } + + + Sequence< OUString > SAL_CALL AnimatedImagesControlModel::getImageSet( ::sal_Int32 i_index ) + { + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose ) + throw DisposedException(); + + lcl_checkIndex( maImageSets, i_index, *this ); + + return maImageSets[ i_index ]; + } + + + void SAL_CALL AnimatedImagesControlModel::insertImageSet( ::sal_Int32 i_index, const Sequence< OUString >& i_imageURLs ) + { + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // sanity checks + if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose ) + throw DisposedException(); + + lcl_checkIndex( maImageSets, i_index, *this, true ); + + // actual insertion + maImageSets.insert( maImageSets.begin() + i_index, i_imageURLs ); + + // listener notification + lcl_notify( aGuard, BrdcstHelper, &XContainerListener::elementInserted, i_index, i_imageURLs, *this ); + } + + + void SAL_CALL AnimatedImagesControlModel::replaceImageSet( ::sal_Int32 i_index, const Sequence< OUString >& i_imageURLs ) + { + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // sanity checks + if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose ) + throw DisposedException(); + + lcl_checkIndex( maImageSets, i_index, *this ); + + // actual insertion + maImageSets[ i_index ] = i_imageURLs; + + // listener notification + lcl_notify( aGuard, BrdcstHelper, &XContainerListener::elementReplaced, i_index, i_imageURLs, *this ); + } + + + void SAL_CALL AnimatedImagesControlModel::removeImageSet( ::sal_Int32 i_index ) + { + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // sanity checks + if ( GetBroadcastHelper().bDisposed || GetBroadcastHelper().bInDispose ) + throw DisposedException(); + + lcl_checkIndex( maImageSets, i_index, *this ); + + // actual removal + ::std::vector< Sequence< OUString > >::iterator removalPos = maImageSets.begin() + i_index; + Sequence< OUString > aRemovedElement( *removalPos ); + maImageSets.erase( removalPos ); + + // listener notification + lcl_notify( aGuard, BrdcstHelper, &XContainerListener::elementRemoved, i_index, aRemovedElement, *this ); + } + + + void SAL_CALL AnimatedImagesControlModel::addContainerListener( const Reference< XContainerListener >& i_listener ) + { + BrdcstHelper.addListener( cppu::UnoType<XContainerListener>::get(), i_listener ); + } + + + void SAL_CALL AnimatedImagesControlModel::removeContainerListener( const Reference< XContainerListener >& i_listener ) + { + BrdcstHelper.removeListener( cppu::UnoType<XContainerListener>::get(), i_listener ); + } + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +org_openoffice_comp_toolkit_AnimatedImagesControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new AnimatedImagesControl()); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +org_openoffice_comp_toolkit_AnimatedImagesControlModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::AnimatedImagesControlModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/controlmodelcontainerbase.cxx b/toolkit/source/controls/controlmodelcontainerbase.cxx new file mode 100644 index 000000000..677d000f9 --- /dev/null +++ b/toolkit/source/controls/controlmodelcontainerbase.cxx @@ -0,0 +1,1820 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <controls/controlmodelcontainerbase.hxx> +#include <vcl/svapp.hxx> +#include <o3tl/safeint.hxx> +#include <osl/mutex.hxx> +#include <toolkit/helper/property.hxx> +#include <helper/servicenames.hxx> +#include <controls/geometrycontrolmodel.hxx> +#include <toolkit/controls/unocontrols.hxx> +#include <controls/formattedcontrol.hxx> +#include <controls/roadmapcontrol.hxx> +#include <controls/tkscrollbar.hxx> +#include <controls/tabpagemodel.hxx> +#include <controls/stdtabcontroller.hxx> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/resource/XStringResourceResolver.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/weakagg.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/outdev.hxx> +#include <comphelper/types.hxx> + +#include "tree/treecontrol.hxx" +#include "grid/gridcontrol.hxx" +#include <controls/tabpagecontainer.hxx> + +#include <map> +#include <algorithm> +#include <tools/urlobj.hxx> +#include <osl/file.hxx> +#include <sal/log.hxx> +#include <controls/dialogcontrol.hxx> + +#include <helper/unopropertyarrayhelper.hxx> +#include "controlmodelcontainerbase_internal.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace toolkit; + +constexpr OUStringLiteral PROPERTY_RESOURCERESOLVER = u"ResourceResolver"; + + +namespace +{ + const Sequence< OUString >& lcl_getLanguageDependentProperties() + { + // note: properties must be sorted + static Sequence<OUString> s_aLanguageDependentProperties{ "HelpText", "Title" }; + return s_aLanguageDependentProperties; + } + +// functor for disposing a control model +struct DisposeControlModel +{ + void operator()( Reference< XControlModel >& _rxModel ) + { + try + { + ::comphelper::disposeComponent( _rxModel ); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while disposing a component" ); + } + } +}; + +} + + +// functor for cloning a control model, and insertion into a target list +struct CloneControlModel +{ +private: + ControlModelContainerBase::UnoControlModelHolderVector& m_rTargetVector; + +public: + explicit CloneControlModel( ControlModelContainerBase::UnoControlModelHolderVector& _rTargetVector ) + :m_rTargetVector( _rTargetVector ) + { + } + + void operator()( const ControlModelContainerBase::UnoControlModelHolder& _rSource ) + { + // clone the source object + Reference< XCloneable > xCloneSource( _rSource.first, UNO_QUERY ); + Reference< XControlModel > xClone( xCloneSource->createClone(), UNO_QUERY ); + // add to target list + m_rTargetVector.emplace_back( xClone, _rSource.second ); + } +}; + + +// functor for comparing a XControlModel with a given reference +struct CompareControlModel +{ +private: + Reference< XControlModel > m_xReference; +public: + explicit CompareControlModel( const Reference< XControlModel >& _rxReference ) : m_xReference( _rxReference ) { } + + bool operator()( const ControlModelContainerBase::UnoControlModelHolder& _rCompare ) + { + return _rCompare.first.get() == m_xReference.get(); + } +}; + + +static void lcl_throwIllegalArgumentException( ) +{ // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this... + throw IllegalArgumentException(); +} + + +static void lcl_throwNoSuchElementException( ) +{ // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this... + throw NoSuchElementException(); +} + + +static void lcl_throwElementExistException( ) +{ // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this... + throw ElementExistException(); +} + + +static OUString getTabIndexPropertyName( ) +{ + return "TabIndex"; +} + + +static OUString getStepPropertyName( ) +{ + return "Step"; +} + + + +ControlModelContainerBase::ControlModelContainerBase( const Reference< XComponentContext >& rxContext ) + :ControlModelContainer_IBase( rxContext ) + ,maContainerListeners( *this ) + ,maChangeListeners ( GetMutex() ) + ,mbGroupsUpToDate( false ) + ,m_nTabPageId(0) +{ + ImplRegisterProperty(BASEPROPERTY_ENABLED); +} + +ControlModelContainerBase::ControlModelContainerBase( const ControlModelContainerBase& rModel ) + : ControlModelContainer_IBase( rModel ) + , maContainerListeners( *this ) + , maChangeListeners ( GetMutex() ) + , mbGroupsUpToDate( false ) + , m_nTabPageId( rModel.m_nTabPageId ) +{ +} + +ControlModelContainerBase::~ControlModelContainerBase() +{ + maModels.clear(); + mbGroupsUpToDate = false; +} + +Any ControlModelContainerBase::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + Any aAny; + + switch ( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + aAny <<= OUString::createFromAscii( szServiceName_UnoControlDialog ); + break; + default: + aAny = UnoControlModel::ImplGetDefaultValue( nPropId ); + } + + return aAny; +} + +::cppu::IPropertyArrayHelper& ControlModelContainerBase::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +void SAL_CALL ControlModelContainerBase::dispose( ) +{ + + // tell our listeners + { + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + EventObject aDisposeEvent; + aDisposeEvent.Source = static_cast< XAggregation* >( static_cast< ::cppu::OWeakAggObject* >( this ) ); + + maContainerListeners.disposeAndClear( aDisposeEvent ); + maChangeListeners.disposeAndClear( aDisposeEvent ); + } + + + // call the base class + UnoControlModel::dispose(); + + + // dispose our child models + // for this, collect the models (we collect them from maModels, and this is modified when disposing children) + ::std::vector< Reference< XControlModel > > aChildModels( maModels.size() ); + + ::std::transform( + maModels.begin(), maModels.end(), // source range + aChildModels.begin(), // target location + []( const UnoControlModelHolder& rUnoControlModelHolder ) + { return rUnoControlModelHolder.first; } // operation to apply -> select the XControlModel part + ); + + // now dispose + ::std::for_each( aChildModels.begin(), aChildModels.end(), DisposeControlModel() ); + aChildModels.clear(); + + mbGroupsUpToDate = false; +} + +// XMultiPropertySet +Reference< XPropertySetInfo > ControlModelContainerBase::getPropertySetInfo( ) +{ + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +void ControlModelContainerBase::Clone_Impl(ControlModelContainerBase& _rClone) const +{ + // clone all children + ::std::for_each( + maModels.begin(), maModels.end(), + CloneControlModel( _rClone.maModels ) + ); +} +rtl::Reference<UnoControlModel> ControlModelContainerBase::Clone() const +{ + // clone the container itself + rtl::Reference<ControlModelContainerBase> pClone = new ControlModelContainerBase( *this ); + Clone_Impl(*pClone); + + return pClone; +} + +ControlModelContainerBase::UnoControlModelHolderVector::iterator ControlModelContainerBase::ImplFindElement( std::u16string_view rName ) +{ + return ::std::find_if( maModels.begin(), maModels.end(), [&](const UnoControlModelHolder& elem) { return elem.second == rName; }); +} + +// ::XMultiServiceFactory +Reference< XInterface > ControlModelContainerBase::createInstance( const OUString& aServiceSpecifier ) +{ + SolarMutexGuard aGuard; + + rtl::Reference<OGeometryControlModel_Base> pNewModel; + + if ( aServiceSpecifier == "com.sun.star.awt.UnoControlEditModel" ) + pNewModel = new OGeometryControlModel< UnoControlEditModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFormattedFieldModel" ) + pNewModel = new OGeometryControlModel< UnoControlFormattedFieldModel >( m_xContext); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFileControlModel" ) + pNewModel = new OGeometryControlModel< UnoControlFileControlModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlButtonModel" ) + pNewModel = new OGeometryControlModel< UnoControlButtonModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlImageControlModel" ) + pNewModel = new OGeometryControlModel< UnoControlImageControlModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRadioButtonModel" ) + pNewModel = new OGeometryControlModel< UnoControlRadioButtonModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCheckBoxModel" ) + pNewModel = new OGeometryControlModel< UnoControlCheckBoxModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedHyperlinkModel" ) + pNewModel = new OGeometryControlModel< UnoControlFixedHyperlinkModel >( m_xContext ); + else if ( aServiceSpecifier == "stardiv.vcl.controlmodel.FixedText" ) + pNewModel = new OGeometryControlModel< UnoControlFixedTextModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlGroupBoxModel" ) + pNewModel = new OGeometryControlModel< UnoControlGroupBoxModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlListBoxModel" ) + pNewModel = new OGeometryControlModel< UnoControlListBoxModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlComboBoxModel" ) + pNewModel = new OGeometryControlModel< UnoControlComboBoxModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlDateFieldModel" ) + pNewModel = new OGeometryControlModel< UnoControlDateFieldModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlTimeFieldModel" ) + pNewModel = new OGeometryControlModel< UnoControlTimeFieldModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlNumericFieldModel" ) + pNewModel = new OGeometryControlModel< UnoControlNumericFieldModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCurrencyFieldModel" ) + pNewModel = new OGeometryControlModel< UnoControlCurrencyFieldModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlPatternFieldModel" ) + pNewModel = new OGeometryControlModel< UnoControlPatternFieldModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlProgressBarModel" ) + pNewModel = new OGeometryControlModel< UnoControlProgressBarModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlScrollBarModel" ) + pNewModel = new OGeometryControlModel< UnoControlScrollBarModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedLineModel" ) + pNewModel = new OGeometryControlModel< UnoControlFixedLineModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRoadmapModel" ) + pNewModel = new OGeometryControlModel< UnoControlRoadmapModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.tree.TreeControlModel" ) + pNewModel = new OGeometryControlModel< UnoTreeModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.grid.UnoControlGridModel" ) + pNewModel = new OGeometryControlModel< UnoGridModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageContainerModel" ) + pNewModel = new OGeometryControlModel< UnoControlTabPageContainerModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoMultiPageModel" ) + pNewModel = new OGeometryControlModel< UnoMultiPageModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageModel" ) + pNewModel = new OGeometryControlModel< UnoControlTabPageModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoPageModel" ) + pNewModel = new OGeometryControlModel< UnoPageModel >( m_xContext ); + else if ( aServiceSpecifier == "com.sun.star.awt.UnoFrameModel" ) + pNewModel = new OGeometryControlModel< UnoFrameModel >( m_xContext ); + + if ( !pNewModel ) + { + Reference< XInterface > xObject = m_xContext->getServiceManager()->createInstanceWithContext(aServiceSpecifier, m_xContext); + Reference< XServiceInfo > xSI( xObject, UNO_QUERY ); + Reference< XCloneable > xCloneAccess( xSI, UNO_QUERY ); + Reference< XAggregation > xAgg( xCloneAccess, UNO_QUERY ); + if ( xAgg.is() ) + { + if ( xSI->supportsService("com.sun.star.awt.UnoControlModel") ) + { + // release 3 of the 4 references we have to the object + xAgg.clear(); + xSI.clear(); + xObject.clear(); + + pNewModel = new OCommonGeometryControlModel( xCloneAccess, aServiceSpecifier ); + } + } + } + + Reference< XInterface > xNewModel = static_cast<cppu::OWeakObject*>(pNewModel.get()); + return xNewModel; +} + +Reference< XInterface > ControlModelContainerBase::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& i_arguments ) +{ + const Reference< XInterface > xInstance( createInstance( ServiceSpecifier ) ); + const Reference< XInitialization > xInstanceInit( xInstance, UNO_QUERY ); + ENSURE_OR_RETURN( xInstanceInit.is(), "ControlModelContainerBase::createInstanceWithArguments: can't pass the arguments!", xInstance ); + xInstanceInit->initialize( i_arguments ); + return xInstance; +} + +Sequence< OUString > ControlModelContainerBase::getAvailableServiceNames() +{ + return { "com.sun.star.awt.UnoControlEditModel", + "com.sun.star.awt.UnoControlFormattedFieldModel", + "com.sun.star.awt.UnoControlFileControlModel", + "com.sun.star.awt.UnoControlButtonModel", + "com.sun.star.awt.UnoControlImageControlModel", + "com.sun.star.awt.UnoControlRadioButtonModel", + "com.sun.star.awt.UnoControlCheckBoxModel", + "com.sun.star.awt.UnoControlFixedTextModel", + "com.sun.star.awt.UnoControlGroupBoxModel", + "com.sun.star.awt.UnoControlListBoxModel", + "com.sun.star.awt.UnoControlComboBoxModel", + "com.sun.star.awt.UnoControlDateFieldModel", + "com.sun.star.awt.UnoControlTimeFieldModel", + "com.sun.star.awt.UnoControlNumericFieldModel", + "com.sun.star.awt.UnoControlCurrencyFieldModel", + "com.sun.star.awt.UnoControlPatternFieldModel", + "com.sun.star.awt.UnoControlProgressBarModel", + "com.sun.star.awt.UnoControlScrollBarModel", + "com.sun.star.awt.UnoControlFixedLineModel", + "com.sun.star.awt.UnoControlRoadmapModel", + "com.sun.star.awt.tree.TreeControlModel", + "com.sun.star.awt.grid.UnoControlGridModel", + "com.sun.star.awt.UnoControlFixedHyperlinkModel", + "com.sun.star.awt.tab.UnoControlTabPageContainerModel", + "com.sun.star.awt.tab.UnoControlTabPageModel", + "com.sun.star.awt.UnoMultiPageModel", + "com.sun.star.awt.UnoFrameModel" + }; +} + +// XContainer +void ControlModelContainerBase::addContainerListener( const Reference< XContainerListener >& l ) +{ + maContainerListeners.addInterface( l ); +} + +void ControlModelContainerBase::removeContainerListener( const Reference< XContainerListener >& l ) +{ + maContainerListeners.removeInterface( l ); +} + +// XElementAccess +Type ControlModelContainerBase::getElementType() +{ + Type aType = cppu::UnoType<XControlModel>::get(); + return aType; +} + +sal_Bool ControlModelContainerBase::hasElements() +{ + return !maModels.empty(); +} + +// XNameContainer, XNameReplace, XNameAccess +void ControlModelContainerBase::replaceByName( const OUString& aName, const Any& aElement ) +{ + SolarMutexGuard aGuard; + + Reference< XControlModel > xNewModel; + aElement >>= xNewModel; + if ( !xNewModel.is() ) + lcl_throwIllegalArgumentException(); + + UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName ); + if ( maModels.end() == aElementPos ) + lcl_throwNoSuchElementException(); + // Dialog behaviour is to have all containee names unique (MSO Userform is the same) + // With container controls you could have constructed an existing hierarchy and are now + // add this to an existing container, in this case a name nested in the containment + // hierarchy of the added control could contain a name clash, if we have access to the + // list of global names then recursively check for previously existing names (we need + // to do this obviously before the 'this' objects container is updated) + Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY ); + if ( xAllChildren.is() ) + { + // remove old control (and children) from global list of containers + updateUserFormChildren( xAllChildren, aName, Remove, uno::Reference< XControlModel >() ); + // Add new control (and containers if they exist) + updateUserFormChildren( xAllChildren, aName, Insert, xNewModel ); + } + // stop listening at the old model + stopControlListening( aElementPos->first ); + Reference< XControlModel > xReplaced( aElementPos->first ); + // remember the new model, and start listening + aElementPos->first = xNewModel; + startControlListening( xNewModel ); + + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Element = aElement; + aEvent.ReplacedElement <<= xReplaced; + aEvent.Accessor <<= aName; + + // notify the container listener + maContainerListeners.elementReplaced( aEvent ); + + // our "tab controller model" has potentially changed -> notify this + implNotifyTabModelChange( aName ); +} + +Any ControlModelContainerBase::getByName( const OUString& aName ) +{ + UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName ); + if ( maModels.end() == aElementPos ) + lcl_throwNoSuchElementException(); + + return Any( aElementPos->first ); +} + +Sequence< OUString > ControlModelContainerBase::getElementNames() +{ + Sequence< OUString > aNames( maModels.size() ); + + ::std::transform( + maModels.begin(), maModels.end(), // source range + aNames.getArray(), // target range + []( const UnoControlModelHolder& rUnoControlModelHolder ) + { return rUnoControlModelHolder.second; } // operator to apply: select the second element (the name) + ); + + return aNames; +} + +sal_Bool ControlModelContainerBase::hasByName( const OUString& aName ) +{ + return maModels.end() != ImplFindElement( aName ); +} + +void ControlModelContainerBase::insertByName( const OUString& aName, const Any& aElement ) +{ + SolarMutexGuard aGuard; + + Reference< XControlModel > xM; + aElement >>= xM; + + if ( xM.is() ) + { + Reference< beans::XPropertySet > xProps( xM, UNO_QUERY ); + if ( xProps.is() ) + { + + Reference< beans::XPropertySetInfo > xPropInfo = xProps->getPropertySetInfo(); + + const OUString& sImageSourceProperty = GetPropertyName( BASEPROPERTY_IMAGEURL ); + if ( xPropInfo->hasPropertyByName( sImageSourceProperty ) && ImplHasProperty(BASEPROPERTY_DIALOGSOURCEURL) ) + { + Any aUrl = xProps->getPropertyValue( sImageSourceProperty ); + + OUString absoluteUrl = + getPhysicalLocation( getPropertyValue( GetPropertyName( BASEPROPERTY_DIALOGSOURCEURL ) ), aUrl ); + + aUrl <<= absoluteUrl; + + xProps->setPropertyValue( sImageSourceProperty , aUrl ); + } + } + } + + + if ( aName.isEmpty() || !xM.is() ) + lcl_throwIllegalArgumentException(); + + UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName ); + if ( maModels.end() != aElementPos ) + lcl_throwElementExistException(); + + // Dialog behaviour is to have all containee names unique (MSO Userform is the same) + // With container controls you could have constructed an existing hierarchy and are now + // add this to an existing container, in this case a name nested in the containment + // hierarchy of the added control could contain a name clash, if we have access to the + // list of global names then we need to recursively check for previously existing + // names (we need to do this obviously before the 'this' objects container is updated) + // remove old control (and children) from global list of containers + Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY ); + + if ( xAllChildren.is() ) + updateUserFormChildren( xAllChildren, aName, Insert, xM ); + maModels.emplace_back( xM, aName ); + mbGroupsUpToDate = false; + startControlListening( xM ); + + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Element = aElement; + aEvent.Accessor <<= aName; + maContainerListeners.elementInserted( aEvent ); + + // our "tab controller model" has potentially changed -> notify this + implNotifyTabModelChange( aName ); +} + +void ControlModelContainerBase::removeByName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + + UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName ); + if ( maModels.end() == aElementPos ) + lcl_throwNoSuchElementException(); + + // Dialog behaviour is to have all containee names unique (MSO Userform is the same) + // With container controls you could have constructed an existing hierarchy and are now + // removing this control from an existing container, in this case all nested names in + // the containment hierarchy of the control to be removed need to be removed from the global + // names cache (we need to do this obviously before the 'this' objects container is updated) + Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY ); + if ( xAllChildren.is() ) + updateUserFormChildren( xAllChildren, aName, Remove, uno::Reference< XControlModel >() ); + + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Element <<= aElementPos->first; + aEvent.Accessor <<= aName; + maContainerListeners.elementRemoved( aEvent ); + + stopControlListening( aElementPos->first ); + Reference< XPropertySet > xPS( aElementPos->first, UNO_QUERY ); + maModels.erase( aElementPos ); + mbGroupsUpToDate = false; + + if ( xPS.is() ) + { + try + { + xPS->setPropertyValue( PROPERTY_RESOURCERESOLVER, Any( Reference< resource::XStringResourceResolver >() ) ); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } + + // our "tab controller model" has potentially changed -> notify this + implNotifyTabModelChange( aName ); +} + + +sal_Bool SAL_CALL ControlModelContainerBase::getGroupControl( ) +{ + return true; +} + + +void SAL_CALL ControlModelContainerBase::setGroupControl( sal_Bool ) +{ + SAL_WARN("toolkit", "explicit grouping not supported" ); +} + + +void SAL_CALL ControlModelContainerBase::setControlModels( const Sequence< Reference< XControlModel > >& _rControls ) +{ + SolarMutexGuard aGuard; + + // set the tab indexes according to the order of models in the sequence + + sal_Int16 nTabIndex = 1; + + for ( auto const & control : _rControls ) + { + // look up the control in our own structure. This is to prevent invalid arguments + UnoControlModelHolderVector::const_iterator aPos = + ::std::find_if( + maModels.begin(), maModels.end(), + CompareControlModel( control ) + ); + if ( maModels.end() != aPos ) + { + // okay, this is an existent model + // now set the TabIndex property (if applicable) + Reference< XPropertySet > xProps( aPos->first, UNO_QUERY ); + Reference< XPropertySetInfo > xPSI; + if ( xProps.is() ) + xPSI = xProps->getPropertySetInfo(); + if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) ) + xProps->setPropertyValue( getTabIndexPropertyName(), Any( nTabIndex++ ) ); + } + mbGroupsUpToDate = false; + } +} + + +typedef ::std::multimap< sal_Int32, Reference< XControlModel > > MapIndexToModel; + + +Sequence< Reference< XControlModel > > SAL_CALL ControlModelContainerBase::getControlModels( ) +{ + SolarMutexGuard aGuard; + + MapIndexToModel aSortedModels; + // will be the sorted container of all models which have a tab index property + ::std::vector< Reference< XControlModel > > aUnindexedModels; + // will be the container of all models which do not have a tab index property + + for ( const auto& rModel : maModels ) + { + Reference< XControlModel > xModel( rModel.first ); + + // see if the model has a TabIndex property + Reference< XPropertySet > xControlProps( xModel, UNO_QUERY ); + Reference< XPropertySetInfo > xPSI; + if ( xControlProps.is() ) + xPSI = xControlProps->getPropertySetInfo( ); + DBG_ASSERT( xPSI.is(), "ControlModelContainerBase::getControlModels: invalid child model!" ); + + // has it? + if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) ) + { // yes + sal_Int32 nTabIndex = -1; + xControlProps->getPropertyValue( getTabIndexPropertyName() ) >>= nTabIndex; + + aSortedModels.emplace( nTabIndex, xModel ); + } + else if ( xModel.is() ) + // no, it hasn't, but we have to include it, anyway + aUnindexedModels.push_back( xModel ); + } + + // okay, here we have a container of all our models, sorted by tab index, + // plus a container of "unindexed" models + // -> merge them + Sequence< Reference< XControlModel > > aReturn( aUnindexedModels.size() + aSortedModels.size() ); + ::std::transform( + aSortedModels.begin(), aSortedModels.end(), + ::std::copy( aUnindexedModels.begin(), aUnindexedModels.end(), aReturn.getArray() ), + [] ( const MapIndexToModel::value_type& entryIndexToModel ) + { return entryIndexToModel.second; } + ); + + return aReturn; +} + + +void SAL_CALL ControlModelContainerBase::setGroup( const Sequence< Reference< XControlModel > >&, const OUString& ) +{ + // not supported. We have only implicit grouping: + // We only have a sequence of control models, and we _know_ (yes, that's a HACK relying on + // implementation details) that VCL does grouping according to the order of controls automatically + // At least VCL does this for all we're interested in: Radio buttons. + SAL_WARN("toolkit", "grouping not supported" ); +} + +////----- XInitialization ------------------------------------------------------------------- +void SAL_CALL ControlModelContainerBase::initialize (const Sequence<Any>& rArguments) +{ + if ( rArguments.getLength() == 1 ) + { + sal_Int16 nPageId = -1; + if ( !( rArguments[ 0 ] >>= nPageId )) + throw lang::IllegalArgumentException(); + m_nTabPageId = nPageId; + } + else + m_nTabPageId = -1; +} +::sal_Int16 SAL_CALL ControlModelContainerBase::getTabPageID() +{ + return m_nTabPageId; +} +sal_Bool SAL_CALL ControlModelContainerBase::getEnabled() +{ + SolarMutexGuard aGuard; + Reference<XPropertySet> xThis(*this, UNO_QUERY); + bool bEnabled = false; + xThis->getPropertyValue(GetPropertyName(BASEPROPERTY_ENABLED)) >>= bEnabled; + return bEnabled; +} +void SAL_CALL ControlModelContainerBase::setEnabled( sal_Bool _enabled ) +{ + SolarMutexGuard aGuard; + Reference<XPropertySet> xThis(*this, UNO_QUERY); + xThis->setPropertyValue(GetPropertyName(BASEPROPERTY_ENABLED), Any(_enabled)); +} +OUString SAL_CALL ControlModelContainerBase::getTitle() +{ + SolarMutexGuard aGuard; + Reference<XPropertySet> xThis(*this,UNO_QUERY); + OUString sTitle; + xThis->getPropertyValue(GetPropertyName(BASEPROPERTY_TITLE)) >>= sTitle; + return sTitle; +} +void SAL_CALL ControlModelContainerBase::setTitle( const OUString& _title ) +{ + SolarMutexGuard aGuard; + Reference<XPropertySet> xThis(*this,UNO_QUERY); + xThis->setPropertyValue(GetPropertyName(BASEPROPERTY_TITLE),Any(_title)); +} +OUString SAL_CALL ControlModelContainerBase::getImageURL() +{ + return m_sImageURL; +} +void SAL_CALL ControlModelContainerBase::setImageURL( const OUString& _imageurl ) +{ + m_sImageURL = _imageurl; +} +OUString SAL_CALL ControlModelContainerBase::getToolTip() +{ + return m_sTooltip; +} +void SAL_CALL ControlModelContainerBase::setToolTip( const OUString& _tooltip ) +{ + m_sTooltip = _tooltip; +} + + +namespace +{ + enum GroupingMachineState + { + eLookingForGroup, + eExpandingGroup + }; + + + sal_Int32 lcl_getDialogStep( const Reference< XControlModel >& _rxModel ) + { + sal_Int32 nStep = 0; + try + { + Reference< XPropertySet > xModelProps( _rxModel, UNO_QUERY ); + xModelProps->getPropertyValue( getStepPropertyName() ) >>= nStep; + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while determining the dialog page" ); + } + return nStep; + } +} + + +sal_Int32 SAL_CALL ControlModelContainerBase::getGroupCount( ) +{ + SolarMutexGuard aGuard; + + implUpdateGroupStructure(); + + return maGroups.size(); +} + + +void SAL_CALL ControlModelContainerBase::getGroup( sal_Int32 _nGroup, Sequence< Reference< XControlModel > >& _rGroup, OUString& _rName ) +{ + SolarMutexGuard aGuard; + + implUpdateGroupStructure(); + + if ( ( _nGroup < 0 ) || ( o3tl::make_unsigned(_nGroup) >= maGroups.size() ) ) + { + SAL_WARN("toolkit", "invalid argument and I am not allowed to throw exception!" ); + _rGroup.realloc( 0 ); + _rName.clear(); + } + else + { + AllGroups::const_iterator aGroupPos = maGroups.begin() + _nGroup; + _rGroup.realloc( aGroupPos->size() ); + // copy the models + ::std::copy( aGroupPos->begin(), aGroupPos->end(), _rGroup.getArray() ); + // give the group a name + _rName = OUString::number( _nGroup ); + } +} + + +void SAL_CALL ControlModelContainerBase::getGroupByName( const OUString& _rName, Sequence< Reference< XControlModel > >& _rGroup ) +{ + SolarMutexGuard aGuard; + + OUString sDummyName; + getGroup( _rName.toInt32( ), _rGroup, sDummyName ); +} + + +void SAL_CALL ControlModelContainerBase::addChangesListener( const Reference< XChangesListener >& _rxListener ) +{ + maChangeListeners.addInterface( _rxListener ); +} + + +void SAL_CALL ControlModelContainerBase::removeChangesListener( const Reference< XChangesListener >& _rxListener ) +{ + maChangeListeners.removeInterface( _rxListener ); +} + + +void ControlModelContainerBase::implNotifyTabModelChange( const OUString& _rAccessor ) +{ + // multiplex to our change listeners: + // the changes event + ChangesEvent aEvent; + aEvent.Source = *this; + aEvent.Base <<= aEvent.Source; // the "base of the changes root" is also ourself + aEvent.Changes.realloc( 1 ); // exactly one change + aEvent.Changes.getArray()[ 0 ].Accessor <<= _rAccessor; + + + std::vector< Reference< css::util::XChangesListener > > aChangeListeners( maChangeListeners.getElements() ); + for ( const auto& rListener : aChangeListeners ) + rListener->changesOccurred( aEvent ); +} + + +void ControlModelContainerBase::implUpdateGroupStructure() +{ + if ( mbGroupsUpToDate ) + // nothing to do + return; + + // conditions for a group: + // * all elements of the group are radio buttons + // * all elements of the group are on the same dialog page + // * in the overall control order (determined by the tab index), all elements are subsequent + + maGroups.clear(); + + const Sequence< Reference< XControlModel > > aControlModels = getControlModels(); + + // in extreme we have as much groups as controls + maGroups.reserve( aControlModels.getLength() ); + + GroupingMachineState eState = eLookingForGroup; // the current state of our machine + Reference< XServiceInfo > xModelSI; // for checking for a radio button + AllGroups::iterator aCurrentGroup = maGroups.end(); // the group which we're currently building + sal_Int32 nCurrentGroupStep = -1; // the step which all controls of the current group belong to + + + for ( const Reference< XControlModel >& rControlModel : aControlModels ) + { + // we'll need this in every state + xModelSI.set(rControlModel, css::uno::UNO_QUERY); + // is it a radio button? + bool bIsRadioButton = xModelSI.is() && xModelSI->supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" ); + + switch ( eState ) + { + case eLookingForGroup: + { + if ( !bIsRadioButton ) + // this is no radio button -> still looking for the beginning of a group + continue; + // the current model is a radio button + // -> we found the beginning of a new group + // create the place for this group + size_t nGroups = maGroups.size(); + maGroups.resize( nGroups + 1 ); + aCurrentGroup = maGroups.begin() + nGroups; + // and add the (only, til now) member + aCurrentGroup->push_back( rControlModel ); + + // get the step which all controls of this group now have to belong to + nCurrentGroupStep = lcl_getDialogStep( rControlModel ); + // new state: looking for further members + eState = eExpandingGroup; + + } + break; + + case eExpandingGroup: + { + if ( !bIsRadioButton ) + { // no radio button -> the group is done + aCurrentGroup = maGroups.end(); + eState = eLookingForGroup; + continue; + } + + // it is a radio button - is it on the proper page? + const sal_Int32 nThisModelStep = lcl_getDialogStep( rControlModel ); + if ( ( nThisModelStep == nCurrentGroupStep ) // the current button is on the same dialog page + || ( 0 == nThisModelStep ) // the current button appears on all pages + ) + { + // -> it belongs to the same group + aCurrentGroup->push_back( rControlModel ); + // state still is eExpandingGroup - we're looking for further elements + eState = eExpandingGroup; + + continue; + } + + // it's a radio button, but on a different page + // -> we open a new group for it + + + // open a new group + size_t nGroups = maGroups.size(); + maGroups.resize( nGroups + 1 ); + aCurrentGroup = maGroups.begin() + nGroups; + // and add the (only, til now) member + aCurrentGroup->push_back( rControlModel ); + + nCurrentGroupStep = nThisModelStep; + + // state is the same: we still are looking for further elements of the current group + eState = eExpandingGroup; + } + break; + } + } + + mbGroupsUpToDate = true; +} + + +void SAL_CALL ControlModelContainerBase::propertyChange( const PropertyChangeEvent& _rEvent ) +{ + SolarMutexGuard aGuard; + + DBG_ASSERT( _rEvent.PropertyName == "TabIndex", + "ControlModelContainerBase::propertyChange: not listening for this property!" ); + + // the accessor for the changed element + OUString sAccessor; + UnoControlModelHolderVector::const_iterator aPos = + ::std::find_if( + maModels.begin(), maModels.end(), + CompareControlModel( Reference< XControlModel >( _rEvent.Source, UNO_QUERY ) ) + ); + OSL_ENSURE( maModels.end() != aPos, "ControlModelContainerBase::propertyChange: don't know this model!" ); + if ( maModels.end() != aPos ) + sAccessor = aPos->second; + + // our groups are not up-to-date + mbGroupsUpToDate = false; + + // notify + implNotifyTabModelChange( sAccessor ); +} + + +void SAL_CALL ControlModelContainerBase::disposing( const EventObject& /*rEvent*/ ) +{ +} + + +void ControlModelContainerBase::startControlListening( const Reference< XControlModel >& _rxChildModel ) +{ + SolarMutexGuard aGuard; + + Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY ); + Reference< XPropertySetInfo > xPSI; + if ( xModelProps.is() ) + xPSI = xModelProps->getPropertySetInfo(); + + if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) ) + xModelProps->addPropertyChangeListener( getTabIndexPropertyName(), this ); +} + + +void ControlModelContainerBase::stopControlListening( const Reference< XControlModel >& _rxChildModel ) +{ + SolarMutexGuard aGuard; + + Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY ); + Reference< XPropertySetInfo > xPSI; + if ( xModelProps.is() ) + xPSI = xModelProps->getPropertySetInfo(); + + if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) ) + xModelProps->removePropertyChangeListener( getTabIndexPropertyName(), this ); +} + + +// = class ResourceListener + + +ResourceListener::ResourceListener( + const Reference< util::XModifyListener >& rListener ) : + m_xListener( rListener ), + m_bListening( false ) +{ +} + +ResourceListener::~ResourceListener() +{ +} + +// XInterface +Any SAL_CALL ResourceListener::queryInterface( const Type& rType ) +{ + Any a = ::cppu::queryInterface( + rType , + static_cast< XModifyListener* >( this ), + static_cast< XEventListener* >( this )); + + if ( a.hasValue() ) + return a; + + return OWeakObject::queryInterface( rType ); +} + +void SAL_CALL ResourceListener::acquire() noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL ResourceListener::release() noexcept +{ + OWeakObject::release(); +} + +void ResourceListener::startListening( + const Reference< resource::XStringResourceResolver >& rResource ) +{ + { + // --- SAFE --- + std::unique_lock aGuard( m_aMutex ); + bool bListening( m_bListening ); + bool bResourceSet( m_xResource.is() ); + aGuard.unlock(); + // --- SAFE --- + + if ( bListening && bResourceSet ) + stopListening(); + + // --- SAFE --- + aGuard.lock(); + m_xResource = rResource; + aGuard.unlock(); + // --- SAFE --- + } + + if ( !rResource.is() ) + return; + + try + { + rResource->addModifyListener( this ); + + // --- SAFE --- + std::scoped_lock aGuard( m_aMutex ); + m_bListening = true; + // --- SAFE --- + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + } +} + +void ResourceListener::stopListening() +{ + Reference< util::XModifyBroadcaster > xModifyBroadcaster; + + // --- SAFE --- + std::unique_lock aGuard( m_aMutex ); + if ( m_bListening && m_xResource.is() ) + xModifyBroadcaster = m_xResource; + aGuard.unlock(); + // --- SAFE --- + + if ( !xModifyBroadcaster.is() ) + return; + + try + { + // --- SAFE --- + aGuard.lock(); + m_bListening = false; + m_xResource.clear(); + aGuard.unlock(); + // --- SAFE --- + + xModifyBroadcaster->removeModifyListener( this ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + } +} + +// XModifyListener +void SAL_CALL ResourceListener::modified( + const lang::EventObject& aEvent ) +{ + Reference< util::XModifyListener > xListener; + + // --- SAFE --- + std::unique_lock aGuard( m_aMutex ); + xListener = m_xListener; + aGuard.unlock(); + // --- SAFE --- + + if ( !xListener.is() ) + return; + + try + { + xListener->modified( aEvent ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + } +} + +// XEventListener +void SAL_CALL ResourceListener::disposing( + const EventObject& Source ) +{ + Reference< lang::XEventListener > xListener; + Reference< resource::XStringResourceResolver > xResource; + + // --- SAFE --- + std::unique_lock aGuard( m_aMutex ); + Reference< XInterface > xIfacRes( m_xResource, UNO_QUERY ); + Reference< XInterface > xIfacList( m_xListener, UNO_QUERY ); + aGuard.unlock(); + // --- SAFE --- + + if ( Source.Source == xIfacRes ) + { + // --- SAFE --- + aGuard.lock(); + m_bListening = false; + xResource = m_xResource; + xListener = m_xListener; + m_xResource.clear(); + aGuard.unlock(); + // --- SAFE --- + + if ( xListener.is() ) + { + try + { + xListener->disposing( Source ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + } + } + } + else if ( Source.Source == xIfacList ) + { + // --- SAFE --- + aGuard.lock(); + m_bListening = false; + xListener = m_xListener; + xResource = m_xResource; + m_xResource.clear(); + m_xListener.clear(); + aGuard.unlock(); + // --- SAFE --- + + // Remove ourself as listener from resource resolver + if ( xResource.is() ) + { + try + { + xResource->removeModifyListener( this ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + } + } + } +} + + + +ControlContainerBase::ControlContainerBase( const Reference< XComponentContext >& rxContext ) + :m_xContext(rxContext) + ,mbSizeModified(false) + ,mbPosModified(false) +{ + maComponentInfos.nWidth = 280; + maComponentInfos.nHeight = 400; + mxListener = new ResourceListener( Reference< util::XModifyListener >(this) ); +} + +ControlContainerBase::~ControlContainerBase() +{ +} + +void ControlContainerBase::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) +{ + SolarMutexGuard aGuard; + UnoControlContainer::createPeer( rxToolkit, rParentPeer ); +} + +void ControlContainerBase::ImplInsertControl( Reference< XControlModel > const & rxModel, const OUString& rName ) +{ + Reference< XPropertySet > xP( rxModel, UNO_QUERY ); + + OUString aDefCtrl; + xP->getPropertyValue( GetPropertyName( BASEPROPERTY_DEFAULTCONTROL ) ) >>= aDefCtrl; + Reference < XControl > xCtrl( m_xContext->getServiceManager()->createInstanceWithContext(aDefCtrl, m_xContext), UNO_QUERY ); + + DBG_ASSERT( xCtrl.is(), "ControlContainerBase::ImplInsertControl: could not create the control!" ); + if ( xCtrl.is() ) + { + xCtrl->setModel( rxModel ); + addControl( rName, xCtrl ); + // will implicitly call addingControl, where we can add the PropertiesChangeListener to the model + // (which we formerly did herein) + // 08.01.2001 - 96008 - fs@openoffice.org + + ImplSetPosSize( xCtrl ); + } +} + +void ControlContainerBase::ImplRemoveControl( Reference< XControlModel > const & rxModel ) +{ + Sequence< Reference< XControl > > aControls = getControls(); + Reference< XControl > xCtrl = StdTabController::FindControl( aControls, rxModel ); + if ( xCtrl.is() ) + { + removeControl( xCtrl ); + try + { + xCtrl->dispose(); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } +} + +void ControlContainerBase::ImplSetPosSize( Reference< XControl >& rxCtrl ) +{ + Reference< XPropertySet > xP( rxCtrl->getModel(), UNO_QUERY ); + + sal_Int32 nX = 0, nY = 0, nWidth = 0, nHeight = 0; + xP->getPropertyValue("PositionX") >>= nX; + xP->getPropertyValue("PositionY") >>= nY; + xP->getPropertyValue("Width") >>= nWidth; + xP->getPropertyValue("Height") >>= nHeight; + MapMode aMode( MapUnit::MapAppFont ); + OutputDevice*pOutDev = Application::GetDefaultDevice(); + if ( pOutDev ) + { + ::Size aTmp( nX, nY ); + aTmp = pOutDev->LogicToPixel( aTmp, aMode ); + nX = aTmp.Width(); + nY = aTmp.Height(); + aTmp = ::Size( nWidth, nHeight ); + aTmp = pOutDev->LogicToPixel( aTmp, aMode ); + nWidth = aTmp.Width(); + nHeight = aTmp.Height(); + } + else + { + Reference< XWindowPeer > xPeer = ImplGetCompatiblePeer(); + Reference< XDevice > xD( xPeer, UNO_QUERY ); + + SimpleFontMetric aFM; + FontDescriptor aFD; + Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR ) ); + aVal >>= aFD; + if ( !aFD.StyleName.isEmpty() ) + { + Reference< XFont > xFont = xD->getFont( aFD ); + aFM = xFont->getFontMetric(); + } + else + { + Reference< XGraphics > xG = xD->createGraphics(); + aFM = xG->getFontMetric(); + } + + sal_Int16 nH = aFM.Ascent + aFM.Descent; + sal_Int16 nW = nH/2; // calculate average width?! + + nX *= nW; + nX /= 4; + nWidth *= nW; + nWidth /= 4; + nY *= nH; + nY /= 8; + nHeight *= nH; + nHeight /= 8; + } + Reference < XWindow > xW( rxCtrl, UNO_QUERY ); + xW->setPosSize( nX, nY, nWidth, nHeight, PosSize::POSSIZE ); +} + +void ControlContainerBase::dispose() +{ + EventObject aEvt; + aEvt.Source = static_cast< ::cppu::OWeakObject* >( this ); + // Notify our listener helper about dispose + // --- SAFE --- + + SolarMutexClearableGuard aGuard; + Reference< XEventListener > xListener = mxListener; + mxListener.clear(); + aGuard.clear(); + // --- SAFE --- + + if ( xListener.is() ) + xListener->disposing( aEvt ); + UnoControlContainer::dispose(); +} + +void SAL_CALL ControlContainerBase::disposing( + const EventObject& Source ) +{ + UnoControlContainer::disposing( Source ); +} + +sal_Bool ControlContainerBase::setModel( const Reference< XControlModel >& rxModel ) +{ + SolarMutexGuard aGuard; + + // destroy the old tab controller, if existent + if ( mxTabController.is() ) + { + mxTabController->setModel( nullptr ); // just to be sure, should not be necessary + removeTabController( mxTabController ); + ::comphelper::disposeComponent( mxTabController ); // just to be sure, should not be necessary + mxTabController.clear(); + } + + if ( getModel().is() ) + { + const Sequence< Reference< XControl > > aControls = getControls(); + + for ( const Reference< XControl >& rCtrl : aControls ) + removeControl( rCtrl ); + // will implicitly call removingControl, which will remove the PropertyChangeListener + // (which we formerly did herein) + // 08.01.2001 - 96008 - fs@openoffice.org + + Reference< XContainer > xC( getModel(), UNO_QUERY ); + if ( xC.is() ) + xC->removeContainerListener( this ); + + Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY ); + if ( xChangeNotifier.is() ) + xChangeNotifier->removeChangesListener( this ); + } + + bool bRet = UnoControl::setModel( rxModel ); + + if ( getModel().is() ) + { + Reference< XNameAccess > xNA( getModel(), UNO_QUERY ); + if ( xNA.is() ) + { + const Sequence< OUString > aNames = xNA->getElementNames(); + + Reference< XControlModel > xCtrlModel; + for( const OUString& rName : aNames ) + { + xNA->getByName( rName ) >>= xCtrlModel; + ImplInsertControl( xCtrlModel, rName ); + } + } + + Reference< XContainer > xC( getModel(), UNO_QUERY ); + if ( xC.is() ) + xC->addContainerListener( this ); + + Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY ); + if ( xChangeNotifier.is() ) + xChangeNotifier->addChangesListener( this ); + } + + Reference< XTabControllerModel > xTabbing( getModel(), UNO_QUERY ); + if ( xTabbing.is() ) + { + mxTabController = new StdTabController; + mxTabController->setModel( xTabbing ); + addTabController( mxTabController ); + } + ImplStartListingForResourceEvents(); + + return bRet; +} +void ControlContainerBase::setDesignMode( sal_Bool bOn ) +{ + SolarMutexGuard aGuard; + + UnoControl::setDesignMode( bOn ); + + Sequence< Reference< XControl > > xCtrls = getControls(); + for ( Reference< XControl >& rControl : asNonConstRange(xCtrls) ) + rControl->setDesignMode( bOn ); + + // #109067# in design mode the tab controller is not notified about + // tab index changes, therefore the tab order must be activated + // when switching from design mode to live mode + if ( mxTabController.is() && !bOn ) + mxTabController->activateTabOrder(); +} + +void ControlContainerBase::elementInserted( const ContainerEvent& Event ) +{ + SolarMutexGuard aGuard; + + Reference< XControlModel > xModel; + OUString aName; + + Event.Accessor >>= aName; + Event.Element >>= xModel; + ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementInserted: illegal element!" ); + try + { + ImplInsertControl( xModel, aName ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } +} + +void ControlContainerBase::elementRemoved( const ContainerEvent& Event ) +{ + SolarMutexGuard aGuard; + + Reference< XControlModel > xModel; + Event.Element >>= xModel; + ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementRemoved: illegal element!" ); + try + { + ImplRemoveControl( xModel ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } +} + +void ControlContainerBase::elementReplaced( const ContainerEvent& Event ) +{ + SolarMutexGuard aGuard; + + Reference< XControlModel > xModel; + Event.ReplacedElement >>= xModel; + try + { + OSL_ENSURE( xModel.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" ); + if ( xModel.is() ) + ImplRemoveControl( xModel ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + + OUString aName; + Event.Accessor >>= aName; + Event.Element >>= xModel; + ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementReplaced: invalid new element!" ); + try + { + ImplInsertControl( xModel, aName ); + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } +} + +// XPropertiesChangeListener +void ControlContainerBase::ImplModelPropertiesChanged( const Sequence< PropertyChangeEvent >& rEvents ) +{ + if( !isDesignMode() && !mbCreatingCompatiblePeer ) + { + auto pEvt = std::find_if(rEvents.begin(), rEvents.end(), + [](const PropertyChangeEvent& rEvt) { + return rEvt.PropertyName == "PositionX" + || rEvt.PropertyName == "PositionY" + || rEvt.PropertyName == "Width" + || rEvt.PropertyName == "Height"; + }); + if (pEvt != rEvents.end()) + { + Reference< XControlModel > xModel( pEvt->Source, UNO_QUERY ); + bool bOwnModel = xModel.get() == getModel().get(); + if ( bOwnModel ) + { + if ( !mbPosModified && !mbSizeModified ) + { + // Don't set new pos/size if we get new values from window listener + Reference< XControl > xThis(this); + ImplSetPosSize( xThis ); + } + } + else + { + Sequence<Reference<XControl> > aControlSequence(getControls()); + Reference<XControl> aControlRef( StdTabController::FindControl( aControlSequence, xModel ) ); + ImplSetPosSize( aControlRef ); + } + } + } + + UnoControlContainer::ImplModelPropertiesChanged( rEvents ); +} + +void ControlContainerBase::addingControl( const Reference< XControl >& _rxControl ) +{ + SolarMutexGuard aGuard; + UnoControlContainer::addingControl( _rxControl ); + + if ( !_rxControl.is() ) + return; + + Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY ); + if ( xProps.is() ) + { + const Sequence< OUString > aNames { + "PositionX", + "PositionY", + "Width", + "Height" + }; + + xProps->addPropertiesChangeListener( aNames, this ); + } +} + +void ControlContainerBase::removingControl( const Reference< XControl >& _rxControl ) +{ + SolarMutexGuard aGuard; + UnoControlContainer::removingControl( _rxControl ); + + if ( _rxControl.is() ) + { + Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY ); + if ( xProps.is() ) + xProps->removePropertiesChangeListener( this ); + } + +} + +void SAL_CALL ControlContainerBase::changesOccurred( const ChangesEvent& ) +{ + SolarMutexGuard aGuard; + // a tab controller model may have changed + + // #109067# in design mode don't notify the tab controller + // about tab index changes + if ( mxTabController.is() && !mbDesignMode ) + mxTabController->activateTabOrder(); +} +static void lcl_ApplyResolverToNestedContainees( const Reference< resource::XStringResourceResolver >& xStringResourceResolver, const Reference< XControlContainer >& xContainer ) +{ + OUString aPropName( PROPERTY_RESOURCERESOLVER ); + + Any aNewStringResourceResolver; + aNewStringResourceResolver <<= xStringResourceResolver; + + Sequence< OUString > aPropNames { aPropName }; + + const Sequence< Reference< awt::XControl > > aSeq = xContainer->getControls(); + for ( const Reference< XControl >& xControl : aSeq ) + { + Reference< XPropertySet > xPropertySet; + + if ( xControl.is() ) + xPropertySet.set( xControl->getModel(), UNO_QUERY ); + + if ( !xPropertySet.is() ) + continue; + + try + { + Reference< resource::XStringResourceResolver > xCurrStringResourceResolver; + Any aOldValue = xPropertySet->getPropertyValue( aPropName ); + if ( ( aOldValue >>= xCurrStringResourceResolver ) + && ( xStringResourceResolver == xCurrStringResourceResolver ) + ) + { + Reference< XMultiPropertySet > xMultiPropSet( xPropertySet, UNO_QUERY ); + Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY ); + xMultiPropSet->firePropertiesChangeEvent( aPropNames, xListener ); + } + else + xPropertySet->setPropertyValue( aPropName, aNewStringResourceResolver ); + } + catch (const Exception&) + { + } + + uno::Reference< XControlContainer > xNestedContainer( xControl, uno::UNO_QUERY ); + if ( xNestedContainer.is() ) + lcl_ApplyResolverToNestedContainees( xStringResourceResolver, xNestedContainer ); + + } + +} +void ControlContainerBase::ImplStartListingForResourceEvents() +{ + Reference< resource::XStringResourceResolver > xStringResourceResolver; + + if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER) ) + return; + + ImplGetPropertyValue( PROPERTY_RESOURCERESOLVER ) >>= xStringResourceResolver; + + // Add our helper as listener to retrieve notifications about changes + Reference< util::XModifyListener > rListener( mxListener ); + ResourceListener* pResourceListener = static_cast< ResourceListener* >( rListener.get() ); + + // resource listener will stop listening if resolver reference is empty + if ( pResourceListener ) + pResourceListener->startListening( xStringResourceResolver ); + ImplUpdateResourceResolver(); +} + +void ControlContainerBase::ImplUpdateResourceResolver() +{ + Reference< resource::XStringResourceResolver > xStringResourceResolver; + + if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER) ) + return; + + ImplGetPropertyValue(PROPERTY_RESOURCERESOLVER) >>= xStringResourceResolver; + + if ( !xStringResourceResolver.is() ) + return; + + lcl_ApplyResolverToNestedContainees( xStringResourceResolver, this ); + + // propagate resource resolver changes to language dependent props of the dialog + Reference< XPropertySet > xPropertySet( getModel(), UNO_QUERY ); + if ( xPropertySet.is() ) + { + Reference< XMultiPropertySet > xMultiPropSet( xPropertySet, UNO_QUERY ); + Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY ); + xMultiPropSet->firePropertiesChangeEvent( lcl_getLanguageDependentProperties(), xListener ); + } +} + +//// ---------------------------------------------------- +//// Helper Method to convert relative url to physical location +//// ---------------------------------------------------- + +OUString getPhysicalLocation( const css::uno::Any& rbase, const css::uno::Any& rUrl ) +{ + + OUString baseLocation; + OUString url; + + rbase >>= baseLocation; + rUrl >>= url; + + OUString absoluteURL( url ); + if ( !url.isEmpty() ) + { + INetURLObject urlObj(baseLocation); + urlObj.removeSegment(); + baseLocation = urlObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + const INetURLObject protocolCheck( url ); + const INetProtocol protocol = protocolCheck.GetProtocol(); + if ( protocol == INetProtocol::NotValid ) + { + OUString testAbsoluteURL; + if ( ::osl::FileBase::E_None == ::osl::FileBase::getAbsoluteFileURL( baseLocation, url, testAbsoluteURL ) ) + absoluteURL = testAbsoluteURL; + } + } + + return absoluteURL; +} + +void +ControlModelContainerBase::updateUserFormChildren( const Reference< XNameContainer >& xAllChildren, const OUString& aName, ChildOperation Operation, const css::uno::Reference< css::awt::XControlModel >& xTarget ) +{ + if ( Operation < Insert || Operation > Remove ) + throw IllegalArgumentException(); + + if ( !xAllChildren.is() ) + throw IllegalArgumentException(); + + if ( Operation == Remove ) + { + Reference< XControlModel > xOldModel( xAllChildren->getByName( aName ), UNO_QUERY ); + xAllChildren->removeByName( aName ); + + Reference< XNameContainer > xChildContainer( xOldModel, UNO_QUERY ); + if ( xChildContainer.is() ) + { + Reference< XPropertySet > xProps( xChildContainer, UNO_QUERY ); + // container control is being removed from this container, reset the + // global list of containers + if ( xProps.is() ) + xProps->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ), uno::Any( uno::Reference< XNameContainer >() ) ); + const Sequence< OUString > aChildNames = xChildContainer->getElementNames(); + for ( const auto& rName : aChildNames ) + updateUserFormChildren( xAllChildren, rName, Operation, Reference< XControlModel > () ); + } + } + else if ( Operation == Insert ) + { + xAllChildren->insertByName( aName, uno::Any( xTarget ) ); + Reference< XNameContainer > xChildContainer( xTarget, UNO_QUERY ); + if ( xChildContainer.is() ) + { + // container control is being added from this container, reset the + // global list of containers to point to the correct global list + Reference< XPropertySet > xProps( xChildContainer, UNO_QUERY ); + if ( xProps.is() ) + xProps->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ), uno::Any( xAllChildren ) ); + const Sequence< OUString > aChildNames = xChildContainer->getElementNames(); + for ( const auto& rName : aChildNames ) + { + Reference< XControlModel > xChildTarget( xChildContainer->getByName( rName ), UNO_QUERY ); + updateUserFormChildren( xAllChildren, rName, Operation, xChildTarget ); + } + } + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/controlmodelcontainerbase_internal.hxx b/toolkit/source/controls/controlmodelcontainerbase_internal.hxx new file mode 100644 index 000000000..c65cabc8a --- /dev/null +++ b/toolkit/source/controls/controlmodelcontainerbase_internal.hxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_TOOLKIT_SOURCE_CONTROLS_CONTROLMODELCONTAINERBASE_INTERNAL_HXX +#define INCLUDED_TOOLKIT_SOURCE_CONTROLS_CONTROLMODELCONTAINERBASE_INTERNAL_HXX + +#include <com/sun/star/uno/Any.hxx> + +////HELPER +OUString getPhysicalLocation(const css::uno::Any& rbase, const css::uno::Any& rUrl); + +#endif // INCLUDED_TOOLKIT_SOURCE_CONTROLS_CONTROLMODELCONTAINERBASE_INTERNAL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/dialogcontrol.cxx b/toolkit/source/controls/dialogcontrol.cxx new file mode 100644 index 000000000..67ee3bcc6 --- /dev/null +++ b/toolkit/source/controls/dialogcontrol.cxx @@ -0,0 +1,1244 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <algorithm> + +#include <sal/types.h> +#include <vcl/svapp.hxx> +#include <controls/dialogcontrol.hxx> +#include <controls/geometrycontrolmodel.hxx> +#include <toolkit/helper/property.hxx> +#include <helper/servicenames.hxx> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/awt/WindowAttribute.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/weak.hxx> +#include <tools/debug.hxx> +#include <comphelper/sequence.hxx> +#include <vcl/outdev.hxx> + +#include <vcl/image.hxx> +#include <cppuhelper/implbase.hxx> +#include <unordered_map> + +#include <vcl/tabctrl.hxx> +#include <toolkit/controls/unocontrols.hxx> + +#include <awt/vclxwindows.hxx> +#include <helper/unopropertyarrayhelper.hxx> +#include "controlmodelcontainerbase_internal.hxx" +#include <mutex> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; + +constexpr OUStringLiteral PROPERTY_DIALOGSOURCEURL = u"DialogSourceURL"; +constexpr OUStringLiteral PROPERTY_IMAGEURL = u"ImageURL"; +constexpr OUStringLiteral PROPERTY_GRAPHIC = u"Graphic"; + + +// we probably will need both a hash of control models and hash of controls +// => use some template magic + +namespace { + +template< typename T > +class SimpleNamedThingContainer : public ::cppu::WeakImplHelper< container::XNameContainer > +{ + std::unordered_map< OUString, Reference< T > > things; + std::mutex m_aMutex; +public: + // css::container::XNameContainer, XNameReplace, XNameAccess + virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) override + { + std::scoped_lock aGuard( m_aMutex ); + auto it = things.find( aName ); + if ( it == things.end() ) + throw NoSuchElementException(); + Reference< T > xElement; + if ( ! ( aElement >>= xElement ) ) + throw IllegalArgumentException(); + it->second = xElement; + } + virtual Any SAL_CALL getByName( const OUString& aName ) override + { + std::scoped_lock aGuard( m_aMutex ); + auto it = things.find( aName ); + if ( it == things.end() ) + throw NoSuchElementException(); + return uno::Any( it->second ); + } + virtual Sequence< OUString > SAL_CALL getElementNames( ) override + { + std::scoped_lock aGuard( m_aMutex ); + return comphelper::mapKeysToSequence( things ); + } + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + std::scoped_lock aGuard( m_aMutex ); + return ( things.find( aName ) != things.end() ); + } + virtual void SAL_CALL insertByName( const OUString& aName, const Any& aElement ) override + { + std::scoped_lock aGuard( m_aMutex ); + auto it = things.find( aName ); + if ( it != things.end() ) + throw ElementExistException(); + Reference< T > xElement; + if ( ! ( aElement >>= xElement ) ) + throw IllegalArgumentException(); + things[ aName ] = xElement; + } + virtual void SAL_CALL removeByName( const OUString& aName ) override + { + std::scoped_lock aGuard( m_aMutex ); + if ( things.erase( aName ) == 0 ) + throw NoSuchElementException(); + } + virtual Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<T>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + std::scoped_lock aGuard( m_aMutex ); + return !things.empty(); + } +}; + +class UnoControlDialogModel : public ControlModelContainerBase +{ +protected: + css::uno::Reference< css::graphic::XGraphicObject > mxGrfObj; + css::uno::Any ImplGetDefaultValue( sal_uInt16 nPropId ) const override; + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + // ::cppu::OPropertySetHelper + void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override; +public: + explicit UnoControlDialogModel( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + UnoControlDialogModel( const UnoControlDialogModel& rModel ); + + rtl::Reference<UnoControlModel> Clone() const override; + // css::beans::XMultiPropertySet + css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // css::io::XPersistObject + OUString SAL_CALL getServiceName() override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "stardiv.Toolkit.UnoControlDialogModel"; } + + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override + { + auto s(ControlModelContainerBase::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlDialogModel"; + ps[s.getLength() - 1] = "stardiv.vcl.controlmodel.Dialog"; + return s; + } +}; + +UnoControlDialogModel::UnoControlDialogModel( const Reference< XComponentContext >& rxContext ) + :ControlModelContainerBase( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); +// ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); +// ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_TITLE ); + ImplRegisterProperty( BASEPROPERTY_SIZEABLE ); + ImplRegisterProperty( BASEPROPERTY_DESKTOP_AS_PARENT ); + ImplRegisterProperty( BASEPROPERTY_DECORATION ); + ImplRegisterProperty( BASEPROPERTY_DIALOGSOURCEURL ); + ImplRegisterProperty( BASEPROPERTY_GRAPHIC ); + ImplRegisterProperty( BASEPROPERTY_IMAGEURL ); + ImplRegisterProperty( BASEPROPERTY_HSCROLL ); + ImplRegisterProperty( BASEPROPERTY_VSCROLL ); + ImplRegisterProperty( BASEPROPERTY_SCROLLWIDTH ); + ImplRegisterProperty( BASEPROPERTY_SCROLLHEIGHT ); + ImplRegisterProperty( BASEPROPERTY_SCROLLTOP ); + ImplRegisterProperty( BASEPROPERTY_SCROLLLEFT ); + + Any aBool; + aBool <<= true; + ImplRegisterProperty( BASEPROPERTY_MOVEABLE, aBool ); + ImplRegisterProperty( BASEPROPERTY_CLOSEABLE, aBool ); + // #TODO separate class for 'UserForm' ( instead of re-using Dialog ? ) + uno::Reference< XNameContainer > xNameCont = new SimpleNamedThingContainer< XControlModel >; + ImplRegisterProperty( BASEPROPERTY_USERFORMCONTAINEES, uno::Any( xNameCont ) ); +} + +UnoControlDialogModel::UnoControlDialogModel( const UnoControlDialogModel& rModel ) + : ControlModelContainerBase( rModel ) +{ + // need to clone BASEPROPERTY_USERFORMCONTAINEES too + Reference< XNameContainer > xSrcNameCont( const_cast< UnoControlDialogModel& >(rModel).getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY ); + Reference<XNameContainer > xNameCont( new SimpleNamedThingContainer< XControlModel > ); + + const uno::Sequence< OUString > sNames = xSrcNameCont->getElementNames(); + for ( OUString const & name : sNames ) + { + if ( xSrcNameCont->hasByName( name ) ) + xNameCont->insertByName( name, xSrcNameCont->getByName( name ) ); + } + setFastPropertyValue_NoBroadcast( BASEPROPERTY_USERFORMCONTAINEES, Any( xNameCont ) ); +} + +rtl::Reference<UnoControlModel> UnoControlDialogModel::Clone() const +{ + // clone the container itself + rtl::Reference<UnoControlDialogModel> pClone = new UnoControlDialogModel( *this ); + + Clone_Impl(*pClone); + + return pClone; +} + + +OUString UnoControlDialogModel::getServiceName( ) +{ + return "stardiv.vcl.controlmodel.Dialog"; +} + +Any UnoControlDialogModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + Any aAny; + + switch ( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + aAny <<= OUString::createFromAscii( szServiceName_UnoControlDialog ); + break; + case BASEPROPERTY_SCROLLWIDTH: + case BASEPROPERTY_SCROLLHEIGHT: + case BASEPROPERTY_SCROLLTOP: + case BASEPROPERTY_SCROLLLEFT: + aAny <<= sal_Int32(0); + break; + default: + aAny = UnoControlModel::ImplGetDefaultValue( nPropId ); + } + + return aAny; +} + +::cppu::IPropertyArrayHelper& UnoControlDialogModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// XMultiPropertySet +Reference< XPropertySetInfo > UnoControlDialogModel::getPropertySetInfo( ) +{ + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +void SAL_CALL UnoControlDialogModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) +{ + ControlModelContainerBase::setFastPropertyValue_NoBroadcast( nHandle, rValue ); + try + { + if ( nHandle == BASEPROPERTY_IMAGEURL && ImplHasProperty( BASEPROPERTY_GRAPHIC ) ) + { + OUString sImageURL; + uno::Reference<graphic::XGraphic> xGraphic; + if (rValue >>= sImageURL) + { + setPropertyValue( + GetPropertyName(BASEPROPERTY_GRAPHIC), + uno::Any(ImageHelper::getGraphicAndGraphicObjectFromURL_nothrow( + mxGrfObj, sImageURL))); + } + else if (rValue >>= xGraphic) + { + setPropertyValue("Graphic", uno::Any(xGraphic)); + } + } + } + catch( const css::uno::Exception& ) + { + OSL_ENSURE( false, "UnoControlDialogModel::setFastPropertyValue_NoBroadcast: caught an exception while setting ImageURL properties!" ); + } +} + +} + + +// = class UnoDialogControl + + +UnoDialogControl::UnoDialogControl( const uno::Reference< uno::XComponentContext >& rxContext ) + :UnoDialogControl_Base( rxContext ) + ,maTopWindowListeners( *this ) + ,mbWindowListener(false) +{ + maComponentInfos.nWidth = 300; + maComponentInfos.nHeight = 450; + } + +UnoDialogControl::~UnoDialogControl() +{ +} + +OUString UnoDialogControl::GetComponentServiceName() const +{ + + bool bDecoration( true ); + ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_DECORATION )) >>= bDecoration; + if ( bDecoration ) + return "Dialog"; + else + return "TabPage"; +} + +void UnoDialogControl::dispose() +{ + SolarMutexGuard aGuard; + + EventObject aEvt; + aEvt.Source = static_cast< ::cppu::OWeakObject* >( this ); + maTopWindowListeners.disposeAndClear( aEvt ); + ControlContainerBase::dispose(); +} + +void SAL_CALL UnoDialogControl::disposing( + const EventObject& Source ) +{ + ControlContainerBase::disposing( Source ); +} + +sal_Bool UnoDialogControl::setModel( const Reference< XControlModel >& rxModel ) +{ + // #Can we move all the Resource stuff to the ControlContainerBase ? + SolarMutexGuard aGuard; + bool bRet = ControlContainerBase::setModel( rxModel ); + ImplStartListingForResourceEvents(); + return bRet; +} + +void UnoDialogControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) +{ + SolarMutexGuard aGuard; + + UnoControlContainer::createPeer( rxToolkit, rParentPeer ); + + Reference < XTopWindow > xTW( getPeer(), UNO_QUERY ); + if ( !xTW.is() ) + return; + + xTW->setMenuBar( mxMenuBar ); + + if ( !mbWindowListener ) + { + Reference< XWindowListener > xWL(this); + addWindowListener( xWL ); + mbWindowListener = true; + } + + if ( maTopWindowListeners.getLength() ) + xTW->addTopWindowListener( &maTopWindowListeners ); + // there must be a better way than doing this, we can't + // process the scrolltop & scrollleft in XDialog because + // the children haven't been added when those props are applied + ImplSetPeerProperty( GetPropertyName( BASEPROPERTY_SCROLLTOP ), ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_SCROLLTOP ) ) ); + ImplSetPeerProperty( GetPropertyName( BASEPROPERTY_SCROLLLEFT ), ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_SCROLLLEFT ) ) ); +} + +OUString UnoDialogControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoDialogControl"; +} + +sal_Bool UnoDialogControl::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> UnoDialogControl::getSupportedServiceNames() +{ + return css::uno::Sequence<OUString>{ + "com.sun.star.awt.UnoControlDialog", + "stardiv.vcl.control.Dialog"}; +} + +void UnoDialogControl::PrepareWindowDescriptor( css::awt::WindowDescriptor& rDesc ) +{ + UnoControlContainer::PrepareWindowDescriptor( rDesc ); + bool bDecoration( true ); + ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_DECORATION )) >>= bDecoration; + if ( !bDecoration ) + { + // Now we have to manipulate the WindowDescriptor + rDesc.WindowAttributes = rDesc.WindowAttributes | css::awt::WindowAttribute::NODECORATION; + } + + // We have to set the graphic property before the peer + // will be created. Otherwise the properties will be copied + // into the peer via propertiesChangeEvents. As the order of + // can lead to overwrites we have to set the graphic property + // before the propertiesChangeEvents are sent! + OUString aImageURL; + Reference< graphic::XGraphic > xGraphic; + if (( ImplGetPropertyValue( PROPERTY_IMAGEURL ) >>= aImageURL ) && + ( !aImageURL.isEmpty() )) + { + OUString absoluteUrl = getPhysicalLocation(ImplGetPropertyValue(PROPERTY_DIALOGSOURCEURL), uno::Any(aImageURL)); + xGraphic = ImageHelper::getGraphicFromURL_nothrow( absoluteUrl ); + ImplSetPropertyValue( PROPERTY_GRAPHIC, uno::Any( xGraphic ), true ); + } +} + +void UnoDialogControl::addTopWindowListener( const Reference< XTopWindowListener >& rxListener ) +{ + maTopWindowListeners.addInterface( rxListener ); + if( getPeer().is() && maTopWindowListeners.getLength() == 1 ) + { + Reference < XTopWindow > xTW( getPeer(), UNO_QUERY ); + xTW->addTopWindowListener( &maTopWindowListeners ); + } +} + +void UnoDialogControl::removeTopWindowListener( const Reference< XTopWindowListener >& rxListener ) +{ + if( getPeer().is() && maTopWindowListeners.getLength() == 1 ) + { + Reference < XTopWindow > xTW( getPeer(), UNO_QUERY ); + xTW->removeTopWindowListener( &maTopWindowListeners ); + } + maTopWindowListeners.removeInterface( rxListener ); +} + +void UnoDialogControl::toFront( ) +{ + SolarMutexGuard aGuard; + if ( getPeer().is() ) + { + Reference< XTopWindow > xTW( getPeer(), UNO_QUERY ); + if( xTW.is() ) + xTW->toFront(); + } +} + +void UnoDialogControl::toBack( ) +{ + SolarMutexGuard aGuard; + if ( getPeer().is() ) + { + Reference< XTopWindow > xTW( getPeer(), UNO_QUERY ); + if( xTW.is() ) + xTW->toBack(); + } +} + +void UnoDialogControl::setMenuBar( const Reference< XMenuBar >& rxMenuBar ) +{ + SolarMutexGuard aGuard; + mxMenuBar = rxMenuBar; + if ( getPeer().is() ) + { + Reference< XTopWindow > xTW( getPeer(), UNO_QUERY ); + if( xTW.is() ) + xTW->setMenuBar( mxMenuBar ); + } +} +static ::Size ImplMapPixelToAppFont( OutputDevice const * pOutDev, const ::Size& aSize ) +{ + ::Size aTmp = pOutDev->PixelToLogic(aSize, MapMode(MapUnit::MapAppFont)); + return aTmp; +} +// css::awt::XWindowListener +void SAL_CALL UnoDialogControl::windowResized( const css::awt::WindowEvent& e ) +{ + OutputDevice*pOutDev = Application::GetDefaultDevice(); + DBG_ASSERT( pOutDev, "Missing Default Device!" ); + if ( !pOutDev || mbSizeModified ) + return; + + // Currently we are simply using MapUnit::MapAppFont + ::Size aAppFontSize( e.Width, e.Height ); + + Reference< XControl > xDialogControl( *this, UNO_QUERY_THROW ); + Reference< XDevice > xDialogDevice( xDialogControl->getPeer(), UNO_QUERY ); + OSL_ENSURE( xDialogDevice.is(), "UnoDialogControl::windowResized: no peer, but a windowResized event?" ); + + // #i87592 In design mode the drawing layer works with sizes with decoration. + // Therefore we have to subtract them before writing back to the properties (model). + if ( xDialogDevice.is() && mbDesignMode ) + { + DeviceInfo aDeviceInfo( xDialogDevice->getInfo() ); + aAppFontSize.AdjustWidth( -(aDeviceInfo.LeftInset + aDeviceInfo.RightInset) ); + aAppFontSize.AdjustHeight( -(aDeviceInfo.TopInset + aDeviceInfo.BottomInset) ); + } + + aAppFontSize = ImplMapPixelToAppFont( pOutDev, aAppFontSize ); + + // Remember that changes have been done by listener. No need to + // update the position because of property change event. + mbSizeModified = true; + // Properties in a sequence must be sorted! + Sequence< OUString > aProps{ "Height", "Width" }; + Sequence< Any > aValues{ + Any(sal_Int32( + std::clamp(aAppFontSize.Height(), tools::Long(SAL_MIN_INT32), tools::Long(SAL_MAX_INT32)))), + Any(sal_Int32( + std::clamp(aAppFontSize.Width(), tools::Long(SAL_MIN_INT32), tools::Long(SAL_MAX_INT32)))) + }; + + ImplSetPropertyValues( aProps, aValues, true ); + mbSizeModified = false; + +} + +void SAL_CALL UnoDialogControl::windowMoved( const css::awt::WindowEvent& e ) +{ + OutputDevice*pOutDev = Application::GetDefaultDevice(); + DBG_ASSERT( pOutDev, "Missing Default Device!" ); + if ( !pOutDev || mbPosModified ) + return; + + // Currently we are simply using MapUnit::MapAppFont + ::Size aTmp( e.X, e.Y ); + aTmp = ImplMapPixelToAppFont( pOutDev, aTmp ); + + // Remember that changes have been done by listener. No need to + // update the position because of property change event. + mbPosModified = true; + Sequence< OUString > aProps{ "PositionX", "PositionY" }; + Sequence< Any > aValues{ + Any(sal_Int32( + std::clamp(aTmp.Width(), tools::Long(SAL_MIN_INT32), tools::Long(SAL_MAX_INT32)))), + Any(sal_Int32( + std::clamp(aTmp.Height(), tools::Long(SAL_MIN_INT32), tools::Long(SAL_MAX_INT32)))) + }; + + ImplSetPropertyValues( aProps, aValues, true ); + mbPosModified = false; + +} + +void SAL_CALL UnoDialogControl::windowShown( const EventObject& ) {} + +void SAL_CALL UnoDialogControl::windowHidden( const EventObject& ) {} + +void SAL_CALL UnoDialogControl::endDialog( ::sal_Int32 i_result ) +{ + Reference< XDialog2 > xPeerDialog( getPeer(), UNO_QUERY ); + if ( xPeerDialog.is() ) + xPeerDialog->endDialog( i_result ); +} + +void SAL_CALL UnoDialogControl::setHelpId( const OUString& i_id ) +{ + Reference< XDialog2 > xPeerDialog( getPeer(), UNO_QUERY ); + if ( xPeerDialog.is() ) + xPeerDialog->setHelpId( i_id ); +} + +void UnoDialogControl::setTitle( const OUString& Title ) +{ + SolarMutexGuard aGuard; + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TITLE ), uno::Any(Title), true ); +} + +OUString UnoDialogControl::getTitle() +{ + SolarMutexGuard aGuard; + return ImplGetPropertyValue_UString( BASEPROPERTY_TITLE ); +} + +sal_Int16 UnoDialogControl::execute() +{ + SolarMutexGuard aGuard; + sal_Int16 nDone = -1; + if ( getPeer().is() ) + { + Reference< XDialog > xDlg( getPeer(), UNO_QUERY ); + if( xDlg.is() ) + { + GetComponentInfos().bVisible = true; + nDone = xDlg->execute(); + GetComponentInfos().bVisible = false; + } + } + return nDone; +} + +void UnoDialogControl::endExecute() +{ + SolarMutexGuard aGuard; + if ( getPeer().is() ) + { + Reference< XDialog > xDlg( getPeer(), UNO_QUERY ); + if( xDlg.is() ) + { + xDlg->endExecute(); + GetComponentInfos().bVisible = false; + } + } +} + +// XModifyListener +void SAL_CALL UnoDialogControl::modified( + const lang::EventObject& /*rEvent*/ ) +{ + ImplUpdateResourceResolver(); +} + +void UnoDialogControl::ImplModelPropertiesChanged( const Sequence< PropertyChangeEvent >& rEvents ) +{ + for( const PropertyChangeEvent& rEvt : rEvents ) + { + Reference< XControlModel > xModel( rEvt.Source, UNO_QUERY ); + bool bOwnModel = xModel.get() == getModel().get(); + if (bOwnModel && rEvt.PropertyName == "ImageURL" && !ImplHasProperty(BASEPROPERTY_GRAPHIC)) + { + OUString aImageURL; + Reference< graphic::XGraphic > xGraphic; + if (( ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_IMAGEURL ) ) >>= aImageURL ) && + ( !aImageURL.isEmpty() )) + { + OUString absoluteUrl = getPhysicalLocation(ImplGetPropertyValue(GetPropertyName(BASEPROPERTY_DIALOGSOURCEURL)), uno::Any(aImageURL)); + xGraphic = ImageHelper::getGraphicFromURL_nothrow( absoluteUrl ); + } + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_GRAPHIC), uno::Any( xGraphic ), true ); + break; + } + else if (bOwnModel && rEvt.PropertyName == "Graphic") + { + uno::Reference<graphic::XGraphic> xGraphic; + if (ImplGetPropertyValue("Graphic") >>= xGraphic) + { + ImplSetPropertyValue("Graphic", uno::Any(xGraphic), true); + } + break; + } + } + ControlContainerBase::ImplModelPropertiesChanged(rEvents); +} + + + +UnoMultiPageControl::UnoMultiPageControl( const uno::Reference< uno::XComponentContext >& rxContext ) : ControlContainerBase(rxContext), maTabListeners( *this ) +{ + maComponentInfos.nWidth = 280; + maComponentInfos.nHeight = 400; +} + +UnoMultiPageControl::~UnoMultiPageControl() +{ +} +// XTabListener + +void SAL_CALL UnoMultiPageControl::inserted( SAL_UNUSED_PARAMETER ::sal_Int32 ) +{ +} +void SAL_CALL UnoMultiPageControl::removed( SAL_UNUSED_PARAMETER ::sal_Int32 ) +{ +} +void SAL_CALL UnoMultiPageControl::changed( SAL_UNUSED_PARAMETER ::sal_Int32, + SAL_UNUSED_PARAMETER const Sequence< NamedValue >& ) +{ +} +void SAL_CALL UnoMultiPageControl::activated( ::sal_Int32 ID ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_MULTIPAGEVALUE ), uno::Any( ID ), false ); + +} +void SAL_CALL UnoMultiPageControl::deactivated( SAL_UNUSED_PARAMETER ::sal_Int32 ) +{ +} +void SAL_CALL UnoMultiPageControl::disposing(const EventObject&) +{ +} + +void SAL_CALL UnoMultiPageControl::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maTabListeners.disposeAndClear( aEvt ); + ControlContainerBase::dispose(); +} + +// css::awt::XSimpleTabController +::sal_Int32 SAL_CALL UnoMultiPageControl::insertTab() +{ + Reference< XSimpleTabController > xMultiPage( getPeer(), UNO_QUERY_THROW ); + return xMultiPage->insertTab(); +} + +void SAL_CALL UnoMultiPageControl::removeTab( ::sal_Int32 ID ) +{ + Reference< XSimpleTabController > xMultiPage( getPeer(), UNO_QUERY_THROW ); + xMultiPage->removeTab( ID ); +} + +void SAL_CALL UnoMultiPageControl::setTabProps( ::sal_Int32 ID, const Sequence< NamedValue >& Properties ) +{ + Reference< XSimpleTabController > xMultiPage( getPeer(), UNO_QUERY_THROW ); + xMultiPage->setTabProps( ID, Properties ); +} + +Sequence< NamedValue > SAL_CALL UnoMultiPageControl::getTabProps( ::sal_Int32 ID ) +{ + Reference< XSimpleTabController > xMultiPage( getPeer(), UNO_QUERY_THROW ); + return xMultiPage->getTabProps( ID ); +} + +void SAL_CALL UnoMultiPageControl::activateTab( ::sal_Int32 ID ) +{ + Reference< XSimpleTabController > xMultiPage( getPeer(), UNO_QUERY_THROW ); + xMultiPage->activateTab( ID ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_MULTIPAGEVALUE ), uno::Any( ID ), true ); + +} + +::sal_Int32 SAL_CALL UnoMultiPageControl::getActiveTabID() +{ + Reference< XSimpleTabController > xMultiPage( getPeer(), UNO_QUERY_THROW ); + return xMultiPage->getActiveTabID(); +} + +void SAL_CALL UnoMultiPageControl::addTabListener( const Reference< XTabListener >& Listener ) +{ + maTabListeners.addInterface( Listener ); + Reference< XSimpleTabController > xMultiPage( getPeer(), UNO_QUERY ); + if ( xMultiPage.is() && maTabListeners.getLength() == 1 ) + xMultiPage->addTabListener( &maTabListeners ); +} + +void SAL_CALL UnoMultiPageControl::removeTabListener( const Reference< XTabListener >& Listener ) +{ + Reference< XSimpleTabController > xMultiPage( getPeer(), UNO_QUERY ); + if ( xMultiPage.is() && maTabListeners.getLength() == 1 ) + xMultiPage->removeTabListener( &maTabListeners ); + maTabListeners.removeInterface( Listener ); +} + +IMPL_IMPLEMENTATION_ID( UnoMultiPageControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoMultiPageControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XSimpleTabController>::get(), + cppu::UnoType<awt::XTabListener>::get(), + ControlContainerBase::getTypes() + ); + return aTypeList.getTypes(); +} + +// uno::XInterface +uno::Any UnoMultiPageControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XTabListener* >(this), + static_cast< awt::XSimpleTabController* >(this) ); + return (aRet.hasValue() ? aRet : ControlContainerBase::queryAggregation( rType )); +} + +OUString UnoMultiPageControl::GetComponentServiceName() const +{ + bool bDecoration( true ); + ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_DECORATION )) >>= bDecoration; + if ( bDecoration ) + return "tabcontrol"; + // Hopefully we can tweak the tabcontrol to display without tabs + return "tabcontrolnotabs"; +} + +void UnoMultiPageControl::bindPage( const uno::Reference< awt::XControl >& _rxControl ) +{ + uno::Reference< awt::XWindowPeer > xPage( _rxControl->getPeer() ); + uno::Reference< awt::XSimpleTabController > xTabCntrl( getPeer(), uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xProps( _rxControl->getModel(), uno::UNO_QUERY ); + + VCLXTabPage* pXPage = dynamic_cast< VCLXTabPage* >( xPage.get() ); + TabPage* pPage = pXPage ? pXPage->getTabPage() : nullptr; + if ( xTabCntrl.is() && pPage ) + { + VCLXMultiPage* pXTab = dynamic_cast< VCLXMultiPage* >( xTabCntrl.get() ); + if ( pXTab ) + { + OUString sTitle; + xProps->getPropertyValue( GetPropertyName( BASEPROPERTY_TITLE ) ) >>= sTitle; + pXTab->insertTab( pPage, sTitle); + } + } + +} + +void UnoMultiPageControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) +{ + SolarMutexGuard aSolarGuard; + + UnoControlContainer::createPeer( rxToolkit, rParentPeer ); + + const uno::Sequence< uno::Reference< awt::XControl > > aCtrls = getControls(); + for( const auto& rCtrl : aCtrls ) + bindPage( rCtrl ); + sal_Int32 nActiveTab(0); + Reference< XPropertySet > xMultiProps( getModel(), UNO_QUERY ); + xMultiProps->getPropertyValue( GetPropertyName( BASEPROPERTY_MULTIPAGEVALUE ) ) >>= nActiveTab; + + uno::Reference< awt::XSimpleTabController > xTabCntrl( getPeer(), uno::UNO_QUERY ); + if ( xTabCntrl.is() ) + { + xTabCntrl->addTabListener( this ); + if ( nActiveTab && aCtrls.hasElements() ) // Ensure peer is initialise with correct activated tab + { + xTabCntrl->activateTab( nActiveTab ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_MULTIPAGEVALUE ), uno::Any( nActiveTab ), true ); + } + } +} + +void UnoMultiPageControl::impl_createControlPeerIfNecessary( const uno::Reference< awt::XControl >& _rxControl) +{ + OSL_PRECOND( _rxControl.is(), "UnoMultiPageControl::impl_createControlPeerIfNecessary: invalid control, this will crash!" ); + + // if the container already has a peer, then also create a peer for the control + uno::Reference< awt::XWindowPeer > xMyPeer( getPeer() ); + + if( xMyPeer.is() ) + { + _rxControl->createPeer( nullptr, xMyPeer ); + bindPage( _rxControl ); + ImplActivateTabControllers(); + } + +} + +// ------------- UnoMultiPageModel ----------------- + +UnoMultiPageModel::UnoMultiPageModel( const Reference< XComponentContext >& rxContext ) : ControlModelContainerBase( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_SIZEABLE ); + //ImplRegisterProperty( BASEPROPERTY_DIALOGSOURCEURL ); + ImplRegisterProperty( BASEPROPERTY_MULTIPAGEVALUE ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_USERFORMCONTAINEES ); + + Any aBool; + aBool <<= true; + ImplRegisterProperty( BASEPROPERTY_MOVEABLE, aBool ); + ImplRegisterProperty( BASEPROPERTY_CLOSEABLE, aBool ); + ImplRegisterProperty( BASEPROPERTY_DECORATION, aBool ); + // MultiPage Control has the tab stop property. And the default value is True. + ImplRegisterProperty( BASEPROPERTY_TABSTOP, aBool ); + + uno::Reference< XNameContainer > xNameCont = new SimpleNamedThingContainer< XControlModel >; + ImplRegisterProperty( BASEPROPERTY_USERFORMCONTAINEES, uno::Any( xNameCont ) ); +} + +UnoMultiPageModel::~UnoMultiPageModel() +{ +} + +rtl::Reference<UnoControlModel> UnoMultiPageModel::Clone() const +{ + // clone the container itself + rtl::Reference<UnoMultiPageModel> pClone = new UnoMultiPageModel( *this ); + Clone_Impl( *pClone ); + return pClone; +} + +OUString UnoMultiPageModel::getServiceName() +{ + return "com.sun.star.awt.UnoMultiPageModel"; +} + +uno::Any UnoMultiPageModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "com.sun.star.awt.UnoControlMultiPage" ) ); + } + return ControlModelContainerBase::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoMultiPageModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoMultiPageModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +void UnoMultiPageModel::insertByName( const OUString& aName, const Any& aElement ) +{ + Reference< XServiceInfo > xInfo; + aElement >>= xInfo; + + if ( !xInfo.is() ) + throw IllegalArgumentException(); + + // Only a Page model can be inserted into the multipage + if ( !xInfo->supportsService( "com.sun.star.awt.UnoPageModel" ) ) + throw IllegalArgumentException(); + + return ControlModelContainerBase::insertByName( aName, aElement ); +} + + +sal_Bool SAL_CALL UnoMultiPageModel::getGroupControl( ) +{ + return true; +} + + + +UnoPageControl::UnoPageControl( const uno::Reference< uno::XComponentContext >& rxContext ) : ControlContainerBase(rxContext) +{ + maComponentInfos.nWidth = 280; + maComponentInfos.nHeight = 400; +} + +UnoPageControl::~UnoPageControl() +{ +} + +OUString UnoPageControl::GetComponentServiceName() const +{ + return "tabpage"; +} + + +// ------------- UnoPageModel ----------------- + +UnoPageModel::UnoPageModel( const Reference< XComponentContext >& rxContext ) : ControlModelContainerBase( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_TITLE ); + ImplRegisterProperty( BASEPROPERTY_SIZEABLE ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_USERFORMCONTAINEES ); +// ImplRegisterProperty( BASEPROPERTY_DIALOGSOURCEURL ); + + Any aBool; + aBool <<= true; + ImplRegisterProperty( BASEPROPERTY_MOVEABLE, aBool ); + ImplRegisterProperty( BASEPROPERTY_CLOSEABLE, aBool ); + //ImplRegisterProperty( BASEPROPERTY_TABSTOP, aBool ); + + uno::Reference< XNameContainer > xNameCont = new SimpleNamedThingContainer< XControlModel >; + ImplRegisterProperty( BASEPROPERTY_USERFORMCONTAINEES, uno::Any( xNameCont ) ); +} + +UnoPageModel::~UnoPageModel() +{ +} + +rtl::Reference<UnoControlModel> UnoPageModel::Clone() const +{ + // clone the container itself + rtl::Reference<UnoPageModel> pClone = new UnoPageModel( *this ); + Clone_Impl( *pClone ); + return pClone; +} + +OUString UnoPageModel::getServiceName() +{ + return "com.sun.star.awt.UnoPageModel"; +} + +uno::Any UnoPageModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "com.sun.star.awt.UnoControlPage" ) ); + } + return ControlModelContainerBase::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoPageModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoPageModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + + +sal_Bool SAL_CALL UnoPageModel::getGroupControl( ) +{ + return false; +} + +// Frame control + + + +UnoFrameControl::UnoFrameControl( const uno::Reference< uno::XComponentContext >& rxContext ) : ControlContainerBase(rxContext) +{ + maComponentInfos.nWidth = 280; + maComponentInfos.nHeight = 400; +} + +UnoFrameControl::~UnoFrameControl() +{ +} + +OUString UnoFrameControl::GetComponentServiceName() const +{ + return "frame"; +} + +void UnoFrameControl::ImplSetPosSize( Reference< XControl >& rxCtrl ) +{ + bool bOwnCtrl = false; + OUString sTitle; + if ( rxCtrl.get() == Reference<XControl>( this ).get() ) + bOwnCtrl = true; + Reference< XPropertySet > xProps( getModel(), UNO_QUERY ); + //xProps->getPropertyValue( GetPropertyName( BASEPROPERTY_TITLE ) ) >>= sTitle; + xProps->getPropertyValue( GetPropertyName( BASEPROPERTY_LABEL ) ) >>= sTitle; + + ControlContainerBase::ImplSetPosSize( rxCtrl ); + Reference < XWindow > xW( rxCtrl, UNO_QUERY ); + if ( bOwnCtrl || !xW.is() || sTitle.isEmpty() ) + return; + + awt::Rectangle aSizePos = xW->getPosSize(); + + sal_Int32 nX = aSizePos.X, nY = aSizePos.Y, nWidth = aSizePos.Width, nHeight = aSizePos.Height; + // Retrieve the values set by the base class + OutputDevice*pOutDev = Application::GetDefaultDevice(); + if ( pOutDev ) + { + // Adjust Y based on height of Title + ::tools::Rectangle aRect = pOutDev->GetTextRect( {}, sTitle ); + nY = nY + ( aRect.GetHeight() / 2 ); + } + else + { + Reference< XWindowPeer > xPeer = ImplGetCompatiblePeer(); + Reference< XDevice > xD( xPeer, UNO_QUERY ); + + SimpleFontMetric aFM; + FontDescriptor aFD; + Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR ) ); + + aVal >>= aFD; + if ( !aFD.StyleName.isEmpty() ) + { + Reference< XFont > xFont = xD->getFont( aFD ); + aFM = xFont->getFontMetric(); + } + else + { + Reference< XGraphics > xG = xD->createGraphics(); + aFM = xG->getFontMetric(); + } + + sal_Int16 nH = aFM.Ascent + aFM.Descent; + // offset y based on height of font ( not sure if my guess at the correct calculation is correct here ) + nY = nY + ( nH / 8); // how do I test this + } + xW->setPosSize( nX, nY, nWidth, nHeight, PosSize::POSSIZE ); +} + +// ------------- UnoFrameModel ----------------- + +UnoFrameModel::UnoFrameModel( const Reference< XComponentContext >& rxContext ) : ControlModelContainerBase( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_LABEL ); + ImplRegisterProperty( BASEPROPERTY_WRITING_MODE ); + ImplRegisterProperty( BASEPROPERTY_CONTEXT_WRITING_MODE ); + ImplRegisterProperty( BASEPROPERTY_USERFORMCONTAINEES ); + ImplRegisterProperty( BASEPROPERTY_HSCROLL ); + ImplRegisterProperty( BASEPROPERTY_VSCROLL ); + ImplRegisterProperty( BASEPROPERTY_SCROLLWIDTH ); + ImplRegisterProperty( BASEPROPERTY_SCROLLHEIGHT ); + ImplRegisterProperty( BASEPROPERTY_SCROLLTOP ); + ImplRegisterProperty( BASEPROPERTY_SCROLLLEFT ); + + + uno::Reference< XNameContainer > xNameCont = new SimpleNamedThingContainer< XControlModel >; + ImplRegisterProperty( BASEPROPERTY_USERFORMCONTAINEES, uno::Any( xNameCont ) ); +} + +UnoFrameModel::~UnoFrameModel() +{ +} + +rtl::Reference<UnoControlModel> UnoFrameModel::Clone() const +{ + // clone the container itself + rtl::Reference<UnoFrameModel> pClone = new UnoFrameModel( *this ); + Clone_Impl( *pClone ); + return pClone; +} + +OUString UnoFrameModel::getServiceName() +{ + return "com.sun.star.awt.UnoFrameModel"; +} + +uno::Any UnoFrameModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + switch ( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + { + return uno::Any( OUString( "com.sun.star.awt.UnoControlFrame" ) ); + } + case BASEPROPERTY_SCROLLWIDTH: + case BASEPROPERTY_SCROLLHEIGHT: + case BASEPROPERTY_SCROLLTOP: + case BASEPROPERTY_SCROLLLEFT: + return uno::Any( sal_Int32(0) ); + case BASEPROPERTY_USERFORMCONTAINEES: + { + uno::Reference< XNameContainer > xNameCont = new SimpleNamedThingContainer< XControlModel >; + return Any( xNameCont ); + } + } + return ControlModelContainerBase::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoFrameModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoFrameModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlDialogModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new OGeometryControlModel<UnoControlDialogModel>(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoDialogControl_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoDialogControl(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoMultiPageControl_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoMultiPageControl(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoMultiPageModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoMultiPageModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoPageControl_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoPageControl(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoPageModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoPageModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoFrameControl_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoFrameControl(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoFrameModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoFrameModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/eventcontainer.cxx b/toolkit/source/controls/eventcontainer.cxx new file mode 100644 index 000000000..1b57e984d --- /dev/null +++ b/toolkit/source/controls/eventcontainer.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 <cppuhelper/factory.hxx> + +#include <controls/eventcontainer.hxx> +#include <com/sun/star/script/ScriptEventDescriptor.hpp> + + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; +using namespace com::sun::star::registry; +using namespace com::sun::star::script; +using namespace cppu; + +namespace toolkit +{ + +// Methods XElementAccess +Type ScriptEventContainer::getElementType() +{ + return mType; +} + +sal_Bool ScriptEventContainer::hasElements() +{ + return !mHashMap.empty(); +} + +// Methods XNameAccess +Any ScriptEventContainer::getByName( const OUString& aName ) +{ + NameContainerNameMap::iterator aIt = mHashMap.find( aName ); + if( aIt == mHashMap.end() ) + { + throw NoSuchElementException(); + } + sal_Int32 iHashResult = (*aIt).second; + Any aRetAny = mValues[ iHashResult ]; + return aRetAny; +} + +Sequence< OUString > ScriptEventContainer::getElementNames() +{ + return mNames; +} + +sal_Bool ScriptEventContainer::hasByName( const OUString& aName ) +{ + NameContainerNameMap::iterator aIt = mHashMap.find( aName ); + bool bRet = ( aIt != mHashMap.end() ); + return bRet; +} + + +// Methods XNameReplace +void ScriptEventContainer::replaceByName( const OUString& aName, const Any& aElement ) +{ + const Type& aAnyType = aElement.getValueType(); + if( mType != aAnyType ) + throw IllegalArgumentException(); + + NameContainerNameMap::iterator aIt = mHashMap.find( aName ); + if( aIt == mHashMap.end() ) + { + throw NoSuchElementException(); + } + sal_Int32 iHashResult = (*aIt).second; + Any aOldElement = mValues[ iHashResult ]; + mValues[ iHashResult ] = aElement; + + // Fire event + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Element = aElement; + aEvent.ReplacedElement = aOldElement; + aEvent.Accessor <<= aName; + maContainerListeners.elementReplaced( aEvent ); +} + + +// Methods XNameContainer +void ScriptEventContainer::insertByName( const OUString& aName, const Any& aElement ) +{ + const Type& aAnyType = aElement.getValueType(); + if( mType != aAnyType ) + throw IllegalArgumentException(); + + NameContainerNameMap::iterator aIt = mHashMap.find( aName ); + if( aIt != mHashMap.end() ) + { + throw ElementExistException(); + } + + sal_Int32 nCount = mNames.getLength(); + mNames.realloc( nCount + 1 ); + mValues.resize( nCount + 1 ); + mNames.getArray()[ nCount ] = aName; + mValues[ nCount ] = aElement; + mHashMap[ aName ] = nCount; + + // Fire event + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Element = aElement; + aEvent.Accessor <<= aName; + maContainerListeners.elementInserted( aEvent ); +} + +void ScriptEventContainer::removeByName( const OUString& Name ) +{ + NameContainerNameMap::iterator aIt = mHashMap.find( Name ); + if( aIt == mHashMap.end() ) + { + throw NoSuchElementException(); + } + + sal_Int32 iHashResult = (*aIt).second; + Any aOldElement = mValues[ iHashResult ]; + + // Fire event + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Element = aOldElement; + aEvent.Accessor <<= Name; + maContainerListeners.elementRemoved( aEvent ); + + mHashMap.erase( aIt ); + sal_Int32 iLast = mNames.getLength() - 1; + if( iLast != iHashResult ) + { + OUString* pNames = mNames.getArray(); + pNames[ iHashResult ] = pNames[ iLast ]; + mValues[ iHashResult ] = mValues[ iLast ]; + mHashMap[ pNames[ iHashResult ] ] = iHashResult; + } + mNames.realloc( iLast ); + mValues.resize( iLast ); +} + +// Methods XContainer +void ScriptEventContainer::addContainerListener( const css::uno::Reference< css::container::XContainerListener >& l ) +{ + maContainerListeners.addInterface( l ); +} + +void ScriptEventContainer::removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& l ) +{ + maContainerListeners.removeInterface( l ); +} + + +ScriptEventContainer::ScriptEventContainer() + : mType( cppu::UnoType<ScriptEventDescriptor>::get() ), + maContainerListeners( *this ) +{ +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/filectrl.cxx b/toolkit/source/controls/filectrl.cxx new file mode 100644 index 000000000..68fa61a02 --- /dev/null +++ b/toolkit/source/controls/filectrl.cxx @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <controls/filectrl.hxx> + +#include <com/sun/star/ui/dialogs/FilePicker.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <comphelper/processfactory.hxx> +#include <osl/file.h> +#include <svl/svlresid.hxx> +#include <svl/svl.hrc> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> +#include <vcl/toolkit/edit.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui; + + +FileControl::FileControl( vcl::Window* pParent, WinBits nStyle ) : + Window( pParent, nStyle|WB_DIALOGCONTROL ), + maEdit( VclPtr<Edit>::Create(this, (nStyle&(~WB_BORDER))|WB_NOTABSTOP) ), + maButton( VclPtr<PushButton>::Create( this, (nStyle&(~WB_BORDER))|WB_NOLIGHTBORDER|WB_NOPOINTERFOCUS|WB_NOTABSTOP ) ), + maButtonText( SvlResId(STR_FILECTRL_BUTTONTEXT) ), + mnInternalFlags( FileControlMode_Internal::ORIGINALBUTTONTEXT ) +{ + maButton->SetClickHdl( LINK( this, FileControl, ButtonHdl ) ); + + maButton->Show(); + maEdit->Show(); + + SetCompoundControl( true ); + + SetStyle( ImplInitStyle( GetStyle() ) ); +} + + +WinBits FileControl::ImplInitStyle( WinBits nStyle ) +{ + if ( !( nStyle & WB_NOTABSTOP ) ) + { + maEdit->SetStyle( (maEdit->GetStyle()|WB_TABSTOP)&(~WB_NOTABSTOP) ); + maButton->SetStyle( (maButton->GetStyle()|WB_TABSTOP)&(~WB_NOTABSTOP) ); + } + else + { + maEdit->SetStyle( (maEdit->GetStyle()|WB_NOTABSTOP)&(~WB_TABSTOP) ); + maButton->SetStyle( (maButton->GetStyle()|WB_NOTABSTOP)&(~WB_TABSTOP) ); + } + + const WinBits nAlignmentStyle = ( WB_TOP | WB_VCENTER | WB_BOTTOM ); + maEdit->SetStyle( ( maEdit->GetStyle() & ~nAlignmentStyle ) | ( nStyle & nAlignmentStyle ) ); + + if ( !(nStyle & WB_NOGROUP) ) + nStyle |= WB_GROUP; + + if ( !(nStyle & WB_NOBORDER ) ) + nStyle |= WB_BORDER; + + nStyle &= ~WB_TABSTOP; + + return nStyle; +} + + +FileControl::~FileControl() +{ + disposeOnce(); +} + +void FileControl::dispose() +{ + maEdit.disposeAndClear(); + maButton.disposeAndClear(); + Window::dispose(); +} + +void FileControl::SetText( const OUString& rStr ) +{ + maEdit->SetText( rStr ); +} + + +OUString FileControl::GetText() const +{ + return maEdit->GetText(); +} + + +void FileControl::StateChanged( StateChangedType nType ) +{ + if ( nType == StateChangedType::Enable ) + { + maEdit->Enable( IsEnabled() ); + maButton->Enable( IsEnabled() ); + } + else if ( nType == StateChangedType::Zoom ) + { + GetEdit().SetZoom( GetZoom() ); + GetButton().SetZoom( GetZoom() ); + } + else if ( nType == StateChangedType::Style ) + { + SetStyle( ImplInitStyle( GetStyle() ) ); + } + else if ( nType == StateChangedType::ControlFont ) + { + GetEdit().SetControlFont( GetControlFont() ); + // Only use height of the button, as in HTML + // always Courier is used + vcl::Font aFont = GetButton().GetControlFont(); + aFont.SetFontSize( GetControlFont().GetFontSize() ); + GetButton().SetControlFont( aFont ); + } + else if ( nType == StateChangedType::ControlForeground ) + { + GetEdit().SetControlForeground( GetControlForeground() ); + GetButton().SetControlForeground( GetControlForeground() ); + } + else if ( nType == StateChangedType::ControlBackground ) + { + GetEdit().SetControlBackground( GetControlBackground() ); + GetButton().SetControlBackground( GetControlBackground() ); + } + Window::StateChanged( nType ); +} + + +void FileControl::Resize() +{ + static const tools::Long ButtonBorder = 10; + + if( mnInternalFlags & FileControlMode_Internal::INRESIZE ) + return; + mnInternalFlags |= FileControlMode_Internal::INRESIZE;//InResize = sal_True + + Size aOutSz = GetOutputSizePixel(); + tools::Long nButtonTextWidth = maButton->GetTextWidth( maButtonText ); + if ( !(mnInternalFlags & FileControlMode_Internal::ORIGINALBUTTONTEXT) || + ( nButtonTextWidth < aOutSz.Width()/3 ) ) + { + maButton->SetText( maButtonText ); + } + else + { + OUString aSmallText( "..." ); + maButton->SetText( aSmallText ); + nButtonTextWidth = maButton->GetTextWidth( aSmallText ); + } + + tools::Long nButtonWidth = nButtonTextWidth+ButtonBorder; + maEdit->setPosSizePixel( 0, 0, aOutSz.Width()-nButtonWidth, aOutSz.Height() ); + maButton->setPosSizePixel( aOutSz.Width()-nButtonWidth, 0, nButtonWidth, aOutSz.Height() ); + + mnInternalFlags &= ~FileControlMode_Internal::INRESIZE; //InResize = sal_False +} + + +void FileControl::GetFocus() +{ + if (!maEdit || maEdit->isDisposed()) + return; + maEdit->GrabFocus(); +} + +void FileControl::SetEditModifyHdl( const Link<Edit&,void>& rLink ) +{ + if (!maEdit || maEdit->isDisposed()) + return; + maEdit->SetModifyHdl(rLink); +} + +void FileControl::Draw( OutputDevice* pDev, const Point& rPos, SystemTextColorFlags nFlags ) +{ + WinBits nOldEditStyle = GetEdit().GetStyle(); + if ( GetStyle() & WB_BORDER ) + GetEdit().SetStyle( nOldEditStyle|WB_BORDER ); + Size aOrigSize(GetEdit().GetSizePixel()); + GetEdit().SetSizePixel(GetSizePixel()); + GetEdit().Draw( pDev, rPos, nFlags ); + GetEdit().SetSizePixel(aOrigSize); + if ( GetStyle() & WB_BORDER ) + GetEdit().SetStyle( nOldEditStyle ); +} + +IMPL_LINK_NOARG(FileControl, ButtonHdl, Button*, void) +{ + try + { + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + Reference < dialogs::XFilePicker3 > xFilePicker = dialogs::FilePicker::createWithMode( xContext, dialogs::TemplateDescription::FILEOPEN_SIMPLE ); + // transform the system notation text into a file URL + OUString sSystemNotation = GetText(), sFileURL; + oslFileError nError = osl_getFileURLFromSystemPath( sSystemNotation.pData, &sFileURL.pData ); + if ( nError == osl_File_E_INVAL ) + sFileURL = GetText(); // #97709# Maybe URL is already a file URL... + + //#90430# Check if URL is really a file URL + OUString aTmp; + if ( osl_getSystemPathFromFileURL( sFileURL.pData, &aTmp.pData ) == osl_File_E_None ) + { + // initially set this directory + xFilePicker->setDisplayDirectory( sFileURL ); + } + + if ( xFilePicker->execute() ) + { + Sequence < OUString > aPathSeq = xFilePicker->getSelectedFiles(); + + if ( aPathSeq.hasElements() ) + { + OUString aNewText = aPathSeq[0]; + INetURLObject aObj( aNewText ); + if ( aObj.GetProtocol() == INetProtocol::File ) + aNewText = aObj.PathToFileName(); + SetText( aNewText ); + maEdit->GetModifyHdl().Call( *maEdit ); + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "toolkit", "FileControl::ImplBrowseFile: caught an exception while executing the file picker!" ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/formattedcontrol.cxx b/toolkit/source/controls/formattedcontrol.cxx new file mode 100644 index 000000000..6bf71b5c5 --- /dev/null +++ b/toolkit/source/controls/formattedcontrol.cxx @@ -0,0 +1,476 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <controls/formattedcontrol.hxx> +#include <toolkit/helper/property.hxx> + +#include <com/sun/star/awt/XVclWindowPeer.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/util/NumberFormatsSupplier.hpp> + +#include <tools/diagnose_ex.h> +#include <comphelper/processfactory.hxx> +#include <osl/diagnose.h> + +#include <helper/unopropertyarrayhelper.hxx> +#include <mutex> + +namespace toolkit +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + + + namespace + { + + std::mutex& getDefaultFormatsMutex() + { + static std::mutex s_aDefaultFormatsMutex; + return s_aDefaultFormatsMutex; + } + + Reference< XNumberFormatsSupplier > s_xDefaultFormats; + bool s_bTriedCreation = false; + oslInterlockedCount s_refCount(0); + + const Reference< XNumberFormatsSupplier >& lcl_getDefaultFormats_throw() + { + std::scoped_lock aGuard( getDefaultFormatsMutex() ); + + if ( !s_xDefaultFormats.is() && !s_bTriedCreation ) + { + s_bTriedCreation = true; + s_xDefaultFormats = NumberFormatsSupplier::createWithDefaultLocale( ::comphelper::getProcessComponentContext() ); + } + if ( !s_xDefaultFormats.is() ) + throw RuntimeException(); + + return s_xDefaultFormats; + } + + void lcl_registerDefaultFormatsClient() + { + osl_atomic_increment( &s_refCount ); + } + + void lcl_revokeDefaultFormatsClient() + { + Reference< XNumberFormatsSupplier > xReleasePotentialLastReference; + { + std::scoped_lock aGuard( getDefaultFormatsMutex() ); + if ( 0 != osl_atomic_decrement( &s_refCount ) ) + return; + + xReleasePotentialLastReference = std::move(s_xDefaultFormats); + s_bTriedCreation = false; + } + xReleasePotentialLastReference.clear(); + } + } + + + // = UnoControlFormattedFieldModel + + + UnoControlFormattedFieldModel::UnoControlFormattedFieldModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) + ,m_bRevokedAsClient( false ) + ,m_bSettingValueAndText( false ) + { + ImplRegisterProperty( BASEPROPERTY_ALIGN ); + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_EFFECTIVE_DEFAULT ); + ImplRegisterProperty( BASEPROPERTY_EFFECTIVE_VALUE ); + ImplRegisterProperty( BASEPROPERTY_EFFECTIVE_MAX ); + ImplRegisterProperty( BASEPROPERTY_EFFECTIVE_MIN ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_FORMATKEY ); + ImplRegisterProperty( BASEPROPERTY_FORMATSSUPPLIER ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_MAXTEXTLEN ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_REPEAT ); + ImplRegisterProperty( BASEPROPERTY_REPEAT_DELAY ); + ImplRegisterProperty( BASEPROPERTY_READONLY ); + ImplRegisterProperty( BASEPROPERTY_SPIN ); + ImplRegisterProperty( BASEPROPERTY_STRICTFORMAT ); + ImplRegisterProperty( BASEPROPERTY_TABSTOP ); + ImplRegisterProperty( BASEPROPERTY_TEXT ); + ImplRegisterProperty( BASEPROPERTY_TEXTCOLOR ); + ImplRegisterProperty( BASEPROPERTY_HIDEINACTIVESELECTION ); + ImplRegisterProperty( BASEPROPERTY_ENFORCE_FORMAT ); + ImplRegisterProperty( BASEPROPERTY_VERTICALALIGN ); + ImplRegisterProperty( BASEPROPERTY_WRITING_MODE ); + ImplRegisterProperty( BASEPROPERTY_CONTEXT_WRITING_MODE ); + ImplRegisterProperty( BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR ); + + Any aTreatAsNumber; + aTreatAsNumber <<= true; + ImplRegisterProperty( BASEPROPERTY_TREATASNUMBER, aTreatAsNumber ); + + lcl_registerDefaultFormatsClient(); + } + + + UnoControlFormattedFieldModel::~UnoControlFormattedFieldModel() + { + } + + + OUString UnoControlFormattedFieldModel::getServiceName() + { + return "stardiv.vcl.controlmodel.FormattedField"; + } + + + void SAL_CALL UnoControlFormattedFieldModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) + { + UnoControlModel::setFastPropertyValue_NoBroadcast( nHandle, rValue ); + + switch ( nHandle ) + { + case BASEPROPERTY_EFFECTIVE_VALUE: + if ( !m_bSettingValueAndText ) + impl_updateTextFromValue_nothrow(); + break; + case BASEPROPERTY_FORMATSSUPPLIER: + impl_updateCachedFormatter_nothrow(); + impl_updateTextFromValue_nothrow(); + break; + case BASEPROPERTY_FORMATKEY: + impl_updateCachedFormatKey_nothrow(); + impl_updateTextFromValue_nothrow(); + break; + } + } + + + void UnoControlFormattedFieldModel::impl_updateTextFromValue_nothrow() + { + if ( !m_xCachedFormatter.is() ) + impl_updateCachedFormatter_nothrow(); + if ( !m_xCachedFormatter.is() ) + return; + + try + { + Any aEffectiveValue; + getFastPropertyValue( aEffectiveValue, BASEPROPERTY_EFFECTIVE_VALUE ); + + OUString sStringValue; + if ( !( aEffectiveValue >>= sStringValue ) ) + { + double nDoubleValue(0); + if ( aEffectiveValue >>= nDoubleValue ) + { + sal_Int32 nFormatKey( 0 ); + if ( m_aCachedFormat.hasValue() ) + m_aCachedFormat >>= nFormatKey; + sStringValue = m_xCachedFormatter->convertNumberToString( nFormatKey, nDoubleValue ); + } + } + + Reference< XPropertySet > xThis( *this, UNO_QUERY ); + xThis->setPropertyValue( GetPropertyName( BASEPROPERTY_TEXT ), Any( sStringValue ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } + + + void UnoControlFormattedFieldModel::impl_updateCachedFormatter_nothrow() + { + Any aFormatsSupplier; + getFastPropertyValue( aFormatsSupplier, BASEPROPERTY_FORMATSSUPPLIER ); + try + { + Reference< XNumberFormatsSupplier > xSupplier( aFormatsSupplier, UNO_QUERY ); + if ( !xSupplier.is() ) + xSupplier = lcl_getDefaultFormats_throw(); + + if ( !m_xCachedFormatter.is() ) + { + m_xCachedFormatter.set( + NumberFormatter::create(::comphelper::getProcessComponentContext()), + UNO_QUERY_THROW + ); + } + m_xCachedFormatter->attachNumberFormatsSupplier( xSupplier ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } + + + void UnoControlFormattedFieldModel::impl_updateCachedFormatKey_nothrow() + { + Any aFormatKey; + getFastPropertyValue( aFormatKey, BASEPROPERTY_FORMATKEY ); + m_aCachedFormat = aFormatKey; + } + + + void UnoControlFormattedFieldModel::dispose( ) + { + UnoControlModel::dispose(); + + ::osl::MutexGuard aGuard( GetMutex() ); + if ( !m_bRevokedAsClient ) + { + lcl_revokeDefaultFormatsClient(); + m_bRevokedAsClient = true; + } + } + + + void UnoControlFormattedFieldModel::ImplNormalizePropertySequence( const sal_Int32 _nCount, sal_Int32* _pHandles, + Any* _pValues, sal_Int32* _pValidHandles ) const + { + ImplEnsureHandleOrder( _nCount, _pHandles, _pValues, BASEPROPERTY_EFFECTIVE_VALUE, BASEPROPERTY_TEXT ); + + UnoControlModel::ImplNormalizePropertySequence( _nCount, _pHandles, _pValues, _pValidHandles ); + } + + + namespace + { + class ResetFlagOnExit + { + private: + bool& m_rFlag; + + public: + explicit ResetFlagOnExit( bool& _rFlag ) + :m_rFlag( _rFlag ) + { + } + ~ResetFlagOnExit() + { + m_rFlag = false; + } + }; + } + + + void SAL_CALL UnoControlFormattedFieldModel::setPropertyValues( const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues ) + { + bool bSettingValue = false; + bool bSettingText = false; + for ( auto const & propertyName : _rPropertyNames ) + { + if ( BASEPROPERTY_EFFECTIVE_VALUE == GetPropertyId( propertyName ) ) + bSettingValue = true; + + if ( BASEPROPERTY_TEXT == GetPropertyId( propertyName ) ) + bSettingText = true; + } + + m_bSettingValueAndText = ( bSettingValue && bSettingText ); + ResetFlagOnExit aResetFlag( m_bSettingValueAndText ); + UnoControlModel::setPropertyValues( _rPropertyNames, _rValues ); + } + + + sal_Bool UnoControlFormattedFieldModel::convertFastPropertyValue( + Any& rConvertedValue, Any& rOldValue, sal_Int32 nPropId, + const Any& rValue ) + { + if ( BASEPROPERTY_EFFECTIVE_DEFAULT == nPropId && rValue.hasValue() ) + { + double dVal = 0; + bool bStreamed = (rValue >>= dVal); + if ( bStreamed ) + { + rConvertedValue <<= dVal; + } + else + { + sal_Int32 nVal = 0; + bStreamed = (rValue >>= nVal); + if ( bStreamed ) + { + rConvertedValue <<= static_cast<double>(nVal); + } + else + { + OUString sVal; + bStreamed = (rValue >>= sVal); + if ( bStreamed ) + { + rConvertedValue <<= sVal; + } + } + } + + if ( bStreamed ) + { + getFastPropertyValue( rOldValue, nPropId ); + return !CompareProperties( rConvertedValue, rOldValue ); + } + + throw IllegalArgumentException( + ("Unable to convert the given value for the property " + + GetPropertyName(static_cast<sal_uInt16>(nPropId)) + + " (double, integer, or string expected)."), + static_cast< XPropertySet* >(this), + 1); + } + + return UnoControlModel::convertFastPropertyValue( rConvertedValue, rOldValue, nPropId, rValue ); + } + + + Any UnoControlFormattedFieldModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const + { + Any aReturn; + switch (nPropId) + { + case BASEPROPERTY_DEFAULTCONTROL: aReturn <<= OUString("stardiv.vcl.control.FormattedField"); break; + + case BASEPROPERTY_TREATASNUMBER: aReturn <<= true; break; + + case BASEPROPERTY_EFFECTIVE_DEFAULT: + case BASEPROPERTY_EFFECTIVE_VALUE: + case BASEPROPERTY_EFFECTIVE_MAX: + case BASEPROPERTY_EFFECTIVE_MIN: + case BASEPROPERTY_FORMATKEY: + case BASEPROPERTY_FORMATSSUPPLIER: + // (void) + break; + + default : aReturn = UnoControlModel::ImplGetDefaultValue( nPropId ); break; + } + + return aReturn; + } + + + ::cppu::IPropertyArrayHelper& UnoControlFormattedFieldModel::getInfoHelper() + { + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; + } + + // beans::XMultiPropertySet + + Reference< XPropertySetInfo > UnoControlFormattedFieldModel::getPropertySetInfo( ) + { + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + OUString UnoControlFormattedFieldModel::getImplementationName() + { + return "stardiv.Toolkit.UnoControlFormattedFieldModel"; + } + + css::uno::Sequence<OUString> + UnoControlFormattedFieldModel::getSupportedServiceNames() + { + auto s(UnoControlModel::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlFormattedFieldModel"; + ps[s.getLength() - 1] = "stardiv.vcl.controlmodel.FormattedField"; + return s; + } + + // = UnoFormattedFieldControl + + + UnoFormattedFieldControl::UnoFormattedFieldControl() + { + } + + + OUString UnoFormattedFieldControl::GetComponentServiceName() const + { + return "FormattedField"; + } + + + void UnoFormattedFieldControl::textChanged(const TextEvent& e) + { + Reference< XVclWindowPeer > xPeer(getPeer(), UNO_QUERY); + OSL_ENSURE(xPeer.is(), "UnoFormattedFieldControl::textChanged : what kind of peer do I have ?"); + + Sequence< OUString > aNames{ GetPropertyName( BASEPROPERTY_EFFECTIVE_VALUE ), + GetPropertyName( BASEPROPERTY_TEXT ) }; + + Sequence< Any > aValues{ xPeer->getProperty( aNames[0] ), + xPeer->getProperty( aNames[1] ) }; + + ImplSetPropertyValues( aNames, aValues, false ); + + if ( GetTextListeners().getLength() ) + GetTextListeners().textChanged( e ); + } + + OUString UnoFormattedFieldControl::getImplementationName() + { + return "stardiv.Toolkit.UnoFormattedFieldControl"; + } + + css::uno::Sequence<OUString> + UnoFormattedFieldControl::getSupportedServiceNames() + { + auto s(UnoEditControl::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlFormattedField"; + ps[s.getLength() - 1] = "stardiv.vcl.control.FormattedField"; + return s; + } +} // namespace toolkit + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlFormattedFieldModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoControlFormattedFieldModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoFormattedFieldControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoFormattedFieldControl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/geometrycontrolmodel.cxx b/toolkit/source/controls/geometrycontrolmodel.cxx new file mode 100644 index 000000000..c201d9b15 --- /dev/null +++ b/toolkit/source/controls/geometrycontrolmodel.cxx @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <controls/geometrycontrolmodel.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/resource/XStringResourceResolver.hpp> +#include <osl/diagnose.h> +#include <comphelper/sequence.hxx> +#include <controls/eventcontainer.hxx> +#include <toolkit/helper/property.hxx> +#include <algorithm> +#include <functional> + + +#define GCM_PROPERTY_ID_POS_X 1 +#define GCM_PROPERTY_ID_POS_Y 2 +#define GCM_PROPERTY_ID_WIDTH 3 +#define GCM_PROPERTY_ID_HEIGHT 4 +#define GCM_PROPERTY_ID_NAME 5 +#define GCM_PROPERTY_ID_TABINDEX 6 +#define GCM_PROPERTY_ID_STEP 7 +#define GCM_PROPERTY_ID_TAG 8 +#define GCM_PROPERTY_ID_RESOURCERESOLVER 9 + +constexpr OUStringLiteral GCM_PROPERTY_POS_X = u"PositionX"; +constexpr OUStringLiteral GCM_PROPERTY_POS_Y = u"PositionY"; +constexpr OUStringLiteral GCM_PROPERTY_WIDTH = u"Width"; +constexpr OUStringLiteral GCM_PROPERTY_HEIGHT = u"Height"; +constexpr OUStringLiteral GCM_PROPERTY_NAME = u"Name"; +constexpr OUStringLiteral GCM_PROPERTY_TABINDEX = u"TabIndex"; +constexpr OUStringLiteral GCM_PROPERTY_STEP = u"Step"; +constexpr OUStringLiteral GCM_PROPERTY_TAG = u"Tag"; +constexpr OUStringLiteral GCM_PROPERTY_RESOURCERESOLVER = u"ResourceResolver"; + +#define DEFAULT_ATTRIBS() PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT + + +// namespace toolkit +// { + + + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::container; + using namespace ::comphelper; + + + //= OGeometryControlModel_Base + + + OGeometryControlModel_Base::OGeometryControlModel_Base(css::uno::XAggregation* _pAggregateInstance) + :OPropertySetAggregationHelper( m_aBHelper ) + ,OPropertyContainer( m_aBHelper ) + ,OGCM_Base( m_aMutex ) + ,m_nPosX(0) + ,m_nPosY(0) + ,m_nWidth(0) + ,m_nHeight(0) + ,m_nTabIndex(-1) + ,m_nStep(0) + ,m_bCloneable(false) + { + OSL_ENSURE(nullptr != _pAggregateInstance, "OGeometryControlModel_Base::OGeometryControlModel_Base: invalid aggregate!"); + + osl_atomic_increment(&m_refCount); + { + m_xAggregate = _pAggregateInstance; + + { // check if the aggregate is clonable + Reference< XCloneable > xCloneAccess(m_xAggregate, UNO_QUERY); + m_bCloneable = xCloneAccess.is(); + } + + setAggregation(m_xAggregate); + m_xAggregate->setDelegator(static_cast< XWeak* >(this)); + } + osl_atomic_decrement(&m_refCount); + + registerProperties(); + } + + + OGeometryControlModel_Base::OGeometryControlModel_Base(Reference< XCloneable >& _rxAggregateInstance) + :OPropertySetAggregationHelper( m_aBHelper ) + ,OPropertyContainer( m_aBHelper ) + ,OGCM_Base( m_aMutex ) + ,m_nPosX(0) + ,m_nPosY(0) + ,m_nWidth(0) + ,m_nHeight(0) + ,m_nTabIndex(-1) + ,m_nStep(0) + ,m_bCloneable(_rxAggregateInstance.is()) + { + osl_atomic_increment(&m_refCount); + { + { + // ensure that the temporary gets destructed NOW + m_xAggregate.set(_rxAggregateInstance, UNO_QUERY); + } + OSL_ENSURE(m_xAggregate.is(), "OGeometryControlModel_Base::OGeometryControlModel_Base: invalid object given!"); + + // now the aggregate has a ref count of 2, but before setting the delegator it must be 1 + _rxAggregateInstance.clear(); + // now it should be the 1 we need here ... + + setAggregation(m_xAggregate); + m_xAggregate->setDelegator(static_cast< XWeak* >(this)); + } + osl_atomic_decrement(&m_refCount); + + registerProperties(); + } + + + Sequence< Type > SAL_CALL OGeometryControlModel_Base::getTypes( ) + { + // our own types + Sequence< Type > aTypes = ::comphelper::concatSequences( + OPropertySetAggregationHelper::getTypes(), + getBaseTypes(), + OGCM_Base::getTypes() + ); + + if ( m_xAggregate.is() ) + { + // retrieve the types of the aggregate + Reference< XTypeProvider > xAggregateTypeProv; + m_xAggregate->queryAggregation( cppu::UnoType<decltype(xAggregateTypeProv)>::get() ) >>= xAggregateTypeProv; + OSL_ENSURE( xAggregateTypeProv.is(), "OGeometryControlModel_Base::getTypes: aggregate should be a type provider!" ); + Sequence< Type > aAggTypes; + if ( xAggregateTypeProv.is() ) + aAggTypes = xAggregateTypeProv->getTypes(); + + // concat the sequences + sal_Int32 nOldSize = aTypes.getLength(); + aTypes.realloc( nOldSize + aAggTypes.getLength() ); + ::std::copy( + std::cbegin(aAggTypes), + std::cend(aAggTypes), + aTypes.getArray() + nOldSize + ); + } + + return aTypes; + } + + + void OGeometryControlModel_Base::registerProperties() + { + // register our members for the property handling of the OPropertyContainer + registerProperty(GCM_PROPERTY_POS_X, GCM_PROPERTY_ID_POS_X, DEFAULT_ATTRIBS(), &m_nPosX, cppu::UnoType<decltype(m_nPosX)>::get()); + registerProperty(GCM_PROPERTY_POS_Y, GCM_PROPERTY_ID_POS_Y, DEFAULT_ATTRIBS(), &m_nPosY, cppu::UnoType<decltype(m_nPosY)>::get()); + registerProperty(GCM_PROPERTY_WIDTH, GCM_PROPERTY_ID_WIDTH, DEFAULT_ATTRIBS(), &m_nWidth, cppu::UnoType<decltype(m_nWidth)>::get()); + registerProperty(GCM_PROPERTY_HEIGHT, GCM_PROPERTY_ID_HEIGHT, DEFAULT_ATTRIBS(), &m_nHeight, cppu::UnoType<decltype(m_nHeight)>::get()); + registerProperty(GCM_PROPERTY_NAME, GCM_PROPERTY_ID_NAME, DEFAULT_ATTRIBS(), &m_aName, cppu::UnoType<decltype(m_aName)>::get()); + registerProperty(GCM_PROPERTY_TABINDEX, GCM_PROPERTY_ID_TABINDEX, DEFAULT_ATTRIBS(), &m_nTabIndex, cppu::UnoType<decltype(m_nTabIndex)>::get()); + registerProperty(GCM_PROPERTY_STEP, GCM_PROPERTY_ID_STEP, DEFAULT_ATTRIBS(), &m_nStep, cppu::UnoType<decltype(m_nStep)>::get()); + registerProperty(GCM_PROPERTY_TAG, GCM_PROPERTY_ID_TAG, DEFAULT_ATTRIBS(), &m_aTag, cppu::UnoType<decltype(m_aTag)>::get()); + registerProperty(GCM_PROPERTY_RESOURCERESOLVER, GCM_PROPERTY_ID_RESOURCERESOLVER, DEFAULT_ATTRIBS(), &m_xStrResolver, cppu::UnoType<decltype(m_xStrResolver)>::get()); + } + + + css::uno::Any OGeometryControlModel_Base::ImplGetDefaultValueByHandle(sal_Int32 nHandle) + { + css::uno::Any aDefault; + + switch ( nHandle ) + { + case GCM_PROPERTY_ID_POS_X: aDefault <<= sal_Int32(0); break; + case GCM_PROPERTY_ID_POS_Y: aDefault <<= sal_Int32(0); break; + case GCM_PROPERTY_ID_WIDTH: aDefault <<= sal_Int32(0); break; + case GCM_PROPERTY_ID_HEIGHT: aDefault <<= sal_Int32(0); break; + case GCM_PROPERTY_ID_NAME: aDefault <<= OUString(); break; + case GCM_PROPERTY_ID_TABINDEX: aDefault <<= sal_Int16(-1); break; + case GCM_PROPERTY_ID_STEP: aDefault <<= sal_Int32(0); break; + case GCM_PROPERTY_ID_TAG: aDefault <<= OUString(); break; + case GCM_PROPERTY_ID_RESOURCERESOLVER: aDefault <<= Reference< resource::XStringResourceResolver >(); break; + default: OSL_FAIL( "ImplGetDefaultValueByHandle - unknown Property" ); + } + + return aDefault; + } + + + css::uno::Any OGeometryControlModel_Base::ImplGetPropertyValueByHandle(sal_Int32 nHandle) const + { + css::uno::Any aValue; + + switch ( nHandle ) + { + case GCM_PROPERTY_ID_POS_X: aValue <<= m_nPosX; break; + case GCM_PROPERTY_ID_POS_Y: aValue <<= m_nPosY; break; + case GCM_PROPERTY_ID_WIDTH: aValue <<= m_nWidth; break; + case GCM_PROPERTY_ID_HEIGHT: aValue <<= m_nHeight; break; + case GCM_PROPERTY_ID_NAME: aValue <<= m_aName; break; + case GCM_PROPERTY_ID_TABINDEX: aValue <<= m_nTabIndex; break; + case GCM_PROPERTY_ID_STEP: aValue <<= m_nStep; break; + case GCM_PROPERTY_ID_TAG: aValue <<= m_aTag; break; + case GCM_PROPERTY_ID_RESOURCERESOLVER: aValue <<= m_xStrResolver; break; + default: OSL_FAIL( "ImplGetPropertyValueByHandle - unknown Property" ); + } + + return aValue; + } + + + void OGeometryControlModel_Base::ImplSetPropertyValueByHandle(sal_Int32 nHandle, const css::uno::Any& aValue) + { + switch ( nHandle ) + { + case GCM_PROPERTY_ID_POS_X: aValue >>= m_nPosX; break; + case GCM_PROPERTY_ID_POS_Y: aValue >>= m_nPosY; break; + case GCM_PROPERTY_ID_WIDTH: aValue >>= m_nWidth; break; + case GCM_PROPERTY_ID_HEIGHT: aValue >>= m_nHeight; break; + case GCM_PROPERTY_ID_NAME: aValue >>= m_aName; break; + case GCM_PROPERTY_ID_TABINDEX: aValue >>= m_nTabIndex; break; + case GCM_PROPERTY_ID_STEP: aValue >>= m_nStep; break; + case GCM_PROPERTY_ID_TAG: aValue >>= m_aTag; break; + case GCM_PROPERTY_ID_RESOURCERESOLVER: aValue >>= m_xStrResolver; break; + default: OSL_FAIL( "ImplSetPropertyValueByHandle - unknown Property" ); + } + } + + + Any SAL_CALL OGeometryControlModel_Base::queryAggregation( const Type& _rType ) + { + Any aReturn; + if (_rType.equals(cppu::UnoType<XCloneable>::get()) && !m_bCloneable) + // somebody is asking for the XCloneable interface, but our aggregate does not support it + // -> outta here + // (need this extra check, cause OGCM_Base::queryAggregation would return this interface + // in every case) + return aReturn; + + aReturn = OGCM_Base::queryAggregation(_rType); + // the basic interfaces (XInterface, XAggregation etc) + + if (!aReturn.hasValue()) + aReturn = OPropertySetAggregationHelper::queryInterface(_rType); + // the property set related interfaces + + if (!aReturn.hasValue() && m_xAggregate.is()) + aReturn = m_xAggregate->queryAggregation(_rType); + // the interfaces our aggregate can provide + + return aReturn; + } + + + Any SAL_CALL OGeometryControlModel_Base::queryInterface( const Type& _rType ) + { + return OGCM_Base::queryInterface(_rType); + } + + + void SAL_CALL OGeometryControlModel_Base::acquire( ) noexcept + { + OGCM_Base::acquire(); + } + + + void SAL_CALL OGeometryControlModel_Base::release( ) noexcept + { + OGCM_Base::release(); + } + + + void OGeometryControlModel_Base::releaseAggregation() + { + // release the aggregate (_before_ clearing m_xAggregate) + if (m_xAggregate.is()) + m_xAggregate->setDelegator(nullptr); + setAggregation(nullptr); + } + + + OGeometryControlModel_Base::~OGeometryControlModel_Base() + { + releaseAggregation(); + } + + + sal_Bool SAL_CALL OGeometryControlModel_Base::convertFastPropertyValue(Any& _rConvertedValue, Any& _rOldValue, + sal_Int32 _nHandle, const Any& _rValue) + { + return OPropertyContainer::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue); + } + + + void SAL_CALL OGeometryControlModel_Base::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) + { + OPropertyContainer::setFastPropertyValue_NoBroadcast(_nHandle, _rValue); + } + + + void SAL_CALL OGeometryControlModel_Base::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const + { + OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>(const_cast<OGeometryControlModel_Base*>(this)->getInfoHelper()); + OUString sPropName; + sal_Int32 nOriginalHandle = -1; + + if (rPH.fillAggregatePropertyInfoByHandle(&sPropName, &nOriginalHandle, _nHandle)) + OPropertySetAggregationHelper::getFastPropertyValue(_rValue, _nHandle); + else + OPropertyContainer::getFastPropertyValue(_rValue, _nHandle); + } + + + css::beans::PropertyState OGeometryControlModel_Base::getPropertyStateByHandle(sal_Int32 nHandle) + { + css::uno::Any aValue = ImplGetPropertyValueByHandle( nHandle ); + css::uno::Any aDefault = ImplGetDefaultValueByHandle( nHandle ); + + return CompareProperties( aValue, aDefault ) ? css::beans::PropertyState_DEFAULT_VALUE : css::beans::PropertyState_DIRECT_VALUE; + } + + + void OGeometryControlModel_Base::setPropertyToDefaultByHandle(sal_Int32 nHandle) + { + ImplSetPropertyValueByHandle( nHandle , ImplGetDefaultValueByHandle( nHandle ) ); + } + + + css::uno::Any OGeometryControlModel_Base::getPropertyDefaultByHandle( sal_Int32 nHandle ) const + { + return ImplGetDefaultValueByHandle( nHandle ); + } + + + Reference< XPropertySetInfo> SAL_CALL OGeometryControlModel_Base::getPropertySetInfo() + { + return OPropertySetAggregationHelper::createPropertySetInfo(getInfoHelper()); + } + + + Reference< XCloneable > SAL_CALL OGeometryControlModel_Base::createClone( ) + { + OSL_ENSURE(m_bCloneable, "OGeometryControlModel_Base::createClone: invalid call!"); + if (!m_bCloneable) + return Reference< XCloneable >(); + + // let the aggregate create its own clone + // the interface + Reference< XCloneable > xCloneAccess; + m_xAggregate->queryAggregation(cppu::UnoType<decltype(xCloneAccess)>::get()) >>= xCloneAccess; + OSL_ENSURE(xCloneAccess.is(), "OGeometryControlModel_Base::createClone: suspicious aggregate!"); + if (!xCloneAccess.is()) + return Reference< XCloneable >(); + // the aggregate's clone + Reference< XCloneable > xAggregateClone = xCloneAccess->createClone(); + OSL_ENSURE(xAggregateClone.is(), "OGeometryControlModel_Base::createClone: suspicious return of the aggregate!"); + + // create a new wrapper aggregating this return value + rtl::Reference<OGeometryControlModel_Base> pOwnClone = createClone_Impl(xAggregateClone); + OSL_ENSURE(pOwnClone, "OGeometryControlModel_Base::createClone: invalid derivee behaviour!"); + OSL_ENSURE(!xAggregateClone.is(), "OGeometryControlModel_Base::createClone: invalid ctor behaviour!"); + // should have been reset + + // set properties + pOwnClone->m_nPosX = m_nPosX; + pOwnClone->m_nPosY = m_nPosY; + pOwnClone->m_nWidth = m_nWidth; + pOwnClone->m_nHeight = m_nHeight; + pOwnClone->m_aName = m_aName; + pOwnClone->m_nTabIndex = m_nTabIndex; + pOwnClone->m_nStep = m_nStep; + pOwnClone->m_aTag = m_aTag; + + + // Clone event container + Reference< css::script::XScriptEventsSupplier > xEventsSupplier = + static_cast< css::script::XScriptEventsSupplier* >( this ); + + if( xEventsSupplier.is() ) + { + Reference< XNameContainer > xEventCont = xEventsSupplier->getEvents(); + Reference< XNameContainer > xCloneEventCont = pOwnClone->getEvents(); + + const css::uno::Sequence< OUString > aNames = + xEventCont->getElementNames(); + + for( const OUString& aName : aNames ) + { + css::uno::Any aElement = xEventCont->getByName( aName ); + xCloneEventCont->insertByName( aName, aElement ); + } + } + + return pOwnClone; + } + + + Reference< XNameContainer > SAL_CALL OGeometryControlModel_Base::getEvents() + { + if( !mxEventContainer.is() ) + mxEventContainer = new toolkit::ScriptEventContainer(); + return mxEventContainer; + } + + + void SAL_CALL OGeometryControlModel_Base::disposing() + { + OGCM_Base::disposing(); + OPropertySetAggregationHelper::disposing(); + + Reference<XComponent> xComp; + if ( query_aggregation( m_xAggregate, xComp ) ) + xComp->dispose(); + } + + + //= OCommonGeometryControlModel + + + typedef std::unordered_map< OUString, sal_Int32 > HashMapString2Int; + typedef std::vector< css::uno::Sequence< css::beans::Property > > PropSeqArray; + typedef std::vector< ::std::vector< sal_Int32 > > IntArrayArray; + + // for creating class-unique PropertySetInfo's, we need some info: + namespace { HashMapString2Int gServiceSpecifierMap; } + // this one maps from a String, which is the service specifier for our + // aggregate, to a unique id + + namespace { PropSeqArray gAggregateProperties; } + // this one contains the properties which belong to all the unique ids + // in ServiceSpecifierMap + + namespace { IntArrayArray gAmbiguousPropertyIds; } + // the ids of the properties which we as well as our aggregate supply + // For such props, we let our base class handle them, and whenever such + // a prop is set, we forward this to our aggregate. + + // With this, we can ensure that two instances of this class share the + // same PropertySetInfo if and only if both aggregates have the same + // service specifier. + + + OCommonGeometryControlModel::OCommonGeometryControlModel( Reference< XCloneable >& _rxAgg, const OUString& _rServiceSpecifier ) + :OGeometryControlModel_Base( _rxAgg ) + ,m_sServiceSpecifier( _rServiceSpecifier ) + ,m_nPropertyMapId( 0 ) + { + Reference< XPropertySetInfo > xPI; + if ( m_xAggregateSet.is() ) + xPI = m_xAggregateSet->getPropertySetInfo(); + if ( !xPI.is() ) + { + releaseAggregation(); + throw IllegalArgumentException(); + } + + HashMapString2Int::iterator aPropMapIdPos = gServiceSpecifierMap.find( m_sServiceSpecifier ); + if ( gServiceSpecifierMap.end() == aPropMapIdPos ) + { + m_nPropertyMapId = gAggregateProperties.size(); + gAggregateProperties.push_back( xPI->getProperties() ); + gAmbiguousPropertyIds.emplace_back( ); + + gServiceSpecifierMap[ m_sServiceSpecifier ] = m_nPropertyMapId; + } + else + m_nPropertyMapId = aPropMapIdPos->second; + } + + namespace { + + struct PropertyNameLess + { + bool operator()( const Property& _rLHS, const Property& _rRHS ) + { + return _rLHS.Name < _rRHS.Name; + } + }; + + + struct PropertyNameEqual + { + const OUString& m_rCompare; + explicit PropertyNameEqual( const OUString& _rCompare ) : m_rCompare( _rCompare ) { } + + bool operator()( const Property& _rLHS ) + { + return _rLHS.Name == m_rCompare; + } + }; + + } + + ::cppu::IPropertyArrayHelper* OCommonGeometryControlModel::createArrayHelper( sal_Int32 _nId ) const + { + OSL_ENSURE( _nId == m_nPropertyMapId, "OCommonGeometryControlModel::createArrayHelper: invalid argument!" ); + OSL_ENSURE( _nId < static_cast<sal_Int32>(gAggregateProperties.size()), "OCommonGeometryControlModel::createArrayHelper: invalid status info (1)!" ); + OSL_ENSURE( _nId < static_cast<sal_Int32>(gAmbiguousPropertyIds.size()), "OCommonGeometryControlModel::createArrayHelper: invalid status info (2)!" ); + + // our own properties + Sequence< Property > aProps; + OPropertyContainer::describeProperties( aProps ); + + // the aggregate properties + Sequence< Property > aAggregateProps = gAggregateProperties[ _nId ]; + + // look for duplicates, and remember them + IntArrayArray::value_type& rDuplicateIds = gAmbiguousPropertyIds[ _nId ]; + // for this, sort the aggregate properties + auto [begin, end] = asNonConstRange(aAggregateProps); + ::std::sort( + begin, + end, + PropertyNameLess() + ); + + // now loop through our own props + for ( const Property& rProp : std::as_const(aProps) ) + { + // look for the current property in the properties of our aggregate + const Property* pAggPropPos = ::std::find_if( std::cbegin(aAggregateProps), std::cend(aAggregateProps), PropertyNameEqual( rProp.Name ) ); + if ( pAggPropPos != std::cend(aAggregateProps) ) + { // found a duplicate + // -> remove from the aggregate property sequence + ::comphelper::removeElementAt( aAggregateProps, pAggPropPos - std::cbegin(aAggregateProps) ); + + // and additionally, remember the id of this property + rDuplicateIds.push_back( rProp.Handle ); + } + } + + // now, finally, sort the duplicates + ::std::sort( rDuplicateIds.begin(), rDuplicateIds.end(), ::std::less< sal_Int32 >() ); + + return new OPropertyArrayAggregationHelper(aProps, aAggregateProps); + } + + + ::cppu::IPropertyArrayHelper& SAL_CALL OCommonGeometryControlModel::getInfoHelper() + { + return *getArrayHelper( m_nPropertyMapId ); + } + + + rtl::Reference<OGeometryControlModel_Base> OCommonGeometryControlModel::createClone_Impl( Reference< XCloneable >& _rxAggregateInstance ) + { + return new OCommonGeometryControlModel( _rxAggregateInstance, m_sServiceSpecifier ); + } + + Sequence< sal_Int8 > SAL_CALL OCommonGeometryControlModel::getImplementationId( ) + { + return css::uno::Sequence<sal_Int8>(); + } + + namespace { + + struct Int32Equal + { + sal_Int32 m_nCompare; + explicit Int32Equal( sal_Int32 _nCompare ) : m_nCompare( _nCompare ) { } + + bool operator()( sal_Int32 _nLHS ) + { + return _nLHS == m_nCompare; + } + }; + + } + + void SAL_CALL OCommonGeometryControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) + { + OGeometryControlModel_Base::setFastPropertyValue_NoBroadcast( _nHandle, _rValue ); + + // look if this id is one we recognized as duplicate + IntArrayArray::value_type& rDuplicateIds = gAmbiguousPropertyIds[ m_nPropertyMapId ]; + + if ( std::any_of(rDuplicateIds.begin(), rDuplicateIds.end(), Int32Equal( _nHandle )) ) + { + // yes, it is such a property + OUString sPropName; + sal_Int16 nAttributes(0); + static_cast< OPropertyArrayAggregationHelper* >( getArrayHelper( m_nPropertyMapId ) )->fillPropertyMembersByHandle( &sPropName, &nAttributes, _nHandle ); + + if ( m_xAggregateSet.is() && !sPropName.isEmpty() ) + m_xAggregateSet->setPropertyValue( sPropName, _rValue ); + } + } + + +// } // namespace toolkit + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/defaultgridcolumnmodel.cxx b/toolkit/source/controls/grid/defaultgridcolumnmodel.cxx new file mode 100644 index 000000000..ad17d15ea --- /dev/null +++ b/toolkit/source/controls/grid/defaultgridcolumnmodel.cxx @@ -0,0 +1,389 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 "gridcolumn.hxx" + +#include <com/sun/star/awt/grid/XGridColumnModel.hpp> +#include <com/sun/star/awt/grid/XGridColumn.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/componentguard.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/ref.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +#include <vector> + +using namespace css::awt; +using namespace css::awt::grid; +using namespace css::container; +using namespace css::lang; +using namespace css::uno; +using namespace toolkit; + +namespace { + +typedef ::cppu::WeakComponentImplHelper < css::awt::grid::XGridColumnModel + , css::lang::XServiceInfo + > DefaultGridColumnModel_Base; + +class DefaultGridColumnModel :public ::cppu::BaseMutex + ,public DefaultGridColumnModel_Base +{ +public: + DefaultGridColumnModel(); + DefaultGridColumnModel( DefaultGridColumnModel const & i_copySource ); + + // XGridColumnModel + virtual ::sal_Int32 SAL_CALL getColumnCount() override; + virtual css::uno::Reference< css::awt::grid::XGridColumn > SAL_CALL createColumn( ) override; + virtual ::sal_Int32 SAL_CALL addColumn(const css::uno::Reference< css::awt::grid::XGridColumn > & column) override; + virtual void SAL_CALL removeColumn( ::sal_Int32 i_columnIndex ) override; + virtual css::uno::Sequence< css::uno::Reference< css::awt::grid::XGridColumn > > SAL_CALL getColumns() override; + virtual css::uno::Reference< css::awt::grid::XGridColumn > SAL_CALL getColumn(::sal_Int32 index) override; + virtual void SAL_CALL setDefaultColumns(sal_Int32 rowElements) 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; + + // XContainer + virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override; + virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override; + + // XCloneable + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + +private: + typedef ::std::vector< css::uno::Reference< css::awt::grid::XGridColumn > > Columns; + + ::comphelper::OInterfaceContainerHelper3<XContainerListener> m_aContainerListeners; + Columns m_aColumns; +}; + + DefaultGridColumnModel::DefaultGridColumnModel() + :DefaultGridColumnModel_Base( m_aMutex ) + ,m_aContainerListeners( m_aMutex ) + { + } + + DefaultGridColumnModel::DefaultGridColumnModel( DefaultGridColumnModel const & i_copySource ) + :cppu::BaseMutex() + ,DefaultGridColumnModel_Base( m_aMutex ) + ,m_aContainerListeners( m_aMutex ) + { + Columns aColumns; + aColumns.reserve( i_copySource.m_aColumns.size() ); + try + { + for ( Columns::const_iterator col = i_copySource.m_aColumns.begin(); + col != i_copySource.m_aColumns.end(); + ++col + ) + { + Reference< css::util::XCloneable > const xCloneable( *col, UNO_QUERY_THROW ); + Reference< XGridColumn > const xClone( xCloneable->createClone(), UNO_QUERY_THROW ); + + GridColumn* const pGridColumn = comphelper::getFromUnoTunnel<GridColumn>( xClone ); + if ( pGridColumn == nullptr ) + throw RuntimeException( "invalid clone source implementation", *this ); + // that's indeed a RuntimeException, not an IllegalArgumentException or some such: + // a DefaultGridColumnModel implementation whose columns are not GridColumn implementations + // is borked. + pGridColumn->setIndex( col - i_copySource.m_aColumns.begin() ); + + aColumns.push_back( xClone ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + if ( aColumns.size() == i_copySource.m_aColumns.size() ) + m_aColumns.swap( aColumns ); + } + + ::sal_Int32 SAL_CALL DefaultGridColumnModel::getColumnCount() + { + return m_aColumns.size(); + } + + + Reference< XGridColumn > SAL_CALL DefaultGridColumnModel::createColumn( ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + return new GridColumn(); + } + + + ::sal_Int32 SAL_CALL DefaultGridColumnModel::addColumn( const Reference< XGridColumn > & i_column ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + GridColumn* const pGridColumn = comphelper::getFromUnoTunnel<GridColumn>( i_column ); + if ( pGridColumn == nullptr ) + throw css::lang::IllegalArgumentException( "invalid column implementation", *this, 1 ); + + m_aColumns.push_back( i_column ); + sal_Int32 index = m_aColumns.size() - 1; + pGridColumn->setIndex( index ); + + // fire insertion notifications + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Accessor <<= index; + aEvent.Element <<= i_column; + + aGuard.clear(); + m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent ); + + return index; + } + + + void SAL_CALL DefaultGridColumnModel::removeColumn( ::sal_Int32 i_columnIndex ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( ( i_columnIndex < 0 ) || ( o3tl::make_unsigned( i_columnIndex ) >= m_aColumns.size() ) ) + throw css::lang::IndexOutOfBoundsException( OUString(), *this ); + + Columns::iterator const pos = m_aColumns.begin() + i_columnIndex; + Reference< XGridColumn > const xColumn( *pos ); + m_aColumns.erase( pos ); + + // update indexes of all subsequent columns + sal_Int32 columnIndex( i_columnIndex ); + for ( Columns::iterator updatePos = m_aColumns.begin() + columnIndex; + updatePos != m_aColumns.end(); + ++updatePos, ++columnIndex + ) + { + GridColumn* pColumnImpl = comphelper::getFromUnoTunnel<GridColumn>( *updatePos ); + if ( !pColumnImpl ) + { + SAL_WARN( "toolkit.controls", "DefaultGridColumnModel::removeColumn: invalid column implementation!" ); + continue; + } + + pColumnImpl->setIndex( columnIndex ); + } + + // fire removal notifications + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Accessor <<= i_columnIndex; + aEvent.Element <<= xColumn; + + aGuard.clear(); + m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent ); + + // dispose the removed column + try + { + xColumn->dispose(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } + + + Sequence< Reference< XGridColumn > > SAL_CALL DefaultGridColumnModel::getColumns() + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + return ::comphelper::containerToSequence( m_aColumns ); + } + + + Reference< XGridColumn > SAL_CALL DefaultGridColumnModel::getColumn(::sal_Int32 index) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( index >=0 && o3tl::make_unsigned(index) < m_aColumns.size()) + return m_aColumns[index]; + + throw css::lang::IndexOutOfBoundsException(); + } + + + void SAL_CALL DefaultGridColumnModel::setDefaultColumns(sal_Int32 rowElements) + { + ::std::vector< ContainerEvent > aRemovedColumns; + ::std::vector< ContainerEvent > aInsertedColumns; + + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + // remove existing columns + while ( !m_aColumns.empty() ) + { + const size_t lastColIndex = m_aColumns.size() - 1; + + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Accessor <<= sal_Int32( lastColIndex ); + aEvent.Element <<= m_aColumns[ lastColIndex ]; + aRemovedColumns.push_back( aEvent ); + + m_aColumns.erase( m_aColumns.begin() + lastColIndex ); + } + + // add new columns + for ( sal_Int32 i=0; i<rowElements; ++i ) + { + ::rtl::Reference< GridColumn > const pGridColumn = new GridColumn(); + Reference< XGridColumn > const xColumn( pGridColumn ); + OUString colTitle = "Column " + OUString::number( i + 1 ); + pGridColumn->setTitle( colTitle ); + pGridColumn->setColumnWidth( 80 /* APPFONT */ ); + pGridColumn->setFlexibility( 1 ); + pGridColumn->setResizeable( true ); + pGridColumn->setDataColumnIndex( i ); + + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Accessor <<= i; + aEvent.Element <<= xColumn; + aInsertedColumns.push_back( aEvent ); + + m_aColumns.push_back( xColumn ); + pGridColumn->setIndex( i ); + } + } + + // fire removal notifications + for (const auto& rEvent : aRemovedColumns) + { + m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, rEvent ); + } + + // fire insertion notifications + for (const auto& rEvent : aInsertedColumns) + { + m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, rEvent ); + } + + // dispose removed columns + for (const auto& rEvent : aRemovedColumns) + { + try + { + const Reference< XComponent > xColComp( rEvent.Element, UNO_QUERY_THROW ); + xColComp->dispose(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } + } + + + OUString SAL_CALL DefaultGridColumnModel::getImplementationName( ) + { + return "stardiv.Toolkit.DefaultGridColumnModel"; + } + + sal_Bool SAL_CALL DefaultGridColumnModel::supportsService( const OUString& i_serviceName ) + { + return cppu::supportsService(this, i_serviceName); + } + + Sequence< OUString > SAL_CALL DefaultGridColumnModel::getSupportedServiceNames( ) + { + return { "com.sun.star.awt.grid.DefaultGridColumnModel" }; + } + + + void SAL_CALL DefaultGridColumnModel::addContainerListener( const Reference< XContainerListener >& i_listener ) + { + if ( i_listener.is() ) + m_aContainerListeners.addInterface( i_listener ); + } + + + void SAL_CALL DefaultGridColumnModel::removeContainerListener( const Reference< XContainerListener >& i_listener ) + { + if ( i_listener.is() ) + m_aContainerListeners.removeInterface( i_listener ); + } + + + void SAL_CALL DefaultGridColumnModel::disposing() + { + DefaultGridColumnModel_Base::disposing(); + + EventObject aEvent( *this ); + m_aContainerListeners.disposeAndClear( aEvent ); + + ::osl::MutexGuard aGuard( m_aMutex ); + + // remove, dispose and clear columns + while ( !m_aColumns.empty() ) + { + try + { + const Reference< XComponent > xColComponent( m_aColumns[ 0 ], UNO_QUERY_THROW ); + xColComponent->dispose(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + + m_aColumns.erase( m_aColumns.begin() ); + } + + Columns().swap(m_aColumns); + } + + + Reference< css::util::XCloneable > SAL_CALL DefaultGridColumnModel::createClone( ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + return new DefaultGridColumnModel( *this ); + } + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_DefaultGridColumnModel_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new DefaultGridColumnModel()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/defaultgriddatamodel.cxx b/toolkit/source/controls/grid/defaultgriddatamodel.cxx new file mode 100644 index 000000000..2e5f4e305 --- /dev/null +++ b/toolkit/source/controls/grid/defaultgriddatamodel.cxx @@ -0,0 +1,505 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/awt/grid/XMutableGridDataModel.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <comphelper/componentguard.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/safeint.hxx> + +#include <algorithm> +#include <vector> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::awt::grid; +using namespace ::com::sun::star::lang; + +namespace { + +typedef ::cppu::WeakComponentImplHelper < XMutableGridDataModel + , XServiceInfo + > DefaultGridDataModel_Base; + +class DefaultGridDataModel :public ::cppu::BaseMutex + ,public DefaultGridDataModel_Base +{ +public: + DefaultGridDataModel(); + DefaultGridDataModel( DefaultGridDataModel const & i_copySource ); + + // XMutableGridDataModel + virtual void SAL_CALL addRow( const Any& i_heading, const css::uno::Sequence< css::uno::Any >& Data ) override; + virtual void SAL_CALL addRows( const css::uno::Sequence< css::uno::Any>& Headings, const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& Data ) override; + virtual void SAL_CALL insertRow( ::sal_Int32 i_index, const css::uno::Any& i_heading, const css::uno::Sequence< css::uno::Any >& Data ) override; + virtual void SAL_CALL insertRows( ::sal_Int32 i_index, const css::uno::Sequence< css::uno::Any>& Headings, const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& Data ) override; + virtual void SAL_CALL removeRow( ::sal_Int32 RowIndex ) override; + virtual void SAL_CALL removeAllRows( ) override; + virtual void SAL_CALL updateCellData( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; + virtual void SAL_CALL updateRowData( const css::uno::Sequence< ::sal_Int32 >& ColumnIndexes, ::sal_Int32 RowIndex, const css::uno::Sequence< css::uno::Any >& Values ) override; + virtual void SAL_CALL updateRowHeading( ::sal_Int32 RowIndex, const css::uno::Any& Heading ) override; + virtual void SAL_CALL updateCellToolTip( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; + virtual void SAL_CALL updateRowToolTip( ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; + virtual void SAL_CALL addGridDataListener( const css::uno::Reference< css::awt::grid::XGridDataListener >& Listener ) override; + virtual void SAL_CALL removeGridDataListener( const css::uno::Reference< css::awt::grid::XGridDataListener >& Listener ) override; + + // XGridDataModel + virtual ::sal_Int32 SAL_CALL getRowCount() override; + virtual ::sal_Int32 SAL_CALL getColumnCount() override; + virtual css::uno::Any SAL_CALL getCellData( ::sal_Int32 Column, ::sal_Int32 Row ) override; + virtual css::uno::Any SAL_CALL getCellToolTip( ::sal_Int32 Column, ::sal_Int32 Row ) override; + virtual css::uno::Any SAL_CALL getRowHeading( ::sal_Int32 RowIndex ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getRowData( ::sal_Int32 RowIndex ) override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XCloneable + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) 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; + +private: + typedef ::std::pair< Any, Any > CellData; + typedef ::std::vector< CellData > RowData; + typedef ::std::vector< RowData > GridData; + + void broadcast( + GridDataEvent const & i_event, + void ( SAL_CALL css::awt::grid::XGridDataListener::*i_listenerMethod )( css::awt::grid::GridDataEvent const & ), + ::comphelper::ComponentGuard & i_instanceLock + ); + + void impl_insertRow( sal_Int32 const i_position, Any const & i_heading, Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount = -1 ); + + ::sal_Int32 impl_getRowCount_nolck() const { return sal_Int32( m_aData.size() ); } + + CellData const & impl_getCellData_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex ) const; + CellData& impl_getCellDataAccess_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex ); + RowData& impl_getRowDataAccess_throw( sal_Int32 const i_rowIndex, size_t const i_requiredColumnCount ); + + GridData m_aData; + ::std::vector< css::uno::Any > m_aRowHeaders; + sal_Int32 m_nColumnCount; +}; + + DefaultGridDataModel::DefaultGridDataModel() + :DefaultGridDataModel_Base( m_aMutex ) + ,m_nColumnCount(0) + { + } + + + DefaultGridDataModel::DefaultGridDataModel( DefaultGridDataModel const & i_copySource ) + :cppu::BaseMutex() + ,DefaultGridDataModel_Base( m_aMutex ) + ,m_aData( i_copySource.m_aData ) + ,m_aRowHeaders( i_copySource.m_aRowHeaders ) + ,m_nColumnCount( i_copySource.m_nColumnCount ) + { + } + + void DefaultGridDataModel::broadcast( GridDataEvent const & i_event, + void ( SAL_CALL XGridDataListener::*i_listenerMethod )( GridDataEvent const & ), ::comphelper::ComponentGuard & i_instanceLock ) + { + ::cppu::OInterfaceContainerHelper* pListeners = rBHelper.getContainer( cppu::UnoType<XGridDataListener>::get() ); + if ( !pListeners ) + return; + + i_instanceLock.clear(); + pListeners->notifyEach( i_listenerMethod, i_event ); + } + + + ::sal_Int32 SAL_CALL DefaultGridDataModel::getRowCount() + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + return impl_getRowCount_nolck(); + } + + + ::sal_Int32 SAL_CALL DefaultGridDataModel::getColumnCount() + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + return m_nColumnCount; + } + + + DefaultGridDataModel::CellData const & DefaultGridDataModel::impl_getCellData_throw( sal_Int32 const i_column, sal_Int32 const i_row ) const + { + if ( ( i_row < 0 ) || ( o3tl::make_unsigned( i_row ) > m_aData.size() ) + || ( i_column < 0 ) || ( i_column > m_nColumnCount ) + ) + throw IndexOutOfBoundsException( OUString(), *const_cast< DefaultGridDataModel* >( this ) ); + + RowData const & rRow( m_aData[ i_row ] ); + if ( o3tl::make_unsigned( i_column ) < rRow.size() ) + return rRow[ i_column ]; + + static CellData s_aEmpty; + return s_aEmpty; + } + + + DefaultGridDataModel::RowData& DefaultGridDataModel::impl_getRowDataAccess_throw( sal_Int32 const i_rowIndex, size_t const i_requiredColumnCount ) + { + OSL_ENSURE( i_requiredColumnCount <= o3tl::make_unsigned( m_nColumnCount ), "DefaultGridDataModel::impl_getRowDataAccess_throw: invalid column count!" ); + if ( ( i_rowIndex < 0 ) || ( o3tl::make_unsigned( i_rowIndex ) >= m_aData.size() ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + RowData& rRowData( m_aData[ i_rowIndex ] ); + if ( rRowData.size() < i_requiredColumnCount ) + rRowData.resize( i_requiredColumnCount ); + return rRowData; + } + + + DefaultGridDataModel::CellData& DefaultGridDataModel::impl_getCellDataAccess_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex ) + { + if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= m_nColumnCount ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + RowData& rRowData( impl_getRowDataAccess_throw( i_rowIndex, size_t( i_columnIndex + 1 ) ) ); + return rRowData[ i_columnIndex ]; + } + + + Any SAL_CALL DefaultGridDataModel::getCellData( ::sal_Int32 i_column, ::sal_Int32 i_row ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + return impl_getCellData_throw( i_column, i_row ).first; + } + + + Any SAL_CALL DefaultGridDataModel::getCellToolTip( ::sal_Int32 i_column, ::sal_Int32 i_row ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + return impl_getCellData_throw( i_column, i_row ).second; + } + + + Any SAL_CALL DefaultGridDataModel::getRowHeading( ::sal_Int32 i_row ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( ( i_row < 0 ) || ( o3tl::make_unsigned( i_row ) >= m_aRowHeaders.size() ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + return m_aRowHeaders[ i_row ]; + } + + + Sequence< Any > SAL_CALL DefaultGridDataModel::getRowData( ::sal_Int32 i_rowIndex ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + Sequence< Any > resultData( m_nColumnCount ); + RowData& rRowData = impl_getRowDataAccess_throw( i_rowIndex, m_nColumnCount ); + + ::std::transform( rRowData.begin(), rRowData.end(), resultData.getArray(), + [] ( const CellData& rCellData ) + { return rCellData.first; }); + return resultData; + } + + + void DefaultGridDataModel::impl_insertRow( sal_Int32 const i_position, Any const & i_heading, Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount ) + { + OSL_PRECOND( ( i_assumedColCount <= 0 ) || ( i_assumedColCount >= i_rowData.getLength() ), + "DefaultGridDataModel::impl_insertRow: invalid column count!" ); + + // insert heading + m_aRowHeaders.insert( m_aRowHeaders.begin() + i_position, i_heading ); + + // create new data row + RowData newRow( i_assumedColCount > 0 ? i_assumedColCount : i_rowData.getLength() ); + RowData::iterator cellData = newRow.begin(); + for ( const Any& rData : i_rowData ) + { + cellData->first = rData; + ++cellData; + } + + // insert data row + m_aData.insert( m_aData.begin() + i_position, newRow ); + } + + + void SAL_CALL DefaultGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data ) + { + insertRow( getRowCount(), i_heading, i_data ); + } + + + void SAL_CALL DefaultGridDataModel::addRows( const Sequence< Any >& i_headings, const Sequence< Sequence< Any > >& i_data ) + { + insertRows( getRowCount(), i_headings, i_data ); + } + + + void SAL_CALL DefaultGridDataModel::insertRow( ::sal_Int32 i_index, const Any& i_heading, const Sequence< Any >& i_data ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( ( i_index < 0 ) || ( i_index > impl_getRowCount_nolck() ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + // actually insert the row + impl_insertRow( i_index, i_heading, i_data ); + + // update column count + sal_Int32 const columnCount = i_data.getLength(); + if ( columnCount > m_nColumnCount ) + m_nColumnCount = columnCount; + + broadcast( + GridDataEvent( *this, -1, -1, i_index, i_index ), + &XGridDataListener::rowsInserted, + aGuard + ); + } + + + void SAL_CALL DefaultGridDataModel::insertRows( ::sal_Int32 i_index, const Sequence< Any>& i_headings, const Sequence< Sequence< Any > >& i_data ) + { + if ( i_headings.getLength() != i_data.getLength() ) + throw IllegalArgumentException( OUString(), *this, -1 ); + + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( ( i_index < 0 ) || ( i_index > impl_getRowCount_nolck() ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + sal_Int32 const rowCount = i_headings.getLength(); + if ( rowCount == 0 ) + return; + + // determine max col count in the new data + auto pData = std::max_element(i_data.begin(), i_data.end(), + [](const Sequence< Any >& a, const Sequence< Any >& b) { return a.getLength() < b.getLength(); }); + sal_Int32 maxColCount = pData->getLength(); + + if ( maxColCount < m_nColumnCount ) + maxColCount = m_nColumnCount; + + for ( sal_Int32 row=0; row<rowCount; ++row ) + { + impl_insertRow( i_index + row, i_headings[row], i_data[row], maxColCount ); + } + + if ( maxColCount > m_nColumnCount ) + m_nColumnCount = maxColCount; + + broadcast( + GridDataEvent( *this, -1, -1, i_index, i_index + rowCount - 1 ), + &XGridDataListener::rowsInserted, + aGuard + ); + } + + + void SAL_CALL DefaultGridDataModel::removeRow( ::sal_Int32 i_rowIndex ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( ( i_rowIndex < 0 ) || ( o3tl::make_unsigned( i_rowIndex ) >= m_aData.size() ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + m_aRowHeaders.erase( m_aRowHeaders.begin() + i_rowIndex ); + m_aData.erase( m_aData.begin() + i_rowIndex ); + + broadcast( + GridDataEvent( *this, -1, -1, i_rowIndex, i_rowIndex ), + &XGridDataListener::rowsRemoved, + aGuard + ); + } + + + void SAL_CALL DefaultGridDataModel::removeAllRows( ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + m_aRowHeaders.clear(); + m_aData.clear(); + + broadcast( + GridDataEvent( *this, -1, -1, -1, -1 ), + &XGridDataListener::rowsRemoved, + aGuard + ); + } + + + void SAL_CALL DefaultGridDataModel::updateCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + impl_getCellDataAccess_throw( i_columnIndex, i_rowIndex ).first = i_value; + + broadcast( + GridDataEvent( *this, i_columnIndex, i_columnIndex, i_rowIndex, i_rowIndex ), + &XGridDataListener::dataChanged, + aGuard + ); + } + + + void SAL_CALL DefaultGridDataModel::updateRowData( const Sequence< ::sal_Int32 >& i_columnIndexes, ::sal_Int32 i_rowIndex, const Sequence< Any >& i_values ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( ( i_rowIndex < 0 ) || ( o3tl::make_unsigned( i_rowIndex ) >= m_aData.size() ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + if ( i_columnIndexes.getLength() != i_values.getLength() ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + sal_Int32 const columnCount = i_columnIndexes.getLength(); + if ( columnCount == 0 ) + return; + + for ( sal_Int32 const columnIndex : i_columnIndexes ) + { + if ( ( columnIndex < 0 ) || ( columnIndex > m_nColumnCount ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + } + + RowData& rDataRow = m_aData[ i_rowIndex ]; + for ( sal_Int32 col = 0; col < columnCount; ++col ) + { + sal_Int32 const columnIndex = i_columnIndexes[ col ]; + if ( o3tl::make_unsigned( columnIndex ) >= rDataRow.size() ) + rDataRow.resize( columnIndex + 1 ); + + rDataRow[ columnIndex ].first = i_values[ col ]; + } + + auto aPair = ::std::minmax_element( i_columnIndexes.begin(), i_columnIndexes.end() ); + sal_Int32 const firstAffectedColumn = *aPair.first; + sal_Int32 const lastAffectedColumn = *aPair.second; + broadcast( + GridDataEvent( *this, firstAffectedColumn, lastAffectedColumn, i_rowIndex, i_rowIndex ), + &XGridDataListener::dataChanged, + aGuard + ); + } + + + void SAL_CALL DefaultGridDataModel::updateRowHeading( ::sal_Int32 i_rowIndex, const Any& i_heading ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( ( i_rowIndex < 0 ) || ( o3tl::make_unsigned( i_rowIndex ) >= m_aRowHeaders.size() ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + m_aRowHeaders[ i_rowIndex ] = i_heading; + + broadcast( + GridDataEvent( *this, -1, -1, i_rowIndex, i_rowIndex ), + &XGridDataListener::rowHeadingChanged, + aGuard + ); + } + + + void SAL_CALL DefaultGridDataModel::updateCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + impl_getCellDataAccess_throw( i_columnIndex, i_rowIndex ).second = i_value; + } + + + void SAL_CALL DefaultGridDataModel::updateRowToolTip( ::sal_Int32 i_rowIndex, const Any& i_value ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + RowData& rRowData = impl_getRowDataAccess_throw( i_rowIndex, m_nColumnCount ); + for ( auto& rCell : rRowData ) + rCell.second = i_value; + } + + + void SAL_CALL DefaultGridDataModel::addGridDataListener( const Reference< grid::XGridDataListener >& i_listener ) + { + rBHelper.addListener( cppu::UnoType<XGridDataListener>::get(), i_listener ); + } + + + void SAL_CALL DefaultGridDataModel::removeGridDataListener( const Reference< grid::XGridDataListener >& i_listener ) + { + rBHelper.removeListener( cppu::UnoType<XGridDataListener>::get(), i_listener ); + } + + + void SAL_CALL DefaultGridDataModel::disposing() + { + css::lang::EventObject aEvent; + aEvent.Source.set( *this ); + rBHelper.aLC.disposeAndClear( aEvent ); + + ::osl::MutexGuard aGuard( m_aMutex ); + GridData().swap(m_aData); + std::vector<Any>().swap(m_aRowHeaders); + m_nColumnCount = 0; + } + + + OUString SAL_CALL DefaultGridDataModel::getImplementationName( ) + { + return "stardiv.Toolkit.DefaultGridDataModel"; + } + + sal_Bool SAL_CALL DefaultGridDataModel::supportsService( const OUString& ServiceName ) + { + return cppu::supportsService(this, ServiceName); + } + + Sequence< OUString > SAL_CALL DefaultGridDataModel::getSupportedServiceNames( ) + { + return { "com.sun.star.awt.grid.DefaultGridDataModel" }; + } + + + Reference< css::util::XCloneable > SAL_CALL DefaultGridDataModel::createClone( ) + { + return new DefaultGridDataModel( *this ); + } + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_DefaultGridDataModel_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new DefaultGridDataModel()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/gridcolumn.cxx b/toolkit/source/controls/grid/gridcolumn.cxx new file mode 100644 index 000000000..11a03e647 --- /dev/null +++ b/toolkit/source/controls/grid/gridcolumn.cxx @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 "gridcolumn.hxx" + +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> + +namespace toolkit +{ + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::awt::grid; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::style; + + + //= DefaultGridColumnModel + + + GridColumn::GridColumn() + :m_nIndex(-1) + ,m_nDataColumnIndex(-1) + ,m_nColumnWidth(4) + ,m_nMaxWidth(0) + ,m_nMinWidth(0) + ,m_nFlexibility(1) + ,m_bResizeable(true) + ,m_eHorizontalAlign( HorizontalAlignment_LEFT ) + { + } + + + GridColumn::GridColumn( GridColumn const & i_copySource ) + :m_aIdentifier( i_copySource.m_aIdentifier ) + ,m_nIndex( -1 ) + ,m_nDataColumnIndex( i_copySource.m_nDataColumnIndex ) + ,m_nColumnWidth( i_copySource.m_nColumnWidth ) + ,m_nMaxWidth( i_copySource.m_nMaxWidth ) + ,m_nMinWidth( i_copySource.m_nMinWidth ) + ,m_nFlexibility( i_copySource.m_nFlexibility ) + ,m_bResizeable( i_copySource.m_bResizeable ) + ,m_sTitle( i_copySource.m_sTitle ) + ,m_sHelpText( i_copySource.m_sHelpText ) + ,m_eHorizontalAlign( i_copySource.m_eHorizontalAlign ) + { + } + + + GridColumn::~GridColumn() + { + } + + + void GridColumn::broadcast_changed( char const * const i_asciiAttributeName, const Any& i_oldValue, const Any& i_newValue, + std::unique_lock<std::mutex>& i_Guard ) + { + Reference< XInterface > const xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + GridColumnEvent const aEvent( + xSource, OUString::createFromAscii( i_asciiAttributeName ), + i_oldValue, i_newValue, m_nIndex + ); + + maGridColumnListeners.notifyEach( i_Guard, &XGridColumnListener::columnChanged, aEvent ); + } + + + css::uno::Any SAL_CALL GridColumn::getIdentifier() + { + std::unique_lock aGuard( m_aMutex ); + return m_aIdentifier; + } + + + void SAL_CALL GridColumn::setIdentifier(const css::uno::Any & value) + { + std::unique_lock aGuard( m_aMutex ); + m_aIdentifier = value; + } + + + ::sal_Int32 SAL_CALL GridColumn::getColumnWidth() + { + std::unique_lock aGuard( m_aMutex ); + return m_nColumnWidth; + } + + + void SAL_CALL GridColumn::setColumnWidth(::sal_Int32 value) + { + impl_set( m_nColumnWidth, value, "ColumnWidth" ); + } + + + ::sal_Int32 SAL_CALL GridColumn::getMaxWidth() + { + std::unique_lock aGuard( m_aMutex ); + return m_nMaxWidth; + } + + + void SAL_CALL GridColumn::setMaxWidth(::sal_Int32 value) + { + impl_set( m_nMaxWidth, value, "MaxWidth" ); + } + + + ::sal_Int32 SAL_CALL GridColumn::getMinWidth() + { + std::unique_lock aGuard( m_aMutex ); + return m_nMinWidth; + } + + + void SAL_CALL GridColumn::setMinWidth(::sal_Int32 value) + { + impl_set( m_nMinWidth, value, "MinWidth" ); + } + + + OUString SAL_CALL GridColumn::getTitle() + { + std::unique_lock aGuard( m_aMutex ); + return m_sTitle; + } + + + void SAL_CALL GridColumn::setTitle(const OUString & value) + { + impl_set( m_sTitle, value, "Title" ); + } + + + OUString SAL_CALL GridColumn::getHelpText() + { + std::unique_lock aGuard( m_aMutex ); + return m_sHelpText; + } + + + void SAL_CALL GridColumn::setHelpText( const OUString & value ) + { + impl_set( m_sHelpText, value, "HelpText" ); + } + + + sal_Bool SAL_CALL GridColumn::getResizeable() + { + std::unique_lock aGuard( m_aMutex ); + return m_bResizeable; + } + + + void SAL_CALL GridColumn::setResizeable(sal_Bool value) + { + impl_set( m_bResizeable, bool(value), "Resizeable" ); + } + + + ::sal_Int32 SAL_CALL GridColumn::getFlexibility() + { + std::unique_lock aGuard( m_aMutex ); + return m_nFlexibility; + } + + + void SAL_CALL GridColumn::setFlexibility( ::sal_Int32 i_value ) + { + if ( i_value < 0 ) + throw IllegalArgumentException( OUString(), *this, 1 ); + impl_set( m_nFlexibility, i_value, "Flexibility" ); + } + + + HorizontalAlignment SAL_CALL GridColumn::getHorizontalAlign() + { + std::unique_lock aGuard( m_aMutex ); + return m_eHorizontalAlign; + } + + + void SAL_CALL GridColumn::setHorizontalAlign(HorizontalAlignment align) + { + impl_set( m_eHorizontalAlign, align, "HorizontalAlign" ); + } + + + void SAL_CALL GridColumn::addGridColumnListener( const Reference< XGridColumnListener >& xListener ) + { + std::unique_lock aGuard( m_aMutex ); + maGridColumnListeners.addInterface( aGuard, xListener ); + } + + + void SAL_CALL GridColumn::removeGridColumnListener( const Reference< XGridColumnListener >& xListener ) + { + std::unique_lock aGuard( m_aMutex ); + maGridColumnListeners.removeInterface( aGuard, xListener ); + } + + + void GridColumn::disposing(std::unique_lock<std::mutex>&) + { + m_aIdentifier.clear(); + m_sTitle.clear(); + m_sHelpText.clear(); + } + + + ::sal_Int32 SAL_CALL GridColumn::getIndex() + { + std::unique_lock aGuard( m_aMutex ); + return m_nIndex; + } + + + void GridColumn::setIndex( sal_Int32 const i_index ) + { + std::unique_lock aGuard( m_aMutex ); + m_nIndex = i_index; + } + + + ::sal_Int32 SAL_CALL GridColumn::getDataColumnIndex() + { + std::unique_lock aGuard( m_aMutex ); + return m_nDataColumnIndex; + } + + + void SAL_CALL GridColumn::setDataColumnIndex( ::sal_Int32 i_dataColumnIndex ) + { + impl_set( m_nDataColumnIndex, i_dataColumnIndex, "DataColumnIndex" ); + } + + + OUString SAL_CALL GridColumn::getImplementationName( ) + { + return "org.openoffice.comp.toolkit.GridColumn"; + } + + sal_Bool SAL_CALL GridColumn::supportsService( const OUString& i_serviceName ) + { + return cppu::supportsService(this, i_serviceName); + } + + css::uno::Sequence< OUString > SAL_CALL GridColumn::getSupportedServiceNames( ) + { + return { "com.sun.star.awt.grid.GridColumn" }; + } + + + Reference< XCloneable > SAL_CALL GridColumn::createClone( ) + { + return new GridColumn( *this ); + } + + + sal_Int64 SAL_CALL GridColumn::getSomething( const Sequence< sal_Int8 >& i_identifier ) + { + return comphelper::getSomethingImpl(i_identifier, this); + } + + + const Sequence< sal_Int8 > & GridColumn::getUnoTunnelId() noexcept + { + static const comphelper::UnoIdInit aId; + return aId.getSeq(); + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +org_openoffice_comp_toolkit_GridColumn_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::GridColumn()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/gridcolumn.hxx b/toolkit/source/controls/grid/gridcolumn.hxx new file mode 100644 index 000000000..8008c077d --- /dev/null +++ b/toolkit/source/controls/grid/gridcolumn.hxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_TOOLKIT_SOURCE_CONTROLS_GRID_GRIDCOLUMN_HXX +#define INCLUDED_TOOLKIT_SOURCE_CONTROLS_GRID_GRIDCOLUMN_HXX + +#include <com/sun/star/awt/grid/XGridColumn.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/style/HorizontalAlignment.hpp> + +#include <comphelper/compbase.hxx> +#include <comphelper/interfacecontainer4.hxx> + +namespace toolkit +{ + +typedef comphelper::WeakComponentImplHelper < css::awt::grid::XGridColumn + , css::lang::XServiceInfo + , css::lang::XUnoTunnel + > GridColumn_Base; +class GridColumn final : public GridColumn_Base +{ +public: + GridColumn(); + GridColumn( GridColumn const & i_copySource ); + virtual ~GridColumn() override; + + // css::awt::grid::XGridColumn + virtual css::uno::Any SAL_CALL getIdentifier() override; + virtual void SAL_CALL setIdentifier(const css::uno::Any & value) override; + virtual ::sal_Int32 SAL_CALL getColumnWidth() override; + virtual void SAL_CALL setColumnWidth(::sal_Int32 the_value) override; + virtual ::sal_Int32 SAL_CALL getMaxWidth() override; + virtual void SAL_CALL setMaxWidth(::sal_Int32 the_value) override; + virtual ::sal_Int32 SAL_CALL getMinWidth() override; + virtual void SAL_CALL setMinWidth(::sal_Int32 the_value) override; + virtual sal_Bool SAL_CALL getResizeable() override; + virtual void SAL_CALL setResizeable(sal_Bool the_value) override; + virtual ::sal_Int32 SAL_CALL getFlexibility() override; + virtual void SAL_CALL setFlexibility( ::sal_Int32 _flexibility ) override; + virtual OUString SAL_CALL getTitle() override; + virtual void SAL_CALL setTitle(const OUString & value) override; + virtual OUString SAL_CALL getHelpText() override; + virtual void SAL_CALL setHelpText(const OUString & value) override; + virtual ::sal_Int32 SAL_CALL getIndex() override; + virtual ::sal_Int32 SAL_CALL getDataColumnIndex() override; + virtual void SAL_CALL setDataColumnIndex( ::sal_Int32 i_dataColumnIndex ) override; + virtual css::style::HorizontalAlignment SAL_CALL getHorizontalAlign() override; + virtual void SAL_CALL setHorizontalAlign(css::style::HorizontalAlignment align) override; + virtual void SAL_CALL addGridColumnListener( const css::uno::Reference< css::awt::grid::XGridColumnListener >& xListener ) override; + virtual void SAL_CALL removeGridColumnListener( const css::uno::Reference< css::awt::grid::XGridColumnListener >& xListener ) override; + + // OComponentHelper + virtual void disposing(std::unique_lock<std::mutex>&) override; + + // XCloneable (base of XGridColumn) + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) 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; + + // XUnoTunnel and friends + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& i_identifier ) override; + static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId() noexcept; + + // attribute access + void setIndex( sal_Int32 const i_index ); + +private: + void broadcast_changed( + char const * const i_asciiAttributeName, + const css::uno::Any& i_oldValue, + const css::uno::Any& i_newValue, + std::unique_lock<std::mutex>& i_Guard + ); + + template< class TYPE > + void impl_set( TYPE & io_attribute, TYPE const & i_newValue, char const * i_attributeName ) + { + std::unique_lock aGuard(m_aMutex); + if (m_bDisposed) + throw css::lang::DisposedException( OUString(), static_cast<cppu::OWeakObject*>(this) ); + if ( io_attribute == i_newValue ) + return; + + TYPE const aOldValue( io_attribute ); + io_attribute = i_newValue; + broadcast_changed( i_attributeName, css::uno::Any( aOldValue ), css::uno::Any( io_attribute ), aGuard ); + } + + css::uno::Any m_aIdentifier; + sal_Int32 m_nIndex; + sal_Int32 m_nDataColumnIndex; + sal_Int32 m_nColumnWidth; + sal_Int32 m_nMaxWidth; + sal_Int32 m_nMinWidth; + sal_Int32 m_nFlexibility; + bool m_bResizeable; + OUString m_sTitle; + OUString m_sHelpText; + css::style::HorizontalAlignment m_eHorizontalAlign; + comphelper::OInterfaceContainerHelper4<css::awt::grid::XGridColumnListener> maGridColumnListeners; +}; + +} + +#endif // INCLUDED_TOOLKIT_SOURCE_CONTROLS_GRID_GRIDCOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/gridcontrol.cxx b/toolkit/source/controls/grid/gridcontrol.cxx new file mode 100644 index 000000000..4bf996c8e --- /dev/null +++ b/toolkit/source/controls/grid/gridcontrol.cxx @@ -0,0 +1,460 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 "gridcontrol.hxx" +#include "grideventforwarder.hxx" + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/view/SelectionType.hpp> +#include <com/sun/star/awt/grid/XGridControl.hpp> +#include <com/sun/star/awt/grid/XGridDataModel.hpp> +#include <com/sun/star/awt/grid/XGridRowSelection.hpp> +#include <com/sun/star/awt/grid/XMutableGridDataModel.hpp> +#include <com/sun/star/awt/grid/DefaultGridDataModel.hpp> +#include <com/sun/star/awt/grid/SortableGridDataModel.hpp> +#include <com/sun/star/awt/grid/DefaultGridColumnModel.hpp> +#include <toolkit/helper/property.hxx> +#include <tools/diagnose_ex.h> +#include <toolkit/controls/unocontrolbase.hxx> +#include <toolkit/controls/unocontrolmodel.hxx> +#include <toolkit/helper/listenermultiplexer.hxx> + +#include <memory> + +#include <helper/unopropertyarrayhelper.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::awt::grid; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::util; + +namespace toolkit { + +namespace +{ + Reference< XGridDataModel > lcl_getDefaultDataModel_throw( const Reference<XComponentContext> & i_context ) + { + Reference< XMutableGridDataModel > const xDelegatorModel( DefaultGridDataModel::create( i_context ), UNO_SET_THROW ); + Reference< XGridDataModel > const xDataModel( SortableGridDataModel::create( i_context, xDelegatorModel ), UNO_QUERY_THROW ); + return xDataModel; + } + + Reference< XGridColumnModel > lcl_getDefaultColumnModel_throw( const Reference<XComponentContext> & i_context ) + { + Reference< XGridColumnModel > const xColumnModel = DefaultGridColumnModel::create( i_context ); + return xColumnModel; + } +} + + +UnoGridModel::UnoGridModel( const css::uno::Reference< css::uno::XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_FILLCOLOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_SIZEABLE ); // resizable + ImplRegisterProperty( BASEPROPERTY_HSCROLL ); + ImplRegisterProperty( BASEPROPERTY_VSCROLL ); + ImplRegisterProperty( BASEPROPERTY_TABSTOP ); + ImplRegisterProperty( BASEPROPERTY_GRID_SHOWROWHEADER ); + ImplRegisterProperty( BASEPROPERTY_ROW_HEADER_WIDTH ); + ImplRegisterProperty( BASEPROPERTY_GRID_SHOWCOLUMNHEADER ); + ImplRegisterProperty( BASEPROPERTY_COLUMN_HEADER_HEIGHT ); + ImplRegisterProperty( BASEPROPERTY_ROW_HEIGHT ); + ImplRegisterProperty( BASEPROPERTY_GRID_DATAMODEL, Any( lcl_getDefaultDataModel_throw( m_xContext ) ) ); + ImplRegisterProperty( BASEPROPERTY_GRID_COLUMNMODEL, Any( lcl_getDefaultColumnModel_throw( m_xContext ) ) ); + ImplRegisterProperty( BASEPROPERTY_GRID_SELECTIONMODE ); + ImplRegisterProperty( BASEPROPERTY_FONTRELIEF ); + ImplRegisterProperty( BASEPROPERTY_FONTEMPHASISMARK ); + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_TEXTCOLOR ); + ImplRegisterProperty( BASEPROPERTY_TEXTLINECOLOR ); + ImplRegisterProperty( BASEPROPERTY_USE_GRID_LINES ); + ImplRegisterProperty( BASEPROPERTY_GRID_LINE_COLOR ); + ImplRegisterProperty( BASEPROPERTY_GRID_HEADER_BACKGROUND ); + ImplRegisterProperty( BASEPROPERTY_GRID_HEADER_TEXT_COLOR ); + ImplRegisterProperty( BASEPROPERTY_GRID_ROW_BACKGROUND_COLORS ); + ImplRegisterProperty( BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR ); + ImplRegisterProperty( BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR ); + ImplRegisterProperty( BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR ); + ImplRegisterProperty( BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR ); + ImplRegisterProperty( BASEPROPERTY_VERTICALALIGN ); +} + + +UnoGridModel::UnoGridModel( const UnoGridModel& rModel ) + :UnoControlModel( rModel ) +{ + osl_atomic_increment( &m_refCount ); + { + Reference< XGridDataModel > xDataModel; + // clone the data model + const Reference< XFastPropertySet > xCloneSource( &const_cast< UnoGridModel& >( rModel ) ); + try + { + const Reference< XCloneable > xCloneable( xCloneSource->getFastPropertyValue( BASEPROPERTY_GRID_DATAMODEL ), UNO_QUERY_THROW ); + xDataModel.set( xCloneable->createClone(), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + if ( !xDataModel.is() ) + xDataModel = lcl_getDefaultDataModel_throw( m_xContext ); + UnoControlModel::setFastPropertyValue_NoBroadcast( BASEPROPERTY_GRID_DATAMODEL, Any( xDataModel ) ); + // do *not* use setFastPropertyValue here: The UnoControlModel ctor made a simple copy of all property values, + // so before this call here, we share our data model with the own of the clone source. setFastPropertyValue, + // then, disposes the old data model - which means the data model which in fact belongs to the clone source. + // so, call the UnoControlModel's impl-method for setting the value. + + // clone the column model + Reference< XGridColumnModel > xColumnModel; + try + { + const Reference< XCloneable > xCloneable( xCloneSource->getFastPropertyValue( BASEPROPERTY_GRID_COLUMNMODEL ), UNO_QUERY_THROW ); + xColumnModel.set( xCloneable->createClone(), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + if ( !xColumnModel.is() ) + xColumnModel = lcl_getDefaultColumnModel_throw( m_xContext ); + UnoControlModel::setFastPropertyValue_NoBroadcast( BASEPROPERTY_GRID_COLUMNMODEL, Any( xColumnModel ) ); + // same comment as above: do not use our own setPropertyValue here. + } + osl_atomic_decrement( &m_refCount ); +} + + +rtl::Reference<UnoControlModel> UnoGridModel::Clone() const +{ + return new UnoGridModel( *this ); +} + + +namespace +{ + void lcl_dispose_nothrow( const Any& i_component ) + { + try + { + const Reference< XComponent > xComponent( i_component, UNO_QUERY_THROW ); + xComponent->dispose(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } +} + + +void SAL_CALL UnoGridModel::dispose( ) +{ + lcl_dispose_nothrow( getFastPropertyValue( BASEPROPERTY_GRID_COLUMNMODEL ) ); + lcl_dispose_nothrow( getFastPropertyValue( BASEPROPERTY_GRID_DATAMODEL ) ); + + UnoControlModel::dispose(); +} + + +void SAL_CALL UnoGridModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) +{ + Any aOldSubModel; + if ( ( nHandle == BASEPROPERTY_GRID_COLUMNMODEL ) || ( nHandle == BASEPROPERTY_GRID_DATAMODEL ) ) + { + aOldSubModel = getFastPropertyValue( nHandle ); + if ( aOldSubModel == rValue ) + { + OSL_ENSURE( false, "UnoGridModel::setFastPropertyValue_NoBroadcast: setting the same value, again!" ); + // shouldn't this have been caught by convertFastPropertyValue? + aOldSubModel.clear(); + } + } + + UnoControlModel::setFastPropertyValue_NoBroadcast( nHandle, rValue ); + + if ( aOldSubModel.hasValue() ) + lcl_dispose_nothrow( aOldSubModel ); +} + + +OUString UnoGridModel::getServiceName() +{ + return "com.sun.star.awt.grid.UnoControlGridModel"; +} + + +Any UnoGridModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + switch( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + return uno::Any( OUString("com.sun.star.awt.grid.UnoControlGrid") ); + case BASEPROPERTY_GRID_SELECTIONMODE: + return uno::Any( SelectionType(1) ); + case BASEPROPERTY_GRID_SHOWROWHEADER: + case BASEPROPERTY_USE_GRID_LINES: + return uno::Any( false ); + case BASEPROPERTY_ROW_HEADER_WIDTH: + return uno::Any( sal_Int32( 10 ) ); + case BASEPROPERTY_GRID_SHOWCOLUMNHEADER: + return uno::Any( true ); + case BASEPROPERTY_COLUMN_HEADER_HEIGHT: + case BASEPROPERTY_ROW_HEIGHT: + case BASEPROPERTY_GRID_HEADER_BACKGROUND: + case BASEPROPERTY_GRID_HEADER_TEXT_COLOR: + case BASEPROPERTY_GRID_LINE_COLOR: + case BASEPROPERTY_GRID_ROW_BACKGROUND_COLORS: + case BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR: + case BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR: + case BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR: + case BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR: + return Any(); + default: + return UnoControlModel::ImplGetDefaultValue( nPropId ); + } + +} + + +::cppu::IPropertyArrayHelper& UnoGridModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + + +// XMultiPropertySet +Reference< XPropertySetInfo > UnoGridModel::getPropertySetInfo( ) +{ + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + + +//= UnoGridControl + +UnoGridControl::UnoGridControl() + :m_aSelectionListeners( *this ) + ,m_pEventForwarder( new toolkit::GridEventForwarder( *this ) ) +{ +} + + +UnoGridControl::~UnoGridControl() +{ +} + + +OUString UnoGridControl::GetComponentServiceName() const +{ + return "Grid"; +} + + +void SAL_CALL UnoGridControl::dispose( ) +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + m_aSelectionListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); +} + + +void SAL_CALL UnoGridControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControlBase::createPeer( rxToolkit, rParentPeer ); + + const Reference< XGridRowSelection > xGrid( getPeer(), UNO_QUERY_THROW ); + xGrid->addSelectionListener( &m_aSelectionListeners ); +} + + +namespace +{ + void lcl_setEventForwarding( const Reference< XControlModel >& i_gridControlModel, const std::unique_ptr< toolkit::GridEventForwarder >& i_listener, + bool const i_add ) + { + const Reference< XPropertySet > xModelProps( i_gridControlModel, UNO_QUERY ); + if ( !xModelProps.is() ) + return; + + try + { + Reference< XContainer > const xColModel( + xModelProps->getPropertyValue("ColumnModel"), + UNO_QUERY_THROW ); + if ( i_add ) + xColModel->addContainerListener( i_listener.get() ); + else + xColModel->removeContainerListener( i_listener.get() ); + + Reference< XGridDataModel > const xDataModel( + xModelProps->getPropertyValue("GridDataModel"), + UNO_QUERY_THROW + ); + Reference< XMutableGridDataModel > const xMutableDataModel( xDataModel, UNO_QUERY ); + if ( xMutableDataModel.is() ) + { + if ( i_add ) + xMutableDataModel->addGridDataListener( i_listener.get() ); + else + xMutableDataModel->removeGridDataListener( i_listener.get() ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } +} + + +sal_Bool SAL_CALL UnoGridControl::setModel( const Reference< XControlModel >& i_model ) +{ + lcl_setEventForwarding( getModel(), m_pEventForwarder, false ); + if ( !UnoGridControl_Base::setModel( i_model ) ) + return false; + lcl_setEventForwarding( getModel(), m_pEventForwarder, true ); + return true; +} + + +::sal_Int32 UnoGridControl::getRowAtPoint(::sal_Int32 x, ::sal_Int32 y) +{ + Reference< XGridControl > const xGrid ( getPeer(), UNO_QUERY_THROW ); + return xGrid->getRowAtPoint( x, y ); +} + + +::sal_Int32 UnoGridControl::getColumnAtPoint(::sal_Int32 x, ::sal_Int32 y) +{ + Reference< XGridControl > const xGrid ( getPeer(), UNO_QUERY_THROW ); + return xGrid->getColumnAtPoint( x, y ); +} + + +::sal_Int32 SAL_CALL UnoGridControl::getCurrentColumn( ) +{ + Reference< XGridControl > const xGrid ( getPeer(), UNO_QUERY_THROW ); + return xGrid->getCurrentColumn(); +} + + +::sal_Int32 SAL_CALL UnoGridControl::getCurrentRow( ) +{ + Reference< XGridControl > const xGrid ( getPeer(), UNO_QUERY_THROW ); + return xGrid->getCurrentRow(); +} + + +void SAL_CALL UnoGridControl::goToCell( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) +{ + Reference< XGridControl > const xGrid ( getPeer(), UNO_QUERY_THROW ); + xGrid->goToCell( i_columnIndex, i_rowIndex ); +} + + +void SAL_CALL UnoGridControl::selectRow( ::sal_Int32 i_rowIndex ) +{ + Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->selectRow( i_rowIndex ); +} + + +void SAL_CALL UnoGridControl::selectAllRows() +{ + Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->selectAllRows(); +} + + +void SAL_CALL UnoGridControl::deselectRow( ::sal_Int32 i_rowIndex ) +{ + Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->deselectRow( i_rowIndex ); +} + + +void SAL_CALL UnoGridControl::deselectAllRows() +{ + Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->deselectAllRows(); +} + + +css::uno::Sequence< ::sal_Int32 > SAL_CALL UnoGridControl::getSelectedRows() +{ + return Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->getSelectedRows(); +} + + +sal_Bool SAL_CALL UnoGridControl::hasSelectedRows() +{ + return Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->hasSelectedRows(); +} + + +sal_Bool SAL_CALL UnoGridControl::isRowSelected(::sal_Int32 index) +{ + return Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->isRowSelected( index ); +} + + +void SAL_CALL UnoGridControl::addSelectionListener(const css::uno::Reference< css::awt::grid::XGridSelectionListener > & listener) +{ + m_aSelectionListeners.addInterface( listener ); +} + + +void SAL_CALL UnoGridControl::removeSelectionListener(const css::uno::Reference< css::awt::grid::XGridSelectionListener > & listener) +{ + m_aSelectionListeners.removeInterface( listener ); +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_GridControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoGridControl()); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_GridControlModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoGridModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/gridcontrol.hxx b/toolkit/source/controls/grid/gridcontrol.hxx new file mode 100644 index 000000000..6b4f8152b --- /dev/null +++ b/toolkit/source/controls/grid/gridcontrol.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 . + */ + +#ifndef INCLUDED_TOOLKIT_SOURCE_CONTROLS_GRID_GRIDCONTROL_HXX +#define INCLUDED_TOOLKIT_SOURCE_CONTROLS_GRID_GRIDCONTROL_HXX + +#include <com/sun/star/awt/grid/XGridControl.hpp> +#include <com/sun/star/awt/grid/XGridRowSelection.hpp> + +#include <toolkit/controls/unocontrolbase.hxx> +#include <toolkit/controls/unocontrolmodel.hxx> +#include <cppuhelper/implbase.hxx> +#include <toolkit/helper/listenermultiplexer.hxx> + +#include <memory> + +namespace toolkit +{ + +class GridEventForwarder; + + +// = UnoGridModel + +class UnoGridModel : public UnoControlModel +{ +protected: + css::uno::Any ImplGetDefaultValue( sal_uInt16 nPropId ) const override; + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + +public: + explicit UnoGridModel( const css::uno::Reference< css::uno::XComponentContext >& i_factory ); + UnoGridModel( const UnoGridModel& rModel ); + + rtl::Reference<UnoControlModel> Clone() const override; + + // css::lang::XComponent + void SAL_CALL dispose( ) override; + + // css::beans::XMultiPropertySet + css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // css::io::XPersistObject + OUString SAL_CALL getServiceName() override; + + // OPropertySetHelper + void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "stardiv.Toolkit.GridControlModel"; } + + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override + { + auto s(UnoControlModel::getSupportedServiceNames()); + s.realloc(s.getLength() + 1); + s.getArray()[s.getLength() - 1] = "com.sun.star.awt.grid.UnoControlGridModel"; + return s; + } +}; + + +// = UnoGridControl + +typedef ::cppu::ImplInheritanceHelper < UnoControlBase + , css::awt::grid::XGridControl + , css::awt::grid::XGridRowSelection + > UnoGridControl_Base; +class UnoGridControl : public UnoGridControl_Base +{ +public: + UnoGridControl(); + OUString GetComponentServiceName() const override; + + // css::lang::XComponent + void SAL_CALL dispose( ) override; + + // css::awt::XControl + void SAL_CALL createPeer( const css::uno::Reference< css::awt::XToolkit >& Toolkit, const css::uno::Reference< css::awt::XWindowPeer >& Parent ) override; + sal_Bool SAL_CALL setModel( const css::uno::Reference< css::awt::XControlModel >& rxModel ) override; + + // css::awt::grid::XGridControl + virtual ::sal_Int32 SAL_CALL getColumnAtPoint(::sal_Int32 x, ::sal_Int32 y) override; + virtual ::sal_Int32 SAL_CALL getRowAtPoint(::sal_Int32 x, ::sal_Int32 y) override; + virtual ::sal_Int32 SAL_CALL getCurrentColumn( ) override; + virtual ::sal_Int32 SAL_CALL getCurrentRow( ) override; + virtual void SAL_CALL goToCell( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) override; + + // css::awt::grid::XGridRowSelection + virtual void SAL_CALL selectRow( ::sal_Int32 i_rowIndex ) override; + virtual void SAL_CALL selectAllRows() override; + virtual void SAL_CALL deselectRow( ::sal_Int32 i_rowIndex ) override; + virtual void SAL_CALL deselectAllRows() override; + virtual css::uno::Sequence< ::sal_Int32 > SAL_CALL getSelectedRows() override; + virtual sal_Bool SAL_CALL hasSelectedRows() override; + virtual sal_Bool SAL_CALL isRowSelected(::sal_Int32 index) override; + virtual void SAL_CALL addSelectionListener(const css::uno::Reference< css::awt::grid::XGridSelectionListener > & listener) override; + virtual void SAL_CALL removeSelectionListener(const css::uno::Reference< css::awt::grid::XGridSelectionListener > & listener) override; + + // css::lang::XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "stardiv.Toolkit.GridControl"; } + + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override + { + auto s(UnoControlBase::getSupportedServiceNames()); + s.realloc(s.getLength() + 1); + s.getArray()[s.getLength() - 1] = "com.sun.star.awt.grid.UnoControlGrid"; + return s; + } + + using UnoControl::getPeer; + +protected: + virtual ~UnoGridControl() override; + +private: + SelectionListenerMultiplexer m_aSelectionListeners; + std::unique_ptr< GridEventForwarder > m_pEventForwarder; +}; + +} // toolkit + +#endif // _TOOLKIT_TREE_CONTROL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/grideventforwarder.cxx b/toolkit/source/controls/grid/grideventforwarder.cxx new file mode 100644 index 000000000..5baf5fdda --- /dev/null +++ b/toolkit/source/controls/grid/grideventforwarder.cxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 "grideventforwarder.hxx" +#include "gridcontrol.hxx" + + +namespace toolkit +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::awt::grid::GridDataEvent; + using ::com::sun::star::container::ContainerEvent; + using ::com::sun::star::lang::EventObject; + + + //= GridEventForwarder + + + GridEventForwarder::GridEventForwarder( UnoGridControl& i_parent ) + :m_parent( i_parent ) + { + } + + + GridEventForwarder::~GridEventForwarder() + { + } + + + void SAL_CALL GridEventForwarder::acquire() noexcept + { + m_parent.acquire(); + } + + + void SAL_CALL GridEventForwarder::release() noexcept + { + m_parent.release(); + } + + + void SAL_CALL GridEventForwarder::rowsInserted( const GridDataEvent& i_event ) + { + Reference< XGridDataListener > xPeer( m_parent.getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->rowsInserted( i_event ); + } + + + void SAL_CALL GridEventForwarder::rowsRemoved( const GridDataEvent& i_event ) + { + Reference< XGridDataListener > xPeer( m_parent.getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->rowsRemoved( i_event ); + } + + + void SAL_CALL GridEventForwarder::dataChanged( const GridDataEvent& i_event ) + { + Reference< XGridDataListener > xPeer( m_parent.getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->dataChanged( i_event ); + } + + + void SAL_CALL GridEventForwarder::rowHeadingChanged( const GridDataEvent& i_event ) + { + Reference< XGridDataListener > xPeer( m_parent.getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->rowHeadingChanged( i_event ); + } + + + void SAL_CALL GridEventForwarder::elementInserted( const ContainerEvent& i_event ) + { + Reference< XContainerListener > xPeer( m_parent.getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->elementInserted( i_event ); + } + + + void SAL_CALL GridEventForwarder::elementRemoved( const ContainerEvent& i_event ) + { + Reference< XContainerListener > xPeer( m_parent.getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->elementRemoved( i_event ); + } + + + void SAL_CALL GridEventForwarder::elementReplaced( const ContainerEvent& i_event ) + { + Reference< XContainerListener > xPeer( m_parent.getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->elementReplaced( i_event ); + } + + + void SAL_CALL GridEventForwarder::disposing( const EventObject& i_event ) + { + Reference< XEventListener > xPeer( m_parent.getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->disposing( i_event ); + } + + +} // namespace toolkit + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/grideventforwarder.hxx b/toolkit/source/controls/grid/grideventforwarder.hxx new file mode 100644 index 000000000..9578e62ee --- /dev/null +++ b/toolkit/source/controls/grid/grideventforwarder.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 . + */ + +#ifndef INCLUDED_TOOLKIT_SOURCE_CONTROLS_GRID_GRIDEVENTFORWARDER_HXX +#define INCLUDED_TOOLKIT_SOURCE_CONTROLS_GRID_GRIDEVENTFORWARDER_HXX + +#include <com/sun/star/awt/grid/XGridDataListener.hpp> +#include <com/sun/star/container/XContainerListener.hpp> + +#include <cppuhelper/implbase2.hxx> + + +namespace toolkit +{ + + + class UnoGridControl; + + + //= GridEventForwarder + + typedef ::cppu::ImplHelper2 < css::awt::grid::XGridDataListener + , css::container::XContainerListener + > GridEventForwarder_Base; + + class GridEventForwarder : public GridEventForwarder_Base + { + public: + explicit GridEventForwarder( UnoGridControl& i_parent ); + virtual ~GridEventForwarder(); + + public: + // XInterface + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XGridDataListener + virtual void SAL_CALL rowsInserted( const css::awt::grid::GridDataEvent& Event ) override; + virtual void SAL_CALL rowsRemoved( const css::awt::grid::GridDataEvent& Event ) override; + virtual void SAL_CALL dataChanged( const css::awt::grid::GridDataEvent& Event ) override; + virtual void SAL_CALL rowHeadingChanged( const css::awt::grid::GridDataEvent& Event ) override; + + // XContainerListener + virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override; + virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override; + virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& i_event ) override; + + private: + UnoGridControl& m_parent; + }; + + +} // namespace toolkit + + +#endif // INCLUDED_TOOLKIT_SOURCE_CONTROLS_GRID_GRIDEVENTFORWARDER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/grid/sortablegriddatamodel.cxx b/toolkit/source/controls/grid/sortablegriddatamodel.cxx new file mode 100644 index 000000000..6269d727d --- /dev/null +++ b/toolkit/source/controls/grid/sortablegriddatamodel.cxx @@ -0,0 +1,928 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <com/sun/star/i18n/Collator.hpp> +#include <com/sun/star/i18n/XCollator.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/NotInitializedException.hpp> +#include <com/sun/star/ucb/AlreadyInitializedException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/awt/grid/XGridDataListener.hpp> +#include <com/sun/star/awt/grid/XSortableMutableGridDataModel.hpp> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/implbase1.hxx> +#include <comphelper/anycompare.hxx> +#include <comphelper/componentguard.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <tools/diagnose_ex.h> +#include <i18nlangtag/languagetag.hxx> +#include <o3tl/safeint.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +using namespace css::awt; +using namespace css::awt::grid; +using namespace css::i18n; +using namespace css::lang; +using namespace css::ucb; +using namespace css::uno; + +namespace { + +class SortableGridDataModel; +class MethodGuard; + +typedef ::cppu::WeakComponentImplHelper < css::awt::grid::XSortableMutableGridDataModel + , css::lang::XServiceInfo + , css::lang::XInitialization + > SortableGridDataModel_Base; +typedef ::cppu::ImplHelper1 < css::awt::grid::XGridDataListener + > SortableGridDataModel_PrivateBase; +class SortableGridDataModel :public ::cppu::BaseMutex + ,public SortableGridDataModel_Base + ,public SortableGridDataModel_PrivateBase +{ +public: + explicit SortableGridDataModel( const css::uno::Reference< css::uno::XComponentContext > & rxContext ); + SortableGridDataModel( SortableGridDataModel const & i_copySource ); + + bool isInitialized() const { return m_isInitialized; } + +protected: + virtual ~SortableGridDataModel() override; + +public: + // XSortableGridData + virtual void SAL_CALL sortByColumn( ::sal_Int32 ColumnIndex, sal_Bool SortAscending ) override; + virtual void SAL_CALL removeColumnSort( ) override; + virtual css::beans::Pair< ::sal_Int32, sal_Bool > SAL_CALL getCurrentSortOrder( ) override; + + // XMutableGridDataModel + virtual void SAL_CALL addRow( const css::uno::Any& Heading, const css::uno::Sequence< css::uno::Any >& Data ) override; + virtual void SAL_CALL addRows( const css::uno::Sequence< css::uno::Any >& Headings, const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& Data ) override; + virtual void SAL_CALL insertRow( ::sal_Int32 i_index, const css::uno::Any& i_heading, const css::uno::Sequence< css::uno::Any >& Data ) override; + virtual void SAL_CALL insertRows( ::sal_Int32 i_index, const css::uno::Sequence< css::uno::Any>& Headings, const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& Data ) override; + virtual void SAL_CALL removeRow( ::sal_Int32 RowIndex ) override; + virtual void SAL_CALL removeAllRows( ) override; + virtual void SAL_CALL updateCellData( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; + virtual void SAL_CALL updateRowData( const css::uno::Sequence< ::sal_Int32 >& ColumnIndexes, ::sal_Int32 RowIndex, const css::uno::Sequence< css::uno::Any >& Values ) override; + virtual void SAL_CALL updateRowHeading( ::sal_Int32 RowIndex, const css::uno::Any& Heading ) override; + virtual void SAL_CALL updateCellToolTip( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; + virtual void SAL_CALL updateRowToolTip( ::sal_Int32 RowIndex, const css::uno::Any& Value ) override; + virtual void SAL_CALL addGridDataListener( const css::uno::Reference< css::awt::grid::XGridDataListener >& Listener ) override; + virtual void SAL_CALL removeGridDataListener( const css::uno::Reference< css::awt::grid::XGridDataListener >& Listener ) override; + + // XGridDataModel + virtual ::sal_Int32 SAL_CALL getRowCount() override; + virtual ::sal_Int32 SAL_CALL getColumnCount() override; + virtual css::uno::Any SAL_CALL getCellData( ::sal_Int32 Column, ::sal_Int32 RowIndex ) override; + virtual css::uno::Any SAL_CALL getCellToolTip( ::sal_Int32 Column, ::sal_Int32 RowIndex ) override; + virtual css::uno::Any SAL_CALL getRowHeading( ::sal_Int32 RowIndex ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getRowData( ::sal_Int32 RowIndex ) override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XCloneable + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) 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; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XGridDataListener + virtual void SAL_CALL rowsInserted( const css::awt::grid::GridDataEvent& Event ) override; + virtual void SAL_CALL rowsRemoved( const css::awt::grid::GridDataEvent& Event ) override; + virtual void SAL_CALL dataChanged( const css::awt::grid::GridDataEvent& Event ) override; + virtual void SAL_CALL rowHeadingChanged( const css::awt::grid::GridDataEvent& Event ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& i_event ) override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) noexcept final 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; + +private: + /** translates the given public index into one to be passed to our delegator + @throws css::lang::IndexOutOfBoundsException + if the given index does not denote a valid row + */ + ::sal_Int32 impl_getPrivateRowIndex_throw( ::sal_Int32 const i_publicRowIndex ) const; + + /** translates the given private row index to a public one + */ + ::sal_Int32 impl_getPublicRowIndex_nothrow( ::sal_Int32 const i_privateRowIndex ) const; + + bool impl_isSorted_nothrow() const + { + return m_currentSortColumn >= 0; + } + + /** rebuilds the index translation structure. + + Neither <member>m_currentSortColumn</member> nor <member>m_sortAscending</member> are touched by this method. + Also, the given column index is not checked, this is the responsibility of the caller. + */ + bool impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, bool const i_sortAscending ); + + /** translates the given event, obtained from our delegator, to a version which can be broadcasted to our own + clients. + */ + css::awt::grid::GridDataEvent + impl_createPublicEvent( css::awt::grid::GridDataEvent const & i_originalEvent ) const; + + /** broadcasts the given event to our registered XGridDataListeners + */ + void impl_broadcast( + void ( SAL_CALL css::awt::grid::XGridDataListener::*i_listenerMethod )( const css::awt::grid::GridDataEvent & ), + css::awt::grid::GridDataEvent const & i_publicEvent, + MethodGuard& i_instanceLock + ); + + /** rebuilds our indexes, notifying row removal and row addition events + + First, a rowsRemoved event is notified to our registered listeners. Then, the index translation tables are + rebuilt, and a rowsInserted event is notified. + + Only to be called when we're sorted. + */ + void impl_rebuildIndexesAndNotify( MethodGuard& i_instanceLock ); + + /** removes the current sorting, and notifies a change of all data + */ + void impl_removeColumnSort( MethodGuard& i_instanceLock ); + + /** removes the current sorting, without any broadcast + */ + void impl_removeColumnSort_noBroadcast(); + +private: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + bool m_isInitialized; + css::uno::Reference< css::awt::grid::XMutableGridDataModel > m_delegator; + css::uno::Reference< css::i18n::XCollator > m_collator; + ::sal_Int32 m_currentSortColumn; + bool m_sortAscending; + ::std::vector< ::sal_Int32 > m_publicToPrivateRowIndex; + ::std::vector< ::sal_Int32 > m_privateToPublicRowIndex; +}; + +class MethodGuard : public ::comphelper::ComponentGuard +{ +public: + MethodGuard( SortableGridDataModel& i_component, ::cppu::OBroadcastHelper & i_broadcastHelper ) + :comphelper::ComponentGuard( i_component, i_broadcastHelper ) + { + if ( !i_component.isInitialized() ) + throw css::lang::NotInitializedException( OUString(), i_component ); + } +}; + +template< class STLCONTAINER > +void lcl_clear( STLCONTAINER& i_container ) +{ + STLCONTAINER().swap(i_container); +} + + SortableGridDataModel::SortableGridDataModel( Reference< XComponentContext > const & rxContext ) + :SortableGridDataModel_Base( m_aMutex ) + ,SortableGridDataModel_PrivateBase() + ,m_xContext( rxContext ) + ,m_isInitialized( false ) + ,m_delegator() + ,m_collator() + ,m_currentSortColumn( -1 ) + ,m_sortAscending( true ) + ,m_publicToPrivateRowIndex() + ,m_privateToPublicRowIndex() + { + } + + + SortableGridDataModel::SortableGridDataModel( SortableGridDataModel const & i_copySource ) + :cppu::BaseMutex() + ,SortableGridDataModel_Base( m_aMutex ) + ,SortableGridDataModel_PrivateBase() + ,m_xContext( i_copySource.m_xContext ) + ,m_isInitialized( true ) + ,m_delegator() + ,m_collator( i_copySource.m_collator ) + ,m_currentSortColumn( i_copySource.m_currentSortColumn ) + ,m_sortAscending( i_copySource.m_sortAscending ) + ,m_publicToPrivateRowIndex( i_copySource.m_publicToPrivateRowIndex ) + ,m_privateToPublicRowIndex( i_copySource.m_privateToPublicRowIndex ) + { + ENSURE_OR_THROW( i_copySource.m_delegator.is(), + "not expected to be called for a disposed copy source!" ); + m_delegator.set( i_copySource.m_delegator->createClone(), UNO_QUERY_THROW ); + } + + + SortableGridDataModel::~SortableGridDataModel() + { + if ( !rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + } + + + Any SAL_CALL SortableGridDataModel::queryInterface( const Type& aType ) + { + Any aReturn( SortableGridDataModel_Base::queryInterface( aType ) ); + if ( !aReturn.hasValue() ) + aReturn = SortableGridDataModel_PrivateBase::queryInterface( aType ); + return aReturn; + } + + + void SAL_CALL SortableGridDataModel::acquire( ) noexcept + { + SortableGridDataModel_Base::acquire(); + } + + + void SAL_CALL SortableGridDataModel::release( ) noexcept + { + SortableGridDataModel_Base::release(); + } + + + Sequence< Type > SAL_CALL SortableGridDataModel::getTypes( ) + { + return SortableGridDataModel_Base::getTypes(); + // don't expose the types got via SortableGridDataModel_PrivateBase - they're private, after all + } + + + Sequence< ::sal_Int8 > SAL_CALL SortableGridDataModel::getImplementationId( ) + { + return css::uno::Sequence<sal_Int8>(); + } + + Reference< XCollator > lcl_loadDefaultCollator_throw( const Reference<XComponentContext> & rxContext ) + { + Reference< XCollator > const xCollator = Collator::create( rxContext ); + xCollator->loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 ); + return xCollator; + } + + void SAL_CALL SortableGridDataModel::initialize( const Sequence< Any >& i_arguments ) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( m_delegator.is() ) + throw AlreadyInitializedException( OUString(), *this ); + + Reference< XMutableGridDataModel > xDelegator; + Reference< XCollator > xCollator; + switch ( i_arguments.getLength() ) + { + case 1: // SortableGridDataModel.create( XMutableGridDataModel ) + xDelegator.set( i_arguments[0], UNO_QUERY ); + xCollator = lcl_loadDefaultCollator_throw( m_xContext ); + break; + + case 2: // SortableGridDataModel.createWithCollator( XMutableGridDataModel, XCollator ) + xDelegator.set( i_arguments[0], UNO_QUERY ); + xCollator.set( i_arguments[1], UNO_QUERY ); + if ( !xCollator.is() ) + throw IllegalArgumentException( OUString(), *this, 2 ); + break; + } + if ( !xDelegator.is() ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + m_delegator = xDelegator; + m_collator = xCollator; + + m_delegator->addGridDataListener( this ); + + m_isInitialized = true; + } + + + GridDataEvent SortableGridDataModel::impl_createPublicEvent( GridDataEvent const & i_originalEvent ) const + { + GridDataEvent aEvent( i_originalEvent ); + aEvent.Source = *const_cast< SortableGridDataModel* >( this ); + aEvent.FirstRow = impl_getPublicRowIndex_nothrow( aEvent.FirstRow ); + aEvent.LastRow = impl_getPublicRowIndex_nothrow( aEvent.LastRow ); + return aEvent; + } + + + void SortableGridDataModel::impl_broadcast( void ( SAL_CALL XGridDataListener::*i_listenerMethod )( const GridDataEvent & ), + GridDataEvent const & i_publicEvent, MethodGuard& i_instanceLock ) + { + ::cppu::OInterfaceContainerHelper* pListeners = rBHelper.getContainer( cppu::UnoType<XGridDataListener>::get() ); + if ( pListeners == nullptr ) + return; + + i_instanceLock.clear(); + pListeners->notifyEach( i_listenerMethod, i_publicEvent ); + } + + + void SAL_CALL SortableGridDataModel::rowsInserted( const GridDataEvent& i_event ) + { + MethodGuard aGuard( *this, rBHelper ); + + if ( impl_isSorted_nothrow() ) + { + // no infrastructure is in place currently to sort the new row to its proper location, + // so we remove the sorting here. + impl_removeColumnSort( aGuard ); + aGuard.reset(); + } + + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + impl_broadcast( &XGridDataListener::rowsInserted, aEvent, aGuard ); + } + + void lcl_decrementValuesGreaterThan( ::std::vector< ::sal_Int32 > & io_indexMap, sal_Int32 const i_threshold ) + { + for ( auto& rIndex : io_indexMap ) + { + if ( rIndex >= i_threshold ) + --rIndex; + } + } + + void SortableGridDataModel::impl_rebuildIndexesAndNotify( MethodGuard& i_instanceLock ) + { + OSL_PRECOND( impl_isSorted_nothrow(), "SortableGridDataModel::impl_rebuildIndexesAndNotify: illegal call!" ); + + // clear the indexes + lcl_clear( m_publicToPrivateRowIndex ); + lcl_clear( m_privateToPublicRowIndex ); + + // rebuild the index + if ( !impl_reIndex_nothrow( m_currentSortColumn, m_sortAscending ) ) + { + impl_removeColumnSort( i_instanceLock ); + return; + } + + // broadcast an artificial event, saying that all rows have been removed + GridDataEvent const aRemovalEvent( *this, -1, -1, -1, -1 ); + impl_broadcast( &XGridDataListener::rowsRemoved, aRemovalEvent, i_instanceLock ); + i_instanceLock.reset(); + + // broadcast an artificial event, saying that n rows have been added + GridDataEvent const aAdditionEvent( *this, -1, -1, 0, m_delegator->getRowCount() - 1 ); + impl_broadcast( &XGridDataListener::rowsInserted, aAdditionEvent, i_instanceLock ); + } + + + void SAL_CALL SortableGridDataModel::rowsRemoved( const GridDataEvent& i_event ) + { + MethodGuard aGuard( *this, rBHelper ); + + // if the data is not sorted, broadcast the event unchanged + if ( !impl_isSorted_nothrow() ) + { + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard ); + return; + } + + // if all rows have been removed, also simply multiplex to own listeners + if ( i_event.FirstRow < 0 ) + { + lcl_clear( m_publicToPrivateRowIndex ); + lcl_clear( m_privateToPublicRowIndex ); + GridDataEvent aEvent( i_event ); + aEvent.Source = *this; + impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard ); + return; + } + + bool needReIndex = false; + if ( i_event.FirstRow != i_event.LastRow ) + { + OSL_ENSURE( false, "SortableGridDataModel::rowsRemoved: missing implementation - removal of multiple rows!" ); + needReIndex = true; + } + else if ( o3tl::make_unsigned( i_event.FirstRow ) >= m_privateToPublicRowIndex.size() ) + { + OSL_ENSURE( false, "SortableGridDataModel::rowsRemoved: inconsistent/wrong data!" ); + needReIndex = true; + } + + if ( needReIndex ) + { + impl_rebuildIndexesAndNotify( aGuard ); + return; + } + + // build public event version + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + + // remove the entries from the index maps + sal_Int32 const privateIndex = i_event.FirstRow; + sal_Int32 const publicIndex = aEvent.FirstRow; + + m_publicToPrivateRowIndex.erase( m_publicToPrivateRowIndex.begin() + publicIndex ); + m_privateToPublicRowIndex.erase( m_privateToPublicRowIndex.begin() + privateIndex ); + + // adjust remaining entries in the index maps + lcl_decrementValuesGreaterThan( m_publicToPrivateRowIndex, privateIndex ); + lcl_decrementValuesGreaterThan( m_privateToPublicRowIndex, publicIndex ); + + // broadcast the event + impl_broadcast( &XGridDataListener::rowsRemoved, aEvent, aGuard ); + } + + + void SAL_CALL SortableGridDataModel::dataChanged( const GridDataEvent& i_event ) + { + MethodGuard aGuard( *this, rBHelper ); + + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + impl_broadcast( &XGridDataListener::dataChanged, aEvent, aGuard ); + } + + + void SAL_CALL SortableGridDataModel::rowHeadingChanged( const GridDataEvent& i_event ) + { + MethodGuard aGuard( *this, rBHelper ); + + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); + impl_broadcast( &XGridDataListener::rowHeadingChanged, aEvent, aGuard ); + } + + + void SAL_CALL SortableGridDataModel::disposing( const EventObject& ) + { + } + + class CellDataLessComparison + { + public: + CellDataLessComparison( + ::std::vector< Any > const & i_data, + ::comphelper::IKeyPredicateLess const & i_predicate, + bool const i_sortAscending + ) + :m_data( i_data ) + ,m_predicate( i_predicate ) + ,m_sortAscending( i_sortAscending ) + { + } + + bool operator()( sal_Int32 const i_lhs, sal_Int32 const i_rhs ) const + { + Any const & lhs = m_data[ i_lhs ]; + Any const & rhs = m_data[ i_rhs ]; + // <VOID/> is less than everything else + if ( !lhs.hasValue() ) + return m_sortAscending; + if ( !rhs.hasValue() ) + return !m_sortAscending; + + // actually compare + if ( m_sortAscending ) + return m_predicate.isLess( lhs, rhs ); + else + return m_predicate.isLess( rhs, lhs ); + } + + private: + ::std::vector< Any > const & m_data; + ::comphelper::IKeyPredicateLess const & m_predicate; + bool const m_sortAscending; + }; + + bool SortableGridDataModel::impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, bool const i_sortAscending ) + { + ::sal_Int32 const rowCount( getRowCount() ); + ::std::vector< ::sal_Int32 > aPublicToPrivate( rowCount ); + + try + { + // build an unsorted translation table, and retrieve the unsorted data + ::std::vector< Any > aColumnData( rowCount ); + Type dataType; + for ( ::sal_Int32 rowIndex = 0; rowIndex < rowCount; ++rowIndex ) + { + aColumnData[ rowIndex ] = m_delegator->getCellData( i_columnIndex, rowIndex ); + aPublicToPrivate[ rowIndex ] = rowIndex; + + // determine the data types we assume for the complete column + if ( ( dataType.getTypeClass() == TypeClass_VOID ) && aColumnData[ rowIndex ].hasValue() ) + dataType = aColumnData[ rowIndex ].getValueType(); + } + + // get predicate object + ::std::unique_ptr< ::comphelper::IKeyPredicateLess > const pPredicate( ::comphelper::getStandardLessPredicate( dataType, m_collator ) ); + ENSURE_OR_RETURN_FALSE( + pPredicate, "SortableGridDataModel::impl_reIndex_nothrow: no sortable data found!"); + + // then sort + CellDataLessComparison const aComparator( aColumnData, *pPredicate, i_sortAscending ); + ::std::sort( aPublicToPrivate.begin(), aPublicToPrivate.end(), aComparator ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + return false; + } + + // also build the "private to public" mapping + ::std::vector< sal_Int32 > aPrivateToPublic( aPublicToPrivate.size() ); + for ( size_t i=0; i<aPublicToPrivate.size(); ++i ) + aPrivateToPublic[ aPublicToPrivate[i] ] = i; + + m_publicToPrivateRowIndex.swap( aPublicToPrivate ); + m_privateToPublicRowIndex.swap( aPrivateToPublic ); + + return true; + } + + + void SAL_CALL SortableGridDataModel::sortByColumn( ::sal_Int32 i_columnIndex, sal_Bool i_sortAscending ) + { + MethodGuard aGuard( *this, rBHelper ); + + if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= getColumnCount() ) ) + throw IndexOutOfBoundsException( OUString(), *this ); + + if ( !impl_reIndex_nothrow( i_columnIndex, i_sortAscending ) ) + return; + + m_currentSortColumn = i_columnIndex; + m_sortAscending = i_sortAscending; + + impl_broadcast( + &XGridDataListener::dataChanged, + GridDataEvent( *this, -1, -1, -1, -1 ), + aGuard + ); + } + + + void SortableGridDataModel::impl_removeColumnSort_noBroadcast() + { + lcl_clear( m_publicToPrivateRowIndex ); + lcl_clear( m_privateToPublicRowIndex ); + + m_currentSortColumn = -1; + m_sortAscending = true; + } + + + void SortableGridDataModel::impl_removeColumnSort( MethodGuard& i_instanceLock ) + { + impl_removeColumnSort_noBroadcast(); + impl_broadcast( + &XGridDataListener::dataChanged, + GridDataEvent( *this, -1, -1, -1, -1 ), + i_instanceLock + ); + } + + + void SAL_CALL SortableGridDataModel::removeColumnSort( ) + { + MethodGuard aGuard( *this, rBHelper ); + impl_removeColumnSort( aGuard ); + } + + + css::beans::Pair< ::sal_Int32, sal_Bool > SAL_CALL SortableGridDataModel::getCurrentSortOrder( ) + { + MethodGuard aGuard( *this, rBHelper ); + + return css::beans::Pair< ::sal_Int32, sal_Bool >( m_currentSortColumn, m_sortAscending ); + } + + + void SAL_CALL SortableGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data ) + { + MethodGuard aGuard( *this, rBHelper ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->addRow( i_heading, i_data ); + } + + + void SAL_CALL SortableGridDataModel::addRows( const Sequence< Any >& i_headings, const Sequence< Sequence< Any > >& i_data ) + { + MethodGuard aGuard( *this, rBHelper ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->addRows( i_headings, i_data ); + } + + + void SAL_CALL SortableGridDataModel::insertRow( ::sal_Int32 i_index, const Any& i_heading, const Sequence< Any >& i_data ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = i_index == getRowCount() ? i_index : impl_getPrivateRowIndex_throw( i_index ); + // note that |RowCount| is a valid index in this method, but not for impl_getPrivateRowIndex_throw + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->insertRow( rowIndex, i_heading, i_data ); + } + + + void SAL_CALL SortableGridDataModel::insertRows( ::sal_Int32 i_index, const Sequence< Any>& i_headings, const Sequence< Sequence< Any > >& i_data ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = i_index == getRowCount() ? i_index : impl_getPrivateRowIndex_throw( i_index ); + // note that |RowCount| is a valid index in this method, but not for impl_getPrivateRowIndex_throw + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->insertRows( rowIndex, i_headings, i_data ); + } + + + void SAL_CALL SortableGridDataModel::removeRow( ::sal_Int32 i_rowIndex ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->removeRow( rowIndex ); + } + + + void SAL_CALL SortableGridDataModel::removeAllRows( ) + { + MethodGuard aGuard( *this, rBHelper ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->removeAllRows(); + } + + + void SAL_CALL SortableGridDataModel::updateCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateCellData( i_columnIndex, rowIndex, i_value ); + } + + + void SAL_CALL SortableGridDataModel::updateRowData( const Sequence< ::sal_Int32 >& i_columnIndexes, ::sal_Int32 i_rowIndex, const Sequence< Any >& i_values ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateRowData( i_columnIndexes, rowIndex, i_values ); + } + + + void SAL_CALL SortableGridDataModel::updateRowHeading( ::sal_Int32 i_rowIndex, const Any& i_heading ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateRowHeading( rowIndex, i_heading ); + } + + + void SAL_CALL SortableGridDataModel::updateCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex, const Any& i_value ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateCellToolTip( i_columnIndex, rowIndex, i_value ); + } + + + void SAL_CALL SortableGridDataModel::updateRowToolTip( ::sal_Int32 i_rowIndex, const Any& i_value ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->updateRowToolTip( rowIndex, i_value ); + } + + + void SAL_CALL SortableGridDataModel::addGridDataListener( const Reference< XGridDataListener >& i_listener ) + { + rBHelper.addListener( cppu::UnoType<XGridDataListener>::get(), i_listener ); + } + + + void SAL_CALL SortableGridDataModel::removeGridDataListener( const Reference< XGridDataListener >& i_listener ) + { + rBHelper.removeListener( cppu::UnoType<XGridDataListener>::get(), i_listener ); + } + + + ::sal_Int32 SAL_CALL SortableGridDataModel::getRowCount() + { + MethodGuard aGuard( *this, rBHelper ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getRowCount(); + } + + + ::sal_Int32 SAL_CALL SortableGridDataModel::getColumnCount() + { + MethodGuard aGuard( *this, rBHelper ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getColumnCount(); + } + + + Any SAL_CALL SortableGridDataModel::getCellData( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getCellData( i_columnIndex, rowIndex ); + } + + + Any SAL_CALL SortableGridDataModel::getCellToolTip( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getCellToolTip( i_columnIndex, rowIndex ); + } + + + Any SAL_CALL SortableGridDataModel::getRowHeading( ::sal_Int32 i_rowIndex ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getRowHeading( rowIndex ); + } + + + Sequence< Any > SAL_CALL SortableGridDataModel::getRowData( ::sal_Int32 i_rowIndex ) + { + MethodGuard aGuard( *this, rBHelper ); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getRowData( rowIndex ); + } + + + void SAL_CALL SortableGridDataModel::disposing() + { + m_currentSortColumn = -1; + + Reference< XComponent > const delegatorComponent( m_delegator ); + m_delegator->removeGridDataListener( this ); + m_delegator.clear(); + delegatorComponent->dispose(); + + Reference< XComponent > const collatorComponent( m_collator, UNO_QUERY ); + m_collator.clear(); + if ( collatorComponent.is() ) + collatorComponent->dispose(); + + lcl_clear( m_publicToPrivateRowIndex ); + lcl_clear( m_privateToPublicRowIndex ); + } + + + Reference< css::util::XCloneable > SAL_CALL SortableGridDataModel::createClone( ) + { + MethodGuard aGuard( *this, rBHelper ); + + return new SortableGridDataModel( *this ); + } + + + OUString SAL_CALL SortableGridDataModel::getImplementationName( ) + { + return "org.openoffice.comp.toolkit.SortableGridDataModel"; + } + + sal_Bool SAL_CALL SortableGridDataModel::supportsService( const OUString& i_serviceName ) + { + return cppu::supportsService(this, i_serviceName); + } + + Sequence< OUString > SAL_CALL SortableGridDataModel::getSupportedServiceNames( ) + { + return { "com.sun.star.awt.grid.SortableGridDataModel" }; + } + + + ::sal_Int32 SortableGridDataModel::impl_getPrivateRowIndex_throw( ::sal_Int32 const i_publicRowIndex ) const + { + if ( ( i_publicRowIndex < 0 ) || ( i_publicRowIndex >= m_delegator->getRowCount() ) ) + throw IndexOutOfBoundsException( OUString(), *const_cast< SortableGridDataModel* >( this ) ); + + if ( !impl_isSorted_nothrow() ) + // no need to translate anything + return i_publicRowIndex; + + ENSURE_OR_RETURN( o3tl::make_unsigned( i_publicRowIndex ) < m_publicToPrivateRowIndex.size(), + "SortableGridDataModel::impl_getPrivateRowIndex_throw: inconsistency!", i_publicRowIndex ); + // obviously the translation table contains too few elements - it should have exactly |getRowCount()| + // elements + + return m_publicToPrivateRowIndex[ i_publicRowIndex ]; + } + + + ::sal_Int32 SortableGridDataModel::impl_getPublicRowIndex_nothrow( ::sal_Int32 const i_privateRowIndex ) const + { + if ( !impl_isSorted_nothrow() ) + // no need to translate anything + return i_privateRowIndex; + + if ( i_privateRowIndex < 0 ) + return i_privateRowIndex; + + ENSURE_OR_RETURN( o3tl::make_unsigned( i_privateRowIndex ) < m_privateToPublicRowIndex.size(), + "SortableGridDataModel::impl_getPublicRowIndex_nothrow: invalid index!", i_privateRowIndex ); + + return m_privateToPublicRowIndex[ i_privateRowIndex ]; + } + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +org_openoffice_comp_toolkit_SortableGridDataModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new SortableGridDataModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/roadmapcontrol.cxx b/toolkit/source/controls/roadmapcontrol.cxx new file mode 100644 index 000000000..2640dc6b5 --- /dev/null +++ b/toolkit/source/controls/roadmapcontrol.cxx @@ -0,0 +1,513 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <controls/roadmapcontrol.hxx> +#include <controls/roadmapentry.hxx> +#include <toolkit/helper/property.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <helper/unopropertyarrayhelper.hxx> + +namespace toolkit +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + + +// helper + + +static void lcl_throwIllegalArgumentException( ) +{ // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this... + throw IllegalArgumentException(); +} + +static void lcl_throwIndexOutOfBoundsException( ) +{ // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this... + throw IndexOutOfBoundsException(); +} + + + // = UnoControlRoadmapModel + + + UnoControlRoadmapModel::UnoControlRoadmapModel( const Reference< XComponentContext >& i_factory ) + :UnoControlRoadmapModel_Base( i_factory ) + ,maContainerListeners( *this ) + { + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_IMAGEURL ); + ImplRegisterProperty( BASEPROPERTY_GRAPHIC ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_COMPLETE ); + ImplRegisterProperty( BASEPROPERTY_ACTIVATED ); + ImplRegisterProperty( BASEPROPERTY_CURRENTITEMID ); + ImplRegisterProperty( BASEPROPERTY_TABSTOP ); + ImplRegisterProperty( BASEPROPERTY_TEXT ); + } + + + OUString UnoControlRoadmapModel::getServiceName() + { + return "stardiv.vcl.controlmodel.Roadmap"; + } + + OUString UnoControlRoadmapModel::getImplementationName() + { + return "stardiv.Toolkit.UnoControlRoadmapModel"; + } + + css::uno::Sequence<OUString> + UnoControlRoadmapModel::getSupportedServiceNames() + { + auto s(UnoControlRoadmapModel_Base::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlRoadmapModel"; + ps[s.getLength() - 1] = "stardiv.vcl.controlmodel.Roadmap"; + return s; + } + + Any UnoControlRoadmapModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const + { + Any aReturn; + switch (nPropId) + { + case BASEPROPERTY_COMPLETE: + aReturn <<= true; + break; + case BASEPROPERTY_ACTIVATED: + aReturn <<= true; + break; + case BASEPROPERTY_CURRENTITEMID: + aReturn <<= sal_Int16(-1); + break; + case BASEPROPERTY_TEXT: + break; + case BASEPROPERTY_BORDER: + aReturn <<= sal_Int16(2); // No Border + break; + case BASEPROPERTY_DEFAULTCONTROL: + aReturn <<= OUString( "stardiv.vcl.control.Roadmap" ); + break; + default : aReturn = UnoControlRoadmapModel_Base::ImplGetDefaultValue( nPropId ); break; + } + + return aReturn; + } + + + Reference< XInterface > SAL_CALL UnoControlRoadmapModel::createInstance( ) + { + rtl::Reference<ORoadmapEntry> pRoadmapItem = new ORoadmapEntry(); + Reference< XInterface > xNewRoadmapItem = static_cast<cppu::OWeakObject*>(pRoadmapItem.get()); + return xNewRoadmapItem; + } + + + Reference< XInterface > SAL_CALL UnoControlRoadmapModel::createInstanceWithArguments( const Sequence< Any >& /*aArguments*/ ) + { + // Todo: implementation of the arguments handling + rtl::Reference<ORoadmapEntry> pRoadmapItem = new ORoadmapEntry(); + Reference< XInterface > xNewRoadmapItem = static_cast<cppu::OWeakObject*>(pRoadmapItem.get()); + return xNewRoadmapItem; + } + + + IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoControlRoadmapModel, UnoControlRoadmapModel_Base, UnoControlRoadmapModel_IBase ) + + + css::uno::Any SAL_CALL UnoControlRoadmapModel::queryAggregation( const css::uno::Type & rType ) + { + Any aRet = UnoControlRoadmapModel_Base::queryAggregation( rType ); + if ( !aRet.hasValue() ) + aRet = UnoControlRoadmapModel_IBase::queryInterface( rType ); + return aRet; + } + + + ::cppu::IPropertyArrayHelper& UnoControlRoadmapModel::getInfoHelper() + { + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; + } + + + // beans::XMultiPropertySet + + Reference< XPropertySetInfo > UnoControlRoadmapModel::getPropertySetInfo( ) + { + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + + sal_Int32 SAL_CALL UnoControlRoadmapModel::getCount() + { + return maRoadmapItems.size(); + } + + Any SAL_CALL UnoControlRoadmapModel::getByIndex( sal_Int32 Index ) + { + if ((Index < 0) || ( o3tl::make_unsigned(Index) >= maRoadmapItems.size())) + lcl_throwIndexOutOfBoundsException( ); + Any aAny( maRoadmapItems.at( Index ) ); + return aAny; + } + + + void UnoControlRoadmapModel::MakeRMItemValidation( sal_Int32 Index, const Reference< XInterface >& xRoadmapItem ) + { + if (( Index < 0 ) || (o3tl::make_unsigned(Index) > maRoadmapItems.size()) ) + lcl_throwIndexOutOfBoundsException( ); + if ( !xRoadmapItem.is() ) + lcl_throwIllegalArgumentException(); + Reference< XServiceInfo > xServiceInfo( xRoadmapItem, UNO_QUERY ); + bool bIsRoadmapItem = xServiceInfo->supportsService("com.sun.star.awt.RoadmapItem"); + if ( !bIsRoadmapItem ) + lcl_throwIllegalArgumentException(); + } + + + void UnoControlRoadmapModel::SetRMItemDefaultProperties( const Reference< XInterface >& xRoadmapItem) + { + Reference< XPropertySet > xPropertySet( xRoadmapItem, UNO_QUERY ); + Reference< XPropertySet > xProps( xRoadmapItem, UNO_QUERY ); + if ( xProps.is() ) + { + sal_Int32 LocID = 0; + Any aValue = xPropertySet->getPropertyValue("ID"); + aValue >>= LocID; + if (LocID < 0) // index may not be smaller than zero + { + xPropertySet->setPropertyValue("ID", Any(GetUniqueID()) ); + } + } + } + + +// The performance of this method could certainly be improved. +// As long as only vectors with up to 10 elements are +// involved it should be sufficient + sal_Int32 UnoControlRoadmapModel::GetUniqueID() + { + Any aAny; + bool bIncrement = true; + sal_Int32 CurID = 0; + sal_Int32 n_CurItemID = 0; + Reference< XInterface > CurRoadmapItem; + while ( bIncrement ) + { + bIncrement = false; + for ( const auto& rRoadmapItem : maRoadmapItems ) + { + CurRoadmapItem = rRoadmapItem; + Reference< XPropertySet > xPropertySet( CurRoadmapItem, UNO_QUERY ); + aAny = xPropertySet->getPropertyValue("ID"); + aAny >>= n_CurItemID; + if (n_CurItemID == CurID) + { + bIncrement = true; + CurID++; + break; + } + } + } + return CurID; + } + + + ContainerEvent UnoControlRoadmapModel::GetContainerEvent(sal_Int32 Index, const Reference< XInterface >& xRoadmapItem) + { + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Element <<= xRoadmapItem; + aEvent.Accessor <<= Index; + return aEvent; + } + + + sal_Int16 UnoControlRoadmapModel::GetCurrentItemID( const Reference< XPropertySet >& xPropertySet ) + { + Any aAny = xPropertySet->getPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ) ); + sal_Int16 n_CurrentItemID = 0; + aAny >>= n_CurrentItemID; + return n_CurrentItemID; + } + + + void SAL_CALL UnoControlRoadmapModel::insertByIndex( const sal_Int32 Index, const Any& Element) + { + if ( ( Index >= ( static_cast<sal_Int32>(maRoadmapItems.size()) + 1 ) ) || (Index < 0)) + lcl_throwIndexOutOfBoundsException( ); + Reference< XInterface > xRoadmapItem; + Element >>= xRoadmapItem; + MakeRMItemValidation( Index, xRoadmapItem); + SetRMItemDefaultProperties( xRoadmapItem ); + maRoadmapItems.insert( maRoadmapItems.begin() + Index, xRoadmapItem); + ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem); + maContainerListeners.elementInserted( aEvent ); + Reference< XPropertySet > xPropertySet( this ); + sal_Int16 n_CurrentItemID = GetCurrentItemID( xPropertySet ); + if ( Index <= n_CurrentItemID ) + { + Any aAny(static_cast<sal_Int16>( n_CurrentItemID + 1 ) ); + xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), aAny ); + } + } + + + void SAL_CALL UnoControlRoadmapModel::removeByIndex( sal_Int32 Index) + { + if ((Index < 0) || ( o3tl::make_unsigned(Index) > maRoadmapItems.size())) + lcl_throwIndexOutOfBoundsException( ); + Reference< XInterface > xRoadmapItem; + maRoadmapItems.erase( maRoadmapItems.begin() + Index ); + ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem); + maContainerListeners.elementRemoved( aEvent ); + Reference< XPropertySet > xPropertySet( this ); + sal_Int16 n_CurrentItemID = GetCurrentItemID( xPropertySet ); + Any aAny; + if ( Index > n_CurrentItemID ) + return; + + if ( n_CurrentItemID >= static_cast<sal_Int32>(maRoadmapItems.size()) ) + { + n_CurrentItemID = sal::static_int_cast< sal_Int16 >( + maRoadmapItems.size()-1); + if ( n_CurrentItemID < 0 ) + return; + aAny <<= n_CurrentItemID; + } + else if (Index == n_CurrentItemID) + aAny <<= sal_Int16(-1); + else if( Index < n_CurrentItemID) + aAny <<= static_cast<sal_Int16>( n_CurrentItemID - 1 ); + xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), aAny ); + } + + + void SAL_CALL UnoControlRoadmapModel::replaceByIndex( const sal_Int32 Index, const Any& Element) + { + Reference< XInterface > xRoadmapItem; + Element >>= xRoadmapItem; + MakeRMItemValidation( Index, xRoadmapItem); + SetRMItemDefaultProperties( xRoadmapItem ); + maRoadmapItems.erase( maRoadmapItems.begin() + Index ); + maRoadmapItems.insert( maRoadmapItems.begin() + Index, xRoadmapItem); //push_back( xRoadmapItem ); + ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem); + maContainerListeners.elementReplaced( aEvent ); + } + + + Type SAL_CALL UnoControlRoadmapModel::getElementType() + { + Type aType = cppu::UnoType<XPropertySet>::get(); + return aType; + } + + + sal_Bool SAL_CALL UnoControlRoadmapModel::hasElements() + { + return !maRoadmapItems.empty(); + } + + + void SAL_CALL UnoControlRoadmapModel::addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) + { + maContainerListeners.addInterface( xListener ); + } + + void SAL_CALL UnoControlRoadmapModel::removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) + { + maContainerListeners.removeInterface( xListener ); + } + + + // = UnoRoadmapControl + + + UnoRoadmapControl::UnoRoadmapControl() + :maItemListeners( *this ) + { + } + +IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoRoadmapControl, UnoControlRoadmap_Base, UnoControlRoadmap_IBase ) +IMPLEMENT_FORWARD_XINTERFACE2( UnoRoadmapControl, UnoControlRoadmap_Base, UnoControlRoadmap_IBase ) + + +sal_Bool SAL_CALL UnoRoadmapControl::setModel(const Reference< XControlModel >& _rModel) + { + Reference< XContainer > xC( getModel(), UNO_QUERY ); + if ( xC.is() ) + xC->removeContainerListener( this ); + + bool bReturn = UnoControlBase::setModel( _rModel ); + + xC.set(getModel(), css::uno::UNO_QUERY); + if ( xC.is() ) + xC->addContainerListener( this ); + + return bReturn; + } + + + OUString UnoRoadmapControl::GetComponentServiceName() const + { + return "Roadmap"; + } + + + void UnoRoadmapControl::dispose() + { + EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maItemListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); + } + + +void UnoRoadmapControl::elementInserted( const ContainerEvent& rEvent ) +{ + Reference< XInterface > xRoadmapItem; + rEvent.Element >>= xRoadmapItem; + Reference< XPropertySet > xRoadmapPropertySet( xRoadmapItem, UNO_QUERY ); + if ( xRoadmapPropertySet.is() ) + xRoadmapPropertySet->addPropertyChangeListener( OUString(), this ); + + Reference< XContainerListener > xPeer(getPeer(), UNO_QUERY); + if ( xPeer.is() ) + { + xPeer->elementInserted( rEvent ); + Reference < XPropertySet > xPropertySet( xPeer, UNO_QUERY ); + if ( xPropertySet.is() ) + xPropertySet->addPropertyChangeListener( OUString(), this ); + } +} + + +void UnoRoadmapControl::elementRemoved( const ContainerEvent& rEvent ) +{ + Reference< XContainerListener > xPeer(getPeer(), UNO_QUERY); + if ( xPeer.is() ) + xPeer->elementRemoved( rEvent ); + Reference< XInterface > xRoadmapItem; + rEvent.Element >>= xRoadmapItem; + Reference< XPropertySet > xPropertySet( xRoadmapItem, UNO_QUERY ); + if ( xPropertySet.is() ) + xPropertySet->removePropertyChangeListener( OUString(), this ); +} + + +void UnoRoadmapControl::elementReplaced( const ContainerEvent& rEvent ) +{ + Reference< XContainerListener > xPeer(getPeer(), UNO_QUERY); + if ( xPeer.is() ) + xPeer->elementReplaced( rEvent ); +} + + +void SAL_CALL UnoRoadmapControl::itemStateChanged( const ItemEvent& rEvent ) +{ + sal_Int16 CurItemIndex = sal::static_int_cast< sal_Int16 >(rEvent.ItemId); + Reference< XControlModel > xModel = getModel( ); + Reference< XPropertySet > xPropertySet( xModel, UNO_QUERY ); + xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), Any(CurItemIndex) ); + if ( maItemListeners.getLength() ) + maItemListeners.itemStateChanged( rEvent ); +} + + +void SAL_CALL UnoRoadmapControl::addItemListener( const Reference< XItemListener >& l ) +{ + maItemListeners.addInterface( l ); + if( getPeer().is() && maItemListeners.getLength() == 1 ) + { + Reference < XItemEventBroadcaster > xRoadmap( getPeer(), UNO_QUERY ); + xRoadmap->addItemListener( this ); + } +} + + +void SAL_CALL UnoRoadmapControl::removeItemListener( const Reference< XItemListener >& l ) +{ + if( getPeer().is() && maItemListeners.getLength() == 1 ) + { + Reference < XItemEventBroadcaster > xRoadmap( getPeer(), UNO_QUERY ); + xRoadmap->removeItemListener( this ); + } + + maItemListeners.removeInterface( l ); +} + + +void SAL_CALL UnoRoadmapControl::propertyChange( const PropertyChangeEvent& evt ) +{ + Reference< XPropertyChangeListener > xPeer(getPeer(), UNO_QUERY); + if ( xPeer.is() ) + xPeer->propertyChange( evt ); +} + +OUString UnoRoadmapControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoRoadmapControl"; +} + +css::uno::Sequence<OUString> UnoRoadmapControl::getSupportedServiceNames() +{ + auto s(UnoControlBase::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlRoadmap"; + ps[s.getLength() - 1] = "stardiv.vcl.control.Roadmap"; + return s; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlRoadmapModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoControlRoadmapModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoRoadmapControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoRoadmapControl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/roadmapentry.cxx b/toolkit/source/controls/roadmapentry.cxx new file mode 100644 index 000000000..3de60f707 --- /dev/null +++ b/toolkit/source/controls/roadmapentry.cxx @@ -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 . + */ + +#include <controls/roadmapentry.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <cppuhelper/supportsservice.hxx> + + +ORoadmapEntry::ORoadmapEntry() : OPropertyContainer( GetBroadcastHelper() ) +{ + // registerProperty or registerMayBeVoidProperty or registerPropertyNoMember + + registerProperty( "Label", RM_PROPERTY_ID_LABEL, + css::beans::PropertyAttribute::BOUND | + css::beans::PropertyAttribute::CONSTRAINED, + & m_sLabel, cppu::UnoType<decltype(m_sLabel)>::get() ); + m_nID = -1; + registerProperty( "ID", RM_PROPERTY_ID_ID, + css::beans::PropertyAttribute::BOUND | + css::beans::PropertyAttribute::CONSTRAINED, + & m_nID, cppu::UnoType<decltype(m_nID)>::get() ); + m_bEnabled = true; + registerProperty( "Enabled", RM_PROPERTY_ID_ENABLED, + css::beans::PropertyAttribute::BOUND | + css::beans::PropertyAttribute::MAYBEDEFAULT, + & m_bEnabled, cppu::UnoType<decltype(m_bEnabled)>::get() ); + + registerProperty( "Interactive", RM_PROPERTY_ID_INTERACTIVE, + css::beans::PropertyAttribute::BOUND | + css::beans::PropertyAttribute::MAYBEDEFAULT, + & m_bInteractive, cppu::UnoType<decltype(m_bInteractive)>::get() ); + + + // Note that the list of registered properties has to be fixed: Different + // instances of this class have to register the same set of properties with + // the same attributes. + + // This is because all instances of the class share the same PropertySetInfo + // which has been built from the registered property of _one_ instance. +} + + +IMPLEMENT_FORWARD_XINTERFACE2( ORoadmapEntry, ORoadmapEntry_Base, ::comphelper::OPropertyContainer ); +IMPLEMENT_FORWARD_XTYPEPROVIDER2( ORoadmapEntry, ORoadmapEntry_Base, ::comphelper::OPropertyContainer ); + // order matters: + // the first is the class name + // the second is the class which implements the ref-counting + // the third up to n-th (when using IMPLEMENT_FORWARD_*3 and so on) are other base classes + // whose XInterface and XTypeProvider implementations should be merged + + +css::uno::Reference< css:: beans::XPropertySetInfo > SAL_CALL + ORoadmapEntry::getPropertySetInfo() +{ + return createPropertySetInfo( getInfoHelper() ); +} + +OUString SAL_CALL ORoadmapEntry::getImplementationName( ) +{ + return "com.sun.star.comp.toolkit.RoadmapItem"; +} + +sal_Bool SAL_CALL ORoadmapEntry::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ORoadmapEntry::getSupportedServiceNames( ) +{ + return { "com.sun.star.awt.RoadmapItem" }; +} + +::cppu::IPropertyArrayHelper& ORoadmapEntry::getInfoHelper() +{ + return *getArrayHelper(); +} + + +::cppu::IPropertyArrayHelper* ORoadmapEntry::createArrayHelper() const +{ + css::uno::Sequence< css::beans::Property > aProps; + // describes all properties which have been registered in the ctor + describeProperties( aProps ); + + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/spinningprogress.cxx b/toolkit/source/controls/spinningprogress.cxx new file mode 100644 index 000000000..ccd295d1a --- /dev/null +++ b/toolkit/source/controls/spinningprogress.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 <com/sun/star/uno/XComponentContext.hpp> +#include <controls/animatedimages.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/toolkit/throbber.hxx> + +using namespace css; +using namespace css::uno; + +namespace { + +typedef toolkit::AnimatedImagesControlModel SpinningProgressControlModel_Base; +class SpinningProgressControlModel : public SpinningProgressControlModel_Base +{ +public: + explicit SpinningProgressControlModel( css::uno::Reference< css::uno::XComponentContext > const & i_factory ); + + SpinningProgressControlModel(SpinningProgressControlModel const &) = default; + SpinningProgressControlModel(SpinningProgressControlModel &&) = default; + SpinningProgressControlModel & operator =(SpinningProgressControlModel const &) = delete; // due to SpinningProgressControlModel_Base + SpinningProgressControlModel & operator =(SpinningProgressControlModel &&) = delete; // due to SpinningProgressControlModel_Base + + virtual rtl::Reference<UnoControlModel> Clone() const override; + + // XPropertySet + css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // XPersistObject + OUString SAL_CALL getServiceName() override; + + // XServiceInfo + OUString SAL_CALL getImplementationName( ) override; + css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +protected: + virtual ~SpinningProgressControlModel() override; +}; + + SpinningProgressControlModel::SpinningProgressControlModel( Reference< XComponentContext > const & i_factory ) + :SpinningProgressControlModel_Base( i_factory ) + { + // default image sets + osl_atomic_increment( &m_refCount ); + { + try + { + Throbber::ImageSet aImageSets[] = + { + Throbber::ImageSet::N16px, Throbber::ImageSet::N32px, Throbber::ImageSet::N64px + }; + for ( size_t i=0; i < SAL_N_ELEMENTS(aImageSets); ++i ) + { + const ::std::vector< OUString > aDefaultURLs( Throbber::getDefaultImageURLs( aImageSets[i] ) ); + const Sequence< OUString > aImageURLs( aDefaultURLs.data(), aDefaultURLs.size() ); + insertImageSet( i, aImageURLs ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + } + osl_atomic_decrement( &m_refCount ); + } + + + SpinningProgressControlModel::~SpinningProgressControlModel() + { + } + + + rtl::Reference<UnoControlModel> SpinningProgressControlModel::Clone() const + { + return new SpinningProgressControlModel( *this ); + } + + + Reference< beans::XPropertySetInfo > SAL_CALL SpinningProgressControlModel::getPropertySetInfo( ) + { + static Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + + OUString SAL_CALL SpinningProgressControlModel::getServiceName() + { + return "com.sun.star.awt.SpinningProgressControlModel"; + } + + + OUString SAL_CALL SpinningProgressControlModel::getImplementationName( ) + { + return "org.openoffice.comp.toolkit.SpinningProgressControlModel"; + } + + + Sequence< OUString > SAL_CALL SpinningProgressControlModel::getSupportedServiceNames() + { + return { "com.sun.star.awt.SpinningProgressControlModel", + "com.sun.star.awt.AnimatedImagesControlModel", + "com.sun.star.awt.UnoControlModel" }; + } + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +org_openoffice_comp_toolkit_SpinningProgressControlModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new SpinningProgressControlModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/stdtabcontroller.cxx b/toolkit/source/controls/stdtabcontroller.cxx new file mode 100644 index 000000000..c900d6d15 --- /dev/null +++ b/toolkit/source/controls/stdtabcontroller.cxx @@ -0,0 +1,415 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/beans/XPropertySet.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/awt/XVclContainerPeer.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <controls/stdtabcontroller.hxx> +#include <toolkit/awt/vclxwindow.hxx> +#include <toolkit/helper/macros.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <sal/log.hxx> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> +#include <comphelper/sequence.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + + + +StdTabController::StdTabController() +{ +} + +StdTabController::~StdTabController() +{ +} + +bool StdTabController::ImplCreateComponentSequence( + Sequence< Reference< XControl > >& rControls, + const Sequence< Reference< XControlModel > >& rModels, + Sequence< Reference< XWindow > >& rComponents, + Sequence< Any>* pTabStops, + bool bPeerComponent ) +{ + // Get only the requested controls + sal_Int32 nModels = rModels.getLength(); + if (nModels != rControls.getLength()) + { + Sequence< Reference< XControl > > aSeq( nModels ); + auto aSeqRange = asNonConstRange(aSeq); + Reference< XControl > xCurrentControl; + + sal_Int32 nRealControls = 0; + for (const Reference< XControlModel >& rModel : rModels) + { + xCurrentControl = FindControl(rControls, rModel); + if (xCurrentControl.is()) + aSeqRange[nRealControls++] = xCurrentControl; + } + aSeq.realloc(nRealControls); + rControls = aSeq; + } + + // there may be less controls than models, but never more controls than models + assert(rControls.getLength() <= rModels.getLength()); + + sal_Int32 nCtrls = rControls.getLength(); + rComponents.realloc( nCtrls ); + Reference< XWindow > * pComps = rComponents.getArray(); + Any* pTabs = nullptr; + + + if ( pTabStops ) + { + *pTabStops = Sequence< Any>( nCtrls ); + pTabs = pTabStops->getArray(); + } + + bool bOK = true; + for ( const Reference< XControl >& xCtrl : std::as_const(rControls) ) + { + // Get the matching control for this model + if ( !xCtrl.is() ) + { + SAL_WARN("toolkit", "Control not found" ); + bOK = false; + break; + } + + if (bPeerComponent) + pComps->set(xCtrl->getPeer(), UNO_QUERY); + else + pComps->set(xCtrl, UNO_QUERY); + + // TabStop-Property + if ( pTabs ) + { + // opt: Constant String for TabStop name + static constexpr OUStringLiteral aTabStopName = u"Tabstop"; + + Reference< XPropertySet > xPSet( xCtrl->getModel(), UNO_QUERY ); + Reference< XPropertySetInfo > xInfo = xPSet->getPropertySetInfo(); + if( xInfo->hasPropertyByName( aTabStopName ) ) + *pTabs++ = xPSet->getPropertyValue( aTabStopName ); + else + ++pTabs; + } + + ++pComps; + } + return bOK; +} + +void StdTabController::ImplActivateControl( bool bFirst ) const +{ + // HACK due to bug #53688#, map controls onto an interface if remote controls may occur + Sequence< Reference< XControl > > aCtrls = const_cast<StdTabController*>(this)->getControls(); + const Reference< XControl > * pControls = aCtrls.getConstArray(); + sal_uInt32 nCount = aCtrls.getLength(); + + for ( sal_uInt32 n = bFirst ? 0 : nCount; bFirst ? n < nCount : n != 0; ) + { + sal_uInt32 nCtrl = bFirst ? n++ : --n; + DBG_ASSERT( pControls[nCtrl].is(), "Control not in Container!" ); + if ( pControls[nCtrl].is() ) + { + Reference< XWindowPeer > xCP = pControls[nCtrl]->getPeer(); + if ( xCP.is() ) + { + VCLXWindow* pC = comphelper::getFromUnoTunnel<VCLXWindow>( xCP ); + if ( pC && pC->GetWindow() && ( pC->GetWindow()->GetStyle() & WB_TABSTOP ) ) + { + pC->GetWindow()->GrabFocus(); + break; + } + } + } + } +} + +// XInterface +Any StdTabController::queryAggregation( const Type & rType ) +{ + Any aRet = ::cppu::queryInterface( rType, + static_cast< XTabController* >(this), + static_cast< XServiceInfo* >(this), + static_cast< XTypeProvider* >(this) ); + return (aRet.hasValue() ? aRet : OWeakAggObject::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( StdTabController ) + +// XTypeProvider +css::uno::Sequence< css::uno::Type > StdTabController::getTypes() +{ + static const css::uno::Sequence< css::uno::Type > aTypeList { + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<XTabController>::get(), + cppu::UnoType<XServiceInfo>::get() + }; + return aTypeList; +} + +void StdTabController::setModel( const Reference< XTabControllerModel >& Model ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + mxModel = Model; +} + +Reference< XTabControllerModel > StdTabController::getModel( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + return mxModel; +} + +void StdTabController::setContainer( const Reference< XControlContainer >& Container ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + mxControlContainer = Container; +} + +Reference< XControlContainer > StdTabController::getContainer( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + return mxControlContainer; +} + +Sequence< Reference< XControl > > StdTabController::getControls( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + Sequence< Reference< XControl > > aSeq; + + if ( mxControlContainer.is() ) + { + const Sequence< Reference< XControlModel > > aModels = mxModel->getControlModels(); + + Sequence< Reference< XControl > > xCtrls = mxControlContainer->getControls(); + + sal_Int32 nCtrls = aModels.getLength(); + aSeq = Sequence< Reference< XControl > >( nCtrls ); + std::transform(aModels.begin(), aModels.end(), aSeq.getArray(), + [&xCtrls](const Reference< XControlModel >& xCtrlModel) -> Reference< XControl > { + return FindControl( xCtrls, xCtrlModel ); }); + } + return aSeq; +} + +namespace { + +struct ComponentEntry +{ + css::awt::XWindow* pComponent; + ::Point aPos; +}; + +} + +void StdTabController::autoTabOrder( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + DBG_ASSERT( mxControlContainer.is(), "autoTabOrder: No ControlContainer!" ); + if ( !mxControlContainer.is() ) + return; + + Sequence< Reference< XControlModel > > aSeq = mxModel->getControlModels(); + Sequence< Reference< XWindow > > aCompSeq; + + // This may return a TabController, which returns desired list of controls faster + Sequence< Reference< XControl > > aControls = getControls(); + + // #58317# Some Models may be missing from the Container. Plus there is a + // autoTabOrder call later on. + if( !ImplCreateComponentSequence( aControls, aSeq, aCompSeq, nullptr, false ) ) + return; + + sal_uInt32 nCtrls = aCompSeq.getLength(); + + // insert sort algorithm + std::vector< ComponentEntry > aCtrls; + aCtrls.reserve(nCtrls); + for ( const Reference< XWindow >& rComponent : std::as_const(aCompSeq) ) + { + XWindow* pC = rComponent.get(); + ComponentEntry newEntry; + newEntry.pComponent = pC; + awt::Rectangle aPosSize = pC->getPosSize(); + newEntry.aPos.setX( aPosSize.X ); + newEntry.aPos.setY( aPosSize.Y ); + + decltype(aCtrls)::size_type nPos; + for ( nPos = 0; nPos < aCtrls.size(); nPos++ ) + { + ComponentEntry& rEntry = aCtrls[ nPos ]; + if ( ( rEntry.aPos.Y() > newEntry.aPos.Y() ) || + ( ( rEntry.aPos.Y() == newEntry.aPos.Y() ) && ( rEntry.aPos.X() > newEntry.aPos.X() ) ) ) + break; + } + if ( nPos < aCtrls.size() ) { + aCtrls.insert( aCtrls.begin() + nPos, newEntry ); + } else { + aCtrls.push_back( newEntry ); + } + } + + Sequence< Reference< XControlModel > > aNewSeq( nCtrls ); + std::transform(aCtrls.begin(), aCtrls.end(), aNewSeq.getArray(), + [](const ComponentEntry& rEntry) -> Reference< XControlModel > { + Reference< XControl > xUC( rEntry.pComponent, UNO_QUERY ); + return xUC->getModel(); + }); + + mxModel->setControlModels( aNewSeq ); +} + +void StdTabController::activateTabOrder( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + // Activate tab order for the control container + + Reference< XControl > xC( mxControlContainer, UNO_QUERY ); + Reference< XVclContainerPeer > xVclContainerPeer; + if ( xC.is() ) + xVclContainerPeer.set(xC->getPeer(), css::uno::UNO_QUERY); + if ( !xC.is() || !xVclContainerPeer.is() ) + return; + + // This may return a TabController, which returns desired list of controls faster + // (the dreaded UNO aggregation, retrieve the thing that we are part of) + Reference<XTabController> xTabController( static_cast<XTabController*>(this), UNO_QUERY ); + + // Get a flattened list of controls sequences + Sequence< Reference< XControlModel > > aModels = mxModel->getControlModels(); + Sequence< Reference< XWindow > > aCompSeq; + Sequence< Any> aTabSeq; + + // DG: For the sake of optimization, retrieve Controls from getControls(), + // this may sound counterproductive, but leads to performance improvements + // in practical scenarios (Forms) + Sequence< Reference< XControl > > aControls = xTabController->getControls(); + + // #58317# Some Models may be missing from the Container. Plus there is a + // autoTabOrder call later on. + if( !ImplCreateComponentSequence( aControls, aModels, aCompSeq, &aTabSeq, true ) ) + return; + + xVclContainerPeer->setTabOrder( aCompSeq, aTabSeq, mxModel->getGroupControl() ); + + OUString aName; + Sequence< Reference< XControlModel > > aThisGroupModels; + Sequence< Reference< XWindow > > aControlComponents; + + sal_uInt32 nGroups = mxModel->getGroupCount(); + for ( sal_uInt32 nG = 0; nG < nGroups; nG++ ) + { + mxModel->getGroup( nG, aThisGroupModels, aName ); + + aControls = xTabController->getControls(); + // ImplCreateComponentSequence has a really strange semantics regarding it's first parameter: + // upon method entry, it expects a super set of the controls which it returns + // this means we need to completely fill this sequence with all available controls before + // calling into ImplCreateComponentSequence + + aControlComponents.realloc( 0 ); + + ImplCreateComponentSequence( aControls, aThisGroupModels, aControlComponents, nullptr, true ); + xVclContainerPeer->setGroup( aControlComponents ); + } +} + +void StdTabController::activateFirst( ) +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); //TODO: necessary? + + ImplActivateControl( true ); +} + +void StdTabController::activateLast( ) +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); //TODO: necessary? + + ImplActivateControl( false ); +} + +OUString StdTabController::getImplementationName() +{ + return "stardiv.Toolkit.StdTabController"; +} + +sal_Bool StdTabController::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> StdTabController::getSupportedServiceNames() +{ + return css::uno::Sequence<OUString>{ + "com.sun.star.awt.TabController", + "stardiv.vcl.control.TabController"}; +} + +Reference< XControl > StdTabController::FindControl( Sequence< Reference< XControl > >& rCtrls, + const Reference< XControlModel > & rxCtrlModel ) +{ + if (!rxCtrlModel.is()) + throw lang::IllegalArgumentException("No valid XControlModel", + uno::Reference<uno::XInterface>(), 0); + + auto pCtrl = std::find_if(std::cbegin(rCtrls), std::cend(rCtrls), + [&rxCtrlModel](const Reference< XControl >& rCtrl) { + Reference< XControlModel > xModel(rCtrl.is() ? rCtrl->getModel() : Reference< XControlModel > ()); + return xModel.get() == rxCtrlModel.get(); + }); + if (pCtrl != std::cend(rCtrls)) + { + auto n = static_cast<sal_Int32>(std::distance(std::cbegin(rCtrls), pCtrl)); + Reference< XControl > xCtrl( *pCtrl ); + ::comphelper::removeElementAt( rCtrls, n ); + return xCtrl; + } + return Reference< XControl > (); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_StdTabController_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new StdTabController()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/stdtabcontrollermodel.cxx b/toolkit/source/controls/stdtabcontrollermodel.cxx new file mode 100644 index 000000000..43fd80f17 --- /dev/null +++ b/toolkit/source/controls/stdtabcontrollermodel.cxx @@ -0,0 +1,439 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/io/XMarkableStream.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <controls/stdtabcontrollermodel.hxx> +#include <toolkit/helper/macros.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <tools/debug.hxx> + +#define UNOCONTROL_STREAMVERSION short(2) + + + +UnoControlModelEntryList::UnoControlModelEntryList() +{ +} + +UnoControlModelEntryList::~UnoControlModelEntryList() +{ + Reset(); +} + +void UnoControlModelEntryList::Reset() +{ + for ( size_t n = maList.size(); n; ) + DestroyEntry( --n ); +} + +void UnoControlModelEntryList::DestroyEntry( size_t nEntry ) +{ + UnoControlModelEntryListBase::iterator it = maList.begin(); + ::std::advance( it, nEntry ); + + if ( (*it)->bGroup ) + delete (*it)->pGroup; + else + delete (*it)->pxControl; + + delete *it; + maList.erase( it ); +} + +size_t UnoControlModelEntryList::size() const { + return maList.size(); +} + +UnoControlModelEntry* UnoControlModelEntryList::operator[]( size_t i ) const { + return ( i < maList.size() ) ? maList[ i ] : nullptr; +} + +void UnoControlModelEntryList::push_back( UnoControlModelEntry* item ) { + maList.push_back( item ); +} + +void UnoControlModelEntryList::insert( size_t i, UnoControlModelEntry* item ) { + if ( i < maList.size() ) { + UnoControlModelEntryListBase::iterator it = maList.begin(); + ::std::advance( it, i ); + maList.insert( it, item ); + } else { + maList.push_back( item ); + } +} + + + +StdTabControllerModel::StdTabControllerModel() +{ + mbGroupControl = true; +} + +StdTabControllerModel::~StdTabControllerModel() +{ +} + +sal_uInt32 StdTabControllerModel::ImplGetControlCount( const UnoControlModelEntryList& rList ) const +{ + sal_uInt32 nCount = 0; + size_t nEntries = rList.size(); + for ( size_t n = 0; n < nEntries; n++ ) + { + UnoControlModelEntry* pEntry = rList[ n ]; + if ( pEntry->bGroup ) + nCount += ImplGetControlCount( *pEntry->pGroup ); + else + nCount++; + } + return nCount; +} + +void StdTabControllerModel::ImplGetControlModels( css::uno::Reference< css::awt::XControlModel > ** ppRefs, const UnoControlModelEntryList& rList ) const +{ + size_t nEntries = rList.size(); + for ( size_t n = 0; n < nEntries; n++ ) + { + UnoControlModelEntry* pEntry = rList[ n ]; + if ( pEntry->bGroup ) + ImplGetControlModels( ppRefs, *pEntry->pGroup ); + else + { + **ppRefs = *pEntry->pxControl; + (*ppRefs)++; + } + } +} + +void StdTabControllerModel::ImplSetControlModels( UnoControlModelEntryList& rList, const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& Controls ) +{ + for ( const css::uno::Reference< css::awt::XControlModel >& rRef : Controls ) + { + UnoControlModelEntry* pNewEntry = new UnoControlModelEntry; + pNewEntry->bGroup = false; + pNewEntry->pxControl = new css::uno::Reference< css::awt::XControlModel > ; + *pNewEntry->pxControl = rRef; + rList.push_back( pNewEntry ); + } +} + +sal_uInt32 StdTabControllerModel::ImplGetControlPos( const css::uno::Reference< css::awt::XControlModel >& rCtrl, const UnoControlModelEntryList& rList ) +{ + for ( size_t n = rList.size(); n; ) + { + UnoControlModelEntry* pEntry = rList[ --n ]; + if ( !pEntry->bGroup && ( *pEntry->pxControl == rCtrl ) ) + return n; + } + return CONTROLPOS_NOTFOUND; +} + +static void ImplWriteControls( const css::uno::Reference< css::io::XObjectOutputStream > & OutStream, const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& rCtrls ) +{ + css::uno::Reference< css::io::XMarkableStream > xMark( OutStream, css::uno::UNO_QUERY ); + DBG_ASSERT( xMark.is(), "write: no XMarkableStream!" ); + + sal_uInt32 nStoredControls = 0; + sal_Int32 nDataBeginMark = xMark->createMark(); + + OutStream->writeLong( 0 ); // DataLen + OutStream->writeLong( 0 ); // nStoredControls + + for ( const css::uno::Reference< css::awt::XControlModel >& xI : rCtrls ) + { + css::uno::Reference< css::io::XPersistObject > xPO( xI, css::uno::UNO_QUERY ); + DBG_ASSERT( xPO.is(), "write: Control doesn't support XPersistObject" ); + if ( xPO.is() ) + { + OutStream->writeObject( xPO ); + nStoredControls++; + } + } + sal_Int32 nDataLen = xMark->offsetToMark( nDataBeginMark ); + xMark->jumpToMark( nDataBeginMark ); + OutStream->writeLong( nDataLen ); + OutStream->writeLong( nStoredControls ); + xMark->jumpToFurthest(); + xMark->deleteMark(nDataBeginMark); +} + +static css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > ImplReadControls( const css::uno::Reference< css::io::XObjectInputStream > & InStream ) +{ + css::uno::Reference< css::io::XMarkableStream > xMark( InStream, css::uno::UNO_QUERY ); + DBG_ASSERT( xMark.is(), "write: no XMarkableStream!" ); + + sal_Int32 nDataBeginMark = xMark->createMark(); + + sal_Int32 nDataLen = InStream->readLong(); + sal_uInt32 nCtrls = InStream->readLong(); + + css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > aSeq( nCtrls ); + for ( sal_uInt32 n = 0; n < nCtrls; n++ ) + { + css::uno::Reference< css::io::XPersistObject > xObj = InStream->readObject(); + css::uno::Reference< css::awt::XControlModel > xI( xObj, css::uno::UNO_QUERY ); + aSeq.getArray()[n] = xI; + } + + // Skip remainder if more data exists than this version recognizes + xMark->jumpToMark( nDataBeginMark ); + InStream->skipBytes( nDataLen ); + xMark->deleteMark(nDataBeginMark); + return aSeq; +} + + +// css::uno::XInterface +css::uno::Any StdTabControllerModel::queryAggregation( const css::uno::Type & rType ) +{ + css::uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< css::awt::XTabControllerModel* >(this), + static_cast< css::lang::XServiceInfo* >(this), + static_cast< css::io::XPersistObject* >(this), + static_cast< css::lang::XTypeProvider* >(this) ); + return (aRet.hasValue() ? aRet : OWeakAggObject::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( StdTabControllerModel ) + +// css::lang::XTypeProvider +css::uno::Sequence< css::uno::Type > StdTabControllerModel::getTypes() +{ + static const css::uno::Sequence< css::uno::Type > aTypeList { + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<css::awt::XTabControllerModel>::get(), + cppu::UnoType<css::lang::XServiceInfo>::get(), + cppu::UnoType<css::io::XPersistObject>::get() + }; + return aTypeList; +} + +sal_Bool StdTabControllerModel::getGroupControl( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + return mbGroupControl; +} + +void StdTabControllerModel::setGroupControl( sal_Bool GroupControl ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + mbGroupControl = GroupControl; +} + +void StdTabControllerModel::setControlModels( const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& Controls ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + maControls.Reset(); + ImplSetControlModels( maControls, Controls ); +} + +css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > StdTabControllerModel::getControlModels( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > aSeq( ImplGetControlCount( maControls ) ); + css::uno::Reference< css::awt::XControlModel > * pRefs = aSeq.getArray(); + ImplGetControlModels( &pRefs, maControls ); + return aSeq; +} + +void StdTabControllerModel::setGroup( const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& Group, const OUString& GroupName ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + // The controls might occur as a flat list and will be grouped. + // Nested groups are not possible. + // The first element of a group determines its position. + UnoControlModelEntry* pNewEntry = new UnoControlModelEntry; + pNewEntry->bGroup = true; + pNewEntry->pGroup = new UnoControlModelEntryList; + pNewEntry->pGroup->SetName( GroupName ); + ImplSetControlModels( *pNewEntry->pGroup, Group ); + + bool bInserted = false; + size_t nElements = pNewEntry->pGroup->size(); + for ( size_t n = 0; n < nElements; n++ ) + { + UnoControlModelEntry* pEntry = (*pNewEntry->pGroup)[ n ]; + if ( !pEntry->bGroup ) + { + sal_uInt32 nPos = ImplGetControlPos( *pEntry->pxControl, maControls ); + // At the beginning, all Controls should be in a flattened list + DBG_ASSERT( nPos != CONTROLPOS_NOTFOUND, "setGroup - Element not found" ); + if ( nPos != CONTROLPOS_NOTFOUND ) + { + maControls.DestroyEntry( nPos ); + if ( !bInserted ) + { + maControls.insert( nPos, pNewEntry ); + bInserted = true; + } + } + } + } + if ( !bInserted ) + maControls.push_back( pNewEntry ); +} + +sal_Int32 StdTabControllerModel::getGroupCount( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + // Start with only one group layer, even though Model and Impl-methods + // work recursively, this is not presented to the outside. + + sal_Int32 nGroups = 0; + size_t nEntries = maControls.size(); + for ( size_t n = 0; n < nEntries; n++ ) + { + UnoControlModelEntry* pEntry = maControls[ n ]; + if ( pEntry->bGroup ) + nGroups++; + } + return nGroups; +} + +void StdTabControllerModel::getGroup( sal_Int32 nGroup, css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& rGroup, OUString& rName ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > aSeq; + sal_uInt32 nG = 0; + size_t nEntries = maControls.size(); + for ( size_t n = 0; n < nEntries; n++ ) + { + UnoControlModelEntry* pEntry = maControls[ n ]; + if ( pEntry->bGroup ) + { + if ( nG == static_cast<sal_uInt32>(nGroup) ) + { + sal_uInt32 nCount = ImplGetControlCount( *pEntry->pGroup ); + aSeq = css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >( nCount ); + css::uno::Reference< css::awt::XControlModel > * pRefs = aSeq.getArray(); + ImplGetControlModels( &pRefs, *pEntry->pGroup ); + rName = pEntry->pGroup->GetName(); + break; + } + nG++; + } + } + rGroup = aSeq; +} + +void StdTabControllerModel::getGroupByName( const OUString& rName, css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& rGroup ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + sal_uInt32 nGroup = 0; + size_t nEntries = maControls.size(); + for ( size_t n = 0; n < nEntries; n++ ) + { + UnoControlModelEntry* pEntry = maControls[ n ]; + if ( pEntry->bGroup ) + { + if ( pEntry->pGroup->GetName() == rName ) + { + OUString Dummy; + getGroup( nGroup, rGroup, Dummy ); + break; + } + nGroup++; + } + } +} + + +// css::io::XPersistObject +OUString StdTabControllerModel::getServiceName( ) +{ + return "stardiv.vcl.controlmodel.TabController"; +} + +void StdTabControllerModel::write( const css::uno::Reference< css::io::XObjectOutputStream >& OutStream ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::uno::Reference< css::io::XMarkableStream > xMark( OutStream, css::uno::UNO_QUERY ); + DBG_ASSERT( xMark.is(), "write: no XMarkableStream!" ); + + OutStream->writeShort( UNOCONTROL_STREAMVERSION ); + + css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > aCtrls = getControlModels(); + ImplWriteControls( OutStream, aCtrls ); + + sal_uInt32 nGroups = getGroupCount(); + OutStream->writeLong( nGroups ); + for ( sal_uInt32 n = 0; n < nGroups; n++ ) + { + css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > aGroupCtrls; + OUString aGroupName; + getGroup( n, aGroupCtrls, aGroupName ); + OutStream->writeUTF( aGroupName ); + ImplWriteControls( OutStream, aGroupCtrls ); + } +} + +void StdTabControllerModel::read( const css::uno::Reference< css::io::XObjectInputStream >& InStream ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > aSeq = ImplReadControls( InStream ); + setControlModels( aSeq ); + + sal_uInt32 nGroups = InStream->readLong(); + for ( sal_uInt32 n = 0; n < nGroups; n++ ) + { + OUString aGroupName = InStream->readUTF(); + css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > aCtrlSeq = ImplReadControls( InStream ); + setGroup( aCtrlSeq, aGroupName ); + } +} + +OUString StdTabControllerModel::getImplementationName() +{ + return "stardiv.Toolkit.StdTabControllerModel"; +} + +sal_Bool StdTabControllerModel::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> StdTabControllerModel::getSupportedServiceNames() +{ + return css::uno::Sequence<OUString>{ + "com.sun.star.awt.TabControllerModel", + "stardiv.vcl.controlmodel.TabController"}; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_StdTabControllerModel_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new StdTabControllerModel()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/svmedit.cxx b/toolkit/source/controls/svmedit.cxx new file mode 100644 index 000000000..383f22804 --- /dev/null +++ b/toolkit/source/controls/svmedit.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 <awt/vclxwindows.hxx> +#include <controls/svmedit.hxx> + +MultiLineEdit::MultiLineEdit(vcl::Window* pParent, WinBits nWinStyle) + : VclMultiLineEdit(pParent, nWinStyle) +{ +} + +// virtual +css::uno::Reference<css::awt::XWindowPeer> MultiLineEdit::GetComponentInterface(bool bCreate) +{ + css::uno::Reference<css::awt::XWindowPeer> xPeer( + VclMultiLineEdit::GetComponentInterface(false)); + if (!xPeer.is() && bCreate) + { + rtl::Reference<VCLXMultiLineEdit> xVCLMEdit(new VCLXMultiLineEdit); + xVCLMEdit->SetWindow(this); + xPeer = xVCLMEdit.get(); + SetComponentInterface(xPeer); + } + return xPeer; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/tabpagecontainer.cxx b/toolkit/source/controls/tabpagecontainer.cxx new file mode 100644 index 000000000..d4028b290 --- /dev/null +++ b/toolkit/source/controls/tabpagecontainer.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 <controls/geometrycontrolmodel.hxx> +#include <controls/tabpagecontainer.hxx> +#include <controls/tabpagemodel.hxx> +#include <toolkit/helper/property.hxx> + +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <o3tl/safeint.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> + +#include <helper/unopropertyarrayhelper.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::view; +using ::com::sun::star::awt::tab::XTabPageModel; + +constexpr OUStringLiteral WRONG_TYPE_EXCEPTION = u"Type must be css::awt::tab::XTabPageModel!"; + + +UnoControlTabPageContainerModel::UnoControlTabPageContainerModel( const Reference< XComponentContext >& i_factory ) + :UnoControlTabPageContainerModel_Base( i_factory ) + ,maContainerListeners( *this ) +{ + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_TEXT ); +} + +OUString UnoControlTabPageContainerModel::getServiceName() +{ + return "com.sun.star.awt.tab.UnoControlTabPageContainerModel"; +} + +uno::Any UnoControlTabPageContainerModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + switch(nPropId) + { + case BASEPROPERTY_DEFAULTCONTROL: + return uno::Any( OUString("com.sun.star.awt.tab.UnoControlTabPageContainer") ); + case BASEPROPERTY_BORDER: + return uno::Any(sal_Int16(0)); // No Border + default: + return UnoControlModel::ImplGetDefaultValue( nPropId ); + } +} + +::cppu::IPropertyArrayHelper& UnoControlTabPageContainerModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} +Reference< css::beans::XPropertySetInfo > UnoControlTabPageContainerModel::getPropertySetInfo( ) +{ + static Reference< css::beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +namespace +{ + Reference< XTabPageModel > lcl_createTabPageModel( Reference<XComponentContext> const & i_context, + Sequence< Any > const & i_initArguments, Reference< XPropertySet > const & i_parentModel ) + { + try + { + Reference< XPropertySetInfo > const xPSI( i_parentModel->getPropertySetInfo() ); + bool const isGeometryControlModel = xPSI.is() && xPSI->hasPropertyByName("PositionX"); + + Reference< XInterface > xInstance; + if ( isGeometryControlModel ) + xInstance = *( new OGeometryControlModel< UnoControlTabPageModel >( i_context ) ); + else + xInstance = *( new UnoControlTabPageModel( i_context ) ); + + Reference< XTabPageModel > const xTabPageModel( xInstance, UNO_QUERY_THROW ); + Reference< XInitialization > const xInit( xTabPageModel, UNO_QUERY_THROW ); + xInit->initialize( i_initArguments ); + + return xTabPageModel; + } + catch( const RuntimeException& ) + { + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + return nullptr; + } +} + +Reference< XTabPageModel > SAL_CALL UnoControlTabPageContainerModel::createTabPage( ::sal_Int16 i_tabPageID ) +{ + Sequence< Any > aInitArgs{ Any(i_tabPageID) }; + return lcl_createTabPageModel( m_xContext, aInitArgs, this ); +} + +Reference< XTabPageModel > SAL_CALL UnoControlTabPageContainerModel::loadTabPage( ::sal_Int16 i_tabPageID, const OUString& i_resourceURL ) +{ + Sequence< Any > aInitArgs{ Any(i_tabPageID), Any(i_resourceURL) }; + return lcl_createTabPageModel( m_xContext, aInitArgs, this ); +} + +void SAL_CALL UnoControlTabPageContainerModel::insertByIndex( ::sal_Int32 nIndex, const css::uno::Any& aElement) +{ + SolarMutexGuard aSolarGuard; + uno::Reference < XTabPageModel > xTabPageModel; + if(!(aElement >>= xTabPageModel)) + throw IllegalArgumentException( WRONG_TYPE_EXCEPTION, static_cast<OWeakObject *>(this), 2 ); + + if ( sal_Int32( m_aTabPageVector.size()) ==nIndex ) + m_aTabPageVector.push_back( xTabPageModel ); + else if ( sal_Int32( m_aTabPageVector.size()) > nIndex ) + { + std::vector< uno::Reference< XTabPageModel > >::iterator aIter = m_aTabPageVector.begin(); + aIter += nIndex; + m_aTabPageVector.insert( aIter, xTabPageModel ); + } + else + throw IndexOutOfBoundsException( OUString(), static_cast<OWeakObject *>(this) ); + ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Element = aElement; + aEvent.Accessor <<= OUString::number(nIndex); + maContainerListeners.elementInserted( aEvent ); + +} + +void SAL_CALL UnoControlTabPageContainerModel::removeByIndex( ::sal_Int32 /*Index*/ ) +{ +} +// XIndexReplace +void SAL_CALL UnoControlTabPageContainerModel::replaceByIndex( ::sal_Int32 /*Index*/, const uno::Any& /*Element*/ ) +{ +} + +// XIndexAccess +::sal_Int32 SAL_CALL UnoControlTabPageContainerModel::getCount( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + return sal_Int32( m_aTabPageVector.size()); +} + +uno::Any SAL_CALL UnoControlTabPageContainerModel::getByIndex( ::sal_Int32 nIndex ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + if ( nIndex < 0 || o3tl::make_unsigned(nIndex) > m_aTabPageVector.size() ) + throw lang::IndexOutOfBoundsException(); + return uno::Any(m_aTabPageVector[nIndex]); +} + +// XElementAccess +uno::Type SAL_CALL UnoControlTabPageContainerModel::getElementType( ) +{ + return cppu::UnoType<css::awt::XControlModel>::get(); +} + +sal_Bool SAL_CALL UnoControlTabPageContainerModel::hasElements( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + return !m_aTabPageVector.empty(); +} +// XContainer +void UnoControlTabPageContainerModel::addContainerListener( const Reference< XContainerListener >& l ) +{ + maContainerListeners.addInterface( l ); +} + +void UnoControlTabPageContainerModel::removeContainerListener( const Reference< XContainerListener >& l ) +{ + maContainerListeners.removeInterface( l ); +} + + + +UnoControlTabPageContainer::UnoControlTabPageContainer( const uno::Reference< uno::XComponentContext >& rxContext ) + :UnoControlTabPageContainer_Base(rxContext) + ,m_aTabPageListeners( *this ) +{ +} + +OUString UnoControlTabPageContainer::GetComponentServiceName() const +{ + return "TabPageContainer"; +} + +void SAL_CALL UnoControlTabPageContainer::dispose( ) +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + m_aTabPageListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); +} + +void UnoControlTabPageContainer::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControlBase::createPeer( rxToolkit, rParentPeer ); + + Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); + if ( m_aTabPageListeners.getLength() ) + xTPContainer->addTabPageContainerListener(&m_aTabPageListeners); +} + + +// XTabPageContainer + +::sal_Int16 SAL_CALL UnoControlTabPageContainer::getActiveTabPageID() +{ + SolarMutexGuard aSolarGuard; + Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); + return xTPContainer->getActiveTabPageID(); +} +void SAL_CALL UnoControlTabPageContainer::setActiveTabPageID( ::sal_Int16 _activetabpageid ) +{ + SolarMutexGuard aSolarGuard; + Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); + xTPContainer->setActiveTabPageID(_activetabpageid); +} +::sal_Int16 SAL_CALL UnoControlTabPageContainer::getTabPageCount( ) +{ + SolarMutexGuard aSolarGuard; + Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); + return xTPContainer->getTabPageCount(); +} +sal_Bool SAL_CALL UnoControlTabPageContainer::isTabPageActive( ::sal_Int16 tabPageIndex ) +{ + SolarMutexGuard aSolarGuard; + Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); + return xTPContainer->isTabPageActive(tabPageIndex); +} +Reference< css::awt::tab::XTabPage > SAL_CALL UnoControlTabPageContainer::getTabPage( ::sal_Int16 tabPageIndex ) +{ + SolarMutexGuard aSolarGuard; + Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); + return xTPContainer->getTabPage(tabPageIndex); +} +Reference< css::awt::tab::XTabPage > SAL_CALL UnoControlTabPageContainer::getTabPageByID( ::sal_Int16 tabPageID ) +{ + SolarMutexGuard aSolarGuard; + Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); + return xTPContainer->getTabPageByID(tabPageID); +} +void SAL_CALL UnoControlTabPageContainer::addTabPageContainerListener( const Reference< css::awt::tab::XTabPageContainerListener >& listener ) +{ + m_aTabPageListeners.addInterface( listener ); + if( getPeer().is() && m_aTabPageListeners.getLength() == 1 ) + { + uno::Reference < awt::tab::XTabPageContainer > xTabPageContainer( getPeer(), uno::UNO_QUERY ); + xTabPageContainer->addTabPageContainerListener( &m_aTabPageListeners ); + } +} +void SAL_CALL UnoControlTabPageContainer::removeTabPageContainerListener( const Reference< css::awt::tab::XTabPageContainerListener >& listener ) +{ + if( getPeer().is() && m_aTabPageListeners.getLength() == 1 ) + { + uno::Reference < awt::tab::XTabPageContainer > xTabPageContainer( getPeer(), uno::UNO_QUERY ); + xTabPageContainer->removeTabPageContainerListener( &m_aTabPageListeners ); + } + m_aTabPageListeners.removeInterface( listener ); +} + +void UnoControlTabPageContainer::propertiesChange(const::css::uno::Sequence<PropertyChangeEvent> &aEvent) +{ + UnoControlTabPageContainer_Base::propertiesChange(aEvent); + + SolarMutexGuard aSolarGuard; + Reference< XPropertiesChangeListener > xPropertiesChangeListener( getPeer(), UNO_QUERY_THROW ); + return xPropertiesChangeListener->propertiesChange(aEvent); +} + +void UnoControlTabPageContainer::updateFromModel() +{ + UnoControlTabPageContainer_Base::updateFromModel(); + if (!getPeer().is()) + throw RuntimeException("No peer for tabpage container!"); + Reference< XContainerListener > xContainerListener( getPeer(), UNO_QUERY ); + ENSURE_OR_RETURN_VOID( xContainerListener.is(), "UnoListBoxControl::updateFromModel: a peer which is no ItemListListener?!" ); + + ContainerEvent aEvent; + aEvent.Source = getModel(); + const Sequence< Reference< XControl > > aControls = getControls(); + + for ( const Reference< XControl >& rCtrl : aControls ) + { + aEvent.Element <<= rCtrl; + xContainerListener->elementInserted( aEvent ); + } +} +void SAL_CALL UnoControlTabPageContainer::addControl( const OUString& Name, const Reference< css::awt::XControl >& Control ) +{ + SolarMutexGuard aSolarGuard; + ControlContainerBase::addControl(Name,Control); + if (!getPeer().is()) + throw RuntimeException("No peer for tabpage container!"); + Reference< XContainerListener > xContainerListener( getPeer(), UNO_QUERY ); + ContainerEvent aEvent; + aEvent.Source = getModel(); + aEvent.Element <<= Control; + xContainerListener->elementInserted( aEvent ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlTabPageContainerModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlTabPageContainerModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlTabPageContainer_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlTabPageContainer(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/tabpagemodel.cxx b/toolkit/source/controls/tabpagemodel.cxx new file mode 100644 index 000000000..c82e54e41 --- /dev/null +++ b/toolkit/source/controls/tabpagemodel.cxx @@ -0,0 +1,304 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <controls/tabpagemodel.hxx> + +#include <vcl/svapp.hxx> +#include <toolkit/helper/property.hxx> +#include <com/sun/star/awt/UnoControlDialogModelProvider.hpp> +#include <com/sun/star/awt/tab/XTabPage.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <tools/debug.hxx> +#include <vcl/outdev.hxx> + +#include <controls/controlmodelcontainerbase.hxx> +#include <controls/unocontrolcontainer.hxx> + +#include <helper/unopropertyarrayhelper.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; + +UnoControlTabPageModel::UnoControlTabPageModel( Reference< XComponentContext > const & i_factory ) + :ControlModelContainerBase( i_factory ) +{ + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_TITLE ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_USERFORMCONTAINEES ); + ImplRegisterProperty( BASEPROPERTY_HSCROLL ); + ImplRegisterProperty( BASEPROPERTY_VSCROLL ); + ImplRegisterProperty( BASEPROPERTY_SCROLLWIDTH ); + ImplRegisterProperty( BASEPROPERTY_SCROLLHEIGHT ); + ImplRegisterProperty( BASEPROPERTY_SCROLLTOP ); + ImplRegisterProperty( BASEPROPERTY_SCROLLLEFT ); +} + +OUString SAL_CALL UnoControlTabPageModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlTabPageModel"; +} + +css::uno::Sequence< OUString > SAL_CALL UnoControlTabPageModel::getSupportedServiceNames() +{ + css::uno::Sequence< OUString > aNames = ControlModelContainerBase::getSupportedServiceNames( ); + aNames.realloc( aNames.getLength() + 1 ); + aNames.getArray()[ aNames.getLength() - 1 ] = "com.sun.star.awt.tab.UnoControlTabPageModel"; + return aNames; +} + +OUString UnoControlTabPageModel::getServiceName( ) +{ + return "com.sun.star.awt.tab.UnoControlTabPageModel"; +} + +Any UnoControlTabPageModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + Any aAny; + + switch ( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + aAny <<= OUString("com.sun.star.awt.tab.UnoControlTabPage"); + break; + case BASEPROPERTY_USERFORMCONTAINEES: + { + // We do not have here any usercontainers (yet?), but let's return empty container back + // so normal properties could be set without triggering UnknownPropertyException + aAny <<= uno::Reference< XNameContainer >(); + break; + } + default: + aAny = UnoControlModel::ImplGetDefaultValue( nPropId ); + } + + return aAny; +} + +::cppu::IPropertyArrayHelper& UnoControlTabPageModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlTabPageModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +////----- XInitialization ------------------------------------------------------------------- +void SAL_CALL UnoControlTabPageModel::initialize (const Sequence<Any>& rArguments) +{ + sal_Int16 nPageId = -1; + if ( rArguments.getLength() == 1 ) + { + if ( !( rArguments[ 0 ] >>= nPageId )) + throw lang::IllegalArgumentException(); + m_nTabPageId = nPageId; + } + else if ( rArguments.getLength() == 2 ) + { + if ( !( rArguments[ 0 ] >>= nPageId )) + throw lang::IllegalArgumentException(); + m_nTabPageId = nPageId; + OUString sURL; + if ( !( rArguments[ 1 ] >>= sURL )) + throw lang::IllegalArgumentException(); + Reference<container::XNameContainer > xDialogModel = awt::UnoControlDialogModelProvider::create( m_xContext, sURL ); + if ( xDialogModel.is() ) + { + const Sequence< OUString> aNames = xDialogModel->getElementNames(); + for(const OUString& rName : aNames) + { + try + { + Any aElement(xDialogModel->getByName(rName)); + xDialogModel->removeByName(rName); + insertByName(rName,aElement); + } + catch(const Exception&) {} + } + Reference<XPropertySet> xDialogProp(xDialogModel,UNO_QUERY); + if ( xDialogProp.is() ) + { + static constexpr OUStringLiteral s_sResourceResolver = u"ResourceResolver"; + Reference<XPropertySet> xThis(*this,UNO_QUERY); + xThis->setPropertyValue(s_sResourceResolver,xDialogProp->getPropertyValue(s_sResourceResolver)); + xThis->setPropertyValue(GetPropertyName(BASEPROPERTY_TITLE),xDialogProp->getPropertyValue(GetPropertyName(BASEPROPERTY_TITLE))); + xThis->setPropertyValue(GetPropertyName(BASEPROPERTY_HELPTEXT),xDialogProp->getPropertyValue(GetPropertyName(BASEPROPERTY_HELPTEXT))); + xThis->setPropertyValue(GetPropertyName(BASEPROPERTY_HELPURL),xDialogProp->getPropertyValue(GetPropertyName(BASEPROPERTY_HELPURL))); + } + } + } + else + m_nTabPageId = -1; +} + + +UnoControlTabPage::UnoControlTabPage( const uno::Reference< uno::XComponentContext >& rxContext ) + :UnoControlTabPage_Base(rxContext) + ,m_bWindowListener(false) +{ + maComponentInfos.nWidth = 280; + maComponentInfos.nHeight = 400; +} +UnoControlTabPage::~UnoControlTabPage() +{ +} + +OUString UnoControlTabPage::GetComponentServiceName() const +{ + return "TabPageModel"; +} + +OUString SAL_CALL UnoControlTabPage::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlTabPage"; +} + +sal_Bool SAL_CALL UnoControlTabPage::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL UnoControlTabPage::getSupportedServiceNames() +{ + return { "com.sun.star.awt.tab.UnoControlTabPage" }; +} + +void UnoControlTabPage::dispose() +{ + SolarMutexGuard aSolarGuard; + + lang::EventObject aEvt; + aEvt.Source = static_cast< ::cppu::OWeakObject* >( this ); + ControlContainerBase::dispose(); +} + +void SAL_CALL UnoControlTabPage::disposing( const lang::EventObject& Source ) +{ + ControlContainerBase::disposing( Source ); +} + +void UnoControlTabPage::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) +{ + SolarMutexGuard aSolarGuard; + ImplUpdateResourceResolver(); + + UnoControlContainer::createPeer( rxToolkit, rParentPeer ); + + Reference < tab::XTabPage > xTabPage( getPeer(), UNO_QUERY ); + if ( xTabPage.is() ) + { + if ( !m_bWindowListener ) + { + Reference< XWindowListener > xWL(this); + addWindowListener( xWL ); + m_bWindowListener = true; + } + } +} + +static ::Size ImplMapPixelToAppFont( OutputDevice const * pOutDev, const ::Size& aSize ) +{ + ::Size aTmp = pOutDev->PixelToLogic(aSize, MapMode(MapUnit::MapAppFont)); + return aTmp; +} +// css::awt::XWindowListener +void SAL_CALL UnoControlTabPage::windowResized( const css::awt::WindowEvent& e ) +{ + OutputDevice*pOutDev = Application::GetDefaultDevice(); + DBG_ASSERT( pOutDev, "Missing Default Device!" ); + if ( !pOutDev || mbSizeModified ) + return; + + // Currently we are simply using MapUnit::MapAppFont + ::Size aAppFontSize( e.Width, e.Height ); + + Reference< XControl > xDialogControl( *this, UNO_QUERY_THROW ); + Reference< XDevice > xDialogDevice( xDialogControl->getPeer(), UNO_QUERY ); + OSL_ENSURE( xDialogDevice.is(), "UnoDialogControl::windowResized: no peer, but a windowResized event?" ); + if ( xDialogDevice.is() ) + { + DeviceInfo aDeviceInfo( xDialogDevice->getInfo() ); + aAppFontSize.AdjustWidth( -(aDeviceInfo.LeftInset + aDeviceInfo.RightInset) ); + aAppFontSize.AdjustHeight( -(aDeviceInfo.TopInset + aDeviceInfo.BottomInset) ); + } + + aAppFontSize = ImplMapPixelToAppFont( pOutDev, aAppFontSize ); + + // Remember that changes have been done by listener. No need to + // update the position because of property change event. + mbSizeModified = true; + // Properties in a sequence must be sorted! + Sequence< OUString > aProps{ "Height", "Width" }; + Sequence< Any > aValues{ Any(aAppFontSize.Height()), Any(aAppFontSize.Width()) }; + + ImplSetPropertyValues( aProps, aValues, true ); + mbSizeModified = false; + +} + +void SAL_CALL UnoControlTabPage::windowMoved( const css::awt::WindowEvent& e ) +{ + OutputDevice*pOutDev = Application::GetDefaultDevice(); + DBG_ASSERT( pOutDev, "Missing Default Device!" ); + if ( !pOutDev || mbPosModified ) + return; + + // Currently we are simply using MapUnit::MapAppFont + ::Size aTmp( e.X, e.Y ); + aTmp = ImplMapPixelToAppFont( pOutDev, aTmp ); + + // Remember that changes have been done by listener. No need to + // update the position because of property change event. + mbPosModified = true; + Sequence< OUString > aProps{ "PositionX", "PositionY" }; + Sequence< Any > aValues{ Any(aTmp.Width()), Any(aTmp.Height()) }; + + ImplSetPropertyValues( aProps, aValues, true ); + mbPosModified = false; + +} + +void SAL_CALL UnoControlTabPage::windowShown( const css::lang::EventObject& ) {} + +void SAL_CALL UnoControlTabPage::windowHidden( const css::lang::EventObject& ) {} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlTabPageModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlTabPageModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlTabPage_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlTabPage(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/tkscrollbar.cxx b/toolkit/source/controls/tkscrollbar.cxx new file mode 100644 index 000000000..48a2a560b --- /dev/null +++ b/toolkit/source/controls/tkscrollbar.cxx @@ -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 . + */ + +#include <controls/tkscrollbar.hxx> +#include <toolkit/helper/property.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <toolkit/awt/vclxwindows.hxx> + +#include <helper/unopropertyarrayhelper.hxx> + +namespace toolkit +{ + + + using namespace ::com::sun::star; + + + //= UnoControlScrollBarModel + + + UnoControlScrollBarModel::UnoControlScrollBarModel( const uno::Reference< uno::XComponentContext >& i_factory ) + :UnoControlModel( i_factory ) + { + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXScrollBar>(); + } + + + OUString UnoControlScrollBarModel::getServiceName( ) + { + return "stardiv.vcl.controlmodel.ScrollBar"; + } + + OUString UnoControlScrollBarModel::getImplementationName() + { + return "stardiv.Toolkit.UnoControlScrollBarModel"; + } + + css::uno::Sequence<OUString> + UnoControlScrollBarModel::getSupportedServiceNames() + { + auto s(UnoControlModel::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlScrollBarModel"; + ps[s.getLength() - 1] = "stardiv.vcl.controlmodel.ScrollBar"; + return s; + } + + uno::Any UnoControlScrollBarModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const + { + switch ( nPropId ) + { + case BASEPROPERTY_LIVE_SCROLL: + return uno::Any( false ); + case BASEPROPERTY_DEFAULTCONTROL: + return uno::Any( OUString( "stardiv.vcl.control.ScrollBar" ) ); + + default: + return UnoControlModel::ImplGetDefaultValue( nPropId ); + } + } + + + ::cppu::IPropertyArrayHelper& UnoControlScrollBarModel::getInfoHelper() + { + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; + } + + + uno::Reference< beans::XPropertySetInfo > UnoControlScrollBarModel::getPropertySetInfo( ) + { + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + + //= UnoControlScrollBarModel + + UnoScrollBarControl::UnoScrollBarControl() + :maAdjustmentListeners( *this ) + { + } + + OUString UnoScrollBarControl::GetComponentServiceName() const + { + return "ScrollBar"; + } + + // css::uno::XInterface + uno::Any UnoScrollBarControl::queryAggregation( const uno::Type & rType ) + { + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XAdjustmentListener* >(this), + static_cast< awt::XScrollBar* >(this) ); + return (aRet.hasValue() ? aRet : UnoControlBase::queryAggregation( rType )); + } + + IMPL_IMPLEMENTATION_ID( UnoScrollBarControl ) + + // css::lang::XTypeProvider + css::uno::Sequence< css::uno::Type > UnoScrollBarControl::getTypes() + { + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XAdjustmentListener>::get(), + cppu::UnoType<awt::XScrollBar>::get(), + UnoControlBase::getTypes() + ); + return aTypeList.getTypes(); + } + + void UnoScrollBarControl::dispose() + { + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maAdjustmentListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); + } + + void UnoScrollBarControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) + { + UnoControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XScrollBar > xScrollBar( getPeer(), uno::UNO_QUERY ); + xScrollBar->addAdjustmentListener( this ); + } + + // css::awt::XAdjustmentListener + void UnoScrollBarControl::adjustmentValueChanged( const css::awt::AdjustmentEvent& rEvent ) + { + switch ( rEvent.Type ) + { + case css::awt::AdjustmentType_ADJUST_LINE: + case css::awt::AdjustmentType_ADJUST_PAGE: + case css::awt::AdjustmentType_ADJUST_ABS: + { + uno::Reference< awt::XScrollBar > xScrollBar( getPeer(), uno::UNO_QUERY ); + + if ( xScrollBar.is() ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SCROLLVALUE ), uno::Any(xScrollBar->getValue()), false ); + } + } + break; + default: + { + OSL_FAIL( "UnoScrollBarControl::adjustmentValueChanged - unknown Type" ); + + } + } + + if ( maAdjustmentListeners.getLength() ) + maAdjustmentListeners.adjustmentValueChanged( rEvent ); + } + + // css::awt::XScrollBar + void UnoScrollBarControl::addAdjustmentListener( const css::uno::Reference< css::awt::XAdjustmentListener > & l ) + { + maAdjustmentListeners.addInterface( l ); + } + + void UnoScrollBarControl::removeAdjustmentListener( const css::uno::Reference< css::awt::XAdjustmentListener > & l ) + { + maAdjustmentListeners.removeInterface( l ); + } + + void UnoScrollBarControl::setValue( sal_Int32 n ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SCROLLVALUE ), uno::Any( n ), true ); + } + + void UnoScrollBarControl::setValues( sal_Int32 nValue, sal_Int32 nVisible, sal_Int32 nMax ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SCROLLVALUE ), uno::Any(nValue), true ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VISIBLESIZE ), uno::Any(nVisible), true ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SCROLLVALUE_MAX ), uno::Any(nMax), true ); + } + + sal_Int32 UnoScrollBarControl::getValue() + { + sal_Int32 n = 0; + if ( getPeer().is() ) + { + uno::Reference< awt::XScrollBar > xScrollBar( getPeer(), uno::UNO_QUERY ); + n = xScrollBar->getValue(); + } + return n; + } + + void UnoScrollBarControl::setMaximum( sal_Int32 n ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SCROLLVALUE_MAX ), uno::Any( n ), true ); + } + + sal_Int32 UnoScrollBarControl::getMaximum() + { + sal_Int32 n = 0; + if ( getPeer().is() ) + { + uno::Reference< awt::XScrollBar > xScrollBar( getPeer(), uno::UNO_QUERY ); + n = xScrollBar->getMaximum(); + } + return n; + } + + void UnoScrollBarControl::setLineIncrement( sal_Int32 n ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LINEINCREMENT ), uno::Any( n ), true ); + } + + sal_Int32 UnoScrollBarControl::getLineIncrement() + { + sal_Int32 n = 0; + if ( getPeer().is() ) + { + uno::Reference< awt::XScrollBar > xScrollBar( getPeer(), uno::UNO_QUERY ); + n = xScrollBar->getLineIncrement(); + } + return n; + } + + void UnoScrollBarControl::setBlockIncrement( sal_Int32 n ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_BLOCKINCREMENT ), uno::Any( n ), true ); + } + + sal_Int32 UnoScrollBarControl::getBlockIncrement() + { + sal_Int32 n = 0; + if ( getPeer().is() ) + { + uno::Reference< awt::XScrollBar > xScrollBar( getPeer(), uno::UNO_QUERY ); + n = xScrollBar->getBlockIncrement(); + } + return n; + } + + void UnoScrollBarControl::setVisibleSize( sal_Int32 n ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VISIBLESIZE ), uno::Any( n ), true ); + } + + sal_Int32 UnoScrollBarControl::getVisibleSize() + { + sal_Int32 n = 0; + if ( getPeer().is() ) + { + uno::Reference< awt::XScrollBar > xScrollBar( getPeer(), uno::UNO_QUERY ); + n = xScrollBar->getVisibleSize(); + } + return n; + } + + void UnoScrollBarControl::setOrientation( sal_Int32 n ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_ORIENTATION ), uno::Any( n ), true ); + } + + sal_Int32 UnoScrollBarControl::getOrientation() + { + sal_Int32 n = 0; + if ( getPeer().is() ) + { + uno::Reference< awt::XScrollBar > xScrollBar( getPeer(), uno::UNO_QUERY ); + n = xScrollBar->getOrientation(); + } + return n; + } + + OUString UnoScrollBarControl::getImplementationName() + { + return "stardiv.Toolkit.UnoScrollBarControl"; + } + + css::uno::Sequence<OUString> UnoScrollBarControl::getSupportedServiceNames() + { + auto s(UnoControlBase::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlScrollBar"; + ps[s.getLength() - 1] = "stardiv.vcl.control.ScrollBar"; + return s; + } + +} // namespace toolkit + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlScrollBarModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoControlScrollBarModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoScrollBarControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoScrollBarControl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/tkspinbutton.cxx b/toolkit/source/controls/tkspinbutton.cxx new file mode 100644 index 000000000..2040f6688 --- /dev/null +++ b/toolkit/source/controls/tkspinbutton.cxx @@ -0,0 +1,421 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/awt/ScrollBarOrientation.hpp> +#include <com/sun/star/awt/XSpinValue.hpp> +#include <com/sun/star/awt/XAdjustmentListener.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <comphelper/uno3.hxx> +#include <cppuhelper/implbase2.hxx> +#include <toolkit/controls/unocontrolmodel.hxx> +#include <toolkit/controls/unocontrolbase.hxx> +#include <toolkit/helper/property.hxx> + +#include <helper/unopropertyarrayhelper.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +namespace { + +class UnoSpinButtonModel : public UnoControlModel +{ +protected: + css::uno::Any ImplGetDefaultValue( sal_uInt16 nPropId ) const override; + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + +public: + explicit UnoSpinButtonModel( const css::uno::Reference< css::uno::XComponentContext >& i_factory ); + + rtl::Reference<UnoControlModel> Clone() const override { return new UnoSpinButtonModel( *this ); } + + // XMultiPropertySet + css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // XPersistObject + OUString SAL_CALL getServiceName() override; + + // XServiceInfo + OUString SAL_CALL getImplementationName( ) override; + css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + + +//= UnoSpinButtonControl + + +typedef ::cppu::ImplHelper2 < css::awt::XAdjustmentListener + , css::awt::XSpinValue + > UnoSpinButtonControl_Base; + +class UnoSpinButtonControl :public UnoControlBase + ,public UnoSpinButtonControl_Base +{ +private: + AdjustmentListenerMultiplexer maAdjustmentListeners; + +public: + UnoSpinButtonControl(); + OUString GetComponentServiceName() const override; + + DECLARE_UNO3_AGG_DEFAULTS( UnoSpinButtonControl, UnoControlBase ) + css::uno::Any SAL_CALL queryAggregation( const css::uno::Type & rType ) override; + + void SAL_CALL createPeer( const css::uno::Reference< css::awt::XToolkit >& Toolkit, const css::uno::Reference< css::awt::XWindowPeer >& Parent ) override; + void SAL_CALL disposing( const css::lang::EventObject& Source ) override { UnoControlBase::disposing( Source ); } + void SAL_CALL dispose( ) override; + + // XTypeProvider + DECLARE_XTYPEPROVIDER() + + // XAdjustmentListener + void SAL_CALL adjustmentValueChanged( const css::awt::AdjustmentEvent& rEvent ) override; + + // XSpinValue + virtual void SAL_CALL addAdjustmentListener( const css::uno::Reference< css::awt::XAdjustmentListener >& listener ) override; + virtual void SAL_CALL removeAdjustmentListener( const css::uno::Reference< css::awt::XAdjustmentListener >& listener ) override; + virtual void SAL_CALL setValue( sal_Int32 value ) override; + virtual void SAL_CALL setValues( sal_Int32 minValue, sal_Int32 maxValue, sal_Int32 currentValue ) override; + virtual sal_Int32 SAL_CALL getValue( ) override; + virtual void SAL_CALL setMinimum( sal_Int32 minValue ) override; + virtual void SAL_CALL setMaximum( sal_Int32 maxValue ) override; + virtual sal_Int32 SAL_CALL getMinimum( ) override; + virtual sal_Int32 SAL_CALL getMaximum( ) override; + virtual void SAL_CALL setSpinIncrement( sal_Int32 spinIncrement ) override; + virtual sal_Int32 SAL_CALL getSpinIncrement( ) override; + virtual void SAL_CALL setOrientation( sal_Int32 orientation ) override; + virtual sal_Int32 SAL_CALL getOrientation( ) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName( ) override; + css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + + + //= UnoSpinButtonModel + + + UnoSpinButtonModel::UnoSpinButtonModel( const css::uno::Reference< css::uno::XComponentContext >& i_factory ) + :UnoControlModel( i_factory ) + { + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_ORIENTATION ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_REPEAT ); + ImplRegisterProperty( BASEPROPERTY_REPEAT_DELAY ); + ImplRegisterProperty( BASEPROPERTY_SYMBOL_COLOR ); + ImplRegisterProperty( BASEPROPERTY_SPINVALUE ); + ImplRegisterProperty( BASEPROPERTY_SPINVALUE_MIN ); + ImplRegisterProperty( BASEPROPERTY_SPINVALUE_MAX ); + ImplRegisterProperty( BASEPROPERTY_SPININCREMENT ); + ImplRegisterProperty( BASEPROPERTY_TABSTOP ); + ImplRegisterProperty( BASEPROPERTY_WRITING_MODE ); + ImplRegisterProperty( BASEPROPERTY_CONTEXT_WRITING_MODE ); + } + + + OUString UnoSpinButtonModel::getServiceName( ) + { + return "com.sun.star.awt.UnoControlSpinButtonModel"; + } + + + Any UnoSpinButtonModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const + { + switch ( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + return Any( OUString("com.sun.star.awt.UnoControlSpinButton") ); + + case BASEPROPERTY_BORDER: + return Any( sal_Int16(0) ); + + case BASEPROPERTY_REPEAT: + return Any( true ); + + default: + return UnoControlModel::ImplGetDefaultValue( nPropId ); + } + } + + + ::cppu::IPropertyArrayHelper& UnoSpinButtonModel::getInfoHelper() + { + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; + } + + + Reference< XPropertySetInfo > UnoSpinButtonModel::getPropertySetInfo( ) + { + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + + OUString SAL_CALL UnoSpinButtonModel::getImplementationName( ) + { + return "stardiv.Toolkit.UnoSpinButtonModel"; + } + + + Sequence< OUString > SAL_CALL UnoSpinButtonModel::getSupportedServiceNames() + { + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlSpinButtonModel" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); + } + + + //= UnoSpinButtonControl + + + UnoSpinButtonControl::UnoSpinButtonControl() + :maAdjustmentListeners( *this ) + { + } + + + OUString UnoSpinButtonControl::GetComponentServiceName() const + { + return "SpinButton"; + } + + + Any UnoSpinButtonControl::queryAggregation( const Type & rType ) + { + Any aRet = UnoControlBase::queryAggregation( rType ); + if ( !aRet.hasValue() ) + aRet = UnoSpinButtonControl_Base::queryInterface( rType ); + return aRet; + } + + + IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoSpinButtonControl, UnoControlBase, UnoSpinButtonControl_Base ) + + + void UnoSpinButtonControl::dispose() + { + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + if ( maAdjustmentListeners.getLength() ) + { + Reference< XSpinValue > xSpinnable( getPeer(), UNO_QUERY ); + if ( xSpinnable.is() ) + xSpinnable->removeAdjustmentListener( this ); + + EventObject aDisposeEvent; + aDisposeEvent.Source = *this; + + aGuard.clear(); + maAdjustmentListeners.disposeAndClear( aDisposeEvent ); + } + + UnoControl::dispose(); + } + + + OUString SAL_CALL UnoSpinButtonControl::getImplementationName( ) + { + return "stardiv.Toolkit.UnoSpinButtonControl"; + } + + + Sequence< OUString > SAL_CALL UnoSpinButtonControl::getSupportedServiceNames() + { + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlSpinButton" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals ); + } + + + void UnoSpinButtonControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) + { + UnoControl::createPeer( rxToolkit, rParentPeer ); + + Reference < XSpinValue > xSpinnable( getPeer(), UNO_QUERY ); + if ( xSpinnable.is() ) + xSpinnable->addAdjustmentListener( this ); + } + + + void UnoSpinButtonControl::adjustmentValueChanged( const AdjustmentEvent& rEvent ) + { + switch ( rEvent.Type ) + { + case AdjustmentType_ADJUST_LINE: + case AdjustmentType_ADJUST_PAGE: + case AdjustmentType_ADJUST_ABS: + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SPINVALUE ), Any( rEvent.Value ), false ); + break; + default: + OSL_FAIL( "UnoSpinButtonControl::adjustmentValueChanged - unknown Type" ); + } + + if ( maAdjustmentListeners.getLength() ) + { + AdjustmentEvent aEvent( rEvent ); + aEvent.Source = *this; + maAdjustmentListeners.adjustmentValueChanged( aEvent ); + } + } + + + void UnoSpinButtonControl::addAdjustmentListener( const Reference< XAdjustmentListener > & listener ) + { + ::osl::MutexGuard aGuard( GetMutex() ); + maAdjustmentListeners.addInterface( listener ); + } + + + void UnoSpinButtonControl::removeAdjustmentListener( const Reference< XAdjustmentListener > & listener ) + { + ::osl::MutexGuard aGuard( GetMutex() ); + maAdjustmentListeners.removeInterface( listener ); + } + + + void SAL_CALL UnoSpinButtonControl::setValue( sal_Int32 value ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SPINVALUE ), Any( value ), true ); + } + + + void SAL_CALL UnoSpinButtonControl::setValues( sal_Int32 minValue, sal_Int32 maxValue, sal_Int32 currentValue ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SPINVALUE_MIN ), Any( minValue ), true ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SPINVALUE_MAX ), Any( maxValue ), true ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SPINVALUE ), Any( currentValue ), true ); + } + + + sal_Int32 SAL_CALL UnoSpinButtonControl::getValue( ) + { + ::osl::MutexGuard aGuard( GetMutex() ); + sal_Int32 nValue = 0; + + Reference< XSpinValue > xSpinnable( getPeer(), UNO_QUERY ); + if ( xSpinnable.is() ) + nValue = xSpinnable->getValue(); + + return nValue; + } + + + void SAL_CALL UnoSpinButtonControl::setMinimum( sal_Int32 minValue ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SPINVALUE_MIN ), Any( minValue ), true ); + } + + + void SAL_CALL UnoSpinButtonControl::setMaximum( sal_Int32 maxValue ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SPINVALUE_MAX ), Any( maxValue ), true ); + } + + + sal_Int32 SAL_CALL UnoSpinButtonControl::getMinimum( ) + { + ::osl::MutexGuard aGuard( GetMutex() ); + sal_Int32 nMin = 0; + + Reference< XSpinValue > xSpinnable( getPeer(), UNO_QUERY ); + if ( xSpinnable.is() ) + nMin = xSpinnable->getMinimum(); + + return nMin; + } + + + sal_Int32 SAL_CALL UnoSpinButtonControl::getMaximum( ) + { + ::osl::MutexGuard aGuard( GetMutex() ); + sal_Int32 nMax = 0; + + Reference< XSpinValue > xSpinnable( getPeer(), UNO_QUERY ); + if ( xSpinnable.is() ) + nMax = xSpinnable->getMaximum(); + + return nMax; + } + + + void SAL_CALL UnoSpinButtonControl::setSpinIncrement( sal_Int32 spinIncrement ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SPININCREMENT ), Any( spinIncrement ), true ); + } + + + sal_Int32 SAL_CALL UnoSpinButtonControl::getSpinIncrement( ) + { + ::osl::MutexGuard aGuard( GetMutex() ); + sal_Int32 nIncrement = 0; + + Reference< XSpinValue > xSpinnable( getPeer(), UNO_QUERY ); + if ( xSpinnable.is() ) + nIncrement = xSpinnable->getSpinIncrement(); + + return nIncrement; + } + + + void SAL_CALL UnoSpinButtonControl::setOrientation( sal_Int32 orientation ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_ORIENTATION ), Any( orientation ), true ); + } + + + sal_Int32 SAL_CALL UnoSpinButtonControl::getOrientation( ) + { + ::osl::MutexGuard aGuard( GetMutex() ); + sal_Int32 nOrientation = ScrollBarOrientation::HORIZONTAL; + + Reference< XSpinValue > xSpinnable( getPeer(), UNO_QUERY ); + if ( xSpinnable.is() ) + nOrientation = xSpinnable->getOrientation(); + + return nOrientation; + } + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoSpinButtonModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoSpinButtonModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoSpinButtonControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoSpinButtonControl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/tree/treecontrol.cxx b/toolkit/source/controls/tree/treecontrol.cxx new file mode 100644 index 000000000..d4439a4ff --- /dev/null +++ b/toolkit/source/controls/tree/treecontrol.cxx @@ -0,0 +1,514 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 "treecontrol.hxx" + +#include <com/sun/star/awt/tree/XTreeControl.hpp> +#include <com/sun/star/awt/tree/XTreeDataModel.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/view/SelectionType.hpp> +#include <toolkit/controls/unocontrolbase.hxx> +#include <toolkit/helper/property.hxx> +#include <osl/diagnose.h> +#include <cppuhelper/implbase.hxx> + +#include <helper/unopropertyarrayhelper.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::awt::tree; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::view; + +namespace toolkit +{ + + +UnoTreeModel::UnoTreeModel( const css::uno::Reference< css::uno::XComponentContext >& i_factory ) + :UnoControlModel( i_factory ) +{ + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_FILLCOLOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_TABSTOP ); + ImplRegisterProperty( BASEPROPERTY_TREE_SELECTIONTYPE ); + ImplRegisterProperty( BASEPROPERTY_TREE_EDITABLE ); + ImplRegisterProperty( BASEPROPERTY_TREE_DATAMODEL ); + ImplRegisterProperty( BASEPROPERTY_TREE_ROOTDISPLAYED ); + ImplRegisterProperty( BASEPROPERTY_TREE_SHOWSHANDLES ); + ImplRegisterProperty( BASEPROPERTY_TREE_SHOWSROOTHANDLES ); + ImplRegisterProperty( BASEPROPERTY_ROW_HEIGHT ); + ImplRegisterProperty( BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING ); + ImplRegisterProperty( BASEPROPERTY_HIDEINACTIVESELECTION ); +} + +rtl::Reference<UnoControlModel> UnoTreeModel::Clone() const +{ + return new UnoTreeModel( *this ); +} + +OUString UnoTreeModel::getServiceName() +{ + return "com.sun.star.awt.tree.TreeControlModel"; +} + +Any UnoTreeModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + switch( nPropId ) + { + case BASEPROPERTY_TREE_SELECTIONTYPE: + return Any( SelectionType_NONE ); + case BASEPROPERTY_ROW_HEIGHT: + return Any( sal_Int32( 0 ) ); + case BASEPROPERTY_TREE_DATAMODEL: + return Any( Reference< XTreeDataModel >( nullptr ) ); + case BASEPROPERTY_TREE_EDITABLE: + case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING: + return Any( false ); + case BASEPROPERTY_TREE_ROOTDISPLAYED: + case BASEPROPERTY_TREE_SHOWSROOTHANDLES: + case BASEPROPERTY_TREE_SHOWSHANDLES: + return Any( true ); + case BASEPROPERTY_DEFAULTCONTROL: + return uno::Any( OUString( "com.sun.star.awt.tree.TreeControl" ) ); + default: + return UnoControlModel::ImplGetDefaultValue( nPropId ); + } +} + +::cppu::IPropertyArrayHelper& UnoTreeModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// XMultiPropertySet +Reference< XPropertySetInfo > UnoTreeModel::getPropertySetInfo( ) +{ + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +} + +namespace { + +typedef ::cppu::ImplInheritanceHelper< UnoControlBase, css::awt::tree::XTreeControl > UnoTreeControl_Base; +class UnoTreeControl : public UnoTreeControl_Base +{ +public: + UnoTreeControl(); + OUString GetComponentServiceName() const override; + + // css::lang::XComponent + void SAL_CALL dispose( ) override; + + // css::awt::XControl + void SAL_CALL createPeer( const css::uno::Reference< css::awt::XToolkit >& Toolkit, const css::uno::Reference< css::awt::XWindowPeer >& Parent ) override; + + // css::view::XSelectionSupplier + virtual sal_Bool SAL_CALL select( const css::uno::Any& xSelection ) 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::view::XMultiSelectionSupplier + virtual sal_Bool SAL_CALL addSelection( const css::uno::Any& Selection ) override; + virtual void SAL_CALL removeSelection( const css::uno::Any& Selection ) override; + virtual void SAL_CALL clearSelection( ) override; + virtual ::sal_Int32 SAL_CALL getSelectionCount( ) override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSelectionEnumeration( ) override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createReverseSelectionEnumeration( ) override; + + // css::awt::XTreeControl + virtual OUString SAL_CALL getDefaultExpandedGraphicURL() override; + virtual void SAL_CALL setDefaultExpandedGraphicURL( const OUString& _defaultexpandedgraphicurl ) override; + virtual OUString SAL_CALL getDefaultCollapsedGraphicURL() override; + virtual void SAL_CALL setDefaultCollapsedGraphicURL( const OUString& _defaultcollapsedgraphicurl ) override; + virtual sal_Bool SAL_CALL isNodeExpanded( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual sal_Bool SAL_CALL isNodeCollapsed( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual void SAL_CALL makeNodeVisible( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual sal_Bool SAL_CALL isNodeVisible( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual void SAL_CALL expandNode( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual void SAL_CALL collapseNode( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual void SAL_CALL addTreeExpansionListener( const css::uno::Reference< css::awt::tree::XTreeExpansionListener >& Listener ) override; + virtual void SAL_CALL removeTreeExpansionListener( const css::uno::Reference< css::awt::tree::XTreeExpansionListener >& Listener ) override; + virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getNodeForLocation( ::sal_Int32 x, ::sal_Int32 y ) override; + virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getClosestNodeForLocation( ::sal_Int32 x, ::sal_Int32 y ) override; + virtual css::awt::Rectangle SAL_CALL getNodeRect( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual sal_Bool SAL_CALL isEditing( ) override; + virtual sal_Bool SAL_CALL stopEditing( ) override; + virtual void SAL_CALL cancelEditing( ) override; + virtual void SAL_CALL startEditingAtNode( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual void SAL_CALL addTreeEditListener( const css::uno::Reference< css::awt::tree::XTreeEditListener >& Listener ) override; + virtual void SAL_CALL removeTreeEditListener( const css::uno::Reference< css::awt::tree::XTreeEditListener >& Listener ) override; + + // css::lang::XServiceInfo + DECLIMPL_SERVICEINFO_DERIVED( UnoTreeControl, UnoControlBase, "com.sun.star.awt.tree.TreeControl" ) + + using UnoControl::getPeer; +private: + TreeSelectionListenerMultiplexer maSelectionListeners; + TreeExpansionListenerMultiplexer maTreeExpansionListeners; + TreeEditListenerMultiplexer maTreeEditListeners; +}; + +UnoTreeControl::UnoTreeControl() +: maSelectionListeners( *this ) +, maTreeExpansionListeners( *this ) +, maTreeEditListeners( *this ) +{ +} + +OUString UnoTreeControl::GetComponentServiceName() const +{ + return "Tree"; +} + + +// css::view::XSelectionSupplier + + +sal_Bool SAL_CALL UnoTreeControl::select( const Any& rSelection ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->select( rSelection ); +} + + +Any SAL_CALL UnoTreeControl::getSelection() +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getSelection(); +} + + +void SAL_CALL UnoTreeControl::addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) +{ + maSelectionListeners.addInterface( xListener ); + if( getPeer().is() && (maSelectionListeners.getLength() == 1) ) + { + // maSelectionListeners acts as a proxy, + // add it to the peer if this is the first listener added to that proxy + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->addSelectionChangeListener(&maSelectionListeners); + } +} + + +void SAL_CALL UnoTreeControl::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) +{ + if( getPeer().is() && (maSelectionListeners.getLength() == 1) ) + { + // maSelectionListeners acts as a proxy, + // remove it from the peer if this is the last listener removed from that proxy + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->removeSelectionChangeListener(&maSelectionListeners); + } + maSelectionListeners.removeInterface( xListener ); +} + + +// css::view::XMultiSelectionSupplier + + +sal_Bool SAL_CALL UnoTreeControl::addSelection( const Any& rSelection ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->addSelection(rSelection); +} + + +void SAL_CALL UnoTreeControl::removeSelection( const Any& rSelection ) +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->removeSelection(rSelection); +} + + +void SAL_CALL UnoTreeControl::clearSelection() +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->clearSelection(); +} + + +sal_Int32 SAL_CALL UnoTreeControl::getSelectionCount() +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getSelectionCount(); +} + + +Reference< XEnumeration > SAL_CALL UnoTreeControl::createSelectionEnumeration() +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->createSelectionEnumeration(); +} + + +Reference< XEnumeration > SAL_CALL UnoTreeControl::createReverseSelectionEnumeration() +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->createReverseSelectionEnumeration(); +} + + +// XTreeControl + + +OUString SAL_CALL UnoTreeControl::getDefaultExpandedGraphicURL() +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getDefaultExpandedGraphicURL(); +} + + +void SAL_CALL UnoTreeControl::setDefaultExpandedGraphicURL( const OUString& _defaultexpansiongraphicurl ) +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->setDefaultExpandedGraphicURL(_defaultexpansiongraphicurl); +} + + +OUString SAL_CALL UnoTreeControl::getDefaultCollapsedGraphicURL() +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getDefaultCollapsedGraphicURL(); +} + + +void SAL_CALL UnoTreeControl::setDefaultCollapsedGraphicURL( const OUString& _defaultcollapsedgraphicurl ) +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->setDefaultCollapsedGraphicURL(_defaultcollapsedgraphicurl); +} + + +sal_Bool SAL_CALL UnoTreeControl::isNodeExpanded( const Reference< XTreeNode >& xNode ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->isNodeExpanded(xNode); +} + + +sal_Bool SAL_CALL UnoTreeControl::isNodeCollapsed( const Reference< XTreeNode >& xNode ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->isNodeCollapsed(xNode); +} + + +void SAL_CALL UnoTreeControl::makeNodeVisible( const Reference< XTreeNode >& xNode ) +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->makeNodeVisible(xNode); +} + + +sal_Bool SAL_CALL UnoTreeControl::isNodeVisible( const Reference< XTreeNode >& xNode ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->isNodeVisible(xNode); +} + + +void SAL_CALL UnoTreeControl::expandNode( const Reference< XTreeNode >& xNode ) +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->expandNode(xNode); +} + + +void SAL_CALL UnoTreeControl::collapseNode( const Reference< XTreeNode >& xNode ) +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->collapseNode(xNode); +} + + +void SAL_CALL UnoTreeControl::addTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener ) +{ + maTreeExpansionListeners.addInterface( xListener ); + if( getPeer().is() && (maTreeExpansionListeners.getLength() == 1) ) + { + // maSelectionListeners acts as a proxy, + // add it to the peer if this is the first listener added to that proxy + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->addTreeExpansionListener(&maTreeExpansionListeners); + } +} + + +void SAL_CALL UnoTreeControl::removeTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener ) +{ + if( getPeer().is() && (maTreeExpansionListeners.getLength() == 1) ) + { + // maSelectionListeners acts as a proxy, + // remove it from the peer if this is the last listener removed from that proxy + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->removeTreeExpansionListener(&maTreeExpansionListeners); + } + maTreeExpansionListeners.removeInterface( xListener ); +} + + +Reference< XTreeNode > SAL_CALL UnoTreeControl::getNodeForLocation( sal_Int32 x, sal_Int32 y ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getNodeForLocation(x,y); +} + + +Reference< XTreeNode > SAL_CALL UnoTreeControl::getClosestNodeForLocation( sal_Int32 x, sal_Int32 y ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getClosestNodeForLocation(x,y); +} + + +awt::Rectangle SAL_CALL UnoTreeControl::getNodeRect( const Reference< XTreeNode >& Node ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->getNodeRect( Node ); +} + + +sal_Bool SAL_CALL UnoTreeControl::isEditing( ) +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->isEditing(); +} + + +sal_Bool SAL_CALL UnoTreeControl::stopEditing() +{ + return Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->stopEditing(); +} + + +void SAL_CALL UnoTreeControl::cancelEditing() +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->cancelEditing(); +} + + +void SAL_CALL UnoTreeControl::startEditingAtNode( const Reference< XTreeNode >& xNode ) +{ + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->startEditingAtNode(xNode); +} + + +void SAL_CALL UnoTreeControl::addTreeEditListener( const Reference< XTreeEditListener >& xListener ) +{ + maTreeEditListeners.addInterface( xListener ); + if( getPeer().is() && (maTreeEditListeners.getLength() == 1) ) + { + // maSelectionListeners acts as a proxy, + // add it to the peer if this is the first listener added to that proxy + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->addTreeEditListener(&maTreeEditListeners); + } +} + + +void SAL_CALL UnoTreeControl::removeTreeEditListener( const Reference< XTreeEditListener >& xListener ) +{ + if( getPeer().is() && (maTreeEditListeners.getLength() == 1) ) + { + // maSelectionListeners acts as a proxy, + // remove it from the peer if this is the last listener removed from that proxy + Reference< XTreeControl >( getPeer(), UNO_QUERY_THROW )->removeTreeEditListener(&maTreeEditListeners); + } + maTreeEditListeners.removeInterface( xListener ); +} + + +// XComponent + + +void SAL_CALL UnoTreeControl::dispose( ) +{ + lang::EventObject aEvt; + aEvt.Source = static_cast< ::cppu::OWeakObject* >(this); + maSelectionListeners.disposeAndClear( aEvt ); + maTreeExpansionListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); +} + +void UnoTreeControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControlBase::createPeer( rxToolkit, rParentPeer ); + + Reference< XTreeControl > xTree( getPeer(), UNO_QUERY_THROW ); + if( maSelectionListeners.getLength() ) + xTree->addSelectionChangeListener( &maSelectionListeners ); + if( maTreeExpansionListeners.getLength() ) + xTree->addTreeExpansionListener( &maTreeExpansionListeners ); +} + +} + +void SAL_CALL TreeEditListenerMultiplexer::nodeEditing( const Reference< XTreeNode >& Node ) +{ + ::comphelper::OInterfaceIteratorHelper3 aIt(*this); + while( aIt.hasMoreElements() ) + { + Reference<XTreeEditListener> xListener(aIt.next()); + try + { + xListener->nodeEditing( Node ); + } + catch( const DisposedException& e ) + { + OSL_ENSURE( e.Context.is(), "caught DisposedException with empty Context field" ); + if ( e.Context == xListener || !e.Context.is() ) + aIt.remove(); + } + catch( const RuntimeException& ) + { + DISPLAY_EXCEPTION( TreeEditListenerMultiplexer, nodeEditing ) + } + } +} + +void SAL_CALL TreeEditListenerMultiplexer::nodeEdited( const Reference< XTreeNode >& Node, const OUString& NewText ) +{ + ::comphelper::OInterfaceIteratorHelper3 aIt(*this); + while( aIt.hasMoreElements() ) + { + Reference<XTreeEditListener> xListener(aIt.next()); + try + { + xListener->nodeEdited( Node, NewText ); + } + catch( const DisposedException& e ) + { + OSL_ENSURE( e.Context.is(), "caught DisposedException with empty Context field" ); + if ( e.Context == xListener || !e.Context.is() ) + aIt.remove(); + } + catch( const RuntimeException& ) + { + DISPLAY_EXCEPTION( TreeEditListenerMultiplexer, nodeEdited ) + } + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_TreeControlModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new toolkit::UnoTreeModel(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_TreeControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoTreeControl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/tree/treecontrol.hxx b/toolkit/source/controls/tree/treecontrol.hxx new file mode 100644 index 000000000..af4793fe9 --- /dev/null +++ b/toolkit/source/controls/tree/treecontrol.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_TOOLKIT_SOURCE_CONTROLS_TREE_TREECONTROL_HXX +#define INCLUDED_TOOLKIT_SOURCE_CONTROLS_TREE_TREECONTROL_HXX + +#include <toolkit/controls/unocontrolmodel.hxx> + +namespace toolkit +{ +// = UnoTreeModel + +class UnoTreeModel : public UnoControlModel +{ +protected: + css::uno::Any ImplGetDefaultValue(sal_uInt16 nPropId) const override; + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + +public: + explicit UnoTreeModel(const css::uno::Reference<css::uno::XComponentContext>& i_factory); + + rtl::Reference<UnoControlModel> Clone() const override; + + // css::beans::XMultiPropertySet + css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + + // css::io::XPersistObject + OUString SAL_CALL getServiceName() override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { + return "stardiv.Toolkit.TreeControlModel"; + } + + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override + { + auto s(UnoControlModel::getSupportedServiceNames()); + s.realloc(s.getLength() + 1); + s.getArray()[s.getLength() - 1] = "com.sun.star.awt.tree.TreeControlModel"; + return s; + } +}; + +} // toolkit + +#endif // _ INCLUDED_TOOLKIT_SOURCE_CONTROLS_TREE_TREECONTROL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/tree/treecontrolpeer.cxx b/toolkit/source/controls/tree/treecontrolpeer.cxx new file mode 100644 index 000000000..fe273e0f6 --- /dev/null +++ b/toolkit/source/controls/tree/treecontrolpeer.cxx @@ -0,0 +1,1579 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/graphic/GraphicProvider.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/view/SelectionType.hpp> +#include <com/sun/star/util/VetoException.hpp> +#include <o3tl/any.hxx> +#include <toolkit/helper/property.hxx> +#include <toolkit/helper/vclunohelper.hxx> + +#include <com/sun/star/awt/tree/XMutableTreeNode.hpp> +#include <controls/treecontrolpeer.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> + +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <vcl/graph.hxx> +#include <vcl/svapp.hxx> +#include <vcl/toolkit/treelistbox.hxx> +#include <vcl/toolkit/treelistentry.hxx> +#include <vcl/toolkit/viewdataentry.hxx> +#include <vcl/toolkit/svlbitm.hxx> + +#include <map> +#include <memory> +#include <list> + +using namespace ::com::sun::star; +using namespace css::uno; +using namespace css::lang; +using namespace css::awt::tree; +using namespace css::beans; +using namespace css::view; +using namespace css::container; +using namespace css::util; +using namespace css::graphic; + +namespace { + +struct LockGuard +{ +public: + explicit LockGuard( sal_Int32& rLock ) + : mrLock( rLock ) + { + rLock++; + } + + ~LockGuard() + { + mrLock--; + } + + sal_Int32& mrLock; +}; + + +class ImplContextGraphicItem : public SvLBoxContextBmp +{ +public: + ImplContextGraphicItem( Image const & rI1, Image const & rI2, bool bExpanded) + : SvLBoxContextBmp(rI1, rI2, bExpanded) {} + + OUString msExpandedGraphicURL; + OUString msCollapsedGraphicURL; +}; + + +} + +class UnoTreeListBoxImpl : public SvTreeListBox +{ +public: + UnoTreeListBoxImpl( TreeControlPeer* pPeer, vcl::Window* pParent, WinBits nWinStyle ); + virtual ~UnoTreeListBoxImpl() override; + virtual void dispose() override; + + void insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos ); + + virtual void RequestingChildren( SvTreeListEntry* pParent ) override; + + virtual bool EditingEntry( SvTreeListEntry* pEntry ) override; + virtual bool EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText ) override; + + DECL_LINK(OnSelectionChangeHdl, SvTreeListBox*, void); + DECL_LINK(OnExpandingHdl, SvTreeListBox*, bool); + DECL_LINK(OnExpandedHdl, SvTreeListBox*, void); + +private: + rtl::Reference< TreeControlPeer > mxPeer; +}; + + +namespace { + +class UnoTreeListItem : public SvLBoxString +{ +public: + UnoTreeListItem(); + + void InitViewData( SvTreeListBox*,SvTreeListEntry*,SvViewDataItem * = nullptr ) override; + void SetImage( const Image& rImage ); + const OUString& GetGraphicURL() const { return maGraphicURL;} + void SetGraphicURL( const OUString& rGraphicURL ); + virtual void Paint(const Point& rPos, SvTreeListBox& rOutDev, vcl::RenderContext& rRenderContext, + const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override; + std::unique_ptr<SvLBoxItem> Clone( SvLBoxItem const * pSource ) const override; + +private: + OUString maGraphicURL; + Image maImage; +}; + +} + +class UnoTreeListEntry : public SvTreeListEntry +{ +public: + UnoTreeListEntry( const Reference< XTreeNode >& xNode, TreeControlPeer* pPeer ); + virtual ~UnoTreeListEntry() override; + + Reference< XTreeNode > mxNode; + TreeControlPeer* mpPeer; +}; + +TreeControlPeer::TreeControlPeer() + : maSelectionListeners( *this ) + , maTreeExpansionListeners( *this ) + , maTreeEditListeners( *this ) + , mbIsRootDisplayed(false) + , mpTreeImpl( nullptr ) + , mnEditLock( 0 ) +{ +} + + +TreeControlPeer::~TreeControlPeer() +{ + if( mpTreeImpl ) + mpTreeImpl->Clear(); +} + + +void TreeControlPeer::addEntry( UnoTreeListEntry* pEntry ) +{ + if( pEntry && pEntry->mxNode.is() ) + { + if( !mpTreeNodeMap ) + { + mpTreeNodeMap.reset( new TreeNodeMap ); + } + + (*mpTreeNodeMap)[ pEntry->mxNode ] = pEntry; + } +} + + +void TreeControlPeer::removeEntry( UnoTreeListEntry const * pEntry ) +{ + if( mpTreeNodeMap && pEntry && pEntry->mxNode.is() ) + { + TreeNodeMap::iterator aIter( mpTreeNodeMap->find( pEntry->mxNode ) ); + if( aIter != mpTreeNodeMap->end() ) + { + mpTreeNodeMap->erase( aIter ); + } + } +} + + +UnoTreeListEntry* TreeControlPeer::getEntry( const Reference< XTreeNode >& xNode, bool bThrow /* = true */ ) +{ + if( mpTreeNodeMap ) + { + TreeNodeMap::iterator aIter( mpTreeNodeMap->find( xNode ) ); + if( aIter != mpTreeNodeMap->end() ) + return (*aIter).second; + } + + if( bThrow ) + throw IllegalArgumentException(); + + return nullptr; +} + + +vcl::Window* TreeControlPeer::createVclControl( vcl::Window* pParent, sal_Int64 nWinStyle ) +{ + mpTreeImpl = VclPtr<UnoTreeListBoxImpl>::Create( this, pParent, nWinStyle ); + return mpTreeImpl; +} + + +/** called from the UnoTreeListBoxImpl when it gets deleted */ +void TreeControlPeer::disposeControl() +{ + mpTreeNodeMap.reset(); + mpTreeImpl = nullptr; +} + + +UnoTreeListEntry* TreeControlPeer::createEntry( const Reference< XTreeNode >& xNode, UnoTreeListEntry* pParent, sal_uLong nPos /* = TREELIST_APPEND */ ) +{ + UnoTreeListEntry* pEntry = nullptr; + if( mpTreeImpl ) + { + Image aImage; + pEntry = new UnoTreeListEntry( xNode, this ); + pEntry->AddItem(std::make_unique<ImplContextGraphicItem>(aImage, aImage, true)); + + std::unique_ptr<UnoTreeListItem> pUnoItem(new UnoTreeListItem); + + if( !xNode->getNodeGraphicURL().isEmpty() ) + { + pUnoItem->SetGraphicURL( xNode->getNodeGraphicURL() ); + Image aNodeImage; + loadImage( xNode->getNodeGraphicURL(), aNodeImage ); + pUnoItem->SetImage( aNodeImage ); + mpTreeImpl->AdjustEntryHeight( aNodeImage ); + } + + pEntry->AddItem(std::move(pUnoItem)); + + mpTreeImpl->insert( pEntry, pParent, nPos ); + + if( !msDefaultExpandedGraphicURL.isEmpty() ) + mpTreeImpl->SetExpandedEntryBmp( pEntry, maDefaultExpandedImage ); + + if( !msDefaultCollapsedGraphicURL.isEmpty() ) + mpTreeImpl->SetCollapsedEntryBmp( pEntry, maDefaultCollapsedImage ); + + updateEntry( pEntry ); + } + return pEntry; +} + + +void TreeControlPeer::updateEntry( UnoTreeListEntry* pEntry ) +{ + bool bChanged = false; + if( !(pEntry && pEntry->mxNode.is() && mpTreeImpl) ) + return; + + const OUString aValue( getEntryString( pEntry->mxNode->getDisplayValue() ) ); + UnoTreeListItem* pUnoItem = dynamic_cast< UnoTreeListItem* >( &pEntry->GetItem( 1 ) ); + if( pUnoItem ) + { + if( aValue != pUnoItem->GetText() ) + { + pUnoItem->SetText( aValue ); + bChanged = true; + } + + if( pUnoItem->GetGraphicURL() != pEntry->mxNode->getNodeGraphicURL() ) + { + Image aImage; + if( loadImage( pEntry->mxNode->getNodeGraphicURL(), aImage ) ) + { + pUnoItem->SetGraphicURL( pEntry->mxNode->getNodeGraphicURL() ); + pUnoItem->SetImage( aImage ); + mpTreeImpl->AdjustEntryHeight( aImage ); + bChanged = true; + } + } + } + + if( bool(pEntry->mxNode->hasChildrenOnDemand()) != pEntry->HasChildrenOnDemand() ) + { + pEntry->EnableChildrenOnDemand( pEntry->mxNode->hasChildrenOnDemand() ); + bChanged = true; + } + + ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) ); + if( pContextGraphicItem ) + { + if( pContextGraphicItem->msExpandedGraphicURL != pEntry->mxNode->getExpandedGraphicURL() ) + { + Image aImage; + if( loadImage( pEntry->mxNode->getExpandedGraphicURL(), aImage ) ) + { + pContextGraphicItem->msExpandedGraphicURL = pEntry->mxNode->getExpandedGraphicURL(); + mpTreeImpl->SetExpandedEntryBmp( pEntry, aImage ); + bChanged = true; + } + } + if( pContextGraphicItem->msCollapsedGraphicURL != pEntry->mxNode->getCollapsedGraphicURL() ) + { + Image aImage; + if( loadImage( pEntry->mxNode->getCollapsedGraphicURL(), aImage ) ) + { + pContextGraphicItem->msCollapsedGraphicURL = pEntry->mxNode->getCollapsedGraphicURL(); + mpTreeImpl->SetCollapsedEntryBmp( pEntry, aImage ); + bChanged = true; + } + } + } + + if( bChanged ) + mpTreeImpl->GetModel()->InvalidateEntry( pEntry ); +} + + +void TreeControlPeer::onSelectionChanged() +{ + Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + EventObject aEvent( xSource ); + maSelectionListeners.selectionChanged( aEvent ); +} + + +void TreeControlPeer::onRequestChildNodes( const Reference< XTreeNode >& xNode ) +{ + try + { + Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + TreeExpansionEvent aEvent( xSource, xNode ); + maTreeExpansionListeners.requestChildNodes( aEvent ); + } + catch( Exception& ) + { + } +} + + +bool TreeControlPeer::onExpanding( const Reference< XTreeNode >& xNode, bool bExpanding ) +{ + try + { + Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + TreeExpansionEvent aEvent( xSource, xNode ); + if( bExpanding ) + { + maTreeExpansionListeners.treeExpanding( aEvent ); + } + else + { + maTreeExpansionListeners.treeCollapsing( aEvent ); + } + } + catch( Exception& ) + { + return false; + } + return true; +} + + +void TreeControlPeer::onExpanded( const Reference< XTreeNode >& xNode, bool bExpanding ) +{ + try + { + Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + TreeExpansionEvent aEvent( xSource, xNode ); + + if( bExpanding ) + { + maTreeExpansionListeners.treeExpanded( aEvent ); + } + else + { + maTreeExpansionListeners.treeCollapsed( aEvent ); + } + } + catch( Exception& ) + { + } +} + + +void TreeControlPeer::fillTree( UnoTreeListBoxImpl& rTree, const Reference< XTreeDataModel >& xDataModel ) +{ + rTree.Clear(); + + if( !xDataModel.is() ) + return; + + Reference< XTreeNode > xRootNode( xDataModel->getRoot() ); + if( !xRootNode.is() ) + return; + + if( mbIsRootDisplayed ) + { + addNode( rTree, xRootNode, nullptr ); + } + else + { + const sal_Int32 nChildCount = xRootNode->getChildCount(); + for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ ) + addNode( rTree, xRootNode->getChildAt( nChild ), nullptr ); + } +} + + +void TreeControlPeer::addNode( UnoTreeListBoxImpl& rTree, const Reference< XTreeNode >& xNode, UnoTreeListEntry* pParentEntry ) +{ + if( xNode.is() ) + { + UnoTreeListEntry* pEntry = createEntry( xNode, pParentEntry, TREELIST_APPEND ); + const sal_Int32 nChildCount = xNode->getChildCount(); + for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ ) + addNode( rTree, xNode->getChildAt( nChild ), pEntry ); + } +} + + +UnoTreeListBoxImpl& TreeControlPeer::getTreeListBoxOrThrow() const +{ + if( !mpTreeImpl ) + throw DisposedException(); + return *mpTreeImpl; +} + + +void TreeControlPeer::ChangeNodesSelection( const Any& rSelection, bool bSelect, bool bSetSelection ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + Reference< XTreeNode > xTempNode; + + Sequence<Reference<XTreeNode>> pNodes; + sal_Int32 nCount = 0; + + if( rSelection.hasValue() ) + { + switch( rSelection.getValueTypeClass() ) + { + case TypeClass_INTERFACE: + { + rSelection >>= xTempNode; + if( xTempNode.is() ) + { + nCount = 1; + pNodes = {xTempNode}; + } + break; + } + case TypeClass_SEQUENCE: + { + if( auto rSeq = o3tl::tryAccess<Sequence<Reference<XTreeNode>>>( + rSelection) ) + { + nCount = rSeq->getLength(); + pNodes = *rSeq; + } + break; + } + default: + break; + } + + if( nCount == 0 ) + throw IllegalArgumentException(); + } + + if( bSetSelection ) + rTree.SelectAll( false ); + + for( sal_Int32 i = 0; i != nCount; ++i ) + { + UnoTreeListEntry* pEntry = getEntry( pNodes[i] ); + rTree.Select( pEntry, bSelect ); + } +} + + +// css::view::XSelectionSupplier + + +sal_Bool SAL_CALL TreeControlPeer::select( const Any& rSelection ) +{ + SolarMutexGuard aGuard; + ChangeNodesSelection( rSelection, true, true ); + return true; +} + + +Any SAL_CALL TreeControlPeer::getSelection() +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + Any aRet; + + sal_uLong nSelectionCount = rTree.GetSelectionCount(); + if( nSelectionCount == 1 ) + { + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() ); + if( pEntry && pEntry->mxNode.is() ) + aRet <<= pEntry->mxNode; + } + else if( nSelectionCount > 1 ) + { + Sequence< Reference< XTreeNode > > aSelection( nSelectionCount ); + Reference< XTreeNode >* pNodes = aSelection.getArray(); + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() ); + while( pEntry && nSelectionCount ) + { + *pNodes++ = pEntry->mxNode; + pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) ); + --nSelectionCount; + } + + OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) ); + aRet <<= aSelection; + } + + return aRet; +} + + +void SAL_CALL TreeControlPeer::addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) +{ + maSelectionListeners.addInterface( xListener ); +} + + +void SAL_CALL TreeControlPeer::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) +{ + maSelectionListeners.addInterface( xListener ); +} + + +// css::view::XMultiSelectionSupplier + + +sal_Bool SAL_CALL TreeControlPeer::addSelection( const Any& rSelection ) +{ + ChangeNodesSelection( rSelection, true, false ); + return true; +} + + +void SAL_CALL TreeControlPeer::removeSelection( const Any& rSelection ) +{ + ChangeNodesSelection( rSelection, false, false ); +} + + +void SAL_CALL TreeControlPeer::clearSelection() +{ + SolarMutexGuard aGuard; + getTreeListBoxOrThrow().SelectAll( false ); +} + + +sal_Int32 SAL_CALL TreeControlPeer::getSelectionCount() +{ + SolarMutexGuard aGuard; + return getTreeListBoxOrThrow().GetSelectionCount(); +} + +namespace { + +class TreeSelectionEnumeration : public ::cppu::WeakImplHelper< XEnumeration > +{ +public: + explicit TreeSelectionEnumeration( std::list< Any >& rSelection ); + virtual sal_Bool SAL_CALL hasMoreElements() override; + virtual Any SAL_CALL nextElement() override; + + std::list< Any > maSelection; + std::list< Any >::iterator maIter; +}; + +} + +TreeSelectionEnumeration::TreeSelectionEnumeration( std::list< Any >& rSelection ) +{ + maSelection.swap( rSelection ); + maIter = maSelection.begin(); +} + + +sal_Bool SAL_CALL TreeSelectionEnumeration::hasMoreElements() +{ + return maIter != maSelection.end(); +} + + +Any SAL_CALL TreeSelectionEnumeration::nextElement() +{ + if( maIter == maSelection.end() ) + throw NoSuchElementException(); + + return (*maIter++); +} + + +Reference< XEnumeration > SAL_CALL TreeControlPeer::createSelectionEnumeration() +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + sal_uInt32 nSelectionCount = rTree.GetSelectionCount(); + std::list< Any > aSelection( nSelectionCount ); + + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() ); + while( pEntry && nSelectionCount ) + { + aSelection.emplace_back( pEntry->mxNode ); + pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) ); + --nSelectionCount; + } + + OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) ); + + return Reference< XEnumeration >( new TreeSelectionEnumeration( aSelection ) ); +} + + +Reference< XEnumeration > SAL_CALL TreeControlPeer::createReverseSelectionEnumeration() +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + sal_uInt32 nSelectionCount = rTree.GetSelectionCount(); + std::list< Any > aSelection; + + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.FirstSelected() ); + while( pEntry && nSelectionCount ) + { + aSelection.push_front( Any( pEntry->mxNode ) ); + pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.NextSelected( pEntry ) ); + --nSelectionCount; + } + + OSL_ASSERT( (pEntry == nullptr) && (nSelectionCount == 0) ); + + return Reference< XEnumeration >( new TreeSelectionEnumeration( aSelection ) ); +} + + +// css::awt::XTreeControl + + +OUString SAL_CALL TreeControlPeer::getDefaultExpandedGraphicURL() +{ + SolarMutexGuard aGuard; + return msDefaultExpandedGraphicURL; +} + + +void SAL_CALL TreeControlPeer::setDefaultExpandedGraphicURL( const OUString& sDefaultExpandedGraphicURL ) +{ + SolarMutexGuard aGuard; + if( msDefaultExpandedGraphicURL == sDefaultExpandedGraphicURL ) + return; + + if( !sDefaultExpandedGraphicURL.isEmpty() ) + loadImage( sDefaultExpandedGraphicURL, maDefaultExpandedImage ); + else + maDefaultExpandedImage = Image(); + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + SvTreeListEntry* pEntry = rTree.First(); + while( pEntry ) + { + ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) ); + if( pContextGraphicItem ) + { + if( pContextGraphicItem->msExpandedGraphicURL.isEmpty() ) + rTree.SetExpandedEntryBmp( pEntry, maDefaultExpandedImage ); + } + pEntry = rTree.Next( pEntry ); + } + + msDefaultExpandedGraphicURL = sDefaultExpandedGraphicURL; +} + + +OUString SAL_CALL TreeControlPeer::getDefaultCollapsedGraphicURL() +{ + SolarMutexGuard aGuard; + return msDefaultCollapsedGraphicURL; +} + + +void SAL_CALL TreeControlPeer::setDefaultCollapsedGraphicURL( const OUString& sDefaultCollapsedGraphicURL ) +{ + SolarMutexGuard aGuard; + if( msDefaultCollapsedGraphicURL == sDefaultCollapsedGraphicURL ) + return; + + if( !sDefaultCollapsedGraphicURL.isEmpty() ) + loadImage( sDefaultCollapsedGraphicURL, maDefaultCollapsedImage ); + else + maDefaultCollapsedImage = Image(); + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + SvTreeListEntry* pEntry = rTree.First(); + while( pEntry ) + { + ImplContextGraphicItem* pContextGraphicItem = dynamic_cast< ImplContextGraphicItem* >( &pEntry->GetItem( 0 ) ); + if( pContextGraphicItem ) + { + if( pContextGraphicItem->msCollapsedGraphicURL.isEmpty() ) + rTree.SetCollapsedEntryBmp( pEntry, maDefaultCollapsedImage ); + } + pEntry = rTree.Next( pEntry ); + } + + msDefaultCollapsedGraphicURL = sDefaultCollapsedGraphicURL; +} + + +sal_Bool SAL_CALL TreeControlPeer::isNodeExpanded( const Reference< XTreeNode >& xNode ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + UnoTreeListEntry* pEntry = getEntry( xNode ); + return pEntry && rTree.IsExpanded( pEntry ); +} + + +sal_Bool SAL_CALL TreeControlPeer::isNodeCollapsed( const Reference< XTreeNode >& xNode ) +{ + SolarMutexGuard aGuard; + return !isNodeExpanded( xNode ); +} + + +void SAL_CALL TreeControlPeer::makeNodeVisible( const Reference< XTreeNode >& xNode ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + UnoTreeListEntry* pEntry = getEntry( xNode ); + if( pEntry ) + rTree.MakeVisible( pEntry ); +} + + +sal_Bool SAL_CALL TreeControlPeer::isNodeVisible( const Reference< XTreeNode >& xNode ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + UnoTreeListEntry* pEntry = getEntry( xNode ); + return pEntry && rTree.IsEntryVisible( pEntry ); +} + + +void SAL_CALL TreeControlPeer::expandNode( const Reference< XTreeNode >& xNode ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + UnoTreeListEntry* pEntry = getEntry( xNode ); + if( pEntry ) + rTree.Expand( pEntry ); +} + + +void SAL_CALL TreeControlPeer::collapseNode( const Reference< XTreeNode >& xNode ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + UnoTreeListEntry* pEntry = getEntry( xNode ); + if( pEntry ) + rTree.Collapse( pEntry ); +} + + +void SAL_CALL TreeControlPeer::addTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener ) +{ + maTreeExpansionListeners.addInterface( xListener ); +} + + +void SAL_CALL TreeControlPeer::removeTreeExpansionListener( const Reference< XTreeExpansionListener >& xListener ) +{ + maTreeExpansionListeners.removeInterface( xListener ); +} + + +Reference< XTreeNode > SAL_CALL TreeControlPeer::getNodeForLocation( sal_Int32 x, sal_Int32 y ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + Reference< XTreeNode > xNode; + + const Point aPos( x, y ); + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.GetEntry( aPos, true ) ); + if( pEntry ) + xNode = pEntry->mxNode; + + return xNode; +} + + +Reference< XTreeNode > SAL_CALL TreeControlPeer::getClosestNodeForLocation( sal_Int32 x, sal_Int32 y ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + Reference< XTreeNode > xNode; + + const Point aPos( x, y ); + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( rTree.GetEntry( aPos, true ) ); + if( pEntry ) + xNode = pEntry->mxNode; + + return xNode; +} + + +awt::Rectangle SAL_CALL TreeControlPeer::getNodeRect( const Reference< XTreeNode >& i_Node ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + UnoTreeListEntry* pEntry = getEntry( i_Node ); + + ::tools::Rectangle aEntryRect( rTree.GetFocusRect( pEntry, rTree.GetEntryPosition( pEntry ).Y() ) ); + return VCLUnoHelper::ConvertToAWTRect( aEntryRect ); +} + + +sal_Bool SAL_CALL TreeControlPeer::isEditing( ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + return rTree.IsEditingActive(); +} + + +sal_Bool SAL_CALL TreeControlPeer::stopEditing() +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + if( rTree.IsEditingActive() ) + { + rTree.EndEditing(); + return true; + } + else + { + return false; + } +} + + +void SAL_CALL TreeControlPeer::cancelEditing( ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + rTree.EndEditing(); +} + + +void SAL_CALL TreeControlPeer::startEditingAtNode( const Reference< XTreeNode >& xNode ) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + UnoTreeListEntry* pEntry = getEntry( xNode ); + rTree.EditEntry( pEntry ); +} + +void SAL_CALL TreeControlPeer::addTreeEditListener( const Reference< XTreeEditListener >& xListener ) +{ + maTreeEditListeners.addInterface( xListener ); +} + +void SAL_CALL TreeControlPeer::removeTreeEditListener( const Reference< XTreeEditListener >& xListener ) +{ + maTreeEditListeners.removeInterface( xListener ); +} + +bool TreeControlPeer::onEditingEntry( UnoTreeListEntry const * pEntry ) +{ + if( mpTreeImpl && pEntry && pEntry->mxNode.is() && (maTreeEditListeners.getLength() > 0) ) + { + try + { + maTreeEditListeners.nodeEditing( pEntry->mxNode ); + } + catch( VetoException& ) + { + return false; + } + catch( Exception& ) + { + } + } + return true; +} + +bool TreeControlPeer::onEditedEntry( UnoTreeListEntry const * pEntry, const OUString& rNewText ) +{ + if( mpTreeImpl && pEntry && pEntry->mxNode.is() ) try + { + LockGuard aLockGuard( mnEditLock ); + if( maTreeEditListeners.getLength() > 0 ) + { + maTreeEditListeners.nodeEdited( pEntry->mxNode, rNewText ); + return false; + } + else + { + Reference< XMutableTreeNode > xMutableNode( pEntry->mxNode, UNO_QUERY ); + if( xMutableNode.is() ) + xMutableNode->setDisplayValue( Any( rNewText ) ); + else + return false; + } + + } + catch( Exception& ) + { + } + + return true; +} + + +// css::awt::tree::TreeDataModelListener + + +void SAL_CALL TreeControlPeer::treeNodesChanged( const css::awt::tree::TreeDataModelEvent& rEvent ) +{ + SolarMutexGuard aGuard; + + if( mnEditLock != 0 ) + return; + + updateTree( rEvent ); +} + +void SAL_CALL TreeControlPeer::treeNodesInserted( const css::awt::tree::TreeDataModelEvent& rEvent ) +{ + SolarMutexGuard aGuard; + + if( mnEditLock != 0 ) + return; + + updateTree( rEvent ); +} + +void SAL_CALL TreeControlPeer::treeNodesRemoved( const css::awt::tree::TreeDataModelEvent& rEvent ) +{ + SolarMutexGuard aGuard; + + if( mnEditLock != 0 ) + return; + + updateTree( rEvent ); +} + +void SAL_CALL TreeControlPeer::treeStructureChanged( const css::awt::tree::TreeDataModelEvent& rEvent ) +{ + SolarMutexGuard aGuard; + + if( mnEditLock != 0 ) + return; + + updateTree( rEvent ); +} + +void TreeControlPeer::updateTree( const css::awt::tree::TreeDataModelEvent& rEvent ) +{ + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + Sequence< Reference< XTreeNode > > Nodes; + Reference< XTreeNode > xNode( rEvent.ParentNode ); + if( !xNode.is() && Nodes.hasElements() ) + { + xNode = Nodes[0]; + } + + if( xNode.is() ) + updateNode( rTree, xNode ); +} + +void TreeControlPeer::updateNode( UnoTreeListBoxImpl const & rTree, const Reference< XTreeNode >& xNode ) +{ + if( !xNode.is() ) + return; + + UnoTreeListEntry* pNodeEntry = getEntry( xNode, false ); + + if( !pNodeEntry ) + { + Reference< XTreeNode > xParentNode( xNode->getParent() ); + UnoTreeListEntry* pParentEntry = nullptr; + sal_uLong nChild = TREELIST_APPEND; + + if( xParentNode.is() ) + { + pParentEntry = getEntry( xParentNode ); + nChild = xParentNode->getIndex( xNode ); + } + + pNodeEntry = createEntry( xNode, pParentEntry, nChild ); + } + + updateChildNodes( rTree, xNode, pNodeEntry ); +} + +void TreeControlPeer::updateChildNodes( UnoTreeListBoxImpl const & rTree, const Reference< XTreeNode >& xParentNode, UnoTreeListEntry* pParentEntry ) +{ + if( !(xParentNode.is() && pParentEntry) ) + return; + + UnoTreeListEntry* pCurrentChild = dynamic_cast< UnoTreeListEntry* >( rTree.FirstChild( pParentEntry ) ); + + const sal_Int32 nChildCount = xParentNode->getChildCount(); + for( sal_Int32 nChild = 0; nChild < nChildCount; nChild++ ) + { + Reference< XTreeNode > xNode( xParentNode->getChildAt( nChild ) ); + if( !pCurrentChild || ( pCurrentChild->mxNode != xNode ) ) + { + UnoTreeListEntry* pNodeEntry = getEntry( xNode, false ); + if( pNodeEntry == nullptr ) + { + // child node is not yet part of the tree, add it + pCurrentChild = createEntry( xNode, pParentEntry, nChild ); + } + else if( pNodeEntry != pCurrentChild ) + { + // node is already part of the tree, but not on the correct position + rTree.GetModel()->Move( pNodeEntry, pParentEntry, nChild ); + pCurrentChild = pNodeEntry; + updateEntry( pCurrentChild ); + } + } + else + { + // child node has entry and entry is equal to current entry, + // so no structural changes happened + updateEntry( pCurrentChild ); + } + + pCurrentChild = dynamic_cast< UnoTreeListEntry* >( pCurrentChild->NextSibling() ); + } + + // check if we have entries without nodes left, we need to remove them + while( pCurrentChild ) + { + UnoTreeListEntry* pNextChild = dynamic_cast< UnoTreeListEntry* >( pCurrentChild->NextSibling() ); + rTree.GetModel()->Remove( pCurrentChild ); + pCurrentChild = pNextChild; + } +} + +OUString TreeControlPeer::getEntryString( const Any& rValue ) +{ + OUString sValue; + if( rValue.hasValue() ) + { + switch( rValue.getValueTypeClass() ) + { + case TypeClass_SHORT: + case TypeClass_LONG: + { + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + sValue = OUString::number( nValue ); + break; + } + case TypeClass_BYTE: + case TypeClass_UNSIGNED_SHORT: + case TypeClass_UNSIGNED_LONG: + { + sal_uInt32 nValue = 0; + if( rValue >>= nValue ) + sValue = OUString::number( nValue ); + break; + } + case TypeClass_HYPER: + { + sal_Int64 nValue = 0; + if( rValue >>= nValue ) + sValue = OUString::number( nValue ); + break; + } + case TypeClass_UNSIGNED_HYPER: + { + sal_uInt64 nValue = 0; + if( rValue >>= nValue ) + sValue = OUString::number( nValue ); + break; + } + case TypeClass_FLOAT: + case TypeClass_DOUBLE: + { + double fValue = 0.0; + if( rValue >>= fValue ) + sValue = OUString::number( fValue ); + break; + } + case TypeClass_STRING: + rValue >>= sValue; + break; + /* + case TypeClass_INTERFACE: + // @todo + break; + case TypeClass_SEQUENCE: + { + Sequence< Any > aValues; + if( aValue >>= aValues ) + { + updateEntry( SvTreeListEntry& rEntry, aValues ); + return; + } + } + break; + */ + default: + break; + } + } + return sValue; +} + +// XEventListener +void SAL_CALL TreeControlPeer::disposing( const css::lang::EventObject& ) +{ + // model is disposed, so we clear our tree + SolarMutexGuard aGuard; + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + rTree.Clear(); + mxDataModel.clear(); +} + +void TreeControlPeer::onChangeDataModel( UnoTreeListBoxImpl& rTree, const Reference< XTreeDataModel >& xDataModel ) +{ + if( xDataModel.is() && (mxDataModel == xDataModel) ) + return; // do nothing + + Reference< XTreeDataModelListener > xListener( this ); + + if( mxDataModel.is() ) + mxDataModel->removeTreeDataModelListener( xListener ); + + mxDataModel = xDataModel; + + fillTree( rTree, mxDataModel ); + + if( mxDataModel.is() ) + mxDataModel->addTreeDataModelListener( xListener ); +} + + +// css::awt::XLayoutConstrains + + +css::awt::Size TreeControlPeer::getMinimumSize() +{ + SolarMutexGuard aGuard; + + css::awt::Size aSz; +/* todo + MultiLineEdit* pEdit = (MultiLineEdit*) GetWindow(); + if ( pEdit ) + aSz = AWTSize(pEdit->CalcMinimumSize()); +*/ + return aSz; +} + +css::awt::Size TreeControlPeer::getPreferredSize() +{ + return getMinimumSize(); +} + +css::awt::Size TreeControlPeer::calcAdjustedSize( const css::awt::Size& rNewSize ) +{ + SolarMutexGuard aGuard; + + css::awt::Size aSz = rNewSize; +/* todo + MultiLineEdit* pEdit = (MultiLineEdit*) GetWindow(); + if ( pEdit ) + aSz = AWTSize(pEdit->CalcAdjustedSize( VCLSize(rNewSize ))); +*/ + return aSz; +} + + +// css::awt::XVclWindowPeer + + +void TreeControlPeer::setProperty( const OUString& PropertyName, const Any& aValue) +{ + SolarMutexGuard aGuard; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + switch( GetPropertyId( PropertyName ) ) + { + case BASEPROPERTY_HIDEINACTIVESELECTION: + { + bool bEnabled = false; + if ( aValue >>= bEnabled ) + { + WinBits nStyle = rTree.GetStyle(); + if ( bEnabled ) + nStyle |= WB_HIDESELECTION; + else + nStyle &= ~WB_HIDESELECTION; + rTree.SetStyle( nStyle ); + } + } + break; + + case BASEPROPERTY_TREE_SELECTIONTYPE: + { + SelectionType eSelectionType; + if( aValue >>= eSelectionType ) + { + SelectionMode eSelMode; + switch( eSelectionType ) + { + case SelectionType_SINGLE: eSelMode = SelectionMode::Single; break; + case SelectionType_RANGE: eSelMode = SelectionMode::Range; break; + case SelectionType_MULTI: eSelMode = SelectionMode::Multiple; break; + // case SelectionType_NONE: + default: eSelMode = SelectionMode::NONE; break; + } + if( rTree.GetSelectionMode() != eSelMode ) + rTree.SetSelectionMode( eSelMode ); + } + break; + } + + case BASEPROPERTY_TREE_DATAMODEL: + onChangeDataModel( rTree, Reference< XTreeDataModel >( aValue, UNO_QUERY ) ); + break; + case BASEPROPERTY_ROW_HEIGHT: + { + sal_Int32 nHeight = 0; + if( aValue >>= nHeight ) + rTree.SetEntryHeight( static_cast<short>(nHeight) ); + break; + } + case BASEPROPERTY_TREE_EDITABLE: + { + bool bEnabled = false; + if( aValue >>= bEnabled ) + rTree.EnableInplaceEditing( bEnabled ); + break; + } + case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING: + break; // @todo + case BASEPROPERTY_TREE_ROOTDISPLAYED: + { + bool bDisplayed = false; + if( (aValue >>= bDisplayed) && ( bDisplayed != mbIsRootDisplayed) ) + { + onChangeRootDisplayed(bDisplayed); + } + break; + } + case BASEPROPERTY_TREE_SHOWSHANDLES: + { + bool bEnabled = false; + if( aValue >>= bEnabled ) + { + WinBits nBits = rTree.GetStyle() & (~WB_HASLINES); + if( bEnabled ) + nBits |= WB_HASLINES; + if( nBits != rTree.GetStyle() ) + rTree.SetStyle( nBits ); + } + break; + } + case BASEPROPERTY_TREE_SHOWSROOTHANDLES: + { + bool bEnabled = false; + if( aValue >>= bEnabled ) + { + WinBits nBits = rTree.GetStyle() & (~WB_HASLINESATROOT); + if( bEnabled ) + nBits |= WB_HASLINESATROOT; + if( nBits != rTree.GetStyle() ) + rTree.SetStyle( nBits ); + } + break; + } + default: + VCLXWindow::setProperty( PropertyName, aValue ); + break; + } +} + +Any TreeControlPeer::getProperty( const OUString& PropertyName ) +{ + SolarMutexGuard aGuard; + + const sal_uInt16 nPropId = GetPropertyId( PropertyName ); + if( (nPropId >= BASEPROPERTY_TREE_START) && (nPropId <= BASEPROPERTY_TREE_END) ) + { + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + switch(nPropId) + { + case BASEPROPERTY_TREE_SELECTIONTYPE: + { + SelectionType eSelectionType; + + SelectionMode eSelMode = rTree.GetSelectionMode(); + switch( eSelMode ) + { + case SelectionMode::Single: eSelectionType = SelectionType_SINGLE; break; + case SelectionMode::Range: eSelectionType = SelectionType_RANGE; break; + case SelectionMode::Multiple:eSelectionType = SelectionType_MULTI; break; +// case SelectionMode::NONE: + default: eSelectionType = SelectionType_NONE; break; + } + return Any( eSelectionType ); + } + case BASEPROPERTY_ROW_HEIGHT: + return Any( static_cast<sal_Int32>(rTree.GetEntryHeight()) ); + case BASEPROPERTY_TREE_DATAMODEL: + return Any( mxDataModel ); + case BASEPROPERTY_TREE_EDITABLE: + return Any( rTree.IsInplaceEditingEnabled() ); + case BASEPROPERTY_TREE_INVOKESSTOPNODEEDITING: + return Any( true ); // @todo + case BASEPROPERTY_TREE_ROOTDISPLAYED: + return Any( mbIsRootDisplayed ); + case BASEPROPERTY_TREE_SHOWSHANDLES: + return Any( (rTree.GetStyle() & WB_HASLINES) != 0 ); + case BASEPROPERTY_TREE_SHOWSROOTHANDLES: + return Any( (rTree.GetStyle() & WB_HASLINESATROOT) != 0 ); + } + } + return VCLXWindow::getProperty( PropertyName ); +} + +void TreeControlPeer::onChangeRootDisplayed( bool bIsRootDisplayed ) +{ + if( mbIsRootDisplayed == bIsRootDisplayed ) + return; + + mbIsRootDisplayed = bIsRootDisplayed; + + UnoTreeListBoxImpl& rTree = getTreeListBoxOrThrow(); + + if( rTree.GetEntryCount() == 0 ) + return; + + // todo + fillTree( rTree, mxDataModel ); +} + +bool TreeControlPeer::loadImage( const OUString& rURL, Image& rImage ) +{ + if( !mxGraphicProvider.is() ) + { + mxGraphicProvider = graphic::GraphicProvider::create( + comphelper::getProcessComponentContext()); + } + + try + { + css::beans::PropertyValues aProps{ comphelper::makePropertyValue("URL", rURL) }; + Reference< XGraphic > xGraphic( mxGraphicProvider->queryGraphic( aProps ) ); + + Graphic aGraphic( xGraphic ); + rImage = Image(aGraphic.GetBitmapEx()); + return true; + } + catch( Exception& ) + { + } + + return false; +} + + + + +UnoTreeListBoxImpl::UnoTreeListBoxImpl( TreeControlPeer* pPeer, vcl::Window* pParent, WinBits nWinStyle ) +: SvTreeListBox( pParent, nWinStyle ) +, mxPeer( pPeer ) +{ + SetStyle( WB_BORDER | WB_HASLINES |WB_HASBUTTONS | WB_HASLINESATROOT | WB_HASBUTTONSATROOT | WB_HSCROLL ); + SetNodeDefaultImages(); + SetSelectHdl( LINK(this, UnoTreeListBoxImpl, OnSelectionChangeHdl) ); + SetDeselectHdl( LINK(this, UnoTreeListBoxImpl, OnSelectionChangeHdl) ); + + SetExpandingHdl( LINK(this, UnoTreeListBoxImpl, OnExpandingHdl) ); + SetExpandedHdl( LINK(this, UnoTreeListBoxImpl, OnExpandedHdl) ); + +} + + +UnoTreeListBoxImpl::~UnoTreeListBoxImpl() +{ + disposeOnce(); +} + +void UnoTreeListBoxImpl::dispose() +{ + if( mxPeer.is() ) + mxPeer->disposeControl(); + mxPeer.clear(); + SvTreeListBox::dispose(); +} + + +IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnSelectionChangeHdl, SvTreeListBox*, void) +{ + if( mxPeer.is() ) + mxPeer->onSelectionChanged(); +} + + +IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnExpandingHdl, SvTreeListBox*, bool) +{ + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( GetHdlEntry() ); + + if( pEntry && mxPeer.is() ) + { + return mxPeer->onExpanding( pEntry->mxNode, !IsExpanded( pEntry ) ); + } + return false; +} + + +IMPL_LINK_NOARG(UnoTreeListBoxImpl, OnExpandedHdl, SvTreeListBox*, void) +{ + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( GetHdlEntry() ); + if( pEntry && mxPeer.is() ) + { + mxPeer->onExpanded( pEntry->mxNode, IsExpanded( pEntry ) ); + } +} + + +void UnoTreeListBoxImpl::insert( SvTreeListEntry* pEntry,SvTreeListEntry* pParent,sal_uLong nPos ) +{ + if( pParent ) + SvTreeListBox::Insert( pEntry, pParent, nPos ); + else + SvTreeListBox::Insert( pEntry, nPos ); +} + + +void UnoTreeListBoxImpl::RequestingChildren( SvTreeListEntry* pParent ) +{ + UnoTreeListEntry* pEntry = dynamic_cast< UnoTreeListEntry* >( pParent ); + if( pEntry && pEntry->mxNode.is() && mxPeer.is() ) + mxPeer->onRequestChildNodes( pEntry->mxNode ); +} + + +bool UnoTreeListBoxImpl::EditingEntry( SvTreeListEntry* pEntry ) +{ + return mxPeer.is() && mxPeer->onEditingEntry( dynamic_cast< UnoTreeListEntry* >( pEntry ) ); +} + + +bool UnoTreeListBoxImpl::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText ) +{ + return mxPeer.is() && mxPeer->onEditedEntry( dynamic_cast< UnoTreeListEntry* >( pEntry ), rNewText ); +} + + + + +UnoTreeListItem::UnoTreeListItem() +: SvLBoxString(OUString()) +{ +} + +void UnoTreeListItem::Paint( + const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext, const SvViewDataEntry* /*pView*/, const SvTreeListEntry& rEntry) +{ + Point aPos(rPos); + Size aSize(GetWidth(&rDev, &rEntry), GetHeight(&rDev, &rEntry)); + if (!!maImage) + { + rRenderContext.DrawImage(aPos, maImage, rDev.IsEnabled() ? DrawImageFlags::NONE : DrawImageFlags::Disable); + int nWidth = maImage.GetSizePixel().Width() + 6; + aPos.AdjustX(nWidth ); + aSize.AdjustWidth( -nWidth ); + } + rRenderContext.DrawText(tools::Rectangle(aPos,aSize),maText, rDev.IsEnabled() ? DrawTextFlags::NONE : DrawTextFlags::Disable); +} + + +std::unique_ptr<SvLBoxItem> UnoTreeListItem::Clone(SvLBoxItem const * pSource) const +{ + std::unique_ptr<UnoTreeListItem> pNew(new UnoTreeListItem); + UnoTreeListItem const * pSourceItem = static_cast< UnoTreeListItem const * >( pSource ); + pNew->maText = pSourceItem->maText; + pNew->maImage = pSourceItem->maImage; + return std::unique_ptr<SvLBoxItem>(pNew.release()); +} + + +void UnoTreeListItem::SetImage( const Image& rImage ) +{ + maImage = rImage; +} + + +void UnoTreeListItem::SetGraphicURL( const OUString& rGraphicURL ) +{ + maGraphicURL = rGraphicURL; +} + + +void UnoTreeListItem::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData) +{ + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + + Size aSize(maImage.GetSizePixel()); + pViewData->mnWidth = aSize.Width(); + pViewData->mnHeight = aSize.Height(); + + const Size aTextSize(pView->GetTextWidth( maText ), pView->GetTextHeight()); + if( pViewData->mnWidth ) + { + pViewData->mnWidth += (6 + aTextSize.Width()); + if( pViewData->mnHeight < aTextSize.Height() ) + pViewData->mnHeight = aTextSize.Height(); + } + else + { + pViewData->mnWidth = aTextSize.Width(); + pViewData->mnHeight = aTextSize.Height(); + } +} + + +UnoTreeListEntry::UnoTreeListEntry( const Reference< XTreeNode >& xNode, TreeControlPeer* pPeer ) +: mxNode( xNode ) +, mpPeer( pPeer ) +{ + if( mpPeer ) + mpPeer->addEntry( this ); +} + + +UnoTreeListEntry::~UnoTreeListEntry() +{ + if( mpPeer ) + mpPeer->removeEntry( this ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/tree/treedatamodel.cxx b/toolkit/source/controls/tree/treedatamodel.cxx new file mode 100644 index 000000000..df8056057 --- /dev/null +++ b/toolkit/source/controls/tree/treedatamodel.cxx @@ -0,0 +1,523 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/awt/tree/XMutableTreeDataModel.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/implbase2.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/ref.hxx> +#include <toolkit/helper/mutexandbroadcasthelper.hxx> +#include <mutex> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::awt::tree; +using namespace ::com::sun::star::lang; + +namespace { + + enum broadcast_type { nodes_changed, nodes_inserted, nodes_removed, structure_changed }; + +class MutableTreeNode; +class MutableTreeDataModel; + +typedef std::vector< rtl::Reference< MutableTreeNode > > TreeNodeVector; + +class MutableTreeDataModel : public ::cppu::WeakAggImplHelper2< XMutableTreeDataModel, XServiceInfo >, + public MutexAndBroadcastHelper +{ +public: + MutableTreeDataModel(); + + void broadcast( broadcast_type eType, const Reference< XTreeNode >& xParentNode, const Reference< XTreeNode >& rNode ); + + // XMutableTreeDataModel + virtual css::uno::Reference< css::awt::tree::XMutableTreeNode > SAL_CALL createNode( const css::uno::Any& DisplayValue, sal_Bool ChildrenOnDemand ) override; + virtual void SAL_CALL setRoot( const css::uno::Reference< css::awt::tree::XMutableTreeNode >& RootNode ) override; + + // XTreeDataModel + virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getRoot( ) override; + virtual void SAL_CALL addTreeDataModelListener( const css::uno::Reference< css::awt::tree::XTreeDataModelListener >& Listener ) override; + virtual void SAL_CALL removeTreeDataModelListener( const css::uno::Reference< css::awt::tree::XTreeDataModelListener >& Listener ) override; + + // XComponent + virtual void SAL_CALL dispose( ) override; + virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + +private: + bool mbDisposed; + Reference< XTreeNode > mxRootNode; +}; + +class MutableTreeNode: public ::cppu::WeakAggImplHelper2< XMutableTreeNode, XServiceInfo > +{ + friend class MutableTreeDataModel; + +public: + MutableTreeNode( const rtl::Reference< MutableTreeDataModel >& xModel, const Any& rValue, bool bChildrenOnDemand ); + virtual ~MutableTreeNode() override; + + void setParent( MutableTreeNode* pParent ); + void broadcast_changes(); + void broadcast_changes(std::unique_lock<std::mutex> & rLock, + const Reference< XTreeNode >& xNode, bool bNew); + + // XMutableTreeNode + virtual css::uno::Any SAL_CALL getDataValue() override; + virtual void SAL_CALL setDataValue( const css::uno::Any& _datavalue ) override; + virtual void SAL_CALL appendChild( const css::uno::Reference< css::awt::tree::XMutableTreeNode >& ChildNode ) override; + virtual void SAL_CALL insertChildByIndex( ::sal_Int32 Index, const css::uno::Reference< css::awt::tree::XMutableTreeNode >& ChildNode ) override; + virtual void SAL_CALL removeChildByIndex( ::sal_Int32 Index ) override; + virtual void SAL_CALL setHasChildrenOnDemand( sal_Bool ChildrenOnDemand ) override; + virtual void SAL_CALL setDisplayValue( const css::uno::Any& Value ) override; + virtual void SAL_CALL setNodeGraphicURL( const OUString& URL ) override; + virtual void SAL_CALL setExpandedGraphicURL( const OUString& URL ) override; + virtual void SAL_CALL setCollapsedGraphicURL( const OUString& URL ) override; + + // XTreeNode + virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getChildAt( ::sal_Int32 Index ) override; + virtual ::sal_Int32 SAL_CALL getChildCount( ) override; + virtual css::uno::Reference< css::awt::tree::XTreeNode > SAL_CALL getParent( ) override; + virtual ::sal_Int32 SAL_CALL getIndex( const css::uno::Reference< css::awt::tree::XTreeNode >& Node ) override; + virtual sal_Bool SAL_CALL hasChildrenOnDemand( ) override; + virtual css::uno::Any SAL_CALL getDisplayValue( ) override; + virtual OUString SAL_CALL getNodeGraphicURL( ) override; + virtual OUString SAL_CALL getExpandedGraphicURL( ) override; + virtual OUString SAL_CALL getCollapsedGraphicURL( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + +private: + TreeNodeVector maChildren; + Any maDisplayValue; + Any maDataValue; + bool mbHasChildrenOnDemand; + std::mutex maMutex; + MutableTreeNode* mpParent; + rtl::Reference< MutableTreeDataModel > mxModel; + OUString maNodeGraphicURL; + OUString maExpandedGraphicURL; + OUString maCollapsedGraphicURL; + bool mbIsInserted; +}; + +MutableTreeDataModel::MutableTreeDataModel() +: mbDisposed( false ) +{ +} + +void MutableTreeDataModel::broadcast( broadcast_type eType, const Reference< XTreeNode >& xParentNode, const Reference< XTreeNode >& rNode ) +{ + ::cppu::OInterfaceContainerHelper* pIter = BrdcstHelper.getContainer( cppu::UnoType<XTreeDataModelListener>::get() ); + if( !pIter ) + return; + + Reference< XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + const Sequence< Reference< XTreeNode > > aNodes { rNode }; + TreeDataModelEvent aEvent( xSource, aNodes, xParentNode ); + + ::cppu::OInterfaceIteratorHelper aListIter(*pIter); + while(aListIter.hasMoreElements()) + { + XTreeDataModelListener* pListener = static_cast<XTreeDataModelListener*>(aListIter.next()); + switch( eType ) + { + case nodes_changed: pListener->treeNodesChanged(aEvent); break; + case nodes_inserted: pListener->treeNodesInserted(aEvent); break; + case nodes_removed: pListener->treeNodesRemoved(aEvent); break; + case structure_changed: pListener->treeStructureChanged(aEvent); break; + } + } +} + +Reference< XMutableTreeNode > SAL_CALL MutableTreeDataModel::createNode( const Any& aValue, sal_Bool bChildrenOnDemand ) +{ + return new MutableTreeNode( this, aValue, bChildrenOnDemand ); +} + +void SAL_CALL MutableTreeDataModel::setRoot( const Reference< XMutableTreeNode >& xNode ) +{ + if( !xNode.is() ) + throw IllegalArgumentException(); + + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + if( xNode == mxRootNode ) + return; + + if( mxRootNode.is() ) + { + rtl::Reference< MutableTreeNode > xOldImpl( dynamic_cast< MutableTreeNode* >( mxRootNode.get() ) ); + if( xOldImpl.is() ) + xOldImpl->mbIsInserted = false; + } + + rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xNode.get() ) ); + if( !xImpl.is() || xImpl->mbIsInserted ) + throw IllegalArgumentException(); + + xImpl->mbIsInserted = true; + mxRootNode = xImpl; + + Reference< XTreeNode > xParentNode; + broadcast( structure_changed, xParentNode, mxRootNode ); +} + +Reference< XTreeNode > SAL_CALL MutableTreeDataModel::getRoot( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + return mxRootNode; +} + +void SAL_CALL MutableTreeDataModel::addTreeDataModelListener( const Reference< XTreeDataModelListener >& xListener ) +{ + BrdcstHelper.addListener( cppu::UnoType<XTreeDataModelListener>::get(), xListener ); +} + +void SAL_CALL MutableTreeDataModel::removeTreeDataModelListener( const Reference< XTreeDataModelListener >& xListener ) +{ + BrdcstHelper.removeListener( cppu::UnoType<XTreeDataModelListener>::get(), xListener ); +} + +void SAL_CALL MutableTreeDataModel::dispose() +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + if( !mbDisposed ) + { + mbDisposed = true; + css::lang::EventObject aEvent; + aEvent.Source.set( static_cast< ::cppu::OWeakObject* >( this ) ); + BrdcstHelper.aLC.disposeAndClear( aEvent ); + } +} + +void SAL_CALL MutableTreeDataModel::addEventListener( const Reference< XEventListener >& xListener ) +{ + BrdcstHelper.addListener( cppu::UnoType<XEventListener>::get(), xListener ); +} + +void SAL_CALL MutableTreeDataModel::removeEventListener( const Reference< XEventListener >& xListener ) +{ + BrdcstHelper.removeListener( cppu::UnoType<XEventListener>::get(), xListener ); +} + +OUString SAL_CALL MutableTreeDataModel::getImplementationName( ) +{ + return "toolkit.MutableTreeDataModel"; +} + +sal_Bool SAL_CALL MutableTreeDataModel::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL MutableTreeDataModel::getSupportedServiceNames( ) +{ + Sequence<OUString> aSeq { "com.sun.star.awt.tree.MutableTreeDataModel" }; + return aSeq; +} + +MutableTreeNode::MutableTreeNode( const rtl::Reference< MutableTreeDataModel >& xModel, const Any& rValue, bool bChildrenOnDemand ) +: maDisplayValue( rValue ) +, mbHasChildrenOnDemand( bChildrenOnDemand ) +, mpParent( nullptr ) +, mxModel( xModel ) +, mbIsInserted( false ) +{ +} + +MutableTreeNode::~MutableTreeNode() +{ + for( auto& rChild : maChildren ) + rChild->setParent(nullptr); +} + +void MutableTreeNode::setParent( MutableTreeNode* pParent ) +{ + mpParent = pParent; +} + +void MutableTreeNode::broadcast_changes() +{ + if( mxModel.is() ) + { + mxModel->broadcast( nodes_changed, mpParent, this ); + } +} + +void MutableTreeNode::broadcast_changes(std::unique_lock<std::mutex> & rLock, + const Reference< XTreeNode >& xNode, bool const bNew) +{ + auto const xModel(mxModel); + rLock.unlock(); + if (xModel.is()) + { + xModel->broadcast(bNew ? nodes_inserted : nodes_removed, this, xNode); + } +} + +Any SAL_CALL MutableTreeNode::getDataValue() +{ + std::scoped_lock aGuard( maMutex ); + return maDataValue; +} + +void SAL_CALL MutableTreeNode::setDataValue( const Any& _datavalue ) +{ + std::scoped_lock aGuard( maMutex ); + maDataValue = _datavalue; +} + +void SAL_CALL MutableTreeNode::appendChild( const Reference< XMutableTreeNode >& xChildNode ) +{ + std::unique_lock aGuard( maMutex ); + rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xChildNode.get() ) ); + + if( !xImpl.is() || xImpl->mbIsInserted || (this == xImpl.get()) ) + throw IllegalArgumentException(); + + maChildren.push_back( xImpl ); + xImpl->setParent(this); + xImpl->mbIsInserted = true; + + broadcast_changes(aGuard, xChildNode, true); +} + +void SAL_CALL MutableTreeNode::insertChildByIndex( sal_Int32 nChildIndex, const Reference< XMutableTreeNode >& xChildNode ) +{ + std::unique_lock aGuard( maMutex ); + + if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) > maChildren.size()) ) + throw IndexOutOfBoundsException(); + + rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xChildNode.get() ) ); + if( !xImpl.is() || xImpl->mbIsInserted || (this == xImpl.get()) ) + throw IllegalArgumentException(); + + xImpl->mbIsInserted = true; + + TreeNodeVector::iterator aIter( maChildren.begin() ); + std::advance(aIter, nChildIndex); + + maChildren.insert( aIter, xImpl ); + xImpl->setParent( this ); + + broadcast_changes(aGuard, xChildNode, true); +} + +void SAL_CALL MutableTreeNode::removeChildByIndex( sal_Int32 nChildIndex ) +{ + std::unique_lock aGuard( maMutex ); + + if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) >= maChildren.size()) ) + throw IndexOutOfBoundsException(); + + rtl::Reference< MutableTreeNode > xImpl; + + TreeNodeVector::iterator aIter( maChildren.begin() ); + std::advance(aIter, nChildIndex); + + xImpl = *aIter; + maChildren.erase( aIter ); + + if( !xImpl.is() ) + throw IndexOutOfBoundsException(); + + xImpl->setParent(nullptr); + xImpl->mbIsInserted = false; + + broadcast_changes(aGuard, xImpl, false); +} + +void SAL_CALL MutableTreeNode::setHasChildrenOnDemand( sal_Bool bChildrenOnDemand ) +{ + bool bChanged; + + { + std::scoped_lock aGuard( maMutex ); + bChanged = mbHasChildrenOnDemand != bool(bChildrenOnDemand); + mbHasChildrenOnDemand = bChildrenOnDemand; + } + + if( bChanged ) + broadcast_changes(); +} + +void SAL_CALL MutableTreeNode::setDisplayValue( const Any& aValue ) +{ + { + std::scoped_lock aGuard( maMutex ); + maDisplayValue = aValue; + } + + broadcast_changes(); +} + +void SAL_CALL MutableTreeNode::setNodeGraphicURL( const OUString& rURL ) +{ + bool bChanged; + + { + std::scoped_lock aGuard( maMutex ); + bChanged = maNodeGraphicURL != rURL; + maNodeGraphicURL = rURL; + } + + if( bChanged ) + broadcast_changes(); +} + +void SAL_CALL MutableTreeNode::setExpandedGraphicURL( const OUString& rURL ) +{ + bool bChanged; + + { + std::scoped_lock aGuard( maMutex ); + bChanged = maExpandedGraphicURL != rURL; + maExpandedGraphicURL = rURL; + } + + if( bChanged ) + broadcast_changes(); +} + +void SAL_CALL MutableTreeNode::setCollapsedGraphicURL( const OUString& rURL ) +{ + bool bChanged; + + { + std::scoped_lock aGuard( maMutex ); + bChanged = maCollapsedGraphicURL != rURL; + maCollapsedGraphicURL = rURL; + } + + if( bChanged ) + broadcast_changes(); +} + +Reference< XTreeNode > SAL_CALL MutableTreeNode::getChildAt( sal_Int32 nChildIndex ) +{ + std::scoped_lock aGuard( maMutex ); + + if( (nChildIndex < 0) || (o3tl::make_unsigned(nChildIndex) >= maChildren.size()) ) + throw IndexOutOfBoundsException(); + return maChildren[nChildIndex]; +} + +sal_Int32 SAL_CALL MutableTreeNode::getChildCount( ) +{ + std::scoped_lock aGuard( maMutex ); + return static_cast<sal_Int32>(maChildren.size()); +} + +Reference< XTreeNode > SAL_CALL MutableTreeNode::getParent( ) +{ + std::scoped_lock aGuard( maMutex ); + return mpParent; +} + +sal_Int32 SAL_CALL MutableTreeNode::getIndex( const Reference< XTreeNode >& xNode ) +{ + std::scoped_lock aGuard( maMutex ); + + rtl::Reference< MutableTreeNode > xImpl( dynamic_cast< MutableTreeNode* >( xNode.get() ) ); + if( xImpl.is() ) + { + sal_Int32 nChildCount = maChildren.size(); + while( nChildCount-- ) + { + if( maChildren[nChildCount] == xImpl ) + return nChildCount; + } + } + + return -1; +} + +sal_Bool SAL_CALL MutableTreeNode::hasChildrenOnDemand( ) +{ + std::scoped_lock aGuard( maMutex ); + return mbHasChildrenOnDemand; +} + +Any SAL_CALL MutableTreeNode::getDisplayValue( ) +{ + std::scoped_lock aGuard( maMutex ); + return maDisplayValue; +} + +OUString SAL_CALL MutableTreeNode::getNodeGraphicURL( ) +{ + std::scoped_lock aGuard( maMutex ); + return maNodeGraphicURL; +} + +OUString SAL_CALL MutableTreeNode::getExpandedGraphicURL( ) +{ + std::scoped_lock aGuard( maMutex ); + return maExpandedGraphicURL; +} + +OUString SAL_CALL MutableTreeNode::getCollapsedGraphicURL( ) +{ + std::scoped_lock aGuard( maMutex ); + return maCollapsedGraphicURL; +} + +OUString SAL_CALL MutableTreeNode::getImplementationName( ) +{ + return "toolkit.MutableTreeNode"; +} + +sal_Bool SAL_CALL MutableTreeNode::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL MutableTreeNode::getSupportedServiceNames( ) +{ + Sequence<OUString> aSeq { "com.sun.star.awt.tree.MutableTreeNode" }; + return aSeq; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_MutableTreeDataModel_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new MutableTreeDataModel()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/unocontrol.cxx b/toolkit/source/controls/unocontrol.cxx new file mode 100644 index 000000000..b1e802899 --- /dev/null +++ b/toolkit/source/controls/unocontrol.cxx @@ -0,0 +1,1565 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <com/sun/star/awt/XControlContainer.hpp> +#include <com/sun/star/awt/WindowAttribute.hpp> +#include <com/sun/star/awt/VclWindowPeerAttribute.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/resource/XStringResourceResolver.hpp> +#include <toolkit/controls/unocontrol.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/mutex.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> +#include <toolkit/helper/property.hxx> +#include <toolkit/awt/vclxwindow.hxx> +#include <controls/accessiblecontrolcontext.hxx> + +#include <algorithm> +#include <map> +#include <string_view> +#include <vector> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +using ::com::sun::star::accessibility::XAccessibleContext; +using ::com::sun::star::accessibility::XAccessible; + +namespace { + +struct LanguageDependentProp +{ + const char* pPropName; + sal_Int32 nPropNameLength; +}; + +} + +const LanguageDependentProp aLanguageDependentProp[] = +{ + { "Text", 4 }, + { "Label", 5 }, + { "Title", 5 }, + { "HelpText", 8 }, + { "CurrencySymbol", 14 }, + { "StringItemList", 14 }, + { nullptr, 0 } +}; + +static Sequence< OUString> lcl_ImplGetPropertyNames( const Reference< XMultiPropertySet > & rxModel ) +{ + Sequence< OUString> aNames; + Reference< XPropertySetInfo > xPSInf = rxModel->getPropertySetInfo(); + DBG_ASSERT( xPSInf.is(), "UpdateFromModel: No PropertySetInfo!" ); + if ( xPSInf.is() ) + { + const Sequence< Property> aProps = xPSInf->getProperties(); + sal_Int32 nLen = aProps.getLength(); + aNames = Sequence< OUString>( nLen ); + std::transform(aProps.begin(), aProps.end(), aNames.getArray(), + [](const Property& rProp) -> OUString { return rProp.Name; }); + } + return aNames; +} + +namespace { + +class VclListenerLock +{ +private: + VCLXWindow* m_pLockWindow; + +public: + explicit VclListenerLock( VCLXWindow* _pLockWindow ) + : m_pLockWindow( _pLockWindow ) + { + if ( m_pLockWindow ) + m_pLockWindow->suspendVclEventListening( ); + } + ~VclListenerLock() + { + if ( m_pLockWindow ) + m_pLockWindow->resumeVclEventListening( ); + } + VclListenerLock(const VclListenerLock&) = delete; + VclListenerLock& operator=(const VclListenerLock&) = delete; +}; + +} + +typedef ::std::map< OUString, sal_Int32 > MapString2Int; +struct UnoControl_Data +{ + MapString2Int aSuspendedPropertyNotifications; + /// true if and only if our model has a property ResourceResolver + bool bLocalizationSupport; + + UnoControl_Data() + :bLocalizationSupport( false ) + { + } +}; + +UnoControl::UnoControl() : + maDisposeListeners( *this ) + , maWindowListeners( *this ) + , maFocusListeners( *this ) + , maKeyListeners( *this ) + , maMouseListeners( *this ) + , maMouseMotionListeners( *this ) + , maPaintListeners( *this ) + , maModeChangeListeners( GetMutex() ) + , mpData( new UnoControl_Data ) +{ + mbDisposePeer = true; + mbRefreshingPeer = false; + mbCreatingPeer = false; + mbCreatingCompatiblePeer = false; + mbDesignMode = false; +} + +UnoControl::~UnoControl() +{ +} + +OUString UnoControl::GetComponentServiceName() const +{ + return OUString(); +} + +Reference< XWindowPeer > UnoControl::ImplGetCompatiblePeer() +{ + DBG_ASSERT( !mbCreatingCompatiblePeer, "ImplGetCompatiblePeer - recursive?" ); + + mbCreatingCompatiblePeer = true; + + Reference< XWindowPeer > xCompatiblePeer = getPeer(); + + if ( !xCompatiblePeer.is() ) + { + // Create the pair as invisible + bool bVis = maComponentInfos.bVisible; + if( bVis ) + maComponentInfos.bVisible = false; + + Reference< XWindowPeer > xCurrentPeer = getPeer(); + setPeer( nullptr ); + + // queryInterface ourself, to allow aggregation + Reference< XControl > xMe; + OWeakAggObject::queryInterface( cppu::UnoType<decltype(xMe)>::get() ) >>= xMe; + + vcl::Window* pParentWindow( nullptr ); + { + SolarMutexGuard aGuard; + auto pDefaultDevice = Application::GetDefaultDevice(); + if (pDefaultDevice) + pParentWindow = pDefaultDevice->GetOwnerWindow(); + ENSURE_OR_THROW( pParentWindow != nullptr, "could obtain a default parent window!" ); + } + try + { + xMe->createPeer( nullptr, pParentWindow->GetComponentInterface() ); + } + catch( const Exception& ) + { + mbCreatingCompatiblePeer = false; + throw; + } + xCompatiblePeer = getPeer(); + setPeer( xCurrentPeer ); + + if ( xCompatiblePeer.is() && mxGraphics.is() ) + { + Reference< XView > xPeerView( xCompatiblePeer, UNO_QUERY ); + if ( xPeerView.is() ) + xPeerView->setGraphics( mxGraphics ); + } + + if( bVis ) + maComponentInfos.bVisible = true; + } + + mbCreatingCompatiblePeer = false; + + return xCompatiblePeer; +} + +bool UnoControl::ImplCheckLocalize( OUString& _rPossiblyLocalizable ) +{ + if ( !mpData->bLocalizationSupport + || ( _rPossiblyLocalizable.isEmpty() ) + || ( _rPossiblyLocalizable[0] != '&' ) + // TODO: make this reasonable. At the moment, everything which by accident starts with a & is considered + // localizable, which is probably wrong. + ) + return false; + + try + { + Reference< XPropertySet > xPropSet( mxModel, UNO_QUERY_THROW ); + Reference< resource::XStringResourceResolver > xStringResourceResolver( + xPropSet->getPropertyValue("ResourceResolver"), + UNO_QUERY + ); + if ( xStringResourceResolver.is() ) + { + OUString aLocalizationKey( _rPossiblyLocalizable.copy( 1 ) ); + _rPossiblyLocalizable = xStringResourceResolver->resolveString( aLocalizationKey ); + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + return false; +} + +void UnoControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal ) +{ + // since a change made in propertiesChange, we can't be sure that this is called with a valid getPeer(), + // this assumption may be false in some (seldom) multi-threading scenarios (cause propertiesChange + // releases our mutex before calling here in) + // That's why this additional check + + if ( !mxVclWindowPeer.is() ) + return; + + Any aConvertedValue( rVal ); + + if ( mpData->bLocalizationSupport ) + { + // We now support a mapping for language dependent properties. This is the + // central method to implement it. + if( rPropName == "Text" || + rPropName == "Label" || + rPropName == "Title" || + rPropName == "HelpText" || + rPropName == "CurrencySymbol" || + rPropName == "StringItemList" ) + { + OUString aValue; + uno::Sequence< OUString > aSeqValue; + if ( aConvertedValue >>= aValue ) + { + if ( ImplCheckLocalize( aValue ) ) + aConvertedValue <<= aValue; + } + else if ( aConvertedValue >>= aSeqValue ) + { + for ( auto& rValue : asNonConstRange(aSeqValue) ) + ImplCheckLocalize( rValue ); + aConvertedValue <<= aSeqValue; + } + } + } + + mxVclWindowPeer->setProperty( rPropName, aConvertedValue ); +} + +void UnoControl::PrepareWindowDescriptor( WindowDescriptor& ) +{ +} + +Reference< XWindow > UnoControl::getParentPeer() const +{ + Reference< XWindow > xPeer; + if( mxContext.is() ) + { + Reference< XControl > xContComp( mxContext, UNO_QUERY ); + if ( xContComp.is() ) + { + Reference< XWindowPeer > xP = xContComp->getPeer(); + if ( xP.is() ) + xPeer.set( xP, UNO_QUERY ); + } + } + return xPeer; +} + +void UnoControl::updateFromModel() +{ + // Read default properties and hand over to peer + if( getPeer().is() ) + { + Reference< XMultiPropertySet > xPropSet( mxModel, UNO_QUERY ); + if( xPropSet.is() ) + { + Sequence< OUString> aNames = lcl_ImplGetPropertyNames( xPropSet ); + xPropSet->firePropertiesChangeEvent( aNames, this ); + } + } +} + + +// XTypeProvider +IMPL_IMPLEMENTATION_ID( UnoControl ) + +void +UnoControl::DisposeAccessibleContext(Reference<XComponent> const& xContextComp) +{ + if (xContextComp.is()) + { + try + { + xContextComp->removeEventListener( this ); + xContextComp->dispose(); + } + catch( const Exception& ) + { + OSL_FAIL( "UnoControl::disposeAccessibleContext: could not dispose my AccessibleContext!" ); + } + } +} + +void UnoControl::dispose( ) +{ + Reference< XWindowPeer > xPeer; + Reference<XComponent> xAccessibleComp; + { + ::osl::MutexGuard aGuard( GetMutex() ); + if( mbDisposePeer ) + { + xPeer = mxPeer; + } + setPeer( nullptr ); + xAccessibleComp.set(maAccessibleContext, UNO_QUERY); + maAccessibleContext.clear(); + } + if( xPeer.is() ) + { + xPeer->dispose(); + } + + // dispose our AccessibleContext - without Mutex locked + DisposeAccessibleContext(xAccessibleComp); + + EventObject aDisposeEvent; + aDisposeEvent.Source = static_cast< XAggregation* >( this ); + + maDisposeListeners.disposeAndClear( aDisposeEvent ); + maWindowListeners.disposeAndClear( aDisposeEvent ); + maFocusListeners.disposeAndClear( aDisposeEvent ); + maKeyListeners.disposeAndClear( aDisposeEvent ); + maMouseListeners.disposeAndClear( aDisposeEvent ); + maMouseMotionListeners.disposeAndClear( aDisposeEvent ); + maPaintListeners.disposeAndClear( aDisposeEvent ); + maModeChangeListeners.disposeAndClear( aDisposeEvent ); + + // release Model again + setModel( Reference< XControlModel > () ); + setContext( Reference< XInterface > () ); +} + +void UnoControl::addEventListener( const Reference< XEventListener >& rxListener ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + + maDisposeListeners.addInterface( rxListener ); +} + +void UnoControl::removeEventListener( const Reference< XEventListener >& rxListener ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + + maDisposeListeners.removeInterface( rxListener ); +} + +bool UnoControl::requiresNewPeer( const OUString& /* _rPropertyName */ ) const +{ + return false; +} + +// XPropertiesChangeListener +void UnoControl::propertiesChange( const Sequence< PropertyChangeEvent >& rEvents ) +{ + Sequence< PropertyChangeEvent > aEvents( rEvents ); + { + ::osl::MutexGuard aGuard( GetMutex() ); + + if ( !mpData->aSuspendedPropertyNotifications.empty() ) + { + // strip the property which we are currently updating (somewhere up the stack) + PropertyChangeEvent* pEvents = aEvents.getArray(); + PropertyChangeEvent* pEventsEnd = pEvents + aEvents.getLength(); + for ( ; pEvents < pEventsEnd; ) + if ( mpData->aSuspendedPropertyNotifications.find( pEvents->PropertyName ) != mpData->aSuspendedPropertyNotifications.end() ) + { + std::copy(pEvents + 1, pEventsEnd, pEvents); + --pEventsEnd; + } + else + ++pEvents; + aEvents.realloc( pEventsEnd - aEvents.getConstArray() ); + + if ( !aEvents.hasElements() ) + return; + } + } + + ImplModelPropertiesChanged( aEvents ); +} + +void UnoControl::ImplLockPropertyChangeNotification( const OUString& rPropertyName, bool bLock ) +{ + MapString2Int::iterator pos = mpData->aSuspendedPropertyNotifications.find( rPropertyName ); + if ( bLock ) + { + if ( pos == mpData->aSuspendedPropertyNotifications.end() ) + pos = mpData->aSuspendedPropertyNotifications.emplace( rPropertyName, 0 ).first; + ++pos->second; + } + else + { + OSL_ENSURE( pos != mpData->aSuspendedPropertyNotifications.end(), "UnoControl::ImplLockPropertyChangeNotification: property not locked!" ); + if ( pos != mpData->aSuspendedPropertyNotifications.end() ) + { + OSL_ENSURE( pos->second > 0, "UnoControl::ImplLockPropertyChangeNotification: invalid suspension counter!" ); + if ( 0 == --pos->second ) + mpData->aSuspendedPropertyNotifications.erase( pos ); + } + } +} + +void UnoControl::ImplLockPropertyChangeNotifications( const Sequence< OUString >& rPropertyNames, bool bLock ) +{ + for ( auto const & propertyName : rPropertyNames ) + ImplLockPropertyChangeNotification( propertyName, bLock ); +} + +void UnoControl::ImplModelPropertiesChanged( const Sequence< PropertyChangeEvent >& rEvents ) +{ + ::osl::ClearableGuard< ::osl::Mutex > aGuard( GetMutex() ); + + if( !getPeer().is() ) + return; + + std::vector< PropertyValue > aPeerPropertiesToSet; + sal_Int32 nIndependentPos = 0; + bool bResourceResolverSet( false ); + // position where to insert the independent properties into aPeerPropertiesToSet, + // dependent ones are inserted at the end of the vector + + bool bNeedNewPeer = false; + // some properties require a re-creation of the peer, 'cause they can't be changed on the fly + + Reference< XControlModel > xOwnModel = getModel(); + // our own model for comparison + Reference< XPropertySet > xPS( xOwnModel, UNO_QUERY ); + Reference< XPropertySetInfo > xPSI = xPS->getPropertySetInfo(); + OSL_ENSURE( xPSI.is(), "UnoControl::ImplModelPropertiesChanged: should have property set meta data!" ); + + sal_Int32 nLen = rEvents.getLength(); + aPeerPropertiesToSet.reserve(nLen); + + for( const PropertyChangeEvent& rEvent : rEvents ) + { + Reference< XControlModel > xModel( rEvent.Source, UNO_QUERY ); + bool bOwnModel = xModel.get() == xOwnModel.get(); + if ( !bOwnModel ) + continue; + + // Detect changes on our resource resolver which invalidates + // automatically some language dependent properties. + if ( rEvent.PropertyName == "ResourceResolver" ) + { + Reference< resource::XStringResourceResolver > xStrResolver; + if ( rEvent.NewValue >>= xStrResolver ) + bResourceResolverSet = xStrResolver.is(); + } + + sal_uInt16 nPType = GetPropertyId( rEvent.PropertyName ); + if ( mbDesignMode && mbDisposePeer && !mbRefreshingPeer && !mbCreatingPeer ) + { + // if we're in design mode, then some properties can change which + // require creating a *new* peer (since these properties cannot + // be switched at existing peers) + if ( nPType ) + bNeedNewPeer = ( nPType == BASEPROPERTY_BORDER ) + || ( nPType == BASEPROPERTY_MULTILINE ) + || ( nPType == BASEPROPERTY_DROPDOWN ) + || ( nPType == BASEPROPERTY_HSCROLL ) + || ( nPType == BASEPROPERTY_VSCROLL ) + || ( nPType == BASEPROPERTY_AUTOHSCROLL ) + || ( nPType == BASEPROPERTY_AUTOVSCROLL ) + || ( nPType == BASEPROPERTY_ORIENTATION ) + || ( nPType == BASEPROPERTY_SPIN ) + || ( nPType == BASEPROPERTY_ALIGN ) + || ( nPType == BASEPROPERTY_PAINTTRANSPARENT ); + else + bNeedNewPeer = requiresNewPeer( rEvent.PropertyName ); + + if ( bNeedNewPeer ) + break; + } + + if ( nPType && ( nLen > 1 ) && DoesDependOnOthers( nPType ) ) + { + // Add properties with dependencies on other properties last + // since they're dependent on properties added later (such as + // VALUE dependency on VALUEMIN/MAX) + aPeerPropertiesToSet.emplace_back(rEvent.PropertyName, 0, rEvent.NewValue, PropertyState_DIRECT_VALUE); + } + else + { + if ( bResourceResolverSet ) + { + // The resource resolver property change should be one of the first ones. + // All language dependent properties are dependent on this property. + // As BASEPROPERTY_NATIVE_WIDGET_LOOK is not dependent on resource + // resolver. We don't need to handle a special order for these two props. + aPeerPropertiesToSet.insert( + aPeerPropertiesToSet.begin(), + PropertyValue( rEvent.PropertyName, 0, rEvent.NewValue, PropertyState_DIRECT_VALUE ) ); + ++nIndependentPos; + } + else if ( nPType == BASEPROPERTY_NATIVE_WIDGET_LOOK ) + { + // since *a lot* of other properties might be overruled by this one, we need + // a special handling: + // NativeWidgetLook needs to be set first: If it is set to ON, all other + // properties describing the look (e.g. BackgroundColor) are ignored, anyway. + // If it is switched OFF, then we need to do it first because else it will + // overrule other look-related properties, and re-initialize them from system + // defaults. + aPeerPropertiesToSet.insert( + aPeerPropertiesToSet.begin(), + PropertyValue( rEvent.PropertyName, 0, rEvent.NewValue, PropertyState_DIRECT_VALUE ) ); + ++nIndependentPos; + } + else + { + aPeerPropertiesToSet.insert(aPeerPropertiesToSet.begin() + nIndependentPos, + PropertyValue(rEvent.PropertyName, 0, rEvent.NewValue, PropertyState_DIRECT_VALUE)); + ++nIndependentPos; + } + } + } + + Reference< XWindow > xParent = getParentPeer(); + Reference< XControl > xThis(this); + // call createPeer via an interface got from queryInterface, so the aggregating class can intercept it + + DBG_ASSERT( !bNeedNewPeer || xParent.is(), "Need new peer, but don't have a parent!" ); + + // Check if we have to update language dependent properties + if ( !bNeedNewPeer && bResourceResolverSet ) + { + // Add language dependent properties into the peer property set. + // Our resource resolver has been changed and we must be sure + // that language dependent props use the new resolver. + const LanguageDependentProp* pLangDepProp = aLanguageDependentProp; + while ( pLangDepProp->pPropName != nullptr ) + { + bool bMustBeInserted( true ); + for (const PropertyValue & i : aPeerPropertiesToSet) + { + if ( i.Name.equalsAsciiL( + pLangDepProp->pPropName, pLangDepProp->nPropNameLength )) + { + bMustBeInserted = false; + break; + } + } + + if ( bMustBeInserted ) + { + // Add language dependent props at the end + OUString aPropName( OUString::createFromAscii( pLangDepProp->pPropName )); + if ( xPSI.is() && xPSI->hasPropertyByName( aPropName ) ) + { + aPeerPropertiesToSet.emplace_back( aPropName, 0, xPS->getPropertyValue( aPropName ), PropertyState_DIRECT_VALUE ); + } + } + + ++pLangDepProp; + } + } + aGuard.clear(); + + // clear the guard before creating a new peer - as usual, our peer implementations use the SolarMutex + + if (bNeedNewPeer && xParent.is()) + { + SolarMutexGuard aVclGuard; + // and now this is the final withdrawal: + // I have no other idea than locking the SolarMutex here... + // I really hate the fact that VCL is not threadsafe... + + // Doesn't work for Container! + getPeer()->dispose(); + mxPeer.clear(); + mxVclWindowPeer = nullptr; + mbRefreshingPeer = true; + Reference< XWindowPeer > xP( xParent, UNO_QUERY ); + xThis->createPeer( Reference< XToolkit > (), xP ); + mbRefreshingPeer = false; + aPeerPropertiesToSet.clear(); + } + + // lock the multiplexing of VCL events to our UNO listeners + // this is for compatibility reasons: in OOo 1.0.x, changes which were done at the + // model did not cause the listeners of the controls/peers to be called + // Since the implementations for the listeners changed a lot towards 1.1, this + // would not be the case anymore, if we would not do this listener-lock below + // #i14703# + VCLXWindow* pPeer; + { + SolarMutexGuard g; + VclPtr<vcl::Window> pVclPeer = VCLUnoHelper::GetWindow( getPeer() ); + pPeer = pVclPeer ? pVclPeer->GetWindowPeer() : nullptr; + } + VclListenerLock aNoVclEventMultiplexing( pPeer ); + + // setting peer properties may result in an attempt to acquire the solar mutex, 'cause the peers + // usually don't have an own mutex but use the SolarMutex instead. + // To prevent deadlocks resulting from this, we do this without our own mutex locked + for (const auto& rProp : aPeerPropertiesToSet) + { + ImplSetPeerProperty( rProp.Name, rProp.Value ); + } + +} + +void UnoControl::disposing( const EventObject& rEvt ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // do not compare differing types in case of multiple inheritance + + if ( maAccessibleContext.get() == rEvt.Source ) + { + // just in case the context is disposed, but not released - ensure that we do not re-use it in the future + maAccessibleContext.clear(); + } + else if( mxModel.get() == Reference< XControlModel >(rEvt.Source,UNO_QUERY).get() ) + { + // #62337# if the model dies, it does not make sense for us to live ... + Reference< XControl > xThis = this; + + aGuard.clear(); + xThis->dispose(); + + DBG_ASSERT( !mxModel.is(), "UnoControl::disposing: invalid dispose behaviour!" ); + mxModel.clear(); + } +} + + +void SAL_CALL UnoControl::setOutputSize( const awt::Size& aSize ) +{ + Reference< XWindow2 > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + } + + if ( xPeerWindow.is() ) + xPeerWindow->setOutputSize( aSize ); +} + +namespace +{ + template < typename RETVALTYPE, typename DEFAULTTYPE > + RETVALTYPE lcl_askPeer( const uno::Reference< awt::XWindowPeer >& _rxPeer, RETVALTYPE (SAL_CALL XWindow2::*_pMethod)(), DEFAULTTYPE _aDefault ) + { + RETVALTYPE aReturn( _aDefault ); + + Reference< XWindow2 > xPeerWindow( _rxPeer, UNO_QUERY ); + if ( xPeerWindow.is() ) + aReturn = (xPeerWindow.get()->*_pMethod)(); + + return aReturn; + } +} + +awt::Size SAL_CALL UnoControl::getOutputSize( ) +{ + return lcl_askPeer( getPeer(), &XWindow2::getOutputSize, awt::Size() ); +} + +sal_Bool SAL_CALL UnoControl::isVisible( ) +{ + return lcl_askPeer( getPeer(), &XWindow2::isVisible, maComponentInfos.bVisible ); +} + +sal_Bool SAL_CALL UnoControl::isActive( ) +{ + return lcl_askPeer( getPeer(), &XWindow2::isActive, false ); +} + +sal_Bool SAL_CALL UnoControl::isEnabled( ) +{ + return lcl_askPeer( getPeer(), &XWindow2::isEnabled, maComponentInfos.bEnable ); +} + +sal_Bool SAL_CALL UnoControl::hasFocus( ) +{ + return lcl_askPeer( getPeer(), &XWindow2::hasFocus, false ); +} + +// XWindow +void UnoControl::setPosSize( sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, sal_Int16 Flags ) +{ + Reference< XWindow > xWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + + if ( Flags & awt::PosSize::X ) + maComponentInfos.nX = X; + if ( Flags & awt::PosSize::Y ) + maComponentInfos.nY = Y; + if ( Flags & awt::PosSize::WIDTH ) + maComponentInfos.nWidth = Width; + if ( Flags & awt::PosSize::HEIGHT ) + maComponentInfos.nHeight = Height; + maComponentInfos.nFlags |= Flags; + + xWindow.set(getPeer(), css::uno::UNO_QUERY); + } + + if( xWindow.is() ) + xWindow->setPosSize( X, Y, Width, Height, Flags ); +} + +awt::Rectangle UnoControl::getPosSize( ) +{ + awt::Rectangle aRect( maComponentInfos.nX, maComponentInfos.nY, maComponentInfos.nWidth, maComponentInfos.nHeight); + Reference< XWindow > xWindow; + + { + ::osl::MutexGuard aGuard( GetMutex() ); + xWindow.set(getPeer(), css::uno::UNO_QUERY); + } + + if( xWindow.is() ) + aRect = xWindow->getPosSize(); + return aRect; +} + +void UnoControl::setVisible( sal_Bool bVisible ) +{ + Reference< XWindow > xWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + + // Visible status is handled by View + maComponentInfos.bVisible = bVisible; + xWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xWindow.is() ) + xWindow->setVisible( bVisible ); +} + +void UnoControl::setEnable( sal_Bool bEnable ) +{ + Reference< XWindow > xWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + + // Enable status is handled by View + maComponentInfos.bEnable = bEnable; + xWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xWindow.is() ) + xWindow->setEnable( bEnable ); +} + +void UnoControl::setFocus( ) +{ + Reference< XWindow > xWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + xWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xWindow.is() ) + xWindow->setFocus(); +} + +void UnoControl::addWindowListener( const Reference< XWindowListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + maWindowListeners.addInterface( rxListener ); + if ( maWindowListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerWindow.is() ) + xPeerWindow->addWindowListener( &maWindowListeners ); +} + +void UnoControl::removeWindowListener( const Reference< XWindowListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + if ( maWindowListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + maWindowListeners.removeInterface( rxListener ); + } + if ( xPeerWindow.is() ) + xPeerWindow->removeWindowListener( &maWindowListeners ); +} + +void UnoControl::addFocusListener( const Reference< XFocusListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + maFocusListeners.addInterface( rxListener ); + if ( maFocusListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerWindow.is() ) + xPeerWindow->addFocusListener( &maFocusListeners ); +} + +void UnoControl::removeFocusListener( const Reference< XFocusListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + if ( maFocusListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + maFocusListeners.removeInterface( rxListener ); + } + if ( xPeerWindow.is() ) + xPeerWindow->removeFocusListener( &maFocusListeners ); +} + +void UnoControl::addKeyListener( const Reference< XKeyListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + maKeyListeners.addInterface( rxListener ); + if ( maKeyListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerWindow.is() ) + xPeerWindow->addKeyListener( &maKeyListeners); +} + +void UnoControl::removeKeyListener( const Reference< XKeyListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + if ( maKeyListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + maKeyListeners.removeInterface( rxListener ); + } + if ( xPeerWindow.is() ) + xPeerWindow->removeKeyListener( &maKeyListeners); +} + +void UnoControl::addMouseListener( const Reference< XMouseListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + maMouseListeners.addInterface( rxListener ); + if ( maMouseListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerWindow.is() ) + xPeerWindow->addMouseListener( &maMouseListeners); +} + +void UnoControl::removeMouseListener( const Reference< XMouseListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + if ( maMouseListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + maMouseListeners.removeInterface( rxListener ); + } + if ( xPeerWindow.is() ) + xPeerWindow->removeMouseListener( &maMouseListeners ); +} + +void UnoControl::addMouseMotionListener( const Reference< XMouseMotionListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + maMouseMotionListeners.addInterface( rxListener ); + if ( maMouseMotionListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerWindow.is() ) + xPeerWindow->addMouseMotionListener( &maMouseMotionListeners); +} + +void UnoControl::removeMouseMotionListener( const Reference< XMouseMotionListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + if ( maMouseMotionListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + maMouseMotionListeners.removeInterface( rxListener ); + } + if ( xPeerWindow.is() ) + xPeerWindow->removeMouseMotionListener( &maMouseMotionListeners ); +} + +void UnoControl::addPaintListener( const Reference< XPaintListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + maPaintListeners.addInterface( rxListener ); + if ( maPaintListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerWindow.is() ) + xPeerWindow->addPaintListener( &maPaintListeners); +} + +void UnoControl::removePaintListener( const Reference< XPaintListener >& rxListener ) +{ + Reference< XWindow > xPeerWindow; + { + ::osl::MutexGuard aGuard( GetMutex() ); + if ( maPaintListeners.getLength() == 1 ) + xPeerWindow.set(getPeer(), css::uno::UNO_QUERY); + maPaintListeners.removeInterface( rxListener ); + } + if ( xPeerWindow.is() ) + xPeerWindow->removePaintListener( &maPaintListeners ); +} + +// XView +sal_Bool UnoControl::setGraphics( const Reference< XGraphics >& rDevice ) +{ + Reference< XView > xView; + { + ::osl::MutexGuard aGuard( GetMutex() ); + + mxGraphics = rDevice; + xView.set(getPeer(), css::uno::UNO_QUERY); + } + return !xView.is() || xView->setGraphics( rDevice ); +} + +Reference< XGraphics > UnoControl::getGraphics( ) +{ + return mxGraphics; +} + +awt::Size UnoControl::getSize( ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + return awt::Size( maComponentInfos.nWidth, maComponentInfos.nHeight ); +} + +void UnoControl::draw( sal_Int32 x, sal_Int32 y ) +{ + Reference< XWindowPeer > xDrawPeer; + Reference< XView > xDrawPeerView; + + bool bDisposeDrawPeer( false ); + { + ::osl::MutexGuard aGuard( GetMutex() ); + + xDrawPeer = ImplGetCompatiblePeer(); + bDisposeDrawPeer = xDrawPeer.is() && ( xDrawPeer != getPeer() ); + + xDrawPeerView.set( xDrawPeer, UNO_QUERY ); + DBG_ASSERT( xDrawPeerView.is(), "UnoControl::draw: no peer!" ); + } + + if ( xDrawPeerView.is() ) + { + Reference< XVclWindowPeer > xWindowPeer; + xWindowPeer.set( xDrawPeer, UNO_QUERY ); + if ( xWindowPeer.is() ) + xWindowPeer->setDesignMode( mbDesignMode ); + xDrawPeerView->draw( x, y ); + } + + if ( bDisposeDrawPeer ) + xDrawPeer->dispose(); +} + +void UnoControl::setZoom( float fZoomX, float fZoomY ) +{ + Reference< XView > xView; + { + ::osl::MutexGuard aGuard( GetMutex() ); + + maComponentInfos.nZoomX = fZoomX; + maComponentInfos.nZoomY = fZoomY; + + xView.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xView.is() ) + xView->setZoom( fZoomX, fZoomY ); +} + +// XControl +void UnoControl::setContext( const Reference< XInterface >& rxContext ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + + mxContext = rxContext; +} + +Reference< XInterface > UnoControl::getContext( ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + + return mxContext; +} + +void UnoControl::peerCreated() +{ + Reference< XWindow > xWindow( getPeer(), UNO_QUERY ); + if ( !xWindow.is() ) + return; + + if ( maWindowListeners.getLength() ) + xWindow->addWindowListener( &maWindowListeners ); + + if ( maFocusListeners.getLength() ) + xWindow->addFocusListener( &maFocusListeners ); + + if ( maKeyListeners.getLength() ) + xWindow->addKeyListener( &maKeyListeners ); + + if ( maMouseListeners.getLength() ) + xWindow->addMouseListener( &maMouseListeners ); + + if ( maMouseMotionListeners.getLength() ) + xWindow->addMouseMotionListener( &maMouseMotionListeners ); + + if ( maPaintListeners.getLength() ) + xWindow->addPaintListener( &maPaintListeners ); +} + +void UnoControl::createPeer( const Reference< XToolkit >& rxToolkit, const Reference< XWindowPeer >& rParentPeer ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + if ( !mxModel.is() ) + { + RuntimeException aException; + aException.Message = "createPeer: no model!"; + aException.Context = static_cast<XAggregation*>(static_cast<cppu::OWeakAggObject*>(this)); + throw aException; + } + + if( getPeer().is() ) + return; + + mbCreatingPeer = true; + + WindowClass eType; + Reference< XToolkit > xToolkit = rxToolkit; + if( rParentPeer.is() && mxContext.is() ) + { + // no TopWindow + if ( !xToolkit.is() ) + xToolkit = rParentPeer->getToolkit(); + Any aAny = OWeakAggObject::queryInterface( cppu::UnoType<XControlContainer>::get()); + Reference< XControlContainer > xC; + aAny >>= xC; + if( xC.is() ) + // It's a container + eType = WindowClass_CONTAINER; + else + eType = WindowClass_SIMPLE; + } + else + { // This is only correct for Top Window + if( rParentPeer.is() ) + { + if ( !xToolkit.is() ) + xToolkit = rParentPeer->getToolkit(); + eType = WindowClass_CONTAINER; + } + else + { + if ( !xToolkit.is() ) + xToolkit = VCLUnoHelper::CreateToolkit(); + eType = WindowClass_TOP; + } + } + WindowDescriptor aDescr; + aDescr.Type = eType; + aDescr.WindowServiceName = GetComponentServiceName(); + aDescr.Parent = rParentPeer; + aDescr.Bounds = getPosSize(); + aDescr.WindowAttributes = 0; + + // Border + Reference< XPropertySet > xPSet( mxModel, UNO_QUERY ); + Reference< XPropertySetInfo > xInfo = xPSet->getPropertySetInfo(); + + Any aVal; + OUString aPropName = GetPropertyName( BASEPROPERTY_BORDER ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + sal_Int16 n = sal_Int16(); + if ( aVal >>= n ) + { + if ( n ) + aDescr.WindowAttributes |= WindowAttribute::BORDER; + else + aDescr.WindowAttributes |= VclWindowPeerAttribute::NOBORDER; + } + } + + // DESKTOP_AS_PARENT + if ( aDescr.Type == WindowClass_TOP ) + { + aPropName = GetPropertyName( BASEPROPERTY_DESKTOP_AS_PARENT ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.ParentIndex = -1; + } + } + // Moveable + aPropName = GetPropertyName( BASEPROPERTY_MOVEABLE ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= WindowAttribute::MOVEABLE; + } + + // Sizeable + aPropName = GetPropertyName( BASEPROPERTY_SIZEABLE ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= WindowAttribute::SIZEABLE; + } + + // Closeable + aPropName = GetPropertyName( BASEPROPERTY_CLOSEABLE ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= WindowAttribute::CLOSEABLE; + } + + // Dropdown + aPropName = GetPropertyName( BASEPROPERTY_DROPDOWN ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= VclWindowPeerAttribute::DROPDOWN; + } + + // Spin + aPropName = GetPropertyName( BASEPROPERTY_SPIN ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= VclWindowPeerAttribute::SPIN; + } + + // HScroll + aPropName = GetPropertyName( BASEPROPERTY_HSCROLL ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= VclWindowPeerAttribute::HSCROLL; + } + + // VScroll + aPropName = GetPropertyName( BASEPROPERTY_VSCROLL ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= VclWindowPeerAttribute::VSCROLL; + } + + // AutoHScroll + aPropName = GetPropertyName( BASEPROPERTY_AUTOHSCROLL ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= VclWindowPeerAttribute::AUTOHSCROLL; + } + + // AutoVScroll + aPropName = GetPropertyName( BASEPROPERTY_AUTOVSCROLL ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>= b ) && b) + aDescr.WindowAttributes |= VclWindowPeerAttribute::AUTOVSCROLL; + } + + //added for issue79712 + //NoLabel + aPropName = GetPropertyName( BASEPROPERTY_NOLABEL ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + bool b = bool(); + if ( ( aVal >>=b ) && b ) + aDescr.WindowAttributes |= VclWindowPeerAttribute::NOLABEL; + } + //issue79712 ends + + // Align + aPropName = GetPropertyName( BASEPROPERTY_ALIGN ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + aVal = xPSet->getPropertyValue( aPropName ); + sal_Int16 n = sal_Int16(); + if ( aVal >>= n ) + { + if ( n == PROPERTY_ALIGN_LEFT ) + aDescr.WindowAttributes |= VclWindowPeerAttribute::LEFT; + else if ( n == PROPERTY_ALIGN_CENTER ) + aDescr.WindowAttributes |= VclWindowPeerAttribute::CENTER; + else + aDescr.WindowAttributes |= VclWindowPeerAttribute::RIGHT; + } + } + + // Allow derivates to manipulate attributes + PrepareWindowDescriptor(aDescr); + + // create the peer + setPeer( xToolkit->createWindow( aDescr ) ); + + // release the mutex guard (and work with copies of our members) + // this is necessary as our peer may lock the SolarMutex (actually, all currently known peers do), so calling + // into the peer with our own mutex locked may cause deadlocks + // (We _really_ need peers which do not use the SolarMutex. It's really pissing me off that from time to + // time deadlocks pop up because the low-level components like our peers use a mutex which usually + // is locked at the top of the stack (it protects the global message looping). This is always dangerous, and + // can not always be solved by tampering with other mutexes. + // Unfortunately, the VCL used in the peers is not threadsafe, and by definition needs a locked SolarMutex.) + // 82300 - 12/21/00 - FS + UnoControlComponentInfos aComponentInfos(maComponentInfos); + bool bDesignMode(mbDesignMode); + + Reference< XGraphics > xGraphics( mxGraphics ); + Reference< XView > xView ( getPeer(), UNO_QUERY_THROW ); + Reference< XWindow > xWindow ( getPeer(), UNO_QUERY_THROW ); + + aGuard.clear(); + + // the updateFromModel is done without a locked mutex, too. + // The reason is that the only thing this method does is firing property changes, and this in general has + // to be done without locked mutexes (as every notification to external listeners). + // 82300 - 12/21/00 - FS + updateFromModel(); + + xView->setZoom( aComponentInfos.nZoomX, aComponentInfos.nZoomY ); + + setPosSize( aComponentInfos.nX, aComponentInfos.nY, aComponentInfos.nWidth, aComponentInfos.nHeight, aComponentInfos.nFlags ); + + if( aComponentInfos.bVisible && !bDesignMode ) + // Show only after setting the data + xWindow->setVisible( aComponentInfos.bVisible ); + + if( !aComponentInfos.bEnable ) + xWindow->setEnable( aComponentInfos.bEnable ); + + xView->setGraphics( xGraphics ); + + peerCreated(); + + mbCreatingPeer = false; + +} + +Reference< XWindowPeer > UnoControl::getPeer() +{ + ::osl::MutexGuard aGuard( GetMutex() ); + return mxPeer; +} + +sal_Bool UnoControl::setModel( const Reference< XControlModel >& rxModel ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + + Reference< XMultiPropertySet > xPropSet( mxModel, UNO_QUERY ); + + // query for the XPropertiesChangeListener - our delegator is allowed to overwrite this interface + Reference< XPropertiesChangeListener > xListener; + queryInterface( cppu::UnoType<decltype(xListener)>::get() ) >>= xListener; + + if( xPropSet.is() ) + xPropSet->removePropertiesChangeListener( xListener ); + + mpData->bLocalizationSupport = false; + mxModel = rxModel; + + if( mxModel.is() ) + { + try + { + xPropSet.set( mxModel, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xPSI( xPropSet->getPropertySetInfo(), UNO_SET_THROW ); + + Sequence< OUString> aNames = lcl_ImplGetPropertyNames( xPropSet ); + xPropSet->addPropertiesChangeListener( aNames, xListener ); + + mpData->bLocalizationSupport = xPSI->hasPropertyByName("ResourceResolver"); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + mxModel.clear(); + } + } + + return mxModel.is(); +} + +Reference< XControlModel > UnoControl::getModel( ) +{ + return mxModel; +} + +Reference< XView > UnoControl::getView( ) +{ + return static_cast< XView* >( this ); +} + +void UnoControl::setDesignMode( sal_Bool bOn ) +{ + ModeChangeEvent aModeChangeEvent; + + Reference< XWindow > xWindow; + Reference<XComponent> xAccessibleComp; + { + ::osl::MutexGuard aGuard( GetMutex() ); + if ( bool(bOn) == mbDesignMode ) + return; + + // remember this + mbDesignMode = bOn; + xWindow.set(getPeer(), css::uno::UNO_QUERY); + + xAccessibleComp.set(maAccessibleContext, UNO_QUERY); + maAccessibleContext.clear(); + + aModeChangeEvent.Source = *this; + aModeChangeEvent.NewMode = mbDesignMode ? std::u16string_view(u"design") : std::u16string_view(u"alive" ); + } + + // dispose current AccessibleContext, if we have one - without Mutex lock + // (changing the design mode implies having a new implementation for this context, + // so the old one must be declared DEFUNC) + DisposeAccessibleContext(xAccessibleComp); + + // adjust the visibility of our window + if ( xWindow.is() ) + xWindow->setVisible( !bOn ); + + // and notify our mode listeners + maModeChangeListeners.notifyEach( &XModeChangeListener::modeChanged, aModeChangeEvent ); +} + +sal_Bool UnoControl::isDesignMode( ) +{ + return mbDesignMode; +} + +sal_Bool UnoControl::isTransparent( ) +{ + return false; +} + +// XServiceInfo +OUString UnoControl::getImplementationName( ) +{ + OSL_FAIL( "This method should be overridden!" ); + return OUString(); +} + +sal_Bool UnoControl::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > UnoControl::getSupportedServiceNames( ) +{ + return { "com.sun.star.awt.UnoControl" }; +} + + +Reference< XAccessibleContext > SAL_CALL UnoControl::getAccessibleContext( ) +{ + // creation of the context will certainly require the SolarMutex ... + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( GetMutex() ); + + Reference< XAccessibleContext > xCurrentContext( maAccessibleContext.get(), UNO_QUERY ); + if ( !xCurrentContext.is() ) + { + if ( !mbDesignMode ) + { // in alive mode, use the AccessibleContext of the peer + Reference< XAccessible > xPeerAcc( getPeer(), UNO_QUERY ); + if ( xPeerAcc.is() ) + xCurrentContext = xPeerAcc->getAccessibleContext( ); + } + else + // in design mode, use a fallback + xCurrentContext = ::toolkit::OAccessibleControlContext::create( this ); + + DBG_ASSERT( xCurrentContext.is(), "UnoControl::getAccessibleContext: invalid context (invalid peer?)!" ); + maAccessibleContext = xCurrentContext; + + // get notified when the context is disposed + Reference< XComponent > xContextComp( xCurrentContext, UNO_QUERY ); + if ( xContextComp.is() ) + xContextComp->addEventListener( this ); + // In an ideal world, this is not necessary - there the object would be released as soon as it has been + // disposed, and thus our weak reference would be empty, too. + // But 'til this ideal world comes (means 'til we do never have any refcount/lifetime bugs anymore), we + // need to listen for disposal and reset our weak reference then. + } + + return xCurrentContext; +} + +void SAL_CALL UnoControl::addModeChangeListener( const Reference< XModeChangeListener >& _rxListener ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + maModeChangeListeners.addInterface( _rxListener ); +} + +void SAL_CALL UnoControl::removeModeChangeListener( const Reference< XModeChangeListener >& _rxListener ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + maModeChangeListeners.removeInterface( _rxListener ); +} + +void SAL_CALL UnoControl::addModeChangeApproveListener( const Reference< XModeChangeApproveListener >& ) +{ + throw NoSupportException( ); +} + +void SAL_CALL UnoControl::removeModeChangeApproveListener( const Reference< XModeChangeApproveListener >& ) +{ + throw NoSupportException( ); +} + + +awt::Point SAL_CALL UnoControl::convertPointToLogic( const awt::Point& i_Point, ::sal_Int16 i_TargetUnit ) +{ + Reference< XUnitConversion > xPeerConversion; + { + ::osl::MutexGuard aGuard( GetMutex() ); + xPeerConversion.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerConversion.is() ) + return xPeerConversion->convertPointToLogic( i_Point, i_TargetUnit ); + return awt::Point( ); +} + + +awt::Point SAL_CALL UnoControl::convertPointToPixel( const awt::Point& i_Point, ::sal_Int16 i_SourceUnit ) +{ + Reference< XUnitConversion > xPeerConversion; + { + ::osl::MutexGuard aGuard( GetMutex() ); + xPeerConversion.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerConversion.is() ) + return xPeerConversion->convertPointToPixel( i_Point, i_SourceUnit ); + return awt::Point( ); +} + + +awt::Size SAL_CALL UnoControl::convertSizeToLogic( const awt::Size& i_Size, ::sal_Int16 i_TargetUnit ) +{ + Reference< XUnitConversion > xPeerConversion; + { + ::osl::MutexGuard aGuard( GetMutex() ); + xPeerConversion.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerConversion.is() ) + return xPeerConversion->convertSizeToLogic( i_Size, i_TargetUnit ); + return awt::Size( ); +} + + +awt::Size SAL_CALL UnoControl::convertSizeToPixel( const awt::Size& i_Size, ::sal_Int16 i_SourceUnit ) +{ + Reference< XUnitConversion > xPeerConversion; + { + ::osl::MutexGuard aGuard( GetMutex() ); + xPeerConversion.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerConversion.is() ) + return xPeerConversion->convertSizeToPixel( i_Size, i_SourceUnit ); + return awt::Size( ); +} + + +uno::Reference< awt::XStyleSettings > SAL_CALL UnoControl::getStyleSettings() +{ + Reference< awt::XStyleSettingsSupplier > xPeerSupplier; + { + ::osl::MutexGuard aGuard( GetMutex() ); + xPeerSupplier.set(getPeer(), css::uno::UNO_QUERY); + } + if ( xPeerSupplier.is() ) + return xPeerSupplier->getStyleSettings(); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/unocontrolbase.cxx b/toolkit/source/controls/unocontrolbase.cxx new file mode 100644 index 000000000..69cfbac5d --- /dev/null +++ b/toolkit/source/controls/unocontrolbase.cxx @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/awt/XLayoutConstrains.hpp> +#include <com/sun/star/awt/XTextLayoutConstrains.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> + +#include <toolkit/controls/unocontrolbase.hxx> +#include <toolkit/helper/property.hxx> + +#include <tools/debug.hxx> + +using namespace com::sun::star; + + + + +bool UnoControlBase::ImplHasProperty( sal_uInt16 nPropId ) +{ + const OUString& aPropName( GetPropertyName( nPropId ) ); + return ImplHasProperty( aPropName ); +} + +bool UnoControlBase::ImplHasProperty( const OUString& aPropertyName ) +{ + css::uno::Reference< css::beans::XPropertySet > xPSet( mxModel, css::uno::UNO_QUERY ); + if ( !xPSet.is() ) + return false; + css::uno::Reference< css::beans::XPropertySetInfo > xInfo = xPSet->getPropertySetInfo(); + if ( !xInfo.is() ) + return false; + + return xInfo->hasPropertyByName( aPropertyName ); +} + +void UnoControlBase::ImplSetPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues, bool bUpdateThis ) +{ + css::uno::Reference< css::beans::XMultiPropertySet > xMPS( mxModel, css::uno::UNO_QUERY ); + if ( !mxModel.is() ) + return; + + DBG_ASSERT( xMPS.is(), "UnoControlBase::ImplSetPropertyValues: no multi property set interface!" ); + if ( !xMPS.is() ) + return; + + if ( !bUpdateThis ) + ImplLockPropertyChangeNotifications( aPropertyNames, true ); + + try + { + xMPS->setPropertyValues( aPropertyNames, aValues ); + } + catch( const css::uno::Exception& ) + { + if ( !bUpdateThis ) + ImplLockPropertyChangeNotifications( aPropertyNames, false ); + } + if ( !bUpdateThis ) + ImplLockPropertyChangeNotifications( aPropertyNames, false ); +} + +void UnoControlBase::ImplSetPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue, bool bUpdateThis ) +{ + // Model might be logged off already but an event still fires + if ( !mxModel.is() ) + return; + + css::uno::Reference< css::beans::XPropertySet > xPSet( mxModel, css::uno::UNO_QUERY ); + if ( !bUpdateThis ) + ImplLockPropertyChangeNotification( aPropertyName, true ); + + try + { + xPSet->setPropertyValue( aPropertyName, aValue ); + } + catch( const css::uno::Exception& ) + { + if ( !bUpdateThis ) + ImplLockPropertyChangeNotification( aPropertyName, false ); + throw; + } + if ( !bUpdateThis ) + ImplLockPropertyChangeNotification( aPropertyName, false ); +} + +css::uno::Any UnoControlBase::ImplGetPropertyValue( const OUString& aPropertyName ) const +{ + css::uno::Reference< css::beans::XPropertySet > xPSet( mxModel, css::uno::UNO_QUERY ); + if ( xPSet.is() ) + return xPSet->getPropertyValue( aPropertyName ); + else + return css::uno::Any(); +} + +template <typename T> T UnoControlBase::ImplGetPropertyValuePOD( sal_uInt16 nProp ) +{ + T t(0); + if ( mxModel.is() ) + { + css::uno::Any aVal = ImplGetPropertyValue( GetPropertyName( nProp ) ); + aVal >>= t; + } + return t; +} + +template <typename T> T UnoControlBase::ImplGetPropertyValueClass( sal_uInt16 nProp ) +{ + T t; + if ( mxModel.is() ) + { + css::uno::Any aVal = ImplGetPropertyValue( GetPropertyName( nProp ) ); + aVal >>= t; + } + return t; +} + +bool UnoControlBase::ImplGetPropertyValue_BOOL( sal_uInt16 nProp ) +{ + return ImplGetPropertyValuePOD<bool>(nProp); +} + +sal_Int16 UnoControlBase::ImplGetPropertyValue_INT16( sal_uInt16 nProp ) +{ + return ImplGetPropertyValuePOD<sal_Int16>(nProp); +} + +sal_Int32 UnoControlBase::ImplGetPropertyValue_INT32( sal_uInt16 nProp ) +{ + return ImplGetPropertyValuePOD<sal_Int32>(nProp); +} + +double UnoControlBase::ImplGetPropertyValue_DOUBLE( sal_uInt16 nProp ) +{ + return ImplGetPropertyValuePOD<double>(nProp); +} + +OUString UnoControlBase::ImplGetPropertyValue_UString( sal_uInt16 nProp ) +{ + return ImplGetPropertyValueClass<OUString>(nProp); +} + +util::Date UnoControlBase::ImplGetPropertyValue_Date( sal_uInt16 nProp ) +{ + return ImplGetPropertyValueClass<util::Date>(nProp); +} + +util::Time UnoControlBase::ImplGetPropertyValue_Time( sal_uInt16 nProp ) +{ + return ImplGetPropertyValueClass<util::Time>(nProp); +} + +css::awt::Size UnoControlBase::Impl_getMinimumSize() +{ + css::awt::Size aSz; + css::uno::Reference< css::awt::XWindowPeer > xP = ImplGetCompatiblePeer(); + DBG_ASSERT( xP.is(), "Layout: No Peer!" ); + if ( xP.is() ) + { + css::uno::Reference< css::awt::XLayoutConstrains > xL( xP, css::uno::UNO_QUERY ); + if ( xL.is() ) + aSz = xL->getMinimumSize(); + + if ( !getPeer().is() || ( getPeer() != xP ) ) + xP->dispose(); + } + return aSz; +} + +css::awt::Size UnoControlBase::Impl_getPreferredSize() +{ + css::awt::Size aSz; + css::uno::Reference< css::awt::XWindowPeer > xP = ImplGetCompatiblePeer(); + DBG_ASSERT( xP.is(), "Layout: No Peer!" ); + if ( xP.is() ) + { + css::uno::Reference< css::awt::XLayoutConstrains > xL( xP, css::uno::UNO_QUERY ); + if ( xL.is() ) + aSz = xL->getPreferredSize(); + + if ( !getPeer().is() || ( getPeer() != xP ) ) + xP->dispose(); + } + return aSz; +} + +css::awt::Size UnoControlBase::Impl_calcAdjustedSize( const css::awt::Size& rNewSize ) +{ + css::awt::Size aSz; + css::uno::Reference< css::awt::XWindowPeer > xP = ImplGetCompatiblePeer(); + DBG_ASSERT( xP.is(), "Layout: No Peer!" ); + if ( xP.is() ) + { + css::uno::Reference< css::awt::XLayoutConstrains > xL( xP, css::uno::UNO_QUERY ); + if ( xL.is() ) + aSz = xL->calcAdjustedSize( rNewSize ); + + if ( !getPeer().is() || ( getPeer() != xP ) ) + xP->dispose(); + } + return aSz; +} + +css::awt::Size UnoControlBase::Impl_getMinimumSize( sal_Int16 nCols, sal_Int16 nLines ) +{ + css::awt::Size aSz; + css::uno::Reference< css::awt::XWindowPeer > xP = ImplGetCompatiblePeer(); + DBG_ASSERT( xP.is(), "Layout: No Peer!" ); + if ( xP.is() ) + { + css::uno::Reference< css::awt::XTextLayoutConstrains > xL( xP, css::uno::UNO_QUERY ); + if ( xL.is() ) + aSz = xL->getMinimumSize( nCols, nLines ); + + if ( !getPeer().is() || ( getPeer() != xP ) ) + xP->dispose(); + } + return aSz; +} + +void UnoControlBase::Impl_getColumnsAndLines( sal_Int16& nCols, sal_Int16& nLines ) +{ + css::uno::Reference< css::awt::XWindowPeer > xP = ImplGetCompatiblePeer(); + DBG_ASSERT( xP.is(), "Layout: No Peer!" ); + if ( xP.is() ) + { + css::uno::Reference< css::awt::XTextLayoutConstrains > xL( xP, css::uno::UNO_QUERY ); + if ( xL.is() ) + xL->getColumnsAndLines( nCols, nLines ); + + if ( !getPeer().is() || ( getPeer() != xP ) ) + xP->dispose(); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/unocontrolcontainer.cxx b/toolkit/source/controls/unocontrolcontainer.cxx new file mode 100644 index 000000000..806ec4863 --- /dev/null +++ b/toolkit/source/controls/unocontrolcontainer.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 <com/sun/star/awt/XVclContainerPeer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <cppuhelper/implbase.hxx> + +#include <controls/unocontrolcontainer.hxx> +#include <comphelper/sequence.hxx> + +#include <tools/debug.hxx> + +#include <limits> +#include <map> +#include <memory> +#include <com/sun/star/awt/VclWindowPeerAttribute.hpp> + +using namespace ::com::sun::star; + + + +namespace { + +struct UnoControlHolder +{ + uno::Reference< awt::XControl > mxControl; + OUString msName; + +public: + UnoControlHolder( const OUString& rName, const uno::Reference< awt::XControl > & rControl ) + : mxControl( rControl ), + msName( rName ) + { + } + + const OUString& getName() const { return msName; } + const uno::Reference< awt::XControl >& getControl() const { return mxControl; } +}; + +} + +class UnoControlHolderList +{ +public: + typedef sal_Int32 ControlIdentifier; +private: + typedef std::shared_ptr< UnoControlHolder > ControlInfo; + typedef ::std::map< ControlIdentifier, ControlInfo > ControlMap; + +private: + ControlMap maControls; + +public: + UnoControlHolderList(); + + /** adds a control with the given name to the list + @param _rxControl + the control to add. Must not be <NULL/> + @param _pBName + the name of the control, or <NULL/> if an automatic name should be generated + @return + the identifier of the newly added control + */ + ControlIdentifier addControl( const uno::Reference< awt::XControl >& _rxControl, const OUString* _pName ); + + /** determines whether or not the list is empty + */ + bool empty() const { return maControls.empty(); } + + /** retrieves all controls currently in the list + */ + void getControls( uno::Sequence< uno::Reference< awt::XControl > >& _out_rControls ) const; + + /** retrieves all identifiers of all controls currently in the list + */ + void getIdentifiers( uno::Sequence< sal_Int32 >& _out_rIdentifiers ) const; + + /** returns the first control which is registered under the given name + */ + uno::Reference< awt::XControl > + getControlForName( const OUString& _rName ) const; + + /** returns the identifier which a control is registered for, or -1 if the control + isn't registered + */ + ControlIdentifier + getControlIdentifier( const uno::Reference< awt::XControl >& _rxControl ); + + /** retrieves the control for a given id + @param _nIdentifier + the identifier for the control + @param _out_rxControl + takes the XControl upon successful return + @return + <TRUE/> if and only if a control with the given id is part of the list + */ + bool getControlForIdentifier( ControlIdentifier _nIdentifier, uno::Reference< awt::XControl >& _out_rxControl ) const; + + /** removes a control from the list, given by id + @param _nId + The identifier of the control to remove. + */ + void removeControlById( ControlIdentifier _nId ); + + /** replaces a control from the list with another one + @param _nId + The identifier of the control to replace + @param _rxNewControl + the new control to put into the list + */ + void replaceControlById( ControlIdentifier _nId, const uno::Reference< awt::XControl >& _rxNewControl ); + +private: + /** adds a control + @param _rxControl + the control to add to the container + @param _pName + pointer to the name of the control. Might be <NULL/>, in this case, a name is generated. + @return + the identifier of the newly inserted control + */ + ControlIdentifier impl_addControl( + const uno::Reference< awt::XControl >& _rxControl, + const OUString* _pName + ); + + /** finds a free identifier + @throw uno::RuntimeException + if no free identifier can be found + */ + ControlIdentifier impl_getFreeIdentifier_throw(); + + /** finds a free name + @throw uno::RuntimeException + if no free name can be found + */ + OUString impl_getFreeName_throw(); +}; + + +UnoControlHolderList::UnoControlHolderList() +{ +} + + +UnoControlHolderList::ControlIdentifier UnoControlHolderList::addControl( const uno::Reference< awt::XControl >& _rxControl, const OUString* _pName ) +{ + return impl_addControl( _rxControl, _pName ); +} + + +void UnoControlHolderList::getControls( uno::Sequence< uno::Reference< awt::XControl > >& _out_rControls ) const +{ + _out_rControls.realloc( maControls.size() ); + uno::Reference< awt::XControl >* pControls = _out_rControls.getArray(); + for (const auto& rEntry : maControls) + { + *pControls = rEntry.second->getControl(); + ++pControls; + } +} + + +void UnoControlHolderList::getIdentifiers( uno::Sequence< sal_Int32 >& _out_rIdentifiers ) const +{ + _out_rIdentifiers.realloc( maControls.size() ); + sal_Int32* pIdentifiers = _out_rIdentifiers.getArray(); + for (const auto& rEntry : maControls) + { + *pIdentifiers = rEntry.first; + ++pIdentifiers; + } +} + + +uno::Reference< awt::XControl > UnoControlHolderList::getControlForName( const OUString& _rName ) const +{ + auto loop = std::find_if(maControls.begin(), maControls.end(), + [&_rName](const ControlMap::value_type& rEntry) { return rEntry.second->getName() == _rName; }); + if (loop != maControls.end()) + return loop->second->getControl(); + return uno::Reference< awt::XControl >(); +} + + +UnoControlHolderList::ControlIdentifier UnoControlHolderList::getControlIdentifier( const uno::Reference< awt::XControl >& _rxControl ) +{ + auto loop = std::find_if(maControls.begin(), maControls.end(), + [&_rxControl](const ControlMap::value_type& rEntry) { return rEntry.second->getControl().get() == _rxControl.get(); }); + if (loop != maControls.end()) + return loop->first; + return -1; +} + + +bool UnoControlHolderList::getControlForIdentifier( UnoControlHolderList::ControlIdentifier _nIdentifier, uno::Reference< awt::XControl >& _out_rxControl ) const +{ + ControlMap::const_iterator pos = maControls.find( _nIdentifier ); + if ( pos == maControls.end() ) + return false; + _out_rxControl = pos->second->getControl(); + return true; +} + + +void UnoControlHolderList::removeControlById( UnoControlHolderList::ControlIdentifier _nId ) +{ + ControlMap::iterator pos = maControls.find( _nId ); + DBG_ASSERT( pos != maControls.end(), "UnoControlHolderList::removeControlById: invalid id!" ); + if ( pos == maControls.end() ) + return; + + maControls.erase( pos ); +} + + +void UnoControlHolderList::replaceControlById( ControlIdentifier _nId, const uno::Reference< awt::XControl >& _rxNewControl ) +{ + DBG_ASSERT( _rxNewControl.is(), "UnoControlHolderList::replaceControlById: invalid new control!" ); + + ControlMap::iterator pos = maControls.find( _nId ); + DBG_ASSERT( pos != maControls.end(), "UnoControlHolderList::replaceControlById: invalid id!" ); + if ( pos == maControls.end() ) + return; + + pos->second = std::make_shared<UnoControlHolder>( pos->second->getName(), _rxNewControl ); +} + + +UnoControlHolderList::ControlIdentifier UnoControlHolderList::impl_addControl( const uno::Reference< awt::XControl >& _rxControl, const OUString* _pName ) +{ + DBG_ASSERT( _rxControl.is(), "UnoControlHolderList::impl_addControl: invalid control!" ); + + OUString sName = _pName ? *_pName : impl_getFreeName_throw(); + sal_Int32 nId = impl_getFreeIdentifier_throw(); + + maControls[ nId ] = std::make_shared<UnoControlHolder>( sName, _rxControl ); + return nId; +} + + +UnoControlHolderList::ControlIdentifier UnoControlHolderList::impl_getFreeIdentifier_throw() +{ + for ( ControlIdentifier candidateId = 0; candidateId < ::std::numeric_limits< ControlIdentifier >::max(); ++candidateId ) + { + ControlMap::const_iterator existent = maControls.find( candidateId ); + if ( existent == maControls.end() ) + return candidateId; + } + throw uno::RuntimeException("out of identifiers" ); +} + + +OUString UnoControlHolderList::impl_getFreeName_throw() +{ + for ( ControlIdentifier candidateId = 0; candidateId < ::std::numeric_limits< ControlIdentifier >::max(); ++candidateId ) + { + OUString candidateName( "control_" + OUString::number( candidateId ) ); + if ( std::none_of(maControls.begin(), maControls.end(), + [&candidateName](const ControlMap::value_type& rEntry) { return rEntry.second->getName() == candidateName; }) ) + return candidateName; + } + throw uno::RuntimeException("out of identifiers" ); +} + +// Function to set the controls' visibility according +// to the dialog's "Step" property + +static void implUpdateVisibility +( + sal_Int32 nDialogStep, + const uno::Reference< awt::XControlContainer >& xControlContainer +) +{ + const uno::Sequence< uno::Reference< awt::XControl > > + aCtrls = xControlContainer->getControls(); + bool bCompleteVisible = (nDialogStep == 0); + for( const uno::Reference< awt::XControl >& xControl : aCtrls ) + { + bool bVisible = bCompleteVisible; + if( !bVisible ) + { + uno::Reference< awt::XControlModel > xModel( xControl->getModel() ); + uno::Reference< beans::XPropertySet > xPSet + ( xModel, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySetInfo > + xInfo = xPSet->getPropertySetInfo(); + OUString aPropName( "Step" ); + sal_Int32 nControlStep = 0; + if ( xInfo->hasPropertyByName( aPropName ) ) + { + uno::Any aVal = xPSet->getPropertyValue( aPropName ); + aVal >>= nControlStep; + } + bVisible = (nControlStep == 0) || (nControlStep == nDialogStep); + } + + uno::Reference< awt::XWindow> xWindow + ( xControl, uno::UNO_QUERY ); + if( xWindow.is() ) + xWindow->setVisible( bVisible ); + } +} + + + +typedef ::cppu::WeakImplHelper< beans::XPropertyChangeListener > PropertyChangeListenerHelper; + +namespace { + +class DialogStepChangedListener: public PropertyChangeListenerHelper +{ +private: + uno::Reference< awt::XControlContainer > mxControlContainer; + +public: + explicit DialogStepChangedListener( uno::Reference< awt::XControlContainer > const & xControlContainer ) + : mxControlContainer( xControlContainer ) {} + + // XEventListener + virtual void SAL_CALL disposing( const lang::EventObject& Source ) override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const beans::PropertyChangeEvent& evt ) override; + +}; + +} + +void SAL_CALL DialogStepChangedListener::disposing( const lang::EventObject& /*_rSource*/) +{ + mxControlContainer.clear(); +} + +void SAL_CALL DialogStepChangedListener::propertyChange( const beans::PropertyChangeEvent& evt ) +{ + // evt.PropertyName HAS to be "Step" because we only use the listener for that + sal_Int32 nDialogStep = 0; + evt.NewValue >>= nDialogStep; + implUpdateVisibility( nDialogStep, mxControlContainer ); +} + + + +UnoControlContainer::UnoControlContainer() + :maCListeners( *this ) +{ + mpControls.reset(new UnoControlHolderList); +} + +UnoControlContainer::UnoControlContainer(const uno::Reference< awt::XWindowPeer >& xP ) + :maCListeners( *this ) +{ + setPeer( xP ); + mbDisposePeer = false; + mpControls.reset(new UnoControlHolderList); +} + +UnoControlContainer::~UnoControlContainer() +{ +} + +void UnoControlContainer::ImplActivateTabControllers() +{ + for ( auto& rTabController : asNonConstRange(maTabControllers) ) + { + rTabController->setContainer( this ); + rTabController->activateTabOrder(); + } +} + +// lang::XComponent +void UnoControlContainer::dispose( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + lang::EventObject aDisposeEvent; + aDisposeEvent.Source = static_cast< uno::XAggregation* >( this ); + + // Notify listeners about disposal of this Container (This is much faster if they + // listen on the controls and the container). + maDisposeListeners.disposeAndClear( aDisposeEvent ); + maCListeners.disposeAndClear( aDisposeEvent ); + + + const uno::Sequence< uno::Reference< awt::XControl > > aCtrls = getControls(); + + for( uno::Reference< awt::XControl > const & control : aCtrls ) + { + removingControl( control ); + // Delete control + control->dispose(); + } + + + // Delete all structures + mpControls.reset(new UnoControlHolderList); + + UnoControlBase::dispose(); +} + +// lang::XEventListener +void UnoControlContainer::disposing( const lang::EventObject& _rEvt ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + uno::Reference< awt::XControl > xControl( _rEvt.Source, uno::UNO_QUERY ); + if ( xControl.is() ) + removeControl( xControl ); + + UnoControlBase::disposing( _rEvt ); +} + +// container::XContainer +void UnoControlContainer::addContainerListener( const uno::Reference< container::XContainerListener >& rxListener ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + maCListeners.addInterface( rxListener ); +} + +void UnoControlContainer::removeContainerListener( const uno::Reference< container::XContainerListener >& rxListener ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + maCListeners.removeInterface( rxListener ); +} + + +::sal_Int32 SAL_CALL UnoControlContainer::insert( const uno::Any& _rElement ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + uno::Reference< awt::XControl > xControl; + if ( !( _rElement >>= xControl ) || !xControl.is() ) + throw lang::IllegalArgumentException( + "Elements must support the XControl interface.", + *this, + 1 + ); + + return impl_addControl( xControl ); +} + +void SAL_CALL UnoControlContainer::removeByIdentifier( ::sal_Int32 _nIdentifier ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + uno::Reference< awt::XControl > xControl; + if ( !mpControls->getControlForIdentifier( _nIdentifier, xControl ) ) + throw container::NoSuchElementException( + "There is no element with the given identifier.", + *this + ); + + impl_removeControl( _nIdentifier, xControl ); +} + +void SAL_CALL UnoControlContainer::replaceByIdentifer( ::sal_Int32 _nIdentifier, const uno::Any& _rElement ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + uno::Reference< awt::XControl > xExistentControl; + if ( !mpControls->getControlForIdentifier( _nIdentifier, xExistentControl ) ) + throw container::NoSuchElementException( + "There is no element with the given identifier.", + *this + ); + + uno::Reference< awt::XControl > xNewControl; + if ( !( _rElement >>= xNewControl ) ) + throw lang::IllegalArgumentException( + "Elements must support the XControl interface.", + *this, + 1 + ); + + removingControl( xExistentControl ); + + mpControls->replaceControlById( _nIdentifier, xNewControl ); + + addingControl( xNewControl ); + + impl_createControlPeerIfNecessary( xNewControl ); + + if ( maCListeners.getLength() ) + { + container::ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Accessor <<= _nIdentifier; + aEvent.Element <<= xNewControl; + aEvent.ReplacedElement <<= xExistentControl; + maCListeners.elementReplaced( aEvent ); + } +} + +uno::Any SAL_CALL UnoControlContainer::getByIdentifier( ::sal_Int32 _nIdentifier ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + uno::Reference< awt::XControl > xControl; + if ( !mpControls->getControlForIdentifier( _nIdentifier, xControl ) ) + throw container::NoSuchElementException(); + return uno::Any( xControl ); +} + +uno::Sequence< ::sal_Int32 > SAL_CALL UnoControlContainer::getIdentifiers( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + uno::Sequence< ::sal_Int32 > aIdentifiers; + mpControls->getIdentifiers( aIdentifiers ); + return aIdentifiers; +} + +// container::XElementAccess +uno::Type SAL_CALL UnoControlContainer::getElementType( ) +{ + return cppu::UnoType<awt::XControlModel>::get(); +} + +sal_Bool SAL_CALL UnoControlContainer::hasElements( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + return !mpControls->empty(); +} + +// awt::XControlContainer +void UnoControlContainer::setStatusText( const OUString& rStatusText ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + // Descend the parent hierarchy + uno::Reference< awt::XControlContainer > xContainer( mxContext, uno::UNO_QUERY ); + if( xContainer.is() ) + xContainer->setStatusText( rStatusText ); +} + +uno::Sequence< uno::Reference< awt::XControl > > UnoControlContainer::getControls( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + uno::Sequence< uno::Reference< awt::XControl > > aControls; + mpControls->getControls( aControls ); + return aControls; +} + +uno::Reference< awt::XControl > UnoControlContainer::getControl( const OUString& rName ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + return mpControls->getControlForName( rName ); +} + +void UnoControlContainer::addingControl( const uno::Reference< awt::XControl >& _rxControl ) +{ + if ( _rxControl.is() ) + { + uno::Reference< uno::XInterface > xThis; + OWeakAggObject::queryInterface( cppu::UnoType<uno::XInterface>::get() ) >>= xThis; + + _rxControl->setContext( xThis ); + _rxControl->addEventListener( this ); + } +} + +void UnoControlContainer::impl_createControlPeerIfNecessary( const uno::Reference< awt::XControl >& _rxControl ) +{ + OSL_PRECOND( _rxControl.is(), "UnoControlContainer::impl_createControlPeerIfNecessary: invalid control, this will crash!" ); + + // if the container already has a peer, then also create a peer for the control + uno::Reference< awt::XWindowPeer > xMyPeer( getPeer() ); + + if( xMyPeer.is() ) + { + _rxControl->createPeer( nullptr, xMyPeer ); + ImplActivateTabControllers(); + } + +} + +sal_Int32 UnoControlContainer::impl_addControl( const uno::Reference< awt::XControl >& _rxControl, const OUString* _pName ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + UnoControlHolderList::ControlIdentifier id = mpControls->addControl( _rxControl, _pName ); + + addingControl( _rxControl ); + + impl_createControlPeerIfNecessary( _rxControl ); + + if ( maCListeners.getLength() ) + { + container::ContainerEvent aEvent; + aEvent.Source = *this; + if (_pName) + aEvent.Accessor <<= *_pName; + else + aEvent.Accessor <<= static_cast<sal_Int32>(id); + aEvent.Element <<= _rxControl; + maCListeners.elementInserted( aEvent ); + } + + return id; +} + +void UnoControlContainer::addControl( const OUString& rName, const uno::Reference< awt::XControl >& rControl ) +{ + if ( rControl.is() ) + impl_addControl( rControl, &rName ); +} + +void UnoControlContainer::removingControl( const uno::Reference< awt::XControl >& _rxControl ) +{ + if ( _rxControl.is() ) + { + _rxControl->removeEventListener( this ); + _rxControl->setContext( nullptr ); + } +} + +void UnoControlContainer::impl_removeControl( sal_Int32 _nId, const uno::Reference< awt::XControl >& _rxControl ) +{ +#ifdef DBG_UTIL + { + uno::Reference< awt::XControl > xControl; + bool bHas = mpControls->getControlForIdentifier( _nId, xControl ); + DBG_ASSERT( bHas && xControl == _rxControl, "UnoControlContainer::impl_removeControl: inconsistency in the parameters!" ); + } +#endif + removingControl( _rxControl ); + + mpControls->removeControlById( _nId ); + + if ( maCListeners.getLength() ) + { + container::ContainerEvent aEvent; + aEvent.Source = *this; + aEvent.Accessor <<= _nId; + aEvent.Element <<= _rxControl; + maCListeners.elementRemoved( aEvent ); + } +} + +void UnoControlContainer::removeControl( const uno::Reference< awt::XControl >& _rxControl ) +{ + if ( _rxControl.is() ) + { + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + UnoControlHolderList::ControlIdentifier id = mpControls->getControlIdentifier( _rxControl ); + if ( id != -1 ) + impl_removeControl( id, _rxControl ); + } +} + + +// awt::XUnoControlContainer +void UnoControlContainer::setTabControllers( const uno::Sequence< uno::Reference< awt::XTabController > >& TabControllers ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + maTabControllers = TabControllers; +} + +uno::Sequence< uno::Reference< awt::XTabController > > UnoControlContainer::getTabControllers( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + return maTabControllers; +} + +void UnoControlContainer::addTabController( const uno::Reference< awt::XTabController >& TabController ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + sal_uInt32 nCount = maTabControllers.getLength(); + maTabControllers.realloc( nCount + 1 ); + maTabControllers.getArray()[ nCount ] = TabController; +} + +void UnoControlContainer::removeTabController( const uno::Reference< awt::XTabController >& TabController ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + auto pTabController = std::find_if(std::cbegin(maTabControllers), std::cend(maTabControllers), + [&TabController](const uno::Reference< awt::XTabController >& rTabController) { + return rTabController.get() == TabController.get(); }); + if (pTabController != std::cend(maTabControllers)) + { + auto n = static_cast<sal_Int32>(std::distance(std::cbegin(maTabControllers), pTabController)); + ::comphelper::removeElementAt( maTabControllers, n ); + } +} + +// awt::XControl +void UnoControlContainer::createPeer( const uno::Reference< awt::XToolkit >& rxToolkit, const uno::Reference< awt::XWindowPeer >& rParent ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + if( getPeer().is() ) + return; + + bool bVis = maComponentInfos.bVisible; + if( bVis ) + UnoControl::setVisible( false ); + + // Create a new peer + UnoControl::createPeer( rxToolkit, rParent ); + + // Create all children's peers + if ( !mbCreatingCompatiblePeer ) + { + // Evaluate "Step" property + uno::Reference< awt::XControlModel > xModel( getModel() ); + uno::Reference< beans::XPropertySet > xPSet + ( xModel, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySetInfo > + xInfo = xPSet->getPropertySetInfo(); + OUString aPropName( "Step" ); + if ( xInfo->hasPropertyByName( aPropName ) ) + { + css::uno::Any aVal = xPSet->getPropertyValue( aPropName ); + sal_Int32 nDialogStep = 0; + aVal >>= nDialogStep; + uno::Reference< awt::XControlContainer > xContainer = + static_cast< awt::XControlContainer* >(this); + implUpdateVisibility( nDialogStep, xContainer ); + + uno::Reference< beans::XPropertyChangeListener > xListener = + new DialogStepChangedListener(xContainer); + xPSet->addPropertyChangeListener( aPropName, xListener ); + } + + uno::Sequence< uno::Reference< awt::XControl > > aCtrls = getControls(); + for( auto& rCtrl : asNonConstRange(aCtrls) ) + rCtrl->createPeer( rxToolkit, getPeer() ); + + uno::Reference< awt::XVclContainerPeer > xC( getPeer(), uno::UNO_QUERY ); + if ( xC.is() ) + xC->enableDialogControl( true ); + ImplActivateTabControllers(); + } + + if( bVis && !isDesignMode() ) + UnoControl::setVisible( true ); +} + + +// awt::XWindow +void UnoControlContainer::setVisible( sal_Bool bVisible ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + UnoControl::setVisible( bVisible ); + if( !mxContext.is() && bVisible ) + // This is a Topwindow, thus show it automatically + createPeer( uno::Reference< awt::XToolkit > (), uno::Reference< awt::XWindowPeer > () ); +} + +OUString UnoControlContainer::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlContainer"; +} + +css::uno::Sequence<OUString> UnoControlContainer::getSupportedServiceNames() +{ + auto s(UnoControlBase::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlContainer"; + ps[s.getLength() - 1] = "stardiv.vcl.control.ControlContainer"; + return s; +} + +void UnoControlContainer::PrepareWindowDescriptor( css::awt::WindowDescriptor& rDesc ) +{ + // HACK due to the fact that we can't really use VSCROLL & HSCROLL + // for Dialog ( css::awt::VclWindowPeerAttribute::VSCROLL + // has the same value as + // css::awt::WindowAttribute::NODECORATION ) + // For convenience in the PropBrowse using HSCROLL and VSCROLL ensures + // the Correct text. We exchange them here and the control knows + // about this hack ( it sucks badly I know ) + if ( rDesc.WindowAttributes & css::awt::VclWindowPeerAttribute::VSCROLL ) + { + rDesc.WindowAttributes &= ~css::awt::VclWindowPeerAttribute::VSCROLL; + rDesc.WindowAttributes |= css::awt::VclWindowPeerAttribute::AUTOVSCROLL; + } + if ( rDesc.WindowAttributes & css::awt::VclWindowPeerAttribute::HSCROLL ) + { + rDesc.WindowAttributes &= ~css::awt::VclWindowPeerAttribute::HSCROLL; + rDesc.WindowAttributes |= css::awt::VclWindowPeerAttribute::AUTOHSCROLL; + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlContainer_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlContainer()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/unocontrolcontainermodel.cxx b/toolkit/source/controls/unocontrolcontainermodel.cxx new file mode 100644 index 000000000..ffcd520a4 --- /dev/null +++ b/toolkit/source/controls/unocontrolcontainermodel.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 <com/sun/star/uno/XComponentContext.hpp> +#include <controls/unocontrolcontainermodel.hxx> +#include <toolkit/helper/property.hxx> + +#include <helper/unopropertyarrayhelper.hxx> + + +UnoControlContainerModel::UnoControlContainerModel( const css::uno::Reference< css::uno::XComponentContext >& i_factory ) + :UnoControlModel( i_factory ) +{ + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_TEXT ); +} + +OUString UnoControlContainerModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.ControlContainer"; +} + +OUString UnoControlContainerModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlContainerModel"; +} + +css::uno::Sequence<OUString> +UnoControlContainerModel::getSupportedServiceNames() +{ + auto s(UnoControlModel::getSupportedServiceNames()); + s.realloc(s.getLength() + 2); + auto ps = s.getArray(); + ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlContainerModel"; + ps[s.getLength() - 1] = "stardiv.vcl.controlmodel.ControlContainer"; + return s; +} + +css::uno::Any UnoControlContainerModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + css::uno::Any aDefault; + if ( nPropId == BASEPROPERTY_BORDER ) + aDefault <<= sal_Int16(0); + else + aDefault = UnoControlModel::ImplGetDefaultValue( nPropId ); + return aDefault; +} + + +css::uno::Reference< css::beans::XPropertySetInfo > UnoControlContainerModel::getPropertySetInfo( ) +{ + static css::uno::Reference< css::beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::cppu::IPropertyArrayHelper& UnoControlContainerModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlContainerModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlContainerModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/unocontrolmodel.cxx b/toolkit/source/controls/unocontrolmodel.cxx new file mode 100644 index 000000000..f28a0c0b4 --- /dev/null +++ b/toolkit/source/controls/unocontrolmodel.cxx @@ -0,0 +1,1388 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/beans/PropertyState.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/awt/FontWidth.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/MouseWheelBehavior.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/awt/XDevice.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/io/XMarkableStream.hpp> +#include <com/sun/star/i18n/Currency2.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <toolkit/controls/unocontrolmodel.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> +#include <tools/debug.hxx> +#include <tools/long.hxx> +#include <toolkit/helper/property.hxx> +#include <toolkit/helper/emptyfontdescriptor.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/configmgr.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/servicehelper.hxx> +#include <vcl/unohelp.hxx> + +#include <memory> +#include <o3tl/sorted_vector.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::i18n; +using ::com::sun::star::awt::FontDescriptor; + + +#define UNOCONTROL_STREAMVERSION short(2) + +static void lcl_ImplMergeFontProperty( FontDescriptor& rFD, sal_uInt16 nPropId, const Any& rValue ) +{ + // some props are defined with other types than the matching FontDescriptor members have + // (e.g. FontWidth, FontSlant) + // 78474 - 09/19/2000 - FS + float nExtractFloat = 0; + sal_Int16 nExtractShort = 0; + + switch ( nPropId ) + { + case BASEPROPERTY_FONTDESCRIPTORPART_NAME: rValue >>= rFD.Name; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_STYLENAME: rValue >>= rFD.StyleName; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_FAMILY: rValue >>= rFD.Family; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_CHARSET: rValue >>= rFD.CharSet; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_HEIGHT: rValue >>= nExtractFloat; rFD.Height = static_cast<sal_Int16>(nExtractFloat); + break; + case BASEPROPERTY_FONTDESCRIPTORPART_WEIGHT: rValue >>= rFD.Weight; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_SLANT: if ( rValue >>= nExtractShort ) + rFD.Slant = static_cast<css::awt::FontSlant>(nExtractShort); + else + rValue >>= rFD.Slant; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_UNDERLINE: rValue >>= rFD.Underline; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_STRIKEOUT: rValue >>= rFD.Strikeout; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_WIDTH: rValue >>= rFD.Width; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_PITCH: rValue >>= rFD.Pitch; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_CHARWIDTH: rValue >>= rFD.CharacterWidth; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_ORIENTATION: rValue >>= rFD.Orientation; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_KERNING: rValue >>= rFD.Kerning; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_WORDLINEMODE: rValue >>= rFD.WordLineMode; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_TYPE: rValue >>= rFD.Type; + break; + default: OSL_FAIL( "FontProperty?!" ); + } +} + + + +UnoControlModel::UnoControlModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel_Base() + ,OPropertySetHelper( BrdcstHelper ) + ,maDisposeListeners( *this ) + ,m_xContext( rxContext ) +{ + // Insert properties from Model into table, + // only existing properties are valid, even if they're VOID +} + +UnoControlModel::UnoControlModel( const UnoControlModel& rModel ) + : UnoControlModel_Base() + , OPropertySetHelper( BrdcstHelper ) + , maData( rModel.maData ) + , maDisposeListeners( *this ) + , m_xContext( rModel.m_xContext ) +{ +} + +css::uno::Sequence<sal_Int32> UnoControlModel::ImplGetPropertyIds() const +{ + sal_uInt32 nIDs = maData.size(); + css::uno::Sequence<sal_Int32> aIDs( nIDs ); + sal_Int32* pIDs = aIDs.getArray(); + sal_uInt32 n = 0; + for ( const auto& rData : maData ) + pIDs[n++] = rData.first; + return aIDs; +} + +bool UnoControlModel::ImplHasProperty( sal_uInt16 nPropId ) const +{ + if ( ( nPropId >= BASEPROPERTY_FONTDESCRIPTORPART_START ) && ( nPropId <= BASEPROPERTY_FONTDESCRIPTORPART_END ) ) + nPropId = BASEPROPERTY_FONTDESCRIPTOR; + + return maData.find( nPropId ) != maData.end(); +} + +css::uno::Any UnoControlModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + css::uno::Any aDefault; + + if ( + (nPropId == BASEPROPERTY_FONTDESCRIPTOR) || + ( + (nPropId >= BASEPROPERTY_FONTDESCRIPTORPART_START) && + (nPropId <= BASEPROPERTY_FONTDESCRIPTORPART_END) + ) + ) + { + EmptyFontDescriptor aFD; + switch ( nPropId ) + { + case BASEPROPERTY_FONTDESCRIPTOR: aDefault <<= aFD; break; + case BASEPROPERTY_FONTDESCRIPTORPART_NAME: aDefault <<= aFD.Name; break; + case BASEPROPERTY_FONTDESCRIPTORPART_STYLENAME: aDefault <<= aFD.StyleName; break; + case BASEPROPERTY_FONTDESCRIPTORPART_FAMILY: aDefault <<= aFD.Family; break; + case BASEPROPERTY_FONTDESCRIPTORPART_CHARSET: aDefault <<= aFD.CharSet; break; + case BASEPROPERTY_FONTDESCRIPTORPART_HEIGHT: aDefault <<= static_cast<float>(aFD.Height); break; + case BASEPROPERTY_FONTDESCRIPTORPART_WEIGHT: aDefault <<= aFD.Weight; break; + case BASEPROPERTY_FONTDESCRIPTORPART_SLANT: aDefault <<= static_cast<sal_Int16>(aFD.Slant); break; + case BASEPROPERTY_FONTDESCRIPTORPART_UNDERLINE: aDefault <<= aFD.Underline; break; + case BASEPROPERTY_FONTDESCRIPTORPART_STRIKEOUT: aDefault <<= aFD.Strikeout; break; + case BASEPROPERTY_FONTDESCRIPTORPART_WIDTH: aDefault <<= aFD.Width; break; + case BASEPROPERTY_FONTDESCRIPTORPART_PITCH: aDefault <<= aFD.Pitch; break; + case BASEPROPERTY_FONTDESCRIPTORPART_CHARWIDTH: aDefault <<= aFD.CharacterWidth; break; + case BASEPROPERTY_FONTDESCRIPTORPART_ORIENTATION: aDefault <<= aFD.Orientation; break; + case BASEPROPERTY_FONTDESCRIPTORPART_KERNING: aDefault <<= aFD.Kerning; break; + case BASEPROPERTY_FONTDESCRIPTORPART_WORDLINEMODE: aDefault <<= aFD.WordLineMode; break; + case BASEPROPERTY_FONTDESCRIPTORPART_TYPE: aDefault <<= aFD.Type; break; + default: OSL_FAIL( "FontProperty?!" ); + } + } + else + { + switch ( nPropId ) + { + case BASEPROPERTY_GRAPHIC: + aDefault <<= Reference< graphic::XGraphic >(); + break; + + case BASEPROPERTY_REFERENCE_DEVICE: + aDefault <<= Reference< awt::XDevice >(); + break; + + case BASEPROPERTY_ITEM_SEPARATOR_POS: + case BASEPROPERTY_VERTICALALIGN: + case BASEPROPERTY_BORDERCOLOR: + case BASEPROPERTY_SYMBOL_COLOR: + case BASEPROPERTY_TABSTOP: + case BASEPROPERTY_TEXTCOLOR: + case BASEPROPERTY_TEXTLINECOLOR: + case BASEPROPERTY_DATE: + case BASEPROPERTY_DATESHOWCENTURY: + case BASEPROPERTY_TIME: + case BASEPROPERTY_VALUE_DOUBLE: + case BASEPROPERTY_PROGRESSVALUE: + case BASEPROPERTY_SCROLLVALUE: + case BASEPROPERTY_VISIBLESIZE: + case BASEPROPERTY_BACKGROUNDCOLOR: + case BASEPROPERTY_FILLCOLOR: break; // Void + + case BASEPROPERTY_FONTRELIEF: + case BASEPROPERTY_FONTEMPHASISMARK: + case BASEPROPERTY_MAXTEXTLEN: + case BASEPROPERTY_STATE: + case BASEPROPERTY_EXTDATEFORMAT: + case BASEPROPERTY_EXTTIMEFORMAT: + case BASEPROPERTY_ECHOCHAR: aDefault <<= sal_Int16(0); break; + case BASEPROPERTY_BORDER: aDefault <<= sal_Int16(1); break; + case BASEPROPERTY_DECIMALACCURACY: aDefault <<= sal_Int16(2); break; + case BASEPROPERTY_LINECOUNT: aDefault <<= sal_Int16(5); break; + case BASEPROPERTY_ALIGN: aDefault <<= sal_Int16(PROPERTY_ALIGN_LEFT); break; + case BASEPROPERTY_IMAGEALIGN: aDefault <<= sal_Int16(1) /*ImageAlign::Top*/; break; + case BASEPROPERTY_IMAGEPOSITION: aDefault <<= sal_Int16(12) /*ImagePosition::Centered*/; break; + case BASEPROPERTY_PUSHBUTTONTYPE: aDefault <<= sal_Int16(0) /*PushButtonType::STANDARD*/; break; + case BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR:aDefault <<= sal_Int16(awt::MouseWheelBehavior::SCROLL_FOCUS_ONLY); break; + + case BASEPROPERTY_DATEMAX: aDefault <<= util::Date( 31, 12, 2200 ); break; + case BASEPROPERTY_DATEMIN: aDefault <<= util::Date( 1, 1, 1900 ); break; + case BASEPROPERTY_TIMEMAX: aDefault <<= util::Time(0, 0, 59, 23, false); break; + case BASEPROPERTY_TIMEMIN: aDefault <<= util::Time(); break; + case BASEPROPERTY_VALUEMAX_DOUBLE: aDefault <<= double(1000000); break; + case BASEPROPERTY_VALUEMIN_DOUBLE: aDefault <<= double(-1000000); break; + case BASEPROPERTY_VALUESTEP_DOUBLE: aDefault <<= double(1); break; + case BASEPROPERTY_PROGRESSVALUE_MAX: aDefault <<= sal_Int32(100); break; + case BASEPROPERTY_PROGRESSVALUE_MIN: aDefault <<= sal_Int32(0); break; + case BASEPROPERTY_SCROLLVALUE_MAX: aDefault <<= sal_Int32(100); break; + case BASEPROPERTY_SCROLLVALUE_MIN: aDefault <<= sal_Int32(0); break; + case BASEPROPERTY_LINEINCREMENT: aDefault <<= sal_Int32(1); break; + case BASEPROPERTY_BLOCKINCREMENT: aDefault <<= sal_Int32(10); break; + case BASEPROPERTY_ORIENTATION: aDefault <<= sal_Int32(0); break; + case BASEPROPERTY_SPINVALUE: aDefault <<= sal_Int32(0); break; + case BASEPROPERTY_SPININCREMENT: aDefault <<= sal_Int32(1); break; + case BASEPROPERTY_SPINVALUE_MIN: aDefault <<= sal_Int32(0); break; + case BASEPROPERTY_SPINVALUE_MAX: aDefault <<= sal_Int32(100); break; + case BASEPROPERTY_REPEAT_DELAY: aDefault <<= sal_Int32(50); break; // 50 milliseconds + case BASEPROPERTY_DEFAULTCONTROL: aDefault <<= const_cast<UnoControlModel*>(this)->getServiceName(); break; + + case BASEPROPERTY_AUTOHSCROLL: + case BASEPROPERTY_AUTOVSCROLL: + case BASEPROPERTY_MOVEABLE: + case BASEPROPERTY_CLOSEABLE: + case BASEPROPERTY_SIZEABLE: + case BASEPROPERTY_HSCROLL: + case BASEPROPERTY_DEFAULTBUTTON: + case BASEPROPERTY_MULTILINE: + case BASEPROPERTY_MULTISELECTION: + case BASEPROPERTY_TRISTATE: + case BASEPROPERTY_DROPDOWN: + case BASEPROPERTY_SPIN: + case BASEPROPERTY_READONLY: + case BASEPROPERTY_VSCROLL: + case BASEPROPERTY_NUMSHOWTHOUSANDSEP: + case BASEPROPERTY_STRICTFORMAT: + case BASEPROPERTY_REPEAT: + case BASEPROPERTY_PAINTTRANSPARENT: + case BASEPROPERTY_DESKTOP_AS_PARENT: + case BASEPROPERTY_HARDLINEBREAKS: + case BASEPROPERTY_NOLABEL: aDefault <<= false; break; + + case BASEPROPERTY_MULTISELECTION_SIMPLEMODE: + case BASEPROPERTY_HIDEINACTIVESELECTION: + case BASEPROPERTY_ENFORCE_FORMAT: + case BASEPROPERTY_AUTOCOMPLETE: + case BASEPROPERTY_SCALEIMAGE: + case BASEPROPERTY_ENABLED: + case BASEPROPERTY_PRINTABLE: + case BASEPROPERTY_ENABLEVISIBLE: + case BASEPROPERTY_DECORATION: aDefault <<= true; break; + + case BASEPROPERTY_GROUPNAME: + case BASEPROPERTY_HELPTEXT: + case BASEPROPERTY_HELPURL: + case BASEPROPERTY_IMAGEURL: + case BASEPROPERTY_DIALOGSOURCEURL: + case BASEPROPERTY_EDITMASK: + case BASEPROPERTY_LITERALMASK: + case BASEPROPERTY_LABEL: + case BASEPROPERTY_TITLE: + case BASEPROPERTY_TEXT: aDefault <<= OUString(); break; + + case BASEPROPERTY_WRITING_MODE: + case BASEPROPERTY_CONTEXT_WRITING_MODE: + aDefault <<= text::WritingMode2::CONTEXT; + break; + + case BASEPROPERTY_STRINGITEMLIST: + { + css::uno::Sequence< OUString> aStringSeq; + aDefault <<= aStringSeq; + + } + break; + case BASEPROPERTY_TYPEDITEMLIST: + { + css::uno::Sequence< css::uno::Any > aAnySeq; + aDefault <<= aAnySeq; + + } + break; + case BASEPROPERTY_SELECTEDITEMS: + { + css::uno::Sequence<sal_Int16> aINT16Seq; + aDefault <<= aINT16Seq; + } + break; + case BASEPROPERTY_CURRENCYSYMBOL: + { + OUString sDefaultCurrency( + utl::ConfigManager::getDefaultCurrency() ); + + // extract the bank symbol + sal_Int32 nSepPos = sDefaultCurrency.indexOf( '-' ); + OUString sBankSymbol; + if ( nSepPos >= 0 ) + { + sBankSymbol = sDefaultCurrency.copy( 0, nSepPos ); + sDefaultCurrency = sDefaultCurrency.copy( nSepPos + 1 ); + } + + // the remaining is the locale + LocaleDataWrapper aLocaleInfo( m_xContext, LanguageTag(sDefaultCurrency) ); + if ( sBankSymbol.isEmpty() ) + sBankSymbol = aLocaleInfo.getCurrBankSymbol(); + + // look for the currency entry (for this language) which has the given bank symbol + const Sequence< Currency2 > aAllCurrencies = aLocaleInfo.getAllCurrencies(); + + OUString sCurrencySymbol = aLocaleInfo.getCurrSymbol(); + if ( sBankSymbol.isEmpty() ) + { + DBG_ASSERT( aAllCurrencies.hasElements(), "UnoControlModel::ImplGetDefaultValue: no currencies at all!" ); + if ( aAllCurrencies.hasElements() ) + { + sBankSymbol = aAllCurrencies[0].BankSymbol; + sCurrencySymbol = aAllCurrencies[0].Symbol; + } + } + + if ( !sBankSymbol.isEmpty() ) + { + bool bLegacy = false; + bool bFound = false; + for ( const Currency2& rCurrency : aAllCurrencies ) + if ( rCurrency.BankSymbol == sBankSymbol ) + { + sCurrencySymbol = rCurrency.Symbol; + if ( rCurrency.LegacyOnly ) + bLegacy = true; + else + { + bFound = true; + break; + } + } + DBG_ASSERT( bLegacy || bFound, "UnoControlModel::ImplGetDefaultValue: did not find the given bank symbol!" ); + } + + aDefault <<= sCurrencySymbol; + } + break; + + default: OSL_FAIL( "ImplGetDefaultValue - unknown Property" ); + } + } + + return aDefault; +} + +void UnoControlModel::ImplRegisterProperty( sal_uInt16 nPropId, const css::uno::Any& rDefault ) +{ + maData[ nPropId ] = rDefault; +} + +void UnoControlModel::ImplRegisterProperty( sal_uInt16 nPropId ) +{ + ImplRegisterProperty( nPropId, ImplGetDefaultValue( nPropId ) ); + + if ( nPropId == BASEPROPERTY_FONTDESCRIPTOR ) + { + // some properties are not included in the FontDescriptor, but every time + // when we have a FontDescriptor we want to have these properties too. + // => Easier to register the here, instead everywhere where I register the FontDescriptor... + + ImplRegisterProperty( BASEPROPERTY_TEXTCOLOR ); + ImplRegisterProperty( BASEPROPERTY_TEXTLINECOLOR ); + ImplRegisterProperty( BASEPROPERTY_FONTRELIEF ); + ImplRegisterProperty( BASEPROPERTY_FONTEMPHASISMARK ); + } +} + +void UnoControlModel::ImplRegisterProperties( const std::vector< sal_uInt16 > &rIds ) +{ + for (const auto& rId : rIds) + { + if( !ImplHasProperty( rId ) ) + ImplRegisterProperty( rId, ImplGetDefaultValue( rId ) ); + } +} + +// css::uno::XInterface +css::uno::Any UnoControlModel::queryAggregation( const css::uno::Type & rType ) +{ + Any aRet = UnoControlModel_Base::queryAggregation( rType ); + if ( !aRet.hasValue() ) + aRet = ::cppu::OPropertySetHelper::queryInterface( rType ); + return aRet; +} + +// css::lang::XUnoTunnel + +const css::uno::Sequence< sal_Int8 >& UnoControlModel::getUnoTunnelId() noexcept +{ + static const comphelper::UnoIdInit theUnoControlModelUnoTunnelId; + return theUnoControlModelUnoTunnelId.getSeq(); +} + +sal_Int64 UnoControlModel::getSomething( const css::uno::Sequence< sal_Int8 >& rIdentifier ) +{ + return comphelper::getSomethingImpl(rIdentifier, this); +} + +// XInterface +IMPLEMENT_FORWARD_REFCOUNT( UnoControlModel, UnoControlModel_Base ) + +// css::lang::XTypeProvider +IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoControlModel, UnoControlModel_Base, ::cppu::OPropertySetHelper ) + + +uno::Reference< util::XCloneable > UnoControlModel::createClone() +{ + rtl::Reference<UnoControlModel> pClone = Clone(); + return pClone; +} + +// css::lang::XComponent +void UnoControlModel::dispose( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::lang::EventObject aEvt; + aEvt.Source = static_cast<css::uno::XAggregation*>(static_cast<cppu::OWeakAggObject*>(this)); + maDisposeListeners.disposeAndClear( aEvt ); + + BrdcstHelper.aLC.disposeAndClear( aEvt ); + + // let the property set helper notify our property listeners + OPropertySetHelper::disposing(); +} + +void UnoControlModel::addEventListener( const css::uno::Reference< css::lang::XEventListener >& rxListener ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + maDisposeListeners.addInterface( rxListener ); +} + +void UnoControlModel::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& rxListener ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + maDisposeListeners.removeInterface( rxListener ); +} + + +// css::beans::XPropertyState +css::beans::PropertyState UnoControlModel::getPropertyState( const OUString& PropertyName ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + sal_uInt16 nPropId = GetPropertyId( PropertyName ); + + css::uno::Any aValue = getPropertyValue( PropertyName ); + css::uno::Any aDefault = ImplGetDefaultValue( nPropId ); + + return CompareProperties( aValue, aDefault ) ? css::beans::PropertyState_DEFAULT_VALUE : css::beans::PropertyState_DIRECT_VALUE; +} + +css::uno::Sequence< css::beans::PropertyState > UnoControlModel::getPropertyStates( const css::uno::Sequence< OUString >& PropertyNames ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + sal_Int32 nNames = PropertyNames.getLength(); + + css::uno::Sequence< css::beans::PropertyState > aStates( nNames ); + + std::transform(PropertyNames.begin(), PropertyNames.end(), aStates.getArray(), + [this](const OUString& rName) -> css::beans::PropertyState { return getPropertyState(rName); }); + + return aStates; +} + +void UnoControlModel::setPropertyToDefault( const OUString& PropertyName ) +{ + Any aDefaultValue; + { + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + aDefaultValue = ImplGetDefaultValue( GetPropertyId( PropertyName ) ); + } + setPropertyValue( PropertyName, aDefaultValue ); +} + +css::uno::Any UnoControlModel::getPropertyDefault( const OUString& rPropertyName ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + return ImplGetDefaultValue( GetPropertyId( rPropertyName ) ); +} + + +// css::io::XPersistObjec +OUString UnoControlModel::getServiceName( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + OSL_FAIL( "ServiceName of UnoControlModel ?!" ); + return OUString(); +} + +void UnoControlModel::write( const css::uno::Reference< css::io::XObjectOutputStream >& OutStream ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::uno::Reference< css::io::XMarkableStream > xMark( OutStream, css::uno::UNO_QUERY ); + DBG_ASSERT( xMark.is(), "write: no css::io::XMarkableStream!" ); + + OutStream->writeShort( UNOCONTROL_STREAMVERSION ); + + o3tl::sorted_vector<sal_uInt16> aProps; + + for (const auto& rData : maData) + { + if ( ( ( GetPropertyAttribs( rData.first ) & css::beans::PropertyAttribute::TRANSIENT ) == 0 ) + && ( getPropertyState( GetPropertyName( rData.first ) ) != css::beans::PropertyState_DEFAULT_VALUE ) ) + { + aProps.insert( rData.first ); + } + } + + sal_uInt32 nProps = aProps.size(); + + // Save FontProperty always in the old format (due to missing distinction + // between 5.0 and 5.1) + OutStream->writeLong( ( aProps.find( BASEPROPERTY_FONTDESCRIPTOR ) != aProps.end() ) ? ( nProps + 3 ) : nProps ); + for ( const auto& rProp : aProps ) + { + sal_Int32 nPropDataBeginMark = xMark->createMark(); + OutStream->writeLong( 0 ); // DataLen + + const css::uno::Any* pProp = &(maData[rProp]); + OutStream->writeShort( rProp ); + + bool bVoid = pProp->getValueType().getTypeClass() == css::uno::TypeClass_VOID; + + OutStream->writeBoolean( bVoid ); + + if ( !bVoid ) + { + const css::uno::Any& rValue = *pProp; + const css::uno::Type& rType = rValue.getValueType(); + + if ( rType == cppu::UnoType< bool >::get() ) + { + bool b = false; + rValue >>= b; + OutStream->writeBoolean( b ); + } + else if ( rType == ::cppu::UnoType< OUString >::get() ) + { + OUString aUString; + rValue >>= aUString; + OutStream->writeUTF( aUString ); + } + else if ( rType == ::cppu::UnoType< ::cppu::UnoUnsignedShortType >::get() ) + { + sal_uInt16 n = 0; + rValue >>= n; + OutStream->writeShort( n ); + } + else if ( rType == cppu::UnoType<sal_Int16>::get() ) + { + sal_Int16 n = 0; + rValue >>= n; + OutStream->writeShort( n ); + } + else if ( rType == cppu::UnoType<sal_uInt32>::get() ) + { + sal_uInt32 n = 0; + rValue >>= n; + OutStream->writeLong( n ); + } + else if ( rType == cppu::UnoType<sal_Int32>::get() ) + { + sal_Int32 n = 0; + rValue >>= n; + OutStream->writeLong( n ); + } + else if ( rType == cppu::UnoType<double>::get() ) + { + double n = 0; + rValue >>= n; + OutStream->writeDouble( n ); + } + else if ( rType == cppu::UnoType< css::awt::FontDescriptor >::get() ) + { + css::awt::FontDescriptor aFD; + rValue >>= aFD; + OutStream->writeUTF( aFD.Name ); + OutStream->writeShort( aFD.Height ); + OutStream->writeShort( aFD.Width ); + OutStream->writeUTF( aFD.StyleName ); + OutStream->writeShort( aFD.Family ); + OutStream->writeShort( aFD.CharSet ); + OutStream->writeShort( aFD.Pitch ); + OutStream->writeDouble( aFD.CharacterWidth ); + OutStream->writeDouble( aFD.Weight ); + OutStream->writeShort( + sal::static_int_cast< sal_Int16 >(aFD.Slant) ); + OutStream->writeShort( aFD.Underline ); + OutStream->writeShort( aFD.Strikeout ); + OutStream->writeDouble( aFD.Orientation ); + OutStream->writeBoolean( aFD.Kerning ); + OutStream->writeBoolean( aFD.WordLineMode ); + OutStream->writeShort( aFD.Type ); + } + else if ( rType == cppu::UnoType<css::util::Date>::get() ) + { + css::util::Date d; + rValue >>= d; + OutStream->writeLong(d.Day + 100 * d.Month + 10000 * d.Year); + // YYYYMMDD + } + else if ( rType == cppu::UnoType<css::util::Time>::get() ) + { + css::util::Time t; + rValue >>= t; + OutStream->writeLong( + t.NanoSeconds / 1000000 + 100 * t.Seconds + + 10000 * t.Minutes + 1000000 * t.Hours); // HHMMSShh + } + else if ( rType == cppu::UnoType< css::uno::Sequence< OUString> >::get() ) + { + css::uno::Sequence< OUString> aSeq; + rValue >>= aSeq; + tools::Long nEntries = aSeq.getLength(); + OutStream->writeLong( nEntries ); + for ( const auto& rVal : std::as_const(aSeq) ) + OutStream->writeUTF( rVal ); + } + else if ( rType == cppu::UnoType< cppu::UnoSequenceType<cppu::UnoUnsignedShortType> >::get() ) + { + css::uno::Sequence<sal_uInt16> aSeq; + rValue >>= aSeq; + tools::Long nEntries = aSeq.getLength(); + OutStream->writeLong( nEntries ); + for ( const auto nVal : std::as_const(aSeq) ) + OutStream->writeShort( nVal ); + } + else if ( rType == cppu::UnoType< css::uno::Sequence<sal_Int16> >::get() ) + { + css::uno::Sequence<sal_Int16> aSeq; + rValue >>= aSeq; + tools::Long nEntries = aSeq.getLength(); + OutStream->writeLong( nEntries ); + for ( const auto nVal : std::as_const(aSeq) ) + OutStream->writeShort( nVal ); + } + else if ( rType.getTypeClass() == TypeClass_ENUM ) + { + sal_Int32 nAsInt = 0; + ::cppu::enum2int( nAsInt, rValue ); + OutStream->writeLong( nAsInt ); + } +#if OSL_DEBUG_LEVEL > 0 + else + { + SAL_WARN( "toolkit", "UnoControlModel::write: don't know how to handle a property of type '" + << rType.getTypeName() + << "'.\n(Currently handling property '" + << GetPropertyName( rProp ) + << "'.)"); + } +#endif + } + + sal_Int32 nPropDataLen = xMark->offsetToMark( nPropDataBeginMark ); + xMark->jumpToMark( nPropDataBeginMark ); + OutStream->writeLong( nPropDataLen ); + xMark->jumpToFurthest(); + xMark->deleteMark(nPropDataBeginMark); + } + + if ( aProps.find( BASEPROPERTY_FONTDESCRIPTOR ) == aProps.end() ) + return; + + const css::uno::Any* pProp = &maData[ BASEPROPERTY_FONTDESCRIPTOR ]; + // Until 5.0 export arrives, write old format... + css::awt::FontDescriptor aFD; + (*pProp) >>= aFD; + + for ( sal_uInt16 n = BASEPROPERTY_FONT_TYPE; n <= BASEPROPERTY_FONT_ATTRIBS; n++ ) + { + sal_Int32 nPropDataBeginMark = xMark->createMark(); + OutStream->writeLong( 0 ); // DataLen + OutStream->writeShort( n ); // PropId + OutStream->writeBoolean( false ); // Void + + if ( n == BASEPROPERTY_FONT_TYPE ) + { + OutStream->writeUTF( aFD.Name ); + OutStream->writeUTF( aFD.StyleName ); + OutStream->writeShort( aFD.Family ); + OutStream->writeShort( aFD.CharSet ); + OutStream->writeShort( aFD.Pitch ); + } + else if ( n == BASEPROPERTY_FONT_SIZE ) + { + OutStream->writeLong( aFD.Width ); + OutStream->writeLong( aFD.Height ); + OutStream->writeShort( + sal::static_int_cast< sal_Int16 >( + vcl::unohelper::ConvertFontWidth(aFD.CharacterWidth)) ); + } + else if ( n == BASEPROPERTY_FONT_ATTRIBS ) + { + OutStream->writeShort( + sal::static_int_cast< sal_Int16 >( + vcl::unohelper::ConvertFontWeight(aFD.Weight)) ); + OutStream->writeShort( + sal::static_int_cast< sal_Int16 >(aFD.Slant) ); + OutStream->writeShort( aFD.Underline ); + OutStream->writeShort( aFD.Strikeout ); + OutStream->writeShort( static_cast<short>(aFD.Orientation * 10) ); + OutStream->writeBoolean( aFD.Kerning ); + OutStream->writeBoolean( aFD.WordLineMode ); + } + else + { + OSL_FAIL( "Property?!" ); + } + + sal_Int32 nPropDataLen = xMark->offsetToMark( nPropDataBeginMark ); + xMark->jumpToMark( nPropDataBeginMark ); + OutStream->writeLong( nPropDataLen ); + xMark->jumpToFurthest(); + xMark->deleteMark(nPropDataBeginMark); + } +} + +void UnoControlModel::read( const css::uno::Reference< css::io::XObjectInputStream >& InStream ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::uno::Reference< css::io::XMarkableStream > xMark( InStream, css::uno::UNO_QUERY ); + DBG_ASSERT( xMark.is(), "read: no css::io::XMarkableStream!" ); + + short nVersion = InStream->readShort(); + sal_uInt32 nProps = static_cast<sal_uInt32>(InStream->readLong()); + css::uno::Sequence< OUString> aProps( nProps ); + css::uno::Sequence< css::uno::Any> aValues( nProps ); + bool bInvalidEntries = false; + + // Unfortunately, there's no mark for the whole block, thus only properties may be changed. + // No data for the model may be added following the properties + + // Used for import of old parts in css::awt::FontDescriptor + std::unique_ptr<css::awt::FontDescriptor> pFD; + + for ( sal_uInt32 i = 0; i < nProps; i++ ) + { + sal_Int32 nPropDataBeginMark = xMark->createMark(); + sal_Int32 nPropDataLen = InStream->readLong(); + + sal_uInt16 nPropId = static_cast<sal_uInt16>(InStream->readShort()); + + css::uno::Any aValue; + bool bIsVoid = InStream->readBoolean(); + if ( !bIsVoid ) + { + if ( maData.find( nPropId ) != maData.end() ) + { + const css::uno::Type* pType = GetPropertyType( nPropId ); + if ( *pType == cppu::UnoType<bool>::get() ) + { + bool b = InStream->readBoolean(); + aValue <<= b; + } + else if ( *pType == cppu::UnoType<OUString>::get() ) + { + OUString aUTF = InStream->readUTF(); + aValue <<= aUTF; + } + else if ( *pType == ::cppu::UnoType< ::cppu::UnoUnsignedShortType >::get() ) + { + sal_uInt16 n = InStream->readShort(); + aValue <<= n; + } + else if ( *pType == cppu::UnoType<sal_Int16>::get() ) + { + sal_Int16 n = InStream->readShort(); + aValue <<= n; + } + else if ( *pType == cppu::UnoType<sal_uInt32>::get() ) + { + sal_uInt32 n = InStream->readLong(); + aValue <<= n; + } + else if ( *pType == cppu::UnoType<sal_Int32>::get() ) + { + sal_Int32 n = InStream->readLong(); + aValue <<= n; + } + else if ( *pType == cppu::UnoType<double>::get() ) + { + double n = InStream->readDouble(); + aValue <<= n; + } + else if ( *pType == cppu::UnoType< css::awt::FontDescriptor >::get() ) + { + css::awt::FontDescriptor aFD; + aFD.Name = InStream->readUTF(); + aFD.Height = InStream->readShort(); + aFD.Width = InStream->readShort(); + aFD.StyleName = InStream->readUTF(); + aFD.Family = InStream->readShort(); + aFD.CharSet = InStream->readShort(); + aFD.Pitch = InStream->readShort(); + aFD.CharacterWidth = static_cast<float>(InStream->readDouble()); + aFD.Weight = static_cast<float>(InStream->readDouble()); + aFD.Slant = static_cast<css::awt::FontSlant>(InStream->readShort()); + aFD.Underline = InStream->readShort(); + aFD.Strikeout = InStream->readShort(); + aFD.Orientation = static_cast<float>(InStream->readDouble()); + aFD.Kerning = InStream->readBoolean() != 0; + aFD.WordLineMode = InStream->readBoolean() != 0; + aFD.Type = InStream->readShort(); + aValue <<= aFD; + } + else if ( *pType == cppu::UnoType<css::util::Date>::get() ) + { + sal_Int32 n = InStream->readLong(); // YYYYMMDD + aValue <<= css::util::Date( + n % 100, (n / 100) % 100, n / 10000); + } + else if ( *pType == cppu::UnoType<css::util::Time>::get() ) + { + sal_Int32 n = InStream->readLong(); // HHMMSShh + aValue <<= css::util::Time( + (n % 100) * 1000000, (n / 100) % 100, (n / 10000) % 100, + n / 1000000, false); + } + else if ( *pType == cppu::UnoType< css::uno::Sequence< OUString> >::get() ) + { + tools::Long nEntries = InStream->readLong(); + css::uno::Sequence< OUString> aSeq( nEntries ); + for ( tools::Long n = 0; n < nEntries; n++ ) + aSeq.getArray()[n] = InStream->readUTF(); + aValue <<= aSeq; + + } + else if ( *pType == cppu::UnoType< cppu::UnoSequenceType<cppu::UnoUnsignedShortType> >::get() ) + + { + tools::Long nEntries = InStream->readLong(); + css::uno::Sequence<sal_uInt16> aSeq( nEntries ); + for ( tools::Long n = 0; n < nEntries; n++ ) + aSeq.getArray()[n] = static_cast<sal_uInt16>(InStream->readShort()); + aValue <<= aSeq; + } + else if ( *pType == cppu::UnoType< css::uno::Sequence<sal_Int16> >::get() ) + { + tools::Long nEntries = InStream->readLong(); + css::uno::Sequence<sal_Int16> aSeq( nEntries ); + for ( tools::Long n = 0; n < nEntries; n++ ) + aSeq.getArray()[n] = InStream->readShort(); + aValue <<= aSeq; + } + else if ( pType->getTypeClass() == TypeClass_ENUM ) + { + sal_Int32 nAsInt = InStream->readLong(); + aValue = ::cppu::int2enum( nAsInt, *pType ); + } + else + { + SAL_WARN( "toolkit", "UnoControlModel::read: don't know how to handle a property of type '" + << pType->getTypeName() + << "'.\n(Currently handling property '" + << GetPropertyName( nPropId ) + << "'.)"); + } + } + else + { + // Old trash from 5.0 + if ( nPropId == BASEPROPERTY_FONT_TYPE ) + { + // Redundant information for older versions + // is skipped by MarkableStream + if ( nVersion < 2 ) + { + if ( !pFD ) + { + pFD.reset(new css::awt::FontDescriptor); + if ( maData.find( BASEPROPERTY_FONTDESCRIPTOR ) != maData.end() ) // due to defaults... + maData[ BASEPROPERTY_FONTDESCRIPTOR ] >>= *pFD; + } + pFD->Name = InStream->readUTF(); + pFD->StyleName = InStream->readUTF(); + pFD->Family = InStream->readShort(); + pFD->CharSet = InStream->readShort(); + pFD->Pitch = InStream->readShort(); + } + } + else if ( nPropId == BASEPROPERTY_FONT_SIZE ) + { + if ( nVersion < 2 ) + { + if ( !pFD ) + { + pFD.reset(new css::awt::FontDescriptor); + if ( maData.find(BASEPROPERTY_FONTDESCRIPTOR) != maData.end() ) // due to defaults... + maData[BASEPROPERTY_FONTDESCRIPTOR] >>= *pFD; + } + pFD->Width = static_cast<sal_Int16>(InStream->readLong()); + pFD->Height = static_cast<sal_Int16>(InStream->readLong()); + InStream->readShort(); // ignore css::awt::FontWidth - it was + // misspelled and is no longer needed + pFD->CharacterWidth = css::awt::FontWidth::DONTKNOW; + } + } + else if ( nPropId == BASEPROPERTY_FONT_ATTRIBS ) + { + if ( nVersion < 2 ) + { + if ( !pFD ) + { + pFD.reset(new css::awt::FontDescriptor); + if ( maData.find(BASEPROPERTY_FONTDESCRIPTOR) != maData.end() ) // due to defaults... + maData[BASEPROPERTY_FONTDESCRIPTOR] >>= *pFD; + } + pFD->Weight = vcl::unohelper::ConvertFontWeight(static_cast<FontWeight>(InStream->readShort())); + pFD->Slant = static_cast<css::awt::FontSlant>(InStream->readShort()); + pFD->Underline = InStream->readShort(); + pFD->Strikeout = InStream->readShort(); + pFD->Orientation = static_cast<float>(static_cast<double>(InStream->readShort())) / 10; + pFD->Kerning = InStream->readBoolean() != 0; + pFD->WordLineMode = InStream->readBoolean() != 0; + } + } + else + { + OSL_FAIL( "read: unknown Property!" ); + } + } + } + else // bVoid + { + if ( nPropId == BASEPROPERTY_FONTDESCRIPTOR ) + { + EmptyFontDescriptor aFD; + aValue <<= aFD; + } + } + + if ( maData.find( nPropId ) != maData.end() ) + { + aProps.getArray()[i] = GetPropertyName( nPropId ); + aValues.getArray()[i] = aValue; + } + else + { + bInvalidEntries = true; + } + + // Skip rest of input if there is more data in stream than this version can handle + xMark->jumpToMark( nPropDataBeginMark ); + InStream->skipBytes( nPropDataLen ); + xMark->deleteMark(nPropDataBeginMark); + } + if ( bInvalidEntries ) + { + for ( sal_Int32 i = 0; i < aProps.getLength(); i++ ) + { + if ( aProps.getConstArray()[i].isEmpty() ) + { + ::comphelper::removeElementAt( aProps, i ); + ::comphelper::removeElementAt( aValues, i ); + i--; + } + } + } + + try + { + setPropertyValues( aProps, aValues ); + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + + if ( pFD ) + { + css::uno::Any aValue; + aValue <<= *pFD; + setPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR ), aValue ); + } +} + + +// css::lang::XServiceInfo +OUString UnoControlModel::getImplementationName( ) +{ + OSL_FAIL( "This method should be overridden!" ); + return OUString(); + +} + +sal_Bool UnoControlModel::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > UnoControlModel::getSupportedServiceNames( ) +{ + return { "com.sun.star.awt.UnoControlModel" }; +} + +sal_Bool UnoControlModel::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nPropId, const Any& rValue ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + bool bVoid = rValue.getValueType().getTypeClass() == css::uno::TypeClass_VOID; + if ( bVoid ) + { + rConvertedValue.clear(); + } + else + { + const css::uno::Type* pDestType = GetPropertyType( static_cast<sal_uInt16>(nPropId) ); + if ( pDestType->getTypeClass() == TypeClass_ANY ) + { + rConvertedValue = rValue; + } + else + { + if ( pDestType->equals( rValue.getValueType() ) ) + { + rConvertedValue = rValue; + } + else + { + bool bConverted = false; + // 13.03.2001 - 84923 - frank.schoenheit@germany.sun.com + + switch (pDestType->getTypeClass()) + { + case TypeClass_DOUBLE: + { + // try as double + double nAsDouble = 0; + bConverted = ( rValue >>= nAsDouble ); + if ( bConverted ) + rConvertedValue <<= nAsDouble; + else + { // try as integer + sal_Int32 nAsInteger = 0; + bConverted = ( rValue >>= nAsInteger ); + if ( bConverted ) + rConvertedValue <<= static_cast<double>(nAsInteger); + } + } + break; + case TypeClass_SHORT: + { + sal_Int16 n; + bConverted = ( rValue >>= n ); + if ( bConverted ) + rConvertedValue <<= n; + } + break; + case TypeClass_UNSIGNED_SHORT: + { + sal_uInt16 n; + bConverted = ( rValue >>= n ); + if ( bConverted ) + rConvertedValue <<= n; + } + break; + case TypeClass_LONG: + { + sal_Int32 n; + bConverted = ( rValue >>= n ); + if ( bConverted ) + rConvertedValue <<= n; + } + break; + case TypeClass_UNSIGNED_LONG: + { + sal_uInt32 n; + bConverted = ( rValue >>= n ); + if ( bConverted ) + rConvertedValue <<= n; + } + break; + case TypeClass_INTERFACE: + { + if ( rValue.getValueType().getTypeClass() == TypeClass_INTERFACE ) + { + Reference< XInterface > xPure( rValue, UNO_QUERY ); + if ( xPure.is() ) + rConvertedValue = xPure->queryInterface( *pDestType ); + else + rConvertedValue.setValue( nullptr, *pDestType ); + bConverted = true; + } + } + break; + case TypeClass_ENUM: + { + sal_Int32 nValue = 0; + bConverted = ( rValue >>= nValue ); + if ( bConverted ) + rConvertedValue = ::cppu::int2enum( nValue, *pDestType ); + } + break; + default: ; // avoid compiler warning + } + + if (!bConverted) + { + throw css::lang::IllegalArgumentException( + "Unable to convert the given value for the property " + + GetPropertyName( static_cast<sal_uInt16>(nPropId) ) + + ".\nExpected type: " + pDestType->getTypeName() + + "\nFound type: " + rValue.getValueType().getTypeName(), + static_cast< css::beans::XPropertySet* >(this), + 1); + } + } + } + } + + // the current value + getFastPropertyValue( rOldValue, nPropId ); + return !CompareProperties( rConvertedValue, rOldValue ); +} + +void UnoControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nPropId, const css::uno::Any& rValue ) +{ + // Missing: the fake solo properties of the FontDescriptor + + ImplPropertyTable::const_iterator it = maData.find( nPropId ); + const css::uno::Any* pProp = it == maData.end() ? nullptr : &(it->second); + ENSURE_OR_RETURN_VOID( pProp, "UnoControlModel::setFastPropertyValue_NoBroadcast: invalid property id!" ); + + DBG_ASSERT( ( rValue.getValueType().getTypeClass() != css::uno::TypeClass_VOID ) || ( GetPropertyAttribs( static_cast<sal_uInt16>(nPropId) ) & css::beans::PropertyAttribute::MAYBEVOID ), "Property should not be VOID!" ); + maData[ nPropId ] = rValue; +} + +void UnoControlModel::getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nPropId ) const +{ + ::osl::Guard< ::osl::Mutex > aGuard( const_cast<UnoControlModel*>(this)->GetMutex() ); + + ImplPropertyTable::const_iterator it = maData.find( nPropId ); + const css::uno::Any* pProp = it == maData.end() ? nullptr : &(it->second); + + if ( pProp ) + rValue = *pProp; + else if ( ( nPropId >= BASEPROPERTY_FONTDESCRIPTORPART_START ) && ( nPropId <= BASEPROPERTY_FONTDESCRIPTORPART_END ) ) + { + pProp = &( maData.find( BASEPROPERTY_FONTDESCRIPTOR )->second ); + css::awt::FontDescriptor aFD; + (*pProp) >>= aFD; + switch ( nPropId ) + { + case BASEPROPERTY_FONTDESCRIPTORPART_NAME: rValue <<= aFD.Name; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_STYLENAME: rValue <<= aFD.StyleName; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_FAMILY: rValue <<= aFD.Family; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_CHARSET: rValue <<= aFD.CharSet; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_HEIGHT: rValue <<= static_cast<float>(aFD.Height); + break; + case BASEPROPERTY_FONTDESCRIPTORPART_WEIGHT: rValue <<= aFD.Weight; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_SLANT: rValue <<= static_cast<sal_Int16>(aFD.Slant); + break; + case BASEPROPERTY_FONTDESCRIPTORPART_UNDERLINE: rValue <<= aFD.Underline; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_STRIKEOUT: rValue <<= aFD.Strikeout; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_WIDTH: rValue <<= aFD.Width; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_PITCH: rValue <<= aFD.Pitch; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_CHARWIDTH: rValue <<= aFD.CharacterWidth; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_ORIENTATION: rValue <<= aFD.Orientation; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_KERNING: rValue <<= aFD.Kerning; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_WORDLINEMODE: rValue <<= aFD.WordLineMode; + break; + case BASEPROPERTY_FONTDESCRIPTORPART_TYPE: rValue <<= aFD.Type; + break; + default: OSL_FAIL( "FontProperty?!" ); + } + } + else + { + OSL_FAIL( "getFastPropertyValue - invalid Property!" ); + } +} + +// css::beans::XPropertySet +void UnoControlModel::setPropertyValue( const OUString& rPropertyName, const css::uno::Any& rValue ) +{ + sal_Int32 nPropId = 0; + { + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + nPropId = static_cast<sal_Int32>(GetPropertyId( rPropertyName )); + DBG_ASSERT( nPropId, "Invalid ID in UnoControlModel::setPropertyValue" ); + } + if( !nPropId ) + throw css::beans::UnknownPropertyException(rPropertyName); + + setFastPropertyValue( nPropId, rValue ); + +} + +// css::beans::XFastPropertySet +void UnoControlModel::setFastPropertyValue( sal_Int32 nPropId, const css::uno::Any& rValue ) +{ + if ( ( nPropId >= BASEPROPERTY_FONTDESCRIPTORPART_START ) && ( nPropId <= BASEPROPERTY_FONTDESCRIPTORPART_END ) ) + { + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + + Any aOldSingleValue; + getFastPropertyValue( aOldSingleValue, BASEPROPERTY_FONTDESCRIPTORPART_START ); + + css::uno::Any* pProp = &maData[ BASEPROPERTY_FONTDESCRIPTOR ]; + FontDescriptor aOldFontDescriptor; + (*pProp) >>= aOldFontDescriptor; + + FontDescriptor aNewFontDescriptor( aOldFontDescriptor ); + lcl_ImplMergeFontProperty( aNewFontDescriptor, static_cast<sal_uInt16>(nPropId), rValue ); + + Any aNewValue; + aNewValue <<= aNewFontDescriptor; + sal_Int32 nDescriptorId = BASEPROPERTY_FONTDESCRIPTOR; + + // also, we need fire a propertyChange event for the single property, since with + // the above line, only an event for the FontDescriptor property will be fired + Any aNewSingleValue; + getFastPropertyValue( aNewSingleValue, BASEPROPERTY_FONTDESCRIPTORPART_START ); + + aGuard.clear(); + setFastPropertyValues( 1, &nDescriptorId, &aNewValue, 1 ); + fire( &nPropId, &aNewSingleValue, &aOldSingleValue, 1, false ); + } + else + setFastPropertyValues( 1, &nPropId, &rValue, 1 ); +} + +// css::beans::XMultiPropertySet +css::uno::Reference< css::beans::XPropertySetInfo > UnoControlModel::getPropertySetInfo( ) +{ + OSL_FAIL( "UnoControlModel::getPropertySetInfo() not possible!" ); + return css::uno::Reference< css::beans::XPropertySetInfo >(); +} + +void UnoControlModel::setPropertyValues( const css::uno::Sequence< OUString >& rPropertyNames, const css::uno::Sequence< css::uno::Any >& Values ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + + sal_Int32 nProps = rPropertyNames.getLength(); + +// sal_Int32* pHandles = new sal_Int32[nProps]; + // don't do this - it leaks in case of an exception + Sequence< sal_Int32 > aHandles( nProps ); + sal_Int32* pHandles = aHandles.getArray(); + + // may need to change the order in the sequence, for this we need a non-const value sequence + uno::Sequence< uno::Any > aValues( Values ); + uno::Any* pValues = aValues.getArray(); + + sal_Int32 nValidHandles = getInfoHelper().fillHandles( pHandles, rPropertyNames ); + + if ( !nValidHandles ) + return; + + // if somebody sets properties which are single aspects of a font descriptor, + // remove them, and build a font descriptor instead + std::unique_ptr< awt::FontDescriptor > pFD; + for ( sal_Int32 n = 0; n < nProps; ++n ) + { + if ( ( pHandles[n] >= BASEPROPERTY_FONTDESCRIPTORPART_START ) && ( pHandles[n] <= BASEPROPERTY_FONTDESCRIPTORPART_END ) ) + { + if (!pFD) + { + css::uno::Any* pProp = &maData[ BASEPROPERTY_FONTDESCRIPTOR ]; + pFD.reset( new awt::FontDescriptor ); + (*pProp) >>= *pFD; + } + lcl_ImplMergeFontProperty( *pFD, static_cast<sal_uInt16>(pHandles[n]), pValues[n] ); + pHandles[n] = -1; + nValidHandles--; + } + } + + if ( nValidHandles ) + { + ImplNormalizePropertySequence( nProps, pHandles, pValues, &nValidHandles ); + aGuard.clear(); + // clear our guard before calling into setFastPropertyValues - this method + // will implicitly call property listeners, and this should not happen with + // our mutex locked + // #i23451# + setFastPropertyValues( nProps, pHandles, pValues, nValidHandles ); + } + else + aGuard.clear(); + // same as a few lines above + + // Don't merge FD property into array, as it is sorted + if (pFD) + { + css::uno::Any aValue; + aValue <<= *pFD; + sal_Int32 nHandle = BASEPROPERTY_FONTDESCRIPTOR; + setFastPropertyValues( 1, &nHandle, &aValue, 1 ); + } +} + + +void UnoControlModel::ImplNormalizePropertySequence( const sal_Int32, sal_Int32*, + uno::Any*, sal_Int32* ) const +{ + // nothing to do here +} + +void UnoControlModel::ImplEnsureHandleOrder( const sal_Int32 _nCount, sal_Int32* _pHandles, + uno::Any* _pValues, sal_Int32 _nFirstHandle, sal_Int32 _nSecondHandle ) +{ + for ( sal_Int32 i=0; i < _nCount; ++_pHandles, ++_pValues, ++i ) + { + if ( _nSecondHandle == *_pHandles ) + { + sal_Int32* pLaterHandles = _pHandles + 1; + uno::Any* pLaterValues = _pValues + 1; + for ( sal_Int32 j = i + 1; j < _nCount; ++j, ++pLaterHandles, ++pLaterValues ) + { + if ( _nFirstHandle == *pLaterHandles ) + { + // indeed it is -> exchange the both places in the sequences + sal_Int32 nHandle( *_pHandles ); + *_pHandles = *pLaterHandles; + *pLaterHandles = nHandle; + + uno::Any aValue( *_pValues ); + *_pValues = *pLaterValues; + *pLaterValues = aValue; + + break; + // this will leave the inner loop, and continue with the outer loop. + // Note that this means we will encounter the _nSecondHandle handle, again, once we reached + // (in the outer loop) the place where we just put it. + } + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/controls/unocontrols.cxx b/toolkit/source/controls/unocontrols.cxx new file mode 100644 index 000000000..260fc1301 --- /dev/null +++ b/toolkit/source/controls/unocontrols.cxx @@ -0,0 +1,4760 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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/awt/XTextArea.hpp> +#include <com/sun/star/awt/XVclWindowPeer.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/awt/VisualEffect.hpp> +#include <com/sun/star/awt/LineEndFormat.hpp> +#include <com/sun/star/graphic/GraphicProvider.hpp> +#include <com/sun/star/graphic/XGraphicProvider.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/awt/ImageScaleMode.hpp> + +#include <o3tl/safeint.hxx> +#include <controls/formattedcontrol.hxx> +#include <toolkit/controls/unocontrols.hxx> +#include <toolkit/helper/property.hxx> +#include <toolkit/helper/macros.hxx> + +// for introspection +#include <awt/vclxwindows.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <algorithm> + +#include <helper/imagealign.hxx> +#include <helper/unopropertyarrayhelper.hxx> + +using namespace css; +using namespace css::awt; +using namespace css::lang; +using namespace css::uno; +using ::com::sun::star::graphic::XGraphic; +using ::com::sun::star::uno::Reference; +using namespace ::toolkit; + +uno::Reference< graphic::XGraphic > +ImageHelper::getGraphicAndGraphicObjectFromURL_nothrow( uno::Reference< graphic::XGraphicObject >& xOutGraphicObj, const OUString& _rURL ) +{ + xOutGraphicObj = nullptr; + return ImageHelper::getGraphicFromURL_nothrow( _rURL ); +} + +css::uno::Reference< css::graphic::XGraphic > +ImageHelper::getGraphicFromURL_nothrow( const OUString& _rURL ) +{ + uno::Reference< graphic::XGraphic > xGraphic; + if ( _rURL.isEmpty() ) + return xGraphic; + + try + { + uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) ); + xGraphic = xProvider->queryGraphic({ comphelper::makePropertyValue("URL", _rURL) }); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + } + + return xGraphic; +} + + +UnoControlEditModel::UnoControlEditModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXEdit>(); +} + +OUString UnoControlEditModel::getServiceName( ) +{ + return "stardiv.vcl.controlmodel.Edit"; +} + +uno::Any UnoControlEditModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + uno::Any aReturn; + + switch ( nPropId ) + { + case BASEPROPERTY_LINE_END_FORMAT: + aReturn <<= sal_Int16(awt::LineEndFormat::LINE_FEED); // LF + break; + case BASEPROPERTY_DEFAULTCONTROL: + aReturn <<= OUString( "stardiv.vcl.control.Edit" ); + break; + default: + aReturn = UnoControlModel::ImplGetDefaultValue( nPropId ); + break; + } + return aReturn; +} + +::cppu::IPropertyArrayHelper& UnoControlEditModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlEditModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlEditModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlEditModel"; +} + +css::uno::Sequence<OUString> UnoControlEditModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlEditModel", "stardiv.vcl.controlmodel.Edit" }; + return comphelper::concatSequences(UnoControlModel::getSupportedServiceNames(), vals); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlEditModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlEditModel(context)); +} + + + +UnoEditControl::UnoEditControl() + :maTextListeners( *this ) + ,mnMaxTextLen( 0 ) + ,mbSetTextInPeer( false ) + ,mbSetMaxTextLenInPeer( false ) + ,mbHasTextProperty( false ) +{ + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 12; +} + +uno::Any SAL_CALL UnoEditControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aReturn = UnoControlBase::queryAggregation( rType ); + if ( !aReturn.hasValue() ) + aReturn = UnoEditControl_Base::queryInterface( rType ); + return aReturn; +} + +uno::Any SAL_CALL UnoEditControl::queryInterface( const uno::Type & rType ) +{ + return UnoControlBase::queryInterface( rType ); +} + +void SAL_CALL UnoEditControl::acquire( ) noexcept +{ + UnoControlBase::acquire(); +} + +void SAL_CALL UnoEditControl::release( ) noexcept +{ + UnoControlBase::release(); +} + +IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoEditControl, UnoControlBase, UnoEditControl_Base ) + +OUString UnoEditControl::GetComponentServiceName() const +{ + // by default, we want a simple edit field + OUString sName( "Edit" ); + + // but maybe we are to display multi-line text? + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_MULTILINE ) ); + bool b = bool(); + if ( ( aVal >>= b ) && b ) + sName = "MultiLineEdit"; + + return sName; +} + +sal_Bool SAL_CALL UnoEditControl::setModel(const uno::Reference< awt::XControlModel >& _rModel) +{ + bool bReturn = UnoControlBase::setModel( _rModel ); + mbHasTextProperty = ImplHasProperty( BASEPROPERTY_TEXT ); + return bReturn; +} + +void UnoEditControl::ImplSetPeerProperty( const OUString& rPropName, const uno::Any& rVal ) +{ + bool bDone = false; + if ( GetPropertyId( rPropName ) == BASEPROPERTY_TEXT ) + { + // #96986# use setText(), or text listener will not be called. + uno::Reference < awt::XTextComponent > xTextComponent( getPeer(), uno::UNO_QUERY ); + if ( xTextComponent.is() ) + { + OUString sText; + rVal >>= sText; + ImplCheckLocalize( sText ); + xTextComponent->setText( sText ); + bDone = true; + } + } + + if ( !bDone ) + UnoControlBase::ImplSetPeerProperty( rPropName, rVal ); +} + +void UnoEditControl::dispose() +{ + lang::EventObject aEvt( *this ); + maTextListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); +} + +void UnoEditControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference< awt::XTextComponent > xText( getPeer(), uno::UNO_QUERY ); + if ( xText.is() ) + { + xText->addTextListener( this ); + + if ( mbSetMaxTextLenInPeer ) + xText->setMaxTextLen( mnMaxTextLen ); + if ( mbSetTextInPeer ) + xText->setText( maText ); + } +} + +void UnoEditControl::textChanged(const awt::TextEvent& e) +{ + uno::Reference< awt::XTextComponent > xText( getPeer(), uno::UNO_QUERY ); + + if ( mbHasTextProperty ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TEXT ), uno::Any(xText->getText()), false ); + } + else + { + maText = xText->getText(); + } + + if ( maTextListeners.getLength() ) + maTextListeners.textChanged( e ); +} + +void UnoEditControl::addTextListener(const uno::Reference< awt::XTextListener > & l) +{ + // tdf#150974 some extensions pass null + if (!l) + { + SAL_WARN("toolkit", "null XTextListener"); + return; + } + maTextListeners.addInterface( l ); +} + +void UnoEditControl::removeTextListener(const uno::Reference< awt::XTextListener > & l) +{ + // tdf#150974 some extensions pass null + if (!l) + { + SAL_WARN("toolkit", "null XTextListener"); + return; + } + maTextListeners.removeInterface( l ); +} + +void UnoEditControl::setText( const OUString& aText ) +{ + if ( mbHasTextProperty ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TEXT ), uno::Any(aText), true ); + } + else + { + maText = aText; + mbSetTextInPeer = true; + uno::Reference < awt::XTextComponent > xText( getPeer(), uno::UNO_QUERY ); + if ( xText.is() ) + xText->setText( maText ); + } + + // Setting the property to the VCLXWindow doesn't call textChanged + if ( maTextListeners.getLength() ) + { + awt::TextEvent aEvent; + aEvent.Source = *this; + maTextListeners.textChanged( aEvent ); + } +} + +namespace +{ + void lcl_normalize( awt::Selection& _rSel ) + { + if ( _rSel.Min > _rSel.Max ) + ::std::swap( _rSel.Min, _rSel.Max ); + } +} + +void UnoEditControl::insertText( const awt::Selection& rSel, const OUString& rNewText ) +{ + // normalize the selection - OUString::replaceAt has a strange behaviour if the min is greater than the max + awt::Selection aSelection( rSel ); + lcl_normalize( aSelection ); + + OUString aOldText = getText(); + if (aSelection.Min < 0 || aOldText.getLength() < aSelection.Max) + { + throw lang::IllegalArgumentException(); + } + + // preserve the selection resp. cursor position + awt::Selection aNewSelection( getSelection() ); +#ifdef ALSO_PRESERVE_COMPLETE_SELECTION + // (not sure - looks uglier ...) + sal_Int32 nDeletedCharacters = ( aSelection.Max - aSelection.Min ) - rNewText.getLength(); + if ( aNewSelection.Min > aSelection.Min ) + aNewSelection.Min -= nDeletedCharacters; + if ( aNewSelection.Max > aSelection.Max ) + aNewSelection.Max -= nDeletedCharacters; +#else + aNewSelection.Max = ::std::min( aNewSelection.Min, aNewSelection.Max ) + rNewText.getLength(); + aNewSelection.Min = aNewSelection.Max; +#endif + + OUString aNewText = aOldText.replaceAt( aSelection.Min, aSelection.Max - aSelection.Min, rNewText ); + setText( aNewText ); + + setSelection( aNewSelection ); +} + +OUString UnoEditControl::getText() +{ + OUString aText = maText; + + if ( mbHasTextProperty ) + aText = ImplGetPropertyValue_UString( BASEPROPERTY_TEXT ); + else + { + uno::Reference< awt::XTextComponent > xText( getPeer(), uno::UNO_QUERY ); + if ( xText.is() ) + aText = xText->getText(); + } + + return aText; +} + +OUString UnoEditControl::getSelectedText() +{ + OUString sSelected; + uno::Reference< awt::XTextComponent > xText( getPeer(), uno::UNO_QUERY ); + if ( xText.is() ) + sSelected = xText->getSelectedText(); + + return sSelected; +} + +void UnoEditControl::setSelection( const awt::Selection& aSelection ) +{ + uno::Reference< awt::XTextComponent > xText( getPeer(), uno::UNO_QUERY ); + if ( xText.is() ) + xText->setSelection( aSelection ); +} + +awt::Selection UnoEditControl::getSelection() +{ + awt::Selection aSel; + uno::Reference< awt::XTextComponent > xText( getPeer(), uno::UNO_QUERY ); + if ( xText.is() ) + aSel = xText->getSelection(); + return aSel; +} + +sal_Bool UnoEditControl::isEditable() +{ + return !ImplGetPropertyValue_BOOL( BASEPROPERTY_READONLY ); +} + +void UnoEditControl::setEditable( sal_Bool bEditable ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_READONLY ), uno::Any(!bEditable), true ); +} + +sal_Int16 UnoEditControl::getMaxTextLen() +{ + sal_Int16 nMaxLen = mnMaxTextLen; + + if ( ImplHasProperty( BASEPROPERTY_MAXTEXTLEN ) ) + nMaxLen = ImplGetPropertyValue_INT16( BASEPROPERTY_MAXTEXTLEN ); + + return nMaxLen; +} + +void UnoEditControl::setMaxTextLen( sal_Int16 nLen ) +{ + if ( ImplHasProperty( BASEPROPERTY_MAXTEXTLEN) ) + { + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_MAXTEXTLEN ), uno::Any(nLen), true ); + } + else + { + mnMaxTextLen = nLen; + mbSetMaxTextLenInPeer = true; + uno::Reference < awt::XTextComponent > xText( getPeer(), uno::UNO_QUERY ); + if ( xText.is() ) + xText->setMaxTextLen( mnMaxTextLen ); + } +} + +awt::Size UnoEditControl::getMinimumSize( ) +{ + return Impl_getMinimumSize(); +} + +awt::Size UnoEditControl::getPreferredSize( ) +{ + return Impl_getPreferredSize(); +} + +awt::Size UnoEditControl::calcAdjustedSize( const awt::Size& rNewSize ) +{ + return Impl_calcAdjustedSize( rNewSize ); +} + +awt::Size UnoEditControl::getMinimumSize( sal_Int16 nCols, sal_Int16 nLines ) +{ + return Impl_getMinimumSize( nCols, nLines ); +} + +void UnoEditControl::getColumnsAndLines( sal_Int16& nCols, sal_Int16& nLines ) +{ + Impl_getColumnsAndLines( nCols, nLines ); +} + +OUString UnoEditControl::getImplementationName( ) +{ + return "stardiv.Toolkit.UnoEditControl"; +} + +uno::Sequence< OUString > UnoEditControl::getSupportedServiceNames() +{ + css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlEdit", "stardiv.vcl.control.Edit" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames( ), vals); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoEditControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoEditControl()); +} + + + +UnoControlFileControlModel::UnoControlFileControlModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_ALIGN ); + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_READONLY ); + ImplRegisterProperty( BASEPROPERTY_TABSTOP ); + ImplRegisterProperty( BASEPROPERTY_TEXT ); + ImplRegisterProperty( BASEPROPERTY_VERTICALALIGN ); + ImplRegisterProperty( BASEPROPERTY_WRITING_MODE ); + ImplRegisterProperty( BASEPROPERTY_CONTEXT_WRITING_MODE ); + ImplRegisterProperty( BASEPROPERTY_HIDEINACTIVESELECTION ); +} + +OUString UnoControlFileControlModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.FileControl"; +} + +uno::Any UnoControlFileControlModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.FileControl" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlFileControlModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlFileControlModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlFileControlModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlFileControlModel"; +} + +css::uno::Sequence<OUString> +UnoControlFileControlModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlFileControlModel", "stardiv.vcl.controlmodel.FileControl" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlFileControlModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlFileControlModel(context)); +} + + + +UnoFileControl::UnoFileControl() +{ +} + +OUString UnoFileControl::GetComponentServiceName() const +{ + return "filecontrol"; +} + +OUString UnoFileControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoFileControl"; +} + +css::uno::Sequence<OUString> UnoFileControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlFileControl", "stardiv.vcl.control.FileControl" }; + return comphelper::concatSequences( UnoEditControl::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoFileControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoFileControl()); +} + + + +uno::Any GraphicControlModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_GRAPHIC ) + return uno::Any( uno::Reference< graphic::XGraphic >() ); + + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +void SAL_CALL GraphicControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) +{ + UnoControlModel::setFastPropertyValue_NoBroadcast( nHandle, rValue ); + + // - ImageAlign and ImagePosition need to correspond to each other + // - Graphic and ImageURL need to correspond to each other + try + { + switch ( nHandle ) + { + case BASEPROPERTY_IMAGEURL: + if ( !mbAdjustingGraphic && ImplHasProperty( BASEPROPERTY_GRAPHIC ) ) + { + mbAdjustingGraphic = true; + OUString sImageURL; + OSL_VERIFY( rValue >>= sImageURL ); + setDependentFastPropertyValue( BASEPROPERTY_GRAPHIC, uno::Any( ImageHelper::getGraphicFromURL_nothrow( sImageURL ) ) ); + mbAdjustingGraphic = false; + } + break; + + case BASEPROPERTY_GRAPHIC: + if ( !mbAdjustingGraphic && ImplHasProperty( BASEPROPERTY_IMAGEURL ) ) + { + mbAdjustingGraphic = true; + setDependentFastPropertyValue( BASEPROPERTY_IMAGEURL, uno::Any( OUString() ) ); + mbAdjustingGraphic = false; + } + break; + + case BASEPROPERTY_IMAGEALIGN: + if ( !mbAdjustingImagePosition && ImplHasProperty( BASEPROPERTY_IMAGEPOSITION ) ) + { + mbAdjustingImagePosition = true; + sal_Int16 nUNOValue = 0; + OSL_VERIFY( rValue >>= nUNOValue ); + setDependentFastPropertyValue( BASEPROPERTY_IMAGEPOSITION, uno::Any( getExtendedImagePosition( nUNOValue ) ) ); + mbAdjustingImagePosition = false; + } + break; + case BASEPROPERTY_IMAGEPOSITION: + if ( !mbAdjustingImagePosition && ImplHasProperty( BASEPROPERTY_IMAGEALIGN ) ) + { + mbAdjustingImagePosition = true; + sal_Int16 nUNOValue = 0; + OSL_VERIFY( rValue >>= nUNOValue ); + setDependentFastPropertyValue( BASEPROPERTY_IMAGEALIGN, uno::Any( getCompatibleImageAlign( translateImagePosition( nUNOValue ) ) ) ); + mbAdjustingImagePosition = false; + } + break; + } + } + catch( const css::uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("toolkit.controls"); + OSL_FAIL( "GraphicControlModel::setFastPropertyValue_NoBroadcast: caught an exception while aligning the ImagePosition/ImageAlign properties!" ); + mbAdjustingImagePosition = false; + } +} + + + +UnoControlButtonModel::UnoControlButtonModel( const Reference< XComponentContext >& rxContext ) + :GraphicControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXButton>(); + + osl_atomic_increment( &m_refCount ); + { + setFastPropertyValue_NoBroadcast( BASEPROPERTY_IMAGEPOSITION, ImplGetDefaultValue( BASEPROPERTY_IMAGEPOSITION ) ); + // this ensures that our ImagePosition is consistent with our ImageAlign property (since both + // defaults are not per se consistent), since both are coupled in setFastPropertyValue_NoBroadcast + } + osl_atomic_decrement( &m_refCount ); +} + +OUString UnoControlButtonModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.Button"; +} + +uno::Any UnoControlButtonModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + switch ( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + return uno::Any( OUString( "stardiv.vcl.control.Button" ) ); + case BASEPROPERTY_TOGGLE: + return uno::Any( false ); + case BASEPROPERTY_ALIGN: + return uno::Any( sal_Int16(PROPERTY_ALIGN_CENTER) ); + case BASEPROPERTY_FOCUSONCLICK: + return uno::Any( true ); + } + + return GraphicControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlButtonModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlButtonModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlButtonModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlButtonModel"; +} + +css::uno::Sequence<OUString> UnoControlButtonModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlButtonModel", "stardiv.vcl.controlmodel.Button" }; + return comphelper::concatSequences( GraphicControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlButtonModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlButtonModel(context)); +} + + + +UnoButtonControl::UnoButtonControl() + :maActionListeners( *this ) + ,maItemListeners( *this ) +{ + maComponentInfos.nWidth = 50; + maComponentInfos.nHeight = 14; +} + +OUString UnoButtonControl::GetComponentServiceName() const +{ + OUString aName( "pushbutton" ); + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_PUSHBUTTONTYPE ) ); + sal_Int16 n = sal_Int16(); + if ( ( aVal >>= n ) && n ) + { + // Use PushButtonType later when available... + switch ( n ) + { + case 1 /*PushButtonType::OK*/: aName = "okbutton"; + break; + case 2 /*PushButtonType::CANCEL*/: aName = "cancelbutton"; + break; + case 3 /*PushButtonType::HELP*/: aName = "helpbutton"; + break; + default: + { + OSL_FAIL( "Unknown Button Type!" ); + } + } + } + return aName; +} + +void UnoButtonControl::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maActionListeners.disposeAndClear( aEvt ); + maItemListeners.disposeAndClear( aEvt ); + UnoControlBase::dispose(); +} + +void UnoButtonControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControlBase::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->setActionCommand( maActionCommand ); + if ( maActionListeners.getLength() ) + xButton->addActionListener( &maActionListeners ); + + uno::Reference< XToggleButton > xPushButton( getPeer(), uno::UNO_QUERY ); + if ( xPushButton.is() ) + xPushButton->addItemListener( this ); +} + +void UnoButtonControl::addActionListener(const uno::Reference< awt::XActionListener > & l) +{ + // tdf#150974 some extensions pass null + if (!l) + { + SAL_WARN("toolkit", "null XActionListener"); + return; + } + + maActionListeners.addInterface( l ); + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->addActionListener( &maActionListeners ); + } +} + +void UnoButtonControl::removeActionListener(const uno::Reference< awt::XActionListener > & l) +{ + // tdf#150974 some extensions pass null + if (!l) + { + SAL_WARN("toolkit", "null XActionListener"); + return; + } + + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->removeActionListener( &maActionListeners ); + } + maActionListeners.removeInterface( l ); +} + +void UnoButtonControl::addItemListener(const uno::Reference< awt::XItemListener > & l) +{ + maItemListeners.addInterface( l ); +} + +void UnoButtonControl::removeItemListener(const uno::Reference< awt::XItemListener > & l) +{ + maItemListeners.removeInterface( l ); +} + +void SAL_CALL UnoButtonControl::disposing( const lang::EventObject& Source ) +{ + UnoControlBase::disposing( Source ); +} + +void SAL_CALL UnoButtonControl::itemStateChanged( const awt::ItemEvent& rEvent ) +{ + // forward to model + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STATE ), uno::Any(static_cast<sal_Int16>(rEvent.Selected)), false ); + + // multiplex + ItemEvent aEvent( rEvent ); + aEvent.Source = *this; + maItemListeners.itemStateChanged( aEvent ); +} + +void UnoButtonControl::setLabel( const OUString& rLabel ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LABEL ), uno::Any(rLabel), true ); +} + +void UnoButtonControl::setActionCommand( const OUString& rCommand ) +{ + maActionCommand = rCommand; + if ( getPeer().is() ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->setActionCommand( rCommand ); + } +} + +awt::Size UnoButtonControl::getMinimumSize( ) +{ + return Impl_getMinimumSize(); +} + +awt::Size UnoButtonControl::getPreferredSize( ) +{ + return Impl_getPreferredSize(); +} + +awt::Size UnoButtonControl::calcAdjustedSize( const awt::Size& rNewSize ) +{ + return Impl_calcAdjustedSize( rNewSize ); +} + +OUString UnoButtonControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoButtonControl"; +} + +css::uno::Sequence<OUString> UnoButtonControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlButton", "stardiv.vcl.control.Button" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoButtonControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoButtonControl()); +} + + + +UnoControlImageControlModel::UnoControlImageControlModel( const Reference< XComponentContext >& rxContext ) + :GraphicControlModel( rxContext ) + ,mbAdjustingImageScaleMode( false ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXImageControl>(); +} + +OUString UnoControlImageControlModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.ImageControl"; +} + +OUString UnoControlImageControlModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlImageControlModel"; +} + +css::uno::Sequence<OUString> +UnoControlImageControlModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { + "com.sun.star.awt.UnoControlImageButtonModel", + "com.sun.star.awt.UnoControlImageControlModel", + "stardiv.vcl.controlmodel.ImageButton", + "stardiv.vcl.controlmodel.ImageControl" + }; + return comphelper::concatSequences( GraphicControlModel::getSupportedServiceNames(), vals); +} + +uno::Any UnoControlImageControlModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + return uno::Any( OUString( "stardiv.vcl.control.ImageControl" ) ); + + if ( nPropId == BASEPROPERTY_IMAGE_SCALE_MODE ) + return Any( awt::ImageScaleMode::ANISOTROPIC ); + + return GraphicControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlImageControlModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlImageControlModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +void SAL_CALL UnoControlImageControlModel::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const css::uno::Any& _rValue ) +{ + GraphicControlModel::setFastPropertyValue_NoBroadcast( _nHandle, _rValue ); + + // ScaleImage is an older (and less powerful) version of ScaleMode, but keep both in sync as far as possible + try + { + switch ( _nHandle ) + { + case BASEPROPERTY_IMAGE_SCALE_MODE: + if ( !mbAdjustingImageScaleMode && ImplHasProperty( BASEPROPERTY_SCALEIMAGE ) ) + { + mbAdjustingImageScaleMode = true; + sal_Int16 nScaleMode( awt::ImageScaleMode::ANISOTROPIC ); + OSL_VERIFY( _rValue >>= nScaleMode ); + setDependentFastPropertyValue( BASEPROPERTY_SCALEIMAGE, uno::Any( nScaleMode != awt::ImageScaleMode::NONE ) ); + mbAdjustingImageScaleMode = false; + } + break; + case BASEPROPERTY_SCALEIMAGE: + if ( !mbAdjustingImageScaleMode && ImplHasProperty( BASEPROPERTY_IMAGE_SCALE_MODE ) ) + { + mbAdjustingImageScaleMode = true; + bool bScale = true; + OSL_VERIFY( _rValue >>= bScale ); + setDependentFastPropertyValue( BASEPROPERTY_IMAGE_SCALE_MODE, uno::Any( bScale ? awt::ImageScaleMode::ANISOTROPIC : awt::ImageScaleMode::NONE ) ); + mbAdjustingImageScaleMode = false; + } + break; + } + } + catch( const Exception& ) + { + mbAdjustingImageScaleMode = false; + throw; + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlImageControlModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlImageControlModel(context)); +} + + + +UnoImageControlControl::UnoImageControlControl() + :maActionListeners( *this ) +{ + // TODO: Where should I look for defaults? + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 100; +} + +OUString UnoImageControlControl::GetComponentServiceName() const +{ + return "fixedimage"; +} + +void UnoImageControlControl::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maActionListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); +} + +sal_Bool UnoImageControlControl::isTransparent() +{ + return true; +} + +awt::Size UnoImageControlControl::getMinimumSize( ) +{ + return Impl_getMinimumSize(); +} + +awt::Size UnoImageControlControl::getPreferredSize( ) +{ + return Impl_getPreferredSize(); +} + +awt::Size UnoImageControlControl::calcAdjustedSize( const awt::Size& rNewSize ) +{ + return Impl_calcAdjustedSize( rNewSize ); +} + +OUString UnoImageControlControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoImageControlControl"; +} + +css::uno::Sequence<OUString> UnoImageControlControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { + "com.sun.star.awt.UnoControlImageButton", + "com.sun.star.awt.UnoControlImageControl", + "stardiv.vcl.control.ImageButton", + "stardiv.vcl.control.ImageControl" + }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoImageControlControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoImageControlControl()); +} + + + +UnoControlRadioButtonModel::UnoControlRadioButtonModel( const Reference< XComponentContext >& rxContext ) + :GraphicControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXRadioButton>(); +} + +OUString UnoControlRadioButtonModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.RadioButton"; +} + +uno::Any UnoControlRadioButtonModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + switch ( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + return uno::Any( OUString( "stardiv.vcl.control.RadioButton" ) ); + + case BASEPROPERTY_VISUALEFFECT: + return uno::Any( sal_Int16(awt::VisualEffect::LOOK3D) ); + } + + return GraphicControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlRadioButtonModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlRadioButtonModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlRadioButtonModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlRadioButtonModel"; +} + +css::uno::Sequence<OUString> +UnoControlRadioButtonModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlRadioButtonModel", "stardiv.vcl.controlmodel.RadioButton" }; + return comphelper::concatSequences( GraphicControlModel::getSupportedServiceNames(), vals); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlRadioButtonModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlRadioButtonModel(context)); +} + + + +UnoRadioButtonControl::UnoRadioButtonControl() + :maItemListeners( *this ) + ,maActionListeners( *this ) +{ + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 12; +} + +OUString UnoRadioButtonControl::GetComponentServiceName() const +{ + return "radiobutton"; +} + +void UnoRadioButtonControl::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maItemListeners.disposeAndClear( aEvt ); + UnoControlBase::dispose(); +} + + +sal_Bool UnoRadioButtonControl::isTransparent() +{ + return true; +} + +void UnoRadioButtonControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControlBase::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XRadioButton > xRadioButton( getPeer(), uno::UNO_QUERY ); + xRadioButton->addItemListener( this ); + + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->setActionCommand( maActionCommand ); + if ( maActionListeners.getLength() ) + xButton->addActionListener( &maActionListeners ); + + // as default, set the "AutoToggle" to true + // (it is set to false in VCLXToolkit::ImplCreateWindow because of #87254#, but we want to + // have it enabled by default because of 85071) + uno::Reference< awt::XVclWindowPeer > xVclWindowPeer( getPeer(), uno::UNO_QUERY ); + if ( xVclWindowPeer.is() ) + xVclWindowPeer->setProperty( GetPropertyName( BASEPROPERTY_AUTOTOGGLE ), css::uno::Any(true) ); +} + +void UnoRadioButtonControl::addItemListener(const uno::Reference < awt::XItemListener > & l) +{ + maItemListeners.addInterface( l ); +} + +void UnoRadioButtonControl::removeItemListener(const uno::Reference < awt::XItemListener > & l) +{ + maItemListeners.removeInterface( l ); +} + +void UnoRadioButtonControl::addActionListener(const uno::Reference< awt::XActionListener > & l) +{ + maActionListeners.addInterface( l ); + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->addActionListener( &maActionListeners ); + } +} + +void UnoRadioButtonControl::removeActionListener(const uno::Reference< awt::XActionListener > & l) +{ + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->removeActionListener( &maActionListeners ); + } + maActionListeners.removeInterface( l ); +} + +void UnoRadioButtonControl::setLabel( const OUString& rLabel ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LABEL ), uno::Any(rLabel), true ); +} + +void UnoRadioButtonControl::setActionCommand( const OUString& rCommand ) +{ + maActionCommand = rCommand; + if ( getPeer().is() ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->setActionCommand( rCommand ); + } +} + +void UnoRadioButtonControl::setState( sal_Bool bOn ) +{ + sal_Int16 nState = bOn ? 1 : 0; + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STATE ), uno::Any(nState), true ); +} + +sal_Bool UnoRadioButtonControl::getState() +{ + sal_Int16 nState = 0; + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STATE ) ); + aVal >>= nState; + return nState != 0; +} + +void UnoRadioButtonControl::itemStateChanged( const awt::ItemEvent& rEvent ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STATE ), uno::Any(static_cast<sal_Int16>(rEvent.Selected)), false ); + + // compatibility: + // in OOo 1.0.x, when the user clicked a radio button in a group of buttons, this resulted + // in _one_ itemStateChanged call for exactly the radio button which's state changed from + // "0" to "1". + // Nowadays, since the listener handling changed a lot towards 1.1 (the VCLXWindow reacts on more + // basic events from the VCL-windows, not anymore on the Link-based events like in 1.0.x), this + // isn't the case anymore: For instance, this method here gets called for the radio button + // which is being implicitly _de_selected, too. This is pretty bad for compatibility. + // Thus, we suppress all events with a new state other than "1". This is unlogical, and weird, when looking + // from a pure API perspective, but it's _compatible_ with older product versions, and this is + // all which matters here. + // #i14703# + if ( 1 == rEvent.Selected ) + { + if ( maItemListeners.getLength() ) + maItemListeners.itemStateChanged( rEvent ); + } + // note that speaking strictly, this is wrong: When in 1.0.x, the user would have de-selected + // a radio button _without_ selecting another one, this would have caused a notification. + // With the change done here, this today won't cause a notification anymore. + + // Fortunately, it's not possible for the user to de-select a radio button without selecting another on, + // at least not via the regular UI. It _would_ be possible via the Accessibility API, which + // counts as "user input", too. But in 1.0.x, there was no Accessibility API, so there is nothing + // to be inconsistent with. +} + +awt::Size UnoRadioButtonControl::getMinimumSize( ) +{ + return Impl_getMinimumSize(); +} + +awt::Size UnoRadioButtonControl::getPreferredSize( ) +{ + return Impl_getPreferredSize(); +} + +awt::Size UnoRadioButtonControl::calcAdjustedSize( const awt::Size& rNewSize ) +{ + return Impl_calcAdjustedSize( rNewSize ); +} + +OUString UnoRadioButtonControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoRadioButtonControl"; +} + +css::uno::Sequence<OUString> UnoRadioButtonControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlRadioButton", "stardiv.vcl.control.RadioButton" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoRadioButtonControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoRadioButtonControl()); +} + + + +UnoControlCheckBoxModel::UnoControlCheckBoxModel( const Reference< XComponentContext >& rxContext ) + :GraphicControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXCheckBox>(); +} + +OUString UnoControlCheckBoxModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.CheckBox"; +} + +uno::Any UnoControlCheckBoxModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + switch ( nPropId ) + { + case BASEPROPERTY_DEFAULTCONTROL: + return uno::Any( OUString( "stardiv.vcl.control.CheckBox" ) ); + + case BASEPROPERTY_VISUALEFFECT: + return uno::Any( sal_Int16(awt::VisualEffect::LOOK3D) ); + } + + return GraphicControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlCheckBoxModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlCheckBoxModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlCheckBoxModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlCheckBoxModel"; +} + +css::uno::Sequence<OUString> UnoControlCheckBoxModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlCheckBoxModel", "stardiv.vcl.controlmodel.CheckBox" }; + return comphelper::concatSequences( GraphicControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlCheckBoxModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlCheckBoxModel(context)); +} + + + +UnoCheckBoxControl::UnoCheckBoxControl() + :maItemListeners( *this ), maActionListeners( *this ) +{ + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 12; +} + +OUString UnoCheckBoxControl::GetComponentServiceName() const +{ + return "checkbox"; +} + +void UnoCheckBoxControl::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maItemListeners.disposeAndClear( aEvt ); + UnoControlBase::dispose(); +} + +sal_Bool UnoCheckBoxControl::isTransparent() +{ + return true; +} + +void UnoCheckBoxControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControlBase::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XCheckBox > xCheckBox( getPeer(), uno::UNO_QUERY ); + xCheckBox->addItemListener( this ); + + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->setActionCommand( maActionCommand ); + if ( maActionListeners.getLength() ) + xButton->addActionListener( &maActionListeners ); +} + +void UnoCheckBoxControl::addItemListener(const uno::Reference < awt::XItemListener > & l) +{ + maItemListeners.addInterface( l ); +} + +void UnoCheckBoxControl::removeItemListener(const uno::Reference < awt::XItemListener > & l) +{ + maItemListeners.removeInterface( l ); +} + +void UnoCheckBoxControl::addActionListener(const uno::Reference< awt::XActionListener > & l) +{ + maActionListeners.addInterface( l ); + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->addActionListener( &maActionListeners ); + } +} + +void UnoCheckBoxControl::removeActionListener(const uno::Reference< awt::XActionListener > & l) +{ + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->removeActionListener( &maActionListeners ); + } + maActionListeners.removeInterface( l ); +} + +void UnoCheckBoxControl::setActionCommand( const OUString& rCommand ) +{ + maActionCommand = rCommand; + if ( getPeer().is() ) + { + uno::Reference < awt::XButton > xButton( getPeer(), uno::UNO_QUERY ); + xButton->setActionCommand( rCommand ); + } +} + + +void UnoCheckBoxControl::setLabel( const OUString& rLabel ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LABEL ), uno::Any(rLabel), true ); +} + +void UnoCheckBoxControl::setState( sal_Int16 n ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STATE ), uno::Any(n), true ); +} + +sal_Int16 UnoCheckBoxControl::getState() +{ + sal_Int16 nState = 0; + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STATE ) ); + aVal >>= nState; + return nState; +} + +void UnoCheckBoxControl::enableTriState( sal_Bool b ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TRISTATE ), uno::Any(b), true ); +} + +void UnoCheckBoxControl::itemStateChanged( const awt::ItemEvent& rEvent ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STATE ), uno::Any(static_cast<sal_Int16>(rEvent.Selected)), false ); + + if ( maItemListeners.getLength() ) + maItemListeners.itemStateChanged( rEvent ); +} + +awt::Size UnoCheckBoxControl::getMinimumSize( ) +{ + return Impl_getMinimumSize(); +} + +awt::Size UnoCheckBoxControl::getPreferredSize( ) +{ + return Impl_getPreferredSize(); +} + +awt::Size UnoCheckBoxControl::calcAdjustedSize( const awt::Size& rNewSize ) +{ + return Impl_calcAdjustedSize( rNewSize ); +} + +OUString UnoCheckBoxControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoCheckBoxControl"; +} + +css::uno::Sequence<OUString> UnoCheckBoxControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlCheckBox", "stardiv.vcl.control.CheckBox" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoCheckBoxControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoCheckBoxControl()); +} + + + +UnoControlFixedHyperlinkModel::UnoControlFixedHyperlinkModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXFixedHyperlink>(); +} + +OUString UnoControlFixedHyperlinkModel::getServiceName() +{ + return "com.sun.star.awt.UnoControlFixedHyperlinkModel"; +} + +uno::Any UnoControlFixedHyperlinkModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "com.sun.star.awt.UnoControlFixedHyperlink" ) ); + } + else if ( nPropId == BASEPROPERTY_BORDER ) + { + return uno::Any(sal_Int16(0)); + } + else if ( nPropId == BASEPROPERTY_URL ) + { + return uno::Any( OUString() ); + } + + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlFixedHyperlinkModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlFixedHyperlinkModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlFixedHyperlinkModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlFixedHyperlinkModel(context)); +} + + + +UnoFixedHyperlinkControl::UnoFixedHyperlinkControl() + :maActionListeners( *this ) +{ + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 12; +} + +OUString UnoFixedHyperlinkControl::GetComponentServiceName() const +{ + return "fixedhyperlink"; +} + +// uno::XInterface +uno::Any UnoFixedHyperlinkControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XFixedHyperlink* >(this), + static_cast< awt::XLayoutConstrains* >(this) ); + return (aRet.hasValue() ? aRet : UnoControlBase::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoFixedHyperlinkControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoFixedHyperlinkControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XFixedHyperlink>::get(), + cppu::UnoType<awt::XLayoutConstrains>::get(), + UnoControlBase::getTypes() + ); + return aTypeList.getTypes(); +} + +sal_Bool UnoFixedHyperlinkControl::isTransparent() +{ + return true; +} + +void UnoFixedHyperlinkControl::setText( const OUString& Text ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LABEL ), uno::Any(Text), true ); +} + +OUString UnoFixedHyperlinkControl::getText() +{ + return ImplGetPropertyValue_UString( BASEPROPERTY_LABEL ); +} + +void UnoFixedHyperlinkControl::setURL( const OUString& URL ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_URL ), uno::Any(URL), true ); +} + +OUString UnoFixedHyperlinkControl::getURL( ) +{ + return ImplGetPropertyValue_UString( BASEPROPERTY_URL ); +} + +void UnoFixedHyperlinkControl::setAlignment( sal_Int16 nAlign ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_ALIGN ), uno::Any(nAlign), true ); +} + +sal_Int16 UnoFixedHyperlinkControl::getAlignment() +{ + sal_Int16 nAlign = 0; + if ( mxModel.is() ) + { + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_ALIGN ) ); + aVal >>= nAlign; + } + return nAlign; +} + +awt::Size UnoFixedHyperlinkControl::getMinimumSize( ) +{ + return Impl_getMinimumSize(); +} + +awt::Size UnoFixedHyperlinkControl::getPreferredSize( ) +{ + return Impl_getPreferredSize(); +} + +awt::Size UnoFixedHyperlinkControl::calcAdjustedSize( const awt::Size& rNewSize ) +{ + return Impl_calcAdjustedSize( rNewSize ); +} + +void UnoFixedHyperlinkControl::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maActionListeners.disposeAndClear( aEvt ); + UnoControlBase::dispose(); +} + +void UnoFixedHyperlinkControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControlBase::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XFixedHyperlink > xFixedHyperlink( getPeer(), uno::UNO_QUERY ); + if ( maActionListeners.getLength() ) + xFixedHyperlink->addActionListener( &maActionListeners ); +} + +void UnoFixedHyperlinkControl::addActionListener(const uno::Reference< awt::XActionListener > & l) +{ + maActionListeners.addInterface( l ); + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XFixedHyperlink > xFixedHyperlink( getPeer(), uno::UNO_QUERY ); + xFixedHyperlink->addActionListener( &maActionListeners ); + } +} + +void UnoFixedHyperlinkControl::removeActionListener(const uno::Reference< awt::XActionListener > & l) +{ + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XFixedHyperlink > xFixedHyperlink( getPeer(), uno::UNO_QUERY ); + xFixedHyperlink->removeActionListener( &maActionListeners ); + } + maActionListeners.removeInterface( l ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoFixedHyperlinkControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoFixedHyperlinkControl()); +} + + + +UnoControlFixedTextModel::UnoControlFixedTextModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXFixedText>(); +} + +OUString UnoControlFixedTextModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.FixedText"; +} + +uno::Any UnoControlFixedTextModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.FixedText" ) ); + } + else if ( nPropId == BASEPROPERTY_BORDER ) + { + return uno::Any(sal_Int16(0)); + } + + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlFixedTextModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlFixedTextModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlFixedTextModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlFixedTextModel"; +} + +css::uno::Sequence<OUString> +UnoControlFixedTextModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlFixedTextModel", "stardiv.vcl.controlmodel.FixedText" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlFixedTextModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlFixedTextModel(context)); +} + + + +UnoFixedTextControl::UnoFixedTextControl() +{ + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 12; +} + +OUString UnoFixedTextControl::GetComponentServiceName() const +{ + return "fixedtext"; +} + +// uno::XInterface +uno::Any UnoFixedTextControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XFixedText* >(this), + static_cast< awt::XLayoutConstrains* >(this) ); + return (aRet.hasValue() ? aRet : UnoControlBase::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoFixedTextControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoFixedTextControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XFixedText>::get(), + cppu::UnoType<awt::XLayoutConstrains>::get(), + UnoControlBase::getTypes() + ); + return aTypeList.getTypes(); +} + +sal_Bool UnoFixedTextControl::isTransparent() +{ + return true; +} + +void UnoFixedTextControl::setText( const OUString& Text ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LABEL ), uno::Any(Text), true ); +} + +OUString UnoFixedTextControl::getText() +{ + return ImplGetPropertyValue_UString( BASEPROPERTY_LABEL ); +} + +void UnoFixedTextControl::setAlignment( sal_Int16 nAlign ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_ALIGN ), uno::Any(nAlign), true ); +} + +sal_Int16 UnoFixedTextControl::getAlignment() +{ + sal_Int16 nAlign = 0; + if ( mxModel.is() ) + { + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_ALIGN ) ); + aVal >>= nAlign; + } + return nAlign; +} + +awt::Size UnoFixedTextControl::getMinimumSize( ) +{ + return Impl_getMinimumSize(); +} + +awt::Size UnoFixedTextControl::getPreferredSize( ) +{ + return Impl_getPreferredSize(); +} + +awt::Size UnoFixedTextControl::calcAdjustedSize( const awt::Size& rNewSize ) +{ + return Impl_calcAdjustedSize( rNewSize ); +} + +OUString UnoFixedTextControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoFixedTextControl"; +} + +css::uno::Sequence<OUString> UnoFixedTextControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlFixedText", "stardiv.vcl.control.FixedText" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoFixedTextControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoFixedTextControl()); +} + + + +UnoControlGroupBoxModel::UnoControlGroupBoxModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_LABEL ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_WRITING_MODE ); + ImplRegisterProperty( BASEPROPERTY_CONTEXT_WRITING_MODE ); +} + +OUString UnoControlGroupBoxModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.GroupBox"; +} + +uno::Any UnoControlGroupBoxModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any(OUString( "stardiv.vcl.control.GroupBox" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlGroupBoxModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlGroupBoxModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlGroupBoxModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlGroupBoxModel"; +} + +css::uno::Sequence<OUString> UnoControlGroupBoxModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlGroupBoxModel", "stardiv.vcl.controlmodel.GroupBox" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlGroupBoxModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlGroupBoxModel(context)); +} + + + +UnoGroupBoxControl::UnoGroupBoxControl() +{ + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 100; +} + +OUString UnoGroupBoxControl::GetComponentServiceName() const +{ + return "groupbox"; +} + +sal_Bool UnoGroupBoxControl::isTransparent() +{ + return true; +} + +OUString UnoGroupBoxControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoGroupBoxControl"; +} + +css::uno::Sequence<OUString> UnoGroupBoxControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlGroupBox", "stardiv.vcl.control.GroupBox" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoGroupBoxControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoGroupBoxControl()); +} + + +// = UnoControlListBoxModel_Data + +namespace { + +struct ListItem +{ + OUString ItemText; + OUString ItemImageURL; + Any ItemData; + + ListItem() + { + } + + explicit ListItem( const OUString& i_rItemText ) + :ItemText( i_rItemText ) + { + } +}; + +} + +typedef beans::Pair< OUString, OUString > UnoListItem; + +namespace { + +struct StripItemData +{ + UnoListItem operator()( const ListItem& i_rItem ) + { + return UnoListItem( i_rItem.ItemText, i_rItem.ItemImageURL ); + } +}; + +} + +struct UnoControlListBoxModel_Data +{ + explicit UnoControlListBoxModel_Data( UnoControlListBoxModel& i_rAntiImpl ) + :m_bSettingLegacyProperty( false ) + ,m_rAntiImpl( i_rAntiImpl ) + { + } + + sal_Int32 getItemCount() const { return sal_Int32( m_aListItems.size() ); } + + const ListItem& getItem( const sal_Int32 i_nIndex ) const + { + if ( ( i_nIndex < 0 ) || ( o3tl::make_unsigned(i_nIndex) >= m_aListItems.size() ) ) + throw IndexOutOfBoundsException( OUString(), m_rAntiImpl ); + return m_aListItems[ i_nIndex ]; + } + + ListItem& getItem( const sal_Int32 i_nIndex ) + { + return const_cast< ListItem& >( static_cast< const UnoControlListBoxModel_Data* >( this )->getItem( i_nIndex ) ); + } + + ListItem& insertItem( const sal_Int32 i_nIndex ) + { + if ( ( i_nIndex < 0 ) || ( o3tl::make_unsigned(i_nIndex) > m_aListItems.size() ) ) + throw IndexOutOfBoundsException( OUString(), m_rAntiImpl ); + return *m_aListItems.insert( m_aListItems.begin() + i_nIndex, ListItem() ); + } + + Sequence< UnoListItem > getAllItems() const + { + Sequence< UnoListItem > aItems( sal_Int32( m_aListItems.size() ) ); + ::std::transform( m_aListItems.begin(), m_aListItems.end(), aItems.getArray(), StripItemData() ); + return aItems; + } + + void copyItems( const UnoControlListBoxModel_Data& i_copySource ) + { + m_aListItems = i_copySource.m_aListItems; + } + + void setAllItems( ::std::vector< ListItem >&& i_rItems ) + { + m_aListItems = std::move(i_rItems); + } + + void removeItem( const sal_Int32 i_nIndex ) + { + if ( ( i_nIndex < 0 ) || ( o3tl::make_unsigned(i_nIndex) >= m_aListItems.size() ) ) + throw IndexOutOfBoundsException( OUString(), m_rAntiImpl ); + m_aListItems.erase( m_aListItems.begin() + i_nIndex ); + } + + void removeAllItems() + { + std::vector<ListItem>().swap(m_aListItems); + } + +public: + bool m_bSettingLegacyProperty; + +private: + UnoControlListBoxModel& m_rAntiImpl; + ::std::vector< ListItem > m_aListItems; +}; + + +// = UnoControlListBoxModel + + +UnoControlListBoxModel::UnoControlListBoxModel( const Reference< XComponentContext >& rxContext, ConstructorMode const i_mode ) + :UnoControlListBoxModel_Base( rxContext ) + ,m_xData( new UnoControlListBoxModel_Data( *this ) ) + ,m_aItemListListeners( GetMutex() ) +{ + if ( i_mode == ConstructDefault ) + { + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXListBox>(); + } +} + +UnoControlListBoxModel::UnoControlListBoxModel( const UnoControlListBoxModel& i_rSource ) + :UnoControlListBoxModel_Base( i_rSource ) + ,m_xData( new UnoControlListBoxModel_Data( *this ) ) + ,m_aItemListListeners( GetMutex() ) +{ + m_xData->copyItems( *i_rSource.m_xData ); +} +UnoControlListBoxModel::~UnoControlListBoxModel() +{ +} + +OUString UnoControlListBoxModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlListBoxModel"; +} + +css::uno::Sequence<OUString> UnoControlListBoxModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlListBoxModel", "stardiv.vcl.controlmodel.ListBox" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +OUString UnoControlListBoxModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.ListBox"; +} + + +uno::Any UnoControlListBoxModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.ListBox" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + + +::cppu::IPropertyArrayHelper& UnoControlListBoxModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlListBoxModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + + +namespace +{ + struct CreateListItem + { + ListItem operator()( const OUString& i_rItemText ) + { + return ListItem( i_rItemText ); + } + }; +} + + +void SAL_CALL UnoControlListBoxModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const uno::Any& rValue ) +{ + UnoControlModel::setFastPropertyValue_NoBroadcast( nHandle, rValue ); + + if ( nHandle != BASEPROPERTY_STRINGITEMLIST ) + return; + + // reset selection + uno::Sequence<sal_Int16> aSeq; + setDependentFastPropertyValue( BASEPROPERTY_SELECTEDITEMS, uno::Any(aSeq) ); + + if ( m_xData->m_bSettingLegacyProperty ) + return; + + // synchronize the legacy StringItemList property with our list items + Sequence< OUString > aStringItemList; + Any aPropValue; + getFastPropertyValue( aPropValue, BASEPROPERTY_STRINGITEMLIST ); + OSL_VERIFY( aPropValue >>= aStringItemList ); + + ::std::vector< ListItem > aItems( aStringItemList.getLength() ); + ::std::transform( + std::cbegin(aStringItemList), + std::cend(aStringItemList), + aItems.begin(), + CreateListItem() + ); + m_xData->setAllItems( std::move(aItems) ); + + // since an XItemListListener does not have a "all items modified" or some such method, + // we simulate this by notifying removal of all items, followed by insertion of all new + // items + lang::EventObject aEvent; + aEvent.Source = *this; + m_aItemListListeners.notifyEach( &XItemListListener::itemListChanged, aEvent ); + // TODO: OPropertySetHelper calls into this method with the mutex locked ... + // which is wrong for the above notifications ... +} + + +void UnoControlListBoxModel::ImplNormalizePropertySequence( const sal_Int32 _nCount, sal_Int32* _pHandles, + uno::Any* _pValues, sal_Int32* _pValidHandles ) const +{ + // dependencies we know: + // BASEPROPERTY_STRINGITEMLIST->BASEPROPERTY_SELECTEDITEMS + ImplEnsureHandleOrder( _nCount, _pHandles, _pValues, BASEPROPERTY_STRINGITEMLIST, BASEPROPERTY_SELECTEDITEMS ); + // BASEPROPERTY_STRINGITEMLIST->BASEPROPERTY_TYPEDITEMLIST + ImplEnsureHandleOrder( _nCount, _pHandles, _pValues, BASEPROPERTY_STRINGITEMLIST, BASEPROPERTY_TYPEDITEMLIST ); + + UnoControlModel::ImplNormalizePropertySequence( _nCount, _pHandles, _pValues, _pValidHandles ); +} + + +::sal_Int32 SAL_CALL UnoControlListBoxModel::getItemCount() +{ + ::osl::MutexGuard aGuard( GetMutex() ); + return m_xData->getItemCount(); +} + + +void SAL_CALL UnoControlListBoxModel::insertItem( ::sal_Int32 i_nPosition, const OUString& i_rItemText, const OUString& i_rItemImageURL ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // SYNCHRONIZED -----> + ListItem& rItem( m_xData->insertItem( i_nPosition ) ); + rItem.ItemText = i_rItemText; + rItem.ItemImageURL = i_rItemImageURL; + + impl_handleInsert( i_nPosition, i_rItemText, i_rItemImageURL, aGuard ); + // <----- SYNCHRONIZED +} + + +void SAL_CALL UnoControlListBoxModel::insertItemText( ::sal_Int32 i_nPosition, const OUString& i_rItemText ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // SYNCHRONIZED -----> + ListItem& rItem( m_xData->insertItem( i_nPosition ) ); + rItem.ItemText = i_rItemText; + + impl_handleInsert( i_nPosition, i_rItemText, ::std::optional< OUString >(), aGuard ); + // <----- SYNCHRONIZED +} + + +void SAL_CALL UnoControlListBoxModel::insertItemImage( ::sal_Int32 i_nPosition, const OUString& i_rItemImageURL ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // SYNCHRONIZED -----> + ListItem& rItem( m_xData->insertItem( i_nPosition ) ); + rItem.ItemImageURL = i_rItemImageURL; + + impl_handleInsert( i_nPosition, ::std::optional< OUString >(), i_rItemImageURL, aGuard ); + // <----- SYNCHRONIZED +} + + +void SAL_CALL UnoControlListBoxModel::removeItem( ::sal_Int32 i_nPosition ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // SYNCHRONIZED -----> + m_xData->removeItem( i_nPosition ); + + impl_handleRemove( i_nPosition, aGuard ); + // <----- SYNCHRONIZED +} + + +void SAL_CALL UnoControlListBoxModel::removeAllItems( ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // SYNCHRONIZED -----> + m_xData->removeAllItems(); + + impl_handleRemove( -1, aGuard ); + // <----- SYNCHRONIZED +} + + +void SAL_CALL UnoControlListBoxModel::setItemText( ::sal_Int32 i_nPosition, const OUString& i_rItemText ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // SYNCHRONIZED -----> + ListItem& rItem( m_xData->getItem( i_nPosition ) ); + rItem.ItemText = i_rItemText; + + impl_handleModify( i_nPosition, i_rItemText, ::std::optional< OUString >(), aGuard ); + // <----- SYNCHRONIZED +} + + +void SAL_CALL UnoControlListBoxModel::setItemImage( ::sal_Int32 i_nPosition, const OUString& i_rItemImageURL ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // SYNCHRONIZED -----> + ListItem& rItem( m_xData->getItem( i_nPosition ) ); + rItem.ItemImageURL = i_rItemImageURL; + + impl_handleModify( i_nPosition, ::std::optional< OUString >(), i_rItemImageURL, aGuard ); + // <----- SYNCHRONIZED +} + + +void SAL_CALL UnoControlListBoxModel::setItemTextAndImage( ::sal_Int32 i_nPosition, const OUString& i_rItemText, const OUString& i_rItemImageURL ) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + // SYNCHRONIZED -----> + ListItem& rItem( m_xData->getItem( i_nPosition ) ); + rItem.ItemText = i_rItemText; + rItem.ItemImageURL = i_rItemImageURL; + + impl_handleModify( i_nPosition, i_rItemText, i_rItemImageURL, aGuard ); + // <----- SYNCHRONIZED +} + + +void SAL_CALL UnoControlListBoxModel::setItemData( ::sal_Int32 i_nPosition, const Any& i_rDataValue ) +{ + osl::MutexGuard aGuard( GetMutex() ); + ListItem& rItem( m_xData->getItem( i_nPosition ) ); + rItem.ItemData = i_rDataValue; +} + + +OUString SAL_CALL UnoControlListBoxModel::getItemText( ::sal_Int32 i_nPosition ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + const ListItem& rItem( m_xData->getItem( i_nPosition ) ); + return rItem.ItemText; +} + + +OUString SAL_CALL UnoControlListBoxModel::getItemImage( ::sal_Int32 i_nPosition ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + const ListItem& rItem( m_xData->getItem( i_nPosition ) ); + return rItem.ItemImageURL; +} + + +beans::Pair< OUString, OUString > SAL_CALL UnoControlListBoxModel::getItemTextAndImage( ::sal_Int32 i_nPosition ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + const ListItem& rItem( m_xData->getItem( i_nPosition ) ); + return beans::Pair< OUString, OUString >( rItem.ItemText, rItem.ItemImageURL ); +} + + +Any SAL_CALL UnoControlListBoxModel::getItemData( ::sal_Int32 i_nPosition ) +{ + osl::MutexGuard aGuard( GetMutex() ); + const ListItem& rItem( m_xData->getItem( i_nPosition ) ); + return rItem.ItemData; +} + + +Sequence< beans::Pair< OUString, OUString > > SAL_CALL UnoControlListBoxModel::getAllItems( ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + return m_xData->getAllItems(); +} + + +void SAL_CALL UnoControlListBoxModel::addItemListListener( const uno::Reference< awt::XItemListListener >& i_Listener ) +{ + if ( i_Listener.is() ) + m_aItemListListeners.addInterface( i_Listener ); +} + + +void SAL_CALL UnoControlListBoxModel::removeItemListListener( const uno::Reference< awt::XItemListListener >& i_Listener ) +{ + if ( i_Listener.is() ) + m_aItemListListeners.removeInterface( i_Listener ); +} + + +void UnoControlListBoxModel::impl_getStringItemList( ::std::vector< OUString >& o_rStringItems ) const +{ + Sequence< OUString > aStringItemList; + Any aPropValue; + getFastPropertyValue( aPropValue, BASEPROPERTY_STRINGITEMLIST ); + OSL_VERIFY( aPropValue >>= aStringItemList ); + + comphelper::sequenceToContainer(o_rStringItems, aStringItemList); +} + + +void UnoControlListBoxModel::impl_setStringItemList_nolck( const ::std::vector< OUString >& i_rStringItems ) +{ + Sequence< OUString > aStringItems( comphelper::containerToSequence(i_rStringItems) ); + m_xData->m_bSettingLegacyProperty = true; + try + { + setFastPropertyValue( BASEPROPERTY_STRINGITEMLIST, uno::Any( aStringItems ) ); + } + catch( const Exception& ) + { + m_xData->m_bSettingLegacyProperty = false; + throw; + } + m_xData->m_bSettingLegacyProperty = false; +} + + +void UnoControlListBoxModel::impl_handleInsert( const sal_Int32 i_nItemPosition, const ::std::optional< OUString >& i_rItemText, + const ::std::optional< OUString >& i_rItemImageURL, ::osl::ClearableMutexGuard& i_rClearBeforeNotify ) +{ + // SYNCHRONIZED -----> + // sync with legacy StringItemList property + ::std::vector< OUString > aStringItems; + impl_getStringItemList( aStringItems ); + OSL_ENSURE( o3tl::make_unsigned( i_nItemPosition ) <= aStringItems.size(), "UnoControlListBoxModel::impl_handleInsert" ); + if ( o3tl::make_unsigned( i_nItemPosition ) <= aStringItems.size() ) + { + const OUString sItemText( !!i_rItemText ? *i_rItemText : OUString() ); + aStringItems.insert( aStringItems.begin() + i_nItemPosition, sItemText ); + } + + i_rClearBeforeNotify.clear(); + // <----- SYNCHRONIZED + impl_setStringItemList_nolck( aStringItems ); + + // notify ItemListListeners + impl_notifyItemListEvent_nolck( i_nItemPosition, i_rItemText, i_rItemImageURL, &XItemListListener::listItemInserted ); +} + + +void UnoControlListBoxModel::impl_handleRemove( const sal_Int32 i_nItemPosition, ::osl::ClearableMutexGuard& i_rClearBeforeNotify ) +{ + // SYNCHRONIZED -----> + const bool bAllItems = ( i_nItemPosition < 0 ); + // sync with legacy StringItemList property + ::std::vector< OUString > aStringItems; + impl_getStringItemList( aStringItems ); + if ( !bAllItems ) + { + OSL_ENSURE( o3tl::make_unsigned( i_nItemPosition ) < aStringItems.size(), "UnoControlListBoxModel::impl_handleRemove" ); + if ( o3tl::make_unsigned( i_nItemPosition ) < aStringItems.size() ) + { + aStringItems.erase( aStringItems.begin() + i_nItemPosition ); + } + } + else + { + aStringItems.resize(0); + } + + i_rClearBeforeNotify.clear(); + // <----- SYNCHRONIZED + impl_setStringItemList_nolck( aStringItems ); + + // notify ItemListListeners + if ( bAllItems ) + { + EventObject aEvent( *this ); + m_aItemListListeners.notifyEach( &XItemListListener::allItemsRemoved, aEvent ); + } + else + { + impl_notifyItemListEvent_nolck( i_nItemPosition, ::std::optional< OUString >(), ::std::optional< OUString >(), + &XItemListListener::listItemRemoved ); + } +} + + +void UnoControlListBoxModel::impl_handleModify( const sal_Int32 i_nItemPosition, const ::std::optional< OUString >& i_rItemText, + const ::std::optional< OUString >& i_rItemImageURL, ::osl::ClearableMutexGuard& i_rClearBeforeNotify ) +{ + // SYNCHRONIZED -----> + if ( !!i_rItemText ) + { + // sync with legacy StringItemList property + ::std::vector< OUString > aStringItems; + impl_getStringItemList( aStringItems ); + OSL_ENSURE( o3tl::make_unsigned( i_nItemPosition ) < aStringItems.size(), "UnoControlListBoxModel::impl_handleModify" ); + if ( o3tl::make_unsigned( i_nItemPosition ) < aStringItems.size() ) + { + aStringItems[ i_nItemPosition] = *i_rItemText; + } + + i_rClearBeforeNotify.clear(); + // <----- SYNCHRONIZED + impl_setStringItemList_nolck( aStringItems ); + } + else + { + i_rClearBeforeNotify.clear(); + // <----- SYNCHRONIZED + } + + // notify ItemListListeners + impl_notifyItemListEvent_nolck( i_nItemPosition, i_rItemText, i_rItemImageURL, &XItemListListener::listItemModified ); +} + + +void UnoControlListBoxModel::impl_notifyItemListEvent_nolck( const sal_Int32 i_nItemPosition, const ::std::optional< OUString >& i_rItemText, + const ::std::optional< OUString >& i_rItemImageURL, + void ( SAL_CALL XItemListListener::*NotificationMethod )( const ItemListEvent& ) ) +{ + ItemListEvent aEvent; + aEvent.Source = *this; + aEvent.ItemPosition = i_nItemPosition; + if ( !!i_rItemText ) + { + aEvent.ItemText.IsPresent = true; + aEvent.ItemText.Value = *i_rItemText; + } + if ( !!i_rItemImageURL ) + { + aEvent.ItemImageURL.IsPresent = true; + aEvent.ItemImageURL.Value = *i_rItemImageURL; + } + + m_aItemListListeners.notifyEach( NotificationMethod, aEvent ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlListBoxModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlListBoxModel(context)); +} + + + +UnoListBoxControl::UnoListBoxControl() + :maActionListeners( *this ) + ,maItemListeners( *this ) +{ + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 12; +} + +OUString UnoListBoxControl::GetComponentServiceName() const +{ + return "listbox"; +} + +OUString UnoListBoxControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoListBoxControl"; +} + +css::uno::Sequence<OUString> UnoListBoxControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlListBox", "stardiv.vcl.control.ListBox" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals); +} + +void UnoListBoxControl::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maActionListeners.disposeAndClear( aEvt ); + maItemListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); +} + +void UnoListBoxControl::ImplUpdateSelectedItemsProperty() +{ + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + DBG_ASSERT( xListBox.is(), "XListBox?" ); + + uno::Sequence<sal_Int16> aSeq = xListBox->getSelectedItemsPos(); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_SELECTEDITEMS ), uno::Any(aSeq), false ); + } +} + +void UnoListBoxControl::updateFromModel() +{ + UnoControlBase::updateFromModel(); + + Reference< XItemListListener > xItemListListener( getPeer(), UNO_QUERY ); + ENSURE_OR_RETURN_VOID( xItemListListener.is(), "UnoListBoxControl::updateFromModel: a peer which is no ItemListListener?!" ); + + EventObject aEvent( getModel() ); + xItemListListener->itemListChanged( aEvent ); + + // notify the change of the SelectedItems property, again. While our base class, in updateFromModel, + // already did this, our peer(s) can only legitimately set the selection after they have the string + // item list, which we just notified with the itemListChanged call. + const OUString& sSelectedItemsPropName( GetPropertyName( BASEPROPERTY_SELECTEDITEMS ) ); + ImplSetPeerProperty( sSelectedItemsPropName, ImplGetPropertyValue( sSelectedItemsPropName ) ); +} + +void UnoListBoxControl::ImplSetPeerProperty( const OUString& rPropName, const uno::Any& rVal ) +{ + if ( rPropName == GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ) + // do not forward this to our peer. We are a XItemListListener at our model, and changes in the string item + // list (which is a legacy property) will, later, arrive as changes in the ItemList. Those latter changes + // will be forwarded to the peer, which will update itself accordingly. + return; + + UnoControl::ImplSetPeerProperty( rPropName, rVal ); +} + +void UnoListBoxControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + xListBox->addItemListener( this ); + + if ( maActionListeners.getLength() ) + xListBox->addActionListener( &maActionListeners ); +} + +void UnoListBoxControl::addActionListener(const uno::Reference< awt::XActionListener > & l) +{ + maActionListeners.addInterface( l ); + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + xListBox->addActionListener( &maActionListeners ); + } +} + +void UnoListBoxControl::removeActionListener(const uno::Reference< awt::XActionListener > & l) +{ + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + xListBox->removeActionListener( &maActionListeners ); + } + maActionListeners.removeInterface( l ); +} + +void UnoListBoxControl::addItemListener(const uno::Reference < awt::XItemListener > & l) +{ + maItemListeners.addInterface( l ); +} + +void UnoListBoxControl::removeItemListener(const uno::Reference < awt::XItemListener > & l) +{ + maItemListeners.removeInterface( l ); +} + +void UnoListBoxControl::addItem( const OUString& aItem, sal_Int16 nPos ) +{ + uno::Sequence<OUString> aSeq { aItem }; + addItems( aSeq, nPos ); +} + +void UnoListBoxControl::addItems( const uno::Sequence< OUString>& aItems, sal_Int16 nPos ) +{ + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + sal_uInt16 nNewItems = static_cast<sal_uInt16>(aItems.getLength()); + sal_uInt16 nOldLen = static_cast<sal_uInt16>(aSeq.getLength()); + sal_uInt16 nNewLen = nOldLen + nNewItems; + + uno::Sequence< OUString> aNewSeq( nNewLen ); + + if ( ( nPos < 0 ) || ( nPos > nOldLen ) ) + nPos = nOldLen; + + // Items before the Paste-Position + auto it = std::copy(std::cbegin(aSeq), std::next(std::cbegin(aSeq), nPos), aNewSeq.getArray()); + + // New Items + it = std::copy(aItems.begin(), aItems.end(), it); + + // Rest of old Items + std::copy(std::next(std::cbegin(aSeq), nPos), std::cend(aSeq), it); + + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ), uno::Any(aNewSeq), true ); +} + +void UnoListBoxControl::removeItems( sal_Int16 nPos, sal_Int16 nCount ) +{ + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + sal_uInt16 nOldLen = static_cast<sal_uInt16>(aSeq.getLength()); + if ( !(nOldLen && ( nPos < nOldLen )) ) + return; + + if ( nCount > ( nOldLen-nPos ) ) + nCount = nOldLen-nPos; + + sal_uInt16 nNewLen = nOldLen - nCount; + + uno::Sequence< OUString> aNewSeq( nNewLen ); + + // Items before the Remove-Position + auto it = std::copy(std::cbegin(aSeq), std::next(std::cbegin(aSeq), nPos), aNewSeq.getArray()); + + // Rest of Items + std::copy(std::next(std::cbegin(aSeq), nPos + nCount), std::cend(aSeq), it); + + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ), uno::Any(aNewSeq), true ); +} + +sal_Int16 UnoListBoxControl::getItemCount() +{ + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + return static_cast<sal_Int16>(aSeq.getLength()); +} + +OUString UnoListBoxControl::getItem( sal_Int16 nPos ) +{ + OUString aItem; + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + if ( nPos < aSeq.getLength() ) + aItem = aSeq[nPos]; + return aItem; +} + +uno::Sequence< OUString> UnoListBoxControl::getItems() +{ + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + return aSeq; +} + +sal_Int16 UnoListBoxControl::getSelectedItemPos() +{ + sal_Int16 n = -1; + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + n = xListBox->getSelectedItemPos(); + } + return n; +} + +uno::Sequence<sal_Int16> UnoListBoxControl::getSelectedItemsPos() +{ + uno::Sequence<sal_Int16> aSeq; + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + aSeq = xListBox->getSelectedItemsPos(); + } + return aSeq; +} + +OUString UnoListBoxControl::getSelectedItem() +{ + OUString aItem; + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + aItem = xListBox->getSelectedItem(); + } + return aItem; +} + +uno::Sequence< OUString> UnoListBoxControl::getSelectedItems() +{ + uno::Sequence< OUString> aSeq; + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + aSeq = xListBox->getSelectedItems(); + } + return aSeq; +} + +void UnoListBoxControl::selectItemPos( sal_Int16 nPos, sal_Bool bSelect ) +{ + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + xListBox->selectItemPos( nPos, bSelect ); + } + ImplUpdateSelectedItemsProperty(); +} + +void UnoListBoxControl::selectItemsPos( const uno::Sequence<sal_Int16>& aPositions, sal_Bool bSelect ) +{ + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + xListBox->selectItemsPos( aPositions, bSelect ); + } + ImplUpdateSelectedItemsProperty(); +} + +void UnoListBoxControl::selectItem( const OUString& aItem, sal_Bool bSelect ) +{ + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + xListBox->selectItem( aItem, bSelect ); + } + ImplUpdateSelectedItemsProperty(); +} + +void UnoListBoxControl::makeVisible( sal_Int16 nEntry ) +{ + if ( getPeer().is() ) + { + uno::Reference < awt::XListBox > xListBox( getPeer(), uno::UNO_QUERY ); + xListBox->makeVisible( nEntry ); + } +} + +void UnoListBoxControl::setDropDownLineCount( sal_Int16 nLines ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LINECOUNT ), uno::Any(nLines), true ); +} + +sal_Int16 UnoListBoxControl::getDropDownLineCount() +{ + return ImplGetPropertyValue_INT16( BASEPROPERTY_LINECOUNT ); +} + +sal_Bool UnoListBoxControl::isMutipleMode() +{ + return ImplGetPropertyValue_BOOL( BASEPROPERTY_MULTISELECTION ); +} + +void UnoListBoxControl::setMultipleMode( sal_Bool bMulti ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_MULTISELECTION ), uno::Any(bMulti), true ); +} + +void UnoListBoxControl::itemStateChanged( const awt::ItemEvent& rEvent ) +{ + ImplUpdateSelectedItemsProperty(); + if ( maItemListeners.getLength() ) + { + try + { + maItemListeners.itemStateChanged( rEvent ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "toolkit", "UnoListBoxControl::itemStateChanged"); + } + } +} + +awt::Size UnoListBoxControl::getMinimumSize( ) +{ + return Impl_getMinimumSize(); +} + +awt::Size UnoListBoxControl::getPreferredSize( ) +{ + return Impl_getPreferredSize(); +} + +awt::Size UnoListBoxControl::calcAdjustedSize( const awt::Size& rNewSize ) +{ + return Impl_calcAdjustedSize( rNewSize ); +} + +awt::Size UnoListBoxControl::getMinimumSize( sal_Int16 nCols, sal_Int16 nLines ) +{ + return Impl_getMinimumSize( nCols, nLines ); +} + +void UnoListBoxControl::getColumnsAndLines( sal_Int16& nCols, sal_Int16& nLines ) +{ + Impl_getColumnsAndLines( nCols, nLines ); +} + +sal_Bool SAL_CALL UnoListBoxControl::setModel( const uno::Reference< awt::XControlModel >& i_rModel ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + + const Reference< XItemList > xOldItems( getModel(), UNO_QUERY ); + OSL_ENSURE( xOldItems.is() || !getModel().is(), "UnoListBoxControl::setModel: illegal old model!" ); + const Reference< XItemList > xNewItems( i_rModel, UNO_QUERY ); + OSL_ENSURE( xNewItems.is() || !i_rModel.is(), "UnoListBoxControl::setModel: illegal new model!" ); + + if ( !UnoListBoxControl_Base::setModel( i_rModel ) ) + return false; + + if ( xOldItems.is() ) + xOldItems->removeItemListListener( this ); + if ( xNewItems.is() ) + xNewItems->addItemListListener( this ); + + return true; +} + +void SAL_CALL UnoListBoxControl::listItemInserted( const awt::ItemListEvent& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoListBoxControl::listItemInserted: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->listItemInserted( i_rEvent ); +} + +void SAL_CALL UnoListBoxControl::listItemRemoved( const awt::ItemListEvent& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoListBoxControl::listItemRemoved: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->listItemRemoved( i_rEvent ); +} + +void SAL_CALL UnoListBoxControl::listItemModified( const awt::ItemListEvent& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoListBoxControl::listItemModified: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->listItemModified( i_rEvent ); +} + +void SAL_CALL UnoListBoxControl::allItemsRemoved( const lang::EventObject& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoListBoxControl::allItemsRemoved: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->allItemsRemoved( i_rEvent ); +} + +void SAL_CALL UnoListBoxControl::itemListChanged( const lang::EventObject& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoListBoxControl::itemListChanged: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->itemListChanged( i_rEvent ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoListBoxControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoListBoxControl()); +} + + + +UnoControlComboBoxModel::UnoControlComboBoxModel( const Reference< XComponentContext >& rxContext ) + :UnoControlListBoxModel( rxContext, ConstructWithoutProperties ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXComboBox>(); +} + +OUString UnoControlComboBoxModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlComboBoxModel"; +} + +css::uno::Sequence<OUString> UnoControlComboBoxModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlComboBoxModel", "stardiv.vcl.controlmodel.ComboBox" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals); +} + +uno::Reference< beans::XPropertySetInfo > UnoControlComboBoxModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::cppu::IPropertyArrayHelper& UnoControlComboBoxModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + + +OUString UnoControlComboBoxModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.ComboBox"; +} + +void SAL_CALL UnoControlComboBoxModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const uno::Any& rValue ) +{ + UnoControlModel::setFastPropertyValue_NoBroadcast( nHandle, rValue ); + + if (nHandle != BASEPROPERTY_STRINGITEMLIST || m_xData->m_bSettingLegacyProperty) + return; + + // synchronize the legacy StringItemList property with our list items + Sequence< OUString > aStringItemList; + Any aPropValue; + getFastPropertyValue( aPropValue, BASEPROPERTY_STRINGITEMLIST ); + OSL_VERIFY( aPropValue >>= aStringItemList ); + + ::std::vector< ListItem > aItems( aStringItemList.getLength() ); + ::std::transform( + std::cbegin(aStringItemList), + std::cend(aStringItemList), + aItems.begin(), + CreateListItem() + ); + m_xData->setAllItems( std::move(aItems) ); + + // since an XItemListListener does not have a "all items modified" or some such method, + // we simulate this by notifying removal of all items, followed by insertion of all new + // items + lang::EventObject aEvent; + aEvent.Source = *this; + m_aItemListListeners.notifyEach( &XItemListListener::itemListChanged, aEvent ); + // TODO: OPropertySetHelper calls into this method with the mutex locked ... + // which is wrong for the above notifications ... +} + +uno::Any UnoControlComboBoxModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.ComboBox" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlComboBoxModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlComboBoxModel(context)); +} + + + +UnoComboBoxControl::UnoComboBoxControl() + :maActionListeners( *this ) + ,maItemListeners( *this ) +{ + maComponentInfos.nWidth = 100; + maComponentInfos.nHeight = 12; +} + +OUString UnoComboBoxControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoComboBoxControl"; +} + +css::uno::Sequence<OUString> UnoComboBoxControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlComboBox", "stardiv.vcl.control.ComboBox" }; + return comphelper::concatSequences( UnoEditControl::getSupportedServiceNames(), vals); +} + +OUString UnoComboBoxControl::GetComponentServiceName() const +{ + return "combobox"; +} + +void UnoComboBoxControl::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast<cppu::OWeakObject*>(this); + maActionListeners.disposeAndClear( aEvt ); + maItemListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); +} +uno::Any UnoComboBoxControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XComboBox* >(this) ); + if ( !aRet.hasValue() ) + { + aRet = ::cppu::queryInterface( rType, + static_cast< awt::XItemListener* >(this) ); + if ( !aRet.hasValue() ) + { + aRet = ::cppu::queryInterface( rType, + static_cast< awt::XItemListListener* >(this) ); + } + } + return (aRet.hasValue() ? aRet : UnoEditControl::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoComboBoxControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoComboBoxControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<awt::XComboBox>::get(), + cppu::UnoType<awt::XItemListener>::get(), + cppu::UnoType<awt::XItemListListener>::get(), + UnoEditControl::getTypes() + ); + return aTypeList.getTypes(); +} + +void UnoComboBoxControl::updateFromModel() +{ + UnoEditControl::updateFromModel(); + + Reference< XItemListListener > xItemListListener( getPeer(), UNO_QUERY ); + ENSURE_OR_RETURN_VOID( xItemListListener.is(), "UnoComboBoxControl::updateFromModel: a peer which is no ItemListListener?!" ); + + EventObject aEvent( getModel() ); + xItemListListener->itemListChanged( aEvent ); +} +void UnoComboBoxControl::ImplSetPeerProperty( const OUString& rPropName, const uno::Any& rVal ) +{ + if ( rPropName == GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ) + // do not forward this to our peer. We are a XItemListListener at our model, and changes in the string item + // list (which is a legacy property) will, later, arrive as changes in the ItemList. Those latter changes + // will be forwarded to the peer, which will update itself accordingly. + return; + + UnoEditControl::ImplSetPeerProperty( rPropName, rVal ); +} +void UnoComboBoxControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoEditControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XComboBox > xComboBox( getPeer(), uno::UNO_QUERY ); + if ( maActionListeners.getLength() ) + xComboBox->addActionListener( &maActionListeners ); + if ( maItemListeners.getLength() ) + xComboBox->addItemListener( &maItemListeners ); +} + +void UnoComboBoxControl::addActionListener(const uno::Reference< awt::XActionListener > & l) +{ + maActionListeners.addInterface( l ); + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XComboBox > xComboBox( getPeer(), uno::UNO_QUERY ); + xComboBox->addActionListener( &maActionListeners ); + } +} + +void UnoComboBoxControl::removeActionListener(const uno::Reference< awt::XActionListener > & l) +{ + if( getPeer().is() && maActionListeners.getLength() == 1 ) + { + uno::Reference < awt::XComboBox > xComboBox( getPeer(), uno::UNO_QUERY ); + xComboBox->removeActionListener( &maActionListeners ); + } + maActionListeners.removeInterface( l ); +} + +void UnoComboBoxControl::addItemListener(const uno::Reference < awt::XItemListener > & l) +{ + maItemListeners.addInterface( l ); + if( getPeer().is() && maItemListeners.getLength() == 1 ) + { + uno::Reference < awt::XComboBox > xComboBox( getPeer(), uno::UNO_QUERY ); + xComboBox->addItemListener( &maItemListeners ); + } +} + +void UnoComboBoxControl::removeItemListener(const uno::Reference < awt::XItemListener > & l) +{ + if( getPeer().is() && maItemListeners.getLength() == 1 ) + { + // This call is prettier than creating a Ref and calling query + uno::Reference < awt::XComboBox > xComboBox( getPeer(), uno::UNO_QUERY ); + xComboBox->removeItemListener( &maItemListeners ); + } + maItemListeners.removeInterface( l ); +} +void UnoComboBoxControl::itemStateChanged( const awt::ItemEvent& rEvent ) +{ + if ( maItemListeners.getLength() ) + { + try + { + maItemListeners.itemStateChanged( rEvent ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "toolkit", "UnoComboBoxControl::itemStateChanged"); + } + } +} +sal_Bool SAL_CALL UnoComboBoxControl::setModel( const uno::Reference< awt::XControlModel >& i_rModel ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + + const Reference< XItemList > xOldItems( getModel(), UNO_QUERY ); + OSL_ENSURE( xOldItems.is() || !getModel().is(), "UnoComboBoxControl::setModel: illegal old model!" ); + const Reference< XItemList > xNewItems( i_rModel, UNO_QUERY ); + OSL_ENSURE( xNewItems.is() || !i_rModel.is(), "UnoComboBoxControl::setModel: illegal new model!" ); + + if ( !UnoEditControl::setModel( i_rModel ) ) + return false; + + if ( xOldItems.is() ) + xOldItems->removeItemListListener( this ); + if ( xNewItems.is() ) + xNewItems->addItemListListener( this ); + + return true; +} + +void SAL_CALL UnoComboBoxControl::listItemInserted( const awt::ItemListEvent& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoComboBoxControl::listItemInserted: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->listItemInserted( i_rEvent ); +} + +void SAL_CALL UnoComboBoxControl::listItemRemoved( const awt::ItemListEvent& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoComboBoxControl::listItemRemoved: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->listItemRemoved( i_rEvent ); +} + +void SAL_CALL UnoComboBoxControl::listItemModified( const awt::ItemListEvent& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoComboBoxControl::listItemModified: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->listItemModified( i_rEvent ); +} + +void SAL_CALL UnoComboBoxControl::allItemsRemoved( const lang::EventObject& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoComboBoxControl::allItemsRemoved: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->allItemsRemoved( i_rEvent ); +} + +void SAL_CALL UnoComboBoxControl::itemListChanged( const lang::EventObject& i_rEvent ) +{ + const Reference< XItemListListener > xPeerListener( getPeer(), UNO_QUERY ); + OSL_ENSURE( xPeerListener.is() || !getPeer().is(), "UnoComboBoxControl::itemListChanged: invalid peer!" ); + if ( xPeerListener.is() ) + xPeerListener->itemListChanged( i_rEvent ); +} + +void UnoComboBoxControl::addItem( const OUString& aItem, sal_Int16 nPos ) +{ + uno::Sequence<OUString> aSeq { aItem }; + addItems( aSeq, nPos ); +} + +void UnoComboBoxControl::addItems( const uno::Sequence< OUString>& aItems, sal_Int16 nPos ) +{ + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + sal_uInt16 nNewItems = static_cast<sal_uInt16>(aItems.getLength()); + sal_uInt16 nOldLen = static_cast<sal_uInt16>(aSeq.getLength()); + sal_uInt16 nNewLen = nOldLen + nNewItems; + + uno::Sequence< OUString> aNewSeq( nNewLen ); + + if ( ( nPos < 0 ) || ( nPos > nOldLen ) ) + nPos = nOldLen; + + // items before the insert position + auto it = std::copy(std::cbegin(aSeq), std::next(std::cbegin(aSeq), nPos), aNewSeq.getArray()); + + // New items + it = std::copy(aItems.begin(), aItems.end(), it); + + // remainder of old items + std::copy(std::next(std::cbegin(aSeq), nPos), std::cend(aSeq), it); + + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ), Any(aNewSeq), true ); +} + +void UnoComboBoxControl::removeItems( sal_Int16 nPos, sal_Int16 nCount ) +{ + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + sal_uInt16 nOldLen = static_cast<sal_uInt16>(aSeq.getLength()); + if ( !nOldLen || ( nPos >= nOldLen ) ) + return; + + if ( nCount > ( nOldLen-nPos ) ) + nCount = nOldLen-nPos; + + sal_uInt16 nNewLen = nOldLen - nCount; + + uno::Sequence< OUString> aNewSeq( nNewLen ); + + // items before the deletion position + auto it = std::copy(std::cbegin(aSeq), std::next(std::cbegin(aSeq), nPos), aNewSeq.getArray()); + + // remainder of old items + std::copy(std::next(std::cbegin(aSeq), nPos + nCount), std::cend(aSeq), it); + + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ), uno::Any(aNewSeq), true ); +} + +sal_Int16 UnoComboBoxControl::getItemCount() +{ + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + return static_cast<sal_Int16>(aSeq.getLength()); +} + +OUString UnoComboBoxControl::getItem( sal_Int16 nPos ) +{ + OUString aItem; + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + if ( nPos < aSeq.getLength() ) + aItem = aSeq[nPos]; + return aItem; +} + +uno::Sequence< OUString> UnoComboBoxControl::getItems() +{ + uno::Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_STRINGITEMLIST ) ); + uno::Sequence< OUString> aSeq; + aVal >>= aSeq; + return aSeq; +} + +void UnoComboBoxControl::setDropDownLineCount( sal_Int16 nLines ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LINECOUNT ), uno::Any(nLines), true ); +} + +sal_Int16 UnoComboBoxControl::getDropDownLineCount() +{ + return ImplGetPropertyValue_INT16( BASEPROPERTY_LINECOUNT ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoComboBoxControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoComboBoxControl()); +} + + +// UnoSpinFieldControl + +UnoSpinFieldControl::UnoSpinFieldControl() + :maSpinListeners( *this ) +{ + mbRepeat = false; +} + +// uno::XInterface +uno::Any UnoSpinFieldControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XSpinField* >(this) ); + return (aRet.hasValue() ? aRet : UnoEditControl::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoSpinFieldControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoSpinFieldControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XSpinField>::get(), + UnoEditControl::getTypes() + ); + return aTypeList.getTypes(); +} + +void UnoSpinFieldControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoEditControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XSpinField > xField( getPeer(), uno::UNO_QUERY ); + xField->enableRepeat( mbRepeat ); + if ( maSpinListeners.getLength() ) + xField->addSpinListener( &maSpinListeners ); +} + + // css::awt::XSpinField +void UnoSpinFieldControl::addSpinListener( const css::uno::Reference< css::awt::XSpinListener >& l ) +{ + maSpinListeners.addInterface( l ); + if( getPeer().is() && maSpinListeners.getLength() == 1 ) + { + uno::Reference < awt::XSpinField > xField( getPeer(), uno::UNO_QUERY ); + xField->addSpinListener( &maSpinListeners ); + } +} + +void UnoSpinFieldControl::removeSpinListener( const css::uno::Reference< css::awt::XSpinListener >& l ) +{ + if( getPeer().is() && maSpinListeners.getLength() == 1 ) + { + uno::Reference < awt::XSpinField > xField( getPeer(), uno::UNO_QUERY ); + xField->removeSpinListener( &maSpinListeners ); + } + maSpinListeners.removeInterface( l ); +} + +void UnoSpinFieldControl::up() +{ + uno::Reference < awt::XSpinField > xField( getPeer(), uno::UNO_QUERY ); + if ( xField.is() ) + xField->up(); +} + +void UnoSpinFieldControl::down() +{ + uno::Reference < awt::XSpinField > xField( getPeer(), uno::UNO_QUERY ); + if ( xField.is() ) + xField->down(); +} + +void UnoSpinFieldControl::first() +{ + uno::Reference < awt::XSpinField > xField( getPeer(), uno::UNO_QUERY ); + if ( xField.is() ) + xField->first(); +} + +void UnoSpinFieldControl::last() +{ + uno::Reference < awt::XSpinField > xField( getPeer(), uno::UNO_QUERY ); + if ( xField.is() ) + xField->last(); +} + +void UnoSpinFieldControl::enableRepeat( sal_Bool bRepeat ) +{ + mbRepeat = bRepeat; + + uno::Reference < awt::XSpinField > xField( getPeer(), uno::UNO_QUERY ); + if ( xField.is() ) + xField->enableRepeat( bRepeat ); +} + + + +UnoControlDateFieldModel::UnoControlDateFieldModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXDateField>(); +} + +OUString UnoControlDateFieldModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.DateField"; +} + +uno::Any UnoControlDateFieldModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.DateField" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + + +::cppu::IPropertyArrayHelper& UnoControlDateFieldModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlDateFieldModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlDateFieldModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlDateFieldModel"; +} + +css::uno::Sequence<OUString> +UnoControlDateFieldModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlDateFieldModel", "stardiv.vcl.controlmodel.DateField" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlDateFieldModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlDateFieldModel(context)); +} + + + +UnoDateFieldControl::UnoDateFieldControl() +{ + mnFirst = util::Date( 1, 1, 1900 ); + mnLast = util::Date( 31, 12, 2200 ); + mbLongFormat = TRISTATE_INDET; +} + +OUString UnoDateFieldControl::GetComponentServiceName() const +{ + return "datefield"; +} + +// uno::XInterface +uno::Any UnoDateFieldControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XDateField* >(this) ); + return (aRet.hasValue() ? aRet : UnoSpinFieldControl::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoDateFieldControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoDateFieldControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XDateField>::get(), + UnoSpinFieldControl::getTypes() + ); + return aTypeList.getTypes(); +} + +void UnoDateFieldControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoSpinFieldControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XDateField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( mnFirst ); + xField->setLast( mnLast ); + if ( mbLongFormat != TRISTATE_INDET ) + xField->setLongFormat( mbLongFormat != TRISTATE_FALSE); +} + + +void UnoDateFieldControl::textChanged( const awt::TextEvent& e ) +{ + uno::Reference< awt::XVclWindowPeer > xPeer( getPeer(), uno::UNO_QUERY ); + + // also change the text property (#i25106#) + if ( xPeer.is() ) + { + const OUString& sTextPropertyName = GetPropertyName( BASEPROPERTY_TEXT ); + ImplSetPropertyValue( sTextPropertyName, xPeer->getProperty( sTextPropertyName ), false ); + } + + // re-calc the Date property + uno::Reference < awt::XDateField > xField( getPeer(), uno::UNO_QUERY ); + uno::Any aValue; + if ( xField->isEmpty() ) + { + // the field says it's empty + bool bEnforceFormat = true; + if ( xPeer.is() ) + xPeer->getProperty( GetPropertyName( BASEPROPERTY_ENFORCE_FORMAT ) ) >>= bEnforceFormat; + if ( !bEnforceFormat ) + { + // and it also says that it is currently accepting invalid inputs, without + // forcing it to a valid date + uno::Reference< awt::XTextComponent > xText( xPeer, uno::UNO_QUERY ); + if ( xText.is() && xText->getText().getLength() ) + // and in real, the text of the peer is *not* empty + // -> simulate an invalid date, which is different from "no date" + aValue <<= util::Date(); + } + } + else + aValue <<= xField->getDate(); + + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_DATE ), aValue, false ); + + // multiplex the event + if ( GetTextListeners().getLength() ) + GetTextListeners().textChanged( e ); +} + +void UnoDateFieldControl::setDate( const util::Date& Date ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_DATE ), uno::Any(Date), true ); +} + +util::Date UnoDateFieldControl::getDate() +{ + return ImplGetPropertyValue_Date( BASEPROPERTY_DATE ); +} + +void UnoDateFieldControl::setMin( const util::Date& Date ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_DATEMIN ), uno::Any(Date), true ); +} + +util::Date UnoDateFieldControl::getMin() +{ + return ImplGetPropertyValue_Date( BASEPROPERTY_DATEMIN ); +} + +void UnoDateFieldControl::setMax( const util::Date& Date ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_DATEMAX ), uno::Any(Date), true ); +} + +util::Date UnoDateFieldControl::getMax() +{ + return ImplGetPropertyValue_Date( BASEPROPERTY_DATEMAX ); +} + +void UnoDateFieldControl::setFirst( const util::Date& Date ) +{ + mnFirst = Date; + if ( getPeer().is() ) + { + uno::Reference < awt::XDateField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( Date ); + } +} + +util::Date UnoDateFieldControl::getFirst() +{ + return mnFirst; +} + +void UnoDateFieldControl::setLast( const util::Date& Date ) +{ + mnLast = Date; + if ( getPeer().is() ) + { + uno::Reference < awt::XDateField > xField( getPeer(), uno::UNO_QUERY ); + xField->setLast( Date ); + } +} + +util::Date UnoDateFieldControl::getLast() +{ + return mnLast; +} + +void UnoDateFieldControl::setLongFormat( sal_Bool bLong ) +{ + mbLongFormat = bLong ? TRISTATE_TRUE : TRISTATE_FALSE; + if ( getPeer().is() ) + { + uno::Reference < awt::XDateField > xField( getPeer(), uno::UNO_QUERY ); + xField->setLongFormat( bLong ); + } +} + +sal_Bool UnoDateFieldControl::isLongFormat() +{ + return mbLongFormat == TRISTATE_TRUE; +} + +void UnoDateFieldControl::setEmpty() +{ + if ( getPeer().is() ) + { + uno::Reference < awt::XDateField > xField( getPeer(), uno::UNO_QUERY ); + xField->setEmpty(); + } +} + +sal_Bool UnoDateFieldControl::isEmpty() +{ + bool bEmpty = false; + if ( getPeer().is() ) + { + uno::Reference < awt::XDateField > xField( getPeer(), uno::UNO_QUERY ); + bEmpty = xField->isEmpty(); + } + return bEmpty; +} + +void UnoDateFieldControl::setStrictFormat( sal_Bool bStrict ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRICTFORMAT ), uno::Any(bStrict), true ); +} + +sal_Bool UnoDateFieldControl::isStrictFormat() +{ + return ImplGetPropertyValue_BOOL( BASEPROPERTY_STRICTFORMAT ); +} + +OUString UnoDateFieldControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoDateFieldControl"; +} + +css::uno::Sequence<OUString> UnoDateFieldControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlDateField", "stardiv.vcl.control.DateField" }; + return comphelper::concatSequences( UnoSpinFieldControl::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoDateFieldControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoDateFieldControl()); +} + + + +UnoControlTimeFieldModel::UnoControlTimeFieldModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXTimeField>(); +} + +OUString UnoControlTimeFieldModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.TimeField"; +} + +uno::Any UnoControlTimeFieldModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.TimeField" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + + +::cppu::IPropertyArrayHelper& UnoControlTimeFieldModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlTimeFieldModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlTimeFieldModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlTimeFieldModel"; +} + +css::uno::Sequence<OUString> +UnoControlTimeFieldModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlTimeFieldModel", "stardiv.vcl.controlmodel.TimeField" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlTimeFieldModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlTimeFieldModel(context)); +} + + + +UnoTimeFieldControl::UnoTimeFieldControl() +{ + mnFirst = util::Time( 0, 0, 0, 0, false ); + mnLast = util::Time( 999999999, 59, 59, 23, false ); +} + +OUString UnoTimeFieldControl::GetComponentServiceName() const +{ + return "timefield"; +} + +// uno::XInterface +uno::Any UnoTimeFieldControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XTimeField* >(this) ); + return (aRet.hasValue() ? aRet : UnoSpinFieldControl::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoTimeFieldControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoTimeFieldControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XTimeField>::get(), + UnoSpinFieldControl::getTypes() + ); + return aTypeList.getTypes(); +} + +void UnoTimeFieldControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoSpinFieldControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XTimeField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( mnFirst ); + xField->setLast( mnLast ); +} + +void UnoTimeFieldControl::textChanged( const awt::TextEvent& e ) +{ + // also change the text property (#i25106#) + uno::Reference< awt::XVclWindowPeer > xPeer( getPeer(), uno::UNO_QUERY ); + const OUString& sTextPropertyName = GetPropertyName( BASEPROPERTY_TEXT ); + ImplSetPropertyValue( sTextPropertyName, xPeer->getProperty( sTextPropertyName ), false ); + + // re-calc the Time property + uno::Reference < awt::XTimeField > xField( getPeer(), uno::UNO_QUERY ); + uno::Any aValue; + if ( !xField->isEmpty() ) + aValue <<= xField->getTime(); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TIME ), aValue, false ); + + // multiplex the event + if ( GetTextListeners().getLength() ) + GetTextListeners().textChanged( e ); +} + +void UnoTimeFieldControl::setTime( const util::Time& Time ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TIME ), Any(Time), true ); +} + +util::Time UnoTimeFieldControl::getTime() +{ + return ImplGetPropertyValue_Time( BASEPROPERTY_TIME ); +} + +void UnoTimeFieldControl::setMin( const util::Time& Time ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TIMEMIN ), uno::Any(Time), true ); +} + +util::Time UnoTimeFieldControl::getMin() +{ + return ImplGetPropertyValue_Time( BASEPROPERTY_TIMEMIN ); +} + +void UnoTimeFieldControl::setMax( const util::Time& Time ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TIMEMAX ), uno::Any(Time), true ); +} + +util::Time UnoTimeFieldControl::getMax() +{ + return ImplGetPropertyValue_Time( BASEPROPERTY_TIMEMAX ); +} + +void UnoTimeFieldControl::setFirst( const util::Time& Time ) +{ + mnFirst = Time; + if ( getPeer().is() ) + { + uno::Reference < awt::XTimeField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( mnFirst ); + } +} + +util::Time UnoTimeFieldControl::getFirst() +{ + return mnFirst; +} + +void UnoTimeFieldControl::setLast( const util::Time& Time ) +{ + mnLast = Time; + if ( getPeer().is() ) + { + uno::Reference < awt::XTimeField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( mnLast ); + } +} + +util::Time UnoTimeFieldControl::getLast() +{ + return mnLast; +} + +void UnoTimeFieldControl::setEmpty() +{ + if ( getPeer().is() ) + { + uno::Reference < awt::XTimeField > xField( getPeer(), uno::UNO_QUERY ); + xField->setEmpty(); + } +} + +sal_Bool UnoTimeFieldControl::isEmpty() +{ + bool bEmpty = false; + if ( getPeer().is() ) + { + uno::Reference < awt::XTimeField > xField( getPeer(), uno::UNO_QUERY ); + bEmpty = xField->isEmpty(); + } + return bEmpty; +} + +void UnoTimeFieldControl::setStrictFormat( sal_Bool bStrict ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRICTFORMAT ), uno::Any(bStrict), true ); +} + +sal_Bool UnoTimeFieldControl::isStrictFormat() +{ + return ImplGetPropertyValue_BOOL( BASEPROPERTY_STRICTFORMAT ); +} + +OUString UnoTimeFieldControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoTimeFieldControl"; +} + +css::uno::Sequence<OUString> UnoTimeFieldControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlTimeField", "stardiv.vcl.control.TimeField" }; + return comphelper::concatSequences( UnoSpinFieldControl::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoTimeFieldControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoTimeFieldControl()); +} + + + +UnoControlNumericFieldModel::UnoControlNumericFieldModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXNumericField>(); +} + +OUString UnoControlNumericFieldModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.NumericField"; +} + +uno::Any UnoControlNumericFieldModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.NumericField" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + + +::cppu::IPropertyArrayHelper& UnoControlNumericFieldModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlNumericFieldModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlNumericFieldModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlNumericFieldModel"; +} + +css::uno::Sequence<OUString> +UnoControlNumericFieldModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "stardiv.vcl.controlmodel.NumericField", "com.sun.star.awt.UnoControlNumericFieldModel" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlNumericFieldModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlNumericFieldModel(context)); +} + + + +UnoNumericFieldControl::UnoNumericFieldControl() +{ + mnFirst = 0; + mnLast = 0x7FFFFFFF; +} + +OUString UnoNumericFieldControl::GetComponentServiceName() const +{ + return "numericfield"; +} + +// uno::XInterface +uno::Any UnoNumericFieldControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XNumericField* >(this) ); + return (aRet.hasValue() ? aRet : UnoSpinFieldControl::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoNumericFieldControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoNumericFieldControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XNumericField>::get(), + UnoSpinFieldControl::getTypes() + ); + return aTypeList.getTypes(); +} + +void UnoNumericFieldControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoSpinFieldControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XNumericField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( mnFirst ); + xField->setLast( mnLast ); +} + + +void UnoNumericFieldControl::textChanged( const awt::TextEvent& e ) +{ + uno::Reference < awt::XNumericField > xField( getPeer(), uno::UNO_QUERY ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUE_DOUBLE ), uno::Any(xField->getValue()), false ); + + if ( GetTextListeners().getLength() ) + GetTextListeners().textChanged( e ); +} + +void UnoNumericFieldControl::setValue( double Value ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUE_DOUBLE ), uno::Any(Value), true ); +} + +double UnoNumericFieldControl::getValue() +{ + return ImplGetPropertyValue_DOUBLE( BASEPROPERTY_VALUE_DOUBLE ); +} + +void UnoNumericFieldControl::setMin( double Value ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUEMIN_DOUBLE ), uno::Any(Value), true ); +} + +double UnoNumericFieldControl::getMin() +{ + return ImplGetPropertyValue_DOUBLE( BASEPROPERTY_VALUEMIN_DOUBLE ); +} + +void UnoNumericFieldControl::setMax( double Value ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUEMAX_DOUBLE ), uno::Any(Value), true ); +} + +double UnoNumericFieldControl::getMax() +{ + return ImplGetPropertyValue_DOUBLE( BASEPROPERTY_VALUEMAX_DOUBLE ); +} + +void UnoNumericFieldControl::setFirst( double Value ) +{ + mnFirst = Value; + if ( getPeer().is() ) + { + uno::Reference < awt::XNumericField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( mnFirst ); + } +} + +double UnoNumericFieldControl::getFirst() +{ + return mnFirst; +} + +void UnoNumericFieldControl::setLast( double Value ) +{ + mnLast = Value; + if ( getPeer().is() ) + { + uno::Reference < awt::XNumericField > xField( getPeer(), uno::UNO_QUERY ); + xField->setLast( mnLast ); + } +} + +double UnoNumericFieldControl::getLast() +{ + return mnLast; +} + +void UnoNumericFieldControl::setStrictFormat( sal_Bool bStrict ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRICTFORMAT ), uno::Any(bStrict), true ); +} + +sal_Bool UnoNumericFieldControl::isStrictFormat() +{ + return ImplGetPropertyValue_BOOL( BASEPROPERTY_STRICTFORMAT ); +} + +OUString UnoNumericFieldControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoNumericFieldControl"; +} + +css::uno::Sequence<OUString> UnoNumericFieldControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlNumericField", "stardiv.vcl.control.NumericField" }; + return comphelper::concatSequences( UnoSpinFieldControl::getSupportedServiceNames(), vals ); +} + +void UnoNumericFieldControl::setSpinSize( double Digits ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUESTEP_DOUBLE ), uno::Any(Digits), true ); +} + +double UnoNumericFieldControl::getSpinSize() +{ + return ImplGetPropertyValue_DOUBLE( BASEPROPERTY_VALUESTEP_DOUBLE ); +} + +void UnoNumericFieldControl::setDecimalDigits( sal_Int16 Digits ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_DECIMALACCURACY ), uno::Any(Digits), true ); +} + +sal_Int16 UnoNumericFieldControl::getDecimalDigits() +{ + return ImplGetPropertyValue_INT16( BASEPROPERTY_DECIMALACCURACY ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoNumericFieldControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoNumericFieldControl()); +} + +UnoControlCurrencyFieldModel::UnoControlCurrencyFieldModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<SVTXCurrencyField>(); +} + +OUString UnoControlCurrencyFieldModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.CurrencyField"; +} + +uno::Any UnoControlCurrencyFieldModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.CurrencyField" ) ); + } + if ( nPropId == BASEPROPERTY_CURSYM_POSITION ) + { + return uno::Any(false); + } + + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlCurrencyFieldModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlCurrencyFieldModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlCurrencyFieldModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlCurrencyFieldModel"; +} + +css::uno::Sequence<OUString> +UnoControlCurrencyFieldModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlCurrencyFieldModel", "stardiv.vcl.controlmodel.CurrencyField" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlCurrencyFieldModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlCurrencyFieldModel(context)); +} + + + +UnoCurrencyFieldControl::UnoCurrencyFieldControl() +{ + mnFirst = 0; + mnLast = 0x7FFFFFFF; +} + +OUString UnoCurrencyFieldControl::GetComponentServiceName() const +{ + return "longcurrencyfield"; +} + +// uno::XInterface +uno::Any UnoCurrencyFieldControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XCurrencyField* >(this) ); + return (aRet.hasValue() ? aRet : UnoSpinFieldControl::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoCurrencyFieldControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoCurrencyFieldControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XCurrencyField>::get(), + UnoSpinFieldControl::getTypes() + ); + return aTypeList.getTypes(); +} + +void UnoCurrencyFieldControl::createPeer( const uno::Reference< awt::XToolkit > & rxToolkit, const uno::Reference< awt::XWindowPeer > & rParentPeer ) +{ + UnoSpinFieldControl::createPeer( rxToolkit, rParentPeer ); + + uno::Reference < awt::XCurrencyField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( mnFirst ); + xField->setLast( mnLast ); +} + +void UnoCurrencyFieldControl::textChanged( const awt::TextEvent& e ) +{ + uno::Reference < awt::XCurrencyField > xField( getPeer(), uno::UNO_QUERY ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUE_DOUBLE ), uno::Any(xField->getValue()), false ); + + if ( GetTextListeners().getLength() ) + GetTextListeners().textChanged( e ); +} + +void UnoCurrencyFieldControl::setValue( double Value ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUE_DOUBLE ), Any(Value), true ); +} + +double UnoCurrencyFieldControl::getValue() +{ + return ImplGetPropertyValue_DOUBLE( BASEPROPERTY_VALUE_DOUBLE ); +} + +void UnoCurrencyFieldControl::setMin( double Value ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUEMIN_DOUBLE ), uno::Any(Value), true ); +} + +double UnoCurrencyFieldControl::getMin() +{ + return ImplGetPropertyValue_DOUBLE( BASEPROPERTY_VALUEMIN_DOUBLE ); +} + +void UnoCurrencyFieldControl::setMax( double Value ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUEMAX_DOUBLE ), uno::Any(Value), true ); +} + +double UnoCurrencyFieldControl::getMax() +{ + return ImplGetPropertyValue_DOUBLE( BASEPROPERTY_VALUEMAX_DOUBLE ); +} + +void UnoCurrencyFieldControl::setFirst( double Value ) +{ + mnFirst = Value; + if ( getPeer().is() ) + { + uno::Reference < awt::XCurrencyField > xField( getPeer(), uno::UNO_QUERY ); + xField->setFirst( mnFirst ); + } +} + +double UnoCurrencyFieldControl::getFirst() +{ + return mnFirst; +} + +void UnoCurrencyFieldControl::setLast( double Value ) +{ + mnLast = Value; + if ( getPeer().is() ) + { + uno::Reference < awt::XCurrencyField > xField( getPeer(), uno::UNO_QUERY ); + xField->setLast( mnLast ); + } +} + +double UnoCurrencyFieldControl::getLast() +{ + return mnLast; +} + +void UnoCurrencyFieldControl::setStrictFormat( sal_Bool bStrict ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRICTFORMAT ), uno::Any(bStrict), true ); +} + +sal_Bool UnoCurrencyFieldControl::isStrictFormat() +{ + return ImplGetPropertyValue_BOOL( BASEPROPERTY_STRICTFORMAT ); +} + +OUString UnoCurrencyFieldControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoCurrencyFieldControl"; +} + +css::uno::Sequence<OUString> +UnoCurrencyFieldControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlCurrencyField", "stardiv.vcl.control.CurrencyField" }; + return comphelper::concatSequences( UnoSpinFieldControl::getSupportedServiceNames(), vals ); +} + +void UnoCurrencyFieldControl::setSpinSize( double Digits ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_VALUESTEP_DOUBLE ), uno::Any(Digits), true ); +} + +double UnoCurrencyFieldControl::getSpinSize() +{ + return ImplGetPropertyValue_DOUBLE( BASEPROPERTY_VALUESTEP_DOUBLE ); +} + +void UnoCurrencyFieldControl::setDecimalDigits( sal_Int16 Digits ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_DECIMALACCURACY ), uno::Any(Digits), true ); +} + +sal_Int16 UnoCurrencyFieldControl::getDecimalDigits() +{ + return ImplGetPropertyValue_INT16( BASEPROPERTY_DECIMALACCURACY ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoCurrencyFieldControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoCurrencyFieldControl()); +} + + + +UnoControlPatternFieldModel::UnoControlPatternFieldModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + UNO_CONTROL_MODEL_REGISTER_PROPERTIES<VCLXPatternField>(); +} + +OUString UnoControlPatternFieldModel::getServiceName() +{ + return "stardiv.vcl.controlmodel.PatternField"; +} + +uno::Any UnoControlPatternFieldModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.PatternField" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlPatternFieldModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlPatternFieldModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlPatternFieldModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlPatternFieldModel"; +} + +css::uno::Sequence<OUString> +UnoControlPatternFieldModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlPatternFieldModel", "stardiv.vcl.controlmodel.PatternField" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlPatternFieldModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlPatternFieldModel(context)); +} + + + +UnoPatternFieldControl::UnoPatternFieldControl() +{ +} + +OUString UnoPatternFieldControl::GetComponentServiceName() const +{ + return "patternfield"; +} + +void UnoPatternFieldControl::ImplSetPeerProperty( const OUString& rPropName, const uno::Any& rVal ) +{ + sal_uInt16 nType = GetPropertyId( rPropName ); + if ( ( nType == BASEPROPERTY_TEXT ) || ( nType == BASEPROPERTY_EDITMASK ) || ( nType == BASEPROPERTY_LITERALMASK ) ) + { + // These masks cannot be set consecutively + OUString Text = ImplGetPropertyValue_UString( BASEPROPERTY_TEXT ); + OUString EditMask = ImplGetPropertyValue_UString( BASEPROPERTY_EDITMASK ); + OUString LiteralMask = ImplGetPropertyValue_UString( BASEPROPERTY_LITERALMASK ); + + uno::Reference < awt::XPatternField > xPF( getPeer(), uno::UNO_QUERY ); + if (xPF.is()) + { + // same comment as in UnoControl::ImplSetPeerProperty - see there + OUString sText( Text ); + ImplCheckLocalize( sText ); + xPF->setString( sText ); + xPF->setMasks( EditMask, LiteralMask ); + } + } + else + UnoSpinFieldControl::ImplSetPeerProperty( rPropName, rVal ); +} + + +// uno::XInterface +uno::Any UnoPatternFieldControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XPatternField* >(this) ); + return (aRet.hasValue() ? aRet : UnoSpinFieldControl::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoPatternFieldControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoPatternFieldControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XPatternField>::get(), + UnoSpinFieldControl::getTypes() + ); + return aTypeList.getTypes(); +} + +void UnoPatternFieldControl::setString( const OUString& rString ) +{ + setText( rString ); +} + +OUString UnoPatternFieldControl::getString() +{ + return getText(); +} + +void UnoPatternFieldControl::setMasks( const OUString& EditMask, const OUString& LiteralMask ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_EDITMASK ), uno::Any(EditMask), true ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_LITERALMASK ), uno::Any(LiteralMask), true ); +} + +void UnoPatternFieldControl::getMasks( OUString& EditMask, OUString& LiteralMask ) +{ + EditMask = ImplGetPropertyValue_UString( BASEPROPERTY_EDITMASK ); + LiteralMask = ImplGetPropertyValue_UString( BASEPROPERTY_LITERALMASK ); +} + +void UnoPatternFieldControl::setStrictFormat( sal_Bool bStrict ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_STRICTFORMAT ), uno::Any(bStrict), true ); +} + +sal_Bool UnoPatternFieldControl::isStrictFormat() +{ + return ImplGetPropertyValue_BOOL( BASEPROPERTY_STRICTFORMAT ); +} + +OUString UnoPatternFieldControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoPatternFieldControl"; +} + +css::uno::Sequence<OUString> UnoPatternFieldControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlPatternField", "stardiv.vcl.control.PatternField" }; + return comphelper::concatSequences( UnoSpinFieldControl::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoPatternFieldControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoPatternFieldControl()); +} + + + +UnoControlProgressBarModel::UnoControlProgressBarModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_BORDER ); + ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_FILLCOLOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); + ImplRegisterProperty( BASEPROPERTY_PROGRESSVALUE ); + ImplRegisterProperty( BASEPROPERTY_PROGRESSVALUE_MAX ); + ImplRegisterProperty( BASEPROPERTY_PROGRESSVALUE_MIN ); +} + +OUString UnoControlProgressBarModel::getServiceName( ) +{ + return "stardiv.vcl.controlmodel.ProgressBar"; +} + +uno::Any UnoControlProgressBarModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.ProgressBar" ) ); + } + + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlProgressBarModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlProgressBarModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlProgressBarModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlProgressBarModel"; +} + +css::uno::Sequence<OUString> +UnoControlProgressBarModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlProgressBarModel", "stardiv.vcl.controlmodel.ProgressBar" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlProgressBarModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlProgressBarModel(context)); +} + + + +UnoProgressBarControl::UnoProgressBarControl() +{ +} + +OUString UnoProgressBarControl::GetComponentServiceName() const +{ + return "ProgressBar"; +} + +// uno::XInterface +uno::Any UnoProgressBarControl::queryAggregation( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< awt::XProgressBar* >(this) ); + return (aRet.hasValue() ? aRet : UnoControlBase::queryAggregation( rType )); +} + +IMPL_IMPLEMENTATION_ID( UnoProgressBarControl ) + +// lang::XTypeProvider +css::uno::Sequence< css::uno::Type > UnoProgressBarControl::getTypes() +{ + static const ::cppu::OTypeCollection aTypeList( + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<awt::XProgressBar>::get(), + UnoControlBase::getTypes() + ); + return aTypeList.getTypes(); +} + +// css::awt::XProgressBar +void UnoProgressBarControl::setForegroundColor( sal_Int32 nColor ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_FILLCOLOR ), uno::Any(nColor), true ); +} + +void UnoProgressBarControl::setBackgroundColor( sal_Int32 nColor ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_BACKGROUNDCOLOR ), uno::Any(nColor), true ); +} + +void UnoProgressBarControl::setValue( sal_Int32 nValue ) +{ + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_PROGRESSVALUE ), uno::Any(nValue), true ); +} + +void UnoProgressBarControl::setRange( sal_Int32 nMin, sal_Int32 nMax ) +{ + uno::Any aMin; + uno::Any aMax; + + if ( nMin < nMax ) + { + // take correct min and max + aMin <<= nMin; + aMax <<= nMax; + } + else + { + // change min and max + aMin <<= nMax; + aMax <<= nMin; + } + + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_PROGRESSVALUE_MIN ), aMin, true ); + ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_PROGRESSVALUE_MAX ), aMax, true ); +} + +sal_Int32 UnoProgressBarControl::getValue() +{ + return ImplGetPropertyValue_INT32( BASEPROPERTY_PROGRESSVALUE ); +} + +OUString UnoProgressBarControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoProgressBarControl"; +} + +css::uno::Sequence<OUString> UnoProgressBarControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlProgressBar", "stardiv.vcl.control.ProgressBar" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoProgressBarControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoProgressBarControl()); +} + + + +UnoControlFixedLineModel::UnoControlFixedLineModel( const Reference< XComponentContext >& rxContext ) + :UnoControlModel( rxContext ) +{ + ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); + ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL ); + ImplRegisterProperty( BASEPROPERTY_ENABLED ); + ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE ); + ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR ); + ImplRegisterProperty( BASEPROPERTY_HELPTEXT ); + ImplRegisterProperty( BASEPROPERTY_HELPURL ); + ImplRegisterProperty( BASEPROPERTY_LABEL ); + ImplRegisterProperty( BASEPROPERTY_ORIENTATION ); + ImplRegisterProperty( BASEPROPERTY_PRINTABLE ); +} + +OUString UnoControlFixedLineModel::getServiceName( ) +{ + return "stardiv.vcl.controlmodel.FixedLine"; +} + +uno::Any UnoControlFixedLineModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const +{ + if ( nPropId == BASEPROPERTY_DEFAULTCONTROL ) + { + return uno::Any( OUString( "stardiv.vcl.control.FixedLine" ) ); + } + return UnoControlModel::ImplGetDefaultValue( nPropId ); +} + +::cppu::IPropertyArrayHelper& UnoControlFixedLineModel::getInfoHelper() +{ + static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() ); + return aHelper; +} + +// beans::XMultiPropertySet +uno::Reference< beans::XPropertySetInfo > UnoControlFixedLineModel::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +OUString UnoControlFixedLineModel::getImplementationName() +{ + return "stardiv.Toolkit.UnoControlFixedLineModel"; +} + +css::uno::Sequence<OUString> +UnoControlFixedLineModel::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlFixedLineModel", "stardiv.vcl.controlmodel.FixedLine" }; + return comphelper::concatSequences( UnoControlModel::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoControlFixedLineModel_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoControlFixedLineModel(context)); +} + + + +UnoFixedLineControl::UnoFixedLineControl() +{ + maComponentInfos.nWidth = 100; // ?? + maComponentInfos.nHeight = 100; // ?? +} + +OUString UnoFixedLineControl::GetComponentServiceName() const +{ + return "FixedLine"; +} + +sal_Bool UnoFixedLineControl::isTransparent() +{ + return true; +} + +OUString UnoFixedLineControl::getImplementationName() +{ + return "stardiv.Toolkit.UnoFixedLineControl"; +} + +css::uno::Sequence<OUString> UnoFixedLineControl::getSupportedServiceNames() +{ + const css::uno::Sequence<OUString> vals { "com.sun.star.awt.UnoControlFixedLine", "stardiv.vcl.control.FixedLine" }; + return comphelper::concatSequences( UnoControlBase::getSupportedServiceNames(), vals ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_UnoFixedLineControl_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UnoFixedLineControl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |