1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 #include <comphelper/accessibleeventnotifier.hxx>
31 #include <osl/diagnose.h>
32 #include <rtl/instance.hxx>
33 #include <comphelper/guarding.hxx>
35 using namespace ::com::sun::star::uno
;
36 using namespace ::com::sun::star::lang
;
37 using namespace ::com::sun::star::accessibility
;
38 using namespace ::comphelper
;
40 //=====================================================================
41 //= AccessibleEventNotifier
42 //=====================================================================
43 //---------------------------------------------------------------------
47 : public rtl::Static
< ::osl::Mutex
, lclMutex
> {};
49 : public rtl::Static
< AccessibleEventNotifier::ClientMap
, Clients
> {};
52 //.........................................................................
55 //.........................................................................
57 //---------------------------------------------------------------------
58 AccessibleEventNotifier::TClientId
AccessibleEventNotifier::generateId()
60 TClientId nBiggestUsedId
= 0;
61 TClientId nFreeId
= 0;
63 // look through all registered clients until we find a "gap" in the ids
65 // Note that the following relies on the fact the elements in the map are traveled with
66 // ascending keys (aka client ids)
67 AccessibleEventNotifier::ClientMap
&rClients
= Clients::get();
68 for ( ClientMap::const_iterator aLookup
= rClients
.begin();
69 aLookup
!= rClients
.end();
73 TClientId nCurrent
= aLookup
->first
;
74 OSL_ENSURE( nCurrent
> nBiggestUsedId
, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );
76 if ( nCurrent
- nBiggestUsedId
> 1 )
78 nFreeId
= nBiggestUsedId
+ 1;
82 nBiggestUsedId
= nCurrent
;
86 nFreeId
= nBiggestUsedId
+ 1;
88 OSL_ENSURE( rClients
.end() == rClients
.find( nFreeId
),
89 "AccessibleEventNotifier::generateId: algorithm broken!" );
94 //---------------------------------------------------------------------
95 AccessibleEventNotifier::TClientId
AccessibleEventNotifier::registerClient( )
97 ::osl::MutexGuard
aGuard( lclMutex::get() );
99 // generate a new client id
100 TClientId nNewClientId
= generateId( );
102 // the event listeners for the new client
103 EventListeners
* pNewListeners
= new EventListeners( lclMutex::get() );
104 // note that we're using our own mutex here, so the listener containers for all
105 // our clients share this same mutex.
106 // this is a reminiscense to the days where the notifier was asynchronous. Today this is
107 // completely nonsense, and potentially slowing down the Office me thinks ...
110 Clients::get().insert( ClientMap::value_type( nNewClientId
, pNewListeners
) );
116 //---------------------------------------------------------------------
117 sal_Bool
AccessibleEventNotifier::implLookupClient( const TClientId _nClient
, ClientMap::iterator
& _rPos
)
119 // look up this client
120 AccessibleEventNotifier::ClientMap
&rClients
= Clients::get();
121 _rPos
= rClients
.find( _nClient
);
122 OSL_ENSURE( rClients
.end() != _rPos
, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );
124 return ( rClients
.end() != _rPos
);
127 //---------------------------------------------------------------------
128 void AccessibleEventNotifier::revokeClient( const TClientId _nClient
)
130 ::osl::MutexGuard
aGuard( lclMutex::get() );
132 ClientMap::iterator aClientPos
;
133 if ( !implLookupClient( _nClient
, aClientPos
) )
134 // already asserted in implLookupClient
137 // remove it from the clients map
138 delete aClientPos
->second
;
139 Clients::get().erase( aClientPos
);
142 //---------------------------------------------------------------------
143 void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient
,
144 const Reference
< XInterface
>& _rxEventSource
) SAL_THROW( ( ) )
146 ::osl::MutexGuard
aGuard( lclMutex::get() );
148 ClientMap::iterator aClientPos
;
149 if ( !implLookupClient( _nClient
, aClientPos
) )
150 // already asserted in implLookupClient
153 // notify the "disposing" event for this client
154 EventObject aDisposalEvent
;
155 aDisposalEvent
.Source
= _rxEventSource
;
157 // notify the listeners
158 EventListeners
* pListeners
= aClientPos
->second
;
160 // we do not need the entry in the clients map anymore
161 // (do this before actually notifying, because some client implementations have re-entrance
162 // problems and call into revokeClient while we are notifying from hereing)
163 Clients::get().erase( aClientPos
);
165 // now really do the notification
166 pListeners
->disposeAndClear( aDisposalEvent
);
171 //---------------------------------------------------------------------
172 sal_Int32
AccessibleEventNotifier::addEventListener(
173 const TClientId _nClient
, const Reference
< XAccessibleEventListener
>& _rxListener
) SAL_THROW( ( ) )
175 ::osl::MutexGuard
aGuard( lclMutex::get() );
177 ClientMap::iterator aClientPos
;
178 if ( !implLookupClient( _nClient
, aClientPos
) )
179 // already asserted in implLookupClient
182 if ( _rxListener
.is() )
183 aClientPos
->second
->addInterface( _rxListener
);
185 return aClientPos
->second
->getLength();
188 //---------------------------------------------------------------------
189 sal_Int32
AccessibleEventNotifier::removeEventListener(
190 const TClientId _nClient
, const Reference
< XAccessibleEventListener
>& _rxListener
) SAL_THROW( ( ) )
192 ::osl::MutexGuard
aGuard( lclMutex::get() );
194 ClientMap::iterator aClientPos
;
195 if ( !implLookupClient( _nClient
, aClientPos
) )
196 // already asserted in implLookupClient
199 if ( _rxListener
.is() )
200 aClientPos
->second
->removeInterface( _rxListener
);
202 return aClientPos
->second
->getLength();
205 //---------------------------------------------------------------------
206 Sequence
< Reference
< XInterface
> > AccessibleEventNotifier::getEventListeners( const TClientId _nClient
) SAL_THROW( ( ) )
208 Sequence
< Reference
< XInterface
> > aListeners
;
210 ::osl::MutexGuard
aGuard( lclMutex::get() );
212 ClientMap::iterator aClientPos
;
213 if ( implLookupClient( _nClient
, aClientPos
) )
214 aListeners
= aClientPos
->second
->getElements();
219 //---------------------------------------------------------------------
220 void AccessibleEventNotifier::addEvent( const TClientId _nClient
, const AccessibleEventObject
& _rEvent
) SAL_THROW( ( ) )
222 Sequence
< Reference
< XInterface
> > aListeners
;
224 // --- <mutex lock> -------------------------------
226 ::osl::MutexGuard
aGuard( lclMutex::get() );
228 ClientMap::iterator aClientPos
;
229 if ( !implLookupClient( _nClient
, aClientPos
) )
230 // already asserted in implLookupClient
233 // since we're synchronous, again, we want to notify immediately
234 aListeners
= aClientPos
->second
->getElements();
236 // --- </mutex lock> ------------------------------
238 // default handling: loop through all listeners, and notify them
239 const Reference
< XInterface
>* pListeners
= aListeners
.getConstArray();
240 const Reference
< XInterface
>* pListenersEnd
= pListeners
+ aListeners
.getLength();
241 while ( pListeners
!= pListenersEnd
)
245 static_cast< XAccessibleEventListener
* >( pListeners
->get() )->notifyEvent( _rEvent
);
247 catch( const Exception
& )
249 // no assertion, because a broken access remote bridge or something like this
250 // can cause this exception
256 //.........................................................................
257 } // namespace comphelper
258 //.........................................................................