merge the formfield patch from ooo-build
[ooovba.git] / scripting / source / vbaevents / eventhelper.cxx
blob6928530e9919741659a21bfd30187c3ed8e69e23
1 #include <comphelper/processfactory.hxx>
2 #include <comphelper/uno3.hxx>
3 #include <comphelper/proparrhlp.hxx>
4 #include <comphelper/propertycontainer.hxx>
6 #include <ooo/vba/XVBAToOOEventDescGen.hpp>
8 #include <com/sun/star/beans/XPropertySet.hpp>
9 #include <com/sun/star/beans/XIntrospection.hpp>
10 #include <com/sun/star/beans/PropertyAttribute.hpp>
12 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
13 #include <com/sun/star/lang/XServiceName.hpp>
14 #include <com/sun/star/lang/XServiceInfo.hpp>
15 #include <com/sun/star/lang/XInitialization.hpp>
17 #include <com/sun/star/frame/XModel.hpp>
19 #include <com/sun/star/script/XLibraryContainer.hpp>
20 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
21 #include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
23 #include <com/sun/star/drawing/XControlShape.hpp>
25 #include <com/sun/star/awt/XControl.hpp>
26 #include <com/sun/star/awt/XDialog.hpp>
27 #include <com/sun/star/awt/KeyEvent.hpp>
28 #include <com/sun/star/awt/MouseEvent.hpp>
29 #include <com/sun/star/awt/XFixedText.hpp> //liuchen 2009-6-5
30 #include <com/sun/star/awt/XTextComponent.hpp> //liuchen 2009-6-5
31 #include <com/sun/star/awt/XComboBox.hpp> //liuchen 2009-6-18
32 #include <com/sun/star/awt/XRadioButton.hpp> //liuchen 2009-7-30
34 #include <msforms/ReturnInteger.hpp>
36 #include <sfx2/objsh.hxx>
37 #include <basic/sbstar.hxx>
38 #include <basic/basmgr.hxx>
39 #include <basic/sbmeth.hxx>
40 #include <basic/sbmod.hxx>
41 #include <basic/sbx.hxx>
42 #include <svx/msvbahelper.hxx>
44 // for debug
45 #include <comphelper/anytostring.hxx>
47 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
48 #include <com/sun/star/script/XScriptListener.hpp>
49 #include <cppuhelper/implbase1.hxx>
50 #include <cppuhelper/implbase2.hxx>
51 #include <comphelper/evtmethodhelper.hxx>
53 #include <set>
54 #include <list>
55 #include <hash_map>
56 #define ASYNC 0
58 // primitive support for asynchronous handling of
59 // events from controls ( all event will be processed asynchronously
60 // in the application thread )
61 #if ASYNC
62 #include <vcl/svapp.hxx>
63 #endif
65 using namespace ::com::sun::star;
66 using namespace ::com::sun::star::script;
67 using namespace ::com::sun::star::uno;
68 using namespace ::ooo::vba;
70 #define MAP_CHAR_LEN(x) ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(x))//liuchen 2009-6-8
71 #define GET_TYPE(x) ::getCppuType((uno::Reference< x > *)0);
73 // Some constants
74 const static rtl::OUString DELIM = rtl::OUString::createFromAscii( "::" );
75 const static sal_Int32 DELIMLEN = DELIM.getLength();
77 #if 0
78 void dumpListeners( const Reference< beans::XIntrospection >& xIntrospection, const Reference<XInterface>& xIfc)
80 Reference< beans::XIntrospectionAccess > xIntrospectionAccess;
81 if ( xIntrospection.is() )
83 xIntrospectionAccess = xIntrospection->inspect(
84 makeAny( xIfc ) );
85 Sequence< Type > aControlListeners =
86 xIntrospectionAccess->getSupportedListeners();
87 sal_Int32 nLength = aControlListeners.getLength();
89 for ( sal_Int32 i = 0; i< nLength; ++i )
91 Type& listType = aControlListeners[ i ];
92 rtl::OUString sFullTypeName = listType.getTypeName();
93 rtl::OUString sTypeName = listType.getTypeName();
94 sal_Int32 lastDotIndex = -1;
95 if ( ( lastDotIndex = sFullTypeName.lastIndexOf( '.' ) ) > -1 )
97 sTypeName = sFullTypeName.copy( lastDotIndex + 1 );
99 Sequence< ::rtl::OUString > sMeths = comphelper::getEventMethodsForType( listType );
100 sal_Int32 sMethLen = sMeths.getLength();
101 for ( sal_Int32 j=0 ; j < sMethLen; ++j )
103 OSL_TRACE("**Listener [%d] Type[%s] Method[%s]",j,
104 rtl::OUStringToOString( sTypeName,
105 RTL_TEXTENCODING_UTF8 ).getStr(),
106 rtl::OUStringToOString( sMeths[ j ],
107 RTL_TEXTENCODING_UTF8 ).getStr() );
114 void dumpEvent( const ScriptEvent& evt )
116 OSL_TRACE("dumpEvent: Source %s",
117 rtl::OUStringToOString( comphelper::anyToString( makeAny(evt.Source)),
118 RTL_TEXTENCODING_UTF8 ).getStr() );
120 OSL_TRACE("dumpEvent: ScriptType %s",
121 rtl::OUStringToOString( evt.ScriptType,
122 RTL_TEXTENCODING_UTF8 ).getStr() );
124 OSL_TRACE("dumpEvent: ScriptCode %s",
125 rtl::OUStringToOString( evt.ScriptCode,
126 RTL_TEXTENCODING_UTF8 ).getStr() );
128 OSL_TRACE("dumpEvent: ListenerType %s",
129 rtl::OUStringToOString( evt.ListenerType.getTypeName(),
130 RTL_TEXTENCODING_UTF8 ).getStr() );
132 OSL_TRACE("dumpEvent: Listener methodname %s",
133 rtl::OUStringToOString( evt.MethodName,
134 RTL_TEXTENCODING_UTF8 ).getStr() );
136 OSL_TRACE("dumpEvent: arguments;");
137 sal_Int32 nLen = evt.Arguments.getLength();
138 for ( sal_Int32 index=0; index < nLen; ++index )
140 OSL_TRACE("\t [%d] %s", index,
141 rtl::OUStringToOString( comphelper::anyToString( evt.Arguments[ index ] ),
142 RTL_TEXTENCODING_UTF8 ).getStr() );
147 #endif
149 bool isKeyEventOk( awt::KeyEvent& evt, const Sequence< Any >& params )
151 if ( !( params.getLength() > 0 ) ||
152 !( params[ 0 ] >>= evt ) )
153 return false;
154 return true;
157 bool isMouseEventOk( awt::MouseEvent& evt, const Sequence< Any >& params )
159 if ( !( params.getLength() > 0 ) ||
160 !( params[ 0 ] >>= evt ) )
161 return false;
162 return true;
165 Sequence< Any > ooMouseEvtToVBADblClick( const Sequence< Any >& params )
167 Sequence< Any > translatedParams;
168 awt::MouseEvent evt;
170 if ( !( isMouseEventOk(evt, params)) ||
171 (evt.ClickCount != 2) )
172 return Sequence< Any >();
173 // give back orig params, this will signal that the event is good
174 return params;
177 Sequence< Any > ooMouseEvtToVBAMouseEvt( const Sequence< Any >& params )
179 Sequence< Any > translatedParams;
180 awt::MouseEvent evt;
182 if ( !isMouseEventOk(evt, params) )
183 return Sequence< Any >();
185 translatedParams.realloc(4);
187 // Buttons
188 translatedParams[ 0 ] <<= evt.Buttons;
189 // Shift
190 translatedParams[ 1 ] <<= evt.Modifiers;
191 // X
192 translatedParams[ 2 ] <<= evt.X;
193 // Y
194 translatedParams[ 3 ] <<= evt.Y;
195 return translatedParams;
198 Sequence< Any > ooKeyPressedToVBAKeyPressed( const Sequence< Any >& params )
200 Sequence< Any > translatedParams;
201 awt::KeyEvent evt;
203 if ( !isKeyEventOk( evt, params ) )
204 return Sequence< Any >();
206 translatedParams.realloc(1);
208 msforms::ReturnInteger keyCode;
209 keyCode.Value = evt.KeyCode;
210 translatedParams[0] <<= keyCode;
211 return translatedParams;
214 Sequence< Any > ooKeyPressedToVBAKeyUpDown( const Sequence< Any >& params )
216 Sequence< Any > translatedParams;
217 awt::KeyEvent evt;
219 if ( !isKeyEventOk( evt, params ) )
220 return Sequence< Any >();
222 translatedParams.realloc(2);
224 msforms::ReturnInteger keyCode;
225 sal_Int8 shift = evt.Modifiers;
227 // #TODO check whether values from OOO conform to values generated from vba
228 keyCode.Value = evt.KeyCode;
229 translatedParams[0] <<= keyCode;
230 translatedParams[1] <<= shift;
231 return translatedParams;
234 typedef Sequence< Any > (*Translator)(const Sequence< Any >&);
236 //liuchen 2009-6-23
237 //expand the "TranslateInfo" struct to support more kinds of events
238 struct TranslateInfo
240 rtl::OUString sVBAName; //vba event name
241 Translator toVBA; //the method to convert OO event parameters to VBA event parameters
242 bool (*ApproveRule)(const ScriptEvent& evt, void* pPara); //this method is used to determine which types of controls should execute the event
243 void *pPara; //Parameters for the above approve method
247 typedef std::hash_map< rtl::OUString,
248 std::list< TranslateInfo >,
249 ::rtl::OUStringHash,
250 ::std::equal_to< ::rtl::OUString > > EventInfoHash;
252 //liuchen 2009-6-23
253 struct TranslatePropMap
255 rtl::OUString sEventInfo; //OO event name
256 TranslateInfo aTransInfo;
259 bool ApproveAll(const ScriptEvent& evt, void* pPara); //allow all types of controls to execute the event
260 bool ApproveType(const ScriptEvent& evt, void* pPara); //certain types of controls should execute the event, those types are given by pPara
261 bool DenyType(const ScriptEvent& evt, void* pPara); //certain types of controls should not execute the event, those types are given by pPara
262 bool DenyMouseDrag(const ScriptEvent& evt, void* pPara); //used for VBA MouseMove event when "Shift" key is pressed
264 struct TypeList
266 uno::Type* pTypeList;
267 int nListLength;
270 Type typeXFixedText = GET_TYPE(awt::XFixedText);
271 Type typeXTextComponent = GET_TYPE(awt::XTextComponent);
272 Type typeXComboBox = GET_TYPE(awt::XComboBox);
273 Type typeXRadioButton = GET_TYPE(awt::XRadioButton);
276 TypeList fixedTextList = {&typeXFixedText, 1};
277 TypeList textCompList = {&typeXTextComponent, 1};
278 TypeList radioButtonList = {&typeXRadioButton, 1};
279 TypeList comboBoxList = {&typeXComboBox, 1};
281 //this array stores the OO event to VBA event translation info
282 static TranslatePropMap aTranslatePropMap_Impl[] =
284 // actionPerformed ooo event
285 { MAP_CHAR_LEN("actionPerformed"), { MAP_CHAR_LEN("_Click"), NULL, ApproveAll, NULL } },
286 { MAP_CHAR_LEN("actionPerformed"), { MAP_CHAR_LEN("_Change"), NULL, DenyType, (void*)(&radioButtonList) } }, //liuchen 2009-7-30, OptionalButton_Change event is not the same as OptionalButton_Click event
288 // itemStateChanged ooo event
289 { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Click"), NULL, ApproveType, (void*)(&comboBoxList) } }, //liuchen, add to support VBA ComboBox_Click event
290 { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveType, (void*)(&radioButtonList) } }, //liuchen 2009-7-30, OptionalButton_Change event should be triggered when the button state is changed
292 // changed ooo event
293 { MAP_CHAR_LEN("changed"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } },
295 // focusGained ooo event
296 { MAP_CHAR_LEN("focusGained"), { MAP_CHAR_LEN("_GotFocus"), NULL, ApproveAll, NULL } },
298 // focusLost ooo event
299 { MAP_CHAR_LEN("focusLost"), { MAP_CHAR_LEN("_LostFocus"), NULL, ApproveAll, NULL } },
300 { MAP_CHAR_LEN("focusLost"), { MAP_CHAR_LEN("_Exit"), NULL, ApproveType, (void*)(&textCompList) } }, //liuchen, add to support VBA TextBox_Exit event
302 // adjustmentValueChanged ooo event
303 { MAP_CHAR_LEN("adjustmentValueChanged"), { MAP_CHAR_LEN("_Scroll"), NULL, ApproveAll, NULL } },
304 { MAP_CHAR_LEN("adjustmentValueChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } },
306 // textChanged ooo event
307 { MAP_CHAR_LEN("textChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } },
309 // keyReleased ooo event
310 { MAP_CHAR_LEN("keyReleased"), { MAP_CHAR_LEN("_KeyUp"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } },
312 // mouseReleased ooo event
313 { MAP_CHAR_LEN("mouseReleased"), { MAP_CHAR_LEN("_Click"), ooMouseEvtToVBAMouseEvt, ApproveType, (void*)(&fixedTextList) } }, //liuchen, add to support VBA Label_Click event
314 { MAP_CHAR_LEN("mouseReleased"), { MAP_CHAR_LEN("_MouseUp"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
316 // mousePressed ooo event
317 { MAP_CHAR_LEN("mousePressed"), { MAP_CHAR_LEN("_MouseDown"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
318 { MAP_CHAR_LEN("mousePressed"), { MAP_CHAR_LEN("_DblClick"), ooMouseEvtToVBADblClick, ApproveAll, NULL } },
320 // mouseMoved ooo event
321 { MAP_CHAR_LEN("mouseMoved"), { MAP_CHAR_LEN("_MouseMove"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
322 { MAP_CHAR_LEN("mouseDragged"), { MAP_CHAR_LEN("_MouseMove"), ooMouseEvtToVBAMouseEvt, DenyMouseDrag, NULL } }, //liuchen, add to support VBA MouseMove event when the "Shift" key is pressed
324 // keyPressed ooo event
325 { MAP_CHAR_LEN("keyPressed"), { MAP_CHAR_LEN("_KeyDown"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } },
326 { MAP_CHAR_LEN("keyPressed"), { MAP_CHAR_LEN("_KeyPress"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } }
329 EventInfoHash& getEventTransInfo()
331 static bool initialised = false;
332 static EventInfoHash eventTransInfo;
333 if ( !initialised )
335 rtl::OUString sEventInfo = MAP_CHAR_LEN("");
336 TranslatePropMap* pTransProp = aTranslatePropMap_Impl;
338 int nCount = sizeof(aTranslatePropMap_Impl) / sizeof(aTranslatePropMap_Impl[0]);
340 int i = 0;
341 while (i < nCount)
343 if (sEventInfo != pTransProp->sEventInfo)
345 sEventInfo = pTransProp->sEventInfo;
346 std::list< TranslateInfo > infoList;
349 infoList.push_back( pTransProp->aTransInfo );
350 i++;
351 pTransProp++;
353 while( ( i < nCount ) && ( sEventInfo == pTransProp->sEventInfo ) );
354 eventTransInfo[sEventInfo] = infoList;
357 initialised = true;
359 return eventTransInfo;
361 //liuchen 2009-6-23 end
363 // Helper class
365 class ScriptEventHelper
367 public:
368 ScriptEventHelper( const Reference< XInterface >& xControl );
369 Sequence< ScriptEventDescriptor > createEvents( const rtl::OUString& sCodeName );
370 Sequence< rtl::OUString > getEventListeners();
371 private:
372 Reference< XComponentContext > m_xCtx;
373 Reference< XInterface > m_xControl;
376 bool
377 eventMethodToDescriptor( const ::rtl::OUString& rEventMethod, ScriptEventDescriptor& evtDesc, const ::rtl::OUString& sCodeName )
379 // format of ControlListener is TypeName::methodname e.g.
380 // "com.sun.star.awt.XActionListener::actionPerformed" or
381 // "XActionListener::actionPerformed
383 ::rtl::OUString sMethodName;
384 ::rtl::OUString sTypeName;
385 sal_Int32 nDelimPos = rEventMethod.indexOf( DELIM );
386 if ( nDelimPos == -1 )
388 return false;
390 sMethodName = rEventMethod.copy( nDelimPos + DELIMLEN );
391 sTypeName = rEventMethod.copy( 0, nDelimPos );
393 EventInfoHash& infos = getEventTransInfo();
395 // Only create an ScriptEventDescriptor for an event we can translate
396 // or emulate
397 if ( sMethodName.getLength()
398 && sTypeName.getLength()
399 && ( infos.find( sMethodName ) != infos.end() ) )
401 // just fill in CodeName, when the event fires the other
402 // info is gathered from the event source to determine what
403 // event handler we try to call
404 evtDesc.ScriptCode = sCodeName;
405 evtDesc.ListenerType = sTypeName;
406 evtDesc.EventMethod = sMethodName;
408 // set this it VBAInterop, ensures that it doesn't
409 // get persisted or shown in property editors
410 evtDesc.ScriptType = rtl::OUString::createFromAscii(
411 "VBAInterop" );
412 return true;
414 return false;
418 ScriptEventHelper::ScriptEventHelper( const Reference< XInterface >& xControl ) : m_xControl( xControl )
420 Reference < beans::XPropertySet > xProps(
421 ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW );
422 m_xCtx.set( xProps->getPropertyValue( rtl::OUString(
423 RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))),
424 uno::UNO_QUERY_THROW );
427 Sequence< rtl::OUString >
428 ScriptEventHelper::getEventListeners()
430 Reference< lang::XMultiComponentFactory > xMFac(
431 m_xCtx->getServiceManager(), UNO_QUERY );
432 std::list< rtl::OUString > eventMethods;
434 if ( xMFac.is() )
436 Reference< beans::XIntrospection > xIntrospection(
437 xMFac->createInstanceWithContext( rtl::OUString(
438 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.Introspection" ) ), m_xCtx ), UNO_QUERY );
439 #if 0
440 dumpListeners( xIntrospection, m_xControl );
441 dumpListeners( xIntrospection, m_xControl->getModel() );
442 #endif
443 Reference< beans::XIntrospectionAccess > xIntrospectionAccess;
444 if ( xIntrospection.is() )
446 xIntrospectionAccess = xIntrospection->inspect(
447 makeAny( m_xControl ) );
448 Sequence< Type > aControlListeners =
449 xIntrospectionAccess->getSupportedListeners();
450 sal_Int32 nLength = aControlListeners.getLength();
451 for ( sal_Int32 i = 0; i< nLength; ++i )
453 Type& listType = aControlListeners[ i ];
454 rtl::OUString sFullTypeName = listType.getTypeName();
455 Sequence< ::rtl::OUString > sMeths =
456 comphelper::getEventMethodsForType( listType );
457 sal_Int32 sMethLen = sMeths.getLength();
458 for ( sal_Int32 j=0 ; j < sMethLen; ++j )
460 rtl::OUString sEventMethod = sFullTypeName;
461 sEventMethod += DELIM;
462 sEventMethod += sMeths[ j ];
463 eventMethods.push_back( sEventMethod );
470 Sequence< rtl::OUString > sEventMethodNames( eventMethods.size() );
471 std::list< rtl::OUString >::const_iterator it = eventMethods.begin();
472 rtl::OUString* pDest = sEventMethodNames.getArray();
474 for ( ; it != eventMethods.end(); ++it, ++pDest )
475 *pDest = *it;
477 return sEventMethodNames;
480 Sequence< ScriptEventDescriptor >
481 ScriptEventHelper::createEvents( const rtl::OUString& sCodeName )
483 Sequence< rtl::OUString > aControlListeners = getEventListeners();
484 rtl::OUString* pSrc = aControlListeners.getArray();
485 sal_Int32 nLength = aControlListeners.getLength();
487 Sequence< ScriptEventDescriptor > aDest( nLength );
488 sal_Int32 nEvts = 0;
489 for ( sal_Int32 i = 0; i< nLength; ++i, ++pSrc )
491 // from getListeners eventName is of form
492 // "com.sun.star.awt.XActionListener::actionPerformed"
493 // we need to strip "com.sun.star.awt." from that for form
494 // controls
495 ScriptEventDescriptor evtDesc;
496 if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) )
498 sal_Int32 dIndex = nEvts;
499 ++nEvts;
500 if ( nEvts > aDest.getLength() )
501 aDest.realloc( nEvts );// should never happen
502 aDest[ dIndex ] = evtDesc;
505 aDest.realloc( nEvts );
507 return aDest;
511 typedef ::cppu::WeakImplHelper1< container::XNameContainer > NameContainer_BASE;
513 class ReadOnlyEventsNameContainer : public NameContainer_BASE
515 public:
516 ReadOnlyEventsNameContainer( const Sequence< rtl::OUString >& eventMethods, const rtl::OUString& sCodeName );
517 // XNameContainer
519 virtual void SAL_CALL insertByName( const ::rtl::OUString&, const Any& ) throw (lang::IllegalArgumentException, container::ElementExistException, lang::WrappedTargetException, RuntimeException)
521 throw RuntimeException( rtl::OUString::createFromAscii( "ReadOnly container" ), Reference< XInterface >() );
524 virtual void SAL_CALL removeByName( const ::rtl::OUString& ) throw (::com::sun::star::container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
526 throw RuntimeException( rtl::OUString::createFromAscii( "ReadOnly container" ), Reference< XInterface >() );
529 // XNameReplace
530 virtual void SAL_CALL replaceByName( const ::rtl::OUString&, const Any& ) throw (lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
532 throw RuntimeException( rtl::OUString::createFromAscii( "ReadOnly container" ), Reference< XInterface >() );
536 // XNameAccess
537 virtual Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException);
538 virtual Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) throw (RuntimeException);
539 virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (RuntimeException);
541 // XElementAccess
542 virtual Type SAL_CALL getElementType( ) throw (RuntimeException)
543 { return getCppuType(static_cast< const rtl::OUString * >(0) ); }
544 virtual ::sal_Bool SAL_CALL hasElements( ) throw (RuntimeException)
545 { return ( ( m_hEvents.size() > 0 ? sal_True : sal_False ) ); }
546 private:
548 typedef std::hash_map< rtl::OUString, Any, ::rtl::OUStringHash,
549 ::std::equal_to< ::rtl::OUString > > EventSupplierHash;
551 EventSupplierHash m_hEvents;
554 ReadOnlyEventsNameContainer::ReadOnlyEventsNameContainer( const Sequence< rtl::OUString >& eventMethods, const rtl::OUString& sCodeName )
556 const rtl::OUString* pSrc = eventMethods.getConstArray();
557 sal_Int32 nLen = eventMethods.getLength();
558 for ( sal_Int32 index = 0; index < nLen; ++index, ++pSrc )
560 Any aDesc;
561 ScriptEventDescriptor evtDesc;
562 if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) )
564 aDesc <<= evtDesc;
565 m_hEvents[ *pSrc ] = aDesc;
570 Any SAL_CALL
571 ReadOnlyEventsNameContainer::getByName( const ::rtl::OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException){
572 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
573 if ( it == m_hEvents.end() )
574 throw container::NoSuchElementException();
575 return it->second;
578 Sequence< ::rtl::OUString > SAL_CALL
579 ReadOnlyEventsNameContainer::getElementNames( ) throw (RuntimeException)
581 Sequence< ::rtl::OUString > names(m_hEvents.size());
582 rtl::OUString* pDest = names.getArray();
583 EventSupplierHash::const_iterator it = m_hEvents.begin();
584 EventSupplierHash::const_iterator it_end = m_hEvents.end();
585 for ( sal_Int32 index = 0; it != it_end; ++index, ++pDest, ++it )
586 *pDest = it->first;
587 return names;
590 sal_Bool SAL_CALL
591 ReadOnlyEventsNameContainer::hasByName( const ::rtl::OUString& aName ) throw (RuntimeException)
593 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
594 if ( it == m_hEvents.end() )
595 return sal_False;
596 return sal_True;
599 typedef ::cppu::WeakImplHelper1< XScriptEventsSupplier > EventsSupplier_BASE;
601 class ReadOnlyEventsSupplier : public EventsSupplier_BASE
603 public:
604 ReadOnlyEventsSupplier( const Sequence< ::rtl::OUString >& eventMethods, const rtl::OUString& sCodeName )
605 { m_xNameContainer = new ReadOnlyEventsNameContainer( eventMethods, sCodeName ); }
607 // XScriptEventSupplier
608 virtual Reference< container::XNameContainer > SAL_CALL getEvents( ) throw (RuntimeException){ return m_xNameContainer; }
609 private:
610 Reference< container::XNameContainer > m_xNameContainer;
613 typedef ::cppu::WeakImplHelper2< XScriptListener, lang::XInitialization > EventListener_BASE;
615 #define EVENTLSTNR_PROPERTY_ID_MODEL 1
616 #define EVENTLSTNR_PROPERTY_MODEL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Model" ) )
618 class EventListener : public EventListener_BASE
619 ,public ::comphelper::OMutexAndBroadcastHelper
620 ,public ::comphelper::OPropertyContainer
621 ,public ::comphelper::OPropertyArrayUsageHelper< EventListener >
625 public:
626 EventListener( const Reference< XComponentContext >& rxContext );
627 // XEventListener
628 virtual void SAL_CALL disposing(const lang::EventObject& Source) throw( RuntimeException );
630 // XScriptListener
631 virtual void SAL_CALL firing(const ScriptEvent& evt) throw(RuntimeException);
632 virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException);
633 // XPropertySet
634 virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException);
635 // XInitialization
636 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException);
637 // XInterface
638 DECLARE_XINTERFACE()
640 // XTypeProvider
641 DECLARE_XTYPEPROVIDER()
642 virtual void SAL_CALL setFastPropertyValue( sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
644 OPropertyContainer::setFastPropertyValue( nHandle, rValue );
645 if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
646 setShellFromModel();
649 protected:
650 // OPropertySetHelper
651 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper( );
653 // OPropertyArrayUsageHelper
654 virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;
656 private:
657 #if ASYNC
658 DECL_LINK( OnAsyncScriptEvent, ScriptEvent* );
659 #endif
660 void setShellFromModel();
661 void firing_Impl( const ScriptEvent& evt, Any *pSyncRet=NULL ) throw( RuntimeException );
663 Reference< XComponentContext > m_xContext;
664 Reference< frame::XModel > m_xModel;
665 SfxObjectShell* mpShell;
669 EventListener::EventListener( const Reference< XComponentContext >& rxContext ) :
670 OPropertyContainer(GetBroadcastHelper()), m_xContext( rxContext ), mpShell( 0 )
672 registerProperty( EVENTLSTNR_PROPERTY_MODEL, EVENTLSTNR_PROPERTY_ID_MODEL,
673 beans::PropertyAttribute::TRANSIENT, &m_xModel, ::getCppuType( &m_xModel ) );
677 void
678 EventListener::setShellFromModel()
680 // reset mpShell
681 mpShell = 0;
682 SfxObjectShell* pShell = SfxObjectShell::GetFirst();
683 while ( m_xModel.is() && pShell )
685 if ( pShell->GetModel() == m_xModel )
687 mpShell = pShell;
688 break;
690 pShell = SfxObjectShell::GetNext( *pShell );
694 //XEventListener
695 void
696 EventListener::disposing(const lang::EventObject&) throw( RuntimeException )
700 //XScriptListener
702 void SAL_CALL
703 EventListener::firing(const ScriptEvent& evt) throw(RuntimeException)
705 #if ASYNC
706 // needs some logic to check if the event handler is oneway or not
707 // if not oneway then firing_Impl otherwise... as below
708 acquire();
709 Application::PostUserEvent( LINK( this, EventListener, OnAsyncScriptEvent ), new ScriptEvent( evt ) );
710 #else
711 firing_Impl( evt );
712 #endif
715 #if ASYNC
716 IMPL_LINK( EventListener, OnAsyncScriptEvent, ScriptEvent*, _pEvent )
718 if ( !_pEvent )
719 return 1L;
722 // #FIXME if we enable ASYNC we probably need something like
723 // below
724 //::osl::ClearableMutexGuard aGuard( m_aMutex );
726 //if ( !impl_isDisposed_nothrow() )
727 // impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, NULL );
728 firing_Impl( *_pEvent, NULL );
731 delete _pEvent;
732 // we acquired ourself immediately before posting the event
733 release();
734 return 0L;
736 #endif
738 Any SAL_CALL
739 EventListener::approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException)
741 Any ret;
742 firing_Impl( evt, &ret );
743 return ret;
746 // XInitialization
747 void SAL_CALL
748 EventListener::initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException)
750 if ( aArguments.getLength() == 1 )
751 aArguments[0] >>= m_xModel;
752 OSL_TRACE("EventListener::initialize() args %d m_xModel %d", aArguments.getLength(), m_xModel.is() );
755 // XInterface
757 IMPLEMENT_FORWARD_XINTERFACE2( EventListener, EventListener_BASE, OPropertyContainer )
759 // XTypeProvider
761 IMPLEMENT_FORWARD_XTYPEPROVIDER2( EventListener, EventListener_BASE, OPropertyContainer )
763 // OPropertySetHelper
765 ::cppu::IPropertyArrayHelper&
766 EventListener::getInfoHelper( )
768 return *getArrayHelper();
771 // OPropertyArrayUsageHelper
773 ::cppu::IPropertyArrayHelper*
774 EventListener::createArrayHelper( ) const
776 Sequence< beans::Property > aProps;
777 describeProperties( aProps );
778 return new ::cppu::OPropertyArrayHelper( aProps );
781 // XPropertySet
782 Reference< beans::XPropertySetInfo >
783 EventListener::getPropertySetInfo( ) throw (RuntimeException)
785 Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
786 return xInfo;
789 //liuchen 2009-6-23
790 //decide if the control should execute the event
791 bool ApproveAll(const ScriptEvent& evt, void* pPara)
793 return true;
796 //for the given control type in evt.Arguments[0], look for if it appears in the type list in pPara
797 bool FindControl(const ScriptEvent& evt, void* pPara)
799 lang::EventObject aEvent;
800 evt.Arguments[ 0 ] >>= aEvent;
801 uno::Reference< uno::XInterface > xInterface( aEvent.Source, uno::UNO_QUERY );
803 TypeList* pTypeListInfo = static_cast<TypeList*>(pPara);
804 Type* pType = pTypeListInfo->pTypeList;
805 int nLen = pTypeListInfo->nListLength;
807 for (int i = 0; i < nLen; i++)
809 if ( xInterface->queryInterface( *pType ).hasValue() )
811 return true;
813 pType++;
816 return false;
819 //if the the given control type in evt.Arguments[0] appears in the type list in pPara, then approve the execution
820 bool ApproveType(const ScriptEvent& evt, void* pPara)
822 return FindControl(evt, pPara);
825 //if the the given control type in evt.Arguments[0] appears in the type list in pPara, then deny the execution
826 bool DenyType(const ScriptEvent& evt, void* pPara)
828 return !FindControl(evt, pPara);
831 //when mouse is moving, either the mouse button is pressed or some key is pressed can trigger the OO mouseDragged event,
832 //the former should be denyed, and the latter allowed, only by doing so can the VBA MouseMove event when the "Shift" key is
833 //pressed can be correctly triggered
834 bool DenyMouseDrag(const ScriptEvent& evt, void* pPara)
836 awt::MouseEvent aEvent;
837 evt.Arguments[ 0 ] >>= aEvent;
838 if (aEvent.Buttons == 0 )
840 return true;
842 else
844 return false;
850 //liuchen 2009-6-23
851 // EventListener
853 void
854 EventListener::firing_Impl(const ScriptEvent& evt, Any* pRet ) throw(RuntimeException)
856 OSL_TRACE("EventListener::firing_Impl( FAKE VBA_EVENTS )");
857 static const ::rtl::OUString vbaInterOp =
858 ::rtl::OUString::createFromAscii("VBAInterop");
860 // let default handlers deal with non vba stuff
861 if ( !evt.ScriptType.equals( vbaInterOp ) )
862 return;
863 lang::EventObject aEvent;
864 evt.Arguments[ 0 ] >>= aEvent;
865 OSL_TRACE("evt.MethodName is %s", rtl::OUStringToOString( evt.MethodName, RTL_TEXTENCODING_UTF8 ).getStr() );
866 OSL_TRACE("Argument[0] is %s", rtl::OUStringToOString( comphelper::anyToString( evt.Arguments[0] ), RTL_TEXTENCODING_UTF8 ).getStr() );
867 OSL_TRACE("Getting Control");
868 uno::Reference< awt::XControl > xControl( aEvent.Source, uno::UNO_QUERY_THROW );
869 OSL_TRACE("Getting properties");
870 uno::Reference< beans::XPropertySet > xProps( xControl->getModel(), uno::UNO_QUERY_THROW );
872 rtl::OUString sName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("UserForm") );
873 OSL_TRACE("Getting Name");
875 uno::Reference< awt::XDialog > xDlg( aEvent.Source, uno::UNO_QUERY );
876 if ( !xDlg.is() )
877 xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) ) >>= sName;
878 //dumpEvent( evt );
879 EventInfoHash& infos = getEventTransInfo();
880 EventInfoHash::const_iterator eventInfo_it = infos.find( evt.MethodName );
881 EventInfoHash::const_iterator it_end = infos.end();
882 if ( eventInfo_it == it_end )
884 OSL_TRACE("Bogus event for %s",
885 rtl::OUStringToOString( evt.ScriptType, RTL_TEXTENCODING_UTF8 ).getStr() );
886 return;
889 uno::Reference< script::provider::XScriptProviderSupplier > xSPS( m_xModel, uno::UNO_QUERY );
890 uno::Reference< script::provider::XScriptProvider > xScriptProvider;
891 if ( xSPS.is() )
892 xScriptProvider = xSPS->getScriptProvider();
893 if ( xScriptProvider.is() && mpShell )
895 std::list< TranslateInfo > matchingMethods;
896 std::list< TranslateInfo >::const_iterator txInfo =
897 eventInfo_it->second.begin();
898 std::list< TranslateInfo >::const_iterator txInfo_end = eventInfo_it->second.end();
900 StarBASIC* pBasic = mpShell->GetBasic();
901 BasicManager* pBasicManager = mpShell->GetBasicManager();
902 rtl::OUString sProject;
903 rtl::OUString sScriptCode( evt.ScriptCode );
904 // dialogs pass their own library, presence of Dot determines that
905 if ( sScriptCode.indexOf( '.' ) == -1 )
907 //'Project' is a better default but I want to force failures
908 //rtl::OUString sMacroLoc = rtl::OUString::createFromAscii("Project");
909 sProject = rtl::OUString::createFromAscii("Standard");
911 if ( pBasicManager->GetName().Len() > 0 )
912 sProject = pBasicManager->GetName();
914 else
916 sal_Int32 nIndex = sScriptCode.indexOf( '.' );
917 sProject = sScriptCode.copy( 0, nIndex );
918 sScriptCode = sScriptCode.copy( nIndex + 1 );
920 rtl::OUString sMacroLoc = sProject;
921 sMacroLoc = sMacroLoc.concat( rtl::OUString::createFromAscii(".") );
922 sMacroLoc = sMacroLoc.concat( sScriptCode ).concat( rtl::OUString::createFromAscii(".") );
924 OSL_TRACE("sMacroLoc is %s", rtl::OUStringToOString( sMacroLoc, RTL_TEXTENCODING_UTF8 ).getStr() );
925 for ( ; txInfo != txInfo_end; ++txInfo )
927 rtl::OUString sTemp = sName.concat( (*txInfo).sVBAName );
928 // see if we have a match for the handlerextension
929 // where ScriptCode is methodname_handlerextension
930 rtl::OUString sToResolve = sMacroLoc.concat( sTemp );
931 OSL_TRACE("*** trying to invoke %s ",
932 rtl::OUStringToOString( sToResolve, RTL_TEXTENCODING_UTF8 ).getStr() );
933 ooo::vba::VBAMacroResolvedInfo aMacroResolvedInfo = ooo::vba::resolveVBAMacro( mpShell, sToResolve );
934 if ( aMacroResolvedInfo.IsResolved() )
936 //liuchen 2009-6-8
937 if (! txInfo->ApproveRule(evt, txInfo->pPara) )
939 continue;
941 //liuchen 2009-6-8
942 // !! translate arguments & emulate events where necessary
943 Sequence< Any > aArguments;
944 if ( (*txInfo).toVBA )
945 aArguments = (*txInfo).toVBA( evt.Arguments );
946 else
947 aArguments = evt.Arguments;
948 if ( aArguments.getLength() )
950 // call basic event handlers for event
952 // create script url
953 rtl::OUString url = aMacroResolvedInfo.ResolvedMacro();
955 OSL_TRACE("resolved script = %s",
956 rtl::OUStringToOString( url,
957 RTL_TEXTENCODING_UTF8 ).getStr() );
960 uno::Any aDummyCaller = uno::makeAny( rtl::OUString::createFromAscii("Error") );
961 if ( pRet )
962 ooo::vba::executeMacro( mpShell, url, aArguments, *pRet, aDummyCaller );
963 else
965 uno::Any aRet;
966 ooo::vba::executeMacro( mpShell, url, aArguments, aRet, aDummyCaller );
969 catch ( uno::Exception& e )
971 OSL_TRACE("event script raised %s", rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
979 typedef ::cppu::WeakImplHelper1< XVBAToOOEventDescGen > VBAToOOEventDescGen_BASE;
982 class VBAToOOEventDescGen : public VBAToOOEventDescGen_BASE
984 public:
985 VBAToOOEventDescGen( const Reference< XComponentContext >& rxContext );
987 // XVBAToOOEventDescGen
988 virtual Sequence< ScriptEventDescriptor > SAL_CALL getEventDescriptions( const Reference< XInterface >& control, const rtl::OUString& sCodeName ) throw (RuntimeException);
989 virtual Reference< XScriptEventsSupplier > SAL_CALL getEventSupplier( const Reference< XInterface >& xControl, const rtl::OUString& sCodeName ) throw (::com::sun::star::uno::RuntimeException);
990 private:
991 Reference< XComponentContext > m_xContext;
995 VBAToOOEventDescGen::VBAToOOEventDescGen( const Reference< XComponentContext >& rxContext ):m_xContext( rxContext ) {}
997 Sequence< ScriptEventDescriptor > SAL_CALL
998 VBAToOOEventDescGen::getEventDescriptions( const Reference< XInterface >& xControl, const rtl::OUString& sCodeName ) throw (RuntimeException)
1000 ScriptEventHelper evntHelper( xControl );
1001 return evntHelper.createEvents( sCodeName );
1004 Reference< XScriptEventsSupplier > SAL_CALL
1005 VBAToOOEventDescGen::getEventSupplier( const Reference< XInterface >& xControl, const rtl::OUString& sCodeName ) throw (::com::sun::star::uno::RuntimeException)
1007 ScriptEventHelper evntHelper( xControl );
1008 Reference< XScriptEventsSupplier > xSupplier =
1009 new ReadOnlyEventsSupplier(
1010 evntHelper.getEventListeners(), sCodeName ) ;
1011 return xSupplier;
1014 // Component related
1016 namespace evtlstner
1018 ::rtl::OUString SAL_CALL getImplementationName()
1020 static ::rtl::OUString* pImplName = 0;
1021 if ( !pImplName )
1023 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
1024 if ( !pImplName )
1026 static ::rtl::OUString aImplName( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.EventListener" ) );
1027 pImplName = &aImplName;
1030 return *pImplName;
1033 uno::Reference< XInterface > SAL_CALL create(
1034 Reference< XComponentContext > const & xContext )
1035 SAL_THROW( () )
1037 return static_cast< lang::XTypeProvider * >( new EventListener( xContext ) );
1040 Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
1042 const ::rtl::OUString strName( ::evtlstner::getImplementationName() );
1043 return Sequence< ::rtl::OUString >( &strName, 1 );
1046 namespace ooevtdescgen
1048 ::rtl::OUString SAL_CALL getImplementationName()
1050 static ::rtl::OUString* pImplName = 0;
1051 if ( !pImplName )
1053 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
1054 if ( !pImplName )
1056 static ::rtl::OUString aImplName( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAToOOEventDesc" ) );
1057 pImplName = &aImplName;
1060 return *pImplName;
1063 uno::Reference< XInterface > SAL_CALL create(
1064 Reference< XComponentContext > const & xContext )
1065 SAL_THROW( () )
1067 return static_cast< lang::XTypeProvider * >( new VBAToOOEventDescGen( xContext ) );
1070 Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
1072 const ::rtl::OUString strName( ::ooevtdescgen::getImplementationName() );
1073 return Sequence< ::rtl::OUString >( &strName, 1 );