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