1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "basprov.hxx"
21 #include "basscript.hxx"
22 #include "baslibnode.hxx"
23 #include <com/sun/star/frame/XModel.hpp>
24 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
25 #include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
26 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
27 #include <com/sun/star/document/XEmbeddedScripts.hpp>
28 #include <com/sun/star/uri/UriReferenceFactory.hpp>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <rtl/uri.hxx>
32 #include <sal/log.hxx>
33 #include <osl/file.hxx>
34 #include <vcl/svapp.hxx>
35 #include <basic/basmgr.hxx>
36 #include <basic/basicmanagerrepository.hxx>
37 #include <basic/sbstar.hxx>
38 #include <basic/sbmod.hxx>
39 #include <basic/sbmeth.hxx>
40 #include <sfx2/app.hxx>
42 #include <com/sun/star/util/theMacroExpander.hpp>
43 #include <com/sun/star/script/XLibraryContainer2.hpp>
44 #include <com/sun/star/uri/XUriReference.hpp>
45 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
46 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
48 #include <util/MiscUtils.hxx>
51 using namespace ::com::sun::star
;
52 using namespace ::com::sun::star::lang
;
53 using namespace ::com::sun::star::uno
;
54 using namespace ::com::sun::star::script
;
55 using namespace ::com::sun::star::document
;
56 using namespace ::sf_misc
;
65 BasicProviderImpl::BasicProviderImpl( const Reference
< XComponentContext
>& xContext
)
66 :m_pAppBasicManager( nullptr )
67 ,m_pDocBasicManager( nullptr )
68 ,m_xContext( xContext
)
69 ,m_bIsAppScriptCtx( true )
75 BasicProviderImpl::~BasicProviderImpl()
77 SolarMutexGuard aGuard
;
82 bool BasicProviderImpl::isLibraryShared( const Reference
< script::XLibraryContainer
>& rxLibContainer
, const OUString
& rLibName
)
84 bool bIsShared
= false;
86 Reference
< script::XLibraryContainer2
> xLibContainer( rxLibContainer
, UNO_QUERY
);
87 if ( xLibContainer
.is() && xLibContainer
->hasByName( rLibName
) && xLibContainer
->isLibraryLink( rLibName
) )
90 if ( m_xContext
.is() )
92 Reference
< uri::XUriReferenceFactory
> xUriFac( uri::UriReferenceFactory::create( m_xContext
) );
94 OUString
aLinkURL( xLibContainer
->getLibraryLinkURL( rLibName
) );
95 Reference
< uri::XUriReference
> xUriRef
= xUriFac
->parse( aLinkURL
);
99 OUString aScheme
= xUriRef
->getScheme();
100 if ( aScheme
.equalsIgnoreAsciiCase("file") )
104 else if ( aScheme
.equalsIgnoreAsciiCase("vnd.sun.star.pkg") )
106 OUString aDecodedURL
= xUriRef
->getAuthority();
107 if ( aDecodedURL
.startsWithIgnoreAsciiCase( "vnd.sun.star.expand:", &aDecodedURL
) )
109 aDecodedURL
= ::rtl::Uri::decode( aDecodedURL
, rtl_UriDecodeWithCharset
, RTL_TEXTENCODING_UTF8
);
110 Reference
<util::XMacroExpander
> xMacroExpander
=
111 util::theMacroExpander::get(m_xContext
);
112 aFileURL
= xMacroExpander
->expandMacros( aDecodedURL
);
118 if ( !aFileURL
.isEmpty() )
120 osl::DirectoryItem aFileItem
;
121 osl::FileStatus
aFileStatus( osl_FileStatus_Mask_FileURL
);
122 OSL_VERIFY( osl::DirectoryItem::get( aFileURL
, aFileItem
) == osl::FileBase::E_None
);
123 OSL_VERIFY( aFileItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
);
124 OUString
aCanonicalFileURL( aFileStatus
.getFileURL() );
126 if( aCanonicalFileURL
.indexOf( "share/basic" ) != -1
127 || aCanonicalFileURL
.indexOf( "share/uno_packages" ) != -1 )
136 void BasicProviderImpl::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
138 if (auto pManager
= dynamic_cast<const BasicManager
*>(&rBC
))
139 if (pManager
== m_pAppBasicManager
&& rHint
.GetId() == SfxHintId::Dying
)
141 EndListening(*m_pAppBasicManager
);
142 m_pAppBasicManager
= nullptr;
147 OUString
BasicProviderImpl::getImplementationName( )
149 return u
"com.sun.star.comp.scripting.ScriptProviderForBasic"_ustr
;
152 sal_Bool
BasicProviderImpl::supportsService( const OUString
& rServiceName
)
154 return cppu::supportsService(this, rServiceName
);
157 Sequence
< OUString
> BasicProviderImpl::getSupportedServiceNames( )
160 u
"com.sun.star.script.provider.ScriptProviderForBasic"_ustr
,
161 u
"com.sun.star.script.provider.LanguageScriptProvider"_ustr
,
162 u
"com.sun.star.script.provider.ScriptProvider"_ustr
,
163 u
"com.sun.star.script.browse.BrowseNode"_ustr
};
170 void BasicProviderImpl::initialize( const Sequence
< Any
>& aArguments
)
174 SolarMutexGuard aGuard
;
176 if ( aArguments
.getLength() != 1 )
178 throw IllegalArgumentException(
179 u
"BasicProviderImpl::initialize: incorrect argument count."_ustr
,
185 Reference
< frame::XModel
> xModel
;
187 m_xInvocationContext
.set( aArguments
[0], UNO_QUERY
);
188 if ( m_xInvocationContext
.is() )
190 xModel
.set( m_xInvocationContext
->getScriptContainer(), UNO_QUERY
);
193 throw IllegalArgumentException(
194 u
"BasicProviderImpl::initialize: unable to determine the document model from the script invocation context."_ustr
,
202 if ( !( aArguments
[0] >>= m_sScriptingContext
) )
204 throw IllegalArgumentException(
205 "BasicProviderImpl::initialize: incorrect argument type " + aArguments
[0].getValueTypeName(),
211 if ( m_sScriptingContext
.startsWith( "vnd.sun.star.tdoc" ) )
213 xModel
= MiscUtils::tDocUrlToModel( m_sScriptingContext
);
219 Reference
< XEmbeddedScripts
> xDocumentScripts( xModel
, UNO_QUERY
);
220 if ( xDocumentScripts
.is() )
222 m_pDocBasicManager
= ::basic::BasicManagerRepository::getDocumentBasicManager( xModel
);
223 m_xLibContainerDoc
= xDocumentScripts
->getBasicLibraries();
224 OSL_ENSURE( m_pDocBasicManager
&& m_xLibContainerDoc
.is(),
225 "BasicProviderImpl::initialize: invalid BasicManager, or invalid script container!" );
227 m_bIsAppScriptCtx
= false;
231 // Provider has been created with application context for user
233 if ( m_sScriptingContext
!= "user" )
235 m_bIsUserCtx
= false;
240 throw RuntimeException(
241 "BasicProviderImpl::initialize: no scripting context!" );
247 if ( !m_pAppBasicManager
)
249 m_pAppBasicManager
= SfxApplication::GetBasicManager();
250 if (m_pAppBasicManager
)
251 StartListening(*m_pAppBasicManager
);
254 if ( !m_xLibContainerApp
.is() )
255 m_xLibContainerApp
= SfxGetpApp()->GetBasicContainer();
262 Reference
< provider::XScript
> BasicProviderImpl::getScript( const OUString
& scriptURI
)
266 SolarMutexGuard aGuard
;
268 Reference
< provider::XScript
> xScript
;
269 Reference
< uri::XUriReferenceFactory
> xFac ( uri::UriReferenceFactory::create( m_xContext
) );
271 Reference
< uri::XUriReference
> uriRef
= xFac
->parse( scriptURI
);
273 Reference
< uri::XVndSunStarScriptUrl
> sfUri( uriRef
, UNO_QUERY
);
275 if ( !uriRef
.is() || !sfUri
.is() )
277 throw provider::ScriptFrameworkErrorException(
278 "BasicProviderImpl::getScript: failed to parse URI: " + scriptURI
,
279 Reference
< XInterface
>(),
280 scriptURI
, u
"Basic"_ustr
,
281 provider::ScriptFrameworkErrorType::MALFORMED_URL
);
285 OUString aDescription
= sfUri
->getName();
286 OUString aLocation
= sfUri
->getParameter( u
"location"_ustr
);
288 sal_Int32 nIndex
= 0;
289 // In some strange circumstances the Library name can have an
290 // apparently illegal '.' in it ( in imported VBA )
292 BasicManager
* pBasicMgr
= nullptr;
293 if ( aLocation
== "document" )
295 pBasicMgr
= m_pDocBasicManager
;
297 else if ( aLocation
== "application" )
299 pBasicMgr
= m_pAppBasicManager
;
301 OUString sProjectName
;
303 sProjectName
= pBasicMgr
->GetName();
306 if ( !sProjectName
.isEmpty() && aDescription
.match( sProjectName
) )
308 SAL_WARN("scripting", "LibraryName " << sProjectName
<< " is part of the url " << aDescription
);
309 aLibrary
= sProjectName
;
310 nIndex
= sProjectName
.getLength() + 1;
313 aLibrary
= aDescription
.getToken( 0, '.', nIndex
);
316 aModule
= aDescription
.getToken( 0, '.', nIndex
);
319 aMethod
= aDescription
.getToken( 0, '.', nIndex
);
321 if ( !aLibrary
.isEmpty() && !aModule
.isEmpty() && !aMethod
.isEmpty() && !aLocation
.isEmpty() )
326 StarBASIC
* pBasic
= pBasicMgr
->GetLib( aLibrary
);
329 sal_uInt16 nId
= pBasicMgr
->GetLibId( aLibrary
);
330 if ( nId
!= LIB_NOTFOUND
)
332 pBasicMgr
->LoadLib( nId
);
333 pBasic
= pBasicMgr
->GetLib( aLibrary
);
338 SbModule
* pModule
= pBasic
->FindModule( aModule
);
341 SbMethod
* pMethod
= pModule
->FindMethod( aMethod
, SbxClassType::Method
);
342 if ( pMethod
&& !pMethod
->IsHidden() )
344 if ( m_pDocBasicManager
== pBasicMgr
)
345 xScript
= new BasicScriptImpl( aDescription
, pMethod
, *m_pDocBasicManager
, m_xInvocationContext
);
347 xScript
= new BasicScriptImpl( aDescription
, pMethod
);
356 throw provider::ScriptFrameworkErrorException(
357 "The following Basic script could not be found:\n"
358 "library: '" + aLibrary
+ "'\n"
359 "module: '" + aModule
+ "'\n"
360 "method: '" + aMethod
+ "'\n"
361 "location: '" + aLocation
+ "'\n",
362 Reference
< XInterface
>(),
363 scriptURI
, u
"Basic"_ustr
,
364 provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT
);
374 OUString
BasicProviderImpl::getName( )
376 return u
"Basic"_ustr
;
380 Sequence
< Reference
< browse::XBrowseNode
> > BasicProviderImpl::getChildNodes( )
382 SolarMutexGuard aGuard
;
384 Reference
< script::XLibraryContainer
> xLibContainer
;
385 BasicManager
* pBasicManager
= nullptr;
387 if ( m_bIsAppScriptCtx
)
389 xLibContainer
= m_xLibContainerApp
;
390 pBasicManager
= m_pAppBasicManager
;
394 xLibContainer
= m_xLibContainerDoc
;
395 pBasicManager
= m_pDocBasicManager
;
398 Sequence
< Reference
< browse::XBrowseNode
> > aChildNodes
;
400 if ( pBasicManager
&& xLibContainer
.is() )
402 const Sequence
< OUString
> aLibNames
= xLibContainer
->getElementNames();
403 sal_Int32 nLibCount
= aLibNames
.getLength();
404 aChildNodes
.realloc( nLibCount
);
405 Reference
< browse::XBrowseNode
>* pChildNodes
= aChildNodes
.getArray();
406 sal_Int32 childrenFound
= 0;
408 for ( const OUString
& rLibName
: aLibNames
)
410 bool bCreate
= false;
411 if ( m_bIsAppScriptCtx
)
413 const bool bShared
= isLibraryShared( xLibContainer
, rLibName
);
414 if (m_bIsUserCtx
!= bShared
)
423 pChildNodes
[childrenFound
++]
424 = new BasicLibraryNodeImpl(m_xContext
, m_sScriptingContext
, pBasicManager
,
425 xLibContainer
, rLibName
, m_bIsAppScriptCtx
);
429 if ( childrenFound
!= nLibCount
)
430 aChildNodes
.realloc( childrenFound
);
437 sal_Bool
BasicProviderImpl::hasChildNodes( )
439 SolarMutexGuard aGuard
;
441 bool bReturn
= false;
442 Reference
< script::XLibraryContainer
> xLibContainer
;
443 if ( m_bIsAppScriptCtx
)
445 xLibContainer
= m_xLibContainerApp
;
449 xLibContainer
= m_xLibContainerDoc
;
451 if ( xLibContainer
.is() )
452 bReturn
= xLibContainer
->hasElements();
458 sal_Int16
BasicProviderImpl::getType( )
460 return browse::BrowseNodeTypes::CONTAINER
;
464 // component operations
466 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
467 scripting_BasicProviderImpl_get_implementation(
468 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
470 return cppu::acquire(new BasicProviderImpl(context
));
474 } // namespace basprov
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */