LibreOffice Module scripting (master) 1
eventhelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/macros.h>
21#include <sal/log.hxx>
23#include <comphelper/uno3.hxx>
27
28#include <ooo/vba/XVBAToOOEventDescGen.hpp>
29
30#include <com/sun/star/beans/XPropertySet.hpp>
31#include <com/sun/star/beans/theIntrospection.hpp>
32#include <com/sun/star/beans/PropertyAttribute.hpp>
33
34#include <com/sun/star/lang/XMultiComponentFactory.hpp>
35#include <com/sun/star/lang/XServiceInfo.hpp>
36#include <com/sun/star/lang/XInitialization.hpp>
37
38#include <com/sun/star/util/XCloseListener.hpp>
39#include <com/sun/star/util/XCloseBroadcaster.hpp>
40
41#include <com/sun/star/frame/XModel.hpp>
42
43#include <com/sun/star/script/ScriptEventDescriptor.hpp>
44#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
45
46#include <com/sun/star/container/XNamed.hpp>
47
48#include <com/sun/star/drawing/XControlShape.hpp>
49
50#include <com/sun/star/awt/XControl.hpp>
51#include <com/sun/star/awt/XDialog.hpp>
52#include <com/sun/star/awt/KeyEvent.hpp>
53#include <com/sun/star/awt/MouseEvent.hpp>
54#include <com/sun/star/awt/XFixedText.hpp>
55#include <com/sun/star/awt/XTextComponent.hpp>
56#include <com/sun/star/awt/XComboBox.hpp>
57#include <com/sun/star/awt/XRadioButton.hpp>
58#include <com/sun/star/awt/XListBox.hpp>
59
60#include <sfx2/objsh.hxx>
61#include <basic/basmgr.hxx>
64
65#include <com/sun/star/script/XScriptListener.hpp>
69
70#include <vector>
71#include <unordered_map>
72
73using namespace ::com::sun::star;
74using namespace ::com::sun::star::script;
75using namespace ::com::sun::star::uno;
76using namespace ::ooo::vba;
77
78// Some constants
79constexpr std::u16string_view DELIM = u"::";
80constexpr sal_Int32 DELIMLEN = DELIM.size();
81
82static bool isKeyEventOk( awt::KeyEvent& evt, const Sequence< Any >& params )
83{
84 return params.hasElements() && ( params[ 0 ] >>= evt );
85}
86
87static bool isMouseEventOk( awt::MouseEvent& evt, const Sequence< Any >& params )
88{
89 return params.hasElements() && ( params[ 0 ] >>= evt );
90}
91
92static Sequence< Any > ooMouseEvtToVBADblClick( const Sequence< Any >& params )
93{
94 awt::MouseEvent evt;
95
96 if ( !( isMouseEventOk(evt, params)) ||
97 (evt.ClickCount != 2) )
98 return Sequence< Any >();
99 // give back orig params, this will signal that the event is good
100 return params;
101}
102
103static Sequence< Any > ooMouseEvtToVBAMouseEvt( const Sequence< Any >& params )
104{
105 awt::MouseEvent evt;
106
107 if ( !isMouseEventOk(evt, params) )
108 return Sequence< Any >();
109
110 Sequence< Any > translatedParams{ Any(evt.Buttons), // Buttons
111 Any(evt.Modifiers), // Shift
112 Any(evt.X), // X
113 Any(evt.Y) }; // Y
114 return translatedParams;
115}
116
117static Sequence< Any > ooKeyPressedToVBAKeyPressed( const Sequence< Any >& params )
118{
119 awt::KeyEvent evt;
120
121 if ( !isKeyEventOk( evt, params ) )
122 return Sequence< Any >();
123
124 Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( sal_Int32( evt.KeyCode ) );
125 Sequence< Any > translatedParams{ Any(xKeyCode) };
126 return translatedParams;
127}
128
129static Sequence< Any > ooKeyPressedToVBAKeyUpDown( const Sequence< Any >& params )
130{
131 awt::KeyEvent evt;
132
133 if ( !isKeyEventOk( evt, params ) )
134 return Sequence< Any >();
135
136 Reference< msforms::XReturnInteger> xKeyCode = new ReturnInteger( evt.KeyCode );
137 sal_Int8 shift = sal::static_int_cast<sal_Int8>( evt.Modifiers );
138
139 // #TODO check whether values from OOO conform to values generated from vba
140 Sequence< Any > translatedParams{ Any(xKeyCode), Any(shift) };
141 return translatedParams;
142}
143
144typedef Sequence< Any > (*Translator)(const Sequence< Any >&);
145
146namespace {
147
148//expand the "TranslateInfo" struct to support more kinds of events
149struct TranslateInfo
150{
151 OUString sVBAName; //vba event name
152 Translator toVBA; //the method to convert OO event parameters to VBA event parameters
153 bool (*ApproveRule)(const ScriptEvent& evt, void const * pPara); //this method is used to determine which types of controls should execute the event
154 void const *pPara; //Parameters for the above approve method
155};
156
157}
158
159typedef std::unordered_map<
160 OUString,
161 std::vector< TranslateInfo > > EventInfoHash;
162
163namespace {
164
165struct TranslatePropMap
166{
167 OUString sEventInfo; //OO event name
168 TranslateInfo aTransInfo;
169};
170
171}
172
173static bool ApproveAll(const ScriptEvent& evt, void const * pPara); //allow all types of controls to execute the event
174static bool ApproveType(const ScriptEvent& evt, void const * pPara); //certain types of controls should execute the event, those types are given by pPara
175static bool DenyType(const ScriptEvent& evt, void const * pPara); //certain types of controls should not execute the event, those types are given by pPara
176static bool DenyMouseDrag(const ScriptEvent& evt, void const * pPara); //used for VBA MouseMove event when "Shift" key is pressed
177
178namespace {
179
180struct TypeList
181{
182 uno::Type const * pTypeList;
183 int nListLength;
184};
185
186}
187
193
194
195TypeList const fixedTextList = {&typeXFixedText, 1};
196TypeList const textCompList = {&typeXTextComponent, 1};
197TypeList const radioButtonList = {&typeXRadioButton, 1};
198TypeList const comboBoxList = {&typeXComboBox, 1};
199TypeList const listBoxList = {&typeXListBox, 1};
200
201//this array stores the OO event to VBA event translation info
202static TranslatePropMap aTranslatePropMap_Impl[] =
203{
204 { OUString("actionPerformed"), { OUString("_Change"), nullptr, DenyType, static_cast<void const *>(&radioButtonList) } },
205 // actionPerformed ooo event
206 { OUString("actionPerformed"), { OUString("_Click"), nullptr, ApproveAll, nullptr } },
207 { OUString("itemStateChanged"), { OUString("_Change"), nullptr, ApproveType, static_cast<void const *>(&radioButtonList) } },
208 // itemStateChanged ooo event
209 { OUString("itemStateChanged"), { OUString("_Click"), nullptr, ApproveType, static_cast<void const *>(&comboBoxList) } },
210
211 { OUString("itemStateChanged"), { OUString("_Click"), nullptr, ApproveType, static_cast<void const *>(&listBoxList) } },
212 // changed ooo event
213 { OUString("changed"), { OUString("_Change"), nullptr, ApproveAll, nullptr } },
214
215 // focusGained ooo event
216 { OUString("focusGained"), { OUString("_GotFocus"), nullptr, ApproveAll, nullptr } },
217
218 // focusLost ooo event
219 { OUString("focusLost"), { OUString("_LostFocus"), nullptr, ApproveAll, nullptr } },
220 { OUString("focusLost"), { OUString("_Exit"), nullptr, ApproveType, static_cast<void const *>(&textCompList) } }, // support VBA TextBox_Exit event
221
222 // adjustmentValueChanged ooo event
223 { OUString("adjustmentValueChanged"), { OUString("_Scroll"), nullptr, ApproveAll, nullptr } },
224 { OUString("adjustmentValueChanged"), { OUString("_Change"), nullptr, ApproveAll, nullptr } },
225
226 // textChanged ooo event
227 { OUString("textChanged"), { OUString("_Change"), nullptr, ApproveAll, nullptr } },
228
229 // keyReleased ooo event
230 { OUString("keyReleased"), { OUString("_KeyUp"), ooKeyPressedToVBAKeyUpDown, ApproveAll, nullptr } },
231
232 // mouseReleased ooo event
233 { OUString("mouseReleased"), { OUString("_Click"), ooMouseEvtToVBAMouseEvt, ApproveType, static_cast<void const *>(&fixedTextList) } },
234 { OUString("mouseReleased"), { OUString("_MouseUp"), ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
235
236 // mousePressed ooo event
237 { OUString("mousePressed"), { OUString("_MouseDown"), ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
238 { OUString("mousePressed"), { OUString("_DblClick"), ooMouseEvtToVBADblClick, ApproveAll, nullptr } },
239
240 // mouseMoved ooo event
241 { OUString("mouseMoved"), { OUString("_MouseMove"), ooMouseEvtToVBAMouseEvt, ApproveAll, nullptr } },
242 { OUString("mouseDragged"), { OUString("_MouseMove"), ooMouseEvtToVBAMouseEvt, DenyMouseDrag, nullptr } },
243
244 // keyPressed ooo event
245 { OUString("keyPressed"), { OUString("_KeyDown"), ooKeyPressedToVBAKeyUpDown, ApproveAll, nullptr } },
246 { OUString("keyPressed"), { OUString("_KeyPress"), ooKeyPressedToVBAKeyPressed, ApproveAll, nullptr } }
247};
248
250{
251 static EventInfoHash eventTransInfo = []()
252 {
253 EventInfoHash tmp;
254 OUString sEventInfo;
255 TranslatePropMap* pTransProp = aTranslatePropMap_Impl;
257
258 int i = 0;
259 while (i < nCount)
260 {
261 sEventInfo = pTransProp->sEventInfo;
262 std::vector< TranslateInfo > infoList;
263 do
264 {
265 infoList.push_back( pTransProp->aTransInfo );
266 pTransProp++;
267 i++;
268 }while(i < nCount && sEventInfo == pTransProp->sEventInfo);
269 tmp[sEventInfo] = std::move(infoList);
270 }
271 return tmp;
272 }();
273 return eventTransInfo;
274}
275
276
277// Helper class
278
279namespace {
280
281class ScriptEventHelper
282{
283public:
284 explicit ScriptEventHelper( const Reference< XInterface >& xControl );
285 explicit ScriptEventHelper( const OUString& sCntrlServiceName );
286 ~ScriptEventHelper();
287 Sequence< ScriptEventDescriptor > createEvents( const OUString& sCodeName );
288 Sequence< OUString > getEventListeners() const;
289private:
290 Reference< XComponentContext > m_xCtx;
291 Reference< XInterface > m_xControl;
292 bool m_bDispose;
293};
294
295}
296
297static bool
298eventMethodToDescriptor( std::u16string_view rEventMethod, ScriptEventDescriptor& evtDesc, const OUString& sCodeName )
299{
300 // format of ControlListener is TypeName::methodname e.g.
301 // "com.sun.star.awt.XActionListener::actionPerformed" or
302 // "XActionListener::actionPerformed
303
304 OUString sMethodName;
305 OUString sTypeName;
306 size_t nDelimPos = rEventMethod.find( DELIM );
307 if ( nDelimPos == std::u16string_view::npos )
308 {
309 return false;
310 }
311 sMethodName = rEventMethod.substr( nDelimPos + DELIMLEN );
312 sTypeName = rEventMethod.substr( 0, nDelimPos );
313
315
316 // Only create an ScriptEventDescriptor for an event we can translate
317 // or emulate
318 if ( !sMethodName.isEmpty()
319 && !sTypeName.isEmpty()
320 && ( infos.find( sMethodName ) != infos.end() ) )
321 {
322 // just fill in CodeName, when the event fires the other
323 // info is gathered from the event source to determine what
324 // event handler we try to call
325 evtDesc.ScriptCode = sCodeName;
326 evtDesc.ListenerType = sTypeName;
327 evtDesc.EventMethod = sMethodName;
328
329 // set this it VBAInterop, ensures that it doesn't
330 // get persisted or shown in property editors
331 evtDesc.ScriptType = "VBAInterop";
332 return true;
333 }
334 return false;
335
336}
337
338ScriptEventHelper::ScriptEventHelper( const Reference< XInterface >& xControl ) :
340 m_xControl( xControl ),
341 m_bDispose( false )
342{}
343
344ScriptEventHelper::ScriptEventHelper( const OUString& sCntrlServiceName ) :
346 m_bDispose( true )
347{
348 m_xControl.set( m_xCtx->getServiceManager()->createInstanceWithContext( sCntrlServiceName, m_xCtx ), uno::UNO_QUERY );
349}
350
351ScriptEventHelper::~ScriptEventHelper()
352{
353 // dispose control ( and remove any associated event registrations )
354 if ( m_bDispose )
355 {
356 try
357 {
358 uno::Reference< lang::XComponent > xComp( m_xControl, uno::UNO_QUERY_THROW );
359 xComp->dispose();
360 }
361 // destructor can't throw
362 catch( uno::Exception& )
363 {
364 }
365 }
366}
367
369ScriptEventHelper::getEventListeners() const
370{
371 std::vector< OUString > eventMethods;
372
373 Reference< beans::XIntrospection > xIntrospection = beans::theIntrospection::get( m_xCtx );
374
375 Reference< beans::XIntrospectionAccess > xIntrospectionAccess =
376 xIntrospection->inspect( Any( m_xControl ) );
377 const Sequence< Type > aControlListeners =
378 xIntrospectionAccess->getSupportedListeners();
379 for ( const Type& listType : aControlListeners )
380 {
381 OUString sFullTypeName = listType.getTypeName();
382 const Sequence< OUString > sMeths =
384 std::transform(sMeths.begin(), sMeths.end(), std::back_inserter(eventMethods),
385 [&sFullTypeName](const OUString& rMeth) -> OUString { return sFullTypeName + DELIM + rMeth; });
386 }
387
388 return comphelper::containerToSequence(eventMethods);
389}
390
391Sequence< ScriptEventDescriptor >
392ScriptEventHelper::createEvents( const OUString& sCodeName )
393{
394 const Sequence< OUString > aControlListeners = getEventListeners();
395 sal_Int32 nLength = aControlListeners.getLength();
396
397 Sequence< ScriptEventDescriptor > aDest( nLength );
398 sal_Int32 nEvts = 0;
399 for ( OUString const & i : aControlListeners)
400 {
401 // from getListeners eventName is of form
402 // "com.sun.star.awt.XActionListener::actionPerformed"
403 // we need to strip "com.sun.star.awt." from that for form
404 // controls
405 ScriptEventDescriptor evtDesc;
406 if ( eventMethodToDescriptor( i, evtDesc, sCodeName ) )
407 {
408 sal_Int32 dIndex = nEvts;
409 ++nEvts;
410 if ( nEvts > aDest.getLength() )
411 aDest.realloc( nEvts );// should never happen
412 aDest.getArray()[ dIndex ] = evtDesc;
413 }
414 }
415 aDest.realloc( nEvts );
416
417 return aDest;
418}
419
420
421typedef ::cppu::WeakImplHelper< container::XNameContainer > NameContainer_BASE;
422
423namespace {
424
425class ReadOnlyEventsNameContainer : public NameContainer_BASE
426{
427public:
428 ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName );
429 // XNameContainer
430
431 virtual void SAL_CALL insertByName( const OUString&, const Any& ) override
432 {
433 throw RuntimeException("ReadOnly container" );
434
435 }
436 virtual void SAL_CALL removeByName( const OUString& ) override
437 {
438 throw RuntimeException("ReadOnly container" );
439 }
440
441 // XNameReplace
442 virtual void SAL_CALL replaceByName( const OUString&, const Any& ) override
443 {
444 throw RuntimeException("ReadOnly container" );
445
446 }
447
448 // XNameAccess
449 virtual Any SAL_CALL getByName( const OUString& aName ) override;
450 virtual Sequence< OUString > SAL_CALL getElementNames( ) override;
451 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
452
453 // XElementAccess
454 virtual Type SAL_CALL getElementType( ) override
455 { return cppu::UnoType<OUString>::get(); }
456 virtual sal_Bool SAL_CALL hasElements( ) override
457 { return !m_hEvents.empty(); }
458private:
459
460typedef std::unordered_map< OUString, Any > EventSupplierHash;
461
462 EventSupplierHash m_hEvents;
463};
464
465}
466
467ReadOnlyEventsNameContainer::ReadOnlyEventsNameContainer( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
468{
469 for ( const OUString& rSrc : eventMethods )
470 {
471 Any aDesc;
472 ScriptEventDescriptor evtDesc;
473 if ( eventMethodToDescriptor( rSrc, evtDesc, sCodeName ) )
474 {
475 aDesc <<= evtDesc;
476 m_hEvents[ rSrc ] = aDesc;
477 }
478 }
479}
480
481Any SAL_CALL
482ReadOnlyEventsNameContainer::getByName( const OUString& aName ){
483 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
484 if ( it == m_hEvents.end() )
485 throw container::NoSuchElementException();
486 return it->second;
487}
488
490ReadOnlyEventsNameContainer::getElementNames( )
491{
492 return comphelper::mapKeysToSequence(m_hEvents);
493}
494
495sal_Bool SAL_CALL
496ReadOnlyEventsNameContainer::hasByName( const OUString& aName )
497{
498 EventSupplierHash::const_iterator it = m_hEvents.find( aName );
499 if ( it == m_hEvents.end() )
500 return false;
501 return true;
502}
503
504namespace {
505
506class ReadOnlyEventsSupplier : public ::cppu::WeakImplHelper< XScriptEventsSupplier >
507{
508public:
509 ReadOnlyEventsSupplier( const Sequence< OUString >& eventMethods, const OUString& sCodeName )
510 { m_xNameContainer = new ReadOnlyEventsNameContainer( eventMethods, sCodeName ); }
511
512 // XScriptEventSupplier
513 virtual Reference< container::XNameContainer > SAL_CALL getEvents( ) override { return m_xNameContainer; }
514private:
516};
517
518}
519
520typedef ::cppu::WeakImplHelper< XScriptListener, util::XCloseListener, lang::XInitialization, css::lang::XServiceInfo > EventListener_BASE;
521
522#define EVENTLSTNR_PROPERTY_ID_MODEL 1
523constexpr OUStringLiteral EVENTLSTNR_PROPERTY_MODEL = u"Model";
524
525namespace {
526
527class EventListener : public EventListener_BASE
530 ,public ::comphelper::OPropertyArrayUsageHelper< EventListener >
531{
532
533public:
534 EventListener();
535 // XEventListener
536 virtual void SAL_CALL disposing(const lang::EventObject& Source) override;
538
539 // XScriptListener
540 virtual void SAL_CALL firing(const ScriptEvent& evt) override;
541 virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) override;
542 // XCloseListener
543 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) override;
544 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) override;
545 // XPropertySet
546 virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
547 // XInitialization
548 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
549 // XInterface
551
552 // XTypeProvider
554 virtual void SAL_CALL setFastPropertyValue( sal_Int32 nHandle, const css::uno::Any& rValue ) override
555 {
557 {
558 uno::Reference< frame::XModel > xModel( rValue, uno::UNO_QUERY );
559 if( xModel != m_xModel)
560 {
561 // Remove the listener from the old XCloseBroadcaster.
562 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
563 if (xCloseBroadcaster.is())
564 {
565 xCloseBroadcaster->removeCloseListener( this );
566 }
567 // Add the listener into the new XCloseBroadcaster.
568 xCloseBroadcaster.set( xModel, uno::UNO_QUERY );
569 if (xCloseBroadcaster.is())
570 {
571 xCloseBroadcaster->addCloseListener( this );
572 }
573 }
574 }
577 setShellFromModel();
578 }
579
580 OUString SAL_CALL getImplementationName() override
581 {
582 return "ooo.vba.EventListener";
583 }
584
585 sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
586 {
588 }
589
590 css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
591 {
592 return { getImplementationName() };
593 }
594
595protected:
596 // OPropertySetHelper
597 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper( ) override;
598
599 // OPropertyArrayUsageHelper
600 virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
601
602private:
603 void setShellFromModel();
605 void firing_Impl( const ScriptEvent& evt, Any *pSyncRet );
606
608 bool m_bDocClosed;
609 SfxObjectShell* mpShell;
610};
611
612}
613
614EventListener::EventListener() :
615OPropertyContainer(GetBroadcastHelper()), m_bDocClosed(false), mpShell( nullptr )
616{
618 beans::PropertyAttribute::TRANSIENT, &m_xModel, cppu::UnoType<decltype(m_xModel)>::get() );
619}
620
621void
622EventListener::setShellFromModel()
623{
624 // reset mpShell
625 mpShell = nullptr;
627 while ( m_xModel.is() && pShell )
628 {
629 if ( pShell->GetModel() == m_xModel )
630 {
631 mpShell = pShell;
632 break;
633 }
634 pShell = SfxObjectShell::GetNext( *pShell );
635 }
636}
637
638//XEventListener
639void
640EventListener::disposing(const lang::EventObject&)
641{
642}
643
644//XScriptListener
645
646void SAL_CALL
647EventListener::firing(const ScriptEvent& evt)
648{
649 firing_Impl( evt, nullptr );
650}
651
652Any SAL_CALL
653EventListener::approveFiring(const ScriptEvent& evt)
654{
655 Any ret;
656 firing_Impl( evt, &ret );
657 return ret;
658}
659
660// XCloseListener
661void SAL_CALL
662EventListener::queryClosing( const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ )
663{
664 //Nothing to do
665}
666
667void SAL_CALL
668EventListener::notifyClosing( const lang::EventObject& /*Source*/ )
669{
670 m_bDocClosed = true;
671 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
672 if (xCloseBroadcaster.is())
673 {
674 xCloseBroadcaster->removeCloseListener( this );
675 }
676}
677
678// XInitialization
679void SAL_CALL
680EventListener::initialize( const Sequence< Any >& aArguments )
681{
682 if ( aArguments.getLength() == 1 )
683 aArguments[0] >>= m_xModel;
684 SAL_INFO(
685 "scripting",
686 "args " << aArguments.getLength() << " m_xModel " << m_xModel.is());
687}
688
689// XInterface
690
691IMPLEMENT_FORWARD_XINTERFACE2( EventListener, EventListener_BASE, OPropertyContainer )
692
693// XTypeProvider
694
695IMPLEMENT_FORWARD_XTYPEPROVIDER2( EventListener, EventListener_BASE, OPropertyContainer )
696
697// OPropertySetHelper
698
699::cppu::IPropertyArrayHelper&
700EventListener::getInfoHelper( )
701{
702 return *getArrayHelper();
703}
704
705// OPropertyArrayUsageHelper
706
708EventListener::createArrayHelper( ) const
709{
711 describeProperties( aProps );
712 return new ::cppu::OPropertyArrayHelper( aProps );
713}
714
715// XPropertySet
717EventListener::getPropertySetInfo( )
718{
719 Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
720 return xInfo;
721}
722
723
724//decide if the control should execute the event
725bool ApproveAll(SAL_UNUSED_PARAMETER const ScriptEvent&, SAL_UNUSED_PARAMETER void const * )
726{
727 return true;
728}
729
730//for the given control type in evt.Arguments[0], look for if it appears in the type list in pPara
731static bool FindControl(const ScriptEvent& evt, void const * pPara)
732{
733 lang::EventObject aEvent;
734 evt.Arguments[ 0 ] >>= aEvent;
735 uno::Reference< uno::XInterface > xInterface( aEvent.Source, uno::UNO_QUERY );
736
737 TypeList const * pTypeListInfo = static_cast<TypeList const *>(pPara);
738 Type const * pType = pTypeListInfo->pTypeList;
739 int nLen = pTypeListInfo->nListLength;
740
741 for (int i = 0; i < nLen; i++)
742 {
743 if ( xInterface->queryInterface( *pType ).hasValue() )
744 {
745 return true;
746 }
747 pType++;
748 }
749
750 return false;
751}
752
753//if the given control type in evt.Arguments[0] appears in the type list in pPara, then approve the execution
754bool ApproveType(const ScriptEvent& evt, void const * pPara)
755{
756 return FindControl(evt, pPara);
757}
758
759//if the given control type in evt.Arguments[0] appears in the type list in pPara, then deny the execution
760bool DenyType(const ScriptEvent& evt, void const * pPara)
761{
762 return !FindControl(evt, pPara);
763}
764
765//when mouse is moving, either the mouse button is pressed or some key is pressed can trigger the OO mouseDragged event,
766//the former should be denied, and the latter allowed, only by doing so can the VBA MouseMove event when the "Shift" key is
767//pressed can be correctly triggered
768bool DenyMouseDrag(const ScriptEvent& evt, SAL_UNUSED_PARAMETER void const * )
769{
770 awt::MouseEvent aEvent;
771 evt.Arguments[ 0 ] >>= aEvent;
772 return aEvent.Buttons == 0;
773}
774
775
776// EventListener
777
778void
779EventListener::firing_Impl(const ScriptEvent& evt, Any* pRet )
780{
781 // let default handlers deal with non vba stuff
782 if ( evt.ScriptType != "VBAInterop" )
783 return;
784 lang::EventObject aEvent;
785 evt.Arguments[ 0 ] >>= aEvent;
786 OUString sName = "UserForm";
787
788 uno::Reference< awt::XDialog > xDlg( aEvent.Source, uno::UNO_QUERY );
789 if ( !xDlg.is() )
790 {
791 // evt.Source is
792 // a) Dialog
793 // b) xShapeControl ( from api (sheet control) )
794 // c) eventmanager ( I guess )
795 // d) vba control ( from api also )
796 uno::Reference< drawing::XControlShape > xCntrlShape( evt.Source, uno::UNO_QUERY );
797 uno::Reference< awt::XControl > xControl( aEvent.Source, uno::UNO_QUERY );
798 if ( xCntrlShape.is() )
799 {
800 // for sheet controls ( that fire from the api ) we don't
801 // have the real control ( that's only available from the view )
802 // api code creates just a control instance that is transferred
803 // via aEvent.Arguments[ 0 ] that control though has no
804 // info like name etc.
805 uno::Reference< container::XNamed > xName( xCntrlShape->getControl(), uno::UNO_QUERY_THROW );
806 sName = xName->getName();
807 }
808 else
809 {
810 // Userform control ( fired from the api or from event manager )
812 xProps.set( xControl->getModel(), uno::UNO_QUERY_THROW );
813 xProps->getPropertyValue("Name") >>= sName;
814 }
815 }
816 //dumpEvent( evt );
818 EventInfoHash::const_iterator eventInfo_it = infos.find( evt.MethodName );
819 EventInfoHash::const_iterator it_end = infos.end();
820 if ( eventInfo_it == it_end )
821 {
822 SAL_WARN("scripting", "Bogus event for " << evt.ScriptType );
823 return;
824 }
825
828 if ( xSPS.is() )
829 {
830 xScriptProvider = xSPS->getScriptProvider();
831 }
832 if ( !(xScriptProvider.is() && mpShell) )
833 return;
834
835 BasicManager* pBasicManager = mpShell->GetBasicManager();
836 OUString sProject;
837 OUString sScriptCode( evt.ScriptCode );
838 // dialogs pass their own library, presence of Dot determines that
839 if ( sScriptCode.indexOf( '.' ) == -1 )
840 {
841 //'Project' is a better default but I want to force failures
842 //OUString sMacroLoc("Project");
843 sProject = "Standard";
844
845 if (!pBasicManager->GetName().isEmpty())
846 {
847 sProject = pBasicManager->GetName();
848 }
849 }
850 else
851 {
852 sal_Int32 nIndex = sScriptCode.indexOf( '.' );
853 sProject = sScriptCode.copy( 0, nIndex );
854 sScriptCode = sScriptCode.copy( nIndex + 1 );
855 }
856 OUString sMacroLoc = sProject + "." + sScriptCode + ".";
857
858 for (const auto& rTxInfo : eventInfo_it->second)
859 {
860 // If the document is closed, we should not execute macro.
861 if (m_bDocClosed)
862 {
863 break;
864 }
865
866 // see if we have a match for the handlerextension
867 // where ScriptCode is methodname_handlerextension
868 OUString sToResolve = sMacroLoc + sName + rTxInfo.sVBAName;
869
870 ooo::vba::MacroResolvedInfo aMacroResolvedInfo = ooo::vba::resolveVBAMacro( mpShell, sToResolve );
871 if ( aMacroResolvedInfo.mbFound )
872 {
873
874 if (! rTxInfo.ApproveRule(evt, rTxInfo.pPara) )
875 {
876 continue;
877 }
878
879 // !! translate arguments & emulate events where necessary
880 Sequence< Any > aArguments;
881 if ( rTxInfo.toVBA )
882 {
883 aArguments = rTxInfo.toVBA( evt.Arguments );
884 }
885 else
886 {
887 aArguments = evt.Arguments;
888 }
889 if ( aArguments.hasElements() )
890 {
891 // call basic event handlers for event
892
893 // create script url
894 OUString url = aMacroResolvedInfo.msResolvedMacro;
895 try
896 {
897 uno::Any aDummyCaller( OUString("Error") );
898 if ( pRet )
899 {
900 ooo::vba::executeMacro( mpShell, url, aArguments, *pRet, aDummyCaller );
901 }
902 else
903 {
904 uno::Any aRet;
905 ooo::vba::executeMacro( mpShell, url, aArguments, aRet, aDummyCaller );
906 }
907 }
908 catch ( const uno::Exception& )
909 {
910 TOOLS_WARN_EXCEPTION("scripting", "event script raised" );
911 }
912 }
913 }
914 }
915}
916
917namespace {
918
919class VBAToOOEventDescGen : public ::cppu::WeakImplHelper< XVBAToOOEventDescGen, css::lang::XServiceInfo >
920{
921public:
922 VBAToOOEventDescGen();
923
924 // XVBAToOOEventDescGen
925 virtual Sequence< ScriptEventDescriptor > SAL_CALL getEventDescriptions( const OUString& sCtrlServiceName, const OUString& sCodeName ) override;
926 virtual Reference< XScriptEventsSupplier > SAL_CALL getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName ) override;
927
928 OUString SAL_CALL getImplementationName() override
929 {
930 return "ooo.vba.VBAToOOEventDesc";
931 }
932
933 sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
934 {
935 return cppu::supportsService(this, ServiceName);
936 }
937
938 css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
939 {
940 return { getImplementationName() };
941 }
942
943};
944
945}
946
947VBAToOOEventDescGen::VBAToOOEventDescGen() {}
948
949Sequence< ScriptEventDescriptor > SAL_CALL
950VBAToOOEventDescGen::getEventDescriptions( const OUString& sCntrlServiceName, const OUString& sCodeName )
951{
952 ScriptEventHelper evntHelper( sCntrlServiceName );
953 return evntHelper.createEvents( sCodeName );
954}
955
956Reference< XScriptEventsSupplier > SAL_CALL
957VBAToOOEventDescGen::getEventSupplier( const Reference< XInterface >& xControl, const OUString& sCodeName )
958{
959 ScriptEventHelper evntHelper( xControl );
960 Reference< XScriptEventsSupplier > xSupplier =
961 new ReadOnlyEventsSupplier(
962 evntHelper.getEventListeners(), sCodeName ) ;
963 return xSupplier;
964}
965
966extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
967ooo_vba_EventListener_get_implementation(css::uno::XComponentContext*,
968 css::uno::Sequence<css::uno::Any> const &)
969{
970 return cppu::acquire(new EventListener);
971}
972
973
974extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
976 css::uno::Sequence<css::uno::Any> const &)
977{
978 return cppu::acquire(new VBAToOOEventDescGen);
979}
980
981
982/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xCtx
AnyEventRef aEvent
const OUString & GetName() const
static SAL_WARN_UNUSED_RESULT SfxObjectShell * GetNext(const SfxObjectShell &rPrev, const std::function< bool(const SfxObjectShell *)> &isObjectShell=nullptr, bool bOnlyVisible=true)
css::uno::Reference< css::frame::XModel3 > GetModel() const
static SAL_WARN_UNUSED_RESULT SfxObjectShell * GetFirst(const std::function< bool(const SfxObjectShell *)> &isObjectShell=nullptr, bool bOnlyVisible=true)
virtual ::cppu::IPropertyArrayHelper * createArrayHelper() const=0
virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const css::uno::Any &rValue) override final
void SAL_CALL disposing()
css::uno::Type const & get()
const ScContentId pTypeList[int(ScContentId::LAST)+1]
int nCount
#define TOOLS_WARN_EXCEPTION(area, stream)
Reference< frame::XModel > m_xModel
Definition: dlgevtatt.cxx:65
Reference< awt::XControl > m_xControl
Definition: dlgevtatt.cxx:81
float u
::cppu::WeakImplHelper< XScriptListener, util::XCloseListener, lang::XInitialization, css::lang::XServiceInfo > EventListener_BASE
TypeList const comboBoxList
static bool DenyType(const ScriptEvent &evt, void const *pPara)
TypeList const radioButtonList
std::unordered_map< OUString, std::vector< TranslateInfo > > EventInfoHash
static bool ApproveAll(const ScriptEvent &evt, void const *pPara)
static EventInfoHash & getEventTransInfo()
static bool FindControl(const ScriptEvent &evt, void const *pPara)
static bool eventMethodToDescriptor(std::u16string_view rEventMethod, ScriptEventDescriptor &evtDesc, const OUString &sCodeName)
constexpr OUStringLiteral EVENTLSTNR_PROPERTY_MODEL
Type const typeXComboBox
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * ooo_vba_EventListener_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
static Sequence< Any > ooKeyPressedToVBAKeyPressed(const Sequence< Any > &params)
Type const typeXTextComponent
#define EVENTLSTNR_PROPERTY_ID_MODEL
static bool isKeyEventOk(awt::KeyEvent &evt, const Sequence< Any > &params)
Definition: eventhelper.cxx:82
static bool DenyMouseDrag(const ScriptEvent &evt, void const *pPara)
::cppu::WeakImplHelper< container::XNameContainer > NameContainer_BASE
TypeList const textCompList
static Sequence< Any > ooMouseEvtToVBADblClick(const Sequence< Any > &params)
Definition: eventhelper.cxx:92
constexpr sal_Int32 DELIMLEN
Definition: eventhelper.cxx:80
constexpr std::u16string_view DELIM
Definition: eventhelper.cxx:79
Type const typeXRadioButton
Sequence< Any >(* Translator)(const Sequence< Any > &)
TypeList const fixedTextList
static bool isMouseEventOk(awt::MouseEvent &evt, const Sequence< Any > &params)
Definition: eventhelper.cxx:87
Type const typeXListBox
Type const typeXFixedText
static Sequence< Any > ooKeyPressedToVBAKeyUpDown(const Sequence< Any > &params)
static bool ApproveType(const ScriptEvent &evt, void const *pPara)
TypeList const listBoxList
static Sequence< Any > ooMouseEvtToVBAMouseEvt(const Sequence< Any > &params)
static TranslatePropMap aTranslatePropMap_Impl[]
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * ooo_vba_VBAToOOEventDesc_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
OUString sName
Sequence< PropertyValue > aArguments
sal_Int32 nIndex
OUString aName
Reference< XIntrospection > xIntrospection
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
#define SAL_N_ELEMENTS(arr)
::cppu::WeakImplHelper< css::container::XNameContainer, css::container::XContainer, css::util::XChangesNotifier > NameContainer_BASE
Sequence< OUString > getEventMethodsForType(const Type &type)
css::uno::Sequence< typename M::key_type > mapKeysToSequence(M const &map)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XComponentContext > getProcessComponentContext()
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
Type
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
int shift
bool executeMacro(SfxObjectShell *pShell, const OUString &sMacroName, uno::Sequence< uno::Any > &aArgs, uno::Any &aRet, const uno::Any &)
OUString resolveVBAMacro(SfxObjectShell const *pShell, const OUString &rLibName, const OUString &rModuleName, const OUString &rMacroName, bool bOnlyPublic, const OUString &sSkipModule)
IMPLEMENT_FORWARD_XTYPEPROVIDER2(ChildWindowPane, ChildWindowPaneInterfaceBase, Pane)
IMPLEMENT_FORWARD_XINTERFACE2(ChildWindowPane, ChildWindowPaneInterfaceBase, Pane)
sal_Int32 nHandle
Reference< XModel > xModel
unsigned char sal_Bool
signed char sal_Int8
#define DECLARE_XTYPEPROVIDER()
#define DECLARE_XINTERFACE()
sal_Int32 nLength