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