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/util/URL.hpp>
24 #include <com/sun/star/frame/Desktop.hpp>
25 #include <com/sun/star/util/URLTransformer.hpp>
26 #include <com/sun/star/util/XURLTransformer.hpp>
27 #include <tools/urlobj.hxx>
28 #include <tools/diagnose_ex.h>
29 #include <svl/macitem.hxx>
30 #include <sfx2/objsh.hxx>
31 #include <sfx2/sfxbasemodel.hxx>
32 #include <sfx2/evntconf.hxx>
33 #include <unotools/eventcfg.hxx>
35 #include <unotools/securityoptions.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <comphelper/namedvaluecollection.hxx>
38 #include "eventsupplier.hxx"
40 #include <sfx2/app.hxx>
41 #include <sfx2/sfxresid.hxx>
43 #include <sfx2/sfxsids.hrc>
44 #include "sfxlocal.hrc"
45 #include <sfx2/docfile.hxx>
46 #include <sfx2/viewfrm.hxx>
47 #include <sfx2/frame.hxx>
48 #include <macroloader.hxx>
52 #define MACRO_PRFIX "macro://"
53 #define MACRO_POSTFIX "()"
58 // --- XNameReplace ---
60 void SAL_CALL
SfxEvents_Impl::replaceByName( const OUString
& aName
, const uno::Any
& rElement
)
61 throw( lang::IllegalArgumentException
, container::NoSuchElementException
,
62 lang::WrappedTargetException
, uno::RuntimeException
, std::exception
)
64 ::osl::MutexGuard
aGuard( maMutex
);
66 // find the event in the list and replace the data
67 long nCount
= maEventNames
.getLength();
68 for ( long i
=0; i
<nCount
; i
++ )
70 if ( maEventNames
[i
] == aName
)
72 // check for correct type of the element
73 if ( !::comphelper::NamedValueCollection::canExtractFrom( rElement
) )
74 throw lang::IllegalArgumentException();
75 ::comphelper::NamedValueCollection
const aEventDescriptor( rElement
);
77 // create Configuration at first, creation might call this method also and that would overwrite everything
78 // we might have stored before!
79 if ( mpObjShell
&& !mpObjShell
->IsLoading() )
80 mpObjShell
->SetModified( true );
82 ::comphelper::NamedValueCollection aNormalizedDescriptor
;
83 NormalizeMacro( aEventDescriptor
, aNormalizedDescriptor
, mpObjShell
);
86 if ( ( aNormalizedDescriptor
.size() == 1 )
87 && !aNormalizedDescriptor
.has( PROP_EVENT_TYPE
) //TODO
88 && ( aNormalizedDescriptor
.get( PROP_EVENT_TYPE
) >>= sType
)
89 && ( sType
.isEmpty() )
92 // An empty event type means no binding. Therefore reset data
93 // to reflect that state.
94 // (that's for compatibility only. Nowadays, the Tools/Customize dialog should
95 // set an empty sequence to indicate the request for resetting the assignment.)
96 OSL_ENSURE( false, "legacy event assignment format detected" );
97 aNormalizedDescriptor
.clear();
100 if ( !aNormalizedDescriptor
.empty() )
102 maEventData
[i
] <<= aNormalizedDescriptor
.getPropertyValues();
106 maEventData
[i
].clear();
112 throw container::NoSuchElementException();
116 // --- XNameAccess ---
118 uno::Any SAL_CALL
SfxEvents_Impl::getByName( const OUString
& aName
)
119 throw( container::NoSuchElementException
, lang::WrappedTargetException
,
120 uno::RuntimeException
, std::exception
)
122 ::osl::MutexGuard
aGuard( maMutex
);
124 // find the event in the list and return the data
126 long nCount
= maEventNames
.getLength();
128 for ( long i
=0; i
<nCount
; i
++ )
130 if ( maEventNames
[i
] == aName
)
131 return maEventData
[i
];
134 throw container::NoSuchElementException();
138 uno::Sequence
< OUString
> SAL_CALL
SfxEvents_Impl::getElementNames() throw ( uno::RuntimeException
, std::exception
)
144 sal_Bool SAL_CALL
SfxEvents_Impl::hasByName( const OUString
& aName
) throw ( uno::RuntimeException
, std::exception
)
146 ::osl::MutexGuard
aGuard( maMutex
);
148 // find the event in the list and return the data
150 long nCount
= maEventNames
.getLength();
152 for ( long i
=0; i
<nCount
; i
++ )
154 if ( maEventNames
[i
] == aName
)
162 // --- XElementAccess ( parent of XNameAccess ) ---
164 uno::Type SAL_CALL
SfxEvents_Impl::getElementType() throw ( uno::RuntimeException
, std::exception
)
166 uno::Type aElementType
= cppu::UnoType
<uno::Sequence
< beans::PropertyValue
>>::get();
171 sal_Bool SAL_CALL
SfxEvents_Impl::hasElements() throw ( uno::RuntimeException
, std::exception
)
173 ::osl::MutexGuard
aGuard( maMutex
);
175 if ( maEventNames
.getLength() )
181 void SfxEvents_Impl::Execute( uno::Any
& aEventData
, const document::DocumentEvent
& aTrigger
, SfxObjectShell
* pDoc
)
183 uno::Sequence
< beans::PropertyValue
> aProperties
;
184 if ( aEventData
>>= aProperties
)
191 sal_Int32 nCount
= aProperties
.getLength();
196 sal_Int32 nIndex
= 0;
197 while ( nIndex
< nCount
)
199 if ( aProperties
[ nIndex
].Name
== PROP_EVENT_TYPE
)
200 aProperties
[ nIndex
].Value
>>= aType
;
201 else if ( aProperties
[ nIndex
].Name
== PROP_SCRIPT
)
202 aProperties
[ nIndex
].Value
>>= aScript
;
203 else if ( aProperties
[ nIndex
].Name
== PROP_LIBRARY
)
204 aProperties
[ nIndex
].Value
>>= aLibrary
;
205 else if ( aProperties
[ nIndex
].Name
== PROP_MACRO_NAME
)
206 aProperties
[ nIndex
].Value
>>= aMacroName
;
208 OSL_FAIL("Unknown property value!");
213 if (aType
== STAR_BASIC
&& !aScript
.isEmpty())
216 SfxMacroLoader::loadMacro( aScript
, aAny
, pDoc
);
218 else if (aType
== "Service" ||
221 if ( !aScript
.isEmpty() )
223 SfxViewFrame
* pView
= pDoc
?
224 SfxViewFrame::GetFirst( pDoc
) :
225 SfxViewFrame::Current();
227 uno::Reference
< util::XURLTransformer
> xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
230 aURL
.Complete
= aScript
;
231 xTrans
->parseStrict( aURL
);
234 < frame::XDispatchProvider
> xProv
;
238 xProv
= uno::Reference
239 < frame::XDispatchProvider
> (
240 pView
->GetFrame().GetFrameInterface(), uno::UNO_QUERY
);
244 xProv
= uno::Reference
< frame::XDispatchProvider
> (
245 frame::Desktop::create( ::comphelper::getProcessComponentContext() ),
249 uno::Reference
< frame::XDispatch
> xDisp
;
251 xDisp
= xProv
->queryDispatch( aURL
, OUString(), 0 );
256 beans::PropertyValue aEventParam
;
257 aEventParam
.Value
<<= aTrigger
;
258 uno::Sequence
< beans::PropertyValue
> aDispatchArgs( &aEventParam
, 1 );
259 xDisp
->dispatch( aURL
, aDispatchArgs
);
263 else if ( aType
.isEmpty() )
265 // Empty type means no active binding for the event. Just ignore do nothing.
269 SAL_WARN( "sfx.notify", "notifyEvent(): Unsupported event type" );
275 // --- ::document::XEventListener ---
277 void SAL_CALL
SfxEvents_Impl::notifyEvent( const document::EventObject
& aEvent
) throw( uno::RuntimeException
, std::exception
)
279 ::osl::ClearableMutexGuard
aGuard( maMutex
);
281 // get the event name, find the coresponding data, execute the data
283 OUString aName
= aEvent
.EventName
;
284 long nCount
= maEventNames
.getLength();
288 while ( !bFound
&& ( nIndex
< nCount
) )
290 if ( maEventNames
[nIndex
] == aName
)
299 uno::Any aEventData
= maEventData
[ nIndex
];
301 Execute( aEventData
, document::DocumentEvent(aEvent
.Source
, aEvent
.EventName
, NULL
, uno::Any()), mpObjShell
);
305 // --- ::lang::XEventListener ---
307 void SAL_CALL
SfxEvents_Impl::disposing( const lang::EventObject
& /*Source*/ ) throw( uno::RuntimeException
, std::exception
)
309 ::osl::MutexGuard
aGuard( maMutex
);
311 if ( mxBroadcaster
.is() )
313 mxBroadcaster
->removeEventListener( this );
314 mxBroadcaster
= NULL
;
320 SfxEvents_Impl::SfxEvents_Impl( SfxObjectShell
* pShell
,
321 uno::Reference
< document::XEventBroadcaster
> xBroadcaster
)
323 // get the list of supported events and store it
325 maEventNames
= pShell
->GetEventNames();
327 maEventNames
= GlobalEventConfig().getElementNames();
329 maEventData
= uno::Sequence
< uno::Any
> ( maEventNames
.getLength() );
332 mxBroadcaster
= xBroadcaster
;
334 if ( mxBroadcaster
.is() )
335 mxBroadcaster
->addEventListener( this );
339 SfxEvents_Impl::~SfxEvents_Impl()
344 SvxMacro
* SfxEvents_Impl::ConvertToMacro( const uno::Any
& rElement
, SfxObjectShell
* pObjShell
, bool bNormalizeMacro
)
346 SvxMacro
* pMacro
= NULL
;
347 uno::Sequence
< beans::PropertyValue
> aProperties
;
349 if ( bNormalizeMacro
)
350 NormalizeMacro( rElement
, aAny
, pObjShell
);
354 if ( aAny
>>= aProperties
)
361 long nCount
= aProperties
.getLength();
367 while ( nIndex
< nCount
)
369 if ( aProperties
[ nIndex
].Name
== PROP_EVENT_TYPE
)
370 aProperties
[ nIndex
].Value
>>= aType
;
371 else if ( aProperties
[ nIndex
].Name
== PROP_SCRIPT
)
372 aProperties
[ nIndex
].Value
>>= aScriptURL
;
373 else if ( aProperties
[ nIndex
].Name
== PROP_LIBRARY
)
374 aProperties
[ nIndex
].Value
>>= aLibrary
;
375 else if ( aProperties
[ nIndex
].Name
== PROP_MACRO_NAME
)
376 aProperties
[ nIndex
].Value
>>= aMacroName
;
378 OSL_FAIL("Unknown propery value!");
384 ScriptType
eType( STARBASIC
);
385 if ( aType
== STAR_BASIC
)
387 else if (aType
== "Script" && !aScriptURL
.isEmpty())
388 eType
= EXTENDED_STYPE
;
389 else if ( aType
== SVX_MACRO_LANGUAGE_JAVASCRIPT
)
392 SAL_WARN( "sfx.notify", "ConvertToMacro: Unknown macro type" );
395 if ( !aMacroName
.isEmpty() )
397 if ( aLibrary
== "application" )
398 aLibrary
= SfxGetpApp()->GetName();
401 pMacro
= new SvxMacro( aMacroName
, aLibrary
, eType
);
403 else if ( eType
== EXTENDED_STYPE
)
404 pMacro
= new SvxMacro( aScriptURL
, aType
);
410 void SfxEvents_Impl::NormalizeMacro( const uno::Any
& rEvent
, uno::Any
& rRet
, SfxObjectShell
* pDoc
)
412 const ::comphelper::NamedValueCollection
aEventDescriptor( rEvent
);
413 ::comphelper::NamedValueCollection aEventDescriptorOut
;
415 NormalizeMacro( aEventDescriptor
, aEventDescriptorOut
, pDoc
);
417 rRet
<<= aEventDescriptorOut
.getPropertyValues();
420 void SfxEvents_Impl::NormalizeMacro( const ::comphelper::NamedValueCollection
& i_eventDescriptor
,
421 ::comphelper::NamedValueCollection
& o_normalizedDescriptor
, SfxObjectShell
* i_document
)
423 SfxObjectShell
* pDoc
= i_document
;
425 pDoc
= SfxObjectShell::Current();
427 OUString aType
= i_eventDescriptor
.getOrDefault( PROP_EVENT_TYPE
, OUString() );
428 OUString aScript
= i_eventDescriptor
.getOrDefault( PROP_SCRIPT
, OUString() );
429 OUString aLibrary
= i_eventDescriptor
.getOrDefault( PROP_LIBRARY
, OUString() );
430 OUString aMacroName
= i_eventDescriptor
.getOrDefault( PROP_MACRO_NAME
, OUString() );
432 if ( !aType
.isEmpty() )
433 o_normalizedDescriptor
.put( PROP_EVENT_TYPE
, aType
);
434 if ( !aScript
.isEmpty() )
435 o_normalizedDescriptor
.put( PROP_SCRIPT
, aScript
);
437 if ( aType
== STAR_BASIC
)
439 if ( !aScript
.isEmpty() )
441 if ( aMacroName
.isEmpty() || aLibrary
.isEmpty() )
443 sal_Int32 nHashPos
= aScript
.indexOf( '/', 8 );
444 sal_Int32 nArgsPos
= aScript
.indexOf( '(' );
445 if ( ( nHashPos
!= -1 ) && ( nArgsPos
== -1 || nHashPos
< nArgsPos
) )
447 OUString
aBasMgrName( INetURLObject::decode( aScript
.copy( 8, nHashPos
-8 ), INetURLObject::DECODE_WITH_CHARSET
) );
448 if ( aBasMgrName
== "." )
449 aLibrary
= pDoc
->GetTitle();
451 aLibrary
= SfxGetpApp()->GetName();
453 // Get the macro name
454 aMacroName
= aScript
.copy( nHashPos
+1, nArgsPos
- nHashPos
- 1 );
458 SAL_WARN( "sfx.notify", "ConvertToMacro: Unknown macro url format" );
462 else if ( !aMacroName
.isEmpty() )
464 aScript
= MACRO_PRFIX
;
465 if ( aLibrary
!= SfxGetpApp()->GetName() && aLibrary
!= "StarDesktop" && aLibrary
!= "application" )
466 aScript
+= OUString('.');
468 aScript
+= OUString('/');
469 aScript
+= aMacroName
;
470 aScript
+= OUString( MACRO_POSTFIX
);
476 if (aLibrary
!= "document")
478 if ( aLibrary
.isEmpty() || (pDoc
&& ( aLibrary
== pDoc
->GetTitle( SFX_TITLE_APINAME
) || aLibrary
== pDoc
->GetTitle() )) )
479 aLibrary
= "document";
481 aLibrary
= "application";
484 o_normalizedDescriptor
.put( PROP_SCRIPT
, aScript
);
485 o_normalizedDescriptor
.put( PROP_LIBRARY
, aLibrary
);
486 o_normalizedDescriptor
.put( PROP_MACRO_NAME
, aMacroName
);
490 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */