bump product version to 4.1.6.2
[LibreOffice.git] / scripting / source / vbaevents / eventhelper.cxx
blob5061fe8b4ea58bff821d65b15bdee1781e53b418
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/macros.h>
21 #include <comphelper/processfactory.hxx>
22 #include <comphelper/uno3.hxx>
23 #include <comphelper/proparrhlp.hxx>
24 #include <comphelper/propertycontainer.hxx>
26 #include <ooo/vba/XVBAToOOEventDescGen.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/beans/Introspection.hpp>
30 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
33 #include <com/sun/star/lang/XServiceName.hpp>
34 #include <com/sun/star/lang/XServiceInfo.hpp>
35 #include <com/sun/star/lang/XInitialization.hpp>
37 #include <com/sun/star/util/XCloseListener.hpp>
38 #include <com/sun/star/util/XCloseBroadcaster.hpp>
40 #include <com/sun/star/frame/XModel.hpp>
42 #include <com/sun/star/script/XLibraryContainer.hpp>
43 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
44 #include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
45 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
47 #include <com/sun/star/container/XNamed.hpp>
49 #include <com/sun/star/drawing/XControlShape.hpp>
51 #include <com/sun/star/awt/XControl.hpp>
52 #include <com/sun/star/awt/XDialog.hpp>
53 #include <com/sun/star/awt/KeyEvent.hpp>
54 #include <com/sun/star/awt/MouseEvent.hpp>
55 #include <com/sun/star/awt/XFixedText.hpp>
56 #include <com/sun/star/awt/XTextComponent.hpp>
57 #include <com/sun/star/awt/XComboBox.hpp>
58 #include <com/sun/star/awt/XRadioButton.hpp>
59 #include <com/sun/star/awt/XListBox.hpp>
61 #include <sfx2/objsh.hxx>
62 #include <basic/sbstar.hxx>
63 #include <basic/basmgr.hxx>
64 #include <basic/sbmeth.hxx>
65 #include <basic/sbmod.hxx>
66 #include <basic/sbx.hxx>
67 #include <filter/msfilter/msvbahelper.hxx>
68 #include <vbahelper/vbareturntypes.hxx>
70 // for debug
71 #include <comphelper/anytostring.hxx>
73 #include <com/sun/star/script/XScriptListener.hpp>
74 #include <cppuhelper/implbase1.hxx>
75 #include <cppuhelper/implbase3.hxx>
76 #include <cppuhelper/implbase2.hxx>
77 #include <comphelper/evtmethodhelper.hxx>
79 #include <set>
80 #include <list>
81 #include <boost/unordered_map.hpp>
82 #define ASYNC 0
84 // primitive support for asynchronous handling of
85 // events from controls ( all event will be processed asynchronously
86 // in the application thread )
87 #if ASYNC
88 #include <vcl/svapp.hxx>
89 #endif
91 using namespace ::com::sun::star;
92 using namespace ::com::sun::star::script;
93 using namespace ::com::sun::star::uno;
94 using namespace ::ooo::vba;
96 #define MAP_CHAR_LEN(x) OUString(x)
97 #define GET_TYPE(x) ::getCppuType((uno::Reference< x > *)0);
99 // Some constants
100 const static OUString DELIM("::");
101 const static sal_Int32 DELIMLEN = DELIM.getLength();
103 bool isKeyEventOk( awt::KeyEvent& evt, const Sequence< Any >& params )
105 if ( !( params.getLength() > 0 ) ||
106 !( params[ 0 ] >>= evt ) )
107 return false;
108 return true;
111 bool isMouseEventOk( awt::MouseEvent& evt, const Sequence< Any >& params )
113 if ( !( params.getLength() > 0 ) ||
114 !( params[ 0 ] >>= evt ) )
115 return false;
116 return true;
119 Sequence< Any > ooMouseEvtToVBADblClick( const Sequence< Any >& params )
121 Sequence< Any > translatedParams;
122 awt::MouseEvent evt;
124 if ( !( isMouseEventOk(evt, params)) ||
125 (evt.ClickCount != 2) )
126 return Sequence< Any >();
127 // give back orig params, this will signal that the event is good
128 return params;
131 Sequence< Any > ooMouseEvtToVBAMouseEvt( const Sequence< Any >& params )
133 Sequence< Any > translatedParams;
134 awt::MouseEvent evt;
136 if ( !isMouseEventOk(evt, params) )
137 return Sequence< Any >();
139 translatedParams.realloc(4);
141 // Buttons
142 translatedParams[ 0 ] <<= evt.Buttons;
143 // Shift
144 translatedParams[ 1 ] <<= evt.Modifiers;
145 // X
146 translatedParams[ 2 ] <<= evt.X;
147 // Y
148 translatedParams[ 3 ] <<= evt.Y;
149 return translatedParams;
152 Sequence< Any > ooKeyPressedToVBAKeyPressed( const Sequence< Any >& params )
154 Sequence< Any > translatedParams;
155 awt::KeyEvent evt;
157 if ( !isKeyEventOk( evt, params ) )
158 return Sequence< Any >();
160 translatedParams.realloc(1);
162 Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( sal_Int32( evt.KeyCode ) );
163 translatedParams[0] <<= xKeyCode;
164 return translatedParams;
167 Sequence< Any > ooKeyPressedToVBAKeyUpDown( const Sequence< Any >& params )
169 Sequence< Any > translatedParams;
170 awt::KeyEvent evt;
172 if ( !isKeyEventOk( evt, params ) )
173 return Sequence< Any >();
175 translatedParams.realloc(2);
177 Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( evt.KeyCode );
178 sal_Int8 shift = sal::static_int_cast<sal_Int8>( evt.Modifiers );
180 // #TODO check whether values from OOO conform to values generated from vba
181 translatedParams[0] <<= xKeyCode;
182 translatedParams[1] <<= shift;
183 return translatedParams;
186 typedef Sequence< Any > (*Translator)(const Sequence< Any >&);
188 //expand the "TranslateInfo" struct to support more kinds of events
189 struct TranslateInfo
191 OUString sVBAName; //vba event name
192 Translator toVBA; //the method to convert OO event parameters to VBA event parameters
193 bool (*ApproveRule)(const ScriptEvent& evt, void* pPara); //this method is used to determine which types of controls should execute the event
194 void *pPara; //Parameters for the above approve method
198 typedef boost::unordered_map< OUString,
199 std::list< TranslateInfo >,
200 OUStringHash,
201 ::std::equal_to< OUString > > EventInfoHash;
204 struct TranslatePropMap
206 OUString sEventInfo; //OO event name
207 TranslateInfo aTransInfo;
210 bool ApproveAll(const ScriptEvent& evt, void* pPara); //allow all types of controls to execute the event
211 bool ApproveType(const ScriptEvent& evt, void* pPara); //certain types of controls should execute the event, those types are given by pPara
212 bool DenyType(const ScriptEvent& evt, void* pPara); //certain types of controls should not execute the event, those types are given by pPara
213 bool DenyMouseDrag(const ScriptEvent& evt, void* pPara); //used for VBA MouseMove event when "Shift" key is pressed
215 struct TypeList
217 uno::Type* pTypeList;
218 int nListLength;
221 Type typeXFixedText = GET_TYPE(awt::XFixedText);
222 Type typeXTextComponent = GET_TYPE(awt::XTextComponent);
223 Type typeXComboBox = GET_TYPE(awt::XComboBox);
224 Type typeXRadioButton = GET_TYPE(awt::XRadioButton);
225 Type typeXListBox = GET_TYPE(awt::XListBox);
228 TypeList fixedTextList = {&typeXFixedText, 1};
229 TypeList textCompList = {&typeXTextComponent, 1};
230 TypeList radioButtonList = {&typeXRadioButton, 1};
231 TypeList comboBoxList = {&typeXComboBox, 1};
232 TypeList listBoxList = {&typeXListBox, 1};
234 //this array stores the OO event to VBA event translation info
235 static TranslatePropMap aTranslatePropMap_Impl[] =
237 { MAP_CHAR_LEN("actionPerformed"), { MAP_CHAR_LEN("_Change"), NULL, DenyType, (void*)(&radioButtonList) } },
238 // actionPerformed ooo event
239 { MAP_CHAR_LEN("actionPerformed"), { MAP_CHAR_LEN("_Click"), NULL, ApproveAll, NULL } },
240 { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveType, (void*)(&radioButtonList) } },
241 // itemStateChanged ooo event
242 { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Click"), NULL, ApproveType, (void*)(&comboBoxList) } },
244 { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Click"), NULL, ApproveType, (void*)(&listBoxList) } },
245 // changed ooo event
246 { MAP_CHAR_LEN("changed"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } },
248 // focusGained ooo event
249 { MAP_CHAR_LEN("focusGained"), { MAP_CHAR_LEN("_GotFocus"), NULL, ApproveAll, NULL } },
251 // focusLost ooo event
252 { MAP_CHAR_LEN("focusLost"), { MAP_CHAR_LEN("_LostFocus"), NULL, ApproveAll, NULL } },
253 { MAP_CHAR_LEN("focusLost"), { MAP_CHAR_LEN("_Exit"), NULL, ApproveType, (void*)(&textCompList) } }, // support VBA TextBox_Exit event
255 // adjustmentValueChanged ooo event
256 { MAP_CHAR_LEN("adjustmentValueChanged"), { MAP_CHAR_LEN("_Scroll"), NULL, ApproveAll, NULL } },
257 { MAP_CHAR_LEN("adjustmentValueChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } },
259 // textChanged ooo event
260 { MAP_CHAR_LEN("textChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } },
262 // keyReleased ooo event
263 { MAP_CHAR_LEN("keyReleased"), { MAP_CHAR_LEN("_KeyUp"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } },
265 // mouseReleased ooo event
266 { MAP_CHAR_LEN("mouseReleased"), { MAP_CHAR_LEN("_Click"), ooMouseEvtToVBAMouseEvt, ApproveType, (void*)(&fixedTextList) } },
267 { MAP_CHAR_LEN("mouseReleased"), { MAP_CHAR_LEN("_MouseUp"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
269 // mousePressed ooo event
270 { MAP_CHAR_LEN("mousePressed"), { MAP_CHAR_LEN("_MouseDown"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
271 { MAP_CHAR_LEN("mousePressed"), { MAP_CHAR_LEN("_DblClick"), ooMouseEvtToVBADblClick, ApproveAll, NULL } },
273 // mouseMoved ooo event
274 { MAP_CHAR_LEN("mouseMoved"), { MAP_CHAR_LEN("_MouseMove"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
275 { MAP_CHAR_LEN("mouseDragged"), { MAP_CHAR_LEN("_MouseMove"), ooMouseEvtToVBAMouseEvt, DenyMouseDrag, NULL } },
277 // keyPressed ooo event
278 { MAP_CHAR_LEN("keyPressed"), { MAP_CHAR_LEN("_KeyDown"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } },
279 { MAP_CHAR_LEN("keyPressed"), { MAP_CHAR_LEN("_KeyPress"), ooKeyPressedToVBAKeyPressed, ApproveAll, NULL } }
282 EventInfoHash& getEventTransInfo()
284 static bool initialised = false;
285 static EventInfoHash eventTransInfo;
286 if ( !initialised )
288 OUString sEventInfo = MAP_CHAR_LEN("");
289 TranslatePropMap* pTransProp = aTranslatePropMap_Impl;
290 int nCount = sizeof(aTranslatePropMap_Impl) / sizeof(aTranslatePropMap_Impl[0]);
292 int i = 0;
293 while (i < nCount)
295 sEventInfo = pTransProp->sEventInfo;
296 std::list< TranslateInfo > infoList;
299 infoList.push_back( pTransProp->aTransInfo );
300 pTransProp++;
301 i++;
302 }while(i < nCount && sEventInfo == pTransProp->sEventInfo);
303 eventTransInfo[sEventInfo] = infoList;
305 initialised = true;
307 return eventTransInfo;
311 // Helper class
313 class ScriptEventHelper
315 public:
316 ScriptEventHelper( const Reference< XInterface >& xControl );
317 ScriptEventHelper( const OUString& sCntrlServiceName );
318 ~ScriptEventHelper();
319 Sequence< ScriptEventDescriptor > createEvents( const OUString& sCodeName );
320 Sequence< OUString > getEventListeners();
321 private:
322 Reference< XComponentContext > m_xCtx;
323 Reference< XInterface > m_xControl;
324 bool m_bDispose;
327 bool
328 eventMethodToDescriptor( const OUString& rEventMethod, ScriptEventDescriptor& evtDesc, const OUString& sCodeName )
330 // format of ControlListener is TypeName::methodname e.g.
331 // "com.sun.star.awt.XActionListener::actionPerformed" or
332 // "XActionListener::actionPerformed
334 OUString sMethodName;
335 OUString sTypeName;
336 sal_Int32 nDelimPos = rEventMethod.indexOf( DELIM );
337 if ( nDelimPos == -1 )
339 return false;
341 sMethodName = rEventMethod.copy( nDelimPos + DELIMLEN );
342 sTypeName = rEventMethod.copy( 0, nDelimPos );
344 EventInfoHash& infos = getEventTransInfo();
346 // Only create an ScriptEventDescriptor for an event we can translate
347 // or emulate
348 if ( !sMethodName.isEmpty()
349 && !sTypeName.isEmpty()
350 && ( infos.find( sMethodName ) != infos.end() ) )
352 // just fill in CodeName, when the event fires the other
353 // info is gathered from the event source to determine what
354 // event handler we try to call
355 evtDesc.ScriptCode = sCodeName;
356 evtDesc.ListenerType = sTypeName;
357 evtDesc.EventMethod = sMethodName;
359 // set this it VBAInterop, ensures that it doesn't
360 // get persisted or shown in property editors
361 evtDesc.ScriptType = OUString(
362 "VBAInterop" );
363 return true;
365 return false;
369 ScriptEventHelper::ScriptEventHelper( const Reference< XInterface >& xControl ) :
370 m_xCtx( comphelper::getProcessComponentContext() ),
371 m_xControl( xControl ),
372 m_bDispose( false )
375 ScriptEventHelper::ScriptEventHelper( const OUString& sCntrlServiceName ) :
376 m_xCtx( comphelper::getProcessComponentContext() ),
377 m_bDispose( true )
379 m_xControl.set( m_xCtx->getServiceManager()->createInstanceWithContext( sCntrlServiceName, m_xCtx ), uno::UNO_QUERY );
382 ScriptEventHelper::~ScriptEventHelper()
384 // dispose control ( and remove any associated event registrations )
385 if ( m_bDispose )
389 uno::Reference< lang::XComponent > xComp( m_xControl, uno::UNO_QUERY_THROW );
390 xComp->dispose();
392 // destructor can't throw
393 catch( uno::Exception& )
399 Sequence< OUString >
400 ScriptEventHelper::getEventListeners()
402 std::list< OUString > eventMethods;
404 Reference< beans::XIntrospection > xIntrospection = beans::Introspection::create( m_xCtx );
406 Reference< beans::XIntrospectionAccess > xIntrospectionAccess =
407 xIntrospection->inspect( makeAny( m_xControl ) );
408 Sequence< Type > aControlListeners =
409 xIntrospectionAccess->getSupportedListeners();
410 sal_Int32 nLength = aControlListeners.getLength();
411 for ( sal_Int32 i = 0; i< nLength; ++i )
413 Type& listType = aControlListeners[ i ];
414 OUString sFullTypeName = listType.getTypeName();
415 Sequence< OUString > sMeths =
416 comphelper::getEventMethodsForType( listType );
417 sal_Int32 sMethLen = sMeths.getLength();
418 for ( sal_Int32 j=0 ; j < sMethLen; ++j )
420 OUString sEventMethod = sFullTypeName;
421 sEventMethod += DELIM;
422 sEventMethod += sMeths[ j ];
423 eventMethods.push_back( sEventMethod );
427 Sequence< OUString > sEventMethodNames( eventMethods.size() );
428 std::list< OUString >::const_iterator it = eventMethods.begin();
429 OUString* pDest = sEventMethodNames.getArray();
431 for ( ; it != eventMethods.end(); ++it, ++pDest )
432 *pDest = *it;
434 return sEventMethodNames;
437 Sequence< ScriptEventDescriptor >
438 ScriptEventHelper::createEvents( const OUString& sCodeName )
440 Sequence< OUString > aControlListeners = getEventListeners();
441 OUString* pSrc = aControlListeners.getArray();
442 sal_Int32 nLength = aControlListeners.getLength();
444 Sequence< ScriptEventDescriptor > aDest( nLength );
445 sal_Int32 nEvts = 0;
446 for ( sal_Int32 i = 0; i< nLength; ++i, ++pSrc )
448 // from getListeners eventName is of form
449 // "com.sun.star.awt.XActionListener::actionPerformed"
450 // we need to strip "com.sun.star.awt." from that for form
451 // controls
452 ScriptEventDescriptor evtDesc;
453 if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) )
455 sal_Int32 dIndex = nEvts;
456 ++nEvts;
457 if ( nEvts > aDest.getLength() )
458 aDest.realloc( nEvts );// should never happen
459 aDest[ dIndex ] = evtDesc;
462 aDest.realloc( nEvts );
464 return aDest;
468 typedef ::cppu::WeakImplHelper1< container::XNameContainer > NameContainer_BASE;
470 class ReadOnlyEventsNameContainer : public NameContainer_BASE
472 public:
473 ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName );
474 // XNameContainer
476 virtual void SAL_CALL insertByName( const OUString&, const Any& ) throw (lang::IllegalArgumentException, container::ElementExistException, lang::WrappedTargetException, RuntimeException)
478 throw RuntimeException( OUString("ReadOnly container"), Reference< XInterface >() );
481 virtual void SAL_CALL removeByName( const OUString& ) throw (::com::sun::star::container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
483 throw RuntimeException( OUString("ReadOnly container"), Reference< XInterface >() );
486 // XNameReplace
487 virtual void SAL_CALL replaceByName( const OUString&, const Any& ) throw (lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
489 throw RuntimeException( OUString("ReadOnly container"), Reference< XInterface >() );
493 // XNameAccess
494 virtual Any SAL_CALL getByName( const OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException);
495 virtual Sequence< OUString > SAL_CALL getElementNames( ) throw (RuntimeException);
496 virtual ::sal_Bool SAL_CALL hasByName( const OUString& aName ) throw (RuntimeException);
498 // XElementAccess
499 virtual Type SAL_CALL getElementType( ) throw (RuntimeException)
500 { return getCppuType(static_cast< const OUString * >(0) ); }
501 virtual ::sal_Bool SAL_CALL hasElements( ) throw (RuntimeException)
502 { return ( ( m_hEvents.size() > 0 ? sal_True : sal_False ) ); }
503 private:
505 typedef boost::unordered_map< OUString, Any, OUStringHash,
506 ::std::equal_to< OUString > > EventSupplierHash;
508 EventSupplierHash m_hEvents;
511 ReadOnlyEventsNameContainer::ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
513 const OUString* pSrc = eventMethods.getConstArray();
514 sal_Int32 nLen = eventMethods.getLength();
515 for ( sal_Int32 index = 0; index < nLen; ++index, ++pSrc )
517 Any aDesc;
518 ScriptEventDescriptor evtDesc;
519 if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) )
521 aDesc <<= evtDesc;
522 m_hEvents[ *pSrc ] = aDesc;
527 Any SAL_CALL
528 ReadOnlyEventsNameContainer::getByName( const OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException){
529 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
530 if ( it == m_hEvents.end() )
531 throw container::NoSuchElementException();
532 return it->second;
535 Sequence< OUString > SAL_CALL
536 ReadOnlyEventsNameContainer::getElementNames( ) throw (RuntimeException)
538 Sequence< OUString > names(m_hEvents.size());
539 OUString* pDest = names.getArray();
540 EventSupplierHash::const_iterator it = m_hEvents.begin();
541 EventSupplierHash::const_iterator it_end = m_hEvents.end();
542 for ( sal_Int32 index = 0; it != it_end; ++index, ++pDest, ++it )
543 *pDest = it->first;
544 return names;
547 sal_Bool SAL_CALL
548 ReadOnlyEventsNameContainer::hasByName( const OUString& aName ) throw (RuntimeException)
550 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
551 if ( it == m_hEvents.end() )
552 return sal_False;
553 return sal_True;
556 typedef ::cppu::WeakImplHelper1< XScriptEventsSupplier > EventsSupplier_BASE;
558 class ReadOnlyEventsSupplier : public EventsSupplier_BASE
560 public:
561 ReadOnlyEventsSupplier( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
562 { m_xNameContainer = new ReadOnlyEventsNameContainer( eventMethods, sCodeName ); }
564 // XScriptEventSupplier
565 virtual Reference< container::XNameContainer > SAL_CALL getEvents( ) throw (RuntimeException){ return m_xNameContainer; }
566 private:
567 Reference< container::XNameContainer > m_xNameContainer;
570 typedef ::cppu::WeakImplHelper3< XScriptListener, util::XCloseListener, lang::XInitialization > EventListener_BASE;
572 #define EVENTLSTNR_PROPERTY_ID_MODEL 1
573 #define EVENTLSTNR_PROPERTY_MODEL OUString( "Model" )
575 class EventListener : public EventListener_BASE
576 ,public ::comphelper::OMutexAndBroadcastHelper
577 ,public ::comphelper::OPropertyContainer
578 ,public ::comphelper::OPropertyArrayUsageHelper< EventListener >
582 public:
583 EventListener( const Reference< XComponentContext >& rxContext );
584 // XEventListener
585 virtual void SAL_CALL disposing(const lang::EventObject& Source) throw( RuntimeException );
586 using cppu::OPropertySetHelper::disposing;
588 // XScriptListener
589 virtual void SAL_CALL firing(const ScriptEvent& evt) throw(RuntimeException);
590 virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException);
591 // XCloseListener
592 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException);
593 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException);
594 // XPropertySet
595 virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException);
596 // XInitialization
597 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException);
598 // XInterface
599 DECLARE_XINTERFACE()
601 // XTypeProvider
602 DECLARE_XTYPEPROVIDER()
603 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)
605 if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
607 uno::Reference< frame::XModel > xModel( rValue, uno::UNO_QUERY );
608 if( xModel != m_xModel)
610 // Remove the listener from the old XCloseBroadcaster.
611 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
612 if (xCloseBroadcaster.is())
614 xCloseBroadcaster->removeCloseListener( this );
616 // Add the listener into the new XCloseBroadcaster.
617 xCloseBroadcaster = uno::Reference< util::XCloseBroadcaster >( xModel, uno::UNO_QUERY );
618 if (xCloseBroadcaster.is())
620 xCloseBroadcaster->addCloseListener( this );
624 OPropertyContainer::setFastPropertyValue( nHandle, rValue );
625 if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
626 setShellFromModel();
629 protected:
630 // OPropertySetHelper
631 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper( );
633 // OPropertyArrayUsageHelper
634 virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;
636 private:
637 #if ASYNC
638 DECL_LINK( OnAsyncScriptEvent, ScriptEvent* );
639 #endif
640 void setShellFromModel();
641 void firing_Impl( const ScriptEvent& evt, Any *pSyncRet=NULL ) throw( RuntimeException );
643 Reference< XComponentContext > m_xContext;
644 Reference< frame::XModel > m_xModel;
645 bool m_bDocClosed;
646 SfxObjectShell* mpShell;
647 OUString msProject;
650 EventListener::EventListener( const Reference< XComponentContext >& rxContext ) :
651 OPropertyContainer(GetBroadcastHelper()), m_xContext( rxContext ), m_bDocClosed(false), mpShell( 0 )
653 registerProperty( EVENTLSTNR_PROPERTY_MODEL, EVENTLSTNR_PROPERTY_ID_MODEL,
654 beans::PropertyAttribute::TRANSIENT, &m_xModel, ::getCppuType( &m_xModel ) );
655 msProject = OUString("Standard");
658 void
659 EventListener::setShellFromModel()
661 // reset mpShell
662 mpShell = 0;
663 SfxObjectShell* pShell = SfxObjectShell::GetFirst();
664 while ( m_xModel.is() && pShell )
666 if ( pShell->GetModel() == m_xModel )
668 mpShell = pShell;
669 break;
671 pShell = SfxObjectShell::GetNext( *pShell );
673 // set ProjectName from model
676 uno::Reference< beans::XPropertySet > xProps( m_xModel, UNO_QUERY_THROW );
677 uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( OUString( "BasicLibraries" ) ), uno::UNO_QUERY_THROW );
678 msProject = xVBAMode->getProjectName();
680 catch ( uno::Exception& ) {}
683 //XEventListener
684 void
685 EventListener::disposing(const lang::EventObject&) throw( RuntimeException )
689 //XScriptListener
691 void SAL_CALL
692 EventListener::firing(const ScriptEvent& evt) throw(RuntimeException)
694 #if ASYNC
695 // needs some logic to check if the event handler is oneway or not
696 // if not oneway then firing_Impl otherwise... as below
697 acquire();
698 Application::PostUserEvent( LINK( this, EventListener, OnAsyncScriptEvent ), new ScriptEvent( evt ) );
699 #else
700 firing_Impl( evt );
701 #endif
704 #if ASYNC
705 IMPL_LINK( EventListener, OnAsyncScriptEvent, ScriptEvent*, _pEvent )
707 if ( !_pEvent )
708 return 1L;
711 // #FIXME if we enable ASYNC we probably need something like
712 // below
713 //::osl::ClearableMutexGuard aGuard( m_aMutex );
715 //if ( !impl_isDisposed_nothrow() )
716 // impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, NULL );
717 firing_Impl( *_pEvent, NULL );
720 delete _pEvent;
721 // we acquired ourself immediately before posting the event
722 release();
723 return 0L;
725 #endif
727 Any SAL_CALL
728 EventListener::approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException)
730 Any ret;
731 firing_Impl( evt, &ret );
732 return ret;
735 // XCloseListener
736 void SAL_CALL
737 EventListener::queryClosing( const lang::EventObject& /*Source*/, ::sal_Bool /*GetsOwnership*/ ) throw (util::CloseVetoException, uno::RuntimeException)
739 //Nothing to do
742 void SAL_CALL
743 EventListener::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
745 m_bDocClosed = true;
746 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
747 if (xCloseBroadcaster.is())
749 xCloseBroadcaster->removeCloseListener( this );
753 // XInitialization
754 void SAL_CALL
755 EventListener::initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException)
757 if ( aArguments.getLength() == 1 )
758 aArguments[0] >>= m_xModel;
759 OSL_TRACE("EventListener::initialize() args %d m_xModel %d", aArguments.getLength(), m_xModel.is() );
762 // XInterface
764 IMPLEMENT_FORWARD_XINTERFACE2( EventListener, EventListener_BASE, OPropertyContainer )
766 // XTypeProvider
768 IMPLEMENT_FORWARD_XTYPEPROVIDER2( EventListener, EventListener_BASE, OPropertyContainer )
770 // OPropertySetHelper
772 ::cppu::IPropertyArrayHelper&
773 EventListener::getInfoHelper( )
775 return *getArrayHelper();
778 // OPropertyArrayUsageHelper
780 ::cppu::IPropertyArrayHelper*
781 EventListener::createArrayHelper( ) const
783 Sequence< beans::Property > aProps;
784 describeProperties( aProps );
785 return new ::cppu::OPropertyArrayHelper( aProps );
788 // XPropertySet
789 Reference< beans::XPropertySetInfo >
790 EventListener::getPropertySetInfo( ) throw (RuntimeException)
792 Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
793 return xInfo;
797 //decide if the control should execute the event
798 bool ApproveAll(const ScriptEvent&, void* )
800 return true;
803 //for the given control type in evt.Arguments[0], look for if it appears in the type list in pPara
804 bool FindControl(const ScriptEvent& evt, void* pPara)
806 lang::EventObject aEvent;
807 evt.Arguments[ 0 ] >>= aEvent;
808 uno::Reference< uno::XInterface > xInterface( aEvent.Source, uno::UNO_QUERY );
810 TypeList* pTypeListInfo = static_cast<TypeList*>(pPara);
811 Type* pType = pTypeListInfo->pTypeList;
812 int nLen = pTypeListInfo->nListLength;
814 for (int i = 0; i < nLen; i++)
816 if ( xInterface->queryInterface( *pType ).hasValue() )
818 return true;
820 pType++;
823 return false;
826 //if the given control type in evt.Arguments[0] appears in the type list in pPara, then approve the execution
827 bool ApproveType(const ScriptEvent& evt, void* pPara)
829 return FindControl(evt, pPara);
832 //if the given control type in evt.Arguments[0] appears in the type list in pPara, then deny the execution
833 bool DenyType(const ScriptEvent& evt, void* pPara)
835 return !FindControl(evt, pPara);
838 //when mouse is moving, either the mouse button is pressed or some key is pressed can trigger the OO mouseDragged event,
839 //the former should be denyed, and the latter allowed, only by doing so can the VBA MouseMove event when the "Shift" key is
840 //pressed can be correctly triggered
841 bool DenyMouseDrag(const ScriptEvent& evt, void* )
843 awt::MouseEvent aEvent;
844 evt.Arguments[ 0 ] >>= aEvent;
845 if (aEvent.Buttons == 0 )
847 return true;
849 else
851 return false;
856 // EventListener
858 void
859 EventListener::firing_Impl(const ScriptEvent& evt, Any* pRet ) throw(RuntimeException)
861 OSL_TRACE("EventListener::firing_Impl( FAKE VBA_EVENTS )");
862 static const OUString vbaInterOp =
863 OUString("VBAInterop");
865 // let default handlers deal with non vba stuff
866 if ( !evt.ScriptType.equals( vbaInterOp ) )
867 return;
868 lang::EventObject aEvent;
869 evt.Arguments[ 0 ] >>= aEvent;
870 OSL_TRACE("evt.MethodName is %s", OUStringToOString( evt.MethodName, RTL_TEXTENCODING_UTF8 ).getStr() );
871 OSL_TRACE("Argument[0] is %s", OUStringToOString( comphelper::anyToString( evt.Arguments[0] ), RTL_TEXTENCODING_UTF8 ).getStr() );
872 OSL_TRACE("Getting Control");
873 OUString sName = OUString( "UserForm" );
874 OSL_TRACE("Getting Name");
876 uno::Reference< awt::XDialog > xDlg( aEvent.Source, uno::UNO_QUERY );
877 if ( !xDlg.is() )
879 OSL_TRACE("Getting Control");
880 // evt.Source is
881 // a) Dialog
882 // b) xShapeControl ( from api (sheet control) )
883 // c) eventmanager ( I guess )
884 // d) vba control ( from api also )
885 uno::Reference< drawing::XControlShape > xCntrlShape( evt.Source, uno::UNO_QUERY );
886 uno::Reference< awt::XControl > xControl( aEvent.Source, uno::UNO_QUERY );
887 if ( xCntrlShape.is() )
889 // for sheet controls ( that fire from the api ) we don't
890 // have the real control ( thats only available from the view )
891 // api code creates just a control instance that is transferred
892 // via aEvent.Arguments[ 0 ] that control though has no
893 // info like name etc.
894 OSL_TRACE("Got control shape");
895 uno::Reference< container::XNamed > xName( xCntrlShape->getControl(), uno::UNO_QUERY_THROW );
896 OSL_TRACE("Got xnamed ");
897 sName = xName->getName();
899 else
901 // Userform control ( fired from the api or from event manager )
902 uno::Reference< beans::XPropertySet > xProps;
903 OSL_TRACE("Getting properties");
904 xProps.set( xControl->getModel(), uno::UNO_QUERY_THROW );
905 xProps->getPropertyValue( OUString( "Name" ) ) >>= sName;
908 //dumpEvent( evt );
909 EventInfoHash& infos = getEventTransInfo();
910 EventInfoHash::const_iterator eventInfo_it = infos.find( evt.MethodName );
911 EventInfoHash::const_iterator it_end = infos.end();
912 if ( eventInfo_it == it_end )
914 OSL_TRACE("Bogus event for %s",
915 OUStringToOString( evt.ScriptType, RTL_TEXTENCODING_UTF8 ).getStr() );
916 return;
919 uno::Reference< script::provider::XScriptProviderSupplier > xSPS( m_xModel, uno::UNO_QUERY );
920 uno::Reference< script::provider::XScriptProvider > xScriptProvider;
921 if ( xSPS.is() )
923 xScriptProvider = xSPS->getScriptProvider();
925 if ( xScriptProvider.is() && mpShell )
927 std::list< TranslateInfo >::const_iterator txInfo =
928 eventInfo_it->second.begin();
929 std::list< TranslateInfo >::const_iterator txInfo_end = eventInfo_it->second.end();
931 BasicManager* pBasicManager = mpShell->GetBasicManager();
932 OUString sProject;
933 OUString sScriptCode( evt.ScriptCode );
934 // dialogs pass their own library, presence of Dot determines that
935 if ( sScriptCode.indexOf( '.' ) == -1 )
937 //'Project' is a better default but I want to force failures
938 //OUString sMacroLoc("Project");
939 sProject = "Standard";
941 if (!pBasicManager->GetName().isEmpty())
943 sProject = pBasicManager->GetName();
946 else
948 sal_Int32 nIndex = sScriptCode.indexOf( '.' );
949 sProject = sScriptCode.copy( 0, nIndex );
950 sScriptCode = sScriptCode.copy( nIndex + 1 );
952 OUString sMacroLoc = sProject;
953 sMacroLoc = sMacroLoc.concat( OUString(".") );
954 sMacroLoc = sMacroLoc.concat( sScriptCode ).concat( OUString(".") );
956 OSL_TRACE("sMacroLoc is %s", OUStringToOString( sMacroLoc, RTL_TEXTENCODING_UTF8 ).getStr() );
957 for ( ; txInfo != txInfo_end; ++txInfo )
959 // If the document is closed, we should not execute macro.
960 if (m_bDocClosed)
962 break;
965 OUString sTemp = sName.concat( (*txInfo).sVBAName );
966 // see if we have a match for the handlerextension
967 // where ScriptCode is methodname_handlerextension
968 OUString sToResolve = sMacroLoc.concat( sTemp );
970 OSL_TRACE("*** trying to invoke %s ",
971 OUStringToOString( sToResolve, RTL_TEXTENCODING_UTF8 ).getStr() );
972 ooo::vba::MacroResolvedInfo aMacroResolvedInfo = ooo::vba::resolveVBAMacro( mpShell, sToResolve );
973 if ( aMacroResolvedInfo.mbFound )
976 if (! txInfo->ApproveRule(evt, txInfo->pPara) )
978 continue;
981 // !! translate arguments & emulate events where necessary
982 Sequence< Any > aArguments;
983 if ( (*txInfo).toVBA )
985 aArguments = (*txInfo).toVBA( evt.Arguments );
987 else
989 aArguments = evt.Arguments;
991 if ( aArguments.getLength() )
993 // call basic event handlers for event
995 // create script url
996 OUString url = aMacroResolvedInfo.msResolvedMacro;
998 OSL_TRACE("resolved script = %s",
999 OUStringToOString( url,
1000 RTL_TEXTENCODING_UTF8 ).getStr() );
1003 uno::Any aDummyCaller = uno::makeAny( OUString("Error") );
1004 if ( pRet )
1006 ooo::vba::executeMacro( mpShell, url, aArguments, *pRet, aDummyCaller );
1008 else
1010 uno::Any aRet;
1011 ooo::vba::executeMacro( mpShell, url, aArguments, aRet, aDummyCaller );
1014 catch ( uno::Exception& e )
1016 OSL_TRACE("event script raised %s", OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1024 typedef ::cppu::WeakImplHelper1< XVBAToOOEventDescGen > VBAToOOEventDescGen_BASE;
1027 class VBAToOOEventDescGen : public VBAToOOEventDescGen_BASE
1029 public:
1030 VBAToOOEventDescGen( const Reference< XComponentContext >& rxContext );
1032 // XVBAToOOEventDescGen
1033 virtual Sequence< ScriptEventDescriptor > SAL_CALL getEventDescriptions( const OUString& sCtrlServiceName, const OUString& sCodeName ) throw (RuntimeException);
1034 virtual Reference< XScriptEventsSupplier > SAL_CALL getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName ) throw (::com::sun::star::uno::RuntimeException);
1035 private:
1036 Reference< XComponentContext > m_xContext;
1040 VBAToOOEventDescGen::VBAToOOEventDescGen( const Reference< XComponentContext >& rxContext ):m_xContext( rxContext ) {}
1042 Sequence< ScriptEventDescriptor > SAL_CALL
1043 VBAToOOEventDescGen::getEventDescriptions( const OUString& sCntrlServiceName, const OUString& sCodeName ) throw (RuntimeException)
1045 ScriptEventHelper evntHelper( sCntrlServiceName );
1046 return evntHelper.createEvents( sCodeName );
1049 Reference< XScriptEventsSupplier > SAL_CALL
1050 VBAToOOEventDescGen::getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName ) throw (::com::sun::star::uno::RuntimeException)
1052 ScriptEventHelper evntHelper( xControl );
1053 Reference< XScriptEventsSupplier > xSupplier =
1054 new ReadOnlyEventsSupplier(
1055 evntHelper.getEventListeners(), sCodeName ) ;
1056 return xSupplier;
1059 // Component related
1061 namespace evtlstner
1063 OUString SAL_CALL getImplementationName()
1065 static OUString* pImplName = 0;
1066 if ( !pImplName )
1068 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
1069 if ( !pImplName )
1071 static OUString aImplName( "ooo.vba.EventListener" );
1072 pImplName = &aImplName;
1075 return *pImplName;
1078 uno::Reference< XInterface > SAL_CALL create(
1079 Reference< XComponentContext > const & xContext )
1080 SAL_THROW(())
1082 return static_cast< lang::XTypeProvider * >( new EventListener( xContext ) );
1085 Sequence< OUString > SAL_CALL getSupportedServiceNames()
1087 const OUString strName( ::evtlstner::getImplementationName() );
1088 return Sequence< OUString >( &strName, 1 );
1091 namespace ooevtdescgen
1093 OUString SAL_CALL getImplementationName()
1095 static OUString* pImplName = 0;
1096 if ( !pImplName )
1098 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
1099 if ( !pImplName )
1101 static OUString aImplName( "ooo.vba.VBAToOOEventDesc" );
1102 pImplName = &aImplName;
1105 return *pImplName;
1108 uno::Reference< XInterface > SAL_CALL create(
1109 Reference< XComponentContext > const & xContext )
1110 SAL_THROW(())
1112 return static_cast< lang::XTypeProvider * >( new VBAToOOEventDescGen( xContext ) );
1115 Sequence< OUString > SAL_CALL getSupportedServiceNames()
1117 const OUString strName( ::ooevtdescgen::getImplementationName() );
1118 return Sequence< OUString >( &strName, 1 );
1122 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */