diff options
Diffstat (limited to 'scripting/source/dlgprov/dlgevtatt.cxx')
-rw-r--r-- | scripting/source/dlgprov/dlgevtatt.cxx | 658 |
1 files changed, 658 insertions, 0 deletions
diff --git a/scripting/source/dlgprov/dlgevtatt.cxx b/scripting/source/dlgprov/dlgevtatt.cxx new file mode 100644 index 000000000..704518e07 --- /dev/null +++ b/scripting/source/dlgprov/dlgevtatt.cxx @@ -0,0 +1,658 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 "dlgevtatt.hxx" + +#include "dlgprov.hxx" + +#include <sfx2/strings.hrc> +#include <sfx2/sfxresid.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <tools/diagnose_ex.h> + +#include <com/sun/star/awt/XControl.hpp> +#include <com/sun/star/awt/XControlContainer.hpp> +#include <com/sun/star/awt/XDialogEventHandler.hpp> +#include <com/sun/star/awt/XContainerWindowEventHandler.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/script/ScriptEventDescriptor.hpp> +#include <com/sun/star/script/XScriptEventsSupplier.hpp> +#include <com/sun/star/script/provider/XScriptProvider.hpp> +#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp> +#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp> +#include <com/sun/star/script/vba/XVBACompatibility.hpp> +#include <com/sun/star/lang/ServiceNotRegisteredException.hpp> +#include <com/sun/star/reflection/XIdlMethod.hpp> +#include <com/sun/star/beans/MethodConcept.hpp> +#include <com/sun/star/beans/XMaterialHolder.hpp> + +#include <ooo/vba/XVBAToOOEventDescGen.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::reflection; + + +namespace dlgprov +{ + namespace { + + class DialogSFScriptListenerImpl : public DialogScriptListenerImpl + { + protected: + Reference< frame::XModel > m_xModel; + virtual void firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* pRet ) override; + public: + DialogSFScriptListenerImpl( const Reference< XComponentContext >& rxContext, const Reference< frame::XModel >& rxModel ) : DialogScriptListenerImpl( rxContext ), m_xModel( rxModel ) {} + }; + + class DialogLegacyScriptListenerImpl : public DialogSFScriptListenerImpl + { + protected: + virtual void firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* pRet ) override; + public: + DialogLegacyScriptListenerImpl( const Reference< XComponentContext >& rxContext, const Reference< frame::XModel >& rxModel ) : DialogSFScriptListenerImpl( rxContext, rxModel ){} + }; + + class DialogUnoScriptListenerImpl : public DialogSFScriptListenerImpl + { + Reference< awt::XControl > m_xControl; + Reference< XInterface > m_xHandler; + Reference< beans::XIntrospectionAccess > m_xIntrospectionAccess; + bool m_bDialogProviderMode; + + virtual void firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* pRet ) override; + + public: + DialogUnoScriptListenerImpl( const Reference< XComponentContext >& rxContext, + const Reference< frame::XModel >& rxModel, + const Reference< awt::XControl >& rxControl, + const Reference< XInterface >& rxHandler, + const Reference< beans::XIntrospectionAccess >& rxIntrospectionAccess, + bool bDialogProviderMode ); // false: ContainerWindowProvider mode + + }; + + class DialogVBAScriptListenerImpl : public DialogScriptListenerImpl + { + protected: + OUString msDialogCodeName; + OUString msDialogLibName; + Reference< script::XScriptListener > mxListener; + virtual void firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* pRet ) override; + public: + DialogVBAScriptListenerImpl( const Reference< XComponentContext >& rxContext, const Reference< awt::XControl >& rxControl, const Reference< frame::XModel >& xModel, const OUString& sDialogLibName ); + }; + + } + + DialogVBAScriptListenerImpl::DialogVBAScriptListenerImpl( const Reference< XComponentContext >& rxContext, const Reference< awt::XControl >& rxControl, const Reference< frame::XModel >& xModel, const OUString& sDialogLibName ) : DialogScriptListenerImpl( rxContext ), msDialogLibName( sDialogLibName ) + { + Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager() ); + Sequence< Any > args(1); + if ( xSMgr.is() ) + { + args.getArray()[0] <<= xModel; + mxListener.set( xSMgr->createInstanceWithArgumentsAndContext( "ooo.vba.EventListener", args, m_xContext ), UNO_QUERY ); + } + if ( !rxControl.is() ) + return; + + try + { + Reference< XPropertySet > xProps( rxControl->getModel(), UNO_QUERY_THROW ); + xProps->getPropertyValue("Name") >>= msDialogCodeName; + xProps.set( mxListener, UNO_QUERY_THROW ); + xProps->setPropertyValue("Model", args[ 0 ] ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("scripting"); + } + + } + + void DialogVBAScriptListenerImpl::firing_impl( const script::ScriptEvent& aScriptEvent, uno::Any* ) + { + if ( !(aScriptEvent.ScriptType == "VBAInterop" && mxListener.is()) ) + return; + + ScriptEvent aScriptEventCopy( aScriptEvent ); + aScriptEventCopy.ScriptCode = msDialogLibName + "." + msDialogCodeName; + try + { + mxListener->firing( aScriptEventCopy ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("scripting"); + } + } + + + // DialogEventsAttacherImpl + + + DialogEventsAttacherImpl::DialogEventsAttacherImpl( const Reference< XComponentContext >& rxContext, const Reference< frame::XModel >& rxModel, const Reference< awt::XControl >& rxControl, const Reference< XInterface >& rxHandler, const Reference< beans::XIntrospectionAccess >& rxIntrospect, bool bProviderMode, const Reference< script::XScriptListener >& rxRTLListener, const OUString& sDialogLibName ) + :mbUseFakeVBAEvents( false ), m_xContext( rxContext ) + { + // key listeners by protocol when ScriptType = 'Script' + // otherwise key is the ScriptType e.g. StarBasic + if ( rxRTLListener.is() ) // set up handler for RTL_BASIC + listenersForTypes[ OUString("StarBasic") ] = rxRTLListener; + else + listenersForTypes[ OUString("StarBasic") ] = new DialogLegacyScriptListenerImpl( rxContext, rxModel ); + // handler for Script & OUString("vnd.sun.star.UNO:") + listenersForTypes[ OUString("vnd.sun.star.UNO") ] = new DialogUnoScriptListenerImpl( rxContext, rxModel, rxControl, rxHandler, rxIntrospect, bProviderMode ); + listenersForTypes[ OUString("vnd.sun.star.script") ] = new DialogSFScriptListenerImpl( rxContext, rxModel ); + + // determine the VBA compatibility mode from the Basic library container + try + { + uno::Reference< beans::XPropertySet > xModelProps( rxModel, uno::UNO_QUERY_THROW ); + uno::Reference< script::vba::XVBACompatibility > xVBACompat( + xModelProps->getPropertyValue("BasicLibraries"), uno::UNO_QUERY_THROW ); + mbUseFakeVBAEvents = xVBACompat->getVBACompatibilityMode(); + } + catch( uno::Exception& ) + { + } + if ( mbUseFakeVBAEvents ) + listenersForTypes[ OUString("VBAInterop") ] = new DialogVBAScriptListenerImpl( rxContext, rxControl, rxModel, sDialogLibName ); + } + + + DialogEventsAttacherImpl::~DialogEventsAttacherImpl() + { + } + + + Reference< script::XScriptListener > const & + DialogEventsAttacherImpl::getScriptListenerForKey( const OUString& sKey ) + { + ListenerHash::iterator it = listenersForTypes.find( sKey ); + if ( it == listenersForTypes.end() ) + throw RuntimeException(); // more text info here please + return it->second; + } + Reference< XScriptEventsSupplier > DialogEventsAttacherImpl::getFakeVbaEventsSupplier( const Reference< XControl >& xControl, OUString const & sControlName ) + { + Reference< XScriptEventsSupplier > xEventsSupplier; + Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager() ); + if ( xSMgr.is() ) + { + Reference< ooo::vba::XVBAToOOEventDescGen > xVBAToOOEvtDesc( xSMgr->createInstanceWithContext("ooo.vba.VBAToOOEventDesc", m_xContext ), UNO_QUERY ); + if ( xVBAToOOEvtDesc.is() ) + xEventsSupplier = xVBAToOOEvtDesc->getEventSupplier( xControl, sControlName ); + + } + return xEventsSupplier; + } + + + void DialogEventsAttacherImpl::attachEventsToControl( const Reference< XControl>& xControl, const Reference< XScriptEventsSupplier >& xEventsSupplier, const Any& Helper ) + { + if ( !xEventsSupplier.is() ) + return; + + Reference< container::XNameContainer > xEventCont = xEventsSupplier->getEvents(); + + Reference< XControlModel > xControlModel = xControl->getModel(); + if ( !xEventCont.is() ) + return; + + const Sequence< OUString > aNames = xEventCont->getElementNames(); + + for ( const OUString& rName : aNames ) + { + ScriptEventDescriptor aDesc; + + Any aElement = xEventCont->getByName( rName ); + aElement >>= aDesc; + OUString sKey = aDesc.ScriptType; + if ( aDesc.ScriptType == "Script" || aDesc.ScriptType == "UNO" ) + { + sal_Int32 nIndex = aDesc.ScriptCode.indexOf( ':' ); + sKey = aDesc.ScriptCode.copy( 0, nIndex ); + } + Reference< XAllListener > xAllListener = + new DialogAllListenerImpl( getScriptListenerForKey( sKey ), aDesc.ScriptType, aDesc.ScriptCode ); + + // try first to attach event to the ControlModel + bool bSuccess = false; + try + { + Reference< XEventListener > xListener_ = m_xEventAttacher->attachSingleEventListener( + xControlModel, xAllListener, Helper, aDesc.ListenerType, + aDesc.AddListenerParam, aDesc.EventMethod ); + + if ( xListener_.is() ) + bSuccess = true; + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("scripting"); + } + + try + { + // if we had no success, try to attach to the control + if ( !bSuccess ) + { + m_xEventAttacher->attachSingleEventListener( + xControl, xAllListener, Helper, aDesc.ListenerType, + aDesc.AddListenerParam, aDesc.EventMethod ); + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("scripting"); + } + } + } + + + void DialogEventsAttacherImpl::nestedAttachEvents( const Sequence< Reference< XInterface > >& Objects, const Any& Helper, OUString& sDialogCodeName ) + { + for ( const Reference< XInterface >& rObject : Objects ) + { + // We know that we have to do with instances of XControl. + // Otherwise this is not the right implementation for + // XScriptEventsAttacher and we have to give up. + Reference< XControl > xControl( rObject, UNO_QUERY ); + Reference< XControlContainer > xControlContainer( xControl, UNO_QUERY ); + Reference< XDialog > xDialog( xControl, UNO_QUERY ); + if ( !xControl.is() ) + throw IllegalArgumentException(); + + // get XEventsSupplier from control model + Reference< XControlModel > xControlModel = xControl->getModel(); + Reference< XScriptEventsSupplier > xEventsSupplier( xControlModel, UNO_QUERY ); + attachEventsToControl( xControl, xEventsSupplier, Helper ); + if ( mbUseFakeVBAEvents ) + { + xEventsSupplier.set( getFakeVbaEventsSupplier( xControl, sDialogCodeName ) ); + Any newHelper(xControl ); + attachEventsToControl( xControl, xEventsSupplier, newHelper ); + } + if ( xControlContainer.is() && !xDialog.is() ) + { + Sequence< Reference< XControl > > aControls = xControlContainer->getControls(); + sal_Int32 nControlCount = aControls.getLength(); + + Sequence< Reference< XInterface > > aObjects( nControlCount ); + Reference< XInterface >* pObjects2 = aObjects.getArray(); + const Reference< XControl >* pControls = aControls.getConstArray(); + + for ( sal_Int32 i2 = 0; i2 < nControlCount; ++i2 ) + { + pObjects2[i2].set( pControls[i2], UNO_QUERY ); + } + nestedAttachEvents( aObjects, Helper, sDialogCodeName ); + } + } + } + + + // XScriptEventsAttacher + + + void SAL_CALL DialogEventsAttacherImpl::attachEvents( const Sequence< Reference< XInterface > >& Objects, + const css::uno::Reference<css::script::XScriptListener>&, + const Any& Helper ) + { + // get EventAttacher + { + ::osl::MutexGuard aGuard( getMutex() ); + + if ( !m_xEventAttacher.is() ) + { + Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager() ); + if ( !xSMgr.is() ) + throw RuntimeException(); + + m_xEventAttacher.set( xSMgr->createInstanceWithContext( + "com.sun.star.script.EventAttacher", m_xContext ), UNO_QUERY ); + + if ( !m_xEventAttacher.is() ) + throw ServiceNotRegisteredException(); + } + } + OUString sDialogCodeName; + sal_Int32 nObjCount = Objects.getLength(); + Reference< awt::XControl > xDlgControl( Objects[ nObjCount - 1 ], uno::UNO_QUERY ); // last object is the dialog + if ( xDlgControl.is() ) + { + Reference< XPropertySet > xProps( xDlgControl->getModel(), UNO_QUERY ); + try + { + xProps->getPropertyValue("Name") >>= sDialogCodeName; + } + catch( Exception& ){} + } + // go over all objects + nestedAttachEvents( Objects, Helper, sDialogCodeName ); + } + + + // DialogAllListenerImpl + + + DialogAllListenerImpl::DialogAllListenerImpl( const Reference< XScriptListener >& rxListener, + const OUString& rScriptType, const OUString& rScriptCode ) + :m_xScriptListener( rxListener ) + ,m_sScriptType( rScriptType ) + ,m_sScriptCode( rScriptCode ) + { + } + + + DialogAllListenerImpl::~DialogAllListenerImpl() + { + } + + + void DialogAllListenerImpl::firing_impl( const AllEventObject& Event, Any* pRet ) + { + ScriptEvent aScriptEvent; + aScriptEvent.Source = static_cast<OWeakObject *>(this); // get correct XInterface + aScriptEvent.ListenerType = Event.ListenerType; + aScriptEvent.MethodName = Event.MethodName; + aScriptEvent.Arguments = Event.Arguments; + aScriptEvent.Helper = Event.Helper; + aScriptEvent.ScriptType = m_sScriptType; + aScriptEvent.ScriptCode = m_sScriptCode; + + if ( m_xScriptListener.is() ) + { + if ( pRet ) + *pRet = m_xScriptListener->approveFiring( aScriptEvent ); + else + m_xScriptListener->firing( aScriptEvent ); + } + } + + + // XEventListener + + + void DialogAllListenerImpl::disposing(const EventObject& ) + { + } + + + // XAllListener + + + void DialogAllListenerImpl::firing( const AllEventObject& Event ) + { + //::osl::MutexGuard aGuard( getMutex() ); + + firing_impl( Event, nullptr ); + } + + + Any DialogAllListenerImpl::approveFiring( const AllEventObject& Event ) + { + //::osl::MutexGuard aGuard( getMutex() ); + + Any aReturn; + firing_impl( Event, &aReturn ); + return aReturn; + } + + + // DialogScriptListenerImpl + + + DialogUnoScriptListenerImpl::DialogUnoScriptListenerImpl( const Reference< XComponentContext >& rxContext, + const Reference< css::frame::XModel >& rxModel, + const Reference< css::awt::XControl >& rxControl, + const Reference< css::uno::XInterface >& rxHandler, + const Reference< css::beans::XIntrospectionAccess >& rxIntrospectionAccess, + bool bDialogProviderMode ) + : DialogSFScriptListenerImpl( rxContext, rxModel ) + ,m_xControl( rxControl ) + ,m_xHandler( rxHandler ) + ,m_xIntrospectionAccess( rxIntrospectionAccess ) + ,m_bDialogProviderMode( bDialogProviderMode ) + { + } + + + DialogScriptListenerImpl::~DialogScriptListenerImpl() + { + } + + + void DialogSFScriptListenerImpl::firing_impl( const ScriptEvent& aScriptEvent, Any* pRet ) + { + try + { + Reference< provider::XScriptProvider > xScriptProvider; + if ( m_xModel.is() ) + { + Reference< provider::XScriptProviderSupplier > xSupplier( m_xModel, UNO_QUERY ); + OSL_ENSURE( xSupplier.is(), "DialogScriptListenerImpl::firing_impl: failed to get script provider supplier" ); + if ( xSupplier.is() ) + xScriptProvider.set( xSupplier->getScriptProvider() ); + } + else + { + OSL_ASSERT( m_xContext.is() ); + if ( m_xContext.is() ) + { + Reference< provider::XScriptProviderFactory > xFactory = + provider::theMasterScriptProviderFactory::get( m_xContext ); + + Any aCtx; + aCtx <<= OUString("user"); + xScriptProvider = xFactory->createScriptProvider( aCtx ); + } + } + + OSL_ENSURE( xScriptProvider.is(), "DialogScriptListenerImpl::firing_impl: failed to get script provider" ); + + if ( xScriptProvider.is() ) + { + Reference< provider::XScript > xScript = xScriptProvider->getScript( aScriptEvent.ScriptCode ); + OSL_ENSURE( xScript.is(), "DialogScriptListenerImpl::firing_impl: failed to get script" ); + + if ( xScript.is() ) + { + Sequence< Any > aInParams; + Sequence< sal_Int16 > aOutParamsIndex; + Sequence< Any > aOutParams; + + // get arguments for script + aInParams = aScriptEvent.Arguments; + + Any aResult = xScript->invoke( aInParams, aOutParamsIndex, aOutParams ); + if ( pRet ) + *pRet = aResult; + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("scripting"); + } + } + + void DialogLegacyScriptListenerImpl::firing_impl( const ScriptEvent& aScriptEvent, Any* pRet ) + { + OUString sScriptURL; + OUString sScriptCode( aScriptEvent.ScriptCode ); + + if ( aScriptEvent.ScriptType != "StarBasic" ) + return; + + // StarBasic script: convert ScriptCode to scriptURL + sal_Int32 nIndex = sScriptCode.indexOf( ':' ); + if ( nIndex >= 0 && nIndex < sScriptCode.getLength() ) + { + sScriptURL = OUString::Concat("vnd.sun.star.script:") + + sScriptCode.subView( nIndex + 1 ) + + "?language=Basic&location=" + + sScriptCode.subView( 0, nIndex ); + } + ScriptEvent aSFScriptEvent( aScriptEvent ); + aSFScriptEvent.ScriptCode = sScriptURL; + DialogSFScriptListenerImpl::firing_impl( aSFScriptEvent, pRet ); + } + + void DialogUnoScriptListenerImpl::firing_impl( const ScriptEvent& aScriptEvent, Any* pRet ) + { + OUString aMethodName = aScriptEvent.ScriptCode.copy( strlen("vnd.sun.star.UNO:") ); + + const Any* pArguments = aScriptEvent.Arguments.getConstArray(); + Any aEventObject = pArguments[0]; + + bool bHandled = false; + if( m_xHandler.is() ) + { + if( m_bDialogProviderMode ) + { + Reference< XDialogEventHandler > xDialogEventHandler( m_xHandler, UNO_QUERY ); + if( xDialogEventHandler.is() ) + { + Reference< XDialog > xDialog( m_xControl, UNO_QUERY ); + bHandled = xDialogEventHandler->callHandlerMethod( xDialog, aEventObject, aMethodName ); + } + } + else + { + Reference< XContainerWindowEventHandler > xContainerWindowEventHandler( m_xHandler, UNO_QUERY ); + if( xContainerWindowEventHandler.is() ) + { + Reference< XWindow > xWindow( m_xControl, UNO_QUERY ); + bHandled = xContainerWindowEventHandler->callHandlerMethod( xWindow, aEventObject, aMethodName ); + } + } + } + + Any aRet; + if( !bHandled && m_xIntrospectionAccess.is() ) + { + try + { + // call method + const Reference< XIdlMethod >& rxMethod = m_xIntrospectionAccess-> + getMethod( aMethodName, MethodConcept::ALL - MethodConcept::DANGEROUS ); + + Reference< XMaterialHolder > xMaterialHolder = + Reference< XMaterialHolder >::query( m_xIntrospectionAccess ); + Any aHandlerObject = xMaterialHolder->getMaterial(); + + Sequence< Reference< XIdlClass > > aParamTypeSeq = rxMethod->getParameterTypes(); + sal_Int32 nParamCount = aParamTypeSeq.getLength(); + if( nParamCount == 0 ) + { + Sequence<Any> args; + rxMethod->invoke( aHandlerObject, args ); + bHandled = true; + } + else if( nParamCount == 2 ) + { + // Signature check automatically done by reflection + Sequence<Any> Args(2); + Any* pArgs = Args.getArray(); + if( m_bDialogProviderMode ) + { + Reference< XDialog > xDialog( m_xControl, UNO_QUERY ); + pArgs[0] <<= xDialog; + } + else + { + Reference< XWindow > xWindow( m_xControl, UNO_QUERY ); + pArgs[0] <<= xWindow; + } + pArgs[1] = aEventObject; + aRet = rxMethod->invoke( aHandlerObject, Args ); + bHandled = true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("scripting"); + } + } + + if( bHandled ) + { + if( pRet ) + *pRet = aRet; + } + else + { + OUString aRes(SfxResId(STR_ERRUNOEVENTBINDUNG)); + OUString aQuoteChar( "\"" ); + + sal_Int32 nIndex = aRes.indexOf( '%' ); + + OUString aOUFinal = + aRes.subView( 0, nIndex ) + + aQuoteChar + aMethodName + aQuoteChar + + aRes.subView( nIndex + 2 ); + + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr, + VclMessageType::Warning, VclButtonsType::Ok, aOUFinal)); + xBox->run(); + } + } + + + // XEventListener + + + void DialogScriptListenerImpl::disposing(const EventObject& ) + { + } + + + // XScriptListener + + + void DialogScriptListenerImpl::firing( const ScriptEvent& aScriptEvent ) + { + //::osl::MutexGuard aGuard( getMutex() ); + + firing_impl( aScriptEvent, nullptr ); + } + + + Any DialogScriptListenerImpl::approveFiring( const ScriptEvent& aScriptEvent ) + { + //::osl::MutexGuard aGuard( getMutex() ); + + Any aReturn; + firing_impl( aScriptEvent, &aReturn ); + return aReturn; + } + + +} // namespace dlgprov + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |