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