LibreOffice Module filter (master) 1
msvbahelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <config_features.h>
21
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>
35#include <tools/urlobj.hxx>
36#include <osl/file.hxx>
37#include <sal/log.hxx>
39#include <rtl/character.hxx>
40#include <sfx2/objsh.hxx>
41#include <o3tl/string_view.hxx>
43#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
44#include <com/sun/star/ui/XUIConfigurationManager.hpp>
45#include <frozen/bits/defines.h>
46#include <frozen/bits/elsa_std.h>
47#include <frozen/unordered_map.h>
48
49using namespace ::com::sun::star;
50
51namespace ooo::vba {
52
53constexpr OUStringLiteral sUrlPart0( u"vnd.sun.star.script:" );
54constexpr OUStringLiteral sUrlPart1( u"?language=Basic&location=document" );
55
56OUString makeMacroURL( std::u16string_view sMacroName )
57{
59}
60
61OUString extractMacroName( std::u16string_view rMacroUrl )
62{
63 if( o3tl::starts_with(rMacroUrl, sUrlPart0 ) && o3tl::ends_with(rMacroUrl, sUrlPart1 ) )
64 {
65 return OUString(rMacroUrl.substr( sUrlPart0.getLength(),
66 rMacroUrl.size() - sUrlPart0.getLength() - sUrlPart1.getLength() ));
67 }
68 return OUString();
69}
70
71static std::u16string_view trimMacroName( std::u16string_view rMacroName )
72{
73 // the name may contain whitespaces and may be enclosed in apostrophs
74 std::u16string_view aMacroName = o3tl::trim(rMacroName);
75 size_t nMacroLen = aMacroName.size();
76 if( (nMacroLen >= 2) && (aMacroName[ 0 ] == '\'') && (aMacroName[ nMacroLen - 1 ] == '\'') )
77 aMacroName = o3tl::trim(aMacroName.substr( 1, nMacroLen - 2 ));
78 return aMacroName;
79}
80
81#if HAVE_FEATURE_SCRIPTING
82
83static SfxObjectShell* findShellForUrl( const OUString& sMacroURLOrPath )
84{
85 SfxObjectShell* pFoundShell=nullptr;
87 INetURLObject aObj;
88 aObj.SetURL( sMacroURLOrPath );
89 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
90 OUString aURL;
91 if ( bIsURL )
92 aURL = sMacroURLOrPath;
93 else
94 {
95 osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath, aURL );
96 aObj.SetURL( aURL );
97 }
98 while ( pShell )
99 {
100
101 uno::Reference< frame::XModel > xModel = pShell->GetModel();
102 // are we searching for a template? if so we have to cater for the
103 // fact that in openoffice a document opened from a template is always
104 // a new document :/
105 if ( xModel.is() )
106 {
107 SAL_INFO(
108 "filter.ms",
109 "shell " << pShell << " has model with url " << xModel->getURL()
110 << " and we look for " << aURL);
111 OUString aName = xModel->getURL() ;
112 if (aName.isEmpty())
113 {
114 uno::Reference< frame::XFrame > xFrame( xModel->getCurrentController()->getFrame(), uno::UNO_SET_THROW );
115 uno::Reference< beans::XPropertySet > xProps( xFrame, uno::UNO_QUERY_THROW );
116 xProps->getPropertyValue("Title") >>= aName;
117 aName = o3tl::trim(o3tl::getToken(aName, 0, '-'));
118 if( sMacroURLOrPath.lastIndexOf( aName ) >= 0 )
119 {
120 pFoundShell = pShell;
121 break;
122 }
123 }
124
125 if ( sMacroURLOrPath.endsWithIgnoreAsciiCase( ".dot" ) )
126 {
127 uno::Reference<document::XDocumentPropertiesSupplier> const
128 xDocPropSupp(xModel, uno::UNO_QUERY);
129 if (xDocPropSupp.is())
130 {
131 uno::Reference< document::XDocumentProperties > const
132 xDocProps(xDocPropSupp->getDocumentProperties(),
133 uno::UNO_SET_THROW);
134 OUString sCurrName = xDocProps->getTemplateName();
135 if( sMacroURLOrPath.lastIndexOf( sCurrName ) >= 0 )
136 {
137 pFoundShell = pShell;
138 break;
139 }
140 }
141 }
142 else
143 {
144 // sometimes just the name of the document ( without the path
145 // is used
146 bool bDocNameNoPathMatch = false;
147 if ( !aURL.isEmpty() && aURL.indexOf( '/' ) == -1 )
148 {
149 sal_Int32 lastSlashIndex = xModel->getURL().lastIndexOf( '/' );
150 if ( lastSlashIndex > -1 )
151 {
152 bDocNameNoPathMatch = xModel->getURL().subView( lastSlashIndex + 1 ) == aURL;
153 if ( !bDocNameNoPathMatch )
154 {
155 OUString aTmpName = OUString::Concat("'") + xModel->getURL().subView( lastSlashIndex + 1 ) + "'";
156 bDocNameNoPathMatch = aTmpName == aURL;
157 }
158 }
159 }
160
161 if ( aURL == xModel->getURL() || bDocNameNoPathMatch )
162 {
163 pFoundShell = pShell;
164 break;
165 }
166 }
167 }
168 pShell = SfxObjectShell::GetNext( *pShell );
169 }
170 return pFoundShell;
171}
172
173// sMod can be empty ( but we really need the library to search in )
174// if sMod is empty and a macro is found then sMod is updated
175// if sMod is empty, only standard modules will be searched (no class, document, form modules)
176static bool hasMacro(SfxObjectShell const* pShell, const OUString& sLibrary, OUString& sMod,
177 const OUString& sMacro, bool bOnlyPublic, const OUString& sSkipModule)
178{
179#if !HAVE_FEATURE_SCRIPTING
180 (void) pShell;
181 (void) sLibrary;
182 (void) sMod;
183 (void) sMacro;
184 (void) bOnlyPublic;
185 (void) sSkipModule;
186#else
187 if (sLibrary.isEmpty() || sMacro.isEmpty())
188 return false;
189
190 BasicManager* pBasicMgr = pShell->GetBasicManager();
191 if (!pBasicMgr)
192 return false;
193
194 StarBASIC* pBasic = pBasicMgr->GetLib(sLibrary);
195 if (!pBasic)
196 {
197 sal_uInt16 nId = pBasicMgr->GetLibId(sLibrary);
198 pBasicMgr->LoadLib(nId);
199 pBasic = pBasicMgr->GetLib(sLibrary);
200 }
201 if (!pBasic)
202 return false;
203
204 if (!sMod.isEmpty()) // we wish to find the macro is a specific module
205 {
206 SbModule* pModule = pBasic->FindModule(sMod);
207 if (!pModule)
208 return false;
209 SbMethod* pMeth = pModule->FindMethod(sMacro, SbxClassType::Method);
210
211 // Must be compiled before we can trust SbxFlagBits::Private
212 if (pMeth && bOnlyPublic && !pModule->IsCompiled())
213 pModule->Compile();
214
215 return pMeth && (!bOnlyPublic || !pMeth->IsSet(SbxFlagBits::Private));
216 }
217
218 for (auto const& rModuleRef : pBasic->GetModules())
219 {
220 SbMethod* pMeth = rModuleRef->FindMethod(sMacro, SbxClassType::Method);
221 if (pMeth)
222 {
223 if (rModuleRef->GetName() == sSkipModule)
224 continue;
225
226 if (bOnlyPublic)
227 {
228 if (!rModuleRef->IsCompiled())
229 rModuleRef->Compile();
230
231 if (pMeth->IsSet(SbxFlagBits::Private))
232 continue;
233 }
234 sMod = rModuleRef->GetName();
235 return true;
236 }
237 }
238#endif
239 return false;
240}
241
242#endif
243
244#if HAVE_FEATURE_SCRIPTING
245
246OUString getDefaultProjectName( SfxObjectShell const * pShell )
247{
248 OUString aPrjName;
249 if( BasicManager* pBasicMgr = pShell ? pShell->GetBasicManager() : nullptr )
250 {
251 aPrjName = pBasicMgr->GetName();
252 if( aPrjName.isEmpty() )
253 aPrjName = "Standard";
254 }
255 return aPrjName;
256}
257
258static void parseMacro( const OUString& sMacro, OUString& sContainer, OUString& sModule, OUString& sProcedure )
259{
260 sal_Int32 nMacroDot = sMacro.lastIndexOf( '.' );
261
262 if ( nMacroDot != -1 )
263 {
264 sProcedure = sMacro.copy( nMacroDot + 1 );
265
266 const sal_Int32 nContainerDot = sMacro.lastIndexOf('.', nMacroDot);
267 if ( nContainerDot != -1 )
268 {
269 sModule = sMacro.copy( nContainerDot + 1, nMacroDot - nContainerDot - 1 );
270 sContainer = sMacro.copy( 0, nContainerDot );
271 }
272 else
273 sModule = sMacro.copy( 0, nMacroDot );
274 }
275 else
276 sProcedure = sMacro;
277}
278
279#endif
280
281OUString resolveVBAMacro(SfxObjectShell const* pShell, const OUString& rLibName,
282 const OUString& rModuleName, const OUString& rMacroName,
283 bool bOnlyPublic, const OUString& sSkipModule)
284{
285#if !HAVE_FEATURE_SCRIPTING
286 (void) pShell;
287 (void) rLibName;
288 (void) rModuleName;
289 (void) rMacroName;
290 (void) bOnlyPublic;
291 (void) sSkipModule;
292#else
293 if( pShell )
294 {
295 OUString aLibName = rLibName.isEmpty() ? getDefaultProjectName( pShell ) : rLibName ;
296 OUString aModuleName = rModuleName;
297 if (hasMacro(pShell, aLibName, aModuleName, rMacroName, bOnlyPublic, sSkipModule))
298 return aLibName + "." + aModuleName + "." + rMacroName;
299 }
300#endif
301 return OUString();
302}
303
304MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const OUString& MacroName, bool bSearchGlobalTemplates )
305{
306#if !HAVE_FEATURE_SCRIPTING
307 (void) pShell;
308 (void) MacroName;
309 (void) bSearchGlobalTemplates;
310
311 return MacroResolvedInfo();
312#else
313 if( !pShell )
314 return MacroResolvedInfo();
315
316 // the name may be enclosed in apostrophs
317 std::u16string_view aMacroName = trimMacroName( MacroName );
318
319 // parse the macro name
320 size_t nDocSepIndex = aMacroName.find( '!' );
321 if( nDocSepIndex > 0 && nDocSepIndex != std::u16string_view::npos )
322 {
323 // macro specified by document name
324 // find document shell for document name and call ourselves
325 // recursively
326
327 // assume for now that the document name is *this* document
328 std::u16string_view sDocUrlOrPath = aMacroName.substr( 0, nDocSepIndex );
329 aMacroName = aMacroName.substr( nDocSepIndex + 1 );
330 SAL_INFO("filter.ms", "doc search, current shell is " << pShell);
331 SfxObjectShell* pFoundShell = nullptr;
332 if( bSearchGlobalTemplates )
333 {
334 SvtPathOptions aPathOpt;
335 const OUString& aAddinPath = aPathOpt.GetAddinPath();
336 if( o3tl::starts_with(sDocUrlOrPath, aAddinPath) )
337 pFoundShell = pShell;
338 }
339 if( !pFoundShell )
340 pFoundShell = findShellForUrl( OUString(sDocUrlOrPath) );
341 SAL_INFO(
342 "filter.ms",
343 "doc search, after find, found shell is " << pFoundShell);
344 return resolveVBAMacro( pFoundShell, OUString(aMacroName) );
345 }
346
347 // macro is contained in 'this' document ( or code imported from a template
348 // where that template is a global template or perhaps the template this
349 // document is created from )
350
351 MacroResolvedInfo aRes( pShell );
352
353 // macro format = Container.Module.Procedure
354 OUString sContainer, sModule, sProcedure;
355 parseMacro( OUString(aMacroName), sContainer, sModule, sProcedure );
356
357#if 0
358 // As long as service VBAProjectNameProvider isn't supported in the model, disable the createInstance call
359 // (the ServiceNotRegisteredException is wrongly caught in ScModelObj::createInstance)
360 uno::Reference< container::XNameContainer > xPrjNameCache;
361 uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY);
362 if ( xSF.is() ) try
363 {
364 xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY );
365 }
366 catch( const uno::Exception& ) // createInstance may throw
367 {
368 }
369#endif
370
371 std::vector< OUString > sSearchList;
372
373 if ( !sContainer.isEmpty() )
374 {
375// service VBAProjectNameProvider not implemented
376#if 0
377 // get the Project associated with the Container
378 if ( xPrjNameCache.is() )
379 {
380 if ( xPrjNameCache->hasByName( sContainer ) )
381 {
382 OUString sProject;
383 xPrjNameCache->getByName( sContainer ) >>= sProject;
384 sContainer = sProject;
385 }
386 }
387#endif
388 sSearchList.push_back( sContainer ); // First Lib to search
389 }
390 else
391 {
392 // Ok, if we have no Container specified then we need to search them in order, this document, template this document created from, global templates,
393 // get the name of Project/Library for 'this' document
394 OUString sThisProject( "Standard" );
395 try
396 {
397 uno::Reference< beans::XPropertySet > xProps( pShell->GetModel(), uno::UNO_QUERY_THROW );
398 uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
399 sThisProject = xVBAMode->getProjectName();
400 }
401 catch( const uno::Exception& /*e*/) {}
402
403 sSearchList.push_back( sThisProject ); // First Lib to search
404
405// service VBAProjectNameProvider not implemented
406#if 0
407 if ( xPrjNameCache.is() )
408 {
409 // is this document created from a template?
410 uno::Reference< document::XDocumentPropertiesSupplier > const
411 xDocPropSupp(pShell->GetModel(), uno::UNO_QUERY_THROW);
412 uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
413
414 OUString sCreatedFrom = xDocProps->getTemplateURL();
415 if ( !sCreatedFrom.isEmpty() )
416 {
417 INetURLObject aObj;
418 aObj.SetURL( sCreatedFrom );
419 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
420 OUString aURL;
421 if ( bIsURL )
422 aURL = sCreatedFrom;
423 else
424 {
425 osl::FileBase::getFileURLFromSystemPath( sCreatedFrom, aURL );
426 aObj.SetURL( aURL );
427 }
428 sCreatedFrom = aObj.GetLastName();
429 }
430
431 sal_Int32 nIndex = sCreatedFrom.lastIndexOf( '.' );
432 if ( nIndex != -1 )
433 sCreatedFrom = sCreatedFrom.copy( 0, nIndex );
434
435 OUString sPrj;
436 if ( !sCreatedFrom.isEmpty() && xPrjNameCache->hasByName( sCreatedFrom ) )
437 {
438 xPrjNameCache->getByName( sCreatedFrom ) >>= sPrj;
439 // Make sure we don't double up with this project
440 if ( !sPrj.equals( sThisProject ) )
441 sSearchList.push_back( sPrj );
442 }
443
444 // get list of global template Names
445 uno::Sequence< OUString > sTemplateNames = xPrjNameCache->getElementNames();
446 sal_Int32 nLen = sTemplateNames.getLength();
447 for ( sal_Int32 index = 0; ( bSearchGlobalTemplates && index < nLen ); ++index )
448 {
449
450 if ( !sCreatedFrom.equals( sTemplateNames[ index ] ) )
451 {
452 if ( xPrjNameCache->hasByName( sTemplateNames[ index ] ) )
453 {
454 xPrjNameCache->getByName( sTemplateNames[ index ] ) >>= sPrj;
455 // Make sure we don't double up with this project
456 if ( !sPrj.equals( sThisProject ) )
457 sSearchList.push_back( sPrj );
458 }
459 }
460
461 }
462 }
463#endif
464 }
465
466 for (auto const& search : sSearchList)
467 {
468 aRes.mbFound = hasMacro(pShell, search, sModule, sProcedure, /*bOnlyPublic=*/false, "");
469 if ( aRes.mbFound )
470 {
471 sContainer = search;
472 break;
473 }
474 }
475 //aRes.msResolvedMacro = sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 );
476 aRes.msResolvedMacro = sContainer + "." + sModule + "." + sProcedure;
477
478 return aRes;
479#endif
480}
481
482// Treat the args as possible inputs (conversion at bottom of method)
483bool executeMacro( SfxObjectShell* pShell, const OUString& sMacroName, uno::Sequence< uno::Any >& aArgs, uno::Any& aRet, const uno::Any& /*aCaller*/)
484{
485#if !HAVE_FEATURE_SCRIPTING
486 (void) pShell;
487 (void) sMacroName;
488 (void) aArgs;
489 (void) aRet;
490
491 return false;
492#else
493 bool bRes = false;
494 if ( !pShell )
495 return bRes;
496 OUString sUrl = makeMacroURL( sMacroName );
497
498 uno::Sequence< sal_Int16 > aOutArgsIndex;
499 uno::Sequence< uno::Any > aOutArgs;
500
501 try
502 {
503 ErrCode nErr = pShell->CallXScript(sUrl, aArgs, aRet, aOutArgsIndex, aOutArgs, false);
504 sal_Int32 nLen = aOutArgs.getLength();
505 // convert any out params to seem like they were inputs
506 if (nLen)
507 {
508 auto pArgs = aArgs.getArray();
509 for (sal_Int32 index = 0; index < nLen; ++index)
510 {
511 sal_Int32 nOutIndex = aOutArgsIndex[index];
512 pArgs[nOutIndex] = aOutArgs[index];
513 }
514 }
515 bRes = ( nErr == ERRCODE_NONE );
516 }
517 catch ( const uno::Exception& )
518 {
519 bRes = false;
520 }
521 return bRes;
522#endif
523}
524
525
526
528 mpObjShell( nullptr )
529{
530}
531
533{
534}
535
536// com.sun.star.lang.XServiceInfo interface -----------------------------------
537
539{
540 return "com.sun.star.comp.vba.VBAMacroResolver";
541}
542
543sal_Bool SAL_CALL VBAMacroResolver::supportsService( const OUString& rService )
544{
545 return cppu::supportsService(this, rService);
546}
547
548uno::Sequence< OUString > SAL_CALL VBAMacroResolver::getSupportedServiceNames()
549{
550 return { "com.sun.star.script.vba.VBAMacroResolver" };
551}
552
553// com.sun.star.lang.XInitialization interface --------------------------------
554
555void SAL_CALL VBAMacroResolver::initialize( const uno::Sequence< uno::Any >& rArgs )
556{
557 OSL_ENSURE( rArgs.getLength() > 1, "VBAMacroResolver::initialize - missing arguments" );
558 if( rArgs.getLength() < 2 )
559 throw uno::RuntimeException();
560
561 // first argument: document model
562 mxModel.set( rArgs[ 0 ], uno::UNO_QUERY_THROW );
563 mpObjShell = comphelper::getFromUnoTunnel<SfxObjectShell>(mxModel);
564 if( !mpObjShell )
565 throw uno::RuntimeException();
566
567 // second argument: VBA project name
568 if( !(rArgs[ 1 ] >>= maProjectName) || (maProjectName.isEmpty()) )
569 throw uno::RuntimeException();
570}
571
572// com.sun.star.script.vba.XVBAMacroResolver interface ------------------------
573
574OUString SAL_CALL VBAMacroResolver::resolveVBAMacroToScriptURL( const OUString& rVBAMacroName )
575{
576 if( !mpObjShell )
577 throw uno::RuntimeException();
578
579 // the name may be enclosed in apostrophs
580 OUString aMacroName( trimMacroName( rVBAMacroName ) );
581 if( aMacroName.isEmpty() )
582 throw lang::IllegalArgumentException();
583
584 // external references not supported here (syntax is "url!macroname" or "[url]!macroname" or "[url]macroname")
585 if( (aMacroName[ 0 ] == '[') || (aMacroName.indexOf( '!' ) >= 0) )
586 throw lang::IllegalArgumentException();
587
588 // check if macro name starts with project name, replace with "Standard"
589 // TODO: adjust this when custom VBA project name is supported
590 sal_Int32 nDotPos = aMacroName.indexOf( '.' );
591 if( (nDotPos == 0) || (nDotPos + 1 == aMacroName.getLength()) )
592 throw lang::IllegalArgumentException();
593 if( (nDotPos > 0) && aMacroName.matchIgnoreAsciiCase( maProjectName ) )
594 aMacroName = aMacroName.copy( nDotPos + 1 );
595
596 // try to find the macro
597 MacroResolvedInfo aInfo = resolveVBAMacro( mpObjShell, aMacroName );
598 if( !aInfo.mbFound )
599 throw lang::IllegalArgumentException();
600
601 // build and return the script URL
602 return makeMacroURL( aInfo.msResolvedMacro );
603}
604
605OUString SAL_CALL VBAMacroResolver::resolveScriptURLtoVBAMacro( const OUString& /*rScriptURL*/ )
606{
607 OSL_ENSURE( false, "VBAMacroResolver::resolveScriptURLtoVBAMacro - not implemented" );
608 throw uno::RuntimeException();
609}
610
611static bool getModifier( sal_Unicode c, sal_uInt16& mod )
612{
613 if ( c == '+' ) {
614 mod |= KEY_SHIFT;
615 return true;
616 } else if ( c == '^' ) {
617 mod |= KEY_MOD1;
618 return true;
619 } else if ( c == '%' ) {
620 mod |= KEY_MOD2;
621 return true;
622 }
623 return false;
624}
625
627static sal_uInt16 parseChar( sal_Unicode c )
628{
629 sal_uInt16 nVclKey = 0;
630 // do we care about locale here for letters/digits? probably not
631 if ( rtl::isAsciiAlpha( c ) )
632 {
633 nVclKey |= ( rtl::toAsciiUpperCase( c ) - 'A' ) + KEY_A;
634 if ( rtl::isAsciiUpperCase( c ) )
635 nVclKey |= KEY_SHIFT;
636 }
637 else if ( rtl::isAsciiDigit( c ) )
638 nVclKey |= ( c - '0' ) + KEY_0;
639 else if ( c == '~' ) // special case
640 nVclKey = KEY_RETURN;
641 else if ( c == ' ' ) // special case
642 nVclKey = KEY_SPACE;
643 else // I guess we have a problem ( but not sure if locale specific keys might come into play here )
644 throw uno::RuntimeException();
645 return nVclKey;
646}
647
648namespace
649{
650
651constexpr frozen::unordered_map<std::u16string_view, sal_uInt16, 34> s_KeyCodes
652{
653 { u"BACKSPACE", KEY_BACKSPACE },
654 { u"BS", KEY_BACKSPACE },
655 { u"DELETE", KEY_DELETE },
656 { u"DEL", KEY_DELETE },
657 { u"DOWN", KEY_DOWN },
658 { u"UP", KEY_UP },
659 { u"LEFT", KEY_LEFT },
660 { u"RIGHT", KEY_RIGHT },
661 { u"END", KEY_END },
662 { u"ESCAPE", KEY_ESCAPE },
663 { u"ESC", KEY_ESCAPE },
664 { u"HELP", KEY_HELP },
665 { u"HOME", KEY_HOME },
666 { u"PGDN", KEY_PAGEDOWN },
667 { u"PGUP", KEY_PAGEUP },
668 { u"INSERT", KEY_INSERT },
669 { u"SCROLLLOCK", KEY_SCROLLLOCK },
670 { u"NUMLOCK", KEY_NUMLOCK },
671 { u"TAB", KEY_TAB },
672 { u"F1", KEY_F1 },
673 { u"F2", KEY_F2 },
674 { u"F3", KEY_F3 },
675 { u"F4", KEY_F4 },
676 { u"F5", KEY_F5 },
677 { u"F6", KEY_F6 },
678 { u"F7", KEY_F7 },
679 { u"F8", KEY_F8 },
680 { u"F9", KEY_F9 },
681 { u"F10", KEY_F10 },
682 { u"F11", KEY_F11 },
683 { u"F12", KEY_F12 },
684 { u"F13", KEY_F13 },
685 { u"F14", KEY_F14 },
686 { u"F15", KEY_F15 }
687};
688
689} // end anonymous namespace
690
691awt::KeyEvent parseKeyEvent( std::u16string_view Key )
692{
693 std::u16string_view sKeyCode;
694 sal_uInt16 nVclKey = 0;
695
696 // parse the modifier if any
697 for ( size_t i=0; i<Key.size(); ++i )
698 {
699 if ( ! getModifier( Key[ i ], nVclKey ) )
700 {
701 sKeyCode = Key.substr( i );
702 break;
703 }
704 }
705
706 // check if keycode is surrounded by '{}', if so scoop out the contents
707 // else it should be just one char of ( 'a-z,A-Z,0-9' )
708 if ( sKeyCode.size() == 1 ) // ( a single char )
709 {
710 nVclKey |= parseChar( sKeyCode[ 0 ] );
711 }
712 else // key should be enclosed in '{}'
713 {
714 if ( sKeyCode.size() < 3 || sKeyCode[0] != '{' || sKeyCode[sKeyCode.size() - 1 ] != '}' )
715 throw uno::RuntimeException();
716
717 sKeyCode = sKeyCode.substr(1, sKeyCode.size() - 2 );
718
719 if ( sKeyCode.size() == 1 )
720 nVclKey |= parseChar( sKeyCode[ 0 ] );
721 else
722 {
723 auto it = s_KeyCodes.find(sKeyCode);
724 if ( it == s_KeyCodes.end() ) // unknown or unsupported
725 throw uno::RuntimeException();
726 nVclKey |= it->second;
727 }
728 }
729
730 awt::KeyEvent aKeyEvent = svt::AcceleratorExecute::st_VCLKey2AWTKey( vcl::KeyCode( nVclKey ) );
731 return aKeyEvent;
732}
733
734void applyShortCutKeyBinding ( const uno::Reference< frame::XModel >& rxModel, const awt::KeyEvent& rKeyEvent, const OUString& rMacroName )
735{
736 OUString MacroName( rMacroName );
737 if ( !MacroName.isEmpty() )
738 {
739 OUString aMacroName = MacroName.trim();
740 if( aMacroName.startsWith("!") )
741 aMacroName = o3tl::trim(aMacroName.subView(1));
742 SfxObjectShell* pShell = nullptr;
743 if ( rxModel.is() )
744 {
745 pShell = comphelper::getFromUnoTunnel<SfxObjectShell>(rxModel);
746 if ( !pShell )
747 throw uno::RuntimeException();
748 }
749 MacroResolvedInfo aMacroInfo = resolveVBAMacro( pShell, aMacroName );
750 if( !aMacroInfo.mbFound )
751 throw uno::RuntimeException( "The procedure doesn't exist" );
752 MacroName = aMacroInfo.msResolvedMacro;
753 }
754 uno::Reference< ui::XUIConfigurationManagerSupplier > xCfgSupplier(rxModel, uno::UNO_QUERY_THROW);
755 uno::Reference< ui::XUIConfigurationManager > xCfgMgr = xCfgSupplier->getUIConfigurationManager();
756
757 uno::Reference< ui::XAcceleratorConfiguration > xAcc( xCfgMgr->getShortCutManager(), uno::UNO_SET_THROW );
758 if ( MacroName.isEmpty() )
759 // I believe this should really restore the [application] default. Since
760 // afaik we don't actually setup application default bindings on import
761 // we don't even know what the 'default' would be for this key
762 xAcc->removeKeyEvent( rKeyEvent );
763 else
764 xAcc->setKeyEvent( rKeyEvent, ooo::vba::makeMacroURL( MacroName ) );
765
766}
767
768
769} // namespace ooo
770
771extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
773 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
774{
775 return cppu::acquire(new ooo::vba::VBAMacroResolver());
776}
777
778/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
779
struct _ADOKey Key
StarBASIC * GetLib(sal_uInt16 nLib) const
const OUString & GetName() const
bool LoadLib(sal_uInt16 nLib)
sal_uInt16 GetLibId(std::u16string_view rName) const
OUString GetLastName(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
INetProtocol GetProtocol() const
bool SetURL(std::u16string_view rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
bool Compile()
SbMethod * FindMethod(const OUString &, SbxClassType)
bool IsCompiled() const
bool IsSet(SbxFlagBits n) const
const OUString & GetName(SbxNameType=SbxNameType::NONE) const
BasicManager * GetBasicManager() const
static SAL_WARN_UNUSED_RESULT SfxObjectShell * GetNext(const SfxObjectShell &rPrev, const std::function< bool(const SfxObjectShell *)> &isObjectShell=nullptr, bool bOnlyVisible=true)
ErrCode CallXScript(const OUString &rScriptURL, const css::uno::Sequence< css::uno::Any > &aParams, css::uno::Any &aRet, css::uno::Sequence< sal_Int16 > &aOutParamIndex, css::uno::Sequence< css::uno::Any > &aOutParam, bool bRaiseError=true, const css::uno::Any *aCaller=nullptr)
css::uno::Reference< css::frame::XModel3 > GetModel() const
static SAL_WARN_UNUSED_RESULT SfxObjectShell * GetFirst(const std::function< bool(const SfxObjectShell *)> &isObjectShell=nullptr, bool bOnlyVisible=true)
SbModules & GetModules()
SbModule * FindModule(std::u16string_view)
const OUString & GetAddinPath() const
virtual OUString SAL_CALL resolveVBAMacroToScriptURL(const OUString &rVBAMacroName) override
SfxObjectShell * mpObjShell
virtual OUString SAL_CALL getImplementationName() override
css::uno::Reference< css::frame::XModel > mxModel
virtual OUString SAL_CALL resolveScriptURLtoVBAMacro(const OUString &rScriptURL) override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual ~VBAMacroResolver() override
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &rArgs) override
virtual sal_Bool SAL_CALL supportsService(const OUString &rService) override
static css::awt::KeyEvent st_VCLKey2AWTKey(const vcl::KeyCode &aKey)
URL aURL
float u
#define ERRCODE_NONE
sal_Int32 nIndex
OUString aName
constexpr sal_uInt16 KEY_RETURN
constexpr sal_uInt16 KEY_0
constexpr sal_uInt16 KEY_F2
constexpr sal_uInt16 KEY_F3
constexpr sal_uInt16 KEY_MOD2
constexpr sal_uInt16 KEY_ESCAPE
constexpr sal_uInt16 KEY_MOD1
constexpr sal_uInt16 KEY_HOME
constexpr sal_uInt16 KEY_SCROLLLOCK
constexpr sal_uInt16 KEY_F15
constexpr sal_uInt16 KEY_LEFT
constexpr sal_uInt16 KEY_F4
constexpr sal_uInt16 KEY_NUMLOCK
constexpr sal_uInt16 KEY_F5
constexpr sal_uInt16 KEY_PAGEDOWN
constexpr sal_uInt16 KEY_TAB
constexpr sal_uInt16 KEY_F6
constexpr sal_uInt16 KEY_UP
constexpr sal_uInt16 KEY_F10
constexpr sal_uInt16 KEY_F9
constexpr sal_uInt16 KEY_F7
constexpr sal_uInt16 KEY_F1
constexpr sal_uInt16 KEY_A
constexpr sal_uInt16 KEY_RIGHT
constexpr sal_uInt16 KEY_F13
constexpr sal_uInt16 KEY_DELETE
constexpr sal_uInt16 KEY_F8
constexpr sal_uInt16 KEY_F12
constexpr sal_uInt16 KEY_DOWN
constexpr sal_uInt16 KEY_SPACE
constexpr sal_uInt16 KEY_PAGEUP
constexpr sal_uInt16 KEY_F11
constexpr sal_uInt16 KEY_HELP
constexpr sal_uInt16 KEY_SHIFT
constexpr sal_uInt16 KEY_F14
constexpr sal_uInt16 KEY_INSERT
constexpr sal_uInt16 KEY_BACKSPACE
constexpr sal_uInt16 KEY_END
#define SAL_INFO(area, stream)
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * filter_VBAMacroResolver_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
Shape IDs per cluster in DGG atom.
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
Definition: gentoken.py:48
index
Definition: js2hxx.py:50
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
constexpr bool ends_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
static bool getModifier(sal_Unicode c, sal_uInt16 &mod)
awt::KeyEvent parseKeyEvent(std::u16string_view Key)
OUString makeMacroURL(std::u16string_view sMacroName)
Definition: msvbahelper.cxx:56
static std::u16string_view trimMacroName(std::u16string_view rMacroName)
Definition: msvbahelper.cxx:71
bool executeMacro(SfxObjectShell *pShell, const OUString &sMacroName, uno::Sequence< uno::Any > &aArgs, uno::Any &aRet, const uno::Any &)
MSFILTER_DLLPUBLIC OUString getDefaultProjectName(SfxObjectShell const *pShell)
OUString extractMacroName(std::u16string_view rMacroUrl)
Definition: msvbahelper.cxx:61
constexpr OUStringLiteral sUrlPart0(u"vnd.sun.star.script:")
OUString resolveVBAMacro(SfxObjectShell const *pShell, const OUString &rLibName, const OUString &rModuleName, const OUString &rMacroName, bool bOnlyPublic, const OUString &sSkipModule)
constexpr OUStringLiteral sUrlPart1(u"?language=Basic&location=document")
static sal_uInt16 parseChar(sal_Unicode c)
void applyShortCutKeyBinding(const uno::Reference< frame::XModel > &rxModel, const awt::KeyEvent &rKeyEvent, const OUString &rMacroName)
sal_Int16 nId
Reference< XFrame > xFrame
Reference< XModel > xModel
unsigned char sal_Bool
sal_uInt16 sal_Unicode
constexpr OUStringLiteral sLibrary
constexpr OUStringLiteral sMacroName