Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sfx2 / source / notify / eventsupplier.cxx
blobe21130d6022c8f48c64dd23539c133a464390e6e
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 .
20 #include <com/sun/star/beans/PropertyValue.hpp>
22 #include <com/sun/star/document/XEmbeddedScripts.hpp>
23 #include <com/sun/star/document/XScriptInvocationContext.hpp>
24 #include <com/sun/star/util/URL.hpp>
25 #include <com/sun/star/frame/Desktop.hpp>
26 #include <com/sun/star/util/URLTransformer.hpp>
27 #include <com/sun/star/util/XURLTransformer.hpp>
28 #include <com/sun/star/uno/XInterface.hpp>
29 #include <tools/urlobj.hxx>
30 #include <tools/diagnose_ex.h>
31 #include <svl/macitem.hxx>
32 #include <sfx2/objsh.hxx>
33 #include <sfx2/sfxbasemodel.hxx>
34 #include <sfx2/evntconf.hxx>
35 #include <unotools/eventcfg.hxx>
36 #include <sal/log.hxx>
38 #include <unotools/securityoptions.hxx>
39 #include <comphelper/processfactory.hxx>
40 #include <comphelper/namedvaluecollection.hxx>
41 #include <comphelper/sequence.hxx>
42 #include <eventsupplier.hxx>
44 #include <sfx2/app.hxx>
46 #include <sfx2/sfxsids.hrc>
47 #include <sfx2/docfile.hxx>
48 #include <sfx2/viewfrm.hxx>
49 #include <sfx2/frame.hxx>
50 #include <macroloader.hxx>
52 using namespace css;
53 using namespace ::com::sun::star;
57 // --- XNameReplace ---
59 void SAL_CALL SfxEvents_Impl::replaceByName( const OUString & aName, const uno::Any & rElement )
61 ::osl::MutexGuard aGuard( maMutex );
63 // find the event in the list and replace the data
64 auto nIndex = comphelper::findValue(maEventNames, aName);
65 if (nIndex != -1)
67 // check for correct type of the element
68 if ( !::comphelper::NamedValueCollection::canExtractFrom( rElement ) )
69 throw lang::IllegalArgumentException();
70 ::comphelper::NamedValueCollection const aEventDescriptor( rElement );
72 // create Configuration at first, creation might call this method also and that would overwrite everything
73 // we might have stored before!
74 if ( mpObjShell && !mpObjShell->IsLoading() )
75 mpObjShell->SetModified();
77 ::comphelper::NamedValueCollection aNormalizedDescriptor;
78 NormalizeMacro( aEventDescriptor, aNormalizedDescriptor, mpObjShell );
80 OUString sType;
81 if ( ( aNormalizedDescriptor.size() == 1 )
82 && !aNormalizedDescriptor.has( PROP_EVENT_TYPE ) //TODO
83 && ( aNormalizedDescriptor.get( PROP_EVENT_TYPE ) >>= sType )
84 && ( sType.isEmpty() )
87 // An empty event type means no binding. Therefore reset data
88 // to reflect that state.
89 // (that's for compatibility only. Nowadays, the Tools/Customize dialog should
90 // set an empty sequence to indicate the request for resetting the assignment.)
91 OSL_ENSURE( false, "legacy event assignment format detected" );
92 aNormalizedDescriptor.clear();
95 if ( !aNormalizedDescriptor.empty() )
97 maEventData[nIndex] <<= aNormalizedDescriptor.getPropertyValues();
99 else
101 maEventData[nIndex].clear();
103 return;
106 throw container::NoSuchElementException();
110 // --- XNameAccess ---
112 uno::Any SAL_CALL SfxEvents_Impl::getByName( const OUString& aName )
114 ::osl::MutexGuard aGuard( maMutex );
116 // find the event in the list and return the data
118 auto nIndex = comphelper::findValue(maEventNames, aName);
119 if (nIndex != -1)
120 return maEventData[nIndex];
122 throw container::NoSuchElementException();
126 uno::Sequence< OUString > SAL_CALL SfxEvents_Impl::getElementNames()
128 return maEventNames;
132 sal_Bool SAL_CALL SfxEvents_Impl::hasByName( const OUString& aName )
134 ::osl::MutexGuard aGuard( maMutex );
136 // find the event in the list and return the data
138 return comphelper::findValue(maEventNames, aName) != -1;
142 // --- XElementAccess ( parent of XNameAccess ) ---
144 uno::Type SAL_CALL SfxEvents_Impl::getElementType()
146 uno::Type aElementType = cppu::UnoType<uno::Sequence < beans::PropertyValue >>::get();
147 return aElementType;
151 sal_Bool SAL_CALL SfxEvents_Impl::hasElements()
153 ::osl::MutexGuard aGuard( maMutex );
155 return maEventNames.hasElements();
158 namespace
160 bool lcl_isScriptAccessAllowed_nothrow(const uno::Reference<uno::XInterface>& rxScriptContext)
164 uno::Reference<document::XEmbeddedScripts> xScripts(rxScriptContext, uno::UNO_QUERY);
165 if (!xScripts.is())
167 uno::Reference<document::XScriptInvocationContext> xContext(rxScriptContext, uno::UNO_QUERY_THROW);
168 xScripts.set(xContext->getScriptContainer(), uno::UNO_SET_THROW);
171 return xScripts->getAllowMacroExecution();
173 catch( const uno::Exception& )
175 DBG_UNHANDLED_EXCEPTION("sfx.doc");
177 return false;
181 void SfxEvents_Impl::Execute( uno::Any const & aEventData, const document::DocumentEvent& aTrigger, SfxObjectShell* pDoc )
183 uno::Sequence < beans::PropertyValue > aProperties;
184 if ( !(aEventData >>= aProperties) )
185 return;
187 OUString aType;
188 OUString aScript;
189 OUString aLibrary;
190 OUString aMacroName;
192 if ( !aProperties.hasElements() )
193 return;
195 for ( const auto& rProp : std::as_const(aProperties) )
197 if ( rProp.Name == PROP_EVENT_TYPE )
198 rProp.Value >>= aType;
199 else if ( rProp.Name == PROP_SCRIPT )
200 rProp.Value >>= aScript;
201 else if ( rProp.Name == PROP_LIBRARY )
202 rProp.Value >>= aLibrary;
203 else if ( rProp.Name == PROP_MACRO_NAME )
204 rProp.Value >>= aMacroName;
205 else {
206 OSL_FAIL("Unknown property value!");
210 if (aType.isEmpty())
212 // Empty type means no active binding for the event. Just ignore do nothing.
213 return;
216 if (aScript.isEmpty())
217 return;
219 if (!pDoc)
220 pDoc = SfxObjectShell::Current();
222 if (pDoc && !lcl_isScriptAccessAllowed_nothrow(pDoc->GetModel()))
223 return;
225 if (aType == STAR_BASIC)
227 uno::Any aAny;
228 SfxMacroLoader::loadMacro( aScript, aAny, pDoc );
230 else if (aType == "Service" || aType == "Script")
232 util::URL aURL;
233 uno::Reference < util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
235 aURL.Complete = aScript;
236 xTrans->parseStrict( aURL );
238 bool bAllowed = !SfxObjectShell::UnTrustedScript(aURL.Complete);
240 if (bAllowed)
242 SfxViewFrame* pView = SfxViewFrame::GetFirst(pDoc);
244 uno::Reference
245 < frame::XDispatchProvider > xProv;
247 if ( pView != nullptr )
249 xProv = uno::Reference
250 < frame::XDispatchProvider > (
251 pView->GetFrame().GetFrameInterface(), uno::UNO_QUERY );
253 else
255 xProv = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
258 uno::Reference < frame::XDispatch > xDisp;
259 if ( xProv.is() )
260 xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
262 if ( xDisp.is() )
264 beans::PropertyValue aEventParam;
265 aEventParam.Value <<= aTrigger;
266 uno::Sequence< beans::PropertyValue > aDispatchArgs( &aEventParam, 1 );
267 xDisp->dispatch( aURL, aDispatchArgs );
271 else
273 SAL_WARN( "sfx.notify", "notifyEvent(): Unsupported event type" );
278 // --- ::document::XEventListener ---
280 void SAL_CALL SfxEvents_Impl::notifyEvent( const document::EventObject& aEvent )
282 ::osl::ClearableMutexGuard aGuard( maMutex );
284 // get the event name, find the corresponding data, execute the data
286 auto nIndex = comphelper::findValue(maEventNames, aEvent.EventName);
287 if ( nIndex == -1 )
288 return;
290 uno::Any aEventData = maEventData[ nIndex ];
291 aGuard.clear();
292 Execute( aEventData, document::DocumentEvent(aEvent.Source, aEvent.EventName, nullptr, uno::Any()), mpObjShell );
296 // --- ::lang::XEventListener ---
298 void SAL_CALL SfxEvents_Impl::disposing( const lang::EventObject& /*Source*/ )
300 ::osl::MutexGuard aGuard( maMutex );
302 if ( mxBroadcaster.is() )
304 mxBroadcaster->removeEventListener( this );
305 mxBroadcaster = nullptr;
310 SfxEvents_Impl::SfxEvents_Impl( SfxObjectShell* pShell,
311 uno::Reference< document::XEventBroadcaster > const & xBroadcaster )
313 // get the list of supported events and store it
314 if ( pShell )
315 maEventNames = pShell->GetEventNames();
316 else
317 maEventNames = rtl::Reference<GlobalEventConfig>(new GlobalEventConfig)->getElementNames();
319 maEventData = uno::Sequence < uno::Any > ( maEventNames.getLength() );
321 mpObjShell = pShell;
322 mxBroadcaster = xBroadcaster;
324 if ( mxBroadcaster.is() )
325 mxBroadcaster->addEventListener( this );
329 SfxEvents_Impl::~SfxEvents_Impl()
334 std::unique_ptr<SvxMacro> SfxEvents_Impl::ConvertToMacro( const uno::Any& rElement, SfxObjectShell* pObjShell )
336 std::unique_ptr<SvxMacro> pMacro;
337 uno::Sequence < beans::PropertyValue > aProperties;
338 uno::Any aAny;
339 NormalizeMacro( rElement, aAny, pObjShell );
341 if ( aAny >>= aProperties )
343 OUString aType;
344 OUString aScriptURL;
345 OUString aLibrary;
346 OUString aMacroName;
348 if ( !aProperties.hasElements() )
349 return pMacro;
351 for ( const auto& rProp : std::as_const(aProperties) )
353 if ( rProp.Name == PROP_EVENT_TYPE )
354 rProp.Value >>= aType;
355 else if ( rProp.Name == PROP_SCRIPT )
356 rProp.Value >>= aScriptURL;
357 else if ( rProp.Name == PROP_LIBRARY )
358 rProp.Value >>= aLibrary;
359 else if ( rProp.Name == PROP_MACRO_NAME )
360 rProp.Value >>= aMacroName;
361 else {
362 OSL_FAIL("Unknown property value!");
366 // Get the type
367 ScriptType eType( STARBASIC );
368 if ( aType == STAR_BASIC )
369 eType = STARBASIC;
370 else if (aType == "Script" && !aScriptURL.isEmpty())
371 eType = EXTENDED_STYPE;
372 else if ( aType == SVX_MACRO_LANGUAGE_JAVASCRIPT )
373 eType = JAVASCRIPT;
374 else {
375 SAL_WARN( "sfx.notify", "ConvertToMacro: Unknown macro type" );
378 if ( !aMacroName.isEmpty() )
380 if ( aLibrary == "application" )
381 aLibrary = SfxGetpApp()->GetName();
382 else
383 aLibrary.clear();
384 pMacro.reset(new SvxMacro( aMacroName, aLibrary, eType ));
386 else if ( eType == EXTENDED_STYPE )
387 pMacro.reset(new SvxMacro( aScriptURL, aType ));
390 return pMacro;
393 void SfxEvents_Impl::NormalizeMacro( const uno::Any& rEvent, uno::Any& rRet, SfxObjectShell* pDoc )
395 const ::comphelper::NamedValueCollection aEventDescriptor( rEvent );
396 ::comphelper::NamedValueCollection aEventDescriptorOut;
398 NormalizeMacro( aEventDescriptor, aEventDescriptorOut, pDoc );
400 rRet <<= aEventDescriptorOut.getPropertyValues();
403 void SfxEvents_Impl::NormalizeMacro( const ::comphelper::NamedValueCollection& i_eventDescriptor,
404 ::comphelper::NamedValueCollection& o_normalizedDescriptor, SfxObjectShell* i_document )
406 SfxObjectShell* pDoc = i_document;
407 if ( !pDoc )
408 pDoc = SfxObjectShell::Current();
410 OUString aType = i_eventDescriptor.getOrDefault( PROP_EVENT_TYPE, OUString() );
411 OUString aScript = i_eventDescriptor.getOrDefault( PROP_SCRIPT, OUString() );
412 OUString aLibrary = i_eventDescriptor.getOrDefault( PROP_LIBRARY, OUString() );
413 OUString aMacroName = i_eventDescriptor.getOrDefault( PROP_MACRO_NAME, OUString() );
415 if ( !aType.isEmpty() )
416 o_normalizedDescriptor.put( PROP_EVENT_TYPE, aType );
417 if ( !aScript.isEmpty() )
418 o_normalizedDescriptor.put( PROP_SCRIPT, aScript );
420 if ( aType != STAR_BASIC )
421 return;
423 if ( !aScript.isEmpty() )
425 if ( aMacroName.isEmpty() || aLibrary.isEmpty() )
427 sal_Int32 nThirdSlashPos = aScript.indexOf( '/', 8 );
428 sal_Int32 nArgsPos = aScript.indexOf( '(' );
429 if ( ( nThirdSlashPos != -1 ) && ( nArgsPos == -1 || nThirdSlashPos < nArgsPos ) )
431 OUString aBasMgrName( INetURLObject::decode( aScript.copy( 8, nThirdSlashPos-8 ), INetURLObject::DecodeMechanism::WithCharset ) );
432 if (pDoc && aBasMgrName == ".")
433 aLibrary = pDoc->GetTitle();
434 else
435 aLibrary = SfxGetpApp()->GetName();
437 // Get the macro name
438 aMacroName = aScript.copy( nThirdSlashPos+1, nArgsPos - nThirdSlashPos - 1 );
440 else
442 SAL_WARN( "sfx.notify", "ConvertToMacro: Unknown macro url format" );
446 else if ( !aMacroName.isEmpty() )
448 aScript = "macro://";
449 if ( aLibrary != SfxGetpApp()->GetName() && aLibrary != "StarDesktop" && aLibrary != "application" )
450 aScript += ".";
451 aScript += "/" + aMacroName + "()";
453 else
454 // wrong properties
455 return;
457 if (aLibrary != "document")
459 if ( aLibrary.isEmpty() || (pDoc && ( aLibrary == pDoc->GetTitle( SFX_TITLE_APINAME ) || aLibrary == pDoc->GetTitle() )) )
460 aLibrary = "document";
461 else
462 aLibrary = "application";
465 o_normalizedDescriptor.put( PROP_SCRIPT, aScript );
466 o_normalizedDescriptor.put( PROP_LIBRARY, aLibrary );
467 o_normalizedDescriptor.put( PROP_MACRO_NAME, aMacroName );
470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */