merge the formfield patch from ooo-build
[ooovba.git] / svx / source / msfilter / msvbahelper.cxx
blobd02746f59705af01d13ef5da09c4d0f8456f465b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile:
10 * $Revision:
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <svx/msvbahelper.hxx>
32 #include <basic/sbx.hxx>
33 #include <basic/sbstar.hxx>
34 #include <basic/basmgr.hxx>
35 #include <basic/sbmod.hxx>
36 #include <basic/sbmeth.hxx>
37 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
38 #include <com/sun/star/document/XDocumentProperties.hpp>
39 #include <com/sun/star/document/XDocumentInfoSupplier.hpp>
40 #include <tools/urlobj.hxx>
41 #include <osl/file.hxx>
43 using namespace ::com::sun::star;
45 const static rtl::OUString sUrlPart0 = rtl::OUString::createFromAscii( "vnd.sun.star.script:");
46 const static rtl::OUString sUrlPart1 = rtl::OUString::createFromAscii( "?language=Basic&location=document");
48 namespace ooo { namespace vba {
50 String makeMacroURL( const String& sMacroName )
52 return sUrlPart0.concat( sMacroName ).concat( sUrlPart1 ) ;
55 SfxObjectShell* findShellForUrl( const rtl::OUString& sMacroURLOrPath )
57 SfxObjectShell* pFoundShell=NULL;
58 SfxObjectShell* pShell = SfxObjectShell::GetFirst();
59 INetURLObject aObj;
60 aObj.SetURL( sMacroURLOrPath );
61 bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
62 rtl::OUString aURL;
63 if ( bIsURL )
64 aURL = sMacroURLOrPath;
65 else
67 osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath, aURL );
68 aObj.SetURL( aURL );
70 OSL_TRACE("Trying to find shell for url %s", rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() );
71 while ( pShell )
74 uno::Reference< frame::XModel > xModel = pShell->GetModel();
75 // are we searching for a template? if so we have to cater for the
76 // fact that in openoffice a document opened from a template is always
77 // a new document :/
78 if ( xModel.is() )
80 OSL_TRACE("shell 0x%x has model with url %s and we look for %s", pShell
81 , rtl::OUStringToOString( xModel->getURL(), RTL_TEXTENCODING_UTF8 ).getStr()
82 , rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr()
84 if ( sMacroURLOrPath.endsWithIgnoreAsciiCaseAsciiL( ".dot", 4 ) )
86 uno::Reference< document::XDocumentInfoSupplier > xDocInfoSupp( xModel, uno::UNO_QUERY );
87 if( xDocInfoSupp.is() )
89 uno::Reference< document::XDocumentPropertiesSupplier > xDocPropSupp( xDocInfoSupp->getDocumentInfo(), uno::UNO_QUERY_THROW );
90 uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
91 rtl::OUString sCurrName = xDocProps->getTemplateName();
92 if( sMacroURLOrPath.lastIndexOf( sCurrName ) >= 0 )
94 pFoundShell = pShell;
95 break;
99 else
101 if ( aURL.equals( xModel->getURL() ) )
103 pFoundShell = pShell;
104 break;
108 pShell = SfxObjectShell::GetNext( *pShell );
110 return pFoundShell;
113 // sMod can be empty ( but we really need the library to search in )
114 // if sMod is empty and a macro is found then sMod is updated
115 bool hasMacro( SfxObjectShell* pShell, const String& sLibrary, String& sMod, const String& sMacro )
117 bool bFound = false;
118 if ( sLibrary.Len() && sMacro.Len() )
120 OSL_TRACE("** Searching for %s.%s in library %s"
121 ,rtl::OUStringToOString( sMod, RTL_TEXTENCODING_UTF8 ).getStr()
122 ,rtl::OUStringToOString( sMacro, RTL_TEXTENCODING_UTF8 ).getStr()
123 ,rtl::OUStringToOString( sLibrary, RTL_TEXTENCODING_UTF8 ).getStr() );
124 BasicManager* pBasicMgr = pShell-> GetBasicManager();
125 if ( pBasicMgr )
127 StarBASIC* pBasic = pBasicMgr->GetLib( sLibrary );
128 if ( !pBasic )
130 USHORT nId = pBasicMgr->GetLibId( sLibrary );
131 pBasicMgr->LoadLib( nId );
132 pBasic = pBasicMgr->GetLib( sLibrary );
134 if ( pBasic )
136 if ( sMod.Len() ) // we wish to find the macro is a specific module
138 SbModule* pModule = pBasic->FindModule( sMod );
139 if ( pModule )
141 SbxArray* pMethods = pModule->GetMethods();
142 if ( pMethods )
144 SbMethod* pMethod = static_cast< SbMethod* >( pMethods->Find( sMacro, SbxCLASS_METHOD ) );
145 if ( pMethod )
146 bFound = true;
150 else if( SbMethod* pMethod = dynamic_cast< SbMethod* >( pBasic->Find( sMacro, SbxCLASS_METHOD ) ) )
152 if( SbModule* pModule = pMethod->GetModule() )
154 sMod = pModule->GetName();
155 bFound = true;
161 return bFound;
163 void parseMacro( const rtl::OUString& sMacro, String& sContainer, String& sModule, String& sProcedure )
165 sal_Int32 nMacroDot = sMacro.lastIndexOf( '.' );
167 if ( nMacroDot != -1 )
169 sProcedure = sMacro.copy( nMacroDot + 1 );
171 sal_Int32 nContainerDot = sMacro.lastIndexOf( '.', nMacroDot - 1 );
172 if ( nContainerDot != -1 )
174 sModule = sMacro.copy( nContainerDot + 1, nMacroDot - nContainerDot - 1 );
175 sContainer = sMacro.copy( 0, nContainerDot );
177 else
178 sModule = sMacro.copy( 0, nMacroDot );
180 else
181 sProcedure = sMacro;
184 VBAMacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const rtl::OUString& MacroName, bool bSearchGlobalTemplates )
186 VBAMacroResolvedInfo aRes;
187 if ( !pShell )
188 return aRes;
189 aRes.SetMacroDocContext( pShell );
190 // parse the macro name
191 sal_Int32 nDocSepIndex = MacroName.indexOfAsciiL( "!", 1 );
192 String sMacroUrl = MacroName;
194 String sContainer;
195 String sModule;
196 String sProcedure;
198 if( nDocSepIndex > 0 )
200 // macro specified by document name
201 // find document shell for document name and call ourselves
202 // recursively
204 // assume for now that the document name is *this* document
205 String sDocUrlOrPath = MacroName.copy( 0, nDocSepIndex );
206 sMacroUrl = MacroName.copy( nDocSepIndex + 1 );
207 OSL_TRACE("doc search, current shell is 0x%x", pShell );
208 SfxObjectShell* pFoundShell = findShellForUrl( sDocUrlOrPath );
209 OSL_TRACE("doc search, after find, found shell is 0x%x", pFoundShell );
210 aRes = resolveVBAMacro( pFoundShell, sMacroUrl );
212 else
214 // macro is contained in 'this' document ( or code imported from a template
215 // where that template is a global template or perhaps the template this
216 // document is created from )
218 // macro format = Container.Module.Procedure
219 parseMacro( MacroName, sContainer, sModule, sProcedure );
220 uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY);
221 uno::Reference< container::XNameContainer > xPrjNameCache;
222 if ( xSF.is() )
223 xPrjNameCache.set( xSF->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAProjectNameProvider" ) ) ), uno::UNO_QUERY );
225 std::vector< rtl::OUString > sSearchList;
227 if ( sContainer.Len() > 0 )
229 // get the Project associated with the Container
230 if ( xPrjNameCache.is() )
232 if ( xPrjNameCache->hasByName( sContainer ) )
234 rtl::OUString sProject;
235 xPrjNameCache->getByName( sContainer ) >>= sProject;
236 sContainer = sProject;
239 sSearchList.push_back( sContainer ); // First Lib to search
241 else
243 // Ok, if we have no Container specified then we need to search them in order, this document, template this document created from, global templates,
244 // get the name of Project/Library for 'this' document
245 rtl::OUString sThisProject;
246 BasicManager* pBasicMgr = pShell-> GetBasicManager();
247 if ( pBasicMgr )
249 if ( pBasicMgr->GetName().Len() )
250 sThisProject = pBasicMgr->GetName();
251 else // cater for the case where VBA is not enabled
252 sThisProject = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Standard") );
254 sSearchList.push_back( sThisProject ); // First Lib to search
255 if ( xPrjNameCache.is() )
257 // is this document created from a template?
258 uno::Reference< document::XDocumentInfoSupplier > xDocInfoSupp( pShell->GetModel(), uno::UNO_QUERY_THROW );
259 uno::Reference< document::XDocumentPropertiesSupplier > xDocPropSupp( xDocInfoSupp->getDocumentInfo(), uno::UNO_QUERY_THROW );
260 uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
262 rtl::OUString sCreatedFrom = xDocProps->getTemplateURL();
263 if ( sCreatedFrom.getLength() )
265 INetURLObject aObj;
266 aObj.SetURL( sCreatedFrom );
267 bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
268 rtl::OUString aURL;
269 if ( bIsURL )
270 aURL = sCreatedFrom;
271 else
273 osl::FileBase::getFileURLFromSystemPath( sCreatedFrom, aURL );
274 aObj.SetURL( aURL );
276 sCreatedFrom = aObj.GetLastName();
279 sal_Int32 nIndex = sCreatedFrom.lastIndexOf( '.' );
280 if ( nIndex != -1 )
281 sCreatedFrom = sCreatedFrom.copy( 0, nIndex );
283 rtl::OUString sPrj;
284 if ( sCreatedFrom.getLength() && xPrjNameCache->hasByName( sCreatedFrom ) )
286 xPrjNameCache->getByName( sCreatedFrom ) >>= sPrj;
287 // Make sure we don't double up with this project
288 if ( !sPrj.equals( sThisProject ) )
289 sSearchList.push_back( sPrj );
292 // get list of global template Names
293 uno::Sequence< rtl::OUString > sTemplateNames = xPrjNameCache->getElementNames();
294 sal_Int32 nLen = sTemplateNames.getLength();
295 for ( sal_Int32 index = 0; ( bSearchGlobalTemplates && index < nLen ); ++index )
298 if ( !sCreatedFrom.equals( sTemplateNames[ index ] ) )
300 if ( xPrjNameCache->hasByName( sTemplateNames[ index ] ) )
302 xPrjNameCache->getByName( sTemplateNames[ index ] ) >>= sPrj;
303 // Make sure we don't double up with this project
304 if ( !sPrj.equals( sThisProject ) )
305 sSearchList.push_back( sPrj );
312 std::vector< rtl::OUString >::iterator it_end = sSearchList.end();
313 for ( std::vector< rtl::OUString >::iterator it = sSearchList.begin(); it != it_end; ++it )
315 bool bRes = hasMacro( pShell, *it, sModule, sProcedure );
316 if ( bRes )
318 aRes.SetResolved( true );
319 aRes.SetMacroDocContext( pShell );
320 sContainer = *it;
321 break;
325 aRes.SetResolvedMacro( sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 ) );
327 return aRes;
330 // Treat the args as possible inouts ( convertion at bottom of method )
331 sal_Bool executeMacro( SfxObjectShell* pShell, const String& sMacroName, uno::Sequence< uno::Any >& aArgs, uno::Any& /*aRet*/, const uno::Any& aCaller )
333 sal_Bool bRes = sal_False;
334 if ( !pShell )
335 return bRes;
336 rtl::OUString sUrl = makeMacroURL( sMacroName );
338 uno::Sequence< sal_Int16 > aOutArgsIndex;
339 uno::Sequence< uno::Any > aOutArgs;
343 uno::Reference< script::provider::XScriptProvider > xScriptProvider;
344 uno::Reference< script::provider::XScriptProviderSupplier > xSPS( pShell->GetModel(), uno::UNO_QUERY_THROW );
346 xScriptProvider.set( xSPS->getScriptProvider(), uno::UNO_QUERY_THROW );
348 uno::Reference< script::provider::XScript > xScript( xScriptProvider->getScript( sUrl ), uno::UNO_QUERY_THROW );
350 if ( aCaller.hasValue() )
352 uno::Reference< beans::XPropertySet > xProps( xScript, uno::UNO_QUERY );
353 if ( xProps.is() )
355 uno::Sequence< uno::Any > aCallerHack(1);
356 aCallerHack[ 0 ] = aCaller;
357 xProps->setPropertyValue( rtl::OUString::createFromAscii( "Caller" ), uno::makeAny( aCallerHack ) );
362 xScript->invoke( aArgs, aOutArgsIndex, aOutArgs );
364 sal_Int32 nLen = aOutArgs.getLength();
365 // convert any out params to seem like they were inouts
366 if ( nLen )
368 for ( sal_Int32 index=0; index < nLen; ++index )
370 sal_Int32 nOutIndex = aOutArgsIndex[ index ];
371 aArgs[ nOutIndex ] = aOutArgs[ index ];
375 bRes = sal_True;
377 catch ( uno::Exception& e )
379 bRes = sal_False;
381 return bRes;
383 } } // vba // ooo