Branch libreoffice-5-0-4
[LibreOffice.git] / sfx2 / source / notify / eventsupplier.cxx
blobb6ad3b1902d158a362d3ead33b1bdc1c39a10a02
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/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 "()"
55 using namespace css;
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 );
85 OUString sType;
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();
104 else
106 maEventData[i].clear();
108 return;
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 )
140 return maEventNames;
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 )
155 return sal_True;
158 return sal_False;
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();
167 return aElementType;
171 sal_Bool SAL_CALL SfxEvents_Impl::hasElements() throw ( uno::RuntimeException, std::exception )
173 ::osl::MutexGuard aGuard( maMutex );
175 if ( maEventNames.getLength() )
176 return sal_True;
177 else
178 return sal_False;
181 void SfxEvents_Impl::Execute( uno::Any& aEventData, const document::DocumentEvent& aTrigger, SfxObjectShell* pDoc )
183 uno::Sequence < beans::PropertyValue > aProperties;
184 if ( aEventData >>= aProperties )
186 OUString aType;
187 OUString aScript;
188 OUString aLibrary;
189 OUString aMacroName;
191 sal_Int32 nCount = aProperties.getLength();
193 if ( !nCount )
194 return;
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;
207 else {
208 OSL_FAIL("Unknown property value!");
210 nIndex += 1;
213 if (aType == STAR_BASIC && !aScript.isEmpty())
215 uno::Any aAny;
216 SfxMacroLoader::loadMacro( aScript, aAny, pDoc );
218 else if (aType == "Service" ||
219 aType == "Script")
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() ) );
229 util::URL aURL;
230 aURL.Complete = aScript;
231 xTrans->parseStrict( aURL );
233 uno::Reference
234 < frame::XDispatchProvider > xProv;
236 if ( pView != NULL )
238 xProv = uno::Reference
239 < frame::XDispatchProvider > (
240 pView->GetFrame().GetFrameInterface(), uno::UNO_QUERY );
242 else
244 xProv = uno::Reference< frame::XDispatchProvider > (
245 frame::Desktop::create( ::comphelper::getProcessComponentContext() ),
246 uno::UNO_QUERY );
249 uno::Reference < frame::XDispatch > xDisp;
250 if ( xProv.is() )
251 xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
253 if ( xDisp.is() )
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.
267 else
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();
285 long nIndex = 0;
286 bool bFound = false;
288 while ( !bFound && ( nIndex < nCount ) )
290 if ( maEventNames[nIndex] == aName )
291 bFound = true;
292 else
293 nIndex += 1;
296 if ( !bFound )
297 return;
299 uno::Any aEventData = maEventData[ nIndex ];
300 aGuard.clear();
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
324 if ( pShell )
325 maEventNames = pShell->GetEventNames();
326 else
327 maEventNames = GlobalEventConfig().getElementNames();
329 maEventData = uno::Sequence < uno::Any > ( maEventNames.getLength() );
331 mpObjShell = pShell;
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;
348 uno::Any aAny;
349 if ( bNormalizeMacro )
350 NormalizeMacro( rElement, aAny, pObjShell );
351 else
352 aAny = rElement;
354 if ( aAny >>= aProperties )
356 OUString aType;
357 OUString aScriptURL;
358 OUString aLibrary;
359 OUString aMacroName;
361 long nCount = aProperties.getLength();
362 long nIndex = 0;
364 if ( !nCount )
365 return pMacro;
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;
377 else {
378 OSL_FAIL("Unknown propery value!");
380 nIndex += 1;
383 // Get the type
384 ScriptType eType( STARBASIC );
385 if ( aType == STAR_BASIC )
386 eType = STARBASIC;
387 else if (aType == "Script" && !aScriptURL.isEmpty())
388 eType = EXTENDED_STYPE;
389 else if ( aType == SVX_MACRO_LANGUAGE_JAVASCRIPT )
390 eType = JAVASCRIPT;
391 else {
392 SAL_WARN( "sfx.notify", "ConvertToMacro: Unknown macro type" );
395 if ( !aMacroName.isEmpty() )
397 if ( aLibrary == "application" )
398 aLibrary = SfxGetpApp()->GetName();
399 else
400 aLibrary.clear();
401 pMacro = new SvxMacro( aMacroName, aLibrary, eType );
403 else if ( eType == EXTENDED_STYPE )
404 pMacro = new SvxMacro( aScriptURL, aType );
407 return pMacro;
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;
424 if ( !pDoc )
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();
450 else
451 aLibrary = SfxGetpApp()->GetName();
453 // Get the macro name
454 aMacroName = aScript.copy( nHashPos+1, nArgsPos - nHashPos - 1 );
456 else
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 );
472 else
473 // wrong properties
474 return;
476 if (aLibrary != "document")
478 if ( aLibrary.isEmpty() || (pDoc && ( aLibrary == pDoc->GetTitle( SFX_TITLE_APINAME ) || aLibrary == pDoc->GetTitle() )) )
479 aLibrary = "document";
480 else
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: */