Branch libreoffice-5-0-4
[LibreOffice.git] / scripting / source / vbaevents / eventhelper.cxx
blob616533c6e3dd9845dff7dac9e6b5799f8815883a
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/theIntrospection.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 #include <comphelper/anytostring.hxx>
72 #include <com/sun/star/script/XScriptListener.hpp>
73 #include <cppuhelper/implbase.hxx>
74 #include <comphelper/evtmethodhelper.hxx>
76 #include <list>
77 #include <unordered_map>
79 #define ASYNC 0
81 // primitive support for asynchronous handling of
82 // events from controls ( all event will be processed asynchronously
83 // in the application thread )
84 #if ASYNC
85 #include <vcl/svapp.hxx>
86 #endif
88 using namespace ::com::sun::star;
89 using namespace ::com::sun::star::script;
90 using namespace ::com::sun::star::uno;
91 using namespace ::ooo::vba;
93 // Some constants
94 static const char DELIM[] = "::";
95 static const sal_Int32 DELIMLEN = strlen(DELIM);
97 bool isKeyEventOk( awt::KeyEvent& evt, const Sequence< Any >& params )
99 if ( !( params.getLength() > 0 ) ||
100 !( params[ 0 ] >>= evt ) )
101 return false;
102 return true;
105 bool isMouseEventOk( awt::MouseEvent& evt, const Sequence< Any >& params )
107 if ( !( params.getLength() > 0 ) ||
108 !( params[ 0 ] >>= evt ) )
109 return false;
110 return true;
113 Sequence< Any > ooMouseEvtToVBADblClick( const Sequence< Any >& params )
115 awt::MouseEvent evt;
117 if ( !( isMouseEventOk(evt, params)) ||
118 (evt.ClickCount != 2) )
119 return Sequence< Any >();
120 // give back orig params, this will signal that the event is good
121 return params;
124 Sequence< Any > ooMouseEvtToVBAMouseEvt( const Sequence< Any >& params )
126 Sequence< Any > translatedParams;
127 awt::MouseEvent evt;
129 if ( !isMouseEventOk(evt, params) )
130 return Sequence< Any >();
132 translatedParams.realloc(4);
134 // Buttons
135 translatedParams[ 0 ] <<= evt.Buttons;
136 // Shift
137 translatedParams[ 1 ] <<= evt.Modifiers;
138 // X
139 translatedParams[ 2 ] <<= evt.X;
140 // Y
141 translatedParams[ 3 ] <<= evt.Y;
142 return translatedParams;
145 Sequence< Any > ooKeyPressedToVBAKeyPressed( const Sequence< Any >& params )
147 Sequence< Any > translatedParams;
148 awt::KeyEvent evt;
150 if ( !isKeyEventOk( evt, params ) )
151 return Sequence< Any >();
153 translatedParams.realloc(1);
155 Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( sal_Int32( evt.KeyCode ) );
156 translatedParams[0] <<= xKeyCode;
157 return translatedParams;
160 Sequence< Any > ooKeyPressedToVBAKeyUpDown( const Sequence< Any >& params )
162 Sequence< Any > translatedParams;
163 awt::KeyEvent evt;
165 if ( !isKeyEventOk( evt, params ) )
166 return Sequence< Any >();
168 translatedParams.realloc(2);
170 Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( evt.KeyCode );
171 sal_Int8 shift = sal::static_int_cast<sal_Int8>( evt.Modifiers );
173 // #TODO check whether values from OOO conform to values generated from vba
174 translatedParams[0] <<= xKeyCode;
175 translatedParams[1] <<= shift;
176 return translatedParams;
179 typedef Sequence< Any > (*Translator)(const Sequence< Any >&);
181 //expand the "TranslateInfo" struct to support more kinds of events
182 struct TranslateInfo
184 OUString sVBAName; //vba event name
185 Translator toVBA; //the method to convert OO event parameters to VBA event parameters
186 bool (*ApproveRule)(const ScriptEvent& evt, void* pPara); //this method is used to determine which types of controls should execute the event
187 void *pPara; //Parameters for the above approve method
191 typedef std::unordered_map< OUString,
192 std::list< TranslateInfo >,
193 OUStringHash,
194 ::std::equal_to< OUString > > EventInfoHash;
197 struct TranslatePropMap
199 OUString sEventInfo; //OO event name
200 TranslateInfo aTransInfo;
203 bool ApproveAll(const ScriptEvent& evt, void* pPara); //allow all types of controls to execute the event
204 bool ApproveType(const ScriptEvent& evt, void* pPara); //certain types of controls should execute the event, those types are given by pPara
205 bool DenyType(const ScriptEvent& evt, void* pPara); //certain types of controls should not execute the event, those types are given by pPara
206 bool DenyMouseDrag(const ScriptEvent& evt, void* pPara); //used for VBA MouseMove event when "Shift" key is pressed
208 struct TypeList
210 uno::Type* pTypeList;
211 int nListLength;
214 Type typeXFixedText = cppu::UnoType<awt::XFixedText>::get();
215 Type typeXTextComponent = cppu::UnoType<awt::XTextComponent>::get();
216 Type typeXComboBox = cppu::UnoType<awt::XComboBox>::get();
217 Type typeXRadioButton = cppu::UnoType<awt::XRadioButton>::get();
218 Type typeXListBox = cppu::UnoType<awt::XListBox>::get();
221 TypeList fixedTextList = {&typeXFixedText, 1};
222 TypeList textCompList = {&typeXTextComponent, 1};
223 TypeList radioButtonList = {&typeXRadioButton, 1};
224 TypeList comboBoxList = {&typeXComboBox, 1};
225 TypeList listBoxList = {&typeXListBox, 1};
227 //this array stores the OO event to VBA event translation info
228 static TranslatePropMap aTranslatePropMap_Impl[] =
230 { OUString("actionPerformed"), { OUString("_Change"), NULL, DenyType, (void*)(&radioButtonList) } },
231 // actionPerformed ooo event
232 { OUString("actionPerformed"), { OUString("_Click"), NULL, ApproveAll, NULL } },
233 { OUString("itemStateChanged"), { OUString("_Change"), NULL, ApproveType, (void*)(&radioButtonList) } },
234 // itemStateChanged ooo event
235 { OUString("itemStateChanged"), { OUString("_Click"), NULL, ApproveType, (void*)(&comboBoxList) } },
237 { OUString("itemStateChanged"), { OUString("_Click"), NULL, ApproveType, (void*)(&listBoxList) } },
238 // changed ooo event
239 { OUString("changed"), { OUString("_Change"), NULL, ApproveAll, NULL } },
241 // focusGained ooo event
242 { OUString("focusGained"), { OUString("_GotFocus"), NULL, ApproveAll, NULL } },
244 // focusLost ooo event
245 { OUString("focusLost"), { OUString("_LostFocus"), NULL, ApproveAll, NULL } },
246 { OUString("focusLost"), { OUString("_Exit"), NULL, ApproveType, (void*)(&textCompList) } }, // support VBA TextBox_Exit event
248 // adjustmentValueChanged ooo event
249 { OUString("adjustmentValueChanged"), { OUString("_Scroll"), NULL, ApproveAll, NULL } },
250 { OUString("adjustmentValueChanged"), { OUString("_Change"), NULL, ApproveAll, NULL } },
252 // textChanged ooo event
253 { OUString("textChanged"), { OUString("_Change"), NULL, ApproveAll, NULL } },
255 // keyReleased ooo event
256 { OUString("keyReleased"), { OUString("_KeyUp"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } },
258 // mouseReleased ooo event
259 { OUString("mouseReleased"), { OUString("_Click"), ooMouseEvtToVBAMouseEvt, ApproveType, (void*)(&fixedTextList) } },
260 { OUString("mouseReleased"), { OUString("_MouseUp"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
262 // mousePressed ooo event
263 { OUString("mousePressed"), { OUString("_MouseDown"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
264 { OUString("mousePressed"), { OUString("_DblClick"), ooMouseEvtToVBADblClick, ApproveAll, NULL } },
266 // mouseMoved ooo event
267 { OUString("mouseMoved"), { OUString("_MouseMove"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } },
268 { OUString("mouseDragged"), { OUString("_MouseMove"), ooMouseEvtToVBAMouseEvt, DenyMouseDrag, NULL } },
270 // keyPressed ooo event
271 { OUString("keyPressed"), { OUString("_KeyDown"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } },
272 { OUString("keyPressed"), { OUString("_KeyPress"), ooKeyPressedToVBAKeyPressed, ApproveAll, NULL } }
275 EventInfoHash& getEventTransInfo()
277 static bool initialised = false;
278 static EventInfoHash eventTransInfo;
279 if ( !initialised )
281 OUString sEventInfo;
282 TranslatePropMap* pTransProp = aTranslatePropMap_Impl;
283 int nCount = sizeof(aTranslatePropMap_Impl) / sizeof(aTranslatePropMap_Impl[0]);
285 int i = 0;
286 while (i < nCount)
288 sEventInfo = pTransProp->sEventInfo;
289 std::list< TranslateInfo > infoList;
292 infoList.push_back( pTransProp->aTransInfo );
293 pTransProp++;
294 i++;
295 }while(i < nCount && sEventInfo == pTransProp->sEventInfo);
296 eventTransInfo[sEventInfo] = infoList;
298 initialised = true;
300 return eventTransInfo;
304 // Helper class
306 class ScriptEventHelper
308 public:
309 ScriptEventHelper( const Reference< XInterface >& xControl );
310 ScriptEventHelper( const OUString& sCntrlServiceName );
311 ~ScriptEventHelper();
312 Sequence< ScriptEventDescriptor > createEvents( const OUString& sCodeName );
313 Sequence< OUString > getEventListeners();
314 private:
315 Reference< XComponentContext > m_xCtx;
316 Reference< XInterface > m_xControl;
317 bool m_bDispose;
320 bool
321 eventMethodToDescriptor( const OUString& rEventMethod, ScriptEventDescriptor& evtDesc, const OUString& sCodeName )
323 // format of ControlListener is TypeName::methodname e.g.
324 // "com.sun.star.awt.XActionListener::actionPerformed" or
325 // "XActionListener::actionPerformed
327 OUString sMethodName;
328 OUString sTypeName;
329 sal_Int32 nDelimPos = rEventMethod.indexOf( DELIM );
330 if ( nDelimPos == -1 )
332 return false;
334 sMethodName = rEventMethod.copy( nDelimPos + DELIMLEN );
335 sTypeName = rEventMethod.copy( 0, nDelimPos );
337 EventInfoHash& infos = getEventTransInfo();
339 // Only create an ScriptEventDescriptor for an event we can translate
340 // or emulate
341 if ( !sMethodName.isEmpty()
342 && !sTypeName.isEmpty()
343 && ( infos.find( sMethodName ) != infos.end() ) )
345 // just fill in CodeName, when the event fires the other
346 // info is gathered from the event source to determine what
347 // event handler we try to call
348 evtDesc.ScriptCode = sCodeName;
349 evtDesc.ListenerType = sTypeName;
350 evtDesc.EventMethod = sMethodName;
352 // set this it VBAInterop, ensures that it doesn't
353 // get persisted or shown in property editors
354 evtDesc.ScriptType = "VBAInterop";
355 return true;
357 return false;
361 ScriptEventHelper::ScriptEventHelper( const Reference< XInterface >& xControl ) :
362 m_xCtx( comphelper::getProcessComponentContext() ),
363 m_xControl( xControl ),
364 m_bDispose( false )
367 ScriptEventHelper::ScriptEventHelper( const OUString& sCntrlServiceName ) :
368 m_xCtx( comphelper::getProcessComponentContext() ),
369 m_bDispose( true )
371 m_xControl.set( m_xCtx->getServiceManager()->createInstanceWithContext( sCntrlServiceName, m_xCtx ), uno::UNO_QUERY );
374 ScriptEventHelper::~ScriptEventHelper()
376 // dispose control ( and remove any associated event registrations )
377 if ( m_bDispose )
381 uno::Reference< lang::XComponent > xComp( m_xControl, uno::UNO_QUERY_THROW );
382 xComp->dispose();
384 // destructor can't throw
385 catch( uno::Exception& )
391 Sequence< OUString >
392 ScriptEventHelper::getEventListeners()
394 std::list< OUString > eventMethods;
396 Reference< beans::XIntrospection > xIntrospection = beans::theIntrospection::get( m_xCtx );
398 Reference< beans::XIntrospectionAccess > xIntrospectionAccess =
399 xIntrospection->inspect( makeAny( m_xControl ) );
400 Sequence< Type > aControlListeners =
401 xIntrospectionAccess->getSupportedListeners();
402 sal_Int32 nLength = aControlListeners.getLength();
403 for ( sal_Int32 i = 0; i< nLength; ++i )
405 Type& listType = aControlListeners[ i ];
406 OUString sFullTypeName = listType.getTypeName();
407 Sequence< OUString > sMeths =
408 comphelper::getEventMethodsForType( listType );
409 sal_Int32 sMethLen = sMeths.getLength();
410 for ( sal_Int32 j=0 ; j < sMethLen; ++j )
412 OUString sEventMethod = sFullTypeName;
413 sEventMethod += DELIM;
414 sEventMethod += sMeths[ j ];
415 eventMethods.push_back( sEventMethod );
419 Sequence< OUString > sEventMethodNames( eventMethods.size() );
420 std::list< OUString >::const_iterator it = eventMethods.begin();
421 OUString* pDest = sEventMethodNames.getArray();
423 for ( ; it != eventMethods.end(); ++it, ++pDest )
424 *pDest = *it;
426 return sEventMethodNames;
429 Sequence< ScriptEventDescriptor >
430 ScriptEventHelper::createEvents( const OUString& sCodeName )
432 Sequence< OUString > aControlListeners = getEventListeners();
433 OUString* pSrc = aControlListeners.getArray();
434 sal_Int32 nLength = aControlListeners.getLength();
436 Sequence< ScriptEventDescriptor > aDest( nLength );
437 sal_Int32 nEvts = 0;
438 for ( sal_Int32 i = 0; i< nLength; ++i, ++pSrc )
440 // from getListeners eventName is of form
441 // "com.sun.star.awt.XActionListener::actionPerformed"
442 // we need to strip "com.sun.star.awt." from that for form
443 // controls
444 ScriptEventDescriptor evtDesc;
445 if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) )
447 sal_Int32 dIndex = nEvts;
448 ++nEvts;
449 if ( nEvts > aDest.getLength() )
450 aDest.realloc( nEvts );// should never happen
451 aDest[ dIndex ] = evtDesc;
454 aDest.realloc( nEvts );
456 return aDest;
460 typedef ::cppu::WeakImplHelper< container::XNameContainer > NameContainer_BASE;
462 class ReadOnlyEventsNameContainer : public NameContainer_BASE
464 public:
465 ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName );
466 // XNameContainer
468 virtual void SAL_CALL insertByName( const OUString&, const Any& ) throw (lang::IllegalArgumentException, container::ElementExistException, lang::WrappedTargetException, RuntimeException, std::exception) SAL_OVERRIDE
470 throw RuntimeException("ReadOnly container" );
473 virtual void SAL_CALL removeByName( const OUString& ) throw (::com::sun::star::container::NoSuchElementException, lang::WrappedTargetException, RuntimeException, std::exception) SAL_OVERRIDE
475 throw RuntimeException("ReadOnly container" );
478 // XNameReplace
479 virtual void SAL_CALL replaceByName( const OUString&, const Any& ) throw (lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, RuntimeException, std::exception) SAL_OVERRIDE
481 throw RuntimeException("ReadOnly container" );
485 // XNameAccess
486 virtual Any SAL_CALL getByName( const OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException, std::exception) SAL_OVERRIDE;
487 virtual Sequence< OUString > SAL_CALL getElementNames( ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
488 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
490 // XElementAccess
491 virtual Type SAL_CALL getElementType( ) throw (RuntimeException, std::exception) SAL_OVERRIDE
492 { return cppu::UnoType<OUString>::get(); }
493 virtual sal_Bool SAL_CALL hasElements( ) throw (RuntimeException, std::exception) SAL_OVERRIDE
494 { return ( ( m_hEvents.empty() ? sal_False : sal_True ) ); }
495 private:
497 typedef std::unordered_map< OUString, Any, OUStringHash,
498 ::std::equal_to< OUString > > EventSupplierHash;
500 EventSupplierHash m_hEvents;
503 ReadOnlyEventsNameContainer::ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
505 const OUString* pSrc = eventMethods.getConstArray();
506 sal_Int32 nLen = eventMethods.getLength();
507 for ( sal_Int32 index = 0; index < nLen; ++index, ++pSrc )
509 Any aDesc;
510 ScriptEventDescriptor evtDesc;
511 if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) )
513 aDesc <<= evtDesc;
514 m_hEvents[ *pSrc ] = aDesc;
519 Any SAL_CALL
520 ReadOnlyEventsNameContainer::getByName( const OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException, std::exception){
521 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
522 if ( it == m_hEvents.end() )
523 throw container::NoSuchElementException();
524 return it->second;
527 Sequence< OUString > SAL_CALL
528 ReadOnlyEventsNameContainer::getElementNames( ) throw (RuntimeException, std::exception)
530 Sequence< OUString > names(m_hEvents.size());
531 OUString* pDest = names.getArray();
532 EventSupplierHash::const_iterator it = m_hEvents.begin();
533 EventSupplierHash::const_iterator it_end = m_hEvents.end();
534 for ( sal_Int32 index = 0; it != it_end; ++index, ++pDest, ++it )
535 *pDest = it->first;
536 return names;
539 sal_Bool SAL_CALL
540 ReadOnlyEventsNameContainer::hasByName( const OUString& aName ) throw (RuntimeException, std::exception)
542 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
543 if ( it == m_hEvents.end() )
544 return sal_False;
545 return sal_True;
548 typedef ::cppu::WeakImplHelper< XScriptEventsSupplier > EventsSupplier_BASE;
550 class ReadOnlyEventsSupplier : public EventsSupplier_BASE
552 public:
553 ReadOnlyEventsSupplier( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
554 { m_xNameContainer = new ReadOnlyEventsNameContainer( eventMethods, sCodeName ); }
556 // XScriptEventSupplier
557 virtual Reference< container::XNameContainer > SAL_CALL getEvents( ) throw (RuntimeException, std::exception) SAL_OVERRIDE { return m_xNameContainer; }
558 private:
559 Reference< container::XNameContainer > m_xNameContainer;
562 typedef ::cppu::WeakImplHelper< XScriptListener, util::XCloseListener, lang::XInitialization, css::lang::XServiceInfo > EventListener_BASE;
564 #define EVENTLSTNR_PROPERTY_ID_MODEL 1
565 #define EVENTLSTNR_PROPERTY_MODEL OUString( "Model" )
567 class EventListener : public EventListener_BASE
568 ,public ::comphelper::OMutexAndBroadcastHelper
569 ,public ::comphelper::OPropertyContainer
570 ,public ::comphelper::OPropertyArrayUsageHelper< EventListener >
574 public:
575 EventListener( const Reference< XComponentContext >& rxContext );
576 // XEventListener
577 virtual void SAL_CALL disposing(const lang::EventObject& Source) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
578 using cppu::OPropertySetHelper::disposing;
580 // XScriptListener
581 virtual void SAL_CALL firing(const ScriptEvent& evt) throw(RuntimeException, std::exception) SAL_OVERRIDE;
582 virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException, std::exception) SAL_OVERRIDE;
583 // XCloseListener
584 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException, std::exception) SAL_OVERRIDE;
585 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
586 // XPropertySet
587 virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
588 // XInitialization
589 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException, std::exception) SAL_OVERRIDE;
590 // XInterface
591 DECLARE_XINTERFACE()
593 // XTypeProvider
594 DECLARE_XTYPEPROVIDER()
595 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, std::exception) SAL_OVERRIDE
597 if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
599 uno::Reference< frame::XModel > xModel( rValue, uno::UNO_QUERY );
600 if( xModel != m_xModel)
602 // Remove the listener from the old XCloseBroadcaster.
603 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
604 if (xCloseBroadcaster.is())
606 xCloseBroadcaster->removeCloseListener( this );
608 // Add the listener into the new XCloseBroadcaster.
609 xCloseBroadcaster = uno::Reference< util::XCloseBroadcaster >( xModel, uno::UNO_QUERY );
610 if (xCloseBroadcaster.is())
612 xCloseBroadcaster->addCloseListener( this );
616 OPropertyContainer::setFastPropertyValue( nHandle, rValue );
617 if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
618 setShellFromModel();
621 OUString SAL_CALL getImplementationName()
622 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
624 return OUString( "ooo.vba.EventListener" );
627 sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
628 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
630 return cppu::supportsService(this, ServiceName);
633 css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
634 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
636 const OUString strName( getImplementationName() );
637 return Sequence< OUString >( &strName, 1 );
640 protected:
641 // OPropertySetHelper
642 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper( ) SAL_OVERRIDE;
644 // OPropertyArrayUsageHelper
645 virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const SAL_OVERRIDE;
647 private:
648 #if ASYNC
649 DECL_LINK( OnAsyncScriptEvent, ScriptEvent* );
650 #endif
651 void setShellFromModel();
652 void firing_Impl( const ScriptEvent& evt, Any *pSyncRet=NULL ) throw( RuntimeException );
654 Reference< XComponentContext > m_xContext;
655 Reference< frame::XModel > m_xModel;
656 bool m_bDocClosed;
657 SfxObjectShell* mpShell;
658 OUString msProject;
661 EventListener::EventListener( const Reference< XComponentContext >& rxContext ) :
662 OPropertyContainer(GetBroadcastHelper()), m_xContext( rxContext ), m_bDocClosed(false), mpShell( 0 )
664 registerProperty( EVENTLSTNR_PROPERTY_MODEL, EVENTLSTNR_PROPERTY_ID_MODEL,
665 beans::PropertyAttribute::TRANSIENT, &m_xModel, cppu::UnoType<decltype(m_xModel)>::get() );
666 msProject = "Standard";
669 void
670 EventListener::setShellFromModel()
672 // reset mpShell
673 mpShell = 0;
674 SfxObjectShell* pShell = SfxObjectShell::GetFirst();
675 while ( m_xModel.is() && pShell )
677 if ( pShell->GetModel() == m_xModel )
679 mpShell = pShell;
680 break;
682 pShell = SfxObjectShell::GetNext( *pShell );
684 // set ProjectName from model
687 uno::Reference< beans::XPropertySet > xProps( m_xModel, UNO_QUERY_THROW );
688 uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue("BasicLibraries"), uno::UNO_QUERY_THROW );
689 msProject = xVBAMode->getProjectName();
691 catch ( uno::Exception& ) {}
694 //XEventListener
695 void
696 EventListener::disposing(const lang::EventObject&) throw( RuntimeException, std::exception )
700 //XScriptListener
702 void SAL_CALL
703 EventListener::firing(const ScriptEvent& evt) throw(RuntimeException, std::exception)
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 ),
710 new ScriptEvent( evt ) );
711 #else
712 firing_Impl( evt );
713 #endif
716 #if ASYNC
717 IMPL_LINK( EventListener, OnAsyncScriptEvent, ScriptEvent*, _pEvent )
719 if ( !_pEvent )
720 return 1L;
723 // #FIXME if we enable ASYNC we probably need something like
724 // below
725 //::osl::ClearableMutexGuard aGuard( m_aMutex );
727 //if ( !impl_isDisposed_nothrow() )
728 // impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, NULL );
729 firing_Impl( *_pEvent, NULL );
732 delete _pEvent;
733 // we acquired ourself immediately before posting the event
734 release();
735 return 0L;
737 #endif
739 Any SAL_CALL
740 EventListener::approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException, std::exception)
742 Any ret;
743 firing_Impl( evt, &ret );
744 return ret;
747 // XCloseListener
748 void SAL_CALL
749 EventListener::queryClosing( const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ ) throw (util::CloseVetoException, uno::RuntimeException, std::exception)
751 //Nothing to do
754 void SAL_CALL
755 EventListener::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException, std::exception)
757 m_bDocClosed = true;
758 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
759 if (xCloseBroadcaster.is())
761 xCloseBroadcaster->removeCloseListener( this );
765 // XInitialization
766 void SAL_CALL
767 EventListener::initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException, std::exception)
769 if ( aArguments.getLength() == 1 )
770 aArguments[0] >>= m_xModel;
771 SAL_INFO(
772 "scripting",
773 "args " << aArguments.getLength() << " m_xModel " << m_xModel.is());
776 // XInterface
778 IMPLEMENT_FORWARD_XINTERFACE2( EventListener, EventListener_BASE, OPropertyContainer )
780 // XTypeProvider
782 IMPLEMENT_FORWARD_XTYPEPROVIDER2( EventListener, EventListener_BASE, OPropertyContainer )
784 // OPropertySetHelper
786 ::cppu::IPropertyArrayHelper&
787 EventListener::getInfoHelper( )
789 return *getArrayHelper();
792 // OPropertyArrayUsageHelper
794 ::cppu::IPropertyArrayHelper*
795 EventListener::createArrayHelper( ) const
797 Sequence< beans::Property > aProps;
798 describeProperties( aProps );
799 return new ::cppu::OPropertyArrayHelper( aProps );
802 // XPropertySet
803 Reference< beans::XPropertySetInfo >
804 EventListener::getPropertySetInfo( ) throw (RuntimeException, std::exception)
806 Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
807 return xInfo;
811 //decide if the control should execute the event
812 bool ApproveAll(const ScriptEvent&, void* )
814 return true;
817 //for the given control type in evt.Arguments[0], look for if it appears in the type list in pPara
818 bool FindControl(const ScriptEvent& evt, void* pPara)
820 lang::EventObject aEvent;
821 evt.Arguments[ 0 ] >>= aEvent;
822 uno::Reference< uno::XInterface > xInterface( aEvent.Source, uno::UNO_QUERY );
824 TypeList* pTypeListInfo = static_cast<TypeList*>(pPara);
825 Type* pType = pTypeListInfo->pTypeList;
826 int nLen = pTypeListInfo->nListLength;
828 for (int i = 0; i < nLen; i++)
830 if ( xInterface->queryInterface( *pType ).hasValue() )
832 return true;
834 pType++;
837 return false;
840 //if the given control type in evt.Arguments[0] appears in the type list in pPara, then approve the execution
841 bool ApproveType(const ScriptEvent& evt, void* pPara)
843 return FindControl(evt, pPara);
846 //if the given control type in evt.Arguments[0] appears in the type list in pPara, then deny the execution
847 bool DenyType(const ScriptEvent& evt, void* pPara)
849 return !FindControl(evt, pPara);
852 //when mouse is moving, either the mouse button is pressed or some key is pressed can trigger the OO mouseDragged event,
853 //the former should be denyed, and the latter allowed, only by doing so can the VBA MouseMove event when the "Shift" key is
854 //pressed can be correctly triggered
855 bool DenyMouseDrag(const ScriptEvent& evt, void* )
857 awt::MouseEvent aEvent;
858 evt.Arguments[ 0 ] >>= aEvent;
859 if (aEvent.Buttons == 0 )
861 return true;
863 else
865 return false;
870 // EventListener
872 void
873 EventListener::firing_Impl(const ScriptEvent& evt, Any* pRet ) throw(RuntimeException)
875 OSL_TRACE("EventListener::firing_Impl( FAKE VBA_EVENTS )");
876 static const OUString vbaInterOp =
877 OUString("VBAInterop");
879 // let default handlers deal with non vba stuff
880 if ( !evt.ScriptType.equals( vbaInterOp ) )
881 return;
882 lang::EventObject aEvent;
883 evt.Arguments[ 0 ] >>= aEvent;
884 OSL_TRACE("evt.MethodName is %s", OUStringToOString( evt.MethodName, RTL_TEXTENCODING_UTF8 ).getStr() );
885 OSL_TRACE("Argument[0] is %s", OUStringToOString( comphelper::anyToString( evt.Arguments[0] ), RTL_TEXTENCODING_UTF8 ).getStr() );
886 OSL_TRACE("Getting Control");
887 OUString sName = "UserForm";
888 OSL_TRACE("Getting Name");
890 uno::Reference< awt::XDialog > xDlg( aEvent.Source, uno::UNO_QUERY );
891 if ( !xDlg.is() )
893 OSL_TRACE("Getting Control");
894 // evt.Source is
895 // a) Dialog
896 // b) xShapeControl ( from api (sheet control) )
897 // c) eventmanager ( I guess )
898 // d) vba control ( from api also )
899 uno::Reference< drawing::XControlShape > xCntrlShape( evt.Source, uno::UNO_QUERY );
900 uno::Reference< awt::XControl > xControl( aEvent.Source, uno::UNO_QUERY );
901 if ( xCntrlShape.is() )
903 // for sheet controls ( that fire from the api ) we don't
904 // have the real control ( thats only available from the view )
905 // api code creates just a control instance that is transferred
906 // via aEvent.Arguments[ 0 ] that control though has no
907 // info like name etc.
908 OSL_TRACE("Got control shape");
909 uno::Reference< container::XNamed > xName( xCntrlShape->getControl(), uno::UNO_QUERY_THROW );
910 OSL_TRACE("Got xnamed ");
911 sName = xName->getName();
913 else
915 // Userform control ( fired from the api or from event manager )
916 uno::Reference< beans::XPropertySet > xProps;
917 OSL_TRACE("Getting properties");
918 xProps.set( xControl->getModel(), uno::UNO_QUERY_THROW );
919 xProps->getPropertyValue("Name") >>= sName;
922 //dumpEvent( evt );
923 EventInfoHash& infos = getEventTransInfo();
924 EventInfoHash::const_iterator eventInfo_it = infos.find( evt.MethodName );
925 EventInfoHash::const_iterator it_end = infos.end();
926 if ( eventInfo_it == it_end )
928 OSL_TRACE("Bogus event for %s",
929 OUStringToOString( evt.ScriptType, RTL_TEXTENCODING_UTF8 ).getStr() );
930 return;
933 uno::Reference< script::provider::XScriptProviderSupplier > xSPS( m_xModel, uno::UNO_QUERY );
934 uno::Reference< script::provider::XScriptProvider > xScriptProvider;
935 if ( xSPS.is() )
937 xScriptProvider = xSPS->getScriptProvider();
939 if ( xScriptProvider.is() && mpShell )
941 std::list< TranslateInfo >::const_iterator txInfo =
942 eventInfo_it->second.begin();
943 std::list< TranslateInfo >::const_iterator txInfo_end = eventInfo_it->second.end();
945 BasicManager* pBasicManager = mpShell->GetBasicManager();
946 OUString sProject;
947 OUString sScriptCode( evt.ScriptCode );
948 // dialogs pass their own library, presence of Dot determines that
949 if ( sScriptCode.indexOf( '.' ) == -1 )
951 //'Project' is a better default but I want to force failures
952 //OUString sMacroLoc("Project");
953 sProject = "Standard";
955 if (!pBasicManager->GetName().isEmpty())
957 sProject = pBasicManager->GetName();
960 else
962 sal_Int32 nIndex = sScriptCode.indexOf( '.' );
963 sProject = sScriptCode.copy( 0, nIndex );
964 sScriptCode = sScriptCode.copy( nIndex + 1 );
966 OUString sMacroLoc = sProject;
967 sMacroLoc = sMacroLoc.concat( OUString(".") );
968 sMacroLoc = sMacroLoc.concat( sScriptCode ).concat( OUString(".") );
970 OSL_TRACE("sMacroLoc is %s", OUStringToOString( sMacroLoc, RTL_TEXTENCODING_UTF8 ).getStr() );
971 for ( ; txInfo != txInfo_end; ++txInfo )
973 // If the document is closed, we should not execute macro.
974 if (m_bDocClosed)
976 break;
979 OUString sTemp = sName.concat( (*txInfo).sVBAName );
980 // see if we have a match for the handlerextension
981 // where ScriptCode is methodname_handlerextension
982 OUString sToResolve = sMacroLoc.concat( sTemp );
984 OSL_TRACE("*** trying to invoke %s ",
985 OUStringToOString( sToResolve, RTL_TEXTENCODING_UTF8 ).getStr() );
986 ooo::vba::MacroResolvedInfo aMacroResolvedInfo = ooo::vba::resolveVBAMacro( mpShell, sToResolve );
987 if ( aMacroResolvedInfo.mbFound )
990 if (! txInfo->ApproveRule(evt, txInfo->pPara) )
992 continue;
995 // !! translate arguments & emulate events where necessary
996 Sequence< Any > aArguments;
997 if ( (*txInfo).toVBA )
999 aArguments = (*txInfo).toVBA( evt.Arguments );
1001 else
1003 aArguments = evt.Arguments;
1005 if ( aArguments.getLength() )
1007 // call basic event handlers for event
1009 // create script url
1010 OUString url = aMacroResolvedInfo.msResolvedMacro;
1012 OSL_TRACE("resolved script = %s",
1013 OUStringToOString( url,
1014 RTL_TEXTENCODING_UTF8 ).getStr() );
1017 uno::Any aDummyCaller = uno::makeAny( OUString("Error") );
1018 if ( pRet )
1020 ooo::vba::executeMacro( mpShell, url, aArguments, *pRet, aDummyCaller );
1022 else
1024 uno::Any aRet;
1025 ooo::vba::executeMacro( mpShell, url, aArguments, aRet, aDummyCaller );
1028 catch ( uno::Exception& e )
1030 OSL_TRACE("event script raised %s", OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1038 typedef ::cppu::WeakImplHelper< XVBAToOOEventDescGen, css::lang::XServiceInfo > VBAToOOEventDescGen_BASE;
1041 class VBAToOOEventDescGen : public VBAToOOEventDescGen_BASE
1043 public:
1044 VBAToOOEventDescGen( const Reference< XComponentContext >& rxContext );
1046 // XVBAToOOEventDescGen
1047 virtual Sequence< ScriptEventDescriptor > SAL_CALL getEventDescriptions( const OUString& sCtrlServiceName, const OUString& sCodeName ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
1048 virtual Reference< XScriptEventsSupplier > SAL_CALL getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
1050 OUString SAL_CALL getImplementationName()
1051 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
1053 return OUString( "ooo.vba.VBAToOOEventDesc" );
1056 sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
1057 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
1059 return cppu::supportsService(this, ServiceName);
1062 css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
1063 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
1065 const OUString strName( getImplementationName() );
1066 return Sequence< OUString >( &strName, 1 );
1069 private:
1070 Reference< XComponentContext > m_xContext;
1074 VBAToOOEventDescGen::VBAToOOEventDescGen( const Reference< XComponentContext >& rxContext ):m_xContext( rxContext ) {}
1076 Sequence< ScriptEventDescriptor > SAL_CALL
1077 VBAToOOEventDescGen::getEventDescriptions( const OUString& sCntrlServiceName, const OUString& sCodeName ) throw (RuntimeException, std::exception)
1079 ScriptEventHelper evntHelper( sCntrlServiceName );
1080 return evntHelper.createEvents( sCodeName );
1083 Reference< XScriptEventsSupplier > SAL_CALL
1084 VBAToOOEventDescGen::getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName ) throw (::com::sun::star::uno::RuntimeException, std::exception)
1086 ScriptEventHelper evntHelper( xControl );
1087 Reference< XScriptEventsSupplier > xSupplier =
1088 new ReadOnlyEventsSupplier(
1089 evntHelper.getEventListeners(), sCodeName ) ;
1090 return xSupplier;
1093 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
1094 ooo_vba_EventListener_get_implementation(::com::sun::star::uno::XComponentContext* context,
1095 ::com::sun::star::uno::Sequence<css::uno::Any> const &)
1097 return cppu::acquire(new EventListener(context));
1101 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
1102 ooo_vba_VBAToOOEventDesc_get_implementation(::com::sun::star::uno::XComponentContext* context,
1103 ::com::sun::star::uno::Sequence<css::uno::Any> const &)
1105 return cppu::acquire(new VBAToOOEventDescGen(context));
1109 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */