related tdf#162786: Add cacert.pem
[LibreOffice.git] / filter / source / msfilter / msvbahelper.cxx
blobfd6e616f1a3d5389d58740c934bc7813e0aab305
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 <config_features.h>
22 #include <filter/msfilter/msvbahelper.hxx>
23 #include <basic/sbstar.hxx>
24 #include <basic/basmgr.hxx>
25 #include <basic/sbmod.hxx>
26 #include <basic/sbmeth.hxx>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
29 #include <com/sun/star/document/XDocumentProperties.hpp>
30 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
31 #include <com/sun/star/script/ModuleType.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <comphelper/servicehelper.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <tools/urlobj.hxx>
36 #include <osl/diagnose.h>
37 #include <osl/file.hxx>
38 #include <sal/log.hxx>
39 #include <unotools/pathoptions.hxx>
40 #include <rtl/character.hxx>
41 #include <sfx2/objsh.hxx>
42 #include <o3tl/string_view.hxx>
43 #include <svtools/acceleratorexecute.hxx>
44 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
45 #include <com/sun/star/ui/XUIConfigurationManager.hpp>
46 #include <frozen/bits/defines.h>
47 #include <frozen/bits/elsa_std.h>
48 #include <frozen/unordered_map.h>
50 using namespace ::com::sun::star;
52 namespace ooo::vba {
54 constexpr OUString sUrlPart0( u"vnd.sun.star.script:"_ustr );
55 constexpr OUString sUrlPart1( u"?language=Basic&location=document"_ustr );
57 OUString makeMacroURL( std::u16string_view sMacroName )
59 return sUrlPart0 + sMacroName + sUrlPart1;
62 OUString extractMacroName( std::u16string_view rMacroUrl )
64 if( o3tl::starts_with(rMacroUrl, sUrlPart0 ) && o3tl::ends_with(rMacroUrl, sUrlPart1 ) )
66 return OUString(rMacroUrl.substr( sUrlPart0.getLength(),
67 rMacroUrl.size() - sUrlPart0.getLength() - sUrlPart1.getLength() ));
69 return OUString();
72 static std::u16string_view trimMacroName( std::u16string_view rMacroName )
74 // the name may contain whitespaces and may be enclosed in apostrophs
75 std::u16string_view aMacroName = o3tl::trim(rMacroName);
76 size_t nMacroLen = aMacroName.size();
77 if( (nMacroLen >= 2) && (aMacroName[ 0 ] == '\'') && (aMacroName[ nMacroLen - 1 ] == '\'') )
78 aMacroName = o3tl::trim(aMacroName.substr( 1, nMacroLen - 2 ));
79 return aMacroName;
82 #if HAVE_FEATURE_SCRIPTING
84 static SfxObjectShell* findShellForUrl( const OUString& sMacroURLOrPath )
86 SfxObjectShell* pFoundShell=nullptr;
87 SfxObjectShell* pShell = SfxObjectShell::GetFirst();
88 INetURLObject aObj;
89 aObj.SetURL( sMacroURLOrPath );
90 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
91 OUString aURL;
92 if ( bIsURL )
93 aURL = sMacroURLOrPath;
94 else
96 osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath, aURL );
97 aObj.SetURL( aURL );
99 while ( pShell )
102 uno::Reference< frame::XModel > xModel = pShell->GetModel();
103 // are we searching for a template? if so we have to cater for the
104 // fact that in openoffice a document opened from a template is always
105 // a new document :/
106 if ( xModel.is() )
108 SAL_INFO(
109 "filter.ms",
110 "shell " << pShell << " has model with url " << xModel->getURL()
111 << " and we look for " << aURL);
112 OUString aName = xModel->getURL() ;
113 if (aName.isEmpty())
115 uno::Reference< frame::XFrame > xFrame( xModel->getCurrentController()->getFrame(), uno::UNO_SET_THROW );
116 uno::Reference< beans::XPropertySet > xProps( xFrame, uno::UNO_QUERY_THROW );
117 xProps->getPropertyValue(u"Title"_ustr) >>= aName;
118 aName = o3tl::trim(o3tl::getToken(aName, 0, '-'));
119 if( sMacroURLOrPath.lastIndexOf( aName ) >= 0 )
121 pFoundShell = pShell;
122 break;
126 if ( sMacroURLOrPath.endsWithIgnoreAsciiCase( ".dot" ) )
128 uno::Reference<document::XDocumentPropertiesSupplier> const
129 xDocPropSupp(xModel, uno::UNO_QUERY);
130 if (xDocPropSupp.is())
132 uno::Reference< document::XDocumentProperties > const
133 xDocProps(xDocPropSupp->getDocumentProperties(),
134 uno::UNO_SET_THROW);
135 OUString sCurrName = xDocProps->getTemplateName();
136 if( sMacroURLOrPath.lastIndexOf( sCurrName ) >= 0 )
138 pFoundShell = pShell;
139 break;
143 else
145 // sometimes just the name of the document ( without the path
146 // is used
147 bool bDocNameNoPathMatch = false;
148 if ( !aURL.isEmpty() && aURL.indexOf( '/' ) == -1 )
150 sal_Int32 lastSlashIndex = xModel->getURL().lastIndexOf( '/' );
151 if ( lastSlashIndex > -1 )
153 bDocNameNoPathMatch = xModel->getURL().subView( lastSlashIndex + 1 ) == aURL;
154 if ( !bDocNameNoPathMatch )
156 OUString aTmpName = OUString::Concat("'") + xModel->getURL().subView( lastSlashIndex + 1 ) + "'";
157 bDocNameNoPathMatch = aTmpName == aURL;
162 if ( aURL == xModel->getURL() || bDocNameNoPathMatch )
164 pFoundShell = pShell;
165 break;
169 pShell = SfxObjectShell::GetNext( *pShell );
171 return pFoundShell;
174 // sMod can be empty ( but we really need the library to search in )
175 // if sMod is empty and a macro is found then sMod is updated
176 // if sMod is empty, only standard modules will be searched (no class, document, form modules)
177 static bool hasMacro(SfxObjectShell const* pShell, const OUString& sLibrary, OUString& sMod,
178 const OUString& sMacro, bool bOnlyPublic, const OUString& sSkipModule)
180 #if !HAVE_FEATURE_SCRIPTING
181 (void) pShell;
182 (void) sLibrary;
183 (void) sMod;
184 (void) sMacro;
185 (void) bOnlyPublic;
186 (void) sSkipModule;
187 #else
188 if (sLibrary.isEmpty() || sMacro.isEmpty())
189 return false;
191 BasicManager* pBasicMgr = pShell->GetBasicManager();
192 if (!pBasicMgr)
193 return false;
195 StarBASIC* pBasic = pBasicMgr->GetLib(sLibrary);
196 if (!pBasic)
198 sal_uInt16 nId = pBasicMgr->GetLibId(sLibrary);
199 pBasicMgr->LoadLib(nId);
200 pBasic = pBasicMgr->GetLib(sLibrary);
202 if (!pBasic)
203 return false;
205 if (!sMod.isEmpty()) // we wish to find the macro is a specific module
207 SbModule* pModule = pBasic->FindModule(sMod);
208 if (!pModule)
209 return false;
210 SbMethod* pMeth = pModule->FindMethod(sMacro, SbxClassType::Method);
212 // Must be compiled before we can trust SbxFlagBits::Private
213 if (pMeth && bOnlyPublic && !pModule->IsCompiled())
214 pModule->Compile();
216 return pMeth && (!bOnlyPublic || !pMeth->IsSet(SbxFlagBits::Private));
219 for (auto const& rModuleRef : pBasic->GetModules())
221 SbMethod* pMeth = rModuleRef->FindMethod(sMacro, SbxClassType::Method);
222 if (pMeth)
224 if (rModuleRef->GetName() == sSkipModule)
225 continue;
227 if (bOnlyPublic)
229 if (!rModuleRef->IsCompiled())
230 rModuleRef->Compile();
232 if (pMeth->IsSet(SbxFlagBits::Private))
233 continue;
235 sMod = rModuleRef->GetName();
236 return true;
239 #endif
240 return false;
243 #endif
245 #if HAVE_FEATURE_SCRIPTING
247 OUString getDefaultProjectName( SfxObjectShell const * pShell )
249 OUString aPrjName;
250 if( BasicManager* pBasicMgr = pShell ? pShell->GetBasicManager() : nullptr )
252 aPrjName = pBasicMgr->GetName();
253 if( aPrjName.isEmpty() )
254 aPrjName = "Standard";
256 return aPrjName;
259 static void parseMacro( const OUString& sMacro, OUString& sContainer, OUString& sModule, OUString& sProcedure )
261 sal_Int32 nMacroDot = sMacro.lastIndexOf( '.' );
263 if ( nMacroDot != -1 )
265 sProcedure = sMacro.copy( nMacroDot + 1 );
267 const sal_Int32 nContainerDot = sMacro.lastIndexOf('.', nMacroDot);
268 if ( nContainerDot != -1 )
270 sModule = sMacro.copy( nContainerDot + 1, nMacroDot - nContainerDot - 1 );
271 sContainer = sMacro.copy( 0, nContainerDot );
273 else
274 sModule = sMacro.copy( 0, nMacroDot );
276 else
277 sProcedure = sMacro;
280 #endif
282 OUString resolveVBAMacro(SfxObjectShell const* pShell, const OUString& rLibName,
283 const OUString& rModuleName, const OUString& rMacroName,
284 bool bOnlyPublic, const OUString& sSkipModule)
286 #if !HAVE_FEATURE_SCRIPTING
287 (void) pShell;
288 (void) rLibName;
289 (void) rModuleName;
290 (void) rMacroName;
291 (void) bOnlyPublic;
292 (void) sSkipModule;
293 #else
294 if( pShell )
296 OUString aLibName = rLibName.isEmpty() ? getDefaultProjectName( pShell ) : rLibName ;
297 OUString aModuleName = rModuleName;
298 if (hasMacro(pShell, aLibName, aModuleName, rMacroName, bOnlyPublic, sSkipModule))
299 return aLibName + "." + aModuleName + "." + rMacroName;
301 #endif
302 return OUString();
305 MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const OUString& MacroName, bool bSearchGlobalTemplates )
307 #if !HAVE_FEATURE_SCRIPTING
308 (void) pShell;
309 (void) MacroName;
310 (void) bSearchGlobalTemplates;
312 return MacroResolvedInfo();
313 #else
314 if( !pShell )
315 return MacroResolvedInfo();
317 // the name may be enclosed in apostrophs
318 std::u16string_view aMacroName = trimMacroName( MacroName );
320 // parse the macro name
321 size_t nDocSepIndex = aMacroName.find( '!' );
322 if( nDocSepIndex > 0 && nDocSepIndex != std::u16string_view::npos )
324 // macro specified by document name
325 // find document shell for document name and call ourselves
326 // recursively
328 // assume for now that the document name is *this* document
329 std::u16string_view sDocUrlOrPath = aMacroName.substr( 0, nDocSepIndex );
330 aMacroName = aMacroName.substr( nDocSepIndex + 1 );
331 SAL_INFO("filter.ms", "doc search, current shell is " << pShell);
332 SfxObjectShell* pFoundShell = nullptr;
333 if( bSearchGlobalTemplates )
335 SvtPathOptions aPathOpt;
336 const OUString& aAddinPath = aPathOpt.GetAddinPath();
337 if( o3tl::starts_with(sDocUrlOrPath, aAddinPath) )
338 pFoundShell = pShell;
340 if( !pFoundShell )
341 pFoundShell = findShellForUrl( OUString(sDocUrlOrPath) );
342 SAL_INFO(
343 "filter.ms",
344 "doc search, after find, found shell is " << pFoundShell);
345 return resolveVBAMacro( pFoundShell, OUString(aMacroName) );
348 // macro is contained in 'this' document ( or code imported from a template
349 // where that template is a global template or perhaps the template this
350 // document is created from )
352 MacroResolvedInfo aRes( pShell );
354 // macro format = Container.Module.Procedure
355 OUString sContainer, sModule, sProcedure;
356 parseMacro( OUString(aMacroName), sContainer, sModule, sProcedure );
358 #if 0
359 // As long as service VBAProjectNameProvider isn't supported in the model, disable the createInstance call
360 // (the ServiceNotRegisteredException is wrongly caught in ScModelObj::createInstance)
361 uno::Reference< container::XNameContainer > xPrjNameCache;
362 uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY);
363 if ( xSF.is() ) try
365 xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY );
367 catch( const uno::Exception& ) // createInstance may throw
370 #endif
372 std::vector< OUString > sSearchList;
374 if ( !sContainer.isEmpty() )
376 // service VBAProjectNameProvider not implemented
377 #if 0
378 // get the Project associated with the Container
379 if ( xPrjNameCache.is() )
381 if ( xPrjNameCache->hasByName( sContainer ) )
383 OUString sProject;
384 xPrjNameCache->getByName( sContainer ) >>= sProject;
385 sContainer = sProject;
388 #endif
389 sSearchList.push_back( sContainer ); // First Lib to search
391 else
393 // Ok, if we have no Container specified then we need to search them in order, this document, template this document created from, global templates,
394 // get the name of Project/Library for 'this' document
395 OUString sThisProject( u"Standard"_ustr );
398 uno::Reference< beans::XPropertySet > xProps( pShell->GetModel(), uno::UNO_QUERY_THROW );
399 uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( u"BasicLibraries"_ustr ), uno::UNO_QUERY_THROW );
400 sThisProject = xVBAMode->getProjectName();
402 catch( const uno::Exception& /*e*/) {}
404 sSearchList.push_back( sThisProject ); // First Lib to search
406 // service VBAProjectNameProvider not implemented
407 #if 0
408 if ( xPrjNameCache.is() )
410 // is this document created from a template?
411 uno::Reference< document::XDocumentPropertiesSupplier > const
412 xDocPropSupp(pShell->GetModel(), uno::UNO_QUERY_THROW);
413 uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
415 OUString sCreatedFrom = xDocProps->getTemplateURL();
416 if ( !sCreatedFrom.isEmpty() )
418 INetURLObject aObj;
419 aObj.SetURL( sCreatedFrom );
420 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
421 OUString aURL;
422 if ( bIsURL )
423 aURL = sCreatedFrom;
424 else
426 osl::FileBase::getFileURLFromSystemPath( sCreatedFrom, aURL );
427 aObj.SetURL( aURL );
429 sCreatedFrom = aObj.GetLastName();
432 sal_Int32 nIndex = sCreatedFrom.lastIndexOf( '.' );
433 if ( nIndex != -1 )
434 sCreatedFrom = sCreatedFrom.copy( 0, nIndex );
436 OUString sPrj;
437 if ( !sCreatedFrom.isEmpty() && xPrjNameCache->hasByName( sCreatedFrom ) )
439 xPrjNameCache->getByName( sCreatedFrom ) >>= sPrj;
440 // Make sure we don't double up with this project
441 if ( !sPrj.equals( sThisProject ) )
442 sSearchList.push_back( sPrj );
445 // get list of global template Names
446 uno::Sequence< OUString > sTemplateNames = xPrjNameCache->getElementNames();
447 sal_Int32 nLen = sTemplateNames.getLength();
448 for ( sal_Int32 index = 0; ( bSearchGlobalTemplates && index < nLen ); ++index )
451 if ( !sCreatedFrom.equals( sTemplateNames[ index ] ) )
453 if ( xPrjNameCache->hasByName( sTemplateNames[ index ] ) )
455 xPrjNameCache->getByName( sTemplateNames[ index ] ) >>= sPrj;
456 // Make sure we don't double up with this project
457 if ( !sPrj.equals( sThisProject ) )
458 sSearchList.push_back( sPrj );
464 #endif
467 for (auto const& search : sSearchList)
469 aRes.mbFound = hasMacro(pShell, search, sModule, sProcedure, /*bOnlyPublic=*/false, u""_ustr);
470 if ( aRes.mbFound )
472 sContainer = search;
473 break;
476 //aRes.msResolvedMacro = sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 );
477 aRes.msResolvedMacro = sContainer + "." + sModule + "." + sProcedure;
479 return aRes;
480 #endif
483 // Treat the args as possible inputs (conversion at bottom of method)
484 bool executeMacro( SfxObjectShell* pShell, const OUString& sMacroName, uno::Sequence< uno::Any >& aArgs, uno::Any& aRet, const uno::Any& /*aCaller*/)
486 #if !HAVE_FEATURE_SCRIPTING
487 (void) pShell;
488 (void) sMacroName;
489 (void) aArgs;
490 (void) aRet;
492 return false;
493 #else
494 bool bRes = false;
495 if ( !pShell )
496 return bRes;
497 OUString sUrl = makeMacroURL( sMacroName );
499 uno::Sequence< sal_Int16 > aOutArgsIndex;
500 uno::Sequence< uno::Any > aOutArgs;
504 ErrCode nErr = pShell->CallXScript(sUrl, aArgs, aRet, aOutArgsIndex, aOutArgs, false);
505 sal_Int32 nLen = aOutArgs.getLength();
506 // convert any out params to seem like they were inputs
507 if (nLen)
509 auto pArgs = aArgs.getArray();
510 for (sal_Int32 index = 0; index < nLen; ++index)
512 sal_Int32 nOutIndex = aOutArgsIndex[index];
513 pArgs[nOutIndex] = aOutArgs[index];
516 bRes = ( nErr == ERRCODE_NONE );
518 catch ( const uno::Exception& )
520 bRes = false;
522 return bRes;
523 #endif
528 VBAMacroResolver::VBAMacroResolver() :
529 mpObjShell( nullptr )
533 VBAMacroResolver::~VBAMacroResolver()
537 // com.sun.star.lang.XServiceInfo interface -----------------------------------
539 OUString SAL_CALL VBAMacroResolver::getImplementationName()
541 return u"com.sun.star.comp.vba.VBAMacroResolver"_ustr;
544 sal_Bool SAL_CALL VBAMacroResolver::supportsService( const OUString& rService )
546 return cppu::supportsService(this, rService);
549 uno::Sequence< OUString > SAL_CALL VBAMacroResolver::getSupportedServiceNames()
551 return { u"com.sun.star.script.vba.VBAMacroResolver"_ustr };
554 // com.sun.star.lang.XInitialization interface --------------------------------
556 void SAL_CALL VBAMacroResolver::initialize( const uno::Sequence< uno::Any >& rArgs )
558 OSL_ENSURE( rArgs.getLength() > 1, "VBAMacroResolver::initialize - missing arguments" );
559 if( rArgs.getLength() < 2 )
560 throw uno::RuntimeException();
562 // first argument: document model
563 mxModel.set( rArgs[ 0 ], uno::UNO_QUERY_THROW );
564 mpObjShell = comphelper::getFromUnoTunnel<SfxObjectShell>(mxModel);
565 if( !mpObjShell )
566 throw uno::RuntimeException();
568 // second argument: VBA project name
569 if( !(rArgs[ 1 ] >>= maProjectName) || (maProjectName.isEmpty()) )
570 throw uno::RuntimeException();
573 // com.sun.star.script.vba.XVBAMacroResolver interface ------------------------
575 OUString SAL_CALL VBAMacroResolver::resolveVBAMacroToScriptURL( const OUString& rVBAMacroName )
577 if( !mpObjShell )
578 throw uno::RuntimeException();
580 // the name may be enclosed in apostrophs
581 OUString aMacroName( trimMacroName( rVBAMacroName ) );
582 if( aMacroName.isEmpty() )
583 throw lang::IllegalArgumentException();
585 // external references not supported here (syntax is "url!macroname" or "[url]!macroname" or "[url]macroname")
586 if( (aMacroName[ 0 ] == '[') || (aMacroName.indexOf( '!' ) >= 0) )
587 throw lang::IllegalArgumentException();
589 // check if macro name starts with project name, replace with "Standard"
590 // TODO: adjust this when custom VBA project name is supported
591 sal_Int32 nDotPos = aMacroName.indexOf( '.' );
592 if( (nDotPos == 0) || (nDotPos + 1 == aMacroName.getLength()) )
593 throw lang::IllegalArgumentException();
594 if( (nDotPos > 0) && aMacroName.matchIgnoreAsciiCase( maProjectName ) )
595 aMacroName = aMacroName.copy( nDotPos + 1 );
597 // try to find the macro
598 MacroResolvedInfo aInfo = resolveVBAMacro( mpObjShell, aMacroName );
599 if( !aInfo.mbFound )
600 throw lang::IllegalArgumentException();
602 // build and return the script URL
603 return makeMacroURL( aInfo.msResolvedMacro );
606 OUString SAL_CALL VBAMacroResolver::resolveScriptURLtoVBAMacro( const OUString& /*rScriptURL*/ )
608 OSL_ENSURE( false, "VBAMacroResolver::resolveScriptURLtoVBAMacro - not implemented" );
609 throw uno::RuntimeException();
612 static bool getModifier( sal_Unicode c, sal_uInt16& mod )
614 if ( c == '+' ) {
615 mod |= KEY_SHIFT;
616 return true;
617 } else if ( c == '^' ) {
618 mod |= KEY_MOD1;
619 return true;
620 } else if ( c == '%' ) {
621 mod |= KEY_MOD2;
622 return true;
624 return false;
627 /// @throws uno::RuntimeException
628 static sal_uInt16 parseChar( sal_Unicode c )
630 sal_uInt16 nVclKey = 0;
631 // do we care about locale here for letters/digits? probably not
632 if ( rtl::isAsciiAlpha( c ) )
634 nVclKey |= ( rtl::toAsciiUpperCase( c ) - 'A' ) + KEY_A;
635 if ( rtl::isAsciiUpperCase( c ) )
636 nVclKey |= KEY_SHIFT;
638 else if ( rtl::isAsciiDigit( c ) )
639 nVclKey |= ( c - '0' ) + KEY_0;
640 else if ( c == '~' ) // special case
641 nVclKey = KEY_RETURN;
642 else if ( c == ' ' ) // special case
643 nVclKey = KEY_SPACE;
644 else // I guess we have a problem ( but not sure if locale specific keys might come into play here )
645 throw uno::RuntimeException();
646 return nVclKey;
649 namespace
652 constexpr frozen::unordered_map<std::u16string_view, sal_uInt16, 34> s_KeyCodes
654 { u"BACKSPACE", KEY_BACKSPACE },
655 { u"BS", KEY_BACKSPACE },
656 { u"DELETE", KEY_DELETE },
657 { u"DEL", KEY_DELETE },
658 { u"DOWN", KEY_DOWN },
659 { u"UP", KEY_UP },
660 { u"LEFT", KEY_LEFT },
661 { u"RIGHT", KEY_RIGHT },
662 { u"END", KEY_END },
663 { u"ESCAPE", KEY_ESCAPE },
664 { u"ESC", KEY_ESCAPE },
665 { u"HELP", KEY_HELP },
666 { u"HOME", KEY_HOME },
667 { u"PGDN", KEY_PAGEDOWN },
668 { u"PGUP", KEY_PAGEUP },
669 { u"INSERT", KEY_INSERT },
670 { u"SCROLLLOCK", KEY_SCROLLLOCK },
671 { u"NUMLOCK", KEY_NUMLOCK },
672 { u"TAB", KEY_TAB },
673 { u"F1", KEY_F1 },
674 { u"F2", KEY_F2 },
675 { u"F3", KEY_F3 },
676 { u"F4", KEY_F4 },
677 { u"F5", KEY_F5 },
678 { u"F6", KEY_F6 },
679 { u"F7", KEY_F7 },
680 { u"F8", KEY_F8 },
681 { u"F9", KEY_F9 },
682 { u"F10", KEY_F10 },
683 { u"F11", KEY_F11 },
684 { u"F12", KEY_F12 },
685 { u"F13", KEY_F13 },
686 { u"F14", KEY_F14 },
687 { u"F15", KEY_F15 }
690 } // end anonymous namespace
692 awt::KeyEvent parseKeyEvent( std::u16string_view Key )
694 std::u16string_view sKeyCode;
695 sal_uInt16 nVclKey = 0;
697 // parse the modifier if any
698 for ( size_t i=0; i<Key.size(); ++i )
700 if ( ! getModifier( Key[ i ], nVclKey ) )
702 sKeyCode = Key.substr( i );
703 break;
707 // check if keycode is surrounded by '{}', if so scoop out the contents
708 // else it should be just one char of ( 'a-z,A-Z,0-9' )
709 if ( sKeyCode.size() == 1 ) // ( a single char )
711 nVclKey |= parseChar( sKeyCode[ 0 ] );
713 else // key should be enclosed in '{}'
715 if ( sKeyCode.size() < 3 || sKeyCode[0] != '{' || sKeyCode[sKeyCode.size() - 1 ] != '}' )
716 throw uno::RuntimeException();
718 sKeyCode = sKeyCode.substr(1, sKeyCode.size() - 2 );
720 if ( sKeyCode.size() == 1 )
721 nVclKey |= parseChar( sKeyCode[ 0 ] );
722 else
724 auto it = s_KeyCodes.find(sKeyCode);
725 if ( it == s_KeyCodes.end() ) // unknown or unsupported
726 throw uno::RuntimeException();
727 nVclKey |= it->second;
731 awt::KeyEvent aKeyEvent = svt::AcceleratorExecute::st_VCLKey2AWTKey( vcl::KeyCode( nVclKey ) );
732 return aKeyEvent;
735 void applyShortCutKeyBinding ( const uno::Reference< frame::XModel >& rxModel, const awt::KeyEvent& rKeyEvent, const OUString& rMacroName )
737 OUString MacroName( rMacroName );
738 if ( !MacroName.isEmpty() )
740 OUString aMacroName = MacroName.trim();
741 if( aMacroName.startsWith("!") )
742 aMacroName = o3tl::trim(aMacroName.subView(1));
743 SfxObjectShell* pShell = nullptr;
744 if ( rxModel.is() )
746 pShell = comphelper::getFromUnoTunnel<SfxObjectShell>(rxModel);
747 if ( !pShell )
748 throw uno::RuntimeException();
750 MacroResolvedInfo aMacroInfo = resolveVBAMacro( pShell, aMacroName );
751 if( !aMacroInfo.mbFound )
752 throw uno::RuntimeException( u"The procedure doesn't exist"_ustr );
753 MacroName = aMacroInfo.msResolvedMacro;
755 uno::Reference< ui::XUIConfigurationManagerSupplier > xCfgSupplier(rxModel, uno::UNO_QUERY_THROW);
756 uno::Reference< ui::XUIConfigurationManager > xCfgMgr = xCfgSupplier->getUIConfigurationManager();
758 uno::Reference< ui::XAcceleratorConfiguration > xAcc( xCfgMgr->getShortCutManager(), uno::UNO_SET_THROW );
759 if ( MacroName.isEmpty() )
760 // I believe this should really restore the [application] default. Since
761 // afaik we don't actually setup application default bindings on import
762 // we don't even know what the 'default' would be for this key
763 xAcc->removeKeyEvent( rKeyEvent );
764 else
765 xAcc->setKeyEvent( rKeyEvent, ooo::vba::makeMacroURL( MacroName ) );
770 } // namespace ooo
772 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
773 filter_VBAMacroResolver_get_implementation(
774 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
776 return cppu::acquire(new ooo::vba::VBAMacroResolver());
779 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */