Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <com/sun/star/beans/PropertyValue.hpp>
21 :
22 : #include <com/sun/star/util/URL.hpp>
23 :
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>
34 :
35 : #include <unotools/securityoptions.hxx>
36 : #include <comphelper/processfactory.hxx>
37 : #include <comphelper/namedvaluecollection.hxx>
38 : #include "eventsupplier.hxx"
39 :
40 : #include <sfx2/app.hxx>
41 : #include <sfx2/sfxresid.hxx>
42 :
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>
49 :
50 :
51 :
52 : #define MACRO_PRFIX "macro://"
53 : #define MACRO_POSTFIX "()"
54 :
55 : using namespace css;
56 :
57 :
58 : // --- XNameReplace ---
59 :
60 0 : 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 )
63 : {
64 0 : ::osl::MutexGuard aGuard( maMutex );
65 :
66 : // find the event in the list and replace the data
67 0 : long nCount = maEventNames.getLength();
68 0 : for ( long i=0; i<nCount; i++ )
69 : {
70 0 : if ( maEventNames[i] == aName )
71 : {
72 : // check for correct type of the element
73 0 : if ( !::comphelper::NamedValueCollection::canExtractFrom( rElement ) )
74 0 : throw lang::IllegalArgumentException();
75 0 : ::comphelper::NamedValueCollection const aEventDescriptor( rElement );
76 :
77 : // create Configuration at first, creation might call this method also and that would overwrite everything
78 : // we might have stored before!
79 0 : if ( mpObjShell && !mpObjShell->IsLoading() )
80 0 : mpObjShell->SetModified( true );
81 :
82 0 : ::comphelper::NamedValueCollection aNormalizedDescriptor;
83 0 : NormalizeMacro( aEventDescriptor, aNormalizedDescriptor, mpObjShell );
84 :
85 0 : OUString sType;
86 0 : if ( ( aNormalizedDescriptor.size() == 1 )
87 0 : && !aNormalizedDescriptor.has( PROP_EVENT_TYPE ) //TODO
88 0 : && ( aNormalizedDescriptor.get( PROP_EVENT_TYPE ) >>= sType )
89 0 : && ( sType.isEmpty() )
90 : )
91 : {
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 0 : aNormalizedDescriptor.clear();
98 : }
99 :
100 0 : if ( !aNormalizedDescriptor.empty() )
101 : {
102 0 : maEventData[i] <<= aNormalizedDescriptor.getPropertyValues();
103 : }
104 : else
105 : {
106 0 : maEventData[i].clear();
107 : }
108 0 : return;
109 : }
110 : }
111 :
112 0 : throw container::NoSuchElementException();
113 : }
114 :
115 :
116 : // --- XNameAccess ---
117 :
118 0 : uno::Any SAL_CALL SfxEvents_Impl::getByName( const OUString& aName )
119 : throw( container::NoSuchElementException, lang::WrappedTargetException,
120 : uno::RuntimeException, std::exception )
121 : {
122 0 : ::osl::MutexGuard aGuard( maMutex );
123 :
124 : // find the event in the list and return the data
125 :
126 0 : long nCount = maEventNames.getLength();
127 :
128 0 : for ( long i=0; i<nCount; i++ )
129 : {
130 0 : if ( maEventNames[i] == aName )
131 0 : return maEventData[i];
132 : }
133 :
134 0 : throw container::NoSuchElementException();
135 : }
136 :
137 :
138 0 : uno::Sequence< OUString > SAL_CALL SfxEvents_Impl::getElementNames() throw ( uno::RuntimeException, std::exception )
139 : {
140 0 : return maEventNames;
141 : }
142 :
143 :
144 0 : sal_Bool SAL_CALL SfxEvents_Impl::hasByName( const OUString& aName ) throw ( uno::RuntimeException, std::exception )
145 : {
146 0 : ::osl::MutexGuard aGuard( maMutex );
147 :
148 : // find the event in the list and return the data
149 :
150 0 : long nCount = maEventNames.getLength();
151 :
152 0 : for ( long i=0; i<nCount; i++ )
153 : {
154 0 : if ( maEventNames[i] == aName )
155 0 : return sal_True;
156 : }
157 :
158 0 : return sal_False;
159 : }
160 :
161 :
162 : // --- XElementAccess ( parent of XNameAccess ) ---
163 :
164 0 : uno::Type SAL_CALL SfxEvents_Impl::getElementType() throw ( uno::RuntimeException, std::exception )
165 : {
166 0 : uno::Type aElementType = ::getCppuType( (const uno::Sequence < beans::PropertyValue > *)0 );
167 0 : return aElementType;
168 : }
169 :
170 :
171 0 : sal_Bool SAL_CALL SfxEvents_Impl::hasElements() throw ( uno::RuntimeException, std::exception )
172 : {
173 0 : ::osl::MutexGuard aGuard( maMutex );
174 :
175 0 : if ( maEventNames.getLength() )
176 0 : return sal_True;
177 : else
178 0 : return sal_False;
179 : }
180 :
181 0 : void SfxEvents_Impl::Execute( uno::Any& aEventData, const document::DocumentEvent& aTrigger, SfxObjectShell* pDoc )
182 : {
183 0 : uno::Sequence < beans::PropertyValue > aProperties;
184 0 : if ( aEventData >>= aProperties )
185 : {
186 0 : OUString aType;
187 0 : OUString aScript;
188 0 : OUString aLibrary;
189 0 : OUString aMacroName;
190 :
191 0 : sal_Int32 nCount = aProperties.getLength();
192 :
193 0 : if ( !nCount )
194 0 : return;
195 :
196 0 : sal_Int32 nIndex = 0;
197 0 : while ( nIndex < nCount )
198 : {
199 0 : if ( aProperties[ nIndex ].Name == PROP_EVENT_TYPE )
200 0 : aProperties[ nIndex ].Value >>= aType;
201 0 : else if ( aProperties[ nIndex ].Name == PROP_SCRIPT )
202 0 : aProperties[ nIndex ].Value >>= aScript;
203 0 : else if ( aProperties[ nIndex ].Name == PROP_LIBRARY )
204 0 : aProperties[ nIndex ].Value >>= aLibrary;
205 0 : else if ( aProperties[ nIndex ].Name == PROP_MACRO_NAME )
206 0 : aProperties[ nIndex ].Value >>= aMacroName;
207 : else {
208 : OSL_FAIL("Unknown property value!");
209 : }
210 0 : nIndex += 1;
211 : }
212 :
213 0 : if (aType == STAR_BASIC && !aScript.isEmpty())
214 : {
215 0 : uno::Any aAny;
216 0 : SfxMacroLoader::loadMacro( aScript, aAny, pDoc );
217 : }
218 0 : else if (aType == "Service" ||
219 0 : aType == "Script")
220 : {
221 0 : if ( !aScript.isEmpty() )
222 : {
223 : SfxViewFrame* pView = pDoc ?
224 : SfxViewFrame::GetFirst( pDoc ) :
225 0 : SfxViewFrame::Current();
226 :
227 0 : uno::Reference < util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
228 :
229 0 : util::URL aURL;
230 0 : aURL.Complete = aScript;
231 0 : xTrans->parseStrict( aURL );
232 :
233 : uno::Reference
234 0 : < frame::XDispatchProvider > xProv;
235 :
236 0 : if ( pView != NULL )
237 : {
238 0 : xProv = uno::Reference
239 : < frame::XDispatchProvider > (
240 0 : pView->GetFrame().GetFrameInterface(), uno::UNO_QUERY );
241 : }
242 : else
243 : {
244 0 : xProv = uno::Reference< frame::XDispatchProvider > (
245 : frame::Desktop::create( ::comphelper::getProcessComponentContext() ),
246 0 : uno::UNO_QUERY );
247 : }
248 :
249 0 : uno::Reference < frame::XDispatch > xDisp;
250 0 : if ( xProv.is() )
251 0 : xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
252 :
253 0 : if ( xDisp.is() )
254 : {
255 :
256 0 : beans::PropertyValue aEventParam;
257 0 : aEventParam.Value <<= aTrigger;
258 0 : uno::Sequence< beans::PropertyValue > aDispatchArgs( &aEventParam, 1 );
259 0 : xDisp->dispatch( aURL, aDispatchArgs );
260 0 : }
261 : }
262 : }
263 0 : else if ( aType.isEmpty() )
264 : {
265 : // Empty type means no active binding for the event. Just ignore do nothing.
266 : }
267 : else
268 : {
269 : SAL_WARN( "sfx.notify", "notifyEvent(): Unsupported event type" );
270 0 : }
271 0 : }
272 : }
273 :
274 :
275 : // --- ::document::XEventListener ---
276 :
277 0 : void SAL_CALL SfxEvents_Impl::notifyEvent( const document::EventObject& aEvent ) throw( uno::RuntimeException, std::exception )
278 : {
279 0 : ::osl::ClearableMutexGuard aGuard( maMutex );
280 :
281 : // get the event name, find the coresponding data, execute the data
282 :
283 0 : OUString aName = aEvent.EventName;
284 0 : long nCount = maEventNames.getLength();
285 0 : long nIndex = 0;
286 0 : bool bFound = false;
287 :
288 0 : while ( !bFound && ( nIndex < nCount ) )
289 : {
290 0 : if ( maEventNames[nIndex] == aName )
291 0 : bFound = true;
292 : else
293 0 : nIndex += 1;
294 : }
295 :
296 0 : if ( !bFound )
297 0 : return;
298 :
299 0 : uno::Any aEventData = maEventData[ nIndex ];
300 0 : aGuard.clear();
301 0 : Execute( aEventData, document::DocumentEvent(aEvent.Source, aEvent.EventName, NULL, uno::Any()), mpObjShell );
302 : }
303 :
304 :
305 : // --- ::lang::XEventListener ---
306 :
307 0 : void SAL_CALL SfxEvents_Impl::disposing( const lang::EventObject& /*Source*/ ) throw( uno::RuntimeException, std::exception )
308 : {
309 0 : ::osl::MutexGuard aGuard( maMutex );
310 :
311 0 : if ( mxBroadcaster.is() )
312 : {
313 0 : mxBroadcaster->removeEventListener( this );
314 0 : mxBroadcaster = NULL;
315 0 : }
316 0 : }
317 :
318 :
319 :
320 0 : SfxEvents_Impl::SfxEvents_Impl( SfxObjectShell* pShell,
321 0 : uno::Reference< document::XEventBroadcaster > xBroadcaster )
322 : {
323 : // get the list of supported events and store it
324 0 : if ( pShell )
325 0 : maEventNames = pShell->GetEventNames();
326 : else
327 0 : maEventNames = GlobalEventConfig().getElementNames();
328 :
329 0 : maEventData = uno::Sequence < uno::Any > ( maEventNames.getLength() );
330 :
331 0 : mpObjShell = pShell;
332 0 : mxBroadcaster = xBroadcaster;
333 :
334 0 : if ( mxBroadcaster.is() )
335 0 : mxBroadcaster->addEventListener( this );
336 0 : }
337 :
338 :
339 0 : SfxEvents_Impl::~SfxEvents_Impl()
340 : {
341 0 : }
342 :
343 :
344 0 : SvxMacro* SfxEvents_Impl::ConvertToMacro( const uno::Any& rElement, SfxObjectShell* pObjShell, bool bNormalizeMacro )
345 : {
346 0 : SvxMacro* pMacro = NULL;
347 0 : uno::Sequence < beans::PropertyValue > aProperties;
348 0 : uno::Any aAny;
349 0 : if ( bNormalizeMacro )
350 0 : NormalizeMacro( rElement, aAny, pObjShell );
351 : else
352 0 : aAny = rElement;
353 :
354 0 : if ( aAny >>= aProperties )
355 : {
356 0 : OUString aType;
357 0 : OUString aScriptURL;
358 0 : OUString aLibrary;
359 0 : OUString aMacroName;
360 :
361 0 : long nCount = aProperties.getLength();
362 0 : long nIndex = 0;
363 :
364 0 : if ( !nCount )
365 0 : return pMacro;
366 :
367 0 : while ( nIndex < nCount )
368 : {
369 0 : if ( aProperties[ nIndex ].Name == PROP_EVENT_TYPE )
370 0 : aProperties[ nIndex ].Value >>= aType;
371 0 : else if ( aProperties[ nIndex ].Name == PROP_SCRIPT )
372 0 : aProperties[ nIndex ].Value >>= aScriptURL;
373 0 : else if ( aProperties[ nIndex ].Name == PROP_LIBRARY )
374 0 : aProperties[ nIndex ].Value >>= aLibrary;
375 0 : else if ( aProperties[ nIndex ].Name == PROP_MACRO_NAME )
376 0 : aProperties[ nIndex ].Value >>= aMacroName;
377 : else {
378 : OSL_FAIL("Unknown propery value!");
379 : }
380 0 : nIndex += 1;
381 : }
382 :
383 : // Get the type
384 0 : ScriptType eType( STARBASIC );
385 0 : if ( aType == STAR_BASIC )
386 0 : eType = STARBASIC;
387 0 : else if (aType == "Script" && !aScriptURL.isEmpty())
388 0 : eType = EXTENDED_STYPE;
389 0 : else if ( aType == SVX_MACRO_LANGUAGE_JAVASCRIPT )
390 0 : eType = JAVASCRIPT;
391 : else {
392 : SAL_WARN( "sfx.notify", "ConvertToMacro: Unknown macro type" );
393 : }
394 :
395 0 : if ( !aMacroName.isEmpty() )
396 : {
397 0 : if ( aLibrary == "application" )
398 0 : aLibrary = SFX_APP()->GetName();
399 : else
400 0 : aLibrary = "";
401 0 : pMacro = new SvxMacro( aMacroName, aLibrary, eType );
402 : }
403 0 : else if ( eType == EXTENDED_STYPE )
404 0 : pMacro = new SvxMacro( aScriptURL, aType );
405 : }
406 :
407 0 : return pMacro;
408 : }
409 :
410 0 : void SfxEvents_Impl::NormalizeMacro( const uno::Any& rEvent, uno::Any& rRet, SfxObjectShell* pDoc )
411 : {
412 0 : const ::comphelper::NamedValueCollection aEventDescriptor( rEvent );
413 0 : ::comphelper::NamedValueCollection aEventDescriptorOut;
414 :
415 0 : NormalizeMacro( aEventDescriptor, aEventDescriptorOut, pDoc );
416 :
417 0 : rRet <<= aEventDescriptorOut.getPropertyValues();
418 0 : }
419 :
420 0 : void SfxEvents_Impl::NormalizeMacro( const ::comphelper::NamedValueCollection& i_eventDescriptor,
421 : ::comphelper::NamedValueCollection& o_normalizedDescriptor, SfxObjectShell* i_document )
422 : {
423 0 : SfxObjectShell* pDoc = i_document;
424 0 : if ( !pDoc )
425 0 : pDoc = SfxObjectShell::Current();
426 :
427 0 : OUString aType = i_eventDescriptor.getOrDefault( PROP_EVENT_TYPE, OUString() );
428 0 : OUString aScript = i_eventDescriptor.getOrDefault( PROP_SCRIPT, OUString() );
429 0 : OUString aLibrary = i_eventDescriptor.getOrDefault( PROP_LIBRARY, OUString() );
430 0 : OUString aMacroName = i_eventDescriptor.getOrDefault( PROP_MACRO_NAME, OUString() );
431 :
432 0 : if ( !aType.isEmpty() )
433 0 : o_normalizedDescriptor.put( PROP_EVENT_TYPE, aType );
434 0 : if ( !aScript.isEmpty() )
435 0 : o_normalizedDescriptor.put( PROP_SCRIPT, aScript );
436 :
437 0 : if ( aType == STAR_BASIC )
438 : {
439 0 : if ( !aScript.isEmpty() )
440 : {
441 0 : if ( aMacroName.isEmpty() || aLibrary.isEmpty() )
442 : {
443 0 : sal_Int32 nHashPos = aScript.indexOf( '/', 8 );
444 0 : sal_Int32 nArgsPos = aScript.indexOf( '(' );
445 0 : if ( ( nHashPos != -1 ) && ( nArgsPos == -1 || nHashPos < nArgsPos ) )
446 : {
447 0 : OUString aBasMgrName( INetURLObject::decode( aScript.copy( 8, nHashPos-8 ), '%', INetURLObject::DECODE_WITH_CHARSET ) );
448 0 : if ( aBasMgrName == "." )
449 0 : aLibrary = pDoc->GetTitle();
450 : else
451 0 : aLibrary = SFX_APP()->GetName();
452 :
453 : // Get the macro name
454 0 : aMacroName = aScript.copy( nHashPos+1, nArgsPos - nHashPos - 1 );
455 : }
456 : else
457 : {
458 : SAL_WARN( "sfx.notify", "ConvertToMacro: Unknown macro url format" );
459 : }
460 : }
461 : }
462 0 : else if ( !aMacroName.isEmpty() )
463 : {
464 0 : aScript = OUString( MACRO_PRFIX );
465 0 : if ( aLibrary != SFX_APP()->GetName() && aLibrary != "StarDesktop" && aLibrary != "application" )
466 0 : aScript += OUString('.');
467 :
468 0 : aScript += OUString('/');
469 0 : aScript += aMacroName;
470 0 : aScript += OUString( MACRO_POSTFIX );
471 : }
472 : else
473 : // wrong properties
474 0 : return;
475 :
476 0 : if (aLibrary != "document")
477 : {
478 0 : if ( aLibrary.isEmpty() || (pDoc && ( aLibrary == pDoc->GetTitle( SFX_TITLE_APINAME ) || aLibrary == pDoc->GetTitle() )) )
479 0 : aLibrary = "document";
480 : else
481 0 : aLibrary = "application";
482 : }
483 :
484 0 : o_normalizedDescriptor.put( PROP_SCRIPT, aScript );
485 0 : o_normalizedDescriptor.put( PROP_LIBRARY, aLibrary );
486 0 : o_normalizedDescriptor.put( PROP_MACRO_NAME, aMacroName );
487 0 : }
488 : }
489 :
490 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|