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