1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
77 #include <unordered_map>
81 // primitive support for asynchronous handling of
82 // events from controls ( all event will be processed asynchronously
83 // in the application thread )
85 #include <vcl/svapp.hxx>
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
;
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
) )
105 bool isMouseEventOk( awt::MouseEvent
& evt
, const Sequence
< Any
>& params
)
107 if ( !( params
.getLength() > 0 ) ||
108 !( params
[ 0 ] >>= evt
) )
113 Sequence
< Any
> ooMouseEvtToVBADblClick( const Sequence
< Any
>& params
)
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
124 Sequence
< Any
> ooMouseEvtToVBAMouseEvt( const Sequence
< Any
>& params
)
126 Sequence
< Any
> translatedParams
;
129 if ( !isMouseEventOk(evt
, params
) )
130 return Sequence
< Any
>();
132 translatedParams
.realloc(4);
135 translatedParams
[ 0 ] <<= evt
.Buttons
;
137 translatedParams
[ 1 ] <<= evt
.Modifiers
;
139 translatedParams
[ 2 ] <<= evt
.X
;
141 translatedParams
[ 3 ] <<= evt
.Y
;
142 return translatedParams
;
145 Sequence
< Any
> ooKeyPressedToVBAKeyPressed( const Sequence
< Any
>& params
)
147 Sequence
< Any
> translatedParams
;
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
;
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
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
>,
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
210 uno::Type
* pTypeList
;
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
) } },
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
;
282 TranslatePropMap
* pTransProp
= aTranslatePropMap_Impl
;
283 int nCount
= sizeof(aTranslatePropMap_Impl
) / sizeof(aTranslatePropMap_Impl
[0]);
288 sEventInfo
= pTransProp
->sEventInfo
;
289 std::list
< TranslateInfo
> infoList
;
292 infoList
.push_back( pTransProp
->aTransInfo
);
295 }while(i
< nCount
&& sEventInfo
== pTransProp
->sEventInfo
);
296 eventTransInfo
[sEventInfo
] = infoList
;
300 return eventTransInfo
;
306 class ScriptEventHelper
309 ScriptEventHelper( const Reference
< XInterface
>& xControl
);
310 ScriptEventHelper( const OUString
& sCntrlServiceName
);
311 ~ScriptEventHelper();
312 Sequence
< ScriptEventDescriptor
> createEvents( const OUString
& sCodeName
);
313 Sequence
< OUString
> getEventListeners();
315 Reference
< XComponentContext
> m_xCtx
;
316 Reference
< XInterface
> m_xControl
;
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
;
329 sal_Int32 nDelimPos
= rEventMethod
.indexOf( DELIM
);
330 if ( nDelimPos
== -1 )
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
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";
361 ScriptEventHelper::ScriptEventHelper( const Reference
< XInterface
>& xControl
) :
362 m_xCtx( comphelper::getProcessComponentContext() ),
363 m_xControl( xControl
),
367 ScriptEventHelper::ScriptEventHelper( const OUString
& sCntrlServiceName
) :
368 m_xCtx( comphelper::getProcessComponentContext() ),
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 )
381 uno::Reference
< lang::XComponent
> xComp( m_xControl
, uno::UNO_QUERY_THROW
);
384 // destructor can't throw
385 catch( uno::Exception
& )
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
)
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
);
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
444 ScriptEventDescriptor evtDesc
;
445 if ( eventMethodToDescriptor( *pSrc
, evtDesc
, sCodeName
) )
447 sal_Int32 dIndex
= nEvts
;
449 if ( nEvts
> aDest
.getLength() )
450 aDest
.realloc( nEvts
);// should never happen
451 aDest
[ dIndex
] = evtDesc
;
454 aDest
.realloc( nEvts
);
460 typedef ::cppu::WeakImplHelper
< container::XNameContainer
> NameContainer_BASE
;
462 class ReadOnlyEventsNameContainer
: public NameContainer_BASE
465 ReadOnlyEventsNameContainer( const Sequence
< OUString
>& eventMethods
, const OUString
& sCodeName
);
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" );
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" );
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
;
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
) ); }
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
)
510 ScriptEventDescriptor evtDesc
;
511 if ( eventMethodToDescriptor( *pSrc
, evtDesc
, sCodeName
) )
514 m_hEvents
[ *pSrc
] = aDesc
;
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();
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
)
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() )
548 typedef ::cppu::WeakImplHelper
< XScriptEventsSupplier
> EventsSupplier_BASE
;
550 class ReadOnlyEventsSupplier
: public EventsSupplier_BASE
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
; }
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
>
575 EventListener( const Reference
< XComponentContext
>& rxContext
);
577 virtual void SAL_CALL
disposing(const lang::EventObject
& Source
) throw( RuntimeException
, std::exception
) SAL_OVERRIDE
;
578 using cppu::OPropertySetHelper::disposing
;
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
;
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
;
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
;
589 virtual void SAL_CALL
initialize( const Sequence
< Any
>& aArguments
) throw (Exception
, RuntimeException
, std::exception
) SAL_OVERRIDE
;
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
)
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 );
641 // OPropertySetHelper
642 virtual ::cppu::IPropertyArrayHelper
& SAL_CALL
getInfoHelper( ) SAL_OVERRIDE
;
644 // OPropertyArrayUsageHelper
645 virtual ::cppu::IPropertyArrayHelper
* createArrayHelper( ) const SAL_OVERRIDE
;
649 DECL_LINK( OnAsyncScriptEvent
, ScriptEvent
* );
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
;
657 SfxObjectShell
* mpShell
;
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";
670 EventListener::setShellFromModel()
674 SfxObjectShell
* pShell
= SfxObjectShell::GetFirst();
675 while ( m_xModel
.is() && pShell
)
677 if ( pShell
->GetModel() == m_xModel
)
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
& ) {}
696 EventListener::disposing(const lang::EventObject
&) throw( RuntimeException
, std::exception
)
703 EventListener::firing(const ScriptEvent
& evt
) throw(RuntimeException
, std::exception
)
706 // needs some logic to check if the event handler is oneway or not
707 // if not oneway then firing_Impl otherwise... as below
709 Application::PostUserEvent( LINK( this, EventListener
, OnAsyncScriptEvent
),
710 new ScriptEvent( evt
) );
717 IMPL_LINK( EventListener
, OnAsyncScriptEvent
, ScriptEvent
*, _pEvent
)
723 // #FIXME if we enable ASYNC we probably need something like
725 //::osl::ClearableMutexGuard aGuard( m_aMutex );
727 //if ( !impl_isDisposed_nothrow() )
728 // impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, NULL );
729 firing_Impl( *_pEvent
, NULL
);
733 // we acquired ourself immediately before posting the event
740 EventListener::approveFiring(const ScriptEvent
& evt
) throw(reflection::InvocationTargetException
, RuntimeException
, std::exception
)
743 firing_Impl( evt
, &ret
);
749 EventListener::queryClosing( const lang::EventObject
& /*Source*/, sal_Bool
/*GetsOwnership*/ ) throw (util::CloseVetoException
, uno::RuntimeException
, std::exception
)
755 EventListener::notifyClosing( const lang::EventObject
& /*Source*/ ) throw (uno::RuntimeException
, std::exception
)
758 uno::Reference
< util::XCloseBroadcaster
> xCloseBroadcaster( m_xModel
, uno::UNO_QUERY
);
759 if (xCloseBroadcaster
.is())
761 xCloseBroadcaster
->removeCloseListener( this );
767 EventListener::initialize( const Sequence
< Any
>& aArguments
) throw (Exception
, RuntimeException
, std::exception
)
769 if ( aArguments
.getLength() == 1 )
770 aArguments
[0] >>= m_xModel
;
773 "args " << aArguments
.getLength() << " m_xModel " << m_xModel
.is());
778 IMPLEMENT_FORWARD_XINTERFACE2( EventListener
, EventListener_BASE
, OPropertyContainer
)
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
);
803 Reference
< beans::XPropertySetInfo
>
804 EventListener::getPropertySetInfo( ) throw (RuntimeException
, std::exception
)
806 Reference
< beans::XPropertySetInfo
> xInfo( createPropertySetInfo( getInfoHelper() ) );
811 //decide if the control should execute the event
812 bool ApproveAll(const ScriptEvent
&, void* )
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() )
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 )
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
) )
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
);
893 OSL_TRACE("Getting Control");
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();
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
;
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() );
933 uno::Reference
< script::provider::XScriptProviderSupplier
> xSPS( m_xModel
, uno::UNO_QUERY
);
934 uno::Reference
< script::provider::XScriptProvider
> xScriptProvider
;
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();
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();
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.
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
) )
995 // !! translate arguments & emulate events where necessary
996 Sequence
< Any
> aArguments
;
997 if ( (*txInfo
).toVBA
)
999 aArguments
= (*txInfo
).toVBA( evt
.Arguments
);
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") );
1020 ooo::vba::executeMacro( mpShell
, url
, aArguments
, *pRet
, aDummyCaller
);
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
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 );
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
) ;
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: */