bump product version to 4.1.6.2
[LibreOffice.git] / filter / source / msfilter / msvbahelper.cxx
blob4a5576f0bed73bfa1a6e0b87eb2097332a28a56c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
39 #include <map>
41 using namespace ::com::sun::star;
43 namespace ooo {
44 namespace vba {
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() );
63 return OUString();
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();
73 return aMacroName;
76 SfxObjectShell* findShellForUrl( const OUString& sMacroURLOrPath )
78 SfxObjectShell* pFoundShell=NULL;
79 SfxObjectShell* pShell = SfxObjectShell::GetFirst();
80 INetURLObject aObj;
81 aObj.SetURL( sMacroURLOrPath );
82 bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
83 OUString aURL;
84 if ( bIsURL )
85 aURL = sMacroURLOrPath;
86 else
88 osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath, aURL );
89 aObj.SetURL( aURL );
91 OSL_TRACE("Trying to find shell for url %s", OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() );
92 while ( pShell )
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
98 // a new document :/
99 if ( xModel.is() )
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() ;
106 if (aName.isEmpty())
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;
113 sal_Int32 pos = 0;
114 aName = aName.getToken(0,'-',pos);
115 aName = aName.trim();
116 if( sMacroURLOrPath.lastIndexOf( aName ) >= 0 )
118 pFoundShell = pShell;
119 break;
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;
136 break;
140 else
142 // sometimes just the name of the document ( without the path
143 // is used
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;
162 break;
166 pShell = SfxObjectShell::GetNext( *pShell );
168 return pFoundShell;
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 )
176 bool bFound = false;
178 #ifdef DISABLE_SCRIPTING
179 (void) pShell;
180 (void) sLibrary;
181 (void) sMod;
182 (void) sMacro;
183 #else
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();
191 if ( pBasicMgr )
193 StarBASIC* pBasic = pBasicMgr->GetLib( sLibrary );
194 if ( !pBasic )
196 sal_uInt16 nId = pBasicMgr->GetLibId( sLibrary );
197 pBasicMgr->LoadLib( nId );
198 pBasic = pBasicMgr->GetLib( sLibrary );
200 if ( pBasic )
202 if ( !sMod.isEmpty() ) // we wish to find the macro is a specific module
204 SbModule* pModule = pBasic->FindModule( sMod );
205 if ( pModule )
207 SbxArray* pMethods = pModule->GetMethods();
208 if ( pMethods )
210 SbMethod* pMethod = static_cast< SbMethod* >( pMethods->Find( sMacro, SbxCLASS_METHOD ) );
211 if ( pMethod )
212 bFound = true;
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();
224 bFound = true;
231 #endif
232 return bFound;
235 OUString getDefaultProjectName( SfxObjectShell* pShell )
237 OUString aPrjName;
238 if( BasicManager* pBasicMgr = pShell ? pShell->GetBasicManager() : 0 )
240 aPrjName = pBasicMgr->GetName();
241 if( aPrjName.isEmpty() )
242 aPrjName = "Standard";
244 return aPrjName;
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 );
261 else
262 sModule = sMacro.copy( 0, nMacroDot );
264 else
265 sProcedure = sMacro;
268 OUString resolveVBAMacro( SfxObjectShell* pShell, const OUString& rLibName, const OUString& rModuleName, const OUString& rMacroName )
270 #ifdef DISABLE_SCRIPTING
271 (void) pShell;
272 (void) rLibName;
273 (void) rModuleName;
274 (void) rMacroName;
275 #else
276 if( pShell )
278 OUString aLibName = rLibName.isEmpty() ? getDefaultProjectName( pShell ) : rLibName ;
279 OUString aModuleName = rModuleName;
280 if( hasMacro( pShell, aLibName, aModuleName, rMacroName ) )
281 return aLibName + "." + aModuleName + "." + rMacroName;
283 #endif
284 return OUString();
287 MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const OUString& MacroName, bool bSearchGlobalTemplates )
289 #ifdef DISABLE_SCRIPTING
290 (void) pShell;
291 (void) MacroName;
292 (void) bSearchGlobalTemplates;
294 return MacroResolvedInfo();
295 #else
296 if( !pShell )
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
308 // recursively
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;
322 if( !pFoundShell )
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 );
338 #if 0
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);
343 if ( xSF.is() ) try
345 xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY );
347 catch( const uno::Exception& ) // createInstance may throw
350 #endif
352 std::vector< OUString > sSearchList;
354 if ( !sContainer.isEmpty() )
356 // service VBAProjectNameProvider not implemented
357 #if 0
358 // get the Project associated with the Container
359 if ( xPrjNameCache.is() )
361 if ( xPrjNameCache->hasByName( sContainer ) )
363 OUString sProject;
364 xPrjNameCache->getByName( sContainer ) >>= sProject;
365 sContainer = sProject;
368 #endif
369 sSearchList.push_back( sContainer ); // First Lib to search
371 else
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
387 #if 0
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() )
398 INetURLObject aObj;
399 aObj.SetURL( sCreatedFrom );
400 bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
401 OUString aURL;
402 if ( bIsURL )
403 aURL = sCreatedFrom;
404 else
406 osl::FileBase::getFileURLFromSystemPath( sCreatedFrom, aURL );
407 aObj.SetURL( aURL );
409 sCreatedFrom = aObj.GetLastName();
412 sal_Int32 nIndex = sCreatedFrom.lastIndexOf( '.' );
413 if ( nIndex != -1 )
414 sCreatedFrom = sCreatedFrom.copy( 0, nIndex );
416 OUString sPrj;
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 );
444 #endif
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 );
451 if ( aRes.mbFound )
452 sContainer = *it;
454 //aRes.msResolvedMacro = sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 );
455 aRes.msResolvedMacro = sContainer + "." + sModule + "." + sProcedure;
457 return aRes;
458 #endif
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
465 (void) pShell;
466 (void) sMacroName;
467 (void) aArgs;
468 (void) aRet;
470 return sal_False;
471 #else
472 sal_Bool bRes = sal_False;
473 if ( !pShell )
474 return bRes;
475 OUString sUrl = makeMacroURL( sMacroName );
477 uno::Sequence< sal_Int16 > aOutArgsIndex;
478 uno::Sequence< uno::Any > aOutArgs;
481 { ErrCode nErr( ERRCODE_BASIC_INTERNAL_ERROR );
482 if ( pShell )
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
488 if ( nLen )
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& )
501 bRes = sal_False;
503 return bRes;
504 #endif
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() :
529 mpObjShell( 0 )
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() ) );
569 if( !mpObjShell )
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)
581 if( !mpObjShell )
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 );
603 if( !aInfo.mbFound )
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 ];
626 return true;
629 return false;
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
638 if ( isalpha( c ) )
640 nVclKey |= ( toupper( c ) - 'A' ) + KEY_A;
641 if ( isupper( c ) )
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
649 nVclKey = KEY_SPACE;
650 else // I guess we have a problem ( but not sure if locale specific keys might come into play here )
651 throw uno::RuntimeException();
652 return nVclKey;
655 struct KeyCodeEntry
657 const char* sName;
658 sal_uInt16 nCode;
661 KeyCodeEntry aMSKeyCodesData[] = {
662 { "BACKSPACE", KEY_BACKSPACE },
663 { "BS", KEY_BACKSPACE },
664 { "DELETE", KEY_DELETE },
665 { "DEL", KEY_DELETE },
666 { "DOWN", KEY_DOWN },
667 { "UP", KEY_UP },
668 { "LEFT", KEY_LEFT },
669 { "RIGHT", KEY_RIGHT },
670 { "END", KEY_END },
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 },
680 { "TAB", KEY_TAB },
681 { "F1", KEY_F1 },
682 { "F2", KEY_F2 },
683 { "F3", KEY_F3 },
684 { "F4", KEY_F4 },
685 { "F5", KEY_F5 },
686 { "F6", KEY_F6 },
687 { "F7", KEY_F7 },
688 { "F8", KEY_F8 },
689 { "F9", KEY_F1 },
690 { "F10", KEY_F10 },
691 { "F11", KEY_F11 },
692 { "F12", KEY_F12 },
693 { "F13", KEY_F13 },
694 { "F14", KEY_F14 },
695 { "F15", KEY_F15 },
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;
708 OUString sKeyCode;
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 );
717 break;
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 ] ) );
737 else
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 ) );
747 return aKeyEvent;
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;
759 if ( rxModel.is() )
761 uno::Reference< lang::XUnoTunnel > xObjShellTunnel( rxModel, uno::UNO_QUERY_THROW );
762 pShell = reinterpret_cast<SfxObjectShell*>( xObjShellTunnel->getSomething(SfxObjectShell::getUnoTunnelId()));
763 if ( !pShell )
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 );
780 else
781 xAcc->setKeyEvent( rKeyEvent, ooo::vba::makeMacroURL( MacroName ) );
784 // ============================================================================
786 } // namespace vba
787 } // namespace ooo
788 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */