tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / scripting / source / provider / MasterScriptProvider.cxx
blobf033a9dbe31721e606cd2ce6ea4b7e4159c31749
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <comphelper/SetFlagContextHelper.hxx>
22 #include <comphelper/documentinfo.hxx>
24 #include <cppuhelper/exc_hlp.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <comphelper/diagnose_ex.hxx>
27 #include <tools/urlobj.hxx>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
31 #include <com/sun/star/uri/XUriReference.hpp>
32 #include <com/sun/star/uri/UriReferenceFactory.hpp>
33 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
35 #include <com/sun/star/deployment/XPackage.hpp>
36 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
37 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
38 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
40 #include <util/MiscUtils.hxx>
41 #include <sal/log.hxx>
43 #include "MasterScriptProvider.hxx"
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::script;
48 using namespace ::com::sun::star::document;
49 using namespace ::sf_misc;
51 namespace func_provider
54 static bool endsWith( std::u16string_view target, std::u16string_view item )
56 size_t index = target.find( item );
57 return index != std::u16string_view::npos &&
58 index == ( target.size() - item.size() );
61 /* should be available in some central location. */
63 // XScriptProvider implementation
66 MasterScriptProvider::MasterScriptProvider( const Reference< XComponentContext > & xContext ):
67 m_xContext( xContext ), m_bIsValid( false ), m_bInitialised( false ),
68 m_bIsPkgMSP( false )
70 ENSURE_OR_THROW( m_xContext.is(), "MasterScriptProvider::MasterScriptProvider: No context available\n" );
71 m_xMgr = m_xContext->getServiceManager();
72 ENSURE_OR_THROW( m_xMgr.is(), "MasterScriptProvider::MasterScriptProvider: No service manager available\n" );
73 m_bIsValid = true;
77 MasterScriptProvider::~MasterScriptProvider()
82 void SAL_CALL MasterScriptProvider::initialize( const Sequence < Any >& args )
84 if ( m_bInitialised )
85 return;
87 m_bIsValid = false;
89 sal_Int32 len = args.getLength();
90 if ( len > 1 )
92 throw RuntimeException(
93 u"MasterScriptProvider::initialize: invalid number of arguments"_ustr );
96 Sequence< Any > invokeArgs( len );
98 if ( len != 0 )
100 auto pinvokeArgs = invokeArgs.getArray();
101 // check if first parameter is a string
102 // if it is, this implies that this is a MSP created
103 // with a user or share ctx ( used for browse functionality )
105 if ( args[ 0 ] >>= m_sCtxString )
107 pinvokeArgs[ 0 ] = args[ 0 ];
108 if ( m_sCtxString.startsWith( "vnd.sun.star.tdoc" ) )
110 m_xModel = MiscUtils::tDocUrlToModel( m_sCtxString );
113 else if ( args[ 0 ] >>= m_xInvocationContext )
115 m_xModel.set( m_xInvocationContext->getScriptContainer(), UNO_QUERY_THROW );
117 else
119 args[ 0 ] >>= m_xModel;
122 if ( m_xModel.is() )
124 // from the arguments, we were able to deduce a model. That alone doesn't
125 // suffice, we also need an XEmbeddedScripts which actually indicates support
126 // for embedding scripts
127 Reference< XEmbeddedScripts > xScripts( m_xModel, UNO_QUERY );
128 if ( !xScripts.is() )
130 throw lang::IllegalArgumentException(
131 u"The given document does not support embedding scripts into it, and cannot be associated with such a document."_ustr,
132 *this,
139 m_sCtxString = MiscUtils::xModelToTdocUrl( m_xModel, m_xContext );
141 catch ( const Exception& )
143 Any aError( ::cppu::getCaughtException() );
145 Exception aException;
146 aError >>= aException;
147 OUString buf =
148 "MasterScriptProvider::initialize: caught " +
149 aError.getValueTypeName() +
150 ":" +
151 aException.Message;
152 throw lang::WrappedTargetException( buf, *this, aError );
155 if ( m_xInvocationContext.is() && m_xInvocationContext != m_xModel )
156 pinvokeArgs[ 0 ] <<= m_xInvocationContext;
157 else
158 pinvokeArgs[ 0 ] <<= m_sCtxString;
161 OUString pkgSpec = u"uno_packages"_ustr;
162 sal_Int32 indexOfPkgSpec = m_sCtxString.lastIndexOf( pkgSpec );
164 // if context string ends with "uno_packages"
165 if ( indexOfPkgSpec > -1 && m_sCtxString.match( pkgSpec, indexOfPkgSpec ) )
167 m_bIsPkgMSP = true;
169 else
171 m_bIsPkgMSP = false;
174 else // no args
176 // use either scripting context or maybe zero args?
177 invokeArgs = Sequence< Any >( 0 ); // no arguments
179 m_sAargs = std::move(invokeArgs);
180 // don't create pkg mgr MSP for documents, not supported
181 if ( !m_bIsPkgMSP && !m_xModel.is() )
183 createPkgProvider();
186 m_bInitialised = true;
187 m_bIsValid = true;
191 void MasterScriptProvider::createPkgProvider()
195 Any location;
196 location <<= m_sCtxString + ":uno_packages";
198 Reference< provider::XScriptProviderFactory > xFac =
199 provider::theMasterScriptProviderFactory::get( m_xContext );
201 m_xMSPPkg.set(
202 xFac->createScriptProvider( location ), UNO_SET_THROW );
205 catch ( const Exception& )
207 TOOLS_WARN_EXCEPTION("scripting.provider", "Exception creating MasterScriptProvider for uno_packages in context "
208 << m_sCtxString );
213 Reference< provider::XScript >
214 MasterScriptProvider::getScript( const OUString& scriptURI )
216 if ( !m_bIsValid )
218 throw provider::ScriptFrameworkErrorException(
219 u"MasterScriptProvider not initialised"_ustr, Reference< XInterface >(),
220 scriptURI, u""_ustr,
221 provider::ScriptFrameworkErrorType::UNKNOWN );
224 // need to get the language from the string
226 Reference< uri::XUriReferenceFactory > xFac ( uri::UriReferenceFactory::create( m_xContext ) );
228 Reference< uri::XUriReference > uriRef = xFac->parse( scriptURI );
230 Reference < uri::XVndSunStarScriptUrl > sfUri( uriRef, UNO_QUERY );
232 if ( !uriRef.is() || !sfUri.is() )
234 throw provider::ScriptFrameworkErrorException(
235 "Incorrect format for Script URI: " + scriptURI,
236 Reference< XInterface >(),
237 scriptURI, u""_ustr,
238 provider::ScriptFrameworkErrorType::UNKNOWN );
241 OUString langKey(u"language"_ustr);
242 OUString locKey(u"location"_ustr);
244 if ( !sfUri->hasParameter( langKey ) ||
245 !sfUri->hasParameter( locKey ) ||
246 ( sfUri->getName().isEmpty() ) )
248 throw provider::ScriptFrameworkErrorException(
249 "Incorrect format for Script URI: " + scriptURI,
250 Reference< XInterface >(),
251 scriptURI, u""_ustr,
252 provider::ScriptFrameworkErrorType::UNKNOWN );
255 OUString language = sfUri->getParameter( langKey );
256 OUString location = sfUri->getParameter( locKey );
258 // if script us located in uno pkg
259 sal_Int32 index = -1;
260 OUString pkgTag(u":uno_packages"_ustr);
261 // for languages other than basic, scripts located in uno packages
262 // are merged into the user/share location context.
263 // For other languages the location attribute in script url has the form
264 // location = [user|share]:uno_packages or location :uno_packages/xxxx.uno.pkg
265 // we need to extract the value of location part from the
266 // location attribute of the script, if the script is located in an
267 // uno package then that is the location part up to and including
268 // ":uno_packages", if the script is not in a uno package then the
269 // normal value is used e.g. user or share.
270 // The value extracted will be used to determine if the script is
271 // located in the same location context as this MSP.
272 // For Basic, the language script provider can handle the execution of a
273 // script in any location context
274 if ( ( index = location.indexOf( pkgTag ) ) > -1 )
276 location = location.copy( 0, index + pkgTag.getLength() );
279 Reference< provider::XScript > xScript;
281 // If the script location is in the same location context as this
282 // MSP then delete to the language provider controlled by this MSP
283 // ** Special case is BASIC, all calls to getScript will be handled
284 // by the language script provider in the current location context
285 // even if it's different
286 if ( ( location == "document"
287 && m_xModel.is()
289 || ( endsWith( m_sCtxString, location ) )
290 || ( language == "Basic" )
293 Reference< provider::XScriptProvider > xScriptProvider;
294 OUString serviceName = "com.sun.star.script.provider.ScriptProviderFor" + language;
295 if ( !providerCache() )
297 throw provider::ScriptFrameworkErrorException(
298 u"No LanguageProviders detected"_ustr,
299 Reference< XInterface >(),
300 sfUri->getName(), language,
301 provider::ScriptFrameworkErrorType::NOTSUPPORTED );
306 xScriptProvider.set(
307 providerCache()->getProvider( serviceName ),
308 UNO_SET_THROW );
310 catch( const Exception& e )
312 throw provider::ScriptFrameworkErrorException(
313 e.Message, Reference< XInterface >(),
314 sfUri->getName(), language,
315 provider::ScriptFrameworkErrorType::NOTSUPPORTED );
318 xScript=xScriptProvider->getScript( scriptURI );
320 else
322 Reference< provider::XScriptProviderFactory > xFac_ =
323 provider::theMasterScriptProviderFactory::get( m_xContext );
325 Reference< provider::XScriptProvider > xSP(
326 xFac_->createScriptProvider( Any( location ) ), UNO_SET_THROW );
327 xScript = xSP->getScript( scriptURI );
330 return xScript;
334 ProviderCache*
335 MasterScriptProvider::providerCache()
337 std::scoped_lock aGuard( m_mutex );
338 if ( !m_pPCache )
340 Sequence<OUString> denylist { u"com.sun.star.script.provider.ScriptProviderForBasic"_ustr };
342 if ( !m_bIsPkgMSP )
344 m_pPCache.reset( new ProviderCache( m_xContext, m_sAargs ) );
346 else
348 m_pPCache.reset( new ProviderCache( m_xContext, m_sAargs, denylist ) );
351 return m_pPCache.get();
355 OUString SAL_CALL
356 MasterScriptProvider::getName()
358 if ( !m_bIsPkgMSP )
360 OUString sCtx = getContextString();
361 if ( sCtx.startsWith( "vnd.sun.star.tdoc" ) )
363 Reference< frame::XModel > xModel = m_xModel;
364 if ( !xModel.is() )
366 xModel = MiscUtils::tDocUrlToModel( sCtx );
369 m_sNodeName = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
371 else
373 m_sNodeName = parseLocationName( getContextString() );
376 else
378 m_sNodeName = "uno_packages";
380 return m_sNodeName;
384 Sequence< Reference< browse::XBrowseNode > > SAL_CALL
385 MasterScriptProvider::getChildNodes()
387 Sequence< Reference< provider::XScriptProvider > > providers = providerCache()->getAllProviders();
389 sal_Int32 size = providers.getLength();
390 bool hasPkgs = m_xMSPPkg.is();
391 if ( hasPkgs )
393 size++;
395 Sequence< Reference< browse::XBrowseNode > > children( size );
396 auto childrenRange = asNonConstRange(children);
397 sal_Int32 provIndex = 0;
398 for ( ; provIndex < providers.getLength(); provIndex++ )
400 childrenRange[ provIndex ].set( providers[ provIndex ], UNO_QUERY );
403 if ( hasPkgs )
405 childrenRange[ provIndex ].set( m_xMSPPkg, UNO_QUERY );
409 return children;
413 sal_Bool SAL_CALL
414 MasterScriptProvider::hasChildNodes()
416 return true;
420 sal_Int16 SAL_CALL
421 MasterScriptProvider::getType()
423 return browse::BrowseNodeTypes::CONTAINER;
427 OUString
428 MasterScriptProvider::parseLocationName( const OUString& location )
430 // strip out the last leaf of location name
431 // e.g. file://dir1/dir2/Blah.sxw - > Blah.sxw
432 OUString temp = location;
433 INetURLObject aURLObj( temp );
434 if ( !aURLObj.HasError() )
435 temp = aURLObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
436 return temp;
439 namespace
441 template <typename Proc> bool FindProviderAndApply(ProviderCache& rCache, Proc p)
443 auto pass = [&rCache, &p]() -> bool
445 bool bResult = false;
446 const Sequence<Reference<provider::XScriptProvider>> aAllProviders = rCache.getAllProviders();
447 for (const auto& rProv : aAllProviders)
449 Reference<container::XNameContainer> xCont(rProv, UNO_QUERY);
450 if (!xCont.is())
452 continue;
456 bResult = p(xCont);
457 if (bResult)
458 break;
460 catch (const Exception&)
462 TOOLS_INFO_EXCEPTION("scripting.provider", "ignoring");
465 return bResult;
467 bool bSuccess = false;
468 // 1. Try to perform the operation without trying to enable JVM (if disabled)
469 // This allows us to avoid useless user interaction in case when other provider
470 // (not JVM) actually handles the operation.
472 css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
473 bSuccess = pass();
475 // 2. Now retry asking to enable JVM in case we didn't succeed first time
476 if (!bSuccess)
478 bSuccess = pass();
480 return bSuccess;
482 } // namespace
484 // Register Package
485 void SAL_CALL
486 MasterScriptProvider::insertByName( const OUString& aName, const Any& aElement )
488 if ( !m_bIsPkgMSP )
490 if ( !m_xMSPPkg.is() )
492 throw RuntimeException( u"PackageMasterScriptProvider is uninitialised"_ustr );
495 Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
496 xCont->insertByName( aName, aElement );
498 else
500 Reference< deployment::XPackage > xPkg( aElement, UNO_QUERY );
501 if ( !xPkg.is() )
503 throw lang::IllegalArgumentException( u"Couldn't convert to XPackage"_ustr,
504 Reference < XInterface > (), 2 );
506 if ( aName.isEmpty() )
508 throw lang::IllegalArgumentException( u"Name not set!!"_ustr,
509 Reference < XInterface > (), 1 );
511 // TODO for library package parse the language, for the moment will try
512 // to get each provider to process the new Package, the first one the succeeds
513 // will terminate processing
514 const bool bSuccess = FindProviderAndApply(
515 *providerCache(), [&aName, &aElement](Reference<container::XNameContainer>& xCont) {
516 xCont->insertByName(aName, aElement);
517 return true;
519 if (!bSuccess)
521 // No script providers could process the package
522 throw lang::IllegalArgumentException( "Failed to register package for " + aName,
523 Reference < XInterface > (), 2 );
529 // Revoke Package
530 void SAL_CALL
531 MasterScriptProvider::removeByName( const OUString& Name )
533 if ( !m_bIsPkgMSP )
535 if ( !m_xMSPPkg.is() )
537 throw RuntimeException( u"PackageMasterScriptProvider is uninitialised"_ustr );
540 Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
541 xCont->removeByName( Name );
543 else
545 if ( Name.isEmpty() )
547 throw lang::IllegalArgumentException( u"Name not set!!"_ustr,
548 Reference < XInterface > (), 1 );
550 // TODO for Script library package url parse the language,
551 // for the moment will just try to get each provider to process remove/revoke
552 // request, the first one the succeeds will terminate processing
553 const bool bSuccess = FindProviderAndApply(
554 *providerCache(), [&Name](Reference<container::XNameContainer>& xCont) {
555 xCont->removeByName(Name);
556 return true;
558 if (!bSuccess)
560 // No script providers could process the package
561 throw lang::IllegalArgumentException( "Failed to revoke package for " + Name,
562 Reference < XInterface > (), 1 );
569 void SAL_CALL
570 MasterScriptProvider::replaceByName( const OUString& /*aName*/, const Any& /*aElement*/ )
572 // TODO needs implementing
573 throw RuntimeException( u"replaceByName not implemented!!!!"_ustr );
576 Any SAL_CALL
577 MasterScriptProvider::getByName( const OUString& /*aName*/ )
579 // TODO needs to be implemented
580 throw RuntimeException( u"getByName not implemented!!!!"_ustr );
583 sal_Bool SAL_CALL
584 MasterScriptProvider::hasByName( const OUString& aName )
586 bool result = false;
587 if ( !m_bIsPkgMSP )
589 if ( m_xMSPPkg.is() )
591 Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
592 result = xCont->hasByName( aName );
594 // If this is a document provider then we shouldn't
595 // have a PackageProvider
596 else if (!m_xModel.is())
598 throw RuntimeException( u"PackageMasterScriptProvider is uninitialised"_ustr );
602 else
604 if ( aName.isEmpty() )
606 throw lang::IllegalArgumentException( u"Name not set!!"_ustr,
607 Reference < XInterface > (), 1 );
609 // TODO for Script library package url parse the language,
610 // for the moment will just try to get each provider to see if the
611 // package exists in any provider, first one that succeed will
612 // terminate the loop
613 result = FindProviderAndApply(
614 *providerCache(), [&aName](Reference<container::XNameContainer>& xCont) {
615 return xCont->hasByName(aName);
618 return result;
622 Sequence< OUString > SAL_CALL
623 MasterScriptProvider::getElementNames( )
625 // TODO needs implementing
626 throw RuntimeException( u"getElementNames not implemented!!!!"_ustr );
629 Type SAL_CALL
630 MasterScriptProvider::getElementType( )
632 // TODO needs implementing
633 Type t;
634 return t;
637 sal_Bool SAL_CALL MasterScriptProvider::hasElements( )
639 // TODO needs implementing
640 throw RuntimeException( u"hasElements not implemented!!!!"_ustr );
644 OUString SAL_CALL MasterScriptProvider::getImplementationName( )
646 return u"com.sun.star.script.provider.MasterScriptProvider"_ustr;
649 sal_Bool SAL_CALL MasterScriptProvider::supportsService( const OUString& serviceName )
651 return cppu::supportsService(this, serviceName);
655 Sequence< OUString > SAL_CALL MasterScriptProvider::getSupportedServiceNames( )
657 return {
658 u"com.sun.star.script.provider.MasterScriptProvider"_ustr,
659 u"com.sun.star.script.browse.BrowseNode"_ustr,
660 u"com.sun.star.script.provider.ScriptProvider"_ustr };
663 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
664 scripting_MasterScriptProvider_get_implementation(
665 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
667 return cppu::acquire(new MasterScriptProvider(context));
670 } // namespace func_provider
673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */