Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / comphelper / source / misc / accessibleeventnotifier.cxx
blobe6e88de215a026fc7d9f396e6416ba36b02b243f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/accessibleeventnotifier.hxx>
21 #include <osl/diagnose.h>
22 #include <rtl/instance.hxx>
23 #include <comphelper/guarding.hxx>
25 using namespace ::com::sun::star::uno;
26 using namespace ::com::sun::star::lang;
27 using namespace ::com::sun::star::accessibility;
28 using namespace ::comphelper;
30 //=====================================================================
31 //= AccessibleEventNotifier
32 //=====================================================================
33 //---------------------------------------------------------------------
34 namespace
36 struct lclMutex
37 : public rtl::Static< ::osl::Mutex, lclMutex > {};
38 struct Clients
39 : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {};
42 //.........................................................................
43 namespace comphelper
45 //.........................................................................
47 //---------------------------------------------------------------------
48 AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId()
50 TClientId nBiggestUsedId = 0;
51 TClientId nFreeId = 0;
53 // look through all registered clients until we find a "gap" in the ids
55 // Note that the following relies on the fact the elements in the map are traveled with
56 // ascending keys (aka client ids)
57 AccessibleEventNotifier::ClientMap &rClients = Clients::get();
58 for ( ClientMap::const_iterator aLookup = rClients.begin();
59 aLookup != rClients.end();
60 ++aLookup
63 TClientId nCurrent = aLookup->first;
64 OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );
66 if ( nCurrent - nBiggestUsedId > 1 )
67 { // found a "gap"
68 nFreeId = nBiggestUsedId + 1;
69 break;
72 nBiggestUsedId = nCurrent;
75 if ( !nFreeId )
76 nFreeId = nBiggestUsedId + 1;
78 OSL_ENSURE( rClients.end() == rClients.find( nFreeId ),
79 "AccessibleEventNotifier::generateId: algorithm broken!" );
81 return nFreeId;
84 //---------------------------------------------------------------------
85 AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( )
87 ::osl::MutexGuard aGuard( lclMutex::get() );
89 // generate a new client id
90 TClientId nNewClientId = generateId( );
92 // the event listeners for the new client
93 EventListeners* pNewListeners = new EventListeners( lclMutex::get() );
94 // note that we're using our own mutex here, so the listener containers for all
95 // our clients share this same mutex.
96 // this is a reminiscense to the days where the notifier was asynchronous. Today this is
97 // completely nonsense, and potentially slowing down the Office me thinks ...
99 // add the client
100 Clients::get().insert( ClientMap::value_type( nNewClientId, pNewListeners ) );
102 // outta here
103 return nNewClientId;
106 //---------------------------------------------------------------------
107 sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos )
109 // look up this client
110 AccessibleEventNotifier::ClientMap &rClients = Clients::get();
111 _rPos = rClients.find( _nClient );
112 OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );
114 return ( rClients.end() != _rPos );
117 //---------------------------------------------------------------------
118 void AccessibleEventNotifier::revokeClient( const TClientId _nClient )
120 ::osl::MutexGuard aGuard( lclMutex::get() );
122 ClientMap::iterator aClientPos;
123 if ( !implLookupClient( _nClient, aClientPos ) )
124 // already asserted in implLookupClient
125 return;
127 // remove it from the clients map
128 delete aClientPos->second;
129 Clients::get().erase( aClientPos );
132 //---------------------------------------------------------------------
133 void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient,
134 const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) )
136 ::osl::MutexGuard aGuard( lclMutex::get() );
138 ClientMap::iterator aClientPos;
139 if ( !implLookupClient( _nClient, aClientPos ) )
140 // already asserted in implLookupClient
141 return;
143 // notify the "disposing" event for this client
144 EventObject aDisposalEvent;
145 aDisposalEvent.Source = _rxEventSource;
147 // notify the listeners
148 EventListeners* pListeners = aClientPos->second;
150 // we do not need the entry in the clients map anymore
151 // (do this before actually notifying, because some client implementations have re-entrance
152 // problems and call into revokeClient while we are notifying from hereing)
153 Clients::get().erase( aClientPos );
155 // now really do the notification
156 pListeners->disposeAndClear( aDisposalEvent );
157 delete pListeners;
161 //---------------------------------------------------------------------
162 sal_Int32 AccessibleEventNotifier::addEventListener(
163 const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
165 ::osl::MutexGuard aGuard( lclMutex::get() );
167 ClientMap::iterator aClientPos;
168 if ( !implLookupClient( _nClient, aClientPos ) )
169 // already asserted in implLookupClient
170 return 0;
172 if ( _rxListener.is() )
173 aClientPos->second->addInterface( _rxListener );
175 return aClientPos->second->getLength();
178 //---------------------------------------------------------------------
179 sal_Int32 AccessibleEventNotifier::removeEventListener(
180 const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
182 ::osl::MutexGuard aGuard( lclMutex::get() );
184 ClientMap::iterator aClientPos;
185 if ( !implLookupClient( _nClient, aClientPos ) )
186 // already asserted in implLookupClient
187 return 0;
189 if ( _rxListener.is() )
190 aClientPos->second->removeInterface( _rxListener );
192 return aClientPos->second->getLength();
195 //---------------------------------------------------------------------
196 void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) )
198 Sequence< Reference< XInterface > > aListeners;
200 // --- <mutex lock> -------------------------------
202 ::osl::MutexGuard aGuard( lclMutex::get() );
204 ClientMap::iterator aClientPos;
205 if ( !implLookupClient( _nClient, aClientPos ) )
206 // already asserted in implLookupClient
207 return;
209 // since we're synchronous, again, we want to notify immediately
210 aListeners = aClientPos->second->getElements();
212 // --- </mutex lock> ------------------------------
214 // default handling: loop through all listeners, and notify them
215 const Reference< XInterface >* pListeners = aListeners.getConstArray();
216 const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
217 while ( pListeners != pListenersEnd )
221 static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent );
223 catch( const Exception& )
225 // no assertion, because a broken access remote bridge or something like this
226 // can cause this exception
228 ++pListeners;
232 //.........................................................................
233 } // namespace comphelper
234 //.........................................................................
236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */