Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index



On 11/05/12 11:16, Noel Power wrote:
would be very handy to have these in 3.5, these are a bunch of *mostly* vba api implementations ( some cases partial ) and as such should pose little/no risk to the core code. Please cherry pick

Noel

details...
[...]
0006-vba-implementation-for-Application.OnKey.patch ( backport ( and squash ) of master 75fbed472cd689c8cc0b89e13a97969d77a0ea7c & master 14620c3b33cf0315a9b746a0a2418b78d6154821 - impacts a few things, the api part should be safe, there is additionally some tweaking of vbamodule import to try and import the keybinding if it exists, should be ok
I attach a new version here ( I got caught with using the new OUString( char& ) ctor as patch was grabbed from master )
From a1d3cb47d2fd49ac06a49725f5ceac1376a1138d Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power@novell.com>
Date: Mon, 5 Mar 2012 14:54:04 +0000
Subject: [PATCH 6/7] vba implementation for Application.OnKey

support import of key shortcut for macro ( Excel only )
---
 filter/inc/filter/msfilter/msvbahelper.hxx        |    6 +-
 filter/source/msfilter/msvbahelper.cxx            |  176 +++++++++++++++++++++
 oovbaapi/ooo/vba/XApplicationBase.idl             |    2 +-
 oox/source/ole/vbamodule.cxx                      |   36 ++++-
 vbahelper/inc/vbahelper/vbaapplicationbase.hxx    |    1 +
 vbahelper/source/vbahelper/vbaapplicationbase.cxx |   23 +++
 6 files changed, 240 insertions(+), 4 deletions(-)

diff --git a/filter/inc/filter/msfilter/msvbahelper.hxx b/filter/inc/filter/msfilter/msvbahelper.hxx
index affc8b2..e7e6533 100644
--- a/filter/inc/filter/msfilter/msvbahelper.hxx
+++ b/filter/inc/filter/msfilter/msvbahelper.hxx
@@ -33,8 +33,9 @@
 #include <com/sun/star/lang/XInitialization.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
 #include <com/sun/star/script/vba/XVBAMacroResolver.hpp>
+#include <com/sun/star/awt/KeyEvent.hpp>
+#include <com/sun/star/frame/XModel.hpp>
 #include "filter/msfilter/msfilterdllapi.h"
-
 namespace ooo {
 namespace vba {
 
@@ -55,7 +56,8 @@ MSFILTER_DLLPUBLIC ::rtl::OUString getDefaultProjectName( SfxObjectShell* pShell
 MSFILTER_DLLPUBLIC ::rtl::OUString resolveVBAMacro( SfxObjectShell* pShell, const ::rtl::OUString& 
rLibName, const ::rtl::OUString& rModuleName, const ::rtl::OUString& rMacroName );
 MSFILTER_DLLPUBLIC MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const 
::rtl::OUString& rMacroName, bool bSearchGlobalTemplates = false );
 MSFILTER_DLLPUBLIC sal_Bool executeMacro( SfxObjectShell* pShell, const String& sMacroName, 
com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aArgs, com::sun::star::uno::Any& aRet, 
const com::sun::star::uno::Any& aCaller );
-
+MSFILTER_DLLPUBLIC ::com::sun::star::awt::KeyEvent parseKeyEvent( const ::rtl::OUString& sKey ) 
throw (::com::sun::star::uno::RuntimeException);
+MSFILTER_DLLPUBLIC void applyShortCutKeyBinding ( const ::com::sun::star::uno::Reference< 
com::sun::star::frame::XModel >& rxDoc, const ::com::sun::star::awt::KeyEvent& rKeyEvent, const 
::rtl::OUString& sMacro ) throw (::com::sun::star::uno::RuntimeException);
 // ============================================================================
 
 typedef ::cppu::WeakImplHelper3<
diff --git a/filter/source/msfilter/msvbahelper.cxx b/filter/source/msfilter/msvbahelper.cxx
index ca0288f..962d211 100644
--- a/filter/source/msfilter/msvbahelper.cxx
+++ b/filter/source/msfilter/msvbahelper.cxx
@@ -42,6 +42,12 @@
 #include <osl/file.hxx>
 #include <unotools/pathoptions.hxx>
 
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <svtools/acceleratorexecute.hxx>
+#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XUIConfigurationManager.hpp>
+#include <map>
+
 using namespace ::com::sun::star;
 
 namespace ooo {
@@ -581,6 +587,176 @@ void SAL_CALL VBAMacroResolver::initialize( const uno::Sequence< uno::Any >& 
rAr
     throw uno::RuntimeException();
 }
 
+bool getModifier( char c, sal_uInt16& mod )
+{
+    static const char modifiers[] = "+^%";
+    static const sal_uInt16 KEY_MODS[] = {KEY_SHIFT, KEY_MOD1, KEY_MOD2};
+
+    for ( unsigned int i=0; i<SAL_N_ELEMENTS(modifiers); ++i )
+    {
+        if ( c == modifiers[i] )
+        {
+            mod = mod | KEY_MODS[ i ];
+            return true;
+        }
+    }
+    return false;
+}
+
+typedef std::map< rtl::OUString, sal_uInt16 > MSKeyCodeMap;
+
+sal_uInt16 parseChar( char c ) throw ( uno::RuntimeException )
+{
+    sal_uInt16 nVclKey = 0;
+    // do we care about locale here for isupper etc. ? probably not
+    if ( isalpha( c ) )
+    {
+        nVclKey |= ( toupper( c ) - 'A' ) + KEY_A;
+        if ( isupper( c ) )
+            nVclKey |= KEY_SHIFT;
+    }
+    else if ( isdigit( c ) )
+        nVclKey |= ( c  - '0' ) + KEY_0;
+    else if ( c == '~' ) // special case
+        nVclKey = KEY_RETURN;
+    else if ( c == ' ' ) // special case
+        nVclKey = KEY_SPACE;
+    else // I guess we have a problem ( but not sure if locale specific keys might come into play 
here )
+        throw uno::RuntimeException();
+    return nVclKey;
+}
+
+struct KeyCodeEntry
+{
+   const char* sName;
+   sal_uInt16 nCode;
+};
+
+KeyCodeEntry aMSKeyCodesData[] = {
+    { "BACKSPACE", KEY_BACKSPACE },
+    { "BS", KEY_BACKSPACE },
+    { "DELETE", KEY_DELETE },
+    { "DEL", KEY_DELETE },
+    { "DOWN", KEY_DOWN },
+    { "UP", KEY_UP },
+    { "LEFT", KEY_LEFT },
+    { "RIGHT", KEY_RIGHT },
+    { "END", KEY_END },
+    { "ESCAPE", KEY_ESCAPE },
+    { "ESC", KEY_ESCAPE },
+    { "HELP", KEY_HELP },
+    { "HOME", KEY_HOME },
+    { "PGDN", KEY_PAGEDOWN },
+    { "PGUP", KEY_PAGEUP },
+    { "INSERT", KEY_INSERT },
+    { "SCROLLLOCK", KEY_SCROLLLOCK },
+    { "NUMLOCK", KEY_NUMLOCK },
+    { "TAB", KEY_TAB },
+    { "F1", KEY_F1 },
+    { "F2", KEY_F2 },
+    { "F3", KEY_F3 },
+    { "F4", KEY_F4 },
+    { "F5", KEY_F5 },
+    { "F6", KEY_F6 },
+    { "F7", KEY_F7 },
+    { "F8", KEY_F8 },
+    { "F9", KEY_F1 },
+    { "F10", KEY_F10 },
+    { "F11", KEY_F11 },
+    { "F12", KEY_F12 },
+    { "F13", KEY_F13 },
+    { "F14", KEY_F14 },
+    { "F15", KEY_F15 },
+};
+
+awt::KeyEvent parseKeyEvent( const ::rtl::OUString& Key ) throw ( uno::RuntimeException )
+{
+    static MSKeyCodeMap msKeyCodes;
+    if ( msKeyCodes.empty() )
+    {
+        for ( unsigned int i = 0; i < SAL_N_ELEMENTS( aMSKeyCodesData ); ++i )
+        {
+            msKeyCodes[ rtl::OUString::createFromAscii( aMSKeyCodesData[ i ].sName ) ] = 
aMSKeyCodesData[ i ].nCode;
+        }
+    }
+    rtl::OUString sKeyCode;
+    sal_uInt16 nVclKey = 0;
+
+    // parse the modifier if any
+    for ( int i=0; i<Key.getLength(); ++i )
+    {
+        if ( ! getModifier( Key[ i ], nVclKey ) )
+        {
+            sKeyCode = Key.copy( i );
+            break;
+        }
+    }
+
+    // check if keycode is surrounded by '{}', if so scoop out the contents
+    // else it should be just one char of ( 'a-z,A-Z,0-9' )
+    if ( sKeyCode.getLength() == 1 ) // ( a single char )
+    {
+        char c = (char)( sKeyCode[ 0 ] );
+        nVclKey |= parseChar( c );
+    }
+    else // key should be enclosed in '{}'
+    {
+        if ( sKeyCode.getLength() < 3 ||  !( sKeyCode[0] == '{' && sKeyCode[sKeyCode.getLength() - 
1 ] == '}' ) )
+            throw uno::RuntimeException();
+
+        sKeyCode = sKeyCode.copy(1, sKeyCode.getLength() - 2 );
+
+        if ( sKeyCode.getLength() == 1 )
+            nVclKey |= parseChar( (char)( sKeyCode[ 0 ] ) );
+        else
+        {
+            MSKeyCodeMap::iterator it = msKeyCodes.find( sKeyCode );
+            if ( it == msKeyCodes.end() ) // unknown or unsupported
+                throw uno::RuntimeException();
+            nVclKey |= it->second;
+        }
+    }
+
+    awt::KeyEvent aKeyEvent = svt::AcceleratorExecute::st_VCLKey2AWTKey( KeyCode( nVclKey ) );
+    return aKeyEvent;
+}
+
+void applyShortCutKeyBinding ( const uno::Reference< frame::XModel >& rxModel, const 
awt::KeyEvent& rKeyEvent, const ::rtl::OUString& rMacroName ) throw (uno::RuntimeException)
+{
+    rtl::OUString MacroName( rMacroName );
+    if ( !MacroName.isEmpty() )
+    {
+        ::rtl::OUString sSeparator(RTL_CONSTASCII_USTRINGPARAM("/"));
+        ::rtl::OUString sMacroSeparator(RTL_CONSTASCII_USTRINGPARAM("!"));
+        ::rtl::OUString aMacroName = MacroName.trim();
+        if (0 == aMacroName.indexOf('!'))
+            MacroName = aMacroName.copy(1).trim();
+        SfxObjectShell* pShell = NULL;
+        if ( rxModel.is() )
+        {
+            uno::Reference< lang::XUnoTunnel >  xObjShellTunnel( rxModel, uno::UNO_QUERY_THROW );
+            pShell = reinterpret_cast<SfxObjectShell*>( 
xObjShellTunnel->getSomething(SfxObjectShell::getUnoTunnelId()));
+            if ( !pShell )
+                throw uno::RuntimeException();
+        }
+        MacroResolvedInfo aMacroInfo = resolveVBAMacro( pShell, aMacroName );
+        if( !aMacroInfo.mbFound )
+            throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("The procedure 
doesn't exist") ), uno::Reference< uno::XInterface >() );
+       MacroName = aMacroInfo.msResolvedMacro;
+    }
+    uno::Reference< ui::XUIConfigurationManagerSupplier > xCfgSupplier(rxModel, 
uno::UNO_QUERY_THROW);
+    uno::Reference< ui::XUIConfigurationManager > xCfgMgr = 
xCfgSupplier->getUIConfigurationManager();
+
+    uno::Reference< ui::XAcceleratorConfiguration > xAcc( xCfgMgr->getShortCutManager(), 
uno::UNO_QUERY_THROW );
+    if ( MacroName.isEmpty() )
+        // I believe this should really restore the [application] default. Since
+        // afaik we don't actually setup application default bindings on import
+        // we don't even know what the 'default' would be for this key
+        xAcc->removeKeyEvent( rKeyEvent );
+    else
+        xAcc->setKeyEvent( rKeyEvent, ooo::vba::makeMacroURL( MacroName ) );
+
+}
 // ============================================================================
 
 } // namespace vba
diff --git a/oovbaapi/ooo/vba/XApplicationBase.idl b/oovbaapi/ooo/vba/XApplicationBase.idl
index d46eb24..93f39ae 100644
--- a/oovbaapi/ooo/vba/XApplicationBase.idl
+++ b/oovbaapi/ooo/vba/XApplicationBase.idl
@@ -47,7 +47,7 @@ interface XApplicationBase
     [attribute, readonly] any VBE;
 
     void Quit();
-
+    void OnKey( [in] string Key, [in] any Procedure );
     any CommandBars( [in] any Index );
     any Run([in] string MacroName, [in] /*Optional*/ any varg1, [in] /*Optional*/ any varg2, [in] 
/*Optional*/ any varg3, [in] /*Optional*/ any varg4, [in] /*Optional*/ any varg5, [in] /*Optional*/ 
any varg6, [in] /*Optional*/ any varg7, [in] /*Optional*/ any varg8, [in] /*Optional*/ any varg9, 
[in] /*Optional*/ any varg10, [in] /*Optional*/ any varg11, [in] /*Optional*/ any varg12, [in] 
/*Optional*/ any varg13, [in] /*Optional*/ any varg14, [in] /*Optional*/ any varg15, [in] 
/*Optional*/ any varg16, [in] /*Optional*/ any varg17, [in] /*Optional*/ any varg18, [in] 
/*Optional*/ any varg19, [in] /*Optional*/ any varg20, [in] /*Optional*/ any varg21, [in] 
/*Optional*/ any varg22, [in] /*Optional*/ any varg23, [in] /*Optional*/ any varg24, [in] 
/*Optional*/ any varg25, [in] /*Optional*/ any varg26, [in] /*Optional*/ any varg27, [in] 
/*Optional*/ any varg28, [in] /*Optional*/ any varg29, [in] /*Optional*/ any varg30);
     void OnTime( [in] any EarliestTime, [in] string Procedure, [in] any LatestTime, [in] any 
Schedule );
diff --git a/oox/source/ole/vbamodule.cxx b/oox/source/ole/vbamodule.cxx
index cbd9744..5672f59 100644
--- a/oox/source/ole/vbamodule.cxx
+++ b/oox/source/ole/vbamodule.cxx
@@ -33,7 +33,9 @@
 #include <com/sun/star/script/ModuleInfo.hpp>
 #include <com/sun/star/script/ModuleType.hpp>
 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
+#include <com/sun/star/awt/KeyEvent.hpp>
 #include <cppuhelper/implbase1.hxx>
+#include <filter/msfilter/msvbahelper.hxx>
 #include "oox/helper/binaryinputstream.hxx"
 #include "oox/helper/storagebase.hxx"
 #include "oox/helper/textinputstream.hxx"
@@ -54,6 +56,7 @@ using namespace ::com::sun::star::uno;
 
 using ::rtl::OUString;
 using ::rtl::OUStringBuffer;
+using ::com::sun::star::awt::KeyEvent;
 // ============================================================================
 typedef ::cppu::WeakImplHelper1< XIndexContainer > OleIdToNameContainer_BASE;
 typedef boost::unordered_map< sal_Int32, rtl::OUString >  ObjIdToName;
@@ -237,7 +240,38 @@ OUString VbaModule::readSourceCode( StorageBase& rVbaStrg, const Reference< 
XNam
                 if( aCodeLine.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "Attribute " ) ) )
                 {
                     // attribute
-                    extractOleOverrideFromAttr( aCodeLine, rxOleNameOverrides );
+                    int index = aCodeLine.indexOf( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 
".VB_ProcData.VB_Invoke_Func = " ) ) );
+                    if ( index != -1 )
+                    {
+                        // format is
+                        //    'Attribute Procedure.VB_ProcData.VB_Invoke_Func = "*\n14"'
+                        //    where 'Procedure' is the procedure name and '*' is the shortcut key
+                        // note: his is only relevant for Excel, seems that
+                        // word doesn't store the shortcut in the module
+                        // attributes
+                        int nSpaceIndex = aCodeLine.indexOf(' ');
+                        rtl::OUString sProc = aCodeLine.copy( nSpaceIndex + 1, index - nSpaceIndex 
- 1);
+                        // for Excel short cut key seems limited to cntrl+'a-z, A-Z'
+                        rtl::OUString sKey = aCodeLine.copy( aCodeLine.lastIndexOf( rtl::OUString( 
RTL_CONSTASCII_USTRINGPARAM( "= ") ) )+ 3, 1 );
+                        // only alpha key valid for key shortcut, however the api will accept 
other keys
+                        if ( !isalpha( (char)sKey[ 0 ] ) )
+                        {
+                            // cntrl modifier is explicit ( but could be cntrl+shift ), 
parseKeyEvent
+                            // will handle and uppercase letter appropriately
+                            rtl::OUString sApiKey( RTL_CONSTASCII_USTRINGPARAM( "^" ) );
+                            sApiKey += sKey;
+                            try
+                            {
+                                KeyEvent aKeyEvent = ooo::vba::parseKeyEvent( sApiKey );
+                                ooo::vba::applyShortCutKeyBinding( mxDocModel, aKeyEvent, sProc );
+                            }
+                            catch( Exception& )
+                            {
+                            }
+                        }
+                    }
+                    else
+                        extractOleOverrideFromAttr( aCodeLine, rxOleNameOverrides );
                 }
                 else
                 {
diff --git a/vbahelper/inc/vbahelper/vbaapplicationbase.hxx 
b/vbahelper/inc/vbahelper/vbaapplicationbase.hxx
index 7d21d3e..a27afa5 100644
--- a/vbahelper/inc/vbahelper/vbaapplicationbase.hxx
+++ b/vbahelper/inc/vbahelper/vbaapplicationbase.hxx
@@ -58,6 +58,7 @@ public:
     virtual void SAL_CALL setInteractive( ::sal_Bool bInteractive ) throw 
(css::uno::RuntimeException);
     virtual ::sal_Bool SAL_CALL getVisible() throw (css::uno::RuntimeException);
     virtual void SAL_CALL setVisible( ::sal_Bool bVisible ) throw (css::uno::RuntimeException);
+    virtual void SAL_CALL OnKey( const ::rtl::OUString& Key, const ::com::sun::star::uno::Any& 
Procedure ) throw (::com::sun::star::uno::RuntimeException);
     virtual css::uno::Any SAL_CALL CommandBars( const css::uno::Any& aIndex ) throw 
(css::uno::RuntimeException);
     virtual ::rtl::OUString SAL_CALL getVersion() throw (css::uno::RuntimeException);
     virtual css::uno::Any SAL_CALL getVBE() throw (css::uno::RuntimeException);
diff --git a/vbahelper/source/vbahelper/vbaapplicationbase.cxx 
b/vbahelper/source/vbahelper/vbaapplicationbase.cxx
index 162ea28..039494c 100644
--- a/vbahelper/source/vbahelper/vbaapplicationbase.cxx
+++ b/vbahelper/source/vbahelper/vbaapplicationbase.cxx
@@ -277,6 +277,29 @@ void SAL_CALL VbaApplicationBase::setVisible( sal_Bool bVisible ) throw 
(uno::Ru
     m_pImpl->mbVisible = bVisible;  // dummy implementation
 }
 
+
+void SAL_CALL
+VbaApplicationBase::OnKey( const ::rtl::OUString& Key, const uno::Any& Procedure ) throw 
(uno::RuntimeException)
+{
+    // parse the Key & modifiers
+    awt::KeyEvent aKeyEvent = parseKeyEvent( Key );
+    rtl::OUString MacroName;
+    Procedure >>= MacroName;
+    uno::Reference< frame::XModel > xModel;
+    SbMethod* pMeth = StarBASIC::GetActiveMethod();
+    if ( pMeth )
+    {
+        SbModule* pMod = dynamic_cast< SbModule* >( pMeth->GetParent() );
+        if ( pMod )
+            xModel = StarBASIC::GetModelFromBasic( pMod );
+    }
+
+    if ( !xModel.is() )
+        xModel = getCurrentDocument();
+
+    applyShortCutKeyBinding( xModel, aKeyEvent, MacroName );
+}
+
 uno::Any SAL_CALL
 VbaApplicationBase::CommandBars( const uno::Any& aIndex ) throw (uno::RuntimeException)
 {
-- 
1.7.3.4


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.