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