update dev300-m58
[ooovba.git] / svx / source / form / fmscriptingenv.cxx
blobab444c5917b66e9c1bdfcf118512f2bd2757c788
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fmscriptingenv.cxx,v $
10 * $Revision: 1.6 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include "fmscriptingenv.hxx"
34 #include <svx/fmmodel.hxx>
36 /** === begin UNO includes === **/
37 #include <com/sun/star/lang/IllegalArgumentException.hpp>
38 #include <com/sun/star/script/XScriptListener.hpp>
39 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
40 #include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp>
41 #include <com/sun/star/lang/DisposedException.hpp>
42 #include <com/sun/star/lang/EventObject.hpp>
43 #include <com/sun/star/awt/XControl.hpp>
44 /** === end UNO includes === **/
45 #include <tools/diagnose_ex.h>
46 #include <cppuhelper/implbase1.hxx>
47 #include <comphelper/implementationreference.hxx>
48 #include <comphelper/componentcontext.hxx>
49 #include <comphelper/processfactory.hxx>
50 #include <vcl/svapp.hxx>
51 #include <vos/mutex.hxx>
52 #include <sfx2/objsh.hxx>
54 #include <boost/shared_ptr.hpp>
56 //........................................................................
57 namespace svxform
59 //........................................................................
61 /** === begin UNO using === **/
62 using ::com::sun::star::uno::Reference;
63 using ::com::sun::star::script::XEventAttacherManager;
64 using ::com::sun::star::lang::IllegalArgumentException;
65 using ::com::sun::star::script::XScriptListener;
66 using ::com::sun::star::script::ScriptEvent;
67 using ::com::sun::star::uno::RuntimeException;
68 using ::com::sun::star::lang::EventObject;
69 using ::com::sun::star::reflection::InvocationTargetException;
70 using ::com::sun::star::uno::Any;
71 using ::com::sun::star::container::XHierarchicalNameAccess;
72 using ::com::sun::star::reflection::XInterfaceMethodTypeDescription;
73 using ::com::sun::star::uno::UNO_QUERY_THROW;
74 using ::com::sun::star::lang::DisposedException;
75 using ::com::sun::star::uno::RuntimeException;
76 using ::com::sun::star::uno::Exception;
77 using ::com::sun::star::uno::Sequence;
78 using ::com::sun::star::uno::XInterface;
79 using ::com::sun::star::lang::EventObject;
80 using ::com::sun::star::awt::XControl;
81 using ::com::sun::star::beans::XPropertySet;
82 /** === end UNO using === **/
84 class FormScriptingEnvironment;
86 //====================================================================
87 //= FormScriptListener
88 //====================================================================
89 typedef ::cppu::WeakImplHelper1 < XScriptListener
90 > FormScriptListener_Base;
92 /** implements the XScriptListener interface, is used by FormScriptingEnvironment
94 class FormScriptListener :public FormScriptListener_Base
96 private:
97 ::osl::Mutex m_aMutex;
98 ::rtl::Reference< FormScriptingEnvironment > m_pScriptExecutor;
100 public:
101 FormScriptListener( const ::rtl::Reference< FormScriptingEnvironment >& _pScriptExecutor );
103 // XScriptListener
104 virtual void SAL_CALL firing( const ScriptEvent& aEvent ) throw (RuntimeException);
105 virtual Any SAL_CALL approveFiring( const ScriptEvent& aEvent ) throw (InvocationTargetException, RuntimeException);
106 // XEventListener
107 virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException);
109 // lifetime control
110 void SAL_CALL dispose();
112 protected:
113 ~FormScriptListener();
115 private:
116 /** determines whether calling a given method at a given listener interface can be done asynchronously
118 @param _rListenerType
119 the name of the UNO type whose method is to be checked
120 @param _rMethodName
121 the name of the method at the interface determined by _rListenerType
123 @return
124 <TRUE/> if and only if the method is declared <code>oneway</code>, i.e. can be called asynchronously
126 bool impl_allowAsynchronousCall_nothrow( const ::rtl::OUString& _rListenerType, const ::rtl::OUString& _rMethodName ) const;
128 /** determines whether the instance is already disposed
130 bool impl_isDisposed_nothrow() const { return !m_pScriptExecutor.is(); }
132 /** fires the given script event in a thread-safe manner
134 This methods calls our script executor's doFireScriptEvent, with previously releasing the given mutex guard,
135 but ensuring that our script executor is not deleted between this release and the actual call.
137 @param _rGuard
138 a clearable guard to our mutex. Must be the only active guard to our mutex.
139 @param _rEvent
140 the event to fire
141 @param _pSyncronousResult
142 a place to take a possible result of the script call.
144 @precond
145 m_pScriptExecutor is not <NULL/>.
147 void impl_doFireScriptEvent_nothrow( ::osl::ClearableMutexGuard& _rGuard, const ScriptEvent& _rEvent, Any* _pSyncronousResult );
149 private:
150 DECL_LINK( OnAsyncScriptEvent, ScriptEvent* );
153 //====================================================================
154 //= FormScriptingEnvironment
155 //====================================================================
156 class FormScriptingEnvironment : public IFormScriptingEnvironment
158 private:
159 typedef ::comphelper::ImplementationReference< FormScriptListener, XScriptListener > ListenerImplementation;
161 private:
162 ::osl::Mutex m_aMutex;
163 oslInterlockedCount m_refCount;
164 ListenerImplementation m_pScriptListener;
165 FmFormModel& m_rFormModel;
166 bool m_bDisposed;
168 public:
169 FormScriptingEnvironment( FmFormModel& _rModel );
170 virtual ~FormScriptingEnvironment();
172 // callback for FormScriptListener
173 void doFireScriptEvent( const ScriptEvent& _rEvent, Any* _pSyncronousResult );
175 // IFormScriptingEnvironment
176 virtual void registerEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager );
177 virtual void revokeEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager );
178 virtual void dispose();
180 // IReference
181 virtual oslInterlockedCount SAL_CALL acquire();
182 virtual oslInterlockedCount SAL_CALL release();
184 private:
185 void impl_registerOrRevoke_throw( const Reference< XEventAttacherManager >& _rxManager, bool _bRegister );
187 private:
188 FormScriptingEnvironment(); // never implemented
189 FormScriptingEnvironment( const FormScriptingEnvironment& ); // never implemented
190 FormScriptingEnvironment& operator=( const FormScriptingEnvironment& ); // never implemented
193 //====================================================================
194 //= FormScriptListener
195 //====================================================================
196 //--------------------------------------------------------------------
197 FormScriptListener::FormScriptListener( const ::rtl::Reference< FormScriptingEnvironment >& _pScriptExecutor )
198 :m_pScriptExecutor( _pScriptExecutor )
202 //--------------------------------------------------------------------
203 FormScriptListener::~FormScriptListener()
207 //--------------------------------------------------------------------
208 bool FormScriptListener::impl_allowAsynchronousCall_nothrow( const ::rtl::OUString& _rListenerType, const ::rtl::OUString& _rMethodName ) const
210 bool bAllowAsynchronousCall = false;
213 ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() );
214 Reference< XHierarchicalNameAccess > xTypeDescriptions( aContext.getSingleton( "com.sun.star.reflection.theTypeDescriptionManager" ), UNO_QUERY_THROW );
216 ::rtl::OUString sMethodDescription( _rListenerType );
217 sMethodDescription += ::rtl::OUString::createFromAscii( "::" );
218 sMethodDescription += _rMethodName;
220 Reference< XInterfaceMethodTypeDescription > xMethod( xTypeDescriptions->getByHierarchicalName( sMethodDescription ), UNO_QUERY_THROW );
221 bAllowAsynchronousCall = xMethod->isOneway();
223 catch( const Exception& )
225 DBG_UNHANDLED_EXCEPTION();
227 return bAllowAsynchronousCall;
230 //--------------------------------------------------------------------
231 void FormScriptListener::impl_doFireScriptEvent_nothrow( ::osl::ClearableMutexGuard& _rGuard, const ScriptEvent& _rEvent, Any* _pSyncronousResult )
233 OSL_PRECOND( m_pScriptExecutor.is(), "FormScriptListener::impl_doFireScriptEvent_nothrow: this will crash!" );
235 ::rtl::Reference< FormScriptingEnvironment > pExecutor( m_pScriptExecutor );
236 _rGuard.clear();
237 pExecutor->doFireScriptEvent( _rEvent, _pSyncronousResult );
240 //--------------------------------------------------------------------
241 void SAL_CALL FormScriptListener::firing( const ScriptEvent& _rEvent ) throw (RuntimeException)
243 ::osl::ClearableMutexGuard aGuard( m_aMutex );
244 static const ::rtl::OUString vbaInterOp =
245 ::rtl::OUString::createFromAscii("VBAInterop");
246 if ( _rEvent.ScriptType.equals(vbaInterOp) )
247 return; // not handled here
249 if ( impl_isDisposed_nothrow() )
250 return;
252 if ( !impl_allowAsynchronousCall_nothrow( _rEvent.ListenerType.getTypeName(), _rEvent.MethodName ) )
254 impl_doFireScriptEvent_nothrow( aGuard, _rEvent, NULL );
255 return;
258 acquire();
259 Application::PostUserEvent( LINK( this, FormScriptListener, OnAsyncScriptEvent ), new ScriptEvent( _rEvent ) );
262 //--------------------------------------------------------------------
263 Any SAL_CALL FormScriptListener::approveFiring( const ScriptEvent& _rEvent ) throw (InvocationTargetException, RuntimeException)
265 Any aResult;
267 ::osl::ClearableMutexGuard aGuard( m_aMutex );
268 if ( !impl_isDisposed_nothrow() )
269 impl_doFireScriptEvent_nothrow( aGuard, _rEvent, &aResult );
271 return aResult;
274 //--------------------------------------------------------------------
275 void SAL_CALL FormScriptListener::disposing( const EventObject& /*Source*/ ) throw (RuntimeException)
277 // not interested in
280 //--------------------------------------------------------------------
281 void SAL_CALL FormScriptListener::dispose()
283 ::osl::MutexGuard aGuard( m_aMutex );
284 m_pScriptExecutor = NULL;
287 //--------------------------------------------------------------------
288 IMPL_LINK( FormScriptListener, OnAsyncScriptEvent, ScriptEvent*, _pEvent )
290 OSL_PRECOND( _pEvent != NULL, "FormScriptListener::OnAsyncScriptEvent: invalid event!" );
291 if ( !_pEvent )
292 return 1L;
295 ::osl::ClearableMutexGuard aGuard( m_aMutex );
297 if ( !impl_isDisposed_nothrow() )
298 impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, NULL );
301 delete _pEvent;
302 // we acquired ourself immediately before posting the event
303 release();
304 return 0L;
307 //====================================================================
308 //= FormScriptingEnvironment
309 //====================================================================
310 //--------------------------------------------------------------------
311 FormScriptingEnvironment::FormScriptingEnvironment( FmFormModel& _rModel )
312 :m_refCount( 0 )
313 ,m_pScriptListener( NULL )
314 ,m_rFormModel( _rModel )
315 ,m_bDisposed( false )
317 m_pScriptListener = ListenerImplementation( new FormScriptListener( this ) );
318 // note that this is a cyclic reference between the FormScriptListener and the FormScriptingEnvironment
319 // This cycle is broken up when our instance is disposed.
322 //--------------------------------------------------------------------
323 FormScriptingEnvironment::~FormScriptingEnvironment()
327 //--------------------------------------------------------------------
328 void FormScriptingEnvironment::impl_registerOrRevoke_throw( const Reference< XEventAttacherManager >& _rxManager, bool _bRegister )
330 ::osl::MutexGuard aGuard( m_aMutex );
332 if ( !_rxManager.is() )
333 throw IllegalArgumentException();
334 if ( m_bDisposed )
335 throw DisposedException();
339 if ( _bRegister )
340 _rxManager->addScriptListener( m_pScriptListener.getRef() );
341 else
342 _rxManager->removeScriptListener( m_pScriptListener.getRef() );
344 catch( const RuntimeException& ) { throw; }
345 catch( const Exception& )
347 DBG_UNHANDLED_EXCEPTION();
351 //--------------------------------------------------------------------
352 void FormScriptingEnvironment::registerEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager )
354 impl_registerOrRevoke_throw( _rxManager, true );
357 //--------------------------------------------------------------------
358 void FormScriptingEnvironment::revokeEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager )
360 impl_registerOrRevoke_throw( _rxManager, false );
363 //--------------------------------------------------------------------
364 oslInterlockedCount SAL_CALL FormScriptingEnvironment::acquire()
366 return osl_incrementInterlockedCount( &m_refCount );
369 //--------------------------------------------------------------------
370 oslInterlockedCount SAL_CALL FormScriptingEnvironment::release()
372 if ( 0 == osl_decrementInterlockedCount( &m_refCount ) )
374 delete this;
375 return 0;
377 return m_refCount;
380 //--------------------------------------------------------------------
381 IFormScriptingEnvironment::~IFormScriptingEnvironment()
385 //--------------------------------------------------------------------
386 namespace
388 //................................................................
389 //. NewStyleUNOScript
390 //................................................................
391 class SAL_NO_VTABLE IScript
393 public:
394 virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) = 0;
396 virtual ~IScript() { }
398 typedef ::boost::shared_ptr< IScript > PScript;
400 //................................................................
401 //. NewStyleUNOScript
402 //................................................................
403 class NewStyleUNOScript : public IScript
405 SfxObjectShell& m_rObjectShell;
406 const ::rtl::OUString m_sScriptCode;
408 public:
409 NewStyleUNOScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rScriptCode )
410 :m_rObjectShell( _rObjectShell )
411 ,m_sScriptCode( _rScriptCode )
415 // IScript
416 virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult );
419 //................................................................
420 void NewStyleUNOScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult )
422 Sequence< sal_Int16 > aOutArgsIndex;
423 Sequence< Any > aOutArgs;
424 EventObject aEvent;
425 Any aCaller;
426 if ( ( _rArguments.getLength() > 0 ) && ( _rArguments[ 0 ] >>= aEvent ) )
430 Reference< XControl > xControl( aEvent.Source, UNO_QUERY_THROW );
431 Reference< XPropertySet > xProps( xControl->getModel(), UNO_QUERY_THROW );
432 aCaller = xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) );
434 catch( Exception& ) {}
436 m_rObjectShell.CallXScript( m_sScriptCode, _rArguments, _rSynchronousResult, aOutArgsIndex, aOutArgs, true, aCaller.hasValue() ? &aCaller : 0 );
439 //................................................................
440 //. QualifiedBasicScript
441 //................................................................
442 class QualifiedBasicScript : public IScript
444 SfxObjectShell& m_rObjectShell;
445 const ::rtl::OUString m_sMacroLocation;
446 const ::rtl::OUString m_sScriptCode;
448 public:
449 QualifiedBasicScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rLocation, const ::rtl::OUString& _rScriptCode )
450 :m_rObjectShell( _rObjectShell )
451 ,m_sMacroLocation( _rLocation )
452 ,m_sScriptCode( _rScriptCode )
456 // IScript
457 virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult );
460 //................................................................
461 void QualifiedBasicScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult )
463 m_rObjectShell.CallStarBasicScript( m_sScriptCode, m_sMacroLocation,
464 &_rArguments, &_rSynchronousResult );
467 //................................................................
468 //. UnqualifiedBasicScript
469 //................................................................
470 class UnqualifiedBasicScript : public IScript
472 SfxObjectShell& m_rObjectShell;
473 const ::rtl::OUString m_sScriptCode;
475 public:
476 UnqualifiedBasicScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rScriptCode )
477 :m_rObjectShell( _rObjectShell )
478 ,m_sScriptCode( _rScriptCode )
482 // IScript
483 virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult );
486 //................................................................
487 void UnqualifiedBasicScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult )
489 m_rObjectShell.CallScript( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StarBasic" ) ), m_sScriptCode,
490 &_rArguments, &_rSynchronousResult );
494 //--------------------------------------------------------------------
495 void FormScriptingEnvironment::doFireScriptEvent( const ScriptEvent& _rEvent, Any* _pSyncronousResult )
497 ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
498 ::osl::ClearableMutexGuard aGuard( m_aMutex );
500 if ( m_bDisposed )
501 return;
503 SfxObjectShellRef xObjectShell = m_rFormModel.GetObjectShell();
504 if( !xObjectShell.Is() )
505 return;
507 // the script to execute
508 PScript pScript;
510 if ( !_rEvent.ScriptType.equalsAscii( "StarBasic" ) )
512 pScript.reset( new NewStyleUNOScript( *xObjectShell, _rEvent.ScriptCode ) );
514 else
516 ::rtl::OUString sScriptCode = _rEvent.ScriptCode;
517 ::rtl::OUString sMacroLocation;
519 // is there a location in the script name ("application" or "document")?
520 sal_Int32 nPrefixLen = sScriptCode.indexOf( ':' );
521 DBG_ASSERT( 0 <= nPrefixLen, "FormScriptingEnvironment::doFireScriptEvent: Basic script name in old format encountered!" );
523 if ( 0 <= nPrefixLen )
525 // and it has such a prefix
526 sMacroLocation = sScriptCode.copy( 0, nPrefixLen );
527 DBG_ASSERT( 0 == sMacroLocation.compareToAscii( "document" )
528 || 0 == sMacroLocation.compareToAscii( "application" ),
529 "FormScriptingEnvironment::doFireScriptEvent: invalid (unknown) prefix!" );
531 // strip the prefix: the SfxObjectShell::CallScript knows nothing about such prefixes
532 sScriptCode = sScriptCode.copy( nPrefixLen + 1 );
535 if ( sMacroLocation.getLength() )
536 { // we have a StarBasic macro with fully-qualified macro location
537 pScript.reset( new QualifiedBasicScript( *xObjectShell, sMacroLocation, sScriptCode ) );
539 else
540 { // we have a StarBasic macro without qualified location - let the object shell gues ....
541 pScript.reset( new UnqualifiedBasicScript( *xObjectShell, sScriptCode ) );
545 OSL_ENSURE( pScript.get(), "FormScriptingEnvironment::doFireScriptEvent: no script to execute!" );
546 if ( !pScript.get() )
547 // this is an internal error in the above code
548 throw RuntimeException();
550 aGuard.clear();
551 aSolarGuard.clear();
553 Any aIgnoreResult;
554 pScript->invoke( _rEvent.Arguments, _pSyncronousResult ? *_pSyncronousResult : aIgnoreResult );
555 pScript.reset();
558 // object shells are not thread safe, so guard the destruction
559 ::vos::OGuard aSolarGuarsReset( Application::GetSolarMutex() );
560 xObjectShell = NULL;
564 //--------------------------------------------------------------------
565 void FormScriptingEnvironment::dispose()
567 ::osl::MutexGuard aGuard( m_aMutex );
568 m_bDisposed = true;
569 m_pScriptListener->dispose();
572 //--------------------------------------------------------------------
573 PFormScriptingEnvironment createDefaultFormScriptingEnvironment( FmFormModel& _rModel )
575 return new FormScriptingEnvironment( _rModel );
578 //........................................................................
579 } // namespace svxform
580 //........................................................................