diff options
author | Ivo Hinkelmann <ihi@openoffice.org> | 2006-08-28 14:01:24 +0000 |
---|---|---|
committer | Ivo Hinkelmann <ihi@openoffice.org> | 2006-08-28 14:01:24 +0000 |
commit | eae0f62d3f3d1c7b8882b3da9fcfc1cdd094c40b (patch) | |
tree | b4af94484ecf78d5816fed091a270b1dfb9a3793 | |
parent | c83e5fdb25d4a8e350b9f6d3d78ad747cb3ff87f (diff) |
INTEGRATION: CWS dba205a (1.1.2); FILE ADDED
2006/08/01 10:47:55 oj 1.1.2.3: add throw()
2006/07/25 13:02:47 fs 1.1.2.2: #i65420# fire events asynchronously, if possible
2006/07/25 11:22:50 fs 1.1.2.1: helper for handling the scripting needs in a form
-rw-r--r-- | svx/source/form/fmscriptingenv.cxx | 620 |
1 files changed, 620 insertions, 0 deletions
diff --git a/svx/source/form/fmscriptingenv.cxx b/svx/source/form/fmscriptingenv.cxx new file mode 100644 index 000000000000..a7d50cd43747 --- /dev/null +++ b/svx/source/form/fmscriptingenv.cxx @@ -0,0 +1,620 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: fmscriptingenv.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: ihi $ $Date: 2006-08-28 15:01:24 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef SVX_FMSCRIPTINGENV_HXX +#include "fmscriptingenv.hxx" +#endif +#ifndef _SVX_FMMODEL_HXX +#include "fmmodel.hxx" +#endif + +/** === begin UNO includes === **/ +#ifndef _COM_SUN_STAR_LANG_ILLEGALARGUMENTEXCEPTION_HPP_ +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#endif +#ifndef _COM_SUN_STAR_SCRIPT_XSCRIPTLISTENER_HPP_ +#include <com/sun/star/script/XScriptListener.hpp> +#endif +#ifndef _COM_SUN_STAR_CONTAINER_XHIERARCHICALNAMEACCESS_HPP_ +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#endif +#ifndef _COM_SUN_STAR_REFLECTION_XINTERFACEMETHODTYPEDESCRIPTION_HPP_ +#include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_ +#include <com/sun/star/lang/DisposedException.hpp> +#endif +/** === end UNO includes === **/ + +#ifndef TOOLS_DIAGNOSE_EX_H +#include <tools/diagnose_ex.h> +#endif +#ifndef _CPPUHELPER_IMPLBASE1_HXX_ +#include <cppuhelper/implbase1.hxx> +#endif +#ifndef _COMPHELPER_IMPLEMENTATIONREFERENCE_HXX +#include <comphelper/implementationreference.hxx> +#endif +#ifndef COMPHELPER_COMPONENTCONTEXT_HXX +#include <comphelper/componentcontext.hxx> +#endif +#ifndef _COMPHELPER_PROCESSFACTORY_HXX_ +#include <comphelper/processfactory.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <vcl/svapp.hxx> +#endif +#ifndef _VOS_MUTEX_HXX_ +#include <vos/mutex.hxx> +#endif +#ifndef _SFX_OBJSH_HXX //autogen +#include <sfx2/objsh.hxx> +#endif +#ifndef COMPHELPER_ASYNCNOTIFICATION_HXX +#include <comphelper/asyncnotification.hxx> +#endif + +#include <boost/shared_ptr.hpp> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::script::XEventAttacherManager; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::script::XScriptListener; + using ::com::sun::star::script::ScriptEvent; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::reflection::InvocationTargetException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::container::XHierarchicalNameAccess; + using ::com::sun::star::reflection::XInterfaceMethodTypeDescription; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XInterface; + /** === end UNO using === **/ + + class FormScriptingEnvironment; + + typedef ::comphelper::EventHolder< ScriptEvent > ScriptEventDescription; + + //==================================================================== + //= FormScriptListener + //==================================================================== + typedef ::cppu::WeakImplHelper1 < XScriptListener + > FormScriptListener_Base; + + /** implements the XScriptListener interface, is used by FormScriptingEnvironment + */ + class FormScriptListener :public FormScriptListener_Base + ,public ::comphelper::IEventProcessor + { + private: + ::osl::Mutex m_aMutex; + ::rtl::Reference< FormScriptingEnvironment > m_pScriptExecutor; + ::rtl::Reference< ::comphelper::AsyncEventNotifier > m_pNotifier; + + public: + FormScriptListener( const ::rtl::Reference< FormScriptingEnvironment >& _pScriptExecutor ); + + // XScriptListener + virtual void SAL_CALL firing( const ScriptEvent& aEvent ) throw (RuntimeException); + virtual Any SAL_CALL approveFiring( const ScriptEvent& aEvent ) throw (InvocationTargetException, RuntimeException); + // XEventListener + virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException); + + // lifetime control + void SAL_CALL dispose(); + + // IEventProcessor + virtual void processEvent( const ::comphelper::AnyEvent& _rEvent ); + virtual void SAL_CALL acquire() throw(); + virtual void SAL_CALL release() throw(); + + protected: + ~FormScriptListener(); + + private: + /** determines whether calling a given method at a given listener interface can be done asynchronously + + @param _rListenerType + the name of the UNO type whose method is to be checked + @param _rMethodName + the name of the method at the interface determined by _rListenerType + + @return + <TRUE/> if and only if the method is declared <code>oneway</code>, i.e. can be called asynchronously + */ + bool impl_allowAsynchronousCall_nothrow( const ::rtl::OUString& _rListenerType, const ::rtl::OUString& _rMethodName ) const; + + /** determines whether the instance is already disposed + */ + bool impl_isDisposed_nothrow() const { return !m_pScriptExecutor.is(); } + + /** fires the given script event in a thread-safe manner + + This methods calls our script executor's doFireScriptEvent, with previously releasing the given mutex guard, + but ensuring that our script executor is not deleted between this release and the actual call. + + @param _rGuard + a clearable guard to our mutex. Must be the only active guard to our mutex. + @param _rEvent + the event to fire + @param _pSyncronousResult + a place to take a possible result of the script call. + + @precond + m_pScriptExecutor is not <NULL/>. + */ + void impl_doFireScriptEvent_nothrow( ::osl::ClearableMutexGuard& _rGuard, const ScriptEvent& _rEvent, Any* _pSyncronousResult ); + }; + + //==================================================================== + //= FormScriptingEnvironment + //==================================================================== + class FormScriptingEnvironment : public IFormScriptingEnvironment + { + private: + typedef ::comphelper::ImplementationReference< FormScriptListener, XScriptListener > ListenerImplementation; + + private: + ::osl::Mutex m_aMutex; + oslInterlockedCount m_refCount; + ListenerImplementation m_pScriptListener; + FmFormModel& m_rFormModel; + bool m_bDisposed; + + public: + FormScriptingEnvironment( FmFormModel& _rModel ); + virtual ~FormScriptingEnvironment(); + + // callback for FormScriptListener + void doFireScriptEvent( const ScriptEvent& _rEvent, Any* _pSyncronousResult ); + + // IFormScriptingEnvironment + virtual void registerEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager ); + virtual void revokeEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager ); + virtual void dispose(); + + // IReference + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + + private: + void impl_registerOrRevoke_throw( const Reference< XEventAttacherManager >& _rxManager, bool _bRegister ); + + private: + FormScriptingEnvironment(); // never implemented + FormScriptingEnvironment( const FormScriptingEnvironment& ); // never implemented + FormScriptingEnvironment& operator=( const FormScriptingEnvironment& ); // never implemented + }; + + //==================================================================== + //= FormScriptListener + //==================================================================== + //-------------------------------------------------------------------- + FormScriptListener::FormScriptListener( const ::rtl::Reference< FormScriptingEnvironment >& _pScriptExecutor ) + :m_pScriptExecutor( _pScriptExecutor ) + ,m_pNotifier( NULL ) + { + } + + //-------------------------------------------------------------------- + FormScriptListener::~FormScriptListener() + { + } + + //-------------------------------------------------------------------- + bool FormScriptListener::impl_allowAsynchronousCall_nothrow( const ::rtl::OUString& _rListenerType, const ::rtl::OUString& _rMethodName ) const + { + bool bAllowAsynchronousCall = false; + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + Reference< XHierarchicalNameAccess > xTypeDescriptions( aContext.getSingleton( "com.sun.star.reflection.theTypeDescriptionManager" ), UNO_QUERY_THROW ); + + ::rtl::OUString sMethodDescription( _rListenerType ); + sMethodDescription += ::rtl::OUString::createFromAscii( "::" ); + sMethodDescription += _rMethodName; + + Reference< XInterfaceMethodTypeDescription > xMethod( xTypeDescriptions->getByHierarchicalName( sMethodDescription ), UNO_QUERY_THROW ); + bAllowAsynchronousCall = xMethod->isOneway(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bAllowAsynchronousCall; + } + + //-------------------------------------------------------------------- + void FormScriptListener::impl_doFireScriptEvent_nothrow( ::osl::ClearableMutexGuard& _rGuard, const ScriptEvent& _rEvent, Any* _pSyncronousResult ) + { + OSL_PRECOND( m_pScriptExecutor.is(), "FormScriptListener::impl_doFireScriptEvent_nothrow: this will crash!" ); + + ::rtl::Reference< FormScriptingEnvironment > pExecutor( m_pScriptExecutor ); + _rGuard.clear(); + pExecutor->doFireScriptEvent( _rEvent, _pSyncronousResult ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FormScriptListener::firing( const ScriptEvent& _rEvent ) throw (RuntimeException) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + if ( impl_isDisposed_nothrow() ) + return; + + if ( !impl_allowAsynchronousCall_nothrow( _rEvent.ListenerType.getTypeName(), _rEvent.MethodName ) ) + { + impl_doFireScriptEvent_nothrow( aGuard, _rEvent, NULL ); + return; + } + + if ( !m_pNotifier.is() ) + { + m_pNotifier.set( new ::comphelper::AsyncEventNotifier ); + m_pNotifier->create(); + } + m_pNotifier->addEvent( new ScriptEventDescription( _rEvent ), this ); + } + + //-------------------------------------------------------------------- + Any SAL_CALL FormScriptListener::approveFiring( const ScriptEvent& _rEvent ) throw (InvocationTargetException, RuntimeException) + { + Any aResult; + + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + if ( !impl_isDisposed_nothrow() ) + impl_doFireScriptEvent_nothrow( aGuard, _rEvent, &aResult ); + + return aResult; + } + + //-------------------------------------------------------------------- + void SAL_CALL FormScriptListener::disposing( const EventObject& /*Source*/ ) throw (RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + void SAL_CALL FormScriptListener::dispose() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pNotifier.is() ) + { + m_pNotifier->removeEventsForProcessor( this ); + m_pNotifier->terminate(); + m_pNotifier = NULL; + } + + m_pScriptExecutor = NULL; + } + + //-------------------------------------------------------------------- + void FormScriptListener::processEvent( const ::comphelper::AnyEvent& _rEvent ) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + if ( impl_isDisposed_nothrow() ) + return; + + const ScriptEventDescription& rScriptEvent = static_cast< const ScriptEventDescription& >( _rEvent ); + impl_doFireScriptEvent_nothrow( aGuard, rScriptEvent.getEventObject(), NULL ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FormScriptListener::acquire() throw() + { + FormScriptListener_Base::acquire(); + } + + //-------------------------------------------------------------------- + void SAL_CALL FormScriptListener::release() throw() + { + FormScriptListener_Base::release(); + } + + + //==================================================================== + //= FormScriptingEnvironment + //==================================================================== + //-------------------------------------------------------------------- + FormScriptingEnvironment::FormScriptingEnvironment( FmFormModel& _rModel ) + :m_refCount( 0 ) + ,m_pScriptListener( NULL ) + ,m_rFormModel( _rModel ) + ,m_bDisposed( false ) + { + m_pScriptListener = ListenerImplementation( new FormScriptListener( this ) ); + // note that this is a cyclic reference between the FormScriptListener and the FormScriptingEnvironment + // This cycle is broken up when our instance is disposed. + } + + //-------------------------------------------------------------------- + FormScriptingEnvironment::~FormScriptingEnvironment() + { + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::impl_registerOrRevoke_throw( const Reference< XEventAttacherManager >& _rxManager, bool _bRegister ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !_rxManager.is() ) + throw IllegalArgumentException(); + if ( m_bDisposed ) + throw DisposedException(); + + try + { + if ( _bRegister ) + _rxManager->addScriptListener( m_pScriptListener.getRef() ); + else + _rxManager->removeScriptListener( m_pScriptListener.getRef() ); + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::registerEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager ) + { + impl_registerOrRevoke_throw( _rxManager, true ); + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::revokeEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager ) + { + impl_registerOrRevoke_throw( _rxManager, false ); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL FormScriptingEnvironment::acquire() + { + return osl_incrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL FormScriptingEnvironment::release() + { + if ( 0 == osl_decrementInterlockedCount( &m_refCount ) ) + { + delete this; + return 0; + } + return m_refCount; + } + + //-------------------------------------------------------------------- + IFormScriptingEnvironment::~IFormScriptingEnvironment() + { + } + + //-------------------------------------------------------------------- + namespace + { + //................................................................ + //. NewStyleUNOScript + //................................................................ + class SAL_NO_VTABLE IScript + { + public: + virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) = 0; + + virtual ~IScript() { } + }; + typedef ::boost::shared_ptr< IScript > PScript; + + //................................................................ + //. NewStyleUNOScript + //................................................................ + class NewStyleUNOScript : public IScript + { + SfxObjectShell& m_rObjectShell; + const ::rtl::OUString m_sScriptCode; + + public: + NewStyleUNOScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rScriptCode ) + :m_rObjectShell( _rObjectShell ) + ,m_sScriptCode( _rScriptCode ) + { + } + + // IScript + virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ); + }; + + //................................................................ + void NewStyleUNOScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) + { + Sequence< sal_Int16 > aOutArgsIndex; + Sequence< Any > aOutArgs; + + m_rObjectShell.CallXScript( m_sScriptCode, _rArguments, _rSynchronousResult, aOutArgsIndex, aOutArgs ); + } + + //................................................................ + //. QualifiedBasicScript + //................................................................ + class QualifiedBasicScript : public IScript + { + SfxObjectShell& m_rObjectShell; + const ::rtl::OUString m_sMacroLocation; + const ::rtl::OUString m_sScriptCode; + + public: + QualifiedBasicScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rLocation, const ::rtl::OUString& _rScriptCode ) + :m_rObjectShell( _rObjectShell ) + ,m_sMacroLocation( _rLocation ) + ,m_sScriptCode( _rScriptCode ) + { + } + + // IScript + virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ); + }; + + //................................................................ + void QualifiedBasicScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) + { + m_rObjectShell.CallStarBasicScript( m_sScriptCode, m_sMacroLocation, + &_rArguments, &_rSynchronousResult ); + } + + //................................................................ + //. UnqualifiedBasicScript + //................................................................ + class UnqualifiedBasicScript : public IScript + { + SfxObjectShell& m_rObjectShell; + const ::rtl::OUString m_sScriptCode; + + public: + UnqualifiedBasicScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rScriptCode ) + :m_rObjectShell( _rObjectShell ) + ,m_sScriptCode( _rScriptCode ) + { + } + + // IScript + virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ); + }; + + //................................................................ + void UnqualifiedBasicScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) + { + m_rObjectShell.CallScript( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StarBasic" ) ), m_sScriptCode, + &_rArguments, &_rSynchronousResult ); + } + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::doFireScriptEvent( const ScriptEvent& _rEvent, Any* _pSyncronousResult ) + { + ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + if ( m_bDisposed ) + return; + + SfxObjectShellRef xObjectShell = m_rFormModel.GetObjectShell(); + if( !xObjectShell.Is() ) + return; + + // the script to execute + PScript pScript; + + if ( !_rEvent.ScriptType.equalsAscii( "StarBasic" ) ) + { + pScript.reset( new NewStyleUNOScript( *xObjectShell, _rEvent.ScriptCode ) ); + } + else + { + ::rtl::OUString sScriptCode = _rEvent.ScriptCode; + ::rtl::OUString sMacroLocation; + + // is there a location in the script name ("application" or "document")? + sal_Int32 nPrefixLen = sScriptCode.indexOf( ':' ); + DBG_ASSERT( 0 <= nPrefixLen, "FormScriptingEnvironment::doFireScriptEvent: Basic script name in old format encountered!" ); + + if ( 0 <= nPrefixLen ) + { + // and it has such a prefix + sMacroLocation = sScriptCode.copy( 0, nPrefixLen ); + DBG_ASSERT( 0 == sMacroLocation.compareToAscii( "document" ) + || 0 == sMacroLocation.compareToAscii( "application" ), + "FormScriptingEnvironment::doFireScriptEvent: invalid (unknown) prefix!" ); + + // strip the prefix: the SfxObjectShell::CallScript knows nothing about such prefixes + sScriptCode = sScriptCode.copy( nPrefixLen + 1 ); + } + + if ( sMacroLocation.getLength() ) + { // we have a StarBasic macro with fully-qualified macro location + pScript.reset( new QualifiedBasicScript( *xObjectShell, sMacroLocation, sScriptCode ) ); + } + else + { // we have a StarBasic macro without qualified location - let the object shell gues .... + pScript.reset( new UnqualifiedBasicScript( *xObjectShell, sScriptCode ) ); + } + } + + OSL_ENSURE( pScript.get(), "FormScriptingEnvironment::doFireScriptEvent: no script to execute!" ); + if ( !pScript.get() ) + // this is an internal error in the above code + throw RuntimeException(); + + aGuard.clear(); + aSolarGuard.clear(); + + Any aIgnoreResult; + pScript->invoke( _rEvent.Arguments, _pSyncronousResult ? *_pSyncronousResult : aIgnoreResult ); + pScript.reset(); + + { + // object shells are not thread safe, so guard the destruction + ::vos::OGuard aSolarGuarsReset( Application::GetSolarMutex() ); + xObjectShell = NULL; + } + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::dispose() + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_bDisposed = true; + m_pScriptListener->dispose(); + } + + //-------------------------------------------------------------------- + PFormScriptingEnvironment createDefaultFormScriptingEnvironment( FmFormModel& _rModel ) + { + return new FormScriptingEnvironment( _rModel ); + } + +//........................................................................ +} // namespace svxform +//........................................................................ + |