| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_scripting.hxx" |
| #include <comphelper/processfactory.hxx> |
| #include <comphelper/uno3.hxx> |
| #include <comphelper/proparrhlp.hxx> |
| #include <comphelper/propertycontainer.hxx> |
| |
| #include <ooo/vba/XVBAToOOEventDescGen.hpp> |
| |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <com/sun/star/beans/XIntrospection.hpp> |
| #include <com/sun/star/beans/PropertyAttribute.hpp> |
| |
| #include <com/sun/star/lang/XMultiComponentFactory.hpp> |
| #include <com/sun/star/lang/XServiceName.hpp> |
| #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/drawing/XControlShape.hpp> |
| |
| #include <com/sun/star/awt/XControl.hpp> |
| #include <com/sun/star/awt/XDialog.hpp> |
| #include <com/sun/star/awt/KeyEvent.hpp> |
| #include <com/sun/star/awt/MouseEvent.hpp> |
| #include <com/sun/star/awt/XFixedText.hpp> //liuchen 2009-6-5 |
| #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 <msforms/ReturnInteger.hpp> |
| |
| #include <sfx2/objsh.hxx> |
| #include <basic/sbstar.hxx> |
| #include <basic/basmgr.hxx> |
| #include <basic/sbmeth.hxx> |
| #include <basic/sbmod.hxx> |
| #include <basic/sbx.hxx> |
| |
| |
| |
| |
| // for debug |
| #include <comphelper/anytostring.hxx> |
| |
| |
| #include <com/sun/star/lang/XMultiComponentFactory.hpp> |
| #include <com/sun/star/script/XScriptListener.hpp> |
| #include <cppuhelper/implbase1.hxx> |
| #include <cppuhelper/implbase3.hxx> |
| #include <comphelper/evtmethodhelper.hxx> |
| |
| #include <set> |
| #include <list> |
| #include <hash_map> |
| |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::script; |
| using namespace ::com::sun::star::uno; |
| 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 |
| const static rtl::OUString DELIM = rtl::OUString::createFromAscii( "::" ); |
| const static sal_Int32 DELIMLEN = DELIM.getLength(); |
| |
| #if 0 |
| void dumpListeners( const Reference< beans::XIntrospection >& xIntrospection, const Reference<XInterface>& xIfc) |
| { |
| Reference< beans::XIntrospectionAccess > xIntrospectionAccess; |
| if ( xIntrospection.is() ) |
| { |
| xIntrospectionAccess = xIntrospection->inspect( |
| makeAny( xIfc ) ); |
| Sequence< Type > aControlListeners = |
| xIntrospectionAccess->getSupportedListeners(); |
| sal_Int32 nLength = aControlListeners.getLength(); |
| |
| for ( sal_Int32 i = 0; i< nLength; ++i ) |
| { |
| Type& listType = aControlListeners[ i ]; |
| rtl::OUString sFullTypeName = listType.getTypeName(); |
| rtl::OUString sTypeName = listType.getTypeName(); |
| sal_Int32 lastDotIndex = -1; |
| if ( ( lastDotIndex = sFullTypeName.lastIndexOf( '.' ) ) > -1 ) |
| { |
| 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_TEXTENCODING_UTF8 ).getStr(), |
| 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_TEXTENCODING_UTF8 ).getStr() ); |
| |
| OSL_TRACE("dumpEvent: ScriptType %s", |
| rtl::OUStringToOString( evt.ScriptType, |
| RTL_TEXTENCODING_UTF8 ).getStr() ); |
| |
| OSL_TRACE("dumpEvent: ScriptCode %s", |
| rtl::OUStringToOString( evt.ScriptCode, |
| RTL_TEXTENCODING_UTF8 ).getStr() ); |
| |
| OSL_TRACE("dumpEvent: ListenerType %s", |
| rtl::OUStringToOString( evt.ListenerType.getTypeName(), |
| RTL_TEXTENCODING_UTF8 ).getStr() ); |
| |
| OSL_TRACE("dumpEvent: Listener methodname %s", |
| 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 ] ), |
| RTL_TEXTENCODING_UTF8 ).getStr() ); |
| |
| } |
| } |
| |
| #endif |
| |
| bool isKeyEventOk( awt::KeyEvent& evt, const Sequence< Any >& params ) |
| { |
| if ( !( params.getLength() > 0 ) || |
| !( params[ 0 ] >>= evt ) ) |
| return false; |
| return true; |
| } |
| |
| bool isMouseEventOk( awt::MouseEvent& 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)) || |
| (evt.ClickCount != 2) ) |
| return Sequence< Any >(); |
| // give back orig params, this will signal that the event is good |
| return params; |
| } |
| |
| Sequence< Any > ooMouseEvtToVBAMouseEvt( const Sequence< Any >& params ) |
| { |
| Sequence< Any > translatedParams; |
| awt::MouseEvent evt; |
| |
| if ( !isMouseEventOk(evt, params) ) |
| return Sequence< Any >(); |
| |
| translatedParams.realloc(4); |
| |
| // Buttons |
| translatedParams[ 0 ] <<= evt.Buttons; |
| // Shift |
| translatedParams[ 1 ] <<= evt.Modifiers; |
| // X |
| translatedParams[ 2 ] <<= evt.X; |
| // Y |
| translatedParams[ 3 ] <<= evt.Y; |
| return translatedParams; |
| } |
| |
| Sequence< Any > ooKeyPressedToVBAKeyPressed( const Sequence< Any >& params ) |
| { |
| Sequence< Any > translatedParams; |
| awt::KeyEvent evt; |
| |
| if ( !isKeyEventOk( evt, params ) ) |
| return Sequence< Any >(); |
| |
| translatedParams.realloc(1); |
| |
| msforms::ReturnInteger keyCode; |
| keyCode.Value = evt.KeyCode; |
| translatedParams[0] <<= keyCode; |
| return translatedParams; |
| } |
| |
| Sequence< Any > ooKeyPressedToVBAKeyUpDown( const Sequence< Any >& params ) |
| { |
| Sequence< Any > translatedParams; |
| awt::KeyEvent evt; |
| |
| if ( !isKeyEventOk( evt, params ) ) |
| return Sequence< Any >(); |
| |
| translatedParams.realloc(2); |
| |
| msforms::ReturnInteger keyCode; |
| sal_Int8 shift = sal::static_int_cast<sal_Int8>( evt.Modifiers ); |
| |
| // #TODO check whether values from OOO conform to values generated from vba |
| keyCode.Value = evt.KeyCode; |
| translatedParams[0] <<= keyCode; |
| translatedParams[1] <<= shift; |
| return translatedParams; |
| } |
| |
| typedef Sequence< Any > (*Translator)(const Sequence< Any >&); |
| |
| //liuchen 2009-6-23 |
| //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 |
| void *pPara; //Parameters for the above approve method |
| }; |
| |
| |
| typedef std::hash_map< rtl::OUString, |
| std::list< TranslateInfo >, |
| ::rtl::OUStringHash, |
| ::std::equal_to< ::rtl::OUString > > EventInfoHash; |
| |
| //liuchen 2009-6-23 |
| struct TranslatePropMap |
| { |
| rtl::OUString sEventInfo; //OO event name |
| 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 |
| |
| struct TypeList |
| { |
| uno::Type* pTypeList; |
| 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) |
| |
| |
| TypeList fixedTextList = {&typeXFixedText, 1}; |
| TypeList textCompList = {&typeXTextComponent, 1}; |
| TypeList radioButtonList = {&typeXRadioButton, 1}; |
| TypeList comboBoxList = {&typeXComboBox, 1}; |
| |
| //this array stores the OO event to VBA event translation info |
| 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 |
| |
| // 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 |
| |
| // changed ooo event |
| { 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 |
| |
| // adjustmentValueChanged ooo event |
| { MAP_CHAR_LEN("adjustmentValueChanged"), { MAP_CHAR_LEN("_Scroll"), NULL, ApproveAll, NULL } }, |
| { MAP_CHAR_LEN("adjustmentValueChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } }, |
| |
| // textChanged ooo event |
| { MAP_CHAR_LEN("textChanged"), { MAP_CHAR_LEN("_Change"), NULL, ApproveAll, NULL } }, |
| |
| // keyReleased ooo event |
| { MAP_CHAR_LEN("keyReleased"), { MAP_CHAR_LEN("_KeyUp"), ooKeyPressedToVBAKeyUpDown, ApproveAll, NULL } }, |
| |
| // mouseReleased ooo event |
| { MAP_CHAR_LEN("mouseReleased"), { MAP_CHAR_LEN("_Click"), ooMouseEvtToVBAMouseEvt, ApproveType, (void*)(&fixedTextList) } }, //liuchen, add to support VBA Label_Click event |
| { MAP_CHAR_LEN("mouseReleased"), { MAP_CHAR_LEN("_MouseUp"), ooMouseEvtToVBAMouseEvt, ApproveAll, NULL } }, |
| |
| // mousePressed ooo event |
| { 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 |
| { 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 } } |
| }; |
| |
| EventInfoHash& getEventTransInfo() |
| { |
| static bool initialised = false; |
| static EventInfoHash eventTransInfo; |
| if ( !initialised ) |
| { |
| rtl::OUString sEventInfo = MAP_CHAR_LEN(""); |
| TranslatePropMap* pTransProp = aTranslatePropMap_Impl; |
| int nCount = sizeof(aTranslatePropMap_Impl) / sizeof(aTranslatePropMap_Impl[0]); |
| |
| 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; |
| } |
| initialised = true; |
| } |
| return eventTransInfo; |
| } |
| //liuchen 2009-6-23 end |
| |
| // Helper class |
| |
| class ScriptEventHelper |
| { |
| public: |
| ScriptEventHelper( const Reference< XInterface >& xControl ); |
| Sequence< ScriptEventDescriptor > createEvents( const rtl::OUString& sCodeName ); |
| Sequence< rtl::OUString > getEventListeners(); |
| private: |
| Reference< XComponentContext > m_xCtx; |
| Reference< XInterface > m_xControl; |
| }; |
| |
| bool |
| eventMethodToDescriptor( const ::rtl::OUString& rEventMethod, ScriptEventDescriptor& evtDesc, const ::rtl::OUString& sCodeName ) |
| { |
| // format of ControlListener is TypeName::methodname e.g. |
| // "com.sun.star.awt.XActionListener::actionPerformed" or |
| // "XActionListener::actionPerformed |
| |
| ::rtl::OUString sMethodName; |
| ::rtl::OUString sTypeName; |
| sal_Int32 nDelimPos = rEventMethod.indexOf( DELIM ); |
| if ( nDelimPos == -1 ) |
| { |
| return false; |
| } |
| 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() |
| && sTypeName.getLength() |
| && ( infos.find( sMethodName ) != infos.end() ) ) |
| { |
| // 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; |
| evtDesc.ListenerType = sTypeName; |
| evtDesc.EventMethod = sMethodName; |
| |
| // set this it VBAInterop, ensures that it doesn't |
| // get persisted or shown in property editors |
| evtDesc.ScriptType = rtl::OUString::createFromAscii( |
| "VBAInterop" ); |
| return true; |
| } |
| return false; |
| |
| } |
| |
| ScriptEventHelper::ScriptEventHelper( const Reference< XInterface >& xControl ) : m_xControl( xControl ) |
| { |
| Reference < beans::XPropertySet > xProps( |
| ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW ); |
| m_xCtx.set( xProps->getPropertyValue( rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), |
| uno::UNO_QUERY_THROW ); |
| } |
| |
| Sequence< rtl::OUString > |
| ScriptEventHelper::getEventListeners() |
| { |
| 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( |
| RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.Introspection" ) ), m_xCtx ), UNO_QUERY ); |
| #if 0 |
| dumpListeners( xIntrospection, m_xControl ); |
| dumpListeners( xIntrospection, m_xControl->getModel() ); |
| #endif |
| Reference< beans::XIntrospectionAccess > xIntrospectionAccess; |
| if ( xIntrospection.is() ) |
| { |
| xIntrospectionAccess = xIntrospection->inspect( |
| makeAny( m_xControl ) ); |
| Sequence< Type > aControlListeners = |
| xIntrospectionAccess->getSupportedListeners(); |
| 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 ); |
| sal_Int32 sMethLen = sMeths.getLength(); |
| for ( sal_Int32 j=0 ; j < sMethLen; ++j ) |
| { |
| rtl::OUString sEventMethod = sFullTypeName; |
| sEventMethod += DELIM; |
| sEventMethod += sMeths[ j ]; |
| eventMethods.push_back( sEventMethod ); |
| } |
| } |
| |
| } |
| } |
| |
| Sequence< rtl::OUString > sEventMethodNames( eventMethods.size() ); |
| std::list< rtl::OUString >::const_iterator it = eventMethods.begin(); |
| rtl::OUString* pDest = sEventMethodNames.getArray(); |
| |
| for ( ; it != eventMethods.end(); ++it, ++pDest ) |
| *pDest = *it; |
| |
| return sEventMethodNames; |
| } |
| |
| Sequence< ScriptEventDescriptor > |
| ScriptEventHelper::createEvents( const rtl::OUString& sCodeName ) |
| { |
| Sequence< rtl::OUString > aControlListeners = getEventListeners(); |
| rtl::OUString* pSrc = aControlListeners.getArray(); |
| sal_Int32 nLength = aControlListeners.getLength(); |
| |
| Sequence< ScriptEventDescriptor > aDest( nLength ); |
| sal_Int32 nEvts = 0; |
| for ( sal_Int32 i = 0; i< nLength; ++i, ++pSrc ) |
| { |
| // from getListeners eventName is of form |
| // "com.sun.star.awt.XActionListener::actionPerformed" |
| // we need to strip "com.sun.star.awt." from that for form |
| // controls |
| ScriptEventDescriptor evtDesc; |
| if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) ) |
| { |
| sal_Int32 dIndex = nEvts; |
| ++nEvts; |
| if ( nEvts > aDest.getLength() ) |
| aDest.realloc( nEvts );// should never happen |
| aDest[ dIndex ] = evtDesc; |
| } |
| } |
| aDest.realloc( nEvts ); |
| |
| return aDest; |
| } |
| |
| |
| typedef ::cppu::WeakImplHelper1< container::XNameContainer > NameContainer_BASE; |
| |
| class ReadOnlyEventsNameContainer : public NameContainer_BASE |
| { |
| public: |
| ReadOnlyEventsNameContainer( const Sequence< rtl::OUString >& eventMethods, const rtl::OUString& sCodeName ); |
| // XNameContainer |
| |
| 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) |
| { |
| throw RuntimeException( rtl::OUString::createFromAscii( "ReadOnly container" ), Reference< XInterface >() ); |
| } |
| |
| // XNameReplace |
| 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); |
| virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (RuntimeException); |
| |
| // XElementAccess |
| virtual Type SAL_CALL getElementType( ) throw (RuntimeException) |
| { return getCppuType(static_cast< const rtl::OUString * >(0) ); } |
| virtual ::sal_Bool SAL_CALL hasElements( ) throw (RuntimeException) |
| { return ( ( m_hEvents.size() > 0 ? sal_True : sal_False ) ); } |
| private: |
| |
| typedef std::hash_map< rtl::OUString, Any, ::rtl::OUStringHash, |
| ::std::equal_to< ::rtl::OUString > > EventSupplierHash; |
| |
| EventSupplierHash m_hEvents; |
| }; |
| |
| ReadOnlyEventsNameContainer::ReadOnlyEventsNameContainer( const Sequence< rtl::OUString >& eventMethods, const rtl::OUString& sCodeName ) |
| { |
| const rtl::OUString* pSrc = eventMethods.getConstArray(); |
| sal_Int32 nLen = eventMethods.getLength(); |
| for ( sal_Int32 index = 0; index < nLen; ++index, ++pSrc ) |
| { |
| Any aDesc; |
| ScriptEventDescriptor evtDesc; |
| if ( eventMethodToDescriptor( *pSrc, evtDesc, sCodeName ) ) |
| { |
| aDesc <<= evtDesc; |
| m_hEvents[ *pSrc ] = aDesc; |
| } |
| } |
| } |
| |
| 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() ) |
| throw container::NoSuchElementException(); |
| return it->second; |
| } |
| |
| Sequence< ::rtl::OUString > SAL_CALL |
| ReadOnlyEventsNameContainer::getElementNames( ) throw (RuntimeException) |
| { |
| Sequence< ::rtl::OUString > names(m_hEvents.size()); |
| rtl::OUString* pDest = names.getArray(); |
| EventSupplierHash::const_iterator it = m_hEvents.begin(); |
| EventSupplierHash::const_iterator it_end = m_hEvents.end(); |
| for ( sal_Int32 index = 0; it != it_end; ++index, ++pDest, ++it ) |
| *pDest = it->first; |
| return names; |
| } |
| |
| sal_Bool SAL_CALL |
| ReadOnlyEventsNameContainer::hasByName( const ::rtl::OUString& aName ) throw (RuntimeException) |
| { |
| EventSupplierHash::const_iterator it = m_hEvents.find( aName ); |
| if ( it == m_hEvents.end() ) |
| return sal_False; |
| return sal_True; |
| } |
| |
| typedef ::cppu::WeakImplHelper1< XScriptEventsSupplier > EventsSupplier_BASE; |
| |
| 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::WeakImplHelper3< XScriptListener, util::XCloseListener, lang::XInitialization > EventListener_BASE; |
| |
| #define EVENTLSTNR_PROPERTY_ID_MODEL 1 |
| #define EVENTLSTNR_PROPERTY_MODEL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Model" ) ) |
| |
| class EventListener : public EventListener_BASE |
| ,public ::comphelper::OMutexAndBroadcastHelper |
| ,public ::comphelper::OPropertyContainer |
| ,public ::comphelper::OPropertyArrayUsageHelper< EventListener > |
| |
| { |
| |
| public: |
| EventListener( const Reference< XComponentContext >& rxContext ); |
| // XEventListener |
| virtual void SAL_CALL disposing(const lang::EventObject& Source) throw( RuntimeException ); |
| using cppu::OPropertySetHelper::disposing; |
| |
| // 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); |
| // XInitialization |
| virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException); |
| // XInterface |
| DECLARE_XINTERFACE() |
| |
| // XTypeProvider |
| 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(); |
| } |
| |
| protected: |
| // OPropertySetHelper |
| virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper( ); |
| |
| // OPropertyArrayUsageHelper |
| virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const; |
| |
| private: |
| void setShellFromModel(); |
| void firing_Impl( const ScriptEvent& evt, Any *pSyncRet=NULL ) throw( RuntimeException ); |
| |
| Reference< XComponentContext > m_xContext; |
| Reference< frame::XModel > m_xModel; |
| sal_Bool m_bDocClosed; |
| SfxObjectShell* mpShell; |
| |
| }; |
| |
| EventListener::EventListener( const Reference< XComponentContext >& rxContext ) : |
| 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 ) ); |
| |
| } |
| |
| void |
| EventListener::setShellFromModel() |
| { |
| // reset mpShell |
| mpShell = 0; |
| SfxObjectShell* pShell = SfxObjectShell::GetFirst(); |
| while ( m_xModel.is() && pShell ) |
| { |
| if ( pShell->GetModel() == m_xModel ) |
| { |
| mpShell = pShell; |
| break; |
| } |
| pShell = SfxObjectShell::GetNext( *pShell ); |
| } |
| } |
| |
| //XEventListener |
| void |
| EventListener::disposing(const lang::EventObject&) throw( RuntimeException ) |
| { |
| } |
| |
| //XScriptListener |
| |
| void SAL_CALL |
| EventListener::firing(const ScriptEvent& evt) throw(RuntimeException) |
| { |
| firing_Impl( evt ); |
| } |
| |
| Any SAL_CALL |
| EventListener::approveFiring(const ScriptEvent& evt) throw(reflection::InvocationTargetException, RuntimeException) |
| { |
| Any ret; |
| firing_Impl( evt, &ret ); |
| 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 |
| EventListener::initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException) |
| { |
| if ( aArguments.getLength() == 1 ) |
| aArguments[0] >>= m_xModel; |
| OSL_TRACE("EventListener::initialize() args %d m_xModel %d", aArguments.getLength(), m_xModel.is() ); |
| } |
| |
| // XInterface |
| |
| IMPLEMENT_FORWARD_XINTERFACE2( EventListener, EventListener_BASE, OPropertyContainer ) |
| |
| // XTypeProvider |
| |
| IMPLEMENT_FORWARD_XTYPEPROVIDER2( EventListener, EventListener_BASE, OPropertyContainer ) |
| |
| // OPropertySetHelper |
| |
| ::cppu::IPropertyArrayHelper& |
| EventListener::getInfoHelper( ) |
| { |
| return *getArrayHelper(); |
| } |
| |
| // OPropertyArrayUsageHelper |
| |
| ::cppu::IPropertyArrayHelper* |
| EventListener::createArrayHelper( ) const |
| { |
| Sequence< beans::Property > aProps; |
| describeProperties( aProps ); |
| return new ::cppu::OPropertyArrayHelper( aProps ); |
| } |
| |
| // XPropertySet |
| Reference< beans::XPropertySetInfo > |
| EventListener::getPropertySetInfo( ) throw (RuntimeException) |
| { |
| Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); |
| return xInfo; |
| } |
| |
| //liuchen 2009-6-23 |
| //decide if the control should execute the event |
| bool ApproveAll(const ScriptEvent&, void* ) |
| { |
| return true; |
| } |
| |
| //for the given control type in evt.Arguments[0], look for if it appears in the type list in pPara |
| bool FindControl(const ScriptEvent& evt, void* pPara) |
| { |
| lang::EventObject aEvent; |
| evt.Arguments[ 0 ] >>= aEvent; |
| uno::Reference< uno::XInterface > xInterface( aEvent.Source, uno::UNO_QUERY ); |
| |
| TypeList* pTypeListInfo = static_cast<TypeList*>(pPara); |
| Type* pType = pTypeListInfo->pTypeList; |
| int nLen = pTypeListInfo->nListLength; |
| |
| for (int i = 0; i < nLen; i++) |
| { |
| if ( xInterface->queryInterface( *pType ).hasValue() ) |
| { |
| return true; |
| } |
| pType++; |
| } |
| |
| return false; |
| } |
| |
| //if the the given control type in evt.Arguments[0] appears in the type list in pPara, then approve the execution |
| bool ApproveType(const ScriptEvent& evt, void* pPara) |
| { |
| return FindControl(evt, pPara); |
| } |
| |
| //if the the given control type in evt.Arguments[0] appears in the type list in pPara, then deny the execution |
| bool DenyType(const ScriptEvent& evt, void* pPara) |
| { |
| return !FindControl(evt, 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 |
| //pressed can be correctly triggered |
| bool DenyMouseDrag(const ScriptEvent& evt, void* ) |
| { |
| awt::MouseEvent aEvent; |
| evt.Arguments[ 0 ] >>= aEvent; |
| if (aEvent.Buttons == 0 ) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| |
| |
| //liuchen 2009-6-23 |
| // EventListener |
| |
| void |
| EventListener::firing_Impl(const ScriptEvent& evt, Any* /*pRet*/ ) throw(RuntimeException) |
| { |
| OSL_TRACE("EventListener::firing_Impl( FAKE VBA_EVENTS )"); |
| static const ::rtl::OUString vbaInterOp = |
| ::rtl::OUString::createFromAscii("VBAInterop"); |
| |
| // let default handlers deal with non vba stuff |
| if ( !evt.ScriptType.equals( vbaInterOp ) ) |
| return; |
| lang::EventObject aEvent; |
| evt.Arguments[ 0 ] >>= aEvent; |
| 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() ) |
| xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) ) >>= sName; |
| //dumpEvent( evt ); |
| EventInfoHash& infos = getEventTransInfo(); |
| EventInfoHash::const_iterator eventInfo_it = infos.find( evt.MethodName ); |
| EventInfoHash::const_iterator it_end = infos.end(); |
| if ( eventInfo_it == it_end ) |
| { |
| OSL_TRACE("Bogus event for %s", |
| rtl::OUStringToOString( evt.ScriptType, RTL_TEXTENCODING_UTF8 ).getStr() ); |
| return; |
| } |
| |
| uno::Reference< script::provider::XScriptProviderSupplier > xSPS( m_xModel, uno::UNO_QUERY ); |
| uno::Reference< script::provider::XScriptProvider > xScriptProvider; |
| if ( xSPS.is() ) |
| xScriptProvider = xSPS->getScriptProvider(); |
| if ( xScriptProvider.is() && mpShell ) |
| { |
| std::list< TranslateInfo > matchingMethods; |
| 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 ) |
| { |
| // #i106270#: If the document is closed, we should not execute macro. |
| if (m_bDocClosed) |
| { |
| break; |
| } |
| // see if we have a match for the handlerextension |
| // where ScriptCode is methodname_handlerextension |
| rtl::OUString sTemp = sName.concat( (*txInfo).sVBAName ); |
| |
| 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 ) |
| { |
| //liuchen 2009-6-8 |
| if (! txInfo->ApproveRule(evt, txInfo->pPara) ) |
| { |
| continue; |
| } |
| //liuchen 2009-6-8 |
| // !! translate arguments & emulate events where necessary |
| Sequence< Any > aArguments; |
| if ( (*txInfo).toVBA ) |
| aArguments = (*txInfo).toVBA( evt.Arguments ); |
| else |
| aArguments = evt.Arguments; |
| if ( aArguments.getLength() ) |
| { |
| // 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_TEXTENCODING_UTF8 ).getStr() ); |
| Sequence< sal_Int16 > aOutArgsIndex; |
| Sequence< Any > aOutArgs; |
| try |
| { |
| if ( mpShell ) |
| { |
| uno::Any aRet; |
| mpShell->CallXScript( url, |
| aArguments, aRet, aOutArgsIndex, aOutArgs, false ); |
| } |
| } |
| catch ( uno::Exception& e ) |
| { |
| OSL_TRACE("event script raised %s", rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| typedef ::cppu::WeakImplHelper1< XVBAToOOEventDescGen > VBAToOOEventDescGen_BASE; |
| |
| |
| class VBAToOOEventDescGen : public VBAToOOEventDescGen_BASE |
| { |
| public: |
| VBAToOOEventDescGen( const Reference< XComponentContext >& rxContext ); |
| |
| // XVBAToOOEventDescGen |
| virtual Sequence< ScriptEventDescriptor > SAL_CALL getEventDescriptions( const Reference< XInterface >& control, const rtl::OUString& sCodeName ) throw (RuntimeException); |
| 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 |
| VBAToOOEventDescGen::getEventDescriptions( const Reference< XInterface >& xControl, const rtl::OUString& sCodeName ) throw (RuntimeException) |
| { |
| ScriptEventHelper evntHelper( xControl ); |
| return evntHelper.createEvents( sCodeName ); |
| } |
| |
| 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( |
| evntHelper.getEventListeners(), sCodeName ) ; |
| return xSupplier; |
| } |
| |
| // Component related |
| |
| namespace evtlstner |
| { |
| ::rtl::OUString SAL_CALL getImplementationName() |
| { |
| static ::rtl::OUString* pImplName = 0; |
| if ( !pImplName ) |
| { |
| ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); |
| if ( !pImplName ) |
| { |
| static ::rtl::OUString aImplName( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.EventListener" ) ); |
| pImplName = &aImplName; |
| } |
| } |
| return *pImplName; |
| } |
| |
| uno::Reference< XInterface > SAL_CALL create( |
| Reference< XComponentContext > const & xContext ) |
| SAL_THROW( () ) |
| { |
| return static_cast< lang::XTypeProvider * >( new EventListener( xContext ) ); |
| } |
| |
| Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() |
| { |
| const ::rtl::OUString strName( ::evtlstner::getImplementationName() ); |
| return Sequence< ::rtl::OUString >( &strName, 1 ); |
| } |
| } |
| namespace ooevtdescgen |
| { |
| ::rtl::OUString SAL_CALL getImplementationName() |
| { |
| static ::rtl::OUString* pImplName = 0; |
| if ( !pImplName ) |
| { |
| ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); |
| if ( !pImplName ) |
| { |
| static ::rtl::OUString aImplName( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAToOOEventDesc" ) ); |
| pImplName = &aImplName; |
| } |
| } |
| return *pImplName; |
| } |
| |
| uno::Reference< XInterface > SAL_CALL create( |
| Reference< XComponentContext > const & xContext ) |
| SAL_THROW( () ) |
| { |
| return static_cast< lang::XTypeProvider * >( new VBAToOOEventDescGen( xContext ) ); |
| } |
| |
| Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() |
| { |
| const ::rtl::OUString strName( ::ooevtdescgen::getImplementationName() ); |
| return Sequence< ::rtl::OUString >( &strName, 1 ); |
| } |
| } |