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 <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>
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
);
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
);
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();
101 maEventData
[nIndex
].clear();
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
);
120 return maEventData
[nIndex
];
122 throw container::NoSuchElementException();
126 uno::Sequence
< OUString
> SAL_CALL
SfxEvents_Impl::getElementNames()
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();
151 sal_Bool SAL_CALL
SfxEvents_Impl::hasElements()
153 ::osl::MutexGuard
aGuard( maMutex
);
155 return maEventNames
.hasElements();
160 bool lcl_isScriptAccessAllowed_nothrow(const uno::Reference
<uno::XInterface
>& rxScriptContext
)
164 uno::Reference
<document::XEmbeddedScripts
> xScripts(rxScriptContext
, uno::UNO_QUERY
);
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");
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
) )
192 if ( !aProperties
.hasElements() )
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
;
206 OSL_FAIL("Unknown property value!");
212 // Empty type means no active binding for the event. Just ignore do nothing.
216 if (aScript
.isEmpty())
220 pDoc
= SfxObjectShell::Current();
222 if (pDoc
&& !lcl_isScriptAccessAllowed_nothrow(pDoc
->GetModel()))
225 if (aType
== STAR_BASIC
)
228 SfxMacroLoader::loadMacro( aScript
, aAny
, pDoc
);
230 else if (aType
== "Service" || aType
== "Script")
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
);
242 SfxViewFrame
* pView
= SfxViewFrame::GetFirst(pDoc
);
245 < frame::XDispatchProvider
> xProv
;
247 if ( pView
!= nullptr )
249 xProv
= uno::Reference
250 < frame::XDispatchProvider
> (
251 pView
->GetFrame().GetFrameInterface(), uno::UNO_QUERY
);
255 xProv
= frame::Desktop::create( ::comphelper::getProcessComponentContext() );
258 uno::Reference
< frame::XDispatch
> xDisp
;
260 xDisp
= xProv
->queryDispatch( aURL
, OUString(), 0 );
264 beans::PropertyValue aEventParam
;
265 aEventParam
.Value
<<= aTrigger
;
266 uno::Sequence
< beans::PropertyValue
> aDispatchArgs( &aEventParam
, 1 );
267 xDisp
->dispatch( aURL
, aDispatchArgs
);
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
);
290 uno::Any aEventData
= maEventData
[ nIndex
];
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
315 maEventNames
= pShell
->GetEventNames();
317 maEventNames
= rtl::Reference
<GlobalEventConfig
>(new GlobalEventConfig
)->getElementNames();
319 maEventData
= uno::Sequence
< uno::Any
> ( maEventNames
.getLength() );
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
;
339 NormalizeMacro( rElement
, aAny
, pObjShell
);
341 if ( aAny
>>= aProperties
)
348 if ( !aProperties
.hasElements() )
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
;
362 OSL_FAIL("Unknown property value!");
367 ScriptType
eType( STARBASIC
);
368 if ( aType
== STAR_BASIC
)
370 else if (aType
== "Script" && !aScriptURL
.isEmpty())
371 eType
= EXTENDED_STYPE
;
372 else if ( aType
== SVX_MACRO_LANGUAGE_JAVASCRIPT
)
375 SAL_WARN( "sfx.notify", "ConvertToMacro: Unknown macro type" );
378 if ( !aMacroName
.isEmpty() )
380 if ( aLibrary
== "application" )
381 aLibrary
= SfxGetpApp()->GetName();
384 pMacro
.reset(new SvxMacro( aMacroName
, aLibrary
, eType
));
386 else if ( eType
== EXTENDED_STYPE
)
387 pMacro
.reset(new SvxMacro( aScriptURL
, aType
));
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
;
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
)
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();
435 aLibrary
= SfxGetpApp()->GetName();
437 // Get the macro name
438 aMacroName
= aScript
.copy( nThirdSlashPos
+1, nArgsPos
- nThirdSlashPos
- 1 );
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" )
451 aScript
+= "/" + aMacroName
+ "()";
457 if (aLibrary
!= "document")
459 if ( aLibrary
.isEmpty() || (pDoc
&& ( aLibrary
== pDoc
->GetTitle( SFX_TITLE_APINAME
) || aLibrary
== pDoc
->GetTitle() )) )
460 aLibrary
= "document";
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: */