Get the style color and number just once
[LibreOffice.git] / scripting / source / vbaevents / eventhelper.cxx
blob7c02c658a13432e6852182c27a459d5bcd7f2da6
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 <sal/log.hxx>
22 #include <comphelper/processfactory.hxx>
23 #include <comphelper/uno3.hxx>
24 #include <comphelper/compbase.hxx>
25 #include <comphelper/proparrhlp.hxx>
26 #include <comphelper/propertycontainer2.hxx>
27 #include <comphelper/diagnose_ex.hxx>
29 #include <ooo/vba/XVBAToOOEventDescGen.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/beans/theIntrospection.hpp>
33 #include <com/sun/star/beans/PropertyAttribute.hpp>
35 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
36 #include <com/sun/star/lang/XServiceInfo.hpp>
37 #include <com/sun/star/lang/XInitialization.hpp>
39 #include <com/sun/star/util/XCloseListener.hpp>
40 #include <com/sun/star/util/XCloseBroadcaster.hpp>
42 #include <com/sun/star/frame/XModel.hpp>
44 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
45 #include <com/sun/star/script/provider/XScriptProviderSupplier.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/basmgr.hxx>
63 #include <filter/msfilter/msvbahelper.hxx>
64 #include <vbahelper/vbareturntypes.hxx>
66 #include <com/sun/star/script/XScriptListener.hpp>
67 #include <cppuhelper/implbase.hxx>
68 #include <cppuhelper/supportsservice.hxx>
69 #include <comphelper/evtmethodhelper.hxx>
71 #include <vector>
72 #include <unordered_map>
74 using namespace ::com::sun::star;
75 using namespace ::com::sun::star::script;
76 using namespace ::com::sun::star::uno;
77 using namespace ::ooo::vba;
79 // Some constants
80 constexpr std::u16string_view DELIM = u"::";
81 constexpr sal_Int32 DELIMLEN = DELIM.size();
83 static bool isKeyEventOk( awt::KeyEvent& evt, const Sequence< Any >& params )
85 return params.hasElements() && ( params[ 0 ] >>= evt );
88 static bool isMouseEventOk( awt::MouseEvent& evt, const Sequence< Any >& params )
90 return params.hasElements() && ( params[ 0 ] >>= evt );
93 static Sequence< Any > ooMouseEvtToVBADblClick( const Sequence< Any >& params )
95 awt::MouseEvent evt;
97 if ( !( isMouseEventOk(evt, params)) ||
98 (evt.ClickCount != 2) )
99 return Sequence< Any >();
100 // give back orig params, this will signal that the event is good
101 return params;
104 static Sequence< Any > ooMouseEvtToVBAMouseEvt( const Sequence< Any >& params )
106 awt::MouseEvent evt;
108 if ( !isMouseEventOk(evt, params) )
109 return Sequence< Any >();
111 Sequence< Any > translatedParams{ Any(evt.Buttons), // Buttons
112 Any(evt.Modifiers), // Shift
113 Any(evt.X), // X
114 Any(evt.Y) }; // Y
115 return translatedParams;
118 static Sequence< Any > ooKeyPressedToVBAKeyPressed( const Sequence< Any >& params )
120 awt::KeyEvent evt;
122 if ( !isKeyEventOk( evt, params ) )
123 return Sequence< Any >();
125 Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( sal_Int32( evt.KeyCode ) );
126 Sequence< Any > translatedParams{ Any(xKeyCode) };
127 return translatedParams;
130 static Sequence< Any > ooKeyPressedToVBAKeyUpDown( const Sequence< Any >& params )
132 awt::KeyEvent evt;
134 if ( !isKeyEventOk( evt, params ) )
135 return Sequence< Any >();
137 Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( evt.KeyCode );
138 sal_Int8 shift = sal::static_int_cast<sal_Int8>( evt.Modifiers );
140 // #TODO check whether values from OOO conform to values generated from vba
141 Sequence< Any > translatedParams{ Any(xKeyCode), Any(shift) };
142 return translatedParams;
145 typedef Sequence< Any > (*Translator)(const Sequence< Any >&);
147 namespace {
149 //expand the "TranslateInfo" struct to support more kinds of events
150 struct TranslateInfo
152 OUString sVBAName; //vba event name
153 Translator toVBA; //the method to convert OO event parameters to VBA event parameters
154 bool (*ApproveRule)(const ScriptEvent& evt, void const * pPara); //this method is used to determine which types of controls should execute the event
155 void const *pPara; //Parameters for the above approve method
160 typedef std::unordered_map<
161 OUString,
162 std::vector< TranslateInfo > > EventInfoHash;
164 namespace {
166 struct TranslatePropMap
168 OUString sEventInfo; //OO event name
169 TranslateInfo aTransInfo;
174 static bool ApproveAll(const ScriptEvent& evt, void const * pPara); //allow all types of controls to execute the event
175 static bool ApproveType(const ScriptEvent& evt, void const * pPara); //certain types of controls should execute the event, those types are given by pPara
176 static bool DenyType(const ScriptEvent& evt, void const * pPara); //certain types of controls should not execute the event, those types are given by pPara
177 static bool DenyMouseDrag(const ScriptEvent& evt, void const * pPara); //used for VBA MouseMove event when "Shift" key is pressed
179 namespace {
181 struct TypeList
183 uno::Type const * pTypeList;
184 int nListLength;
189 Type const typeXFixedText = cppu::UnoType<awt::XFixedText>::get();
190 Type const typeXTextComponent = cppu::UnoType<awt::XTextComponent>::get();
191 Type const typeXComboBox = cppu::UnoType<awt::XComboBox>::get();
192 Type const typeXRadioButton = cppu::UnoType<awt::XRadioButton>::get();
193 Type const typeXListBox = cppu::UnoType<awt::XListBox>::get();
196 TypeList const fixedTextList = {&typeXFixedText, 1};
197 TypeList const textCompList = {&typeXTextComponent, 1};
198 TypeList const radioButtonList = {&typeXRadioButton, 1};
199 TypeList const comboBoxList = {&typeXComboBox, 1};
200 TypeList const listBoxList = {&typeXListBox, 1};
202 //this array stores the OO event to VBA event translation info
203 static TranslatePropMap aTranslatePropMap_Impl[] =
205 { u"actionPerformed"_ustr, { u"_Change"_ustr, nullptr, DenyType, static_cast<void const *>(&radioButtonList) } },
206 // actionPerformed ooo event
207 { u"actionPerformed"_ustr, { u"_Click"_ustr, nullptr, ApproveAll, nullptr } },
208 { u"itemStateChanged"_ustr, { u"_Change"_ustr, nullptr, ApproveType, static_cast<void const *>(&radioButtonList) } },
209 // itemStateChanged ooo event
210 { u"itemStateChanged"_ustr, { u"_Click"_ustr, nullptr, ApproveType, static_cast<void const *>(&comboBoxList) } },
212 { u"itemStateChanged"_ustr, { u"_Click"_ustr, nullptr, ApproveType, static_cast<void const *>(&listBoxList) } },
213 // changed ooo event
214 { u"changed"_ustr, { u"_Change"_ustr, nullptr, ApproveAll, nullptr } },
216 // focusGained ooo event
217 { u"focusGained"_ustr, { u"_GotFocus"_ustr, nullptr, ApproveAll, nullptr } },
219 // focusLost ooo event
220 { u"focusLost"_ustr, { u"_LostFocus"_ustr, nullptr, ApproveAll, nullptr } },
221 { u"focusLost"_ustr, { u"_Exit"_ustr, nullptr, ApproveType, static_cast<void const *>(&textCompList) } }, // support VBA TextBox_Exit event
223 // adjustmentValueChanged ooo event
224 { u"adjustmentValueChanged"_ustr, { u"_Scroll"_ustr, nullptr, ApproveAll, nullptr } },
225 { u"adjustmentValueChanged"_ustr, { u"_Change"_ustr, nullptr, ApproveAll, nullptr } },
227 // textChanged ooo event
228 { u"textChanged"_ustr, { u"_Change"_ustr, nullptr, ApproveAll, nullptr } },
230 // keyReleased ooo event
231 { u"keyReleased"_ustr, { u"_KeyUp"_ustr, ooKeyPressedToVBAKeyUpDown, ApproveAll, nullptr } },
233 // mouseReleased ooo event
234 { u"mouseReleased"_ustr, { u"_Click"_ustr, ooMouseEvtToVBAMouseEvt, ApproveType, static_cast<void const *>(&fixedTextList) } },
235 { u"mouseReleased"_ustr, { u"_MouseUp"_ustr, ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
237 // mousePressed ooo event
238 { u"mousePressed"_ustr, { u"_MouseDown"_ustr, ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
239 { u"mousePressed"_ustr, { u"_DblClick"_ustr, ooMouseEvtToVBADblClick, ApproveAll, nullptr } },
241 // mouseMoved ooo event
242 { u"mouseMoved"_ustr, { u"_MouseMove"_ustr, ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
243 { u"mouseDragged"_ustr, { u"_MouseMove"_ustr, ooMouseEvtToVBAMouseEvt, DenyMouseDrag, nullptr } },
245 // keyPressed ooo event
246 { u"keyPressed"_ustr, { u"_KeyDown"_ustr, ooKeyPressedToVBAKeyUpDown, ApproveAll, nullptr } },
247 { u"keyPressed"_ustr, { u"_KeyPress"_ustr, ooKeyPressedToVBAKeyPressed, ApproveAll, nullptr } }
250 static EventInfoHash& getEventTransInfo()
252 static EventInfoHash eventTransInfo = []()
254 EventInfoHash tmp;
255 OUString sEventInfo;
256 TranslatePropMap* pTransProp = aTranslatePropMap_Impl;
257 int nCount = SAL_N_ELEMENTS(aTranslatePropMap_Impl);
259 int i = 0;
260 while (i < nCount)
262 sEventInfo = pTransProp->sEventInfo;
263 std::vector< TranslateInfo > infoList;
266 infoList.push_back( pTransProp->aTransInfo );
267 pTransProp++;
268 i++;
269 }while(i < nCount && sEventInfo == pTransProp->sEventInfo);
270 tmp[sEventInfo] = std::move(infoList);
272 return tmp;
273 }();
274 return eventTransInfo;
278 // Helper class
280 namespace {
282 class ScriptEventHelper
284 public:
285 explicit ScriptEventHelper( const Reference< XInterface >& xControl );
286 explicit ScriptEventHelper( const OUString& sCntrlServiceName );
287 ~ScriptEventHelper();
288 Sequence< ScriptEventDescriptor > createEvents( const OUString& sCodeName );
289 Sequence< OUString > getEventListeners() const;
290 private:
291 Reference< XComponentContext > m_xCtx;
292 Reference< XInterface > m_xControl;
293 bool m_bDispose;
298 static bool
299 eventMethodToDescriptor( std::u16string_view rEventMethod, ScriptEventDescriptor& evtDesc, const OUString& sCodeName )
301 // format of ControlListener is TypeName::methodname e.g.
302 // "com.sun.star.awt.XActionListener::actionPerformed" or
303 // "XActionListener::actionPerformed
305 OUString sMethodName;
306 OUString sTypeName;
307 size_t nDelimPos = rEventMethod.find( DELIM );
308 if ( nDelimPos == std::u16string_view::npos )
310 return false;
312 sMethodName = rEventMethod.substr( nDelimPos + DELIMLEN );
313 sTypeName = rEventMethod.substr( 0, nDelimPos );
315 EventInfoHash& infos = getEventTransInfo();
317 // Only create an ScriptEventDescriptor for an event we can translate
318 // or emulate
319 if ( !sMethodName.isEmpty()
320 && !sTypeName.isEmpty()
321 && ( infos.find( sMethodName ) != infos.end() ) )
323 // just fill in CodeName, when the event fires the other
324 // info is gathered from the event source to determine what
325 // event handler we try to call
326 evtDesc.ScriptCode = sCodeName;
327 evtDesc.ListenerType = sTypeName;
328 evtDesc.EventMethod = sMethodName;
330 // set this it VBAInterop, ensures that it doesn't
331 // get persisted or shown in property editors
332 evtDesc.ScriptType = "VBAInterop";
333 return true;
335 return false;
339 ScriptEventHelper::ScriptEventHelper( const Reference< XInterface >& xControl ) :
340 m_xCtx( comphelper::getProcessComponentContext() ),
341 m_xControl( xControl ),
342 m_bDispose( false )
345 ScriptEventHelper::ScriptEventHelper( const OUString& sCntrlServiceName ) :
346 m_xCtx( comphelper::getProcessComponentContext() ),
347 m_bDispose( true )
349 m_xControl.set( m_xCtx->getServiceManager()->createInstanceWithContext( sCntrlServiceName, m_xCtx ), uno::UNO_QUERY );
352 ScriptEventHelper::~ScriptEventHelper()
354 // dispose control ( and remove any associated event registrations )
355 if ( m_bDispose )
359 uno::Reference< lang::XComponent > xComp( m_xControl, uno::UNO_QUERY );
360 if (xComp)
361 xComp->dispose();
363 // destructor can't throw
364 catch( uno::Exception& )
370 Sequence< OUString >
371 ScriptEventHelper::getEventListeners() const
373 std::vector< OUString > eventMethods;
375 Reference< beans::XIntrospection > xIntrospection = beans::theIntrospection::get( m_xCtx );
377 Reference< beans::XIntrospectionAccess > xIntrospectionAccess =
378 xIntrospection->inspect( Any( m_xControl ) );
379 const Sequence< Type > aControlListeners =
380 xIntrospectionAccess->getSupportedListeners();
381 for ( const Type& listType : aControlListeners )
383 OUString sFullTypeName = listType.getTypeName();
384 const Sequence< OUString > sMeths =
385 comphelper::getEventMethodsForType( listType );
386 std::transform(sMeths.begin(), sMeths.end(), std::back_inserter(eventMethods),
387 [&sFullTypeName](const OUString& rMeth) -> OUString { return sFullTypeName + DELIM + rMeth; });
390 return comphelper::containerToSequence(eventMethods);
393 Sequence< ScriptEventDescriptor >
394 ScriptEventHelper::createEvents( const OUString& sCodeName )
396 const Sequence< OUString > aControlListeners = getEventListeners();
397 sal_Int32 nLength = aControlListeners.getLength();
399 Sequence< ScriptEventDescriptor > aDest( nLength );
400 sal_Int32 nEvts = 0;
401 for ( OUString const & i : aControlListeners)
403 // from getListeners eventName is of form
404 // "com.sun.star.awt.XActionListener::actionPerformed"
405 // we need to strip "com.sun.star.awt." from that for form
406 // controls
407 ScriptEventDescriptor evtDesc;
408 if ( eventMethodToDescriptor( i, evtDesc, sCodeName ) )
410 sal_Int32 dIndex = nEvts;
411 ++nEvts;
412 if ( nEvts > aDest.getLength() )
413 aDest.realloc( nEvts );// should never happen
414 aDest.getArray()[ dIndex ] = std::move(evtDesc);
417 aDest.realloc( nEvts );
419 return aDest;
423 typedef ::cppu::WeakImplHelper< container::XNameContainer > NameContainer_BASE;
425 namespace {
427 class ReadOnlyEventsNameContainer : public NameContainer_BASE
429 public:
430 ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName );
431 // XNameContainer
433 virtual void SAL_CALL insertByName( const OUString&, const Any& ) override
435 throw RuntimeException(u"ReadOnly container"_ustr );
438 virtual void SAL_CALL removeByName( const OUString& ) override
440 throw RuntimeException(u"ReadOnly container"_ustr );
443 // XNameReplace
444 virtual void SAL_CALL replaceByName( const OUString&, const Any& ) override
446 throw RuntimeException(u"ReadOnly container"_ustr );
450 // XNameAccess
451 virtual Any SAL_CALL getByName( const OUString& aName ) override;
452 virtual Sequence< OUString > SAL_CALL getElementNames( ) override;
453 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
455 // XElementAccess
456 virtual Type SAL_CALL getElementType( ) override
457 { return cppu::UnoType<OUString>::get(); }
458 virtual sal_Bool SAL_CALL hasElements( ) override
459 { return !m_hEvents.empty(); }
460 private:
462 typedef std::unordered_map< OUString, Any > EventSupplierHash;
464 EventSupplierHash m_hEvents;
469 ReadOnlyEventsNameContainer::ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
471 for ( const OUString& rSrc : eventMethods )
473 Any aDesc;
474 ScriptEventDescriptor evtDesc;
475 if ( eventMethodToDescriptor( rSrc, evtDesc, sCodeName ) )
477 aDesc <<= evtDesc;
478 m_hEvents[ rSrc ] = std::move(aDesc);
483 Any SAL_CALL
484 ReadOnlyEventsNameContainer::getByName( const OUString& aName ){
485 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
486 if ( it == m_hEvents.end() )
487 throw container::NoSuchElementException();
488 return it->second;
491 Sequence< OUString > SAL_CALL
492 ReadOnlyEventsNameContainer::getElementNames( )
494 return comphelper::mapKeysToSequence(m_hEvents);
497 sal_Bool SAL_CALL
498 ReadOnlyEventsNameContainer::hasByName( const OUString& aName )
500 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
501 if ( it == m_hEvents.end() )
502 return false;
503 return true;
506 namespace {
508 class ReadOnlyEventsSupplier : public ::cppu::WeakImplHelper< XScriptEventsSupplier >
510 public:
511 ReadOnlyEventsSupplier( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
512 { m_xNameContainer = new ReadOnlyEventsNameContainer( eventMethods, sCodeName ); }
514 // XScriptEventSupplier
515 virtual Reference< container::XNameContainer > SAL_CALL getEvents( ) override { return m_xNameContainer; }
516 private:
517 rtl::Reference< ReadOnlyEventsNameContainer > m_xNameContainer;
522 typedef ::comphelper::WeakImplHelper< XScriptListener, util::XCloseListener, lang::XInitialization, css::lang::XServiceInfo > EventListener_BASE;
524 #define EVENTLSTNR_PROPERTY_ID_MODEL 1
525 constexpr OUStringLiteral EVENTLSTNR_PROPERTY_MODEL = u"Model";
527 namespace {
529 class EventListener : public EventListener_BASE
530 ,public ::comphelper::OPropertyContainer2
531 ,public ::comphelper::OPropertyArrayUsageHelper< EventListener >
534 public:
535 EventListener();
536 // XEventListener
537 virtual void SAL_CALL disposing(const lang::EventObject& Source) override;
538 using comphelper::OPropertySetHelper::disposing;
540 // XScriptListener
541 virtual void SAL_CALL firing(const ScriptEvent& evt) override;
542 virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) override;
543 // XCloseListener
544 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) override;
545 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) override;
546 // XPropertySet
547 virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
548 // XInitialization
549 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
550 // XInterface
551 DECLARE_XINTERFACE()
553 // XTypeProvider
554 DECLARE_XTYPEPROVIDER()
555 virtual void setFastPropertyValueImpl( std::unique_lock<std::mutex>& rGuard, sal_Int32 nHandle, const css::uno::Any& rValue ) override
557 if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
559 uno::Reference< frame::XModel > xModel( rValue, uno::UNO_QUERY );
560 if( xModel != m_xModel)
562 // Remove the listener from the old XCloseBroadcaster.
563 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
564 if (xCloseBroadcaster.is())
566 xCloseBroadcaster->removeCloseListener( this );
568 // Add the listener into the new XCloseBroadcaster.
569 xCloseBroadcaster.set( xModel, uno::UNO_QUERY );
570 if (xCloseBroadcaster.is())
572 xCloseBroadcaster->addCloseListener( this );
576 OPropertyContainer2::setFastPropertyValueImpl( rGuard, nHandle, rValue );
577 if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL )
578 setShellFromModel();
581 OUString SAL_CALL getImplementationName() override
583 return u"ooo.vba.EventListener"_ustr;
586 sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
588 return cppu::supportsService(this, ServiceName);
591 css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
593 return { getImplementationName() };
596 protected:
597 // OPropertySetHelper
598 virtual ::cppu::IPropertyArrayHelper& getInfoHelper( ) override;
600 // OPropertyArrayUsageHelper
601 virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
603 private:
604 void setShellFromModel();
605 /// @throws RuntimeException
606 void firing_Impl( const ScriptEvent& evt, Any *pSyncRet );
608 Reference< frame::XModel > m_xModel;
609 bool m_bDocClosed;
610 SfxObjectShell* mpShell;
615 EventListener::EventListener() :
616 m_bDocClosed(false), mpShell( nullptr )
618 registerProperty( EVENTLSTNR_PROPERTY_MODEL, EVENTLSTNR_PROPERTY_ID_MODEL,
619 beans::PropertyAttribute::TRANSIENT, &m_xModel, cppu::UnoType<decltype(m_xModel)>::get() );
622 void
623 EventListener::setShellFromModel()
625 // reset mpShell
626 mpShell = nullptr;
627 SfxObjectShell* pShell = SfxObjectShell::GetFirst();
628 while ( m_xModel.is() && pShell )
630 if ( pShell->GetModel() == m_xModel )
632 mpShell = pShell;
633 break;
635 pShell = SfxObjectShell::GetNext( *pShell );
639 //XEventListener
640 void
641 EventListener::disposing(const lang::EventObject&)
645 //XScriptListener
647 void SAL_CALL
648 EventListener::firing(const ScriptEvent& evt)
650 firing_Impl( evt, nullptr );
653 Any SAL_CALL
654 EventListener::approveFiring(const ScriptEvent& evt)
656 Any ret;
657 firing_Impl( evt, &ret );
658 return ret;
661 // XCloseListener
662 void SAL_CALL
663 EventListener::queryClosing( const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ )
665 //Nothing to do
668 void SAL_CALL
669 EventListener::notifyClosing( const lang::EventObject& /*Source*/ )
671 m_bDocClosed = true;
672 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
673 if (xCloseBroadcaster.is())
675 xCloseBroadcaster->removeCloseListener( this );
679 // XInitialization
680 void SAL_CALL
681 EventListener::initialize( const Sequence< Any >& aArguments )
683 if ( aArguments.getLength() == 1 )
684 aArguments[0] >>= m_xModel;
685 SAL_INFO(
686 "scripting",
687 "args " << aArguments.getLength() << " m_xModel " << m_xModel.is());
690 // XInterface
692 IMPLEMENT_FORWARD_XINTERFACE2( EventListener, EventListener_BASE, comphelper::OPropertyContainer2 )
694 // XTypeProvider
696 IMPLEMENT_FORWARD_XTYPEPROVIDER2( EventListener, EventListener_BASE, comphelper::OPropertyContainer2 )
698 // OPropertySetHelper
700 ::cppu::IPropertyArrayHelper&
701 EventListener::getInfoHelper( )
703 return *getArrayHelper();
706 // OPropertyArrayUsageHelper
708 ::cppu::IPropertyArrayHelper*
709 EventListener::createArrayHelper( ) const
711 Sequence< beans::Property > aProps;
712 describeProperties( aProps );
713 return new ::cppu::OPropertyArrayHelper( aProps );
716 // XPropertySet
717 Reference< beans::XPropertySetInfo >
718 EventListener::getPropertySetInfo( )
720 Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
721 return xInfo;
725 //decide if the control should execute the event
726 bool ApproveAll(SAL_UNUSED_PARAMETER const ScriptEvent&, SAL_UNUSED_PARAMETER void const * )
728 return true;
731 //for the given control type in evt.Arguments[0], look for if it appears in the type list in pPara
732 static bool FindControl(const ScriptEvent& evt, void const * pPara)
734 lang::EventObject aEvent;
735 evt.Arguments[ 0 ] >>= aEvent;
736 uno::Reference< uno::XInterface > xInterface( aEvent.Source, uno::UNO_QUERY );
738 TypeList const * pTypeListInfo = static_cast<TypeList const *>(pPara);
739 Type const * pType = pTypeListInfo->pTypeList;
740 int nLen = pTypeListInfo->nListLength;
742 for (int i = 0; i < nLen; i++)
744 if ( xInterface->queryInterface( *pType ).hasValue() )
746 return true;
748 pType++;
751 return false;
754 //if the given control type in evt.Arguments[0] appears in the type list in pPara, then approve the execution
755 bool ApproveType(const ScriptEvent& evt, void const * pPara)
757 return FindControl(evt, pPara);
760 //if the given control type in evt.Arguments[0] appears in the type list in pPara, then deny the execution
761 bool DenyType(const ScriptEvent& evt, void const * pPara)
763 return !FindControl(evt, pPara);
766 //when mouse is moving, either the mouse button is pressed or some key is pressed can trigger the OO mouseDragged event,
767 //the former should be denied, and the latter allowed, only by doing so can the VBA MouseMove event when the "Shift" key is
768 //pressed can be correctly triggered
769 bool DenyMouseDrag(const ScriptEvent& evt, SAL_UNUSED_PARAMETER void const * )
771 awt::MouseEvent aEvent;
772 evt.Arguments[ 0 ] >>= aEvent;
773 return aEvent.Buttons == 0;
777 // EventListener
779 void
780 EventListener::firing_Impl(const ScriptEvent& evt, Any* pRet )
782 // let default handlers deal with non vba stuff
783 if ( evt.ScriptType != "VBAInterop" )
784 return;
785 lang::EventObject aEvent;
786 evt.Arguments[ 0 ] >>= aEvent;
787 OUString sName = u"UserForm"_ustr;
789 uno::Reference< awt::XDialog > xDlg( aEvent.Source, uno::UNO_QUERY );
790 if ( !xDlg.is() )
792 // evt.Source is
793 // a) Dialog
794 // b) xShapeControl ( from api (sheet control) )
795 // c) eventmanager ( I guess )
796 // d) vba control ( from api also )
797 uno::Reference< drawing::XControlShape > xCntrlShape( evt.Source, uno::UNO_QUERY );
798 uno::Reference< awt::XControl > xControl( aEvent.Source, uno::UNO_QUERY );
799 if ( xCntrlShape.is() )
801 // for sheet controls ( that fire from the api ) we don't
802 // have the real control ( that's only available from the view )
803 // api code creates just a control instance that is transferred
804 // via aEvent.Arguments[ 0 ] that control though has no
805 // info like name etc.
806 uno::Reference< container::XNamed > xName( xCntrlShape->getControl(), uno::UNO_QUERY_THROW );
807 sName = xName->getName();
809 else
811 // Userform control ( fired from the api or from event manager )
812 uno::Reference< beans::XPropertySet > xProps;
813 xProps.set( xControl->getModel(), uno::UNO_QUERY_THROW );
814 xProps->getPropertyValue(u"Name"_ustr) >>= sName;
817 //dumpEvent( evt );
818 EventInfoHash& infos = getEventTransInfo();
819 EventInfoHash::const_iterator eventInfo_it = infos.find( evt.MethodName );
820 EventInfoHash::const_iterator it_end = infos.end();
821 if ( eventInfo_it == it_end )
823 SAL_WARN("scripting", "Bogus event for " << evt.ScriptType );
824 return;
827 uno::Reference< script::provider::XScriptProviderSupplier > xSPS( m_xModel, uno::UNO_QUERY );
828 uno::Reference< script::provider::XScriptProvider > xScriptProvider;
829 if ( xSPS.is() )
831 xScriptProvider = xSPS->getScriptProvider();
833 if ( !(xScriptProvider.is() && mpShell) )
834 return;
836 BasicManager* pBasicManager = mpShell->GetBasicManager();
837 OUString sProject;
838 OUString sScriptCode( evt.ScriptCode );
839 // dialogs pass their own library, presence of Dot determines that
840 if ( sScriptCode.indexOf( '.' ) == -1 )
842 //'Project' is a better default but I want to force failures
843 //OUString sMacroLoc("Project");
844 sProject = "Standard";
846 if (!pBasicManager->GetName().isEmpty())
848 sProject = pBasicManager->GetName();
851 else
853 sal_Int32 nIndex = sScriptCode.indexOf( '.' );
854 sProject = sScriptCode.copy( 0, nIndex );
855 sScriptCode = sScriptCode.copy( nIndex + 1 );
857 OUString sMacroLoc = sProject + "." + sScriptCode + ".";
859 for (const auto& rTxInfo : eventInfo_it->second)
861 // If the document is closed, we should not execute macro.
862 if (m_bDocClosed)
864 break;
867 // see if we have a match for the handlerextension
868 // where ScriptCode is methodname_handlerextension
869 OUString sToResolve = sMacroLoc + sName + rTxInfo.sVBAName;
871 ooo::vba::MacroResolvedInfo aMacroResolvedInfo = ooo::vba::resolveVBAMacro( mpShell, sToResolve );
872 if ( aMacroResolvedInfo.mbFound )
875 if (! rTxInfo.ApproveRule(evt, rTxInfo.pPara) )
877 continue;
880 // !! translate arguments & emulate events where necessary
881 Sequence< Any > aArguments;
882 if ( rTxInfo.toVBA )
884 aArguments = rTxInfo.toVBA( evt.Arguments );
886 else
888 aArguments = evt.Arguments;
890 if ( aArguments.hasElements() )
892 // call basic event handlers for event
894 // create script url
895 OUString url = aMacroResolvedInfo.msResolvedMacro;
898 uno::Any aDummyCaller( u"Error"_ustr );
899 if ( pRet )
901 ooo::vba::executeMacro( mpShell, url, aArguments, *pRet, aDummyCaller );
903 else
905 uno::Any aRet;
906 ooo::vba::executeMacro( mpShell, url, aArguments, aRet, aDummyCaller );
909 catch ( const uno::Exception& )
911 TOOLS_WARN_EXCEPTION("scripting", "event script raised" );
918 namespace {
920 class VBAToOOEventDescGen : public ::cppu::WeakImplHelper< XVBAToOOEventDescGen, css::lang::XServiceInfo >
922 public:
923 VBAToOOEventDescGen();
925 // XVBAToOOEventDescGen
926 virtual Sequence< ScriptEventDescriptor > SAL_CALL getEventDescriptions( const OUString& sCtrlServiceName, const OUString& sCodeName ) override;
927 virtual Reference< XScriptEventsSupplier > SAL_CALL getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName ) override;
929 OUString SAL_CALL getImplementationName() override
931 return u"ooo.vba.VBAToOOEventDesc"_ustr;
934 sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
936 return cppu::supportsService(this, ServiceName);
939 css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
941 return { getImplementationName() };
948 VBAToOOEventDescGen::VBAToOOEventDescGen() {}
950 Sequence< ScriptEventDescriptor > SAL_CALL
951 VBAToOOEventDescGen::getEventDescriptions( const OUString& sCntrlServiceName, const OUString& sCodeName )
953 ScriptEventHelper evntHelper( sCntrlServiceName );
954 return evntHelper.createEvents( sCodeName );
957 Reference< XScriptEventsSupplier > SAL_CALL
958 VBAToOOEventDescGen::getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName )
960 ScriptEventHelper evntHelper( xControl );
961 Reference< XScriptEventsSupplier > xSupplier =
962 new ReadOnlyEventsSupplier(
963 evntHelper.getEventListeners(), sCodeName ) ;
964 return xSupplier;
967 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
968 ooo_vba_EventListener_get_implementation(css::uno::XComponentContext*,
969 css::uno::Sequence<css::uno::Any> const &)
971 return cppu::acquire(new EventListener);
975 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
976 ooo_vba_VBAToOOEventDesc_get_implementation(css::uno::XComponentContext*,
977 css::uno::Sequence<css::uno::Any> const &)
979 return cppu::acquire(new VBAToOOEventDescGen);
983 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */