diff options
Diffstat (limited to 'scripting/source/vbaevents/eventhelper.cxx')
-rw-r--r-- | scripting/source/vbaevents/eventhelper.cxx | 483 |
1 files changed, 340 insertions, 143 deletions
diff --git a/scripting/source/vbaevents/eventhelper.cxx b/scripting/source/vbaevents/eventhelper.cxx index 6975fba08e..7e8155fa78 100644 --- a/scripting/source/vbaevents/eventhelper.cxx +++ b/scripting/source/vbaevents/eventhelper.cxx @@ -1,7 +1,7 @@ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * + * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite @@ -46,12 +46,17 @@ #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/util/XCloseListener.hpp> +#include <com/sun/star/util/XCloseBroadcaster.hpp> + #include <com/sun/star/frame/XModel.hpp> #include <com/sun/star/script/XLibraryContainer.hpp> #include <com/sun/star/script/ScriptEventDescriptor.hpp> #include <com/sun/star/script/provider/XScriptProviderSupplier.hpp> +#include <com/sun/star/container/XNamed.hpp> + #include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/awt/XControl.hpp> @@ -62,8 +67,9 @@ #include <com/sun/star/awt/XTextComponent.hpp> //liuchen 2009-6-5 #include <com/sun/star/awt/XComboBox.hpp> //liuchen 2009-6-18 #include <com/sun/star/awt/XRadioButton.hpp> //liuchen 2009-7-30 +#include <com/sun/star/awt/XListBox.hpp> -#include <msforms/ReturnInteger.hpp> +#include "vbamsformreturntypes.hxx" #include <sfx2/objsh.hxx> #include <basic/sbstar.hxx> @@ -71,6 +77,7 @@ #include <basic/sbmeth.hxx> #include <basic/sbmod.hxx> #include <basic/sbx.hxx> +#include <filter/msfilter/msvbahelper.hxx> @@ -82,12 +89,21 @@ #include <com/sun/star/lang/XMultiComponentFactory.hpp> #include <com/sun/star/script/XScriptListener.hpp> #include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase3.hxx> #include <cppuhelper/implbase2.hxx> #include <comphelper/evtmethodhelper.hxx> #include <set> #include <list> #include <hash_map> +#define ASYNC 0 + +// primitive support for asynchronous handling of +// events from controls ( all event will be processed asynchronously +// in the application thread ) +#if ASYNC +#include <vcl/svapp.hxx> +#endif using namespace ::com::sun::star; using namespace ::com::sun::star::script; @@ -97,7 +113,7 @@ using namespace ::ooo::vba; #define MAP_CHAR_LEN(x) ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(x))//liuchen 2009-6-8 #define GET_TYPE(x) ::getCppuType((uno::Reference< x > *)0); -// Some constants +// Some constants const static rtl::OUString DELIM = rtl::OUString::createFromAscii( "::" ); const static sal_Int32 DELIMLEN = DELIM.getLength(); @@ -107,12 +123,12 @@ void dumpListeners( const Reference< beans::XIntrospection >& xIntrospection, co Reference< beans::XIntrospectionAccess > xIntrospectionAccess; if ( xIntrospection.is() ) { - xIntrospectionAccess = xIntrospection->inspect( + xIntrospectionAccess = xIntrospection->inspect( makeAny( xIfc ) ); - Sequence< Type > aControlListeners = + Sequence< Type > aControlListeners = xIntrospectionAccess->getSupportedListeners(); sal_Int32 nLength = aControlListeners.getLength(); - + for ( sal_Int32 i = 0; i< nLength; ++i ) { Type& listType = aControlListeners[ i ]; @@ -121,51 +137,51 @@ void dumpListeners( const Reference< beans::XIntrospection >& xIntrospection, co sal_Int32 lastDotIndex = -1; if ( ( lastDotIndex = sFullTypeName.lastIndexOf( '.' ) ) > -1 ) { - sTypeName = sFullTypeName.copy( lastDotIndex + 1 ); - } - Sequence< ::rtl::OUString > sMeths = comphelper::getEventMethodsForType( listType ); + sTypeName = sFullTypeName.copy( lastDotIndex + 1 ); + } + Sequence< ::rtl::OUString > sMeths = comphelper::getEventMethodsForType( listType ); sal_Int32 sMethLen = sMeths.getLength(); for ( sal_Int32 j=0 ; j < sMethLen; ++j ) { OSL_TRACE("**Listener [%d] Type[%s] Method[%s]",j, - rtl::OUStringToOString( sTypeName, + rtl::OUStringToOString( sTypeName, RTL_TEXTENCODING_UTF8 ).getStr(), - rtl::OUStringToOString( sMeths[ j ], + rtl::OUStringToOString( sMeths[ j ], RTL_TEXTENCODING_UTF8 ).getStr() ); } } - + } } void dumpEvent( const ScriptEvent& evt ) { OSL_TRACE("dumpEvent: Source %s", - rtl::OUStringToOString( comphelper::anyToString( makeAny(evt.Source)), + rtl::OUStringToOString( comphelper::anyToString( makeAny(evt.Source)), RTL_TEXTENCODING_UTF8 ).getStr() ); OSL_TRACE("dumpEvent: ScriptType %s", - rtl::OUStringToOString( evt.ScriptType, + rtl::OUStringToOString( evt.ScriptType, RTL_TEXTENCODING_UTF8 ).getStr() ); - + OSL_TRACE("dumpEvent: ScriptCode %s", - rtl::OUStringToOString( evt.ScriptCode, + rtl::OUStringToOString( evt.ScriptCode, RTL_TEXTENCODING_UTF8 ).getStr() ); OSL_TRACE("dumpEvent: ListenerType %s", - rtl::OUStringToOString( evt.ListenerType.getTypeName(), + rtl::OUStringToOString( evt.ListenerType.getTypeName(), RTL_TEXTENCODING_UTF8 ).getStr() ); - + OSL_TRACE("dumpEvent: Listener methodname %s", - rtl::OUStringToOString( evt.MethodName, + rtl::OUStringToOString( evt.MethodName, RTL_TEXTENCODING_UTF8 ).getStr() ); OSL_TRACE("dumpEvent: arguments;"); sal_Int32 nLen = evt.Arguments.getLength(); for ( sal_Int32 index=0; index < nLen; ++index ) { - OSL_TRACE("\t [%d] %s", index, - rtl::OUStringToOString( comphelper::anyToString( evt.Arguments[ index ] ), + OSL_TRACE("\t [%d] %s", index, + rtl::OUStringToOString( comphelper::anyToString( evt.Arguments[ index ] ), RTL_TEXTENCODING_UTF8 ).getStr() ); } @@ -189,14 +205,22 @@ bool isMouseEventOk( awt::MouseEvent& evt, const Sequence< Any >& params ) return true; } +bool isFocusEventOk( awt::FocusEvent& evt, const Sequence< Any >& params ) +{ + if ( !( params.getLength() > 0 ) || + !( params[ 0 ] >>= evt ) ) + return false; + return true; +} + Sequence< Any > ooMouseEvtToVBADblClick( const Sequence< Any >& params ) { Sequence< Any > translatedParams; awt::MouseEvent evt; - if ( !( isMouseEventOk(evt, params)) || + if ( !( isMouseEventOk(evt, params)) || (evt.ClickCount != 2) ) - return Sequence< Any >(); + return Sequence< Any >(); // give back orig params, this will signal that the event is good return params; } @@ -207,7 +231,7 @@ Sequence< Any > ooMouseEvtToVBAMouseEvt( const Sequence< Any >& params ) awt::MouseEvent evt; if ( !isMouseEventOk(evt, params) ) - return Sequence< Any >(); + return Sequence< Any >(); translatedParams.realloc(4); @@ -228,13 +252,18 @@ Sequence< Any > ooKeyPressedToVBAKeyPressed( const Sequence< Any >& params ) awt::KeyEvent evt; if ( !isKeyEventOk( evt, params ) ) - return Sequence< Any >(); + return Sequence< Any >(); translatedParams.realloc(1); - msforms::ReturnInteger keyCode; - keyCode.Value = evt.KeyCode; - translatedParams[0] <<= keyCode; + //The VBA events such as ComboBox_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger) may cause an error because + //the original input parameter data structure -- msforms::ReturnInteger -- is a struct, it cannot support default value. + //So the newly defined VbaReturnIntege class is used here to support default value. + VbaReturnInteger* pKeyCode = new VbaReturnInteger(); + pKeyCode->Value = evt.KeyChar; + ::uno::Reference< msforms::XReturnInteger > xInteger = + static_cast< ::uno::Reference< msforms::XReturnInteger > > (pKeyCode); + translatedParams[0] <<= xInteger; return translatedParams; } @@ -244,35 +273,57 @@ Sequence< Any > ooKeyPressedToVBAKeyUpDown( const Sequence< Any >& params ) awt::KeyEvent evt; if ( !isKeyEventOk( evt, params ) ) - return Sequence< Any >(); + return Sequence< Any >(); translatedParams.realloc(2); - msforms::ReturnInteger keyCode; - sal_Int8 shift = sal::static_int_cast<sal_Int8>( evt.Modifiers ); + //The VBA events such as ComboBox_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger) may cause an error because + //the original input parameter data structure -- msforms::ReturnInteger -- is a struct, it cannot support default value. + //So the newly defined VbaReturnIntege class is used here to support default value. + VbaReturnInteger* pKeyCode = new VbaReturnInteger(); + sal_Int8 shift = evt.Modifiers; - // #TODO check whether values from OOO conform to values generated from vba - keyCode.Value = evt.KeyCode; - translatedParams[0] <<= keyCode; + pKeyCode->Value = evt.KeyChar; + ::uno::Reference< msforms::XReturnInteger > xInteger = static_cast< ::uno::Reference< msforms::XReturnInteger > > (pKeyCode); + translatedParams[0] <<= xInteger; translatedParams[1] <<= shift; return translatedParams; } +Sequence< Any > ooFocusLostToVBAExit( const Sequence< Any >& params ) +{ + Sequence< Any > translatedParams; + awt::FocusEvent evt; + + if ( !isFocusEventOk( evt, params ) ) + return Sequence< Any >(); + + translatedParams.realloc(1); + + VbaReturnBoolean* pCancel = new VbaReturnBoolean(); + + ::uno::Reference< msforms::XReturnBoolean > xBoolean= + static_cast< ::uno::Reference< msforms::XReturnBoolean > > (pCancel); + translatedParams[0] <<= xBoolean; + return translatedParams; +} + + typedef Sequence< Any > (*Translator)(const Sequence< Any >&); //liuchen 2009-6-23 -//expand the "TranslateInfo" struct to support more kinds of events +//expand the "TranslateInfo" struct to support more kinds of events struct TranslateInfo { rtl::OUString sVBAName; //vba event name - Translator toVBA; //the method to convert OO event parameters to VBA event parameters - bool (*ApproveRule)(const ScriptEvent& evt, void* pPara); //this method is used to determine which types of controls should execute the event + Translator toVBA; //the method to convert OO event parameters to VBA event parameters + bool (*ApproveRule)(const ScriptEvent& evt, void* pPara); //this method is used to determine which types of controls should execute the event void *pPara; //Parameters for the above approve method }; -typedef std::hash_map< rtl::OUString, -std::list< TranslateInfo >, +typedef std::hash_map< rtl::OUString, +std::list< TranslateInfo >, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > EventInfoHash; @@ -280,13 +331,14 @@ std::list< TranslateInfo >, struct TranslatePropMap { rtl::OUString sEventInfo; //OO event name - TranslateInfo aTransInfo; + TranslateInfo aTransInfo; }; - + bool ApproveAll(const ScriptEvent& evt, void* pPara); //allow all types of controls to execute the event bool ApproveType(const ScriptEvent& evt, void* pPara); //certain types of controls should execute the event, those types are given by pPara bool DenyType(const ScriptEvent& evt, void* pPara); //certain types of controls should not execute the event, those types are given by pPara bool DenyMouseDrag(const ScriptEvent& evt, void* pPara); //used for VBA MouseMove event when "Shift" key is pressed +bool DenyKeys(const ScriptEvent& evt, void* pPara); //For some keys, press them will cause Symphony keyPressed event, but will not cause any events in Excel, so deny these key events struct TypeList { @@ -294,37 +346,39 @@ struct TypeList int nListLength; }; -Type typeXFixedText = GET_TYPE(awt::XFixedText) -Type typeXTextComponent = GET_TYPE(awt::XTextComponent) -Type typeXComboBox = GET_TYPE(awt::XComboBox) -Type typeXRadioButton = GET_TYPE(awt::XRadioButton) +Type typeXFixedText = GET_TYPE(awt::XFixedText); +Type typeXTextComponent = GET_TYPE(awt::XTextComponent); +Type typeXComboBox = GET_TYPE(awt::XComboBox); +Type typeXRadioButton = GET_TYPE(awt::XRadioButton); +Type typeXListBox = GET_TYPE(awt::XListBox); TypeList fixedTextList = {&typeXFixedText, 1}; TypeList textCompList = {&typeXTextComponent, 1}; TypeList radioButtonList = {&typeXRadioButton, 1}; TypeList comboBoxList = {&typeXComboBox, 1}; +TypeList listBoxList = {&typeXListBox, 1}; //this array stores the OO event to VBA event translation info -static TranslatePropMap aTranslatePropMap_Impl[] = +static TranslatePropMap aTranslatePropMap_Impl[] = { - // actionPerformed ooo event - { MAP_CHAR_LEN("actionPerformed"), { MAP_CHAR_LEN("_Click"), NULL, ApproveAll, NULL } }, { MAP_CHAR_LEN("actionPerformed"), { MAP_CHAR_LEN("_Change"), NULL, DenyType, (void*)(&radioButtonList) } }, //liuchen 2009-7-30, OptionalButton_Change event is not the same as OptionalButton_Click event - + // actionPerformed ooo event + { MAP_CHAR_LEN("actionPerformed"), { MAP_CHAR_LEN("_Click"), NULL, ApproveAll, NULL } }, + { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveType, (void*)(&radioButtonList) } }, //liuchen 2009-7-30, OptionalButton_Change event should be triggered when the button state is changed // itemStateChanged ooo event { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Click"), NULL, ApproveType, (void*)(&comboBoxList) } }, //liuchen, add to support VBA ComboBox_Click event - { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveType, (void*)(&radioButtonList) } }, //liuchen 2009-7-30, OptionalButton_Change event should be triggered when the button state is changed - + + { MAP_CHAR_LEN("itemStateChanged"), { MAP_CHAR_LEN("_Click"), NULL, ApproveType, (void*)(&listBoxList) } }, // changed ooo event - { MAP_CHAR_LEN("changed"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } }, + { MAP_CHAR_LEN("changed"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } }, // focusGained ooo event { MAP_CHAR_LEN("focusGained"), { MAP_CHAR_LEN("_GotFocus"), NULL, ApproveAll, NULL } }, // focusLost ooo event { MAP_CHAR_LEN("focusLost"), { MAP_CHAR_LEN("_LostFocus"), NULL, ApproveAll, NULL } }, - { MAP_CHAR_LEN("focusLost"), { MAP_CHAR_LEN("_Exit"), NULL, ApproveType, (void*)(&textCompList) } }, //liuchen, add to support VBA TextBox_Exit event + { MAP_CHAR_LEN("focusLost"), { MAP_CHAR_LEN("_Exit"), ooFocusLostToVBAExit, ApproveType, (void*)(&textCompList) } }, //liuchen, add to support VBA TextBox_Exit event // adjustmentValueChanged ooo event { MAP_CHAR_LEN("adjustmentValueChanged"), { MAP_CHAR_LEN("_Scroll"), NULL, ApproveAll, NULL } }, @@ -344,13 +398,13 @@ static TranslatePropMap aTranslatePropMap_Impl[] = { MAP_CHAR_LEN("mousePressed"), { MAP_CHAR_LEN("_MouseDown"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } }, { MAP_CHAR_LEN("mousePressed"), { MAP_CHAR_LEN("_DblClick"), ooMouseEvtToVBADblClick, ApproveAll, NULL } }, - // mouseMoved ooo event + // mouseMoved ooo event { MAP_CHAR_LEN("mouseMoved"), { MAP_CHAR_LEN("_MouseMove"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } }, { MAP_CHAR_LEN("mouseDragged"), { MAP_CHAR_LEN("_MouseMove"), ooMouseEvtToVBAMouseEvt, DenyMouseDrag, NULL } }, //liuchen, add to support VBA MouseMove event when the "Shift" key is pressed // keyPressed ooo event - { MAP_CHAR_LEN("keyPressed"), { MAP_CHAR_LEN("_KeyDown"), ooKeyPressedToVBAKeyPressed, ApproveAll, NULL } }, - { MAP_CHAR_LEN("keyPressed"), { MAP_CHAR_LEN("_KeyPress"), ooKeyPressedToVBAKeyPressed, ApproveAll, NULL } } + { MAP_CHAR_LEN("keyPressed"), { MAP_CHAR_LEN("_KeyDown"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } }, + { MAP_CHAR_LEN("keyPressed"), { MAP_CHAR_LEN("_KeyPress"), ooKeyPressedToVBAKeyUpDown, DenyKeys, NULL } } }; EventInfoHash& getEventTransInfo() @@ -365,17 +419,17 @@ EventInfoHash& getEventTransInfo() int i = 0; while (i < nCount) - { + { sEventInfo = pTransProp->sEventInfo; std::list< TranslateInfo > infoList; do - { + { infoList.push_back( pTransProp->aTransInfo ); pTransProp++; i++; }while(i < nCount && sEventInfo == pTransProp->sEventInfo); - eventTransInfo[sEventInfo] = infoList; - } + eventTransInfo[sEventInfo] = infoList; + } initialised = true; } return eventTransInfo; @@ -388,7 +442,7 @@ class ScriptEventHelper { public: ScriptEventHelper( const Reference< XInterface >& xControl ); - Sequence< ScriptEventDescriptor > createEvents( const rtl::OUString& sCodeName ); + Sequence< ScriptEventDescriptor > createEvents( const rtl::OUString& sCodeName ); Sequence< rtl::OUString > getEventListeners(); private: Reference< XComponentContext > m_xCtx; @@ -411,16 +465,16 @@ eventMethodToDescriptor( const ::rtl::OUString& rEventMethod, ScriptEventDescrip } sMethodName = rEventMethod.copy( nDelimPos + DELIMLEN ); sTypeName = rEventMethod.copy( 0, nDelimPos ); - + EventInfoHash& infos = getEventTransInfo(); // Only create an ScriptEventDescriptor for an event we can translate // or emulate - if ( sMethodName.getLength() + if ( sMethodName.getLength() && sTypeName.getLength() && ( infos.find( sMethodName ) != infos.end() ) ) { - // just fill in CodeName, when the event fires the other + // just fill in CodeName, when the event fires the other // info is gathered from the event source to determine what // event handler we try to call evtDesc.ScriptCode = sCodeName; @@ -430,7 +484,7 @@ eventMethodToDescriptor( const ::rtl::OUString& rEventMethod, ScriptEventDescrip // set this it VBAInterop, ensures that it doesn't // get persisted or shown in property editors evtDesc.ScriptType = rtl::OUString::createFromAscii( - "VBAInterop" ); + "VBAInterop" ); return true; } return false; @@ -442,40 +496,40 @@ ScriptEventHelper::ScriptEventHelper( const Reference< XInterface >& xControl ) Reference < beans::XPropertySet > xProps( ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW ); m_xCtx.set( xProps->getPropertyValue( rtl::OUString( - RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), + RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), uno::UNO_QUERY_THROW ); } -Sequence< rtl::OUString > +Sequence< rtl::OUString > ScriptEventHelper::getEventListeners() { - Reference< lang::XMultiComponentFactory > xMFac( + Reference< lang::XMultiComponentFactory > xMFac( m_xCtx->getServiceManager(), UNO_QUERY ); std::list< rtl::OUString > eventMethods; if ( xMFac.is() ) { - Reference< beans::XIntrospection > xIntrospection( - xMFac->createInstanceWithContext( rtl::OUString( + Reference< beans::XIntrospection > xIntrospection( + xMFac->createInstanceWithContext( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.Introspection" ) ), m_xCtx ), UNO_QUERY ); #if 0 dumpListeners( xIntrospection, m_xControl ); dumpListeners( xIntrospection, m_xControl->getModel() ); -#endif +#endif Reference< beans::XIntrospectionAccess > xIntrospectionAccess; if ( xIntrospection.is() ) { - xIntrospectionAccess = xIntrospection->inspect( + xIntrospectionAccess = xIntrospection->inspect( makeAny( m_xControl ) ); - Sequence< Type > aControlListeners = + Sequence< Type > aControlListeners = xIntrospectionAccess->getSupportedListeners(); - sal_Int32 nLength = aControlListeners.getLength(); + sal_Int32 nLength = aControlListeners.getLength(); for ( sal_Int32 i = 0; i< nLength; ++i ) { Type& listType = aControlListeners[ i ]; rtl::OUString sFullTypeName = listType.getTypeName(); - Sequence< ::rtl::OUString > sMeths = - comphelper::getEventMethodsForType( listType ); + Sequence< ::rtl::OUString > sMeths = + comphelper::getEventMethodsForType( listType ); sal_Int32 sMethLen = sMeths.getLength(); for ( sal_Int32 j=0 ; j < sMethLen; ++j ) { @@ -485,7 +539,7 @@ ScriptEventHelper::getEventListeners() eventMethods.push_back( sEventMethod ); } } - + } } @@ -494,20 +548,20 @@ ScriptEventHelper::getEventListeners() rtl::OUString* pDest = sEventMethodNames.getArray(); for ( ; it != eventMethods.end(); ++it, ++pDest ) - *pDest = *it; + *pDest = *it; return sEventMethodNames; } -Sequence< ScriptEventDescriptor > +Sequence< ScriptEventDescriptor > ScriptEventHelper::createEvents( const rtl::OUString& sCodeName ) { Sequence< rtl::OUString > aControlListeners = getEventListeners(); rtl::OUString* pSrc = aControlListeners.getArray(); - sal_Int32 nLength = aControlListeners.getLength(); + sal_Int32 nLength = aControlListeners.getLength(); Sequence< ScriptEventDescriptor > aDest( nLength ); - sal_Int32 nEvts = 0; + sal_Int32 nEvts = 0; for ( sal_Int32 i = 0; i< nLength; ++i, ++pSrc ) { // from getListeners eventName is of form @@ -541,7 +595,7 @@ public: virtual void SAL_CALL insertByName( const ::rtl::OUString&, const Any& ) throw (lang::IllegalArgumentException, container::ElementExistException, lang::WrappedTargetException, RuntimeException) { throw RuntimeException( rtl::OUString::createFromAscii( "ReadOnly container" ), Reference< XInterface >() ); - + } virtual void SAL_CALL removeByName( const ::rtl::OUString& ) throw (::com::sun::star::container::NoSuchElementException, lang::WrappedTargetException, RuntimeException) { @@ -552,9 +606,9 @@ public: virtual void SAL_CALL replaceByName( const ::rtl::OUString&, const Any& ) throw (lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, RuntimeException) { throw RuntimeException( rtl::OUString::createFromAscii( "ReadOnly container" ), Reference< XInterface >() ); - + } - + // XNameAccess virtual Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException); virtual Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) throw (RuntimeException); @@ -583,13 +637,13 @@ ReadOnlyEventsNameContainer::ReadOnlyEventsNameContainer( const Sequence< rtl::O ScriptEventDescriptor evtDesc; if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) ) { - aDesc <<= evtDesc; + aDesc <<= evtDesc; m_hEvents[ *pSrc ] = aDesc; } } } -Any SAL_CALL +Any SAL_CALL ReadOnlyEventsNameContainer::getByName( const ::rtl::OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException){ EventSupplierHash::const_iterator it = m_hEvents.find( aName ); if ( it == m_hEvents.end() ) @@ -597,7 +651,7 @@ ReadOnlyEventsNameContainer::getByName( const ::rtl::OUString& aName ) throw (co return it->second; } -Sequence< ::rtl::OUString > SAL_CALL +Sequence< ::rtl::OUString > SAL_CALL ReadOnlyEventsNameContainer::getElementNames( ) throw (RuntimeException) { Sequence< ::rtl::OUString > names(m_hEvents.size()); @@ -609,7 +663,7 @@ ReadOnlyEventsNameContainer::getElementNames( ) throw (RuntimeException) return names; } -sal_Bool SAL_CALL +sal_Bool SAL_CALL ReadOnlyEventsNameContainer::hasByName( const ::rtl::OUString& aName ) throw (RuntimeException) { EventSupplierHash::const_iterator it = m_hEvents.find( aName ); @@ -625,14 +679,14 @@ class ReadOnlyEventsSupplier : public EventsSupplier_BASE public: ReadOnlyEventsSupplier( const Sequence< ::rtl::OUString >& eventMethods, const rtl::OUString& sCodeName ) { m_xNameContainer = new ReadOnlyEventsNameContainer( eventMethods, sCodeName ); } - + // XScriptEventSupplier virtual Reference< container::XNameContainer > SAL_CALL getEvents( ) throw (RuntimeException){ return m_xNameContainer; } private: Reference< container::XNameContainer > m_xNameContainer; }; -typedef ::cppu::WeakImplHelper2< XScriptListener, lang::XInitialization > EventListener_BASE; +typedef ::cppu::WeakImplHelper3< XScriptListener, util::XCloseListener, lang::XInitialization > EventListener_BASE; #define EVENTLSTNR_PROPERTY_ID_MODEL 1 #define EVENTLSTNR_PROPERTY_MODEL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Model" ) ) @@ -643,7 +697,7 @@ class EventListener : public EventListener_BASE ,public ::comphelper::OPropertyArrayUsageHelper< EventListener > { - + public: EventListener( const Reference< XComponentContext >& rxContext ); // XEventListener @@ -653,8 +707,11 @@ public: // XScriptListener virtual void SAL_CALL firing(const ScriptEvent& evt) throw(RuntimeException); virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException); + // XCloseListener + virtual void SAL_CALL queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException); + virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException); // XPropertySet - virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException); // XInitialization virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException); // XInterface @@ -664,6 +721,25 @@ public: DECLARE_XTYPEPROVIDER() 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) { + if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL ) + { + uno::Reference< frame::XModel > xModel( rValue, uno::UNO_QUERY ); + if( xModel != m_xModel) + { + // Remove the listener from the old XCloseBroadcaster. + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY ); + if (xCloseBroadcaster.is()) + { + xCloseBroadcaster->removeCloseListener( this ); + } + // Add the listener into the new XCloseBroadcaster. + xCloseBroadcaster = uno::Reference< util::XCloseBroadcaster >( xModel, uno::UNO_QUERY ); + if (xCloseBroadcaster.is()) + { + xCloseBroadcaster->addCloseListener( this ); + } + } + } OPropertyContainer::setFastPropertyValue( nHandle, rValue ); if ( nHandle == EVENTLSTNR_PROPERTY_ID_MODEL ) setShellFromModel(); @@ -677,17 +753,21 @@ protected: virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; private: +#if ASYNC + DECL_LINK( OnAsyncScriptEvent, ScriptEvent* ); +#endif void setShellFromModel(); void firing_Impl( const ScriptEvent& evt, Any *pSyncRet=NULL ) throw( RuntimeException ); Reference< XComponentContext > m_xContext; Reference< frame::XModel > m_xModel; SfxObjectShell* mpShell; - + sal_Bool m_bDocClosed; + }; EventListener::EventListener( const Reference< XComponentContext >& rxContext ) : -OPropertyContainer(GetBroadcastHelper()), m_xContext( rxContext ), mpShell( 0 ) +OPropertyContainer(GetBroadcastHelper()), m_xContext( rxContext ), m_bDocClosed(sal_False), mpShell( 0 ) { registerProperty( EVENTLSTNR_PROPERTY_MODEL, EVENTLSTNR_PROPERTY_ID_MODEL, beans::PropertyAttribute::TRANSIENT, &m_xModel, ::getCppuType( &m_xModel ) ); @@ -708,7 +788,7 @@ EventListener::setShellFromModel() break; } pShell = SfxObjectShell::GetNext( *pShell ); - } + } } //XEventListener @@ -719,13 +799,43 @@ EventListener::disposing(const lang::EventObject&) throw( RuntimeException ) //XScriptListener -void SAL_CALL +void SAL_CALL EventListener::firing(const ScriptEvent& evt) throw(RuntimeException) { +#if ASYNC + // needs some logic to check if the event handler is oneway or not + // if not oneway then firing_Impl otherwise... as below + acquire(); + Application::PostUserEvent( LINK( this, EventListener, OnAsyncScriptEvent ), new ScriptEvent( evt ) ); +#else firing_Impl( evt ); +#endif } -Any SAL_CALL +#if ASYNC +IMPL_LINK( EventListener, OnAsyncScriptEvent, ScriptEvent*, _pEvent ) +{ + if ( !_pEvent ) + return 1L; + + { + // #FIXME if we enable ASYNC we probably need something like + // below + //::osl::ClearableMutexGuard aGuard( m_aMutex ); + + //if ( !impl_isDisposed_nothrow() ) + // impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, NULL ); + firing_Impl( *_pEvent, NULL ); + } + + delete _pEvent; + // we acquired ourself immediately before posting the event + release(); + return 0L; + } +#endif + +Any SAL_CALL EventListener::approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException) { Any ret; @@ -733,8 +843,26 @@ EventListener::approveFiring(const ScriptEvent& evt) throw(reflection::Invocatio return ret; } +// XCloseListener +void SAL_CALL +EventListener::queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException) +{ + //Nothing to do +} + +void SAL_CALL +EventListener::notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException) +{ + m_bDocClosed = sal_True; + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY ); + if (xCloseBroadcaster.is()) + { + xCloseBroadcaster->removeCloseListener( this ); + } +} + // XInitialization -void SAL_CALL +void SAL_CALL EventListener::initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException) { if ( aArguments.getLength() == 1 ) @@ -752,7 +880,7 @@ IMPLEMENT_FORWARD_XTYPEPROVIDER2( EventListener, EventListener_BASE, OPropertyCo // OPropertySetHelper -::cppu::IPropertyArrayHelper& +::cppu::IPropertyArrayHelper& EventListener::getInfoHelper( ) { return *getArrayHelper(); @@ -760,7 +888,7 @@ EventListener::getInfoHelper( ) // OPropertyArrayUsageHelper -::cppu::IPropertyArrayHelper* +::cppu::IPropertyArrayHelper* EventListener::createArrayHelper( ) const { Sequence< beans::Property > aProps; @@ -769,7 +897,7 @@ EventListener::createArrayHelper( ) const } // XPropertySet -Reference< beans::XPropertySetInfo > +Reference< beans::XPropertySetInfo > EventListener::getPropertySetInfo( ) throw (RuntimeException) { Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); @@ -819,7 +947,7 @@ bool DenyType(const ScriptEvent& evt, void* pPara) } //when mouse is moving, either the mouse button is pressed or some key is pressed can trigger the OO mouseDragged event, -//the former should be denyed, and the latter allowed, only by doing so can the VBA MouseMove event when the "Shift" key is +//the former should be denyed, and the latter allowed, only by doing so can the VBA MouseMove event when the "Shift" key is //pressed can be correctly triggered bool DenyMouseDrag(const ScriptEvent& evt, void* ) { @@ -835,13 +963,28 @@ bool DenyMouseDrag(const ScriptEvent& evt, void* ) } } +//For some keys, press them will cause Symphony keyPressed event, but will not cause any events in Excel, so deny these key events +bool DenyKeys(const ScriptEvent& evt, void* /*pPara*/) +{ + awt::KeyEvent aEvent; + evt.Arguments[ 0 ] >>= aEvent; + if (aEvent.KeyChar == 0 || aEvent.KeyChar == 8) + { + return false; + } + else + { + return true; + } +} + //liuchen 2009-6-23 // EventListener void -EventListener::firing_Impl(const ScriptEvent& evt, Any* /*pRet*/ ) throw(RuntimeException) +EventListener::firing_Impl(const ScriptEvent& evt, Any* pRet ) throw(RuntimeException) { OSL_TRACE("EventListener::firing_Impl( FAKE VBA_EVENTS )"); static const ::rtl::OUString vbaInterOp = @@ -852,18 +995,46 @@ EventListener::firing_Impl(const ScriptEvent& evt, Any* /*pRet*/ ) throw(Runtime return; lang::EventObject aEvent; evt.Arguments[ 0 ] >>= aEvent; + OSL_TRACE("evt.MethodName is %s", rtl::OUStringToOString( evt.MethodName, RTL_TEXTENCODING_UTF8 ).getStr() ); OSL_TRACE("Argument[0] is %s", rtl::OUStringToOString( comphelper::anyToString( evt.Arguments[0] ), RTL_TEXTENCODING_UTF8 ).getStr() ); OSL_TRACE("Getting Control"); - uno::Reference< awt::XControl > xControl( aEvent.Source, uno::UNO_QUERY_THROW ); - OSL_TRACE("Getting properties"); - uno::Reference< beans::XPropertySet > xProps( xControl->getModel(), uno::UNO_QUERY_THROW ); - rtl::OUString sName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("UserForm") ); OSL_TRACE("Getting Name"); uno::Reference< awt::XDialog > xDlg( aEvent.Source, uno::UNO_QUERY ); if ( !xDlg.is() ) + { + OSL_TRACE("Getting Control"); + // evt.Source is + // a) Dialog + // b) xShapeControl ( from api (sheet control) ) + // c) eventmanager ( I guess ) + // d) vba control ( from api also ) + uno::Reference< drawing::XControlShape > xCntrlShape( evt.Source, uno::UNO_QUERY ); + uno::Reference< awt::XControl > xControl( aEvent.Source, uno::UNO_QUERY ); + if ( xCntrlShape.is() ) + { + // for sheet controls ( that fire from the api ) we don't + // have the real control ( thats only available from the view ) + // api code creates just a control instance that is transferred + // via aEvent.Arguments[ 0 ] that control though has no + // info like name etc. + uno::Reference< drawing::XControlShape > xCntrlShape( evt.Source, UNO_QUERY_THROW ); + OSL_TRACE("Got control shape"); + uno::Reference< container::XNamed > xName( xCntrlShape->getControl(), uno::UNO_QUERY_THROW ); + OSL_TRACE("Got xnamed "); + sName = xName->getName(); + } + else + { + // Userform control ( fired from the api or from event manager ) + uno::Reference< beans::XPropertySet > xProps; + OSL_TRACE("Getting properties"); + xProps.set( xControl->getModel(), uno::UNO_QUERY_THROW ); xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) ) >>= sName; + } + + } //dumpEvent( evt ); EventInfoHash& infos = getEventTransInfo(); EventInfoHash::const_iterator eventInfo_it = infos.find( evt.MethodName ); @@ -885,20 +1056,49 @@ EventListener::firing_Impl(const ScriptEvent& evt, Any* /*pRet*/ ) throw(Runtime std::list< TranslateInfo >::const_iterator txInfo = eventInfo_it->second.begin(); std::list< TranslateInfo >::const_iterator txInfo_end = eventInfo_it->second.end(); - rtl::OUString sMacroLoc = rtl::OUString::createFromAscii("Standard.").concat( evt.ScriptCode ).concat( rtl::OUString::createFromAscii(".") ); - + StarBASIC* pBasic = mpShell->GetBasic(); - SbModule* pModule = pBasic->FindModule( evt.ScriptCode ); - for ( ; pModule && txInfo != txInfo_end; ++txInfo ) + BasicManager* pBasicManager = mpShell->GetBasicManager(); + rtl::OUString sProject; + rtl::OUString sScriptCode( evt.ScriptCode ); + // dialogs pass their own library, presence of Dot determines that + if ( sScriptCode.indexOf( '.' ) == -1 ) + { + //'Project' is a better default but I want to force failures + //rtl::OUString sMacroLoc = rtl::OUString::createFromAscii("Project"); + sProject = rtl::OUString::createFromAscii("Standard"); + + if ( pBasicManager->GetName().Len() > 0 ) + sProject = pBasicManager->GetName(); + } + else + { + sal_Int32 nIndex = sScriptCode.indexOf( '.' ); + sProject = sScriptCode.copy( 0, nIndex ); + sScriptCode = sScriptCode.copy( nIndex + 1 ); + } + rtl::OUString sMacroLoc = sProject; + sMacroLoc = sMacroLoc.concat( rtl::OUString::createFromAscii(".") ); + sMacroLoc = sMacroLoc.concat( sScriptCode ).concat( rtl::OUString::createFromAscii(".") ); + + OSL_TRACE("sMacroLoc is %s", rtl::OUStringToOString( sMacroLoc, RTL_TEXTENCODING_UTF8 ).getStr() ); + for ( ; txInfo != txInfo_end; ++txInfo ) { + // If the document is closed, we should not execute macro. + if (m_bDocClosed) + { + break; + } + + rtl::OUString sTemp = sName.concat( (*txInfo).sVBAName ); // see if we have a match for the handlerextension - // where ScriptCode is methodname_handlerextension - rtl::OUString sTemp = sName.concat( (*txInfo).sVBAName ); - + // where ScriptCode is methodname_handlerextension + rtl::OUString sToResolve = sMacroLoc.concat( sTemp ); + OSL_TRACE("*** trying to invoke %s ", - rtl::OUStringToOString( sTemp, RTL_TEXTENCODING_UTF8 ).getStr() ); - SbMethod* pMeth = static_cast< SbMethod* >( pModule->Find( sTemp, SbxCLASS_METHOD ) ); - if ( pMeth ) + rtl::OUStringToOString( sToResolve, RTL_TEXTENCODING_UTF8 ).getStr() ); + ooo::vba::VBAMacroResolvedInfo aMacroResolvedInfo = ooo::vba::resolveVBAMacro( mpShell, sToResolve ); + if ( aMacroResolvedInfo.IsResolved() ) { //liuchen 2009-6-8 if (! txInfo->ApproveRule(evt, txInfo->pPara) ) @@ -906,7 +1106,7 @@ EventListener::firing_Impl(const ScriptEvent& evt, Any* /*pRet*/ ) throw(Runtime continue; } //liuchen 2009-6-8 - // !! translate arguments & emulate events where necessary + // !! translate arguments & emulate events where necessary Sequence< Any > aArguments; if ( (*txInfo).toVBA ) aArguments = (*txInfo).toVBA( evt.Arguments ); @@ -916,31 +1116,28 @@ EventListener::firing_Impl(const ScriptEvent& evt, Any* /*pRet*/ ) throw(Runtime { // call basic event handlers for event - static rtl::OUString part1 = rtl::OUString::createFromAscii( "vnd.sun.star.script:"); - static rtl::OUString part2 = rtl::OUString::createFromAscii("?language=Basic&location=document"); - // create script url - rtl::OUString url = part1 + sMacroLoc + sTemp + part2; - - OSL_TRACE("script url = %s", - rtl::OUStringToOString( url, + rtl::OUString url = aMacroResolvedInfo.ResolvedMacro(); + + OSL_TRACE("resolved script = %s", + rtl::OUStringToOString( url, RTL_TEXTENCODING_UTF8 ).getStr() ); - Sequence< sal_Int16 > aOutArgsIndex; - Sequence< Any > aOutArgs; try { - if ( mpShell ) + uno::Any aDummyCaller = uno::makeAny( rtl::OUString::createFromAscii("Error") ); + if ( pRet ) + ooo::vba::executeMacro( mpShell, url, aArguments, *pRet, aDummyCaller ); + else { uno::Any aRet; - mpShell->CallXScript( url, - aArguments, aRet, aOutArgsIndex, aOutArgs, false ); + ooo::vba::executeMacro( mpShell, url, aArguments, aRet, aDummyCaller ); } } catch ( uno::Exception& e ) { OSL_TRACE("event script raised %s", rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); } - } + } } } } @@ -959,29 +1156,29 @@ public: virtual Reference< XScriptEventsSupplier > SAL_CALL getEventSupplier( const Reference< XInterface >& xControl, const rtl::OUString& sCodeName ) throw (::com::sun::star::uno::RuntimeException); private: Reference< XComponentContext > m_xContext; - + }; VBAToOOEventDescGen::VBAToOOEventDescGen( const Reference< XComponentContext >& rxContext ):m_xContext( rxContext ) {} -Sequence< ScriptEventDescriptor > SAL_CALL +Sequence< ScriptEventDescriptor > SAL_CALL VBAToOOEventDescGen::getEventDescriptions( const Reference< XInterface >& xControl, const rtl::OUString& sCodeName ) throw (RuntimeException) { - ScriptEventHelper evntHelper( xControl ); - return evntHelper.createEvents( sCodeName ); + ScriptEventHelper evntHelper( xControl ); + return evntHelper.createEvents( sCodeName ); } -Reference< XScriptEventsSupplier > SAL_CALL +Reference< XScriptEventsSupplier > SAL_CALL VBAToOOEventDescGen::getEventSupplier( const Reference< XInterface >& xControl, const rtl::OUString& sCodeName ) throw (::com::sun::star::uno::RuntimeException) { - ScriptEventHelper evntHelper( xControl ); - Reference< XScriptEventsSupplier > xSupplier = - new ReadOnlyEventsSupplier( + ScriptEventHelper evntHelper( xControl ); + Reference< XScriptEventsSupplier > xSupplier = + new ReadOnlyEventsSupplier( evntHelper.getEventListeners(), sCodeName ) ; return xSupplier; } -// Component related +// Component related namespace evtlstner { @@ -1011,9 +1208,9 @@ namespace evtlstner { const ::rtl::OUString strName( ::evtlstner::getImplementationName() ); return Sequence< ::rtl::OUString >( &strName, 1 ); - } + } } -namespace ooevtdescgen +namespace ooevtdescgen { ::rtl::OUString SAL_CALL getImplementationName() { @@ -1041,5 +1238,5 @@ namespace ooevtdescgen { const ::rtl::OUString strName( ::ooevtdescgen::getImplementationName() ); return Sequence< ::rtl::OUString >( &strName, 1 ); - } + } } |