1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <filter/msfilter/msvbahelper.hxx>
21 #include <basic/sbx.hxx>
22 #include <basic/sbstar.hxx>
23 #include <basic/basmgr.hxx>
24 #include <basic/sbmod.hxx>
25 #include <basic/sbmeth.hxx>
26 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
27 #include <com/sun/star/document/XDocumentProperties.hpp>
28 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
29 #include <com/sun/star/lang/XUnoTunnel.hpp>
30 #include <com/sun/star/script/ModuleType.hpp>
31 #include <tools/urlobj.hxx>
32 #include <osl/file.hxx>
33 #include <unotools/pathoptions.hxx>
35 #include <com/sun/star/awt/KeyModifier.hpp>
36 #include <svtools/acceleratorexecute.hxx>
37 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
38 #include <com/sun/star/ui/XUIConfigurationManager.hpp>
41 using namespace ::com::sun::star
;
46 const OUString
sUrlPart0( "vnd.sun.star.script:" );
47 const OUString
sUrlPart1( "?language=Basic&location=document" );
49 OUString
makeMacroURL( const OUString
& sMacroName
)
51 return sUrlPart0
+ sMacroName
+ sUrlPart1
;
54 OUString
extractMacroName( const OUString
& rMacroUrl
)
56 if( (rMacroUrl
.getLength() > sUrlPart0
.getLength() + sUrlPart1
.getLength()) &&
57 rMacroUrl
.match( sUrlPart0
) &&
58 rMacroUrl
.match( sUrlPart1
, rMacroUrl
.getLength() - sUrlPart1
.getLength() ) )
60 return rMacroUrl
.copy( sUrlPart0
.getLength(),
61 rMacroUrl
.getLength() - sUrlPart0
.getLength() - sUrlPart1
.getLength() );
66 OUString
trimMacroName( const OUString
& rMacroName
)
68 // the name may contain whitespaces and may be enclosed in apostrophs
69 OUString aMacroName
= rMacroName
.trim();
70 sal_Int32 nMacroLen
= aMacroName
.getLength();
71 if( (nMacroLen
>= 2) && (aMacroName
[ 0 ] == '\'') && (aMacroName
[ nMacroLen
- 1 ] == '\'') )
72 aMacroName
= aMacroName
.copy( 1, nMacroLen
- 2 ).trim();
76 SfxObjectShell
* findShellForUrl( const OUString
& sMacroURLOrPath
)
78 SfxObjectShell
* pFoundShell
=NULL
;
79 SfxObjectShell
* pShell
= SfxObjectShell::GetFirst();
81 aObj
.SetURL( sMacroURLOrPath
);
82 bool bIsURL
= aObj
.GetProtocol() != INET_PROT_NOT_VALID
;
85 aURL
= sMacroURLOrPath
;
88 osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath
, aURL
);
91 OSL_TRACE("Trying to find shell for url %s", OUStringToOString( aURL
, RTL_TEXTENCODING_UTF8
).getStr() );
95 uno::Reference
< frame::XModel
> xModel
= pShell
->GetModel();
96 // are we searching for a template? if so we have to cater for the
97 // fact that in openoffice a document opened from a template is always
101 OSL_TRACE("shell 0x%x has model with url %s and we look for %s", pShell
102 , OUStringToOString( xModel
->getURL(), RTL_TEXTENCODING_UTF8
).getStr()
103 , OUStringToOString( aURL
, RTL_TEXTENCODING_UTF8
).getStr()
105 OUString aName
= xModel
->getURL() ;
109 const static OUString
sTitle( "Title" );
110 uno::Reference
< frame::XFrame
> xFrame( xModel
->getCurrentController()->getFrame(), uno::UNO_QUERY_THROW
);
111 uno::Reference
< beans::XPropertySet
> xProps( xFrame
, uno::UNO_QUERY_THROW
);
112 xProps
->getPropertyValue(sTitle
) >>= aName
;
114 aName
= aName
.getToken(0,'-',pos
);
115 aName
= aName
.trim();
116 if( sMacroURLOrPath
.lastIndexOf( aName
) >= 0 )
118 pFoundShell
= pShell
;
123 if ( sMacroURLOrPath
.endsWithIgnoreAsciiCaseAsciiL( ".dot", 4 ) )
125 uno::Reference
<document::XDocumentPropertiesSupplier
> const
126 xDocPropSupp(xModel
, uno::UNO_QUERY
);
127 if (xDocPropSupp
.is())
129 uno::Reference
< document::XDocumentProperties
> const
130 xDocProps(xDocPropSupp
->getDocumentProperties(),
131 uno::UNO_QUERY_THROW
);
132 OUString sCurrName
= xDocProps
->getTemplateName();
133 if( sMacroURLOrPath
.lastIndexOf( sCurrName
) >= 0 )
135 pFoundShell
= pShell
;
142 // sometimes just the name of the document ( without the path
144 bool bDocNameNoPathMatch
= false;
145 if ( !aURL
.isEmpty() && aURL
.indexOf( '/' ) == -1 )
147 sal_Int32 lastSlashIndex
= xModel
->getURL().lastIndexOf( '/' );
148 if ( lastSlashIndex
> -1 )
150 bDocNameNoPathMatch
= xModel
->getURL().copy( lastSlashIndex
+ 1 ).equals( aURL
);
151 if ( !bDocNameNoPathMatch
)
153 OUString aTmpName
= "'" + xModel
->getURL().copy( lastSlashIndex
+ 1 ) + "'";
154 bDocNameNoPathMatch
= aTmpName
.equals( aURL
);
159 if ( aURL
.equals( xModel
->getURL() ) || bDocNameNoPathMatch
)
161 pFoundShell
= pShell
;
166 pShell
= SfxObjectShell::GetNext( *pShell
);
171 // sMod can be empty ( but we really need the library to search in )
172 // if sMod is empty and a macro is found then sMod is updated
173 // if sMod is empty, only standard modules will be searched (no class, document, form modules)
174 bool hasMacro( SfxObjectShell
* pShell
, const OUString
& sLibrary
, OUString
& sMod
, const OUString
& sMacro
)
178 #ifdef DISABLE_SCRIPTING
184 if ( !sLibrary
.isEmpty() && !sMacro
.isEmpty() )
186 OSL_TRACE("** Searching for %s.%s in library %s"
187 ,OUStringToOString( sMod
, RTL_TEXTENCODING_UTF8
).getStr()
188 ,OUStringToOString( sMacro
, RTL_TEXTENCODING_UTF8
).getStr()
189 ,OUStringToOString( sLibrary
, RTL_TEXTENCODING_UTF8
).getStr() );
190 BasicManager
* pBasicMgr
= pShell
-> GetBasicManager();
193 StarBASIC
* pBasic
= pBasicMgr
->GetLib( sLibrary
);
196 sal_uInt16 nId
= pBasicMgr
->GetLibId( sLibrary
);
197 pBasicMgr
->LoadLib( nId
);
198 pBasic
= pBasicMgr
->GetLib( sLibrary
);
202 if ( !sMod
.isEmpty() ) // we wish to find the macro is a specific module
204 SbModule
* pModule
= pBasic
->FindModule( sMod
);
207 SbxArray
* pMethods
= pModule
->GetMethods();
210 SbMethod
* pMethod
= static_cast< SbMethod
* >( pMethods
->Find( sMacro
, SbxCLASS_METHOD
) );
216 else if( SbMethod
* pMethod
= dynamic_cast< SbMethod
* >( pBasic
->Find( sMacro
, SbxCLASS_METHOD
) ) )
218 if( SbModule
* pModule
= pMethod
->GetModule() )
220 // when searching for a macro without module name, do not search in class/document/form modules
221 if( pModule
->GetModuleType() == script::ModuleType::NORMAL
)
223 sMod
= pModule
->GetName();
235 OUString
getDefaultProjectName( SfxObjectShell
* pShell
)
238 if( BasicManager
* pBasicMgr
= pShell
? pShell
->GetBasicManager() : 0 )
240 aPrjName
= pBasicMgr
->GetName();
241 if( aPrjName
.isEmpty() )
242 aPrjName
= "Standard";
247 void parseMacro( const OUString
& sMacro
, OUString
& sContainer
, OUString
& sModule
, OUString
& sProcedure
)
249 sal_Int32 nMacroDot
= sMacro
.lastIndexOf( '.' );
251 if ( nMacroDot
!= -1 )
253 sProcedure
= sMacro
.copy( nMacroDot
+ 1 );
255 sal_Int32 nContainerDot
= sMacro
.lastIndexOf( '.', nMacroDot
- 1 );
256 if ( nContainerDot
!= -1 )
258 sModule
= sMacro
.copy( nContainerDot
+ 1, nMacroDot
- nContainerDot
- 1 );
259 sContainer
= sMacro
.copy( 0, nContainerDot
);
262 sModule
= sMacro
.copy( 0, nMacroDot
);
268 OUString
resolveVBAMacro( SfxObjectShell
* pShell
, const OUString
& rLibName
, const OUString
& rModuleName
, const OUString
& rMacroName
)
270 #ifdef DISABLE_SCRIPTING
278 OUString aLibName
= rLibName
.isEmpty() ? getDefaultProjectName( pShell
) : rLibName
;
279 OUString aModuleName
= rModuleName
;
280 if( hasMacro( pShell
, aLibName
, aModuleName
, rMacroName
) )
281 return aLibName
+ "." + aModuleName
+ "." + rMacroName
;
287 MacroResolvedInfo
resolveVBAMacro( SfxObjectShell
* pShell
, const OUString
& MacroName
, bool bSearchGlobalTemplates
)
289 #ifdef DISABLE_SCRIPTING
292 (void) bSearchGlobalTemplates
;
294 return MacroResolvedInfo();
297 return MacroResolvedInfo();
299 // the name may be enclosed in apostrophs
300 OUString aMacroName
= trimMacroName( MacroName
);
302 // parse the macro name
303 sal_Int32 nDocSepIndex
= aMacroName
.indexOf( '!' );
304 if( nDocSepIndex
> 0 )
306 // macro specified by document name
307 // find document shell for document name and call ourselves
310 // assume for now that the document name is *this* document
311 OUString sDocUrlOrPath
= aMacroName
.copy( 0, nDocSepIndex
);
312 aMacroName
= aMacroName
.copy( nDocSepIndex
+ 1 );
313 OSL_TRACE("doc search, current shell is 0x%x", pShell
);
314 SfxObjectShell
* pFoundShell
= 0;
315 if( bSearchGlobalTemplates
)
317 SvtPathOptions aPathOpt
;
318 OUString aAddinPath
= aPathOpt
.GetAddinPath();
319 if( OUString( sDocUrlOrPath
).indexOf( aAddinPath
) == 0 )
320 pFoundShell
= pShell
;
323 pFoundShell
= findShellForUrl( sDocUrlOrPath
);
324 OSL_TRACE("doc search, after find, found shell is 0x%x", pFoundShell
);
325 return resolveVBAMacro( pFoundShell
, aMacroName
);
328 // macro is contained in 'this' document ( or code imported from a template
329 // where that template is a global template or perhaps the template this
330 // document is created from )
332 MacroResolvedInfo
aRes( pShell
);
334 // macro format = Container.Module.Procedure
335 OUString sContainer
, sModule
, sProcedure
;
336 parseMacro( aMacroName
, sContainer
, sModule
, sProcedure
);
339 // As long as service VBAProjectNameProvider isn't supported in the model, disable the createInstance call
340 // (the ServiceNotRegisteredException is wrongly caught in ScModelObj::createInstance)
341 uno::Reference
< container::XNameContainer
> xPrjNameCache
;
342 uno::Reference
< lang::XMultiServiceFactory
> xSF( pShell
->GetModel(), uno::UNO_QUERY
);
345 xPrjNameCache
.set( xSF
->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY
);
347 catch( const uno::Exception
& ) // createInstance may throw
352 std::vector
< OUString
> sSearchList
;
354 if ( !sContainer
.isEmpty() )
356 // service VBAProjectNameProvider not implemented
358 // get the Project associated with the Container
359 if ( xPrjNameCache
.is() )
361 if ( xPrjNameCache
->hasByName( sContainer
) )
364 xPrjNameCache
->getByName( sContainer
) >>= sProject
;
365 sContainer
= sProject
;
369 sSearchList
.push_back( sContainer
); // First Lib to search
373 // Ok, if we have no Container specified then we need to search them in order, this document, template this document created from, global templates,
374 // get the name of Project/Library for 'this' document
375 OUString
sThisProject( "Standard" );
378 uno::Reference
< beans::XPropertySet
> xProps( pShell
->GetModel(), uno::UNO_QUERY_THROW
);
379 uno::Reference
< script::vba::XVBACompatibility
> xVBAMode( xProps
->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW
);
380 sThisProject
= xVBAMode
->getProjectName();
382 catch( const uno::Exception
& /*e*/) {}
384 sSearchList
.push_back( sThisProject
); // First Lib to search
386 // service VBAProjectNameProvider not implemented
388 if ( xPrjNameCache
.is() )
390 // is this document created from a template?
391 uno::Reference
< document::XDocumentPropertiesSupplier
> const
392 xDocPropSupp(pShell
->GetModel(), uno::UNO_QUERY_THROW
);
393 uno::Reference
< document::XDocumentProperties
> xDocProps( xDocPropSupp
->getDocumentProperties(), uno::UNO_QUERY_THROW
);
395 OUString sCreatedFrom
= xDocProps
->getTemplateURL();
396 if ( !sCreatedFrom
.isEmpty() )
399 aObj
.SetURL( sCreatedFrom
);
400 bool bIsURL
= aObj
.GetProtocol() != INET_PROT_NOT_VALID
;
406 osl::FileBase::getFileURLFromSystemPath( sCreatedFrom
, aURL
);
409 sCreatedFrom
= aObj
.GetLastName();
412 sal_Int32 nIndex
= sCreatedFrom
.lastIndexOf( '.' );
414 sCreatedFrom
= sCreatedFrom
.copy( 0, nIndex
);
417 if ( !sCreatedFrom
.isEmpty() && xPrjNameCache
->hasByName( sCreatedFrom
) )
419 xPrjNameCache
->getByName( sCreatedFrom
) >>= sPrj
;
420 // Make sure we don't double up with this project
421 if ( !sPrj
.equals( sThisProject
) )
422 sSearchList
.push_back( sPrj
);
425 // get list of global template Names
426 uno::Sequence
< OUString
> sTemplateNames
= xPrjNameCache
->getElementNames();
427 sal_Int32 nLen
= sTemplateNames
.getLength();
428 for ( sal_Int32 index
= 0; ( bSearchGlobalTemplates
&& index
< nLen
); ++index
)
431 if ( !sCreatedFrom
.equals( sTemplateNames
[ index
] ) )
433 if ( xPrjNameCache
->hasByName( sTemplateNames
[ index
] ) )
435 xPrjNameCache
->getByName( sTemplateNames
[ index
] ) >>= sPrj
;
436 // Make sure we don't double up with this project
437 if ( !sPrj
.equals( sThisProject
) )
438 sSearchList
.push_back( sPrj
);
447 std::vector
< OUString
>::iterator it_end
= sSearchList
.end();
448 for ( std::vector
< OUString
>::iterator it
= sSearchList
.begin(); !aRes
.mbFound
&& (it
!= it_end
); ++it
)
450 aRes
.mbFound
= hasMacro( pShell
, *it
, sModule
, sProcedure
);
454 //aRes.msResolvedMacro = sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 );
455 aRes
.msResolvedMacro
= sContainer
+ "." + sModule
+ "." + sProcedure
;
461 // Treat the args as possible inouts ( convertion at bottom of method )
462 sal_Bool
executeMacro( SfxObjectShell
* pShell
, const OUString
& sMacroName
, uno::Sequence
< uno::Any
>& aArgs
, uno::Any
& aRet
, const uno::Any
& /*aCaller*/)
464 #ifdef DISABLE_SCRIPTING
472 sal_Bool bRes
= sal_False
;
475 OUString sUrl
= makeMacroURL( sMacroName
);
477 uno::Sequence
< sal_Int16
> aOutArgsIndex
;
478 uno::Sequence
< uno::Any
> aOutArgs
;
481 { ErrCode
nErr( ERRCODE_BASIC_INTERNAL_ERROR
);
484 nErr
= pShell
->CallXScript( sUrl
,
485 aArgs
, aRet
, aOutArgsIndex
, aOutArgs
, false );
486 sal_Int32 nLen
= aOutArgs
.getLength();
487 // convert any out params to seem like they were inouts
490 for ( sal_Int32 index
=0; index
< nLen
; ++index
)
492 sal_Int32 nOutIndex
= aOutArgsIndex
[ index
];
493 aArgs
[ nOutIndex
] = aOutArgs
[ index
];
497 bRes
= ( nErr
== ERRCODE_NONE
);
499 catch ( const uno::Exception
& )
507 // ============================================================================
509 uno::Sequence
< OUString
> VBAMacroResolver_getSupportedServiceNames()
511 uno::Sequence
< OUString
> aServiceNames( 1 );
512 aServiceNames
[ 0 ] = "com.sun.star.script.vba.VBAMacroResolver";
513 return aServiceNames
;
516 OUString
VBAMacroResolver_getImplementationName()
518 return OUString( "com.sun.star.comp.vba.VBAMacroResolver" );
521 uno::Reference
< uno::XInterface
> SAL_CALL
VBAMacroResolver_createInstance( const uno::Reference
< uno::XComponentContext
>& ) throw (uno::Exception
)
523 return static_cast< ::cppu::OWeakObject
* >( new VBAMacroResolver
);
526 // ============================================================================
528 VBAMacroResolver::VBAMacroResolver() :
533 VBAMacroResolver::~VBAMacroResolver()
537 // com.sun.star.lang.XServiceInfo interface -----------------------------------
539 OUString SAL_CALL
VBAMacroResolver::getImplementationName() throw (uno::RuntimeException
)
541 return VBAMacroResolver_getImplementationName();
544 sal_Bool SAL_CALL
VBAMacroResolver::supportsService( const OUString
& rService
) throw (uno::RuntimeException
)
546 uno::Sequence
< OUString
> aServices
= VBAMacroResolver_getSupportedServiceNames();
547 const OUString
* pArray
= aServices
.getConstArray();
548 const OUString
* pArrayEnd
= pArray
+ aServices
.getLength();
549 return ::std::find( pArray
, pArrayEnd
, rService
) != pArrayEnd
;
552 uno::Sequence
< OUString
> SAL_CALL
VBAMacroResolver::getSupportedServiceNames() throw (uno::RuntimeException
)
554 return VBAMacroResolver_getSupportedServiceNames();
557 // com.sun.star.lang.XInitialization interface --------------------------------
559 void SAL_CALL
VBAMacroResolver::initialize( const uno::Sequence
< uno::Any
>& rArgs
) throw (uno::Exception
, uno::RuntimeException
)
561 OSL_ENSURE( rArgs
.getLength() < 2, "VBAMacroResolver::initialize - missing arguments" );
562 if( rArgs
.getLength() < 2 )
563 throw uno::RuntimeException();
565 // first argument: document model
566 mxModel
.set( rArgs
[ 0 ], uno::UNO_QUERY_THROW
);
567 uno::Reference
< lang::XUnoTunnel
> xUnoTunnel( mxModel
, uno::UNO_QUERY_THROW
);
568 mpObjShell
= reinterpret_cast< SfxObjectShell
* >( xUnoTunnel
->getSomething( SfxObjectShell::getUnoTunnelId() ) );
570 throw uno::RuntimeException();
572 // second argument: VBA project name
573 if( !(rArgs
[ 1 ] >>= maProjectName
) || (maProjectName
.isEmpty()) )
574 throw uno::RuntimeException();
577 // com.sun.star.script.vba.XVBAMacroResolver interface ------------------------
579 OUString SAL_CALL
VBAMacroResolver::resolveVBAMacroToScriptURL( const OUString
& rVBAMacroName
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
582 throw uno::RuntimeException();
584 // the name may be enclosed in apostrophs
585 OUString aMacroName
= trimMacroName( rVBAMacroName
);
586 if( aMacroName
.isEmpty() )
587 throw lang::IllegalArgumentException();
589 // external references not supported here (syntax is "url!macroname" or "[url]!macroname" or "[url]macroname")
590 if( (aMacroName
[ 0 ] == '[') || (aMacroName
.indexOf( '!' ) >= 0) )
591 throw lang::IllegalArgumentException();
593 // check if macro name starts with project name, replace with "Standard"
594 // TODO: adjust this when custom VBA project name is supported
595 sal_Int32 nDotPos
= aMacroName
.indexOf( '.' );
596 if( (nDotPos
== 0) || (nDotPos
+ 1 == aMacroName
.getLength()) )
597 throw lang::IllegalArgumentException();
598 if( (nDotPos
> 0) && aMacroName
.matchIgnoreAsciiCase( maProjectName
) )
599 aMacroName
= aMacroName
.copy( nDotPos
+ 1 );
601 // try to find the macro
602 MacroResolvedInfo aInfo
= resolveVBAMacro( mpObjShell
, aMacroName
, false );
604 throw lang::IllegalArgumentException();
606 // build and return the script URL
607 return makeMacroURL( aInfo
.msResolvedMacro
);
610 OUString SAL_CALL
VBAMacroResolver::resolveScriptURLtoVBAMacro( const OUString
& /*rScriptURL*/ ) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
612 OSL_ENSURE( false, "VBAMacroResolver::resolveScriptURLtoVBAMacro - not implemented" );
613 throw uno::RuntimeException();
616 bool getModifier( char c
, sal_uInt16
& mod
)
618 static const char modifiers
[] = "+^%";
619 static const sal_uInt16 KEY_MODS
[] = {KEY_SHIFT
, KEY_MOD1
, KEY_MOD2
};
621 for ( unsigned int i
=0; i
<SAL_N_ELEMENTS(KEY_MODS
); ++i
)
623 if ( c
== modifiers
[i
] )
625 mod
= mod
| KEY_MODS
[ i
];
632 typedef std::map
< OUString
, sal_uInt16
> MSKeyCodeMap
;
634 sal_uInt16
parseChar( char c
) throw ( uno::RuntimeException
)
636 sal_uInt16 nVclKey
= 0;
637 // do we care about locale here for isupper etc. ? probably not
640 nVclKey
|= ( toupper( c
) - 'A' ) + KEY_A
;
642 nVclKey
|= KEY_SHIFT
;
644 else if ( isdigit( c
) )
645 nVclKey
|= ( c
- '0' ) + KEY_0
;
646 else if ( c
== '~' ) // special case
647 nVclKey
= KEY_RETURN
;
648 else if ( c
== ' ' ) // special case
650 else // I guess we have a problem ( but not sure if locale specific keys might come into play here )
651 throw uno::RuntimeException();
661 KeyCodeEntry aMSKeyCodesData
[] = {
662 { "BACKSPACE", KEY_BACKSPACE
},
663 { "BS", KEY_BACKSPACE
},
664 { "DELETE", KEY_DELETE
},
665 { "DEL", KEY_DELETE
},
666 { "DOWN", KEY_DOWN
},
668 { "LEFT", KEY_LEFT
},
669 { "RIGHT", KEY_RIGHT
},
671 { "ESCAPE", KEY_ESCAPE
},
672 { "ESC", KEY_ESCAPE
},
673 { "HELP", KEY_HELP
},
674 { "HOME", KEY_HOME
},
675 { "PGDN", KEY_PAGEDOWN
},
676 { "PGUP", KEY_PAGEUP
},
677 { "INSERT", KEY_INSERT
},
678 { "SCROLLLOCK", KEY_SCROLLLOCK
},
679 { "NUMLOCK", KEY_NUMLOCK
},
698 awt::KeyEvent
parseKeyEvent( const OUString
& Key
) throw ( uno::RuntimeException
)
700 static MSKeyCodeMap msKeyCodes
;
701 if ( msKeyCodes
.empty() )
703 for ( unsigned int i
= 0; i
< SAL_N_ELEMENTS( aMSKeyCodesData
); ++i
)
705 msKeyCodes
[ OUString::createFromAscii( aMSKeyCodesData
[ i
].sName
) ] = aMSKeyCodesData
[ i
].nCode
;
709 sal_uInt16 nVclKey
= 0;
711 // parse the modifier if any
712 for ( int i
=0; i
<Key
.getLength(); ++i
)
714 if ( ! getModifier( Key
[ i
], nVclKey
) )
716 sKeyCode
= Key
.copy( i
);
721 // check if keycode is surrounded by '{}', if so scoop out the contents
722 // else it should be just one char of ( 'a-z,A-Z,0-9' )
723 if ( sKeyCode
.getLength() == 1 ) // ( a single char )
725 char c
= (char)( sKeyCode
[ 0 ] );
726 nVclKey
|= parseChar( c
);
728 else // key should be enclosed in '{}'
730 if ( sKeyCode
.getLength() < 3 || !( sKeyCode
[0] == '{' && sKeyCode
[sKeyCode
.getLength() - 1 ] == '}' ) )
731 throw uno::RuntimeException();
733 sKeyCode
= sKeyCode
.copy(1, sKeyCode
.getLength() - 2 );
735 if ( sKeyCode
.getLength() == 1 )
736 nVclKey
|= parseChar( (char)( sKeyCode
[ 0 ] ) );
739 MSKeyCodeMap::iterator it
= msKeyCodes
.find( sKeyCode
);
740 if ( it
== msKeyCodes
.end() ) // unknown or unsupported
741 throw uno::RuntimeException();
742 nVclKey
|= it
->second
;
746 awt::KeyEvent aKeyEvent
= svt::AcceleratorExecute::st_VCLKey2AWTKey( KeyCode( nVclKey
) );
750 void applyShortCutKeyBinding ( const uno::Reference
< frame::XModel
>& rxModel
, const awt::KeyEvent
& rKeyEvent
, const OUString
& rMacroName
) throw (uno::RuntimeException
)
752 OUString
MacroName( rMacroName
);
753 if ( !MacroName
.isEmpty() )
755 OUString aMacroName
= MacroName
.trim();
756 if (0 == aMacroName
.indexOf('!'))
757 MacroName
= aMacroName
.copy(1).trim();
758 SfxObjectShell
* pShell
= NULL
;
761 uno::Reference
< lang::XUnoTunnel
> xObjShellTunnel( rxModel
, uno::UNO_QUERY_THROW
);
762 pShell
= reinterpret_cast<SfxObjectShell
*>( xObjShellTunnel
->getSomething(SfxObjectShell::getUnoTunnelId()));
764 throw uno::RuntimeException();
766 MacroResolvedInfo aMacroInfo
= resolveVBAMacro( pShell
, aMacroName
);
767 if( !aMacroInfo
.mbFound
)
768 throw uno::RuntimeException( "The procedure doesn't exist", uno::Reference
< uno::XInterface
>() );
769 MacroName
= aMacroInfo
.msResolvedMacro
;
771 uno::Reference
< ui::XUIConfigurationManagerSupplier
> xCfgSupplier(rxModel
, uno::UNO_QUERY_THROW
);
772 uno::Reference
< ui::XUIConfigurationManager
> xCfgMgr
= xCfgSupplier
->getUIConfigurationManager();
774 uno::Reference
< ui::XAcceleratorConfiguration
> xAcc( xCfgMgr
->getShortCutManager(), uno::UNO_QUERY_THROW
);
775 if ( MacroName
.isEmpty() )
776 // I believe this should really restore the [application] default. Since
777 // afaik we don't actually setup application default bindings on import
778 // we don't even know what the 'default' would be for this key
779 xAcc
->removeKeyEvent( rKeyEvent
);
781 xAcc
->setKeyEvent( rKeyEvent
, ooo::vba::makeMacroURL( MacroName
) );
784 // ============================================================================
788 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */