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