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 //--------------------------------------------------------------------------------------------------------
replaceByName(const OUSTRING & aName,const ANY & rElement)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 //--------------------------------------------------------------------------------------------------------
getByName(const OUSTRING & aName)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 //--------------------------------------------------------------------------------------------------------
getElementNames()155 SEQUENCE< OUSTRING > SAL_CALL SfxEvents_Impl::getElementNames() throw ( RUNTIMEEXCEPTION )
156 {
157 	return maEventNames;
158 }
159 
160 //--------------------------------------------------------------------------------------------------------
hasByName(const OUSTRING & aName)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 //--------------------------------------------------------------------------------------------------------
getElementType()181 UNOTYPE SAL_CALL SfxEvents_Impl::getElementType() throw ( RUNTIMEEXCEPTION )
182 {
183 	UNOTYPE aElementType = ::getCppuType( (const SEQUENCE < PROPERTYVALUE > *)0 );
184 	return aElementType;
185 }
186 
187 //--------------------------------------------------------------------------------------------------------
hasElements()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 
Execute(ANY & aEventData,const css::document::DocumentEvent & aTrigger,SfxObjectShell * pDoc)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 				if ( aURL.Protocol.equals( ::rtl::OUString::createFromAscii( "vnd.sun.star.script:" ) ) )
257 				{
258 					::com::sun::star::uno::Reference
259 						< ::com::sun::star::frame::XDispatchProvider > xProv;
260 
261 					if ( pView != NULL )
262 					{
263 						xProv = ::com::sun::star::uno::Reference
264 							< ::com::sun::star::frame::XDispatchProvider > (
265 								pView->GetFrame().GetFrameInterface(), UNO_QUERY );
266 					}
267 					else
268 					{
269 						xProv = ::com::sun::star::uno::Reference
270 							< ::com::sun::star::frame::XDispatchProvider > (
271 								::comphelper::getProcessServiceFactory()->createInstance(
272 									rtl::OUString::createFromAscii(
273 										"com.sun.star.frame.Desktop" ) ),
274 								UNO_QUERY );
275 					}
276 
277 					::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatch > xDisp;
278 					if ( xProv.is() )
279 						xDisp = xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
280 
281 					if ( xDisp.is() )
282 					{
283 						//::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue > aArgs(1);
284 						//aArgs[0].Name = rtl::OUString::createFromAscii("Referer");
285 						//aArs[0].Value <<= ::rtl::OUString( pDoc->GetMedium()->GetName() );
286 						//xDisp->dispatch( aURL, aArgs );
287 
288 						css::beans::PropertyValue aEventParam;
289 						aEventParam.Value <<= aTrigger;
290 						css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs( &aEventParam, 1 );
291 						xDisp->dispatch( aURL, aDispatchArgs );
292 					}
293 				}
294 			}
295 		}
296         else if ( aType.getLength() == 0 )
297         {
298             // Empty type means no active binding for the event. Just ignore do nothing.
299         }
300         else
301 		{
302 			DBG_ERRORFILE( "notifyEvent(): Unsupported event type" );
303 		}
304 	}
305 }
306 
307 //--------------------------------------------------------------------------------------------------------
308 // --- ::document::XEventListener ---
309 //--------------------------------------------------------------------------------------------------------
notifyEvent(const DOCEVENTOBJECT & aEvent)310 void SAL_CALL SfxEvents_Impl::notifyEvent( const DOCEVENTOBJECT& aEvent ) throw( RUNTIMEEXCEPTION )
311 {
312 	::osl::ClearableMutexGuard aGuard( maMutex );
313 
314 	// get the event name, find the coresponding data, execute the data
315 
316 	OUSTRING	aName	= aEvent.EventName;
317 	long		nCount	= maEventNames.getLength();
318 	long		nIndex	= 0;
319 	sal_Bool	bFound	= sal_False;
320 
321 	while ( !bFound && ( nIndex < nCount ) )
322 	{
323 		if ( maEventNames[nIndex] == aName )
324 			bFound = sal_True;
325 		else
326 			nIndex += 1;
327 	}
328 
329 	if ( !bFound )
330 		return;
331 
332 	ANY	aEventData = maEventData[ nIndex ];
333     aGuard.clear();
334     Execute( aEventData, css::document::DocumentEvent(aEvent.Source, aEvent.EventName, NULL, css::uno::Any()), mpObjShell );
335 }
336 
337 //--------------------------------------------------------------------------------------------------------
338 // --- ::lang::XEventListener ---
339 //--------------------------------------------------------------------------------------------------------
disposing(const EVENTOBJECT &)340 void SAL_CALL SfxEvents_Impl::disposing( const EVENTOBJECT& /*Source*/ ) throw( RUNTIMEEXCEPTION )
341 {
342 	::osl::MutexGuard aGuard( maMutex );
343 
344 	if ( mxBroadcaster.is() )
345 	{
346 		mxBroadcaster->removeEventListener( this );
347 		mxBroadcaster = NULL;
348 	}
349 }
350 
351 //--------------------------------------------------------------------------------------------------------
352 //
353 //--------------------------------------------------------------------------------------------------------
SfxEvents_Impl(SfxObjectShell * pShell,REFERENCE<XEVENTBROADCASTER> xBroadcaster)354 SfxEvents_Impl::SfxEvents_Impl( SfxObjectShell* pShell,
355 							    REFERENCE< XEVENTBROADCASTER > xBroadcaster )
356 {
357 	// get the list of supported events and store it
358 	if ( pShell )
359 		maEventNames = pShell->GetEventNames();
360 	else
361 		maEventNames = GlobalEventConfig().getElementNames();
362 
363 	maEventData = SEQUENCE < ANY > ( maEventNames.getLength() );
364 
365 	mpObjShell		= pShell;
366 	mxBroadcaster	= xBroadcaster;
367 
368 	if ( mxBroadcaster.is() )
369 		mxBroadcaster->addEventListener( this );
370 }
371 
372 //--------------------------------------------------------------------------------------------------------
~SfxEvents_Impl()373 SfxEvents_Impl::~SfxEvents_Impl()
374 {
375 }
376 
377 //--------------------------------------------------------------------------------------------------------
ConvertToMacro(const ANY & rElement,SfxObjectShell * pObjShell,sal_Bool bNormalizeMacro)378 SvxMacro* SfxEvents_Impl::ConvertToMacro( const ANY& rElement, SfxObjectShell* pObjShell, sal_Bool bNormalizeMacro )
379 {
380 	SvxMacro* pMacro = NULL;
381 	SEQUENCE < PROPERTYVALUE > aProperties;
382 	ANY aAny;
383 	if ( bNormalizeMacro )
384 		NormalizeMacro( rElement, aAny, pObjShell );
385 	else
386 		aAny = rElement;
387 
388 	if ( aAny >>= aProperties )
389 	{
390 		OUSTRING		aType;
391 		OUSTRING		aScriptURL;
392 		OUSTRING		aLibrary;
393 		OUSTRING		aMacroName;
394 
395 		long nCount = aProperties.getLength();
396 		long nIndex = 0;
397 
398 		if ( !nCount )
399 			return pMacro;
400 
401 		while ( nIndex < nCount )
402 		{
403 			if ( aProperties[ nIndex ].Name.compareToAscii( PROP_EVENT_TYPE ) == 0 )
404 				aProperties[ nIndex ].Value >>= aType;
405 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_SCRIPT ) == 0 )
406 				aProperties[ nIndex ].Value >>= aScriptURL;
407 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_LIBRARY ) == 0 )
408 				aProperties[ nIndex ].Value >>= aLibrary;
409 			else if ( aProperties[ nIndex ].Name.compareToAscii( PROP_MACRO_NAME ) == 0 )
410 				aProperties[ nIndex ].Value >>= aMacroName;
411 			else {
412 				DBG_ERROR("Unknown propery value!");
413             }
414 			nIndex += 1;
415 		}
416 
417 		// Get the type
418 		ScriptType	eType( STARBASIC );
419 		if ( aType.compareToAscii( STAR_BASIC ) == COMPARE_EQUAL )
420 			eType = STARBASIC;
421 		else if ( aType.compareToAscii( "Script" ) == COMPARE_EQUAL && aScriptURL.getLength() )
422 			eType = EXTENDED_STYPE;
423 		else if ( aType.compareToAscii( SVX_MACRO_LANGUAGE_JAVASCRIPT ) == COMPARE_EQUAL )
424 			eType = JAVASCRIPT;
425 		else {
426 			DBG_ERRORFILE( "ConvertToMacro: Unknown macro type" );
427         }
428 
429 		if ( aMacroName.getLength() )
430 		{
431 			if ( aLibrary.compareToAscii("application") == 0 )
432 				aLibrary = SFX_APP()->GetName();
433 			else
434 				aLibrary = ::rtl::OUString();
435 			pMacro = new SvxMacro( aMacroName, aLibrary, eType );
436 		}
437 		else if ( eType == EXTENDED_STYPE )
438 			pMacro = new SvxMacro( aScriptURL, aType );
439 	}
440 
441 	return pMacro;
442 }
443 
NormalizeMacro(const ANY & rEvent,ANY & rRet,SfxObjectShell * pDoc)444 void SfxEvents_Impl::NormalizeMacro( const ANY& rEvent, ANY& rRet, SfxObjectShell* pDoc )
445 {
446     const ::comphelper::NamedValueCollection aEventDescriptor( rEvent );
447     ::comphelper::NamedValueCollection aEventDescriptorOut;
448 
449     NormalizeMacro( aEventDescriptor, aEventDescriptorOut, pDoc );
450 
451     rRet <<= aEventDescriptorOut.getPropertyValues();
452 }
453 
NormalizeMacro(const::comphelper::NamedValueCollection & i_eventDescriptor,::comphelper::NamedValueCollection & o_normalizedDescriptor,SfxObjectShell * i_document)454 void SfxEvents_Impl::NormalizeMacro( const ::comphelper::NamedValueCollection& i_eventDescriptor,
455         ::comphelper::NamedValueCollection& o_normalizedDescriptor, SfxObjectShell* i_document )
456 {
457     SfxObjectShell* pDoc = i_document;
458 	if ( !pDoc )
459 		pDoc = SfxObjectShell::Current();
460 
461     ::rtl::OUString aType = i_eventDescriptor.getOrDefault( PROP_EVENT_TYPE, ::rtl::OUString() );
462 	::rtl::OUString aScript = i_eventDescriptor.getOrDefault( PROP_SCRIPT, ::rtl::OUString() );
463 	::rtl::OUString aLibrary = i_eventDescriptor.getOrDefault( PROP_LIBRARY, ::rtl::OUString() );
464 	::rtl::OUString aMacroName = i_eventDescriptor.getOrDefault( PROP_MACRO_NAME, ::rtl::OUString() );
465 
466     if ( aType.getLength() )
467         o_normalizedDescriptor.put( PROP_EVENT_TYPE, aType );
468     if ( aScript.getLength() )
469         o_normalizedDescriptor.put( PROP_SCRIPT, aScript );
470 
471 	if ( aType.compareToAscii( STAR_BASIC ) == 0 )
472 	{
473 		if ( aScript.getLength() )
474 		{
475 			if ( !aMacroName.getLength() || !aLibrary.getLength() )
476 			{
477 				sal_Int32 nHashPos = aScript.indexOf( '/', 8 );
478 				sal_Int32 nArgsPos = aScript.indexOf( '(' );
479 				if ( ( nHashPos != STRING_NOTFOUND ) && ( nHashPos < nArgsPos ) )
480 				{
481 					OUSTRING aBasMgrName( INetURLObject::decode( aScript.copy( 8, nHashPos-8 ), INET_HEX_ESCAPE, INetURLObject::DECODE_WITH_CHARSET ) );
482 					if ( aBasMgrName.compareToAscii(".") == 0 )
483 						aLibrary = pDoc->GetTitle();
484 /*
485 					else if ( aBasMgrName.getLength() )
486 						aLibrary = aBasMgrName;
487  */
488 					else
489 						aLibrary = SFX_APP()->GetName();
490 
491 					// Get the macro name
492 					aMacroName = aScript.copy( nHashPos+1, nArgsPos - nHashPos - 1 );
493 				}
494 				else
495 				{
496 					DBG_ERRORFILE( "ConvertToMacro: Unknown macro url format" );
497 				}
498 			}
499 		}
500 		else if ( aMacroName.getLength() )
501 		{
502             aScript = OUSTRING( RTL_CONSTASCII_USTRINGPARAM( MACRO_PRFIX ) );
503 			if ( aLibrary.compareTo( SFX_APP()->GetName() ) != 0 && aLibrary.compareToAscii("StarDesktop") != 0 && aLibrary.compareToAscii("application") != 0 )
504 				aScript += String('.');
505 
506 			aScript += String('/');
507 			aScript += aMacroName;
508 			aScript += OUSTRING( RTL_CONSTASCII_USTRINGPARAM( MACRO_POSTFIX ) );
509 		}
510 		else
511 			// wrong properties
512 			return;
513 
514 		if ( aLibrary.compareToAscii("document") != 0 )
515 		{
516 			if ( !aLibrary.getLength() || (pDoc && ( String(aLibrary) == pDoc->GetTitle( SFX_TITLE_APINAME ) || String(aLibrary) == pDoc->GetTitle() )) )
517 				aLibrary = String::CreateFromAscii("document");
518 			else
519 				aLibrary = String::CreateFromAscii("application");
520 		}
521 
522         o_normalizedDescriptor.put( PROP_SCRIPT, aScript );
523         o_normalizedDescriptor.put( PROP_LIBRARY, aLibrary );
524         o_normalizedDescriptor.put( PROP_MACRO_NAME, aMacroName );
525     }
526 }
527 
ModelCollectionEnumeration(const css::uno::Reference<css::lang::XMultiServiceFactory> & xSMGR)528 ModelCollectionEnumeration::ModelCollectionEnumeration(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
529     : ModelCollectionMutexBase(                 )
530     , m_xSMGR                 (xSMGR            )
531     , m_pEnumerationIt        (m_lModels.begin())
532 {
533 }
534 
~ModelCollectionEnumeration()535 ModelCollectionEnumeration::~ModelCollectionEnumeration()
536 {
537 }
538 
setModelList(const TModelList & rList)539 void ModelCollectionEnumeration::setModelList(const TModelList& rList)
540 {
541     // SAFE ->
542     ::osl::ResettableMutexGuard aLock(m_aLock);
543     m_lModels        = rList;
544     m_pEnumerationIt = m_lModels.begin();
545     aLock.clear();
546     // <- SAFE
547 }
548 
hasMoreElements()549 sal_Bool SAL_CALL ModelCollectionEnumeration::hasMoreElements()
550     throw(css::uno::RuntimeException)
551 {
552     // SAFE ->
553     ::osl::ResettableMutexGuard aLock(m_aLock);
554     return (m_pEnumerationIt != m_lModels.end());
555     // <- SAFE
556 }
557 
nextElement()558 css::uno::Any SAL_CALL ModelCollectionEnumeration::nextElement()
559     throw(css::container::NoSuchElementException,
560           css::lang::WrappedTargetException     ,
561           css::uno::RuntimeException            )
562 {
563     // SAFE ->
564     ::osl::ResettableMutexGuard aLock(m_aLock);
565     if (m_pEnumerationIt == m_lModels.end())
566         throw css::container::NoSuchElementException(
567                     ::rtl::OUString::createFromAscii("End of model enumeration reached."),
568                     static_cast< css::container::XEnumeration* >(this));
569     css::uno::Reference< css::frame::XModel > xModel(*m_pEnumerationIt, UNO_QUERY);
570     ++m_pEnumerationIt;
571     aLock.clear();
572     // <- SAFE
573 
574     return css::uno::makeAny(xModel);
575 }
576 
577 SFX_IMPL_XSERVICEINFO( SfxGlobalEvents_Impl, "com.sun.star.frame.GlobalEventBroadcaster", "com.sun.star.comp.sfx2.GlobalEventBroadcaster" )
578 SFX_IMPL_ONEINSTANCEFACTORY( SfxGlobalEvents_Impl );
579 
580 //-----------------------------------------------------------------------------
SfxGlobalEvents_Impl(const com::sun::star::uno::Reference<::com::sun::star::lang::XMultiServiceFactory> & xSMGR)581 SfxGlobalEvents_Impl::SfxGlobalEvents_Impl( const com::sun::star::uno::Reference < ::com::sun::star::lang::XMultiServiceFactory >& xSMGR)
582     : ModelCollectionMutexBase(       )
583     , m_xSMGR                 (xSMGR  )
584 	, m_aLegacyListeners      (m_aLock)
585     , m_aDocumentListeners    (m_aLock)
586     , pImp                    (0      )
587 {
588 	m_refCount++;
589     SFX_APP();
590     pImp                   = new GlobalEventConfig();
591 	m_xEvents              = pImp;
592     m_xJobExecutorListener = css::uno::Reference< css::document::XEventListener >(
593                         xSMGR->createInstance(::rtl::OUString::createFromAscii("com.sun.star.task.JobExecutor")),
594                         UNO_QUERY);
595 	m_refCount--;
596 }
597 
598 //-----------------------------------------------------------------------------
~SfxGlobalEvents_Impl()599 SfxGlobalEvents_Impl::~SfxGlobalEvents_Impl()
600 {
601 }
602 
603 //-----------------------------------------------------------------------------
getEvents()604 css::uno::Reference< css::container::XNameReplace > SAL_CALL SfxGlobalEvents_Impl::getEvents()
605     throw(css::uno::RuntimeException)
606 {
607     // SAFE ->
608     ::osl::ResettableMutexGuard aLock(m_aLock);
609 	return m_xEvents;
610     // <- SAFE
611 }
612 
613 //-----------------------------------------------------------------------------
addEventListener(const css::uno::Reference<css::document::XEventListener> & xListener)614 void SAL_CALL SfxGlobalEvents_Impl::addEventListener(const css::uno::Reference< css::document::XEventListener >& xListener)
615     throw(css::uno::RuntimeException)
616 {
617     // container is threadsafe
618 	m_aLegacyListeners.addInterface(xListener);
619 }
620 
621 //-----------------------------------------------------------------------------
removeEventListener(const css::uno::Reference<css::document::XEventListener> & xListener)622 void SAL_CALL SfxGlobalEvents_Impl::removeEventListener(const css::uno::Reference< css::document::XEventListener >& xListener)
623     throw(css::uno::RuntimeException)
624 {
625     // container is threadsafe
626 	m_aLegacyListeners.removeInterface(xListener);
627 }
628 
629 //-----------------------------------------------------------------------------
addDocumentEventListener(const css::uno::Reference<css::document::XDocumentEventListener> & _Listener)630 void SAL_CALL SfxGlobalEvents_Impl::addDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& _Listener )
631     throw(css::uno::RuntimeException)
632 {
633     m_aDocumentListeners.addInterface( _Listener );
634 }
635 
636 //-----------------------------------------------------------------------------
removeDocumentEventListener(const css::uno::Reference<css::document::XDocumentEventListener> & _Listener)637 void SAL_CALL SfxGlobalEvents_Impl::removeDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& _Listener )
638     throw(css::uno::RuntimeException)
639 {
640     m_aDocumentListeners.removeInterface( _Listener );
641 }
642 
643 //-----------------------------------------------------------------------------
notifyDocumentEvent(const::rtl::OUString &,const css::uno::Reference<css::frame::XController2> &,const css::uno::Any &)644 void SAL_CALL SfxGlobalEvents_Impl::notifyDocumentEvent( const ::rtl::OUString& /*_EventName*/,
645         const css::uno::Reference< css::frame::XController2 >& /*_ViewController*/, const css::uno::Any& /*_Supplement*/ )
646         throw (css::lang::IllegalArgumentException, css::lang::NoSupportException, css::uno::RuntimeException)
647 {
648     // we're a multiplexer only, no chance to generate artifical events here
649     throw css::lang::NoSupportException(::rtl::OUString(), *this);
650 }
651 
652 //-----------------------------------------------------------------------------
notifyEvent(const css::document::EventObject & aEvent)653 void SAL_CALL SfxGlobalEvents_Impl::notifyEvent(const css::document::EventObject& aEvent)
654     throw(css::uno::RuntimeException)
655 {
656     css::document::DocumentEvent aDocEvent(aEvent.Source, aEvent.EventName, NULL, css::uno::Any());
657     implts_notifyJobExecution(aEvent);
658     implts_checkAndExecuteEventBindings(aDocEvent);
659     implts_notifyListener(aDocEvent);
660 }
661 
662 //-----------------------------------------------------------------------------
documentEventOccured(const::css::document::DocumentEvent & _Event)663 void SAL_CALL SfxGlobalEvents_Impl::documentEventOccured( const ::css::document::DocumentEvent& _Event )
664     throw (::css::uno::RuntimeException)
665 {
666     implts_notifyJobExecution(css::document::EventObject(_Event.Source, _Event.EventName));
667     implts_checkAndExecuteEventBindings(_Event);
668     implts_notifyListener(_Event);
669 }
670 
671 //-----------------------------------------------------------------------------
disposing(const css::lang::EventObject & aEvent)672 void SAL_CALL SfxGlobalEvents_Impl::disposing(const css::lang::EventObject& aEvent)
673     throw(css::uno::RuntimeException)
674 {
675     css::uno::Reference< css::frame::XModel > xDoc(aEvent.Source, UNO_QUERY);
676 
677     // SAFE ->
678     ::osl::ResettableMutexGuard aLock(m_aLock);
679     TModelList::iterator pIt = impl_searchDoc(xDoc);
680     if (pIt != m_lModels.end())
681         m_lModels.erase(pIt);
682     aLock.clear();
683     // <- SAFE
684 }
685 
686 //-----------------------------------------------------------------------------
has(const css::uno::Any & aElement)687 sal_Bool SAL_CALL SfxGlobalEvents_Impl::has(const css::uno::Any& aElement)
688     throw (css::uno::RuntimeException)
689 {
690     css::uno::Reference< css::frame::XModel > xDoc;
691     aElement >>= xDoc;
692 
693     sal_Bool bHas = sal_False;
694 
695     // SAFE ->
696     ::osl::ResettableMutexGuard aLock(m_aLock);
697     TModelList::iterator pIt = impl_searchDoc(xDoc);
698     if (pIt != m_lModels.end())
699         bHas = sal_True;
700     aLock.clear();
701     // <- SAFE
702 
703     return bHas;
704 }
705 
706 //-----------------------------------------------------------------------------
insert(const css::uno::Any & aElement)707 void SAL_CALL SfxGlobalEvents_Impl::insert( const css::uno::Any& aElement )
708     throw (css::lang::IllegalArgumentException  ,
709            css::container::ElementExistException,
710            css::uno::RuntimeException           )
711 {
712     css::uno::Reference< css::frame::XModel > xDoc;
713     aElement >>= xDoc;
714     if (!xDoc.is())
715         throw css::lang::IllegalArgumentException(
716                 ::rtl::OUString::createFromAscii("Cant locate at least the model parameter."),
717                 static_cast< css::container::XSet* >(this),
718                 0);
719 
720     // SAFE ->
721     ::osl::ResettableMutexGuard aLock(m_aLock);
722     TModelList::iterator pIt = impl_searchDoc(xDoc);
723     if (pIt != m_lModels.end())
724         throw css::container::ElementExistException(
725                 ::rtl::OUString(),
726                 static_cast< css::container::XSet* >(this));
727     m_lModels.push_back(xDoc);
728     aLock.clear();
729     // <- SAFE
730 
731     css::uno::Reference< css::document::XDocumentEventBroadcaster > xDocBroadcaster(xDoc, UNO_QUERY );
732     if (xDocBroadcaster.is())
733         xDocBroadcaster->addDocumentEventListener(this);
734     else
735     {
736         // try the "legacy version" of XDocumentEventBroadcaster, which is XEventBroadcaster
737         css::uno::Reference< css::document::XEventBroadcaster > xBroadcaster(xDoc, UNO_QUERY);
738         if (xBroadcaster.is())
739             xBroadcaster->addEventListener(static_cast< css::document::XEventListener* >(this));
740     }
741 }
742 
743 //-----------------------------------------------------------------------------
remove(const css::uno::Any & aElement)744 void SAL_CALL SfxGlobalEvents_Impl::remove( const css::uno::Any& aElement )
745     throw (css::lang::IllegalArgumentException   ,
746            css::container::NoSuchElementException,
747            css::uno::RuntimeException            )
748 {
749     css::uno::Reference< css::frame::XModel > xDoc;
750     aElement >>= xDoc;
751     if (!xDoc.is())
752         throw css::lang::IllegalArgumentException(
753                 ::rtl::OUString::createFromAscii("Cant locate at least the model parameter."),
754                 static_cast< css::container::XSet* >(this),
755                 0);
756 
757     // SAFE ->
758     ::osl::ResettableMutexGuard aLock(m_aLock);
759     TModelList::iterator pIt = impl_searchDoc(xDoc);
760     if (pIt == m_lModels.end())
761         throw css::container::NoSuchElementException(
762                 ::rtl::OUString(),
763                 static_cast< css::container::XSet* >(this));
764     m_lModels.erase(pIt);
765     aLock.clear();
766     // <- SAFE
767 
768     css::uno::Reference< css::document::XDocumentEventBroadcaster > xDocBroadcaster(xDoc, UNO_QUERY );
769     if (xDocBroadcaster.is())
770         xDocBroadcaster->removeDocumentEventListener(this);
771     else
772     {
773         // try the "legacy version" of XDocumentEventBroadcaster, which is XEventBroadcaster
774         css::uno::Reference< css::document::XEventBroadcaster > xBroadcaster(xDoc, UNO_QUERY);
775         if (xBroadcaster.is())
776             xBroadcaster->removeEventListener(static_cast< css::document::XEventListener* >(this));
777     }
778 }
779 
780 //-----------------------------------------------------------------------------
createEnumeration()781 css::uno::Reference< css::container::XEnumeration > SAL_CALL SfxGlobalEvents_Impl::createEnumeration()
782     throw (css::uno::RuntimeException)
783 {
784     // SAFE ->
785     ::osl::ResettableMutexGuard aLock(m_aLock);
786     ModelCollectionEnumeration* pEnum = new ModelCollectionEnumeration(m_xSMGR);
787     pEnum->setModelList(m_lModels);
788     css::uno::Reference< css::container::XEnumeration > xEnum(
789         static_cast< css::container::XEnumeration* >(pEnum),
790         UNO_QUERY);
791     aLock.clear();
792     // <- SAFE
793 
794     return xEnum;
795 }
796 
797 //-----------------------------------------------------------------------------
getElementType()798 css::uno::Type SAL_CALL SfxGlobalEvents_Impl::getElementType()
799     throw (css::uno::RuntimeException)
800 {
801     return ::getCppuType(static_cast< css::uno::Reference< css::frame::XModel >* >(NULL));
802 }
803 
804 //-----------------------------------------------------------------------------
hasElements()805 sal_Bool SAL_CALL SfxGlobalEvents_Impl::hasElements()
806     throw (css::uno::RuntimeException)
807 {
808     // SAFE ->
809     ::osl::ResettableMutexGuard aLock(m_aLock);
810     return (m_lModels.size()>0);
811     // <- SAFE
812 }
813 
814 //-----------------------------------------------------------------------------
implts_notifyJobExecution(const css::document::EventObject & aEvent)815 void SfxGlobalEvents_Impl::implts_notifyJobExecution(const css::document::EventObject& aEvent)
816 {
817     try
818     {
819         // SAFE ->
820         ::osl::ResettableMutexGuard aLock(m_aLock);
821         css::uno::Reference< css::document::XEventListener > xJobExecutor(m_xJobExecutorListener);
822         aLock.clear();
823         // <- SAFE
824         if (xJobExecutor.is())
825             xJobExecutor->notifyEvent(aEvent);
826     }
827     catch(const css::uno::RuntimeException& exRun)
828         { throw exRun; }
829     catch(const css::uno::Exception&)
830         {}
831 }
832 
833 //-----------------------------------------------------------------------------
implts_checkAndExecuteEventBindings(const css::document::DocumentEvent & aEvent)834 void SfxGlobalEvents_Impl::implts_checkAndExecuteEventBindings(const css::document::DocumentEvent& aEvent)
835 {
836     try
837     {
838         // SAFE ->
839         ::osl::ResettableMutexGuard aLock(m_aLock);
840         css::uno::Reference< css::container::XNameReplace > xEvents = m_xEvents;
841         aLock.clear();
842         // <- SAFE
843 
844         css::uno::Any aAny;
845         if ( xEvents.is() && xEvents->hasByName( aEvent.EventName ) )
846             aAny = xEvents->getByName(aEvent.EventName);
847         Execute(aAny, aEvent, 0);
848     }
849     catch ( css::uno::RuntimeException const & )
850     {
851         throw;
852     }
853     catch ( css::uno::Exception const & )
854     {
855        DBG_UNHANDLED_EXCEPTION();
856     }
857 }
858 
859 //-----------------------------------------------------------------------------
implts_notifyListener(const css::document::DocumentEvent & aEvent)860 void SfxGlobalEvents_Impl::implts_notifyListener(const css::document::DocumentEvent& aEvent)
861 {
862     // containers are threadsafe
863     css::document::EventObject aLegacyEvent(aEvent.Source, aEvent.EventName);
864     m_aLegacyListeners.notifyEach( &css::document::XEventListener::notifyEvent, aLegacyEvent );
865 
866     m_aDocumentListeners.notifyEach( &css::document::XDocumentEventListener::documentEventOccured, aEvent );
867 }
868 
869 //-----------------------------------------------------------------------------
870 // not threadsafe ... must be locked from outside!
impl_searchDoc(const css::uno::Reference<css::frame::XModel> & xModel)871 TModelList::iterator SfxGlobalEvents_Impl::impl_searchDoc(const css::uno::Reference< css::frame::XModel >& xModel)
872 {
873     if (!xModel.is())
874         return m_lModels.end();
875 
876     TModelList::iterator pIt;
877     for (  pIt  = m_lModels.begin();
878            pIt != m_lModels.end()  ;
879          ++pIt                     )
880     {
881         css::uno::Reference< css::frame::XModel > xContainerDoc(*pIt, UNO_QUERY);
882         if (xContainerDoc == xModel)
883             break;
884     }
885 
886     return pIt;
887 }
888 
889