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