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