1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 //--------------------------------------------------------------------------------------------------------
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 
34 #ifndef  _COM_SUN_STAR_UTL_URL_HPP_
35 #include <com/sun/star/util/URL.hpp>
36 #endif
37 
38 #ifndef  _COM_SUN_STAR_UTL_XURLTRANSFORMER_HPP_
39 #include <com/sun/star/util/XURLTransformer.hpp>
40 #endif
41 #include <tools/urlobj.hxx>
42 #include <tools/diagnose_ex.h>
43 #include <svl/macitem.hxx>
44 #include <sfx2/appuno.hxx>
45 #include <sfx2/objsh.hxx>
46 #include <sfx2/sfxbasemodel.hxx>
47 #include <sfx2/evntconf.hxx>
48 #include <unotools/eventcfg.hxx>
49 
50 #include <unotools/securityoptions.hxx>
51 #include <comphelper/processfactory.hxx>
52 #include <comphelper/namedvaluecollection.hxx>
53 #include "eventsupplier.hxx"
54 
55 #include <sfx2/app.hxx>
56 #include "sfx2/sfxresid.hxx"
57 
58 #include <sfx2/sfxsids.hrc>
59 #include "sfxlocal.hrc"
60 #include <sfx2/docfile.hxx>
61 #include <sfx2/viewfrm.hxx>
62 #include <sfx2/frame.hxx>
63 
64 //--------------------------------------------------------------------------------------------------------
65 
66 #define MACRO_PRFIX			"macro://"
67 #define MACRO_POSTFIX		"()"
68 
69 //--------------------------------------------------------------------------------------------------------
70 
71 #define PROPERTYVALUE		::com::sun::star::beans::PropertyValue
72 #define	UNO_QUERY			::com::sun::star::uno::UNO_QUERY
73 
74 namespace css = ::com::sun::star;
75 using ::com::sun::star::uno::Sequence;
76 using ::com::sun::star::beans::PropertyValue;
77 
78 //--------------------------------------------------------------------------------------------------------
79 	//  --- XNameReplace ---
80 //--------------------------------------------------------------------------------------------------------
81 void SAL_CALL SfxEvents_Impl::replaceByName( const OUSTRING & aName, const ANY & rElement )
82 								throw( ILLEGALARGUMENTEXCEPTION, NOSUCHELEMENTEXCEPTION,
83 									   WRAPPEDTARGETEXCEPTION, RUNTIMEEXCEPTION )
84 {
85 	::osl::MutexGuard aGuard( maMutex );
86 
87 	// find the event in the list and replace the data
88 	long nCount	= maEventNames.getLength();
89 	for ( long i=0; i<nCount; i++ )
90 	{
91 		if ( maEventNames[i] == aName )
92 		{
93             const ::comphelper::NamedValueCollection aEventDescriptor( rElement );
94 			// check for correct type of the element
95             if ( rElement.hasValue() && aEventDescriptor.empty() )
96 				throw ILLEGALARGUMENTEXCEPTION();
97 
98             // create Configuration at first, creation might call this method also and that would overwrite everything
99 			// we might have stored before!
100             if ( mpObjShell && !mpObjShell->IsLoading() )
101                 mpObjShell->SetModified( sal_True );
102 
103             ::comphelper::NamedValueCollection aNormalizedDescriptor;
104 	        NormalizeMacro( aEventDescriptor, aNormalizedDescriptor, mpObjShell );
105 
106             ::rtl::OUString sType;
107             if  (   ( aNormalizedDescriptor.size() == 1 )
108                 &&  ( aNormalizedDescriptor.has( PROP_EVENT_TYPE ) == 0 )
109                 &&  ( aNormalizedDescriptor.get( PROP_EVENT_TYPE ) >>= sType )
110                 &&  ( sType.getLength() == 0 )
111                 )
112             {
113                 // An empty event type means no binding. Therefore reset data
114                 // to reflect that state.
115                 // (that's for compatibility only. Nowadays, the Tools/Customize dialog should
116                 // set an empty sequence to indicate the request for resetting the assignment.)
117                 OSL_ENSURE( false, "legacy event assignment format detected" );
118                 aNormalizedDescriptor.clear();
119             }
120 
121             if ( !aNormalizedDescriptor.empty() )
122             {
123                 maEventData[i] <<= aNormalizedDescriptor.getPropertyValues();
124             }
125             else
126             {
127                 maEventData[i].clear();
128             }
129 			return;
130 		}
131 	}
132 
133 	throw NOSUCHELEMENTEXCEPTION();
134 }
135 
136 //--------------------------------------------------------------------------------------------------------
137 //  --- XNameAccess ---
138 //--------------------------------------------------------------------------------------------------------
139 ANY SAL_CALL SfxEvents_Impl::getByName( const OUSTRING& aName )
140 								throw( NOSUCHELEMENTEXCEPTION, WRAPPEDTARGETEXCEPTION,
141 									   RUNTIMEEXCEPTION )
142 {
143 	::osl::MutexGuard aGuard( maMutex );
144 
145 	// find the event in the list and return the data
146 
147 	long nCount	= maEventNames.getLength();
148 
149 	for ( long i=0; i<nCount; i++ )
150 	{
151 		if ( maEventNames[i] == aName )
152 			return maEventData[i];
153 	}
154 
155 	throw NOSUCHELEMENTEXCEPTION();
156 }
157 
158 //--------------------------------------------------------------------------------------------------------
159 SEQUENCE< OUSTRING > SAL_CALL SfxEvents_Impl::getElementNames() throw ( RUNTIMEEXCEPTION )
160 {
161 	return maEventNames;
162 }
163 
164 //--------------------------------------------------------------------------------------------------------
165 sal_Bool SAL_CALL SfxEvents_Impl::hasByName( const OUSTRING& aName ) throw ( RUNTIMEEXCEPTION )
166 {
167 	::osl::MutexGuard aGuard( maMutex );
168 
169 	// find the event in the list and return the data
170 
171 	long nCount	= maEventNames.getLength();
172 
173 	for ( long i=0; i<nCount; i++ )
174 	{
175 		if ( maEventNames[i] == aName )
176 			return sal_True;
177 	}
178 
179 	return sal_False;
180 }
181 
182 //--------------------------------------------------------------------------------------------------------
183 //  --- XElementAccess ( parent of XNameAccess ) ---
184 //--------------------------------------------------------------------------------------------------------
185 UNOTYPE SAL_CALL SfxEvents_Impl::getElementType() throw ( RUNTIMEEXCEPTION )
186 {
187 	UNOTYPE aElementType = ::getCppuType( (const SEQUENCE < PROPERTYVALUE > *)0 );
188 	return aElementType;
189 }
190 
191 //--------------------------------------------------------------------------------------------------------
192 sal_Bool SAL_CALL SfxEvents_Impl::hasElements() throw ( RUNTIMEEXCEPTION )
193 {
194 	::osl::MutexGuard aGuard( maMutex );
195 
196 	if ( maEventNames.getLength() )
197 		return sal_True;
198 	else
199 		return sal_False;
200 }
201 
202 static void Execute( ANY& aEventData, const css::document::DocumentEvent& aTrigger, SfxObjectShell* pDoc )
203 {
204 	SEQUENCE < PROPERTYVALUE > aProperties;
205 	if ( aEventData >>= aProperties )
206 	{
207         OUSTRING        aPrefix = OUSTRING( RTL_CONSTASCII_USTRINGPARAM( MACRO_PRFIX ) );
208 		OUSTRING		aType;
209 		OUSTRING		aScript;
210 		OUSTRING		aLibrary;
211 		OUSTRING		aMacroName;
212 
213         sal_Int32 nCount = aProperties.getLength();
214 
215 		if ( !nCount )
216 			return;
217 
218         sal_Int32 nIndex = 0;
219 		while ( nIndex < nCount )
220 		{
221 			if ( aProperties[ nIndex ].Name.compareToAscii( PROP_EVENT_TYPE ) == 0 )
222 				aProperties[ nIndex ].Value >>= aType;
223 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_SCRIPT ) == 0 )
224 				aProperties[ nIndex ].Value >>= aScript;
225 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_LIBRARY ) == 0 )
226 				aProperties[ nIndex ].Value >>= aLibrary;
227 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_MACRO_NAME ) == 0 )
228 				aProperties[ nIndex ].Value >>= aMacroName;
229 			else {
230 				DBG_ERROR("Unknown property value!");
231             }
232 			nIndex += 1;
233 		}
234 
235 		if ( aType.compareToAscii( STAR_BASIC ) == 0 && aScript.getLength() )
236 		{
237 			com::sun::star::uno::Any aAny;
238             SfxMacroLoader::loadMacro( aScript, aAny, pDoc );
239 		}
240 		else if ( aType.compareToAscii( "Service" ) == 0 ||
241                   aType.compareToAscii( "Script" ) == 0 )
242 		{
243 			if ( aScript.getLength() )
244 			{
245                 SfxViewFrame* pView = pDoc ?
246                     SfxViewFrame::GetFirst( pDoc ) :
247 					SfxViewFrame::Current();
248 
249 				::com::sun::star::uno::Reference
250 					< ::com::sun::star::util::XURLTransformer > xTrans(
251 						::comphelper::getProcessServiceFactory()->createInstance(
252 							rtl::OUString::createFromAscii(
253 								"com.sun.star.util.URLTransformer" ) ),
254 						UNO_QUERY );
255 
256 				::com::sun::star::util::URL aURL;
257 				aURL.Complete = aScript;
258 				xTrans->parseStrict( aURL );
259 
260 				::com::sun::star::uno::Reference
261 					< ::com::sun::star::frame::XDispatchProvider > xProv;
262 
263 				if ( pView != NULL )
264 				{
265 					xProv = ::com::sun::star::uno::Reference
266 						< ::com::sun::star::frame::XDispatchProvider > (
267 							pView->GetFrame().GetFrameInterface(), UNO_QUERY );
268 				}
269 				else
270 				{
271 					xProv = ::com::sun::star::uno::Reference
272 						< ::com::sun::star::frame::XDispatchProvider > (
273 							::comphelper::getProcessServiceFactory()->createInstance(
274 								rtl::OUString::createFromAscii(
275 									"com.sun.star.frame.Desktop" ) ),
276 							UNO_QUERY );
277 				}
278 
279 				::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatch > xDisp;
280 				if ( xProv.is() )
281 					xDisp = xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
282 
283 				if ( xDisp.is() )
284 				{
285 					//::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue > aArgs(1);
286 					//aArgs[0].Name = rtl::OUString::createFromAscii("Referer");
287                     //aArs[0].Value <<= ::rtl::OUString( pDoc->GetMedium()->GetName() );
288 					//xDisp->dispatch( aURL, aArgs );
289 
290                     css::beans::PropertyValue aEventParam;
291                     aEventParam.Value <<= aTrigger;
292                     css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs( &aEventParam, 1 );
293 					xDisp->dispatch( aURL, aDispatchArgs );
294 				}
295 			}
296 		}
297         else if ( aType.getLength() == 0 )
298         {
299             // Empty type means no active binding for the event. Just ignore do nothing.
300         }
301         else
302 		{
303 			DBG_ERRORFILE( "notifyEvent(): Unsupported event type" );
304 		}
305 	}
306 }
307 
308 //--------------------------------------------------------------------------------------------------------
309 // --- ::document::XEventListener ---
310 //--------------------------------------------------------------------------------------------------------
311 void SAL_CALL SfxEvents_Impl::notifyEvent( const DOCEVENTOBJECT& aEvent ) throw( RUNTIMEEXCEPTION )
312 {
313 	::osl::ClearableMutexGuard aGuard( maMutex );
314 
315 	// get the event name, find the coresponding data, execute the data
316 
317 	OUSTRING	aName	= aEvent.EventName;
318 	long		nCount	= maEventNames.getLength();
319 	long		nIndex	= 0;
320 	sal_Bool	bFound	= sal_False;
321 
322 	while ( !bFound && ( nIndex < nCount ) )
323 	{
324 		if ( maEventNames[nIndex] == aName )
325 			bFound = sal_True;
326 		else
327 			nIndex += 1;
328 	}
329 
330 	if ( !bFound )
331 		return;
332 
333 	ANY	aEventData = maEventData[ nIndex ];
334     aGuard.clear();
335     Execute( aEventData, css::document::DocumentEvent(aEvent.Source, aEvent.EventName, NULL, css::uno::Any()), mpObjShell );
336 }
337 
338 //--------------------------------------------------------------------------------------------------------
339 // --- ::lang::XEventListener ---
340 //--------------------------------------------------------------------------------------------------------
341 void SAL_CALL SfxEvents_Impl::disposing( const EVENTOBJECT& /*Source*/ ) throw( RUNTIMEEXCEPTION )
342 {
343 	::osl::MutexGuard aGuard( maMutex );
344 
345 	if ( mxBroadcaster.is() )
346 	{
347 		mxBroadcaster->removeEventListener( this );
348 		mxBroadcaster = NULL;
349 	}
350 }
351 
352 //--------------------------------------------------------------------------------------------------------
353 //
354 //--------------------------------------------------------------------------------------------------------
355 SfxEvents_Impl::SfxEvents_Impl( SfxObjectShell* pShell,
356 							    REFERENCE< XEVENTBROADCASTER > xBroadcaster )
357 {
358 	// get the list of supported events and store it
359 	if ( pShell )
360 		maEventNames = pShell->GetEventNames();
361 	else
362 		maEventNames = GlobalEventConfig().getElementNames();
363 
364 	maEventData = SEQUENCE < ANY > ( maEventNames.getLength() );
365 
366 	mpObjShell		= pShell;
367 	mxBroadcaster	= xBroadcaster;
368 
369 	if ( mxBroadcaster.is() )
370 		mxBroadcaster->addEventListener( this );
371 }
372 
373 //--------------------------------------------------------------------------------------------------------
374 SfxEvents_Impl::~SfxEvents_Impl()
375 {
376 }
377 
378 //--------------------------------------------------------------------------------------------------------
379 SvxMacro* SfxEvents_Impl::ConvertToMacro( const ANY& rElement, SfxObjectShell* pObjShell, sal_Bool bNormalizeMacro )
380 {
381 	SvxMacro* pMacro = NULL;
382 	SEQUENCE < PROPERTYVALUE > aProperties;
383 	ANY aAny;
384 	if ( bNormalizeMacro )
385 		NormalizeMacro( rElement, aAny, pObjShell );
386 	else
387 		aAny = rElement;
388 
389 	if ( aAny >>= aProperties )
390 	{
391 		OUSTRING		aType;
392 		OUSTRING		aScriptURL;
393 		OUSTRING		aLibrary;
394 		OUSTRING		aMacroName;
395 
396 		long nCount = aProperties.getLength();
397 		long nIndex = 0;
398 
399 		if ( !nCount )
400 			return pMacro;
401 
402 		while ( nIndex < nCount )
403 		{
404 			if ( aProperties[ nIndex ].Name.compareToAscii( PROP_EVENT_TYPE ) == 0 )
405 				aProperties[ nIndex ].Value >>= aType;
406 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_SCRIPT ) == 0 )
407 				aProperties[ nIndex ].Value >>= aScriptURL;
408 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_LIBRARY ) == 0 )
409 				aProperties[ nIndex ].Value >>= aLibrary;
410 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_MACRO_NAME ) == 0 )
411 				aProperties[ nIndex ].Value >>= aMacroName;
412 			else {
413 				DBG_ERROR("Unknown propery value!");
414             }
415 			nIndex += 1;
416 		}
417 
418 		// Get the type
419 		ScriptType	eType( STARBASIC );
420 		if ( aType.compareToAscii( STAR_BASIC ) == COMPARE_EQUAL )
421 			eType = STARBASIC;
422 		else if ( aType.compareToAscii( "Script" ) == COMPARE_EQUAL && aScriptURL.getLength() )
423 			eType = EXTENDED_STYPE;
424 		else if ( aType.compareToAscii( SVX_MACRO_LANGUAGE_JAVASCRIPT ) == COMPARE_EQUAL )
425 			eType = JAVASCRIPT;
426 		else {
427 			DBG_ERRORFILE( "ConvertToMacro: Unknown macro type" );
428         }
429 
430 		if ( aMacroName.getLength() )
431 		{
432 			if ( aLibrary.compareToAscii("application") == 0 )
433 				aLibrary = SFX_APP()->GetName();
434 			else
435 				aLibrary = ::rtl::OUString();
436 			pMacro = new SvxMacro( aMacroName, aLibrary, eType );
437 		}
438 		else if ( eType == EXTENDED_STYPE )
439 			pMacro = new SvxMacro( aScriptURL, aType );
440 	}
441 
442 	return pMacro;
443 }
444 
445 void SfxEvents_Impl::NormalizeMacro( const ANY& rEvent, ANY& rRet, SfxObjectShell* pDoc )
446 {
447     const ::comphelper::NamedValueCollection aEventDescriptor( rEvent );
448     ::comphelper::NamedValueCollection aEventDescriptorOut;
449 
450     NormalizeMacro( aEventDescriptor, aEventDescriptorOut, pDoc );
451 
452     rRet <<= aEventDescriptorOut.getPropertyValues();
453 }
454 
455 void SfxEvents_Impl::NormalizeMacro( const ::comphelper::NamedValueCollection& i_eventDescriptor,
456         ::comphelper::NamedValueCollection& o_normalizedDescriptor, SfxObjectShell* i_document )
457 {
458     SfxObjectShell* pDoc = i_document;
459 	if ( !pDoc )
460 		pDoc = SfxObjectShell::Current();
461 
462     ::rtl::OUString aType = i_eventDescriptor.getOrDefault( PROP_EVENT_TYPE, ::rtl::OUString() );
463 	::rtl::OUString aScript = i_eventDescriptor.getOrDefault( PROP_SCRIPT, ::rtl::OUString() );
464 	::rtl::OUString aLibrary = i_eventDescriptor.getOrDefault( PROP_LIBRARY, ::rtl::OUString() );
465 	::rtl::OUString aMacroName = i_eventDescriptor.getOrDefault( PROP_MACRO_NAME, ::rtl::OUString() );
466 
467     if ( aType.getLength() )
468         o_normalizedDescriptor.put( PROP_EVENT_TYPE, aType );
469     if ( aScript.getLength() )
470         o_normalizedDescriptor.put( PROP_SCRIPT, aScript );
471 
472 	if ( aType.compareToAscii( STAR_BASIC ) == 0 )
473 	{
474 		if ( aScript.getLength() )
475 		{
476 			if ( !aMacroName.getLength() || !aLibrary.getLength() )
477 			{
478 				sal_Int32 nHashPos = aScript.indexOf( '/', 8 );
479 				sal_Int32 nArgsPos = aScript.indexOf( '(' );
480 				if ( ( nHashPos != STRING_NOTFOUND ) && ( nHashPos < nArgsPos ) )
481 				{
482 					OUSTRING aBasMgrName( INetURLObject::decode( aScript.copy( 8, nHashPos-8 ), INET_HEX_ESCAPE, INetURLObject::DECODE_WITH_CHARSET ) );
483 					if ( aBasMgrName.compareToAscii(".") == 0 )
484 						aLibrary = pDoc->GetTitle();
485 /*
486 					else if ( aBasMgrName.getLength() )
487 						aLibrary = aBasMgrName;
488  */
489 					else
490 						aLibrary = SFX_APP()->GetName();
491 
492 					// Get the macro name
493 					aMacroName = aScript.copy( nHashPos+1, nArgsPos - nHashPos - 1 );
494 				}
495 				else
496 				{
497 					DBG_ERRORFILE( "ConvertToMacro: Unknown macro url format" );
498 				}
499 			}
500 		}
501 		else if ( aMacroName.getLength() )
502 		{
503             aScript = OUSTRING( RTL_CONSTASCII_USTRINGPARAM( MACRO_PRFIX ) );
504 			if ( aLibrary.compareTo( SFX_APP()->GetName() ) != 0 && aLibrary.compareToAscii("StarDesktop") != 0 && aLibrary.compareToAscii("application") != 0 )
505 				aScript += String('.');
506 
507 			aScript += String('/');
508 			aScript += aMacroName;
509 			aScript += OUSTRING( RTL_CONSTASCII_USTRINGPARAM( MACRO_POSTFIX ) );
510 		}
511 		else
512 			// wrong properties
513 			return;
514 
515 		if ( aLibrary.compareToAscii("document") != 0 )
516 		{
517 			if ( !aLibrary.getLength() || (pDoc && ( String(aLibrary) == pDoc->GetTitle( SFX_TITLE_APINAME ) || String(aLibrary) == pDoc->GetTitle() )) )
518 				aLibrary = String::CreateFromAscii("document");
519 			else
520 				aLibrary = String::CreateFromAscii("application");
521 		}
522 
523         o_normalizedDescriptor.put( PROP_SCRIPT, aScript );
524         o_normalizedDescriptor.put( PROP_LIBRARY, aLibrary );
525         o_normalizedDescriptor.put( PROP_MACRO_NAME, aMacroName );
526     }
527 }
528 
529 ModelCollectionEnumeration::ModelCollectionEnumeration(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
530     : ModelCollectionMutexBase(                 )
531     , m_xSMGR                 (xSMGR            )
532     , m_pEnumerationIt        (m_lModels.begin())
533 {
534 }
535 
536 ModelCollectionEnumeration::~ModelCollectionEnumeration()
537 {
538 }
539 
540 void ModelCollectionEnumeration::setModelList(const TModelList& rList)
541 {
542     // SAFE ->
543     ::osl::ResettableMutexGuard aLock(m_aLock);
544     m_lModels        = rList;
545     m_pEnumerationIt = m_lModels.begin();
546     aLock.clear();
547     // <- SAFE
548 }
549 
550 sal_Bool SAL_CALL ModelCollectionEnumeration::hasMoreElements()
551     throw(css::uno::RuntimeException)
552 {
553     // SAFE ->
554     ::osl::ResettableMutexGuard aLock(m_aLock);
555     return (m_pEnumerationIt != m_lModels.end());
556     // <- SAFE
557 }
558 
559 css::uno::Any SAL_CALL ModelCollectionEnumeration::nextElement()
560     throw(css::container::NoSuchElementException,
561           css::lang::WrappedTargetException     ,
562           css::uno::RuntimeException            )
563 {
564     // SAFE ->
565     ::osl::ResettableMutexGuard aLock(m_aLock);
566     if (m_pEnumerationIt == m_lModels.end())
567         throw css::container::NoSuchElementException(
568                     ::rtl::OUString::createFromAscii("End of model enumeration reached."),
569                     static_cast< css::container::XEnumeration* >(this));
570     css::uno::Reference< css::frame::XModel > xModel(*m_pEnumerationIt, UNO_QUERY);
571     ++m_pEnumerationIt;
572     aLock.clear();
573     // <- SAFE
574 
575     return css::uno::makeAny(xModel);
576 }
577 
578 SFX_IMPL_XSERVICEINFO( SfxGlobalEvents_Impl, "com.sun.star.frame.GlobalEventBroadcaster", "com.sun.star.comp.sfx2.GlobalEventBroadcaster" )
579 SFX_IMPL_ONEINSTANCEFACTORY( SfxGlobalEvents_Impl );
580 
581 //-----------------------------------------------------------------------------
582 SfxGlobalEvents_Impl::SfxGlobalEvents_Impl( const com::sun::star::uno::Reference < ::com::sun::star::lang::XMultiServiceFactory >& xSMGR)
583     : ModelCollectionMutexBase(       )
584     , m_xSMGR                 (xSMGR  )
585 	, m_aLegacyListeners      (m_aLock)
586     , m_aDocumentListeners    (m_aLock)
587     , pImp                    (0      )
588 {
589 	m_refCount++;
590     SFX_APP();
591     pImp                   = new GlobalEventConfig();
592 	m_xEvents              = pImp;
593     m_xJobExecutorListener = css::uno::Reference< css::document::XEventListener >(
594                         xSMGR->createInstance(::rtl::OUString::createFromAscii("com.sun.star.task.JobExecutor")),
595                         UNO_QUERY);
596 	m_refCount--;
597 }
598 
599 //-----------------------------------------------------------------------------
600 SfxGlobalEvents_Impl::~SfxGlobalEvents_Impl()
601 {
602 }
603 
604 //-----------------------------------------------------------------------------
605 css::uno::Reference< css::container::XNameReplace > SAL_CALL SfxGlobalEvents_Impl::getEvents()
606     throw(css::uno::RuntimeException)
607 {
608     // SAFE ->
609     ::osl::ResettableMutexGuard aLock(m_aLock);
610 	return m_xEvents;
611     // <- SAFE
612 }
613 
614 //-----------------------------------------------------------------------------
615 void SAL_CALL SfxGlobalEvents_Impl::addEventListener(const css::uno::Reference< css::document::XEventListener >& xListener)
616     throw(css::uno::RuntimeException)
617 {
618     // container is threadsafe
619 	m_aLegacyListeners.addInterface(xListener);
620 }
621 
622 //-----------------------------------------------------------------------------
623 void SAL_CALL SfxGlobalEvents_Impl::removeEventListener(const css::uno::Reference< css::document::XEventListener >& xListener)
624     throw(css::uno::RuntimeException)
625 {
626     // container is threadsafe
627 	m_aLegacyListeners.removeInterface(xListener);
628 }
629 
630 //-----------------------------------------------------------------------------
631 void SAL_CALL SfxGlobalEvents_Impl::addDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& _Listener )
632     throw(css::uno::RuntimeException)
633 {
634     m_aDocumentListeners.addInterface( _Listener );
635 }
636 
637 //-----------------------------------------------------------------------------
638 void SAL_CALL SfxGlobalEvents_Impl::removeDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& _Listener )
639     throw(css::uno::RuntimeException)
640 {
641     m_aDocumentListeners.removeInterface( _Listener );
642 }
643 
644 //-----------------------------------------------------------------------------
645 void SAL_CALL SfxGlobalEvents_Impl::notifyDocumentEvent( const ::rtl::OUString& /*_EventName*/,
646         const css::uno::Reference< css::frame::XController2 >& /*_ViewController*/, const css::uno::Any& /*_Supplement*/ )
647         throw (css::lang::IllegalArgumentException, css::lang::NoSupportException, css::uno::RuntimeException)
648 {
649     // we're a multiplexer only, no chance to generate artifical events here
650     throw css::lang::NoSupportException(::rtl::OUString(), *this);
651 }
652 
653 //-----------------------------------------------------------------------------
654 void SAL_CALL SfxGlobalEvents_Impl::notifyEvent(const css::document::EventObject& aEvent)
655     throw(css::uno::RuntimeException)
656 {
657     css::document::DocumentEvent aDocEvent(aEvent.Source, aEvent.EventName, NULL, css::uno::Any());
658     implts_notifyJobExecution(aEvent);
659     implts_checkAndExecuteEventBindings(aDocEvent);
660     implts_notifyListener(aDocEvent);
661 }
662 
663 //-----------------------------------------------------------------------------
664 void SAL_CALL SfxGlobalEvents_Impl::documentEventOccured( const ::css::document::DocumentEvent& _Event )
665     throw (::css::uno::RuntimeException)
666 {
667     implts_notifyJobExecution(css::document::EventObject(_Event.Source, _Event.EventName));
668     implts_checkAndExecuteEventBindings(_Event);
669     implts_notifyListener(_Event);
670 }
671 
672 //-----------------------------------------------------------------------------
673 void SAL_CALL SfxGlobalEvents_Impl::disposing(const css::lang::EventObject& aEvent)
674     throw(css::uno::RuntimeException)
675 {
676     css::uno::Reference< css::frame::XModel > xDoc(aEvent.Source, UNO_QUERY);
677 
678     // SAFE ->
679     ::osl::ResettableMutexGuard aLock(m_aLock);
680     TModelList::iterator pIt = impl_searchDoc(xDoc);
681     if (pIt != m_lModels.end())
682         m_lModels.erase(pIt);
683     aLock.clear();
684     // <- SAFE
685 }
686 
687 //-----------------------------------------------------------------------------
688 sal_Bool SAL_CALL SfxGlobalEvents_Impl::has(const css::uno::Any& aElement)
689     throw (css::uno::RuntimeException)
690 {
691     css::uno::Reference< css::frame::XModel > xDoc;
692     aElement >>= xDoc;
693 
694     sal_Bool bHas = sal_False;
695 
696     // SAFE ->
697     ::osl::ResettableMutexGuard aLock(m_aLock);
698     TModelList::iterator pIt = impl_searchDoc(xDoc);
699     if (pIt != m_lModels.end())
700         bHas = sal_True;
701     aLock.clear();
702     // <- SAFE
703 
704     return bHas;
705 }
706 
707 //-----------------------------------------------------------------------------
708 void SAL_CALL SfxGlobalEvents_Impl::insert( const css::uno::Any& aElement )
709     throw (css::lang::IllegalArgumentException  ,
710            css::container::ElementExistException,
711            css::uno::RuntimeException           )
712 {
713     css::uno::Reference< css::frame::XModel > xDoc;
714     aElement >>= xDoc;
715     if (!xDoc.is())
716         throw css::lang::IllegalArgumentException(
717                 ::rtl::OUString::createFromAscii("Cant locate at least the model parameter."),
718                 static_cast< css::container::XSet* >(this),
719                 0);
720 
721     // SAFE ->
722     ::osl::ResettableMutexGuard aLock(m_aLock);
723     TModelList::iterator pIt = impl_searchDoc(xDoc);
724     if (pIt != m_lModels.end())
725         throw css::container::ElementExistException(
726                 ::rtl::OUString(),
727                 static_cast< css::container::XSet* >(this));
728     m_lModels.push_back(xDoc);
729     aLock.clear();
730     // <- SAFE
731 
732     css::uno::Reference< css::document::XDocumentEventBroadcaster > xDocBroadcaster(xDoc, UNO_QUERY );
733     if (xDocBroadcaster.is())
734         xDocBroadcaster->addDocumentEventListener(this);
735     else
736     {
737         // try the "legacy version" of XDocumentEventBroadcaster, which is XEventBroadcaster
738         css::uno::Reference< css::document::XEventBroadcaster > xBroadcaster(xDoc, UNO_QUERY);
739         if (xBroadcaster.is())
740             xBroadcaster->addEventListener(static_cast< css::document::XEventListener* >(this));
741     }
742 }
743 
744 //-----------------------------------------------------------------------------
745 void SAL_CALL SfxGlobalEvents_Impl::remove( const css::uno::Any& aElement )
746     throw (css::lang::IllegalArgumentException   ,
747            css::container::NoSuchElementException,
748            css::uno::RuntimeException            )
749 {
750     css::uno::Reference< css::frame::XModel > xDoc;
751     aElement >>= xDoc;
752     if (!xDoc.is())
753         throw css::lang::IllegalArgumentException(
754                 ::rtl::OUString::createFromAscii("Cant locate at least the model parameter."),
755                 static_cast< css::container::XSet* >(this),
756                 0);
757 
758     // SAFE ->
759     ::osl::ResettableMutexGuard aLock(m_aLock);
760     TModelList::iterator pIt = impl_searchDoc(xDoc);
761     if (pIt == m_lModels.end())
762         throw css::container::NoSuchElementException(
763                 ::rtl::OUString(),
764                 static_cast< css::container::XSet* >(this));
765     m_lModels.erase(pIt);
766     aLock.clear();
767     // <- SAFE
768 
769     css::uno::Reference< css::document::XDocumentEventBroadcaster > xDocBroadcaster(xDoc, UNO_QUERY );
770     if (xDocBroadcaster.is())
771         xDocBroadcaster->removeDocumentEventListener(this);
772     else
773     {
774         // try the "legacy version" of XDocumentEventBroadcaster, which is XEventBroadcaster
775         css::uno::Reference< css::document::XEventBroadcaster > xBroadcaster(xDoc, UNO_QUERY);
776         if (xBroadcaster.is())
777             xBroadcaster->removeEventListener(static_cast< css::document::XEventListener* >(this));
778     }
779 }
780 
781 //-----------------------------------------------------------------------------
782 css::uno::Reference< css::container::XEnumeration > SAL_CALL SfxGlobalEvents_Impl::createEnumeration()
783     throw (css::uno::RuntimeException)
784 {
785     // SAFE ->
786     ::osl::ResettableMutexGuard aLock(m_aLock);
787     ModelCollectionEnumeration* pEnum = new ModelCollectionEnumeration(m_xSMGR);
788     pEnum->setModelList(m_lModels);
789     css::uno::Reference< css::container::XEnumeration > xEnum(
790         static_cast< css::container::XEnumeration* >(pEnum),
791         UNO_QUERY);
792     aLock.clear();
793     // <- SAFE
794 
795     return xEnum;
796 }
797 
798 //-----------------------------------------------------------------------------
799 css::uno::Type SAL_CALL SfxGlobalEvents_Impl::getElementType()
800     throw (css::uno::RuntimeException)
801 {
802     return ::getCppuType(static_cast< css::uno::Reference< css::frame::XModel >* >(NULL));
803 }
804 
805 //-----------------------------------------------------------------------------
806 sal_Bool SAL_CALL SfxGlobalEvents_Impl::hasElements()
807     throw (css::uno::RuntimeException)
808 {
809     // SAFE ->
810     ::osl::ResettableMutexGuard aLock(m_aLock);
811     return (m_lModels.size()>0);
812     // <- SAFE
813 }
814 
815 //-----------------------------------------------------------------------------
816 void SfxGlobalEvents_Impl::implts_notifyJobExecution(const css::document::EventObject& aEvent)
817 {
818     try
819     {
820         // SAFE ->
821         ::osl::ResettableMutexGuard aLock(m_aLock);
822         css::uno::Reference< css::document::XEventListener > xJobExecutor(m_xJobExecutorListener);
823         aLock.clear();
824         // <- SAFE
825         if (xJobExecutor.is())
826             xJobExecutor->notifyEvent(aEvent);
827     }
828     catch(const css::uno::RuntimeException& exRun)
829         { throw exRun; }
830     catch(const css::uno::Exception&)
831         {}
832 }
833 
834 //-----------------------------------------------------------------------------
835 void SfxGlobalEvents_Impl::implts_checkAndExecuteEventBindings(const css::document::DocumentEvent& aEvent)
836 {
837     try
838     {
839         // SAFE ->
840         ::osl::ResettableMutexGuard aLock(m_aLock);
841         css::uno::Reference< css::container::XNameReplace > xEvents = m_xEvents;
842         aLock.clear();
843         // <- SAFE
844 
845         css::uno::Any aAny;
846         if ( xEvents.is() && xEvents->hasByName( aEvent.EventName ) )
847             aAny = xEvents->getByName(aEvent.EventName);
848         Execute(aAny, aEvent, 0);
849     }
850     catch ( css::uno::RuntimeException const & )
851     {
852         throw;
853     }
854     catch ( css::uno::Exception const & )
855     {
856        DBG_UNHANDLED_EXCEPTION();
857     }
858 }
859 
860 //-----------------------------------------------------------------------------
861 void SfxGlobalEvents_Impl::implts_notifyListener(const css::document::DocumentEvent& aEvent)
862 {
863     // containers are threadsafe
864     css::document::EventObject aLegacyEvent(aEvent.Source, aEvent.EventName);
865     m_aLegacyListeners.notifyEach( &css::document::XEventListener::notifyEvent, aLegacyEvent );
866 
867     m_aDocumentListeners.notifyEach( &css::document::XDocumentEventListener::documentEventOccured, aEvent );
868 }
869 
870 //-----------------------------------------------------------------------------
871 // not threadsafe ... must be locked from outside!
872 TModelList::iterator SfxGlobalEvents_Impl::impl_searchDoc(const css::uno::Reference< css::frame::XModel >& xModel)
873 {
874     if (!xModel.is())
875         return m_lModels.end();
876 
877     TModelList::iterator pIt;
878     for (  pIt  = m_lModels.begin();
879            pIt != m_lModels.end()  ;
880          ++pIt                     )
881     {
882         css::uno::Reference< css::frame::XModel > xContainerDoc(*pIt, UNO_QUERY);
883         if (xContainerDoc == xModel)
884             break;
885     }
886 
887     return pIt;
888 }
889 
890