Update ooo320-m1
[ooovba.git] / comphelper / source / misc / accessibleeventnotifier.cxx
blobf06ce41acb92efffce4d76d94c47247f256bffb4
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: accessibleeventnotifier.cxx,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_comphelper.hxx"
33 #include <comphelper/accessibleeventnotifier.hxx>
34 #include <osl/diagnose.h>
35 #include <rtl/instance.hxx>
36 #include <comphelper/guarding.hxx>
38 using namespace ::com::sun::star::uno;
39 using namespace ::com::sun::star::lang;
40 using namespace ::com::sun::star::accessibility;
41 using namespace ::comphelper;
43 //=====================================================================
44 //= AccessibleEventNotifier
45 //=====================================================================
46 //---------------------------------------------------------------------
47 namespace
49 struct lclMutex
50 : public rtl::Static< ::osl::Mutex, lclMutex > {};
51 struct Clients
52 : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {};
55 //.........................................................................
56 namespace comphelper
58 //.........................................................................
60 //---------------------------------------------------------------------
61 AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId()
63 TClientId nBiggestUsedId = 0;
64 TClientId nFreeId = 0;
66 // look through all registered clients until we find a "gap" in the ids
68 // Note that the following relies on the fact the elements in the map are traveled with
69 // ascending keys (aka client ids)
70 AccessibleEventNotifier::ClientMap &rClients = Clients::get();
71 for ( ClientMap::const_iterator aLookup = rClients.begin();
72 aLookup != rClients.end();
73 ++aLookup
76 TClientId nCurrent = aLookup->first;
77 OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );
79 if ( nCurrent - nBiggestUsedId > 1 )
80 { // found a "gap"
81 nFreeId = nBiggestUsedId + 1;
82 break;
85 nBiggestUsedId = nCurrent;
88 if ( !nFreeId )
89 nFreeId = nBiggestUsedId + 1;
91 OSL_ENSURE( rClients.end() == rClients.find( nFreeId ),
92 "AccessibleEventNotifier::generateId: algorithm broken!" );
94 return nFreeId;
97 //---------------------------------------------------------------------
98 AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( )
100 ::osl::MutexGuard aGuard( lclMutex::get() );
102 // generate a new client id
103 TClientId nNewClientId = generateId( );
105 // the event listeners for the new client
106 EventListeners* pNewListeners = new EventListeners( lclMutex::get() );
107 // note that we're using our own mutex here, so the listener containers for all
108 // our clients share this same mutex.
109 // this is a reminiscense to the days where the notifier was asynchronous. Today this is
110 // completely nonsense, and potentially slowing down the Office me thinks ...
112 // add the client
113 Clients::get().insert( ClientMap::value_type( nNewClientId, pNewListeners ) );
115 // outta here
116 return nNewClientId;
119 //---------------------------------------------------------------------
120 sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos )
122 // look up this client
123 AccessibleEventNotifier::ClientMap &rClients = Clients::get();
124 _rPos = rClients.find( _nClient );
125 OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );
127 return ( rClients.end() != _rPos );
130 //---------------------------------------------------------------------
131 void AccessibleEventNotifier::revokeClient( const TClientId _nClient )
133 ::osl::MutexGuard aGuard( lclMutex::get() );
135 ClientMap::iterator aClientPos;
136 if ( !implLookupClient( _nClient, aClientPos ) )
137 // already asserted in implLookupClient
138 return;
140 // remove it from the clients map
141 delete aClientPos->second;
142 Clients::get().erase( aClientPos );
145 //---------------------------------------------------------------------
146 void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient,
147 const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) )
149 ::osl::MutexGuard aGuard( lclMutex::get() );
151 ClientMap::iterator aClientPos;
152 if ( !implLookupClient( _nClient, aClientPos ) )
153 // already asserted in implLookupClient
154 return;
156 // notify the "disposing" event for this client
157 EventObject aDisposalEvent;
158 aDisposalEvent.Source = _rxEventSource;
160 // notify the listeners
161 EventListeners* pListeners = aClientPos->second;
163 // we do not need the entry in the clients map anymore
164 // (do this before actually notifying, because some client implementations have re-entrance
165 // problems and call into revokeClient while we are notifying from hereing)
166 Clients::get().erase( aClientPos );
168 // now really do the notification
169 pListeners->disposeAndClear( aDisposalEvent );
170 delete pListeners;
174 //---------------------------------------------------------------------
175 sal_Int32 AccessibleEventNotifier::addEventListener(
176 const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
178 ::osl::MutexGuard aGuard( lclMutex::get() );
180 ClientMap::iterator aClientPos;
181 if ( !implLookupClient( _nClient, aClientPos ) )
182 // already asserted in implLookupClient
183 return 0;
185 if ( _rxListener.is() )
186 aClientPos->second->addInterface( _rxListener );
188 return aClientPos->second->getLength();
191 //---------------------------------------------------------------------
192 sal_Int32 AccessibleEventNotifier::removeEventListener(
193 const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
195 ::osl::MutexGuard aGuard( lclMutex::get() );
197 ClientMap::iterator aClientPos;
198 if ( !implLookupClient( _nClient, aClientPos ) )
199 // already asserted in implLookupClient
200 return 0;
202 if ( _rxListener.is() )
203 aClientPos->second->removeInterface( _rxListener );
205 return aClientPos->second->getLength();
208 //---------------------------------------------------------------------
209 Sequence< Reference< XInterface > > AccessibleEventNotifier::getEventListeners( const TClientId _nClient ) SAL_THROW( ( ) )
211 Sequence< Reference< XInterface > > aListeners;
213 ::osl::MutexGuard aGuard( lclMutex::get() );
215 ClientMap::iterator aClientPos;
216 if ( implLookupClient( _nClient, aClientPos ) )
217 aListeners = aClientPos->second->getElements();
219 return aListeners;
222 //---------------------------------------------------------------------
223 void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) )
225 Sequence< Reference< XInterface > > aListeners;
227 // --- <mutex lock> -------------------------------
229 ::osl::MutexGuard aGuard( lclMutex::get() );
231 ClientMap::iterator aClientPos;
232 if ( !implLookupClient( _nClient, aClientPos ) )
233 // already asserted in implLookupClient
234 return;
236 // since we're synchronous, again, we want to notify immediately
237 aListeners = aClientPos->second->getElements();
239 // --- </mutex lock> ------------------------------
241 // default handling: loop through all listeners, and notify them
242 const Reference< XInterface >* pListeners = aListeners.getConstArray();
243 const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
244 while ( pListeners != pListenersEnd )
248 static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent );
250 catch( const Exception& )
252 // no assertion, because a broken access remote bridge or something like this
253 // can cause this exception
255 ++pListeners;
259 //.........................................................................
260 } // namespace comphelper
261 //.........................................................................