1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: accessibleeventnotifier.cxx,v $
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 //---------------------------------------------------------------------
50 : public rtl::Static
< ::osl::Mutex
, lclMutex
> {};
52 : public rtl::Static
< AccessibleEventNotifier::ClientMap
, Clients
> {};
55 //.........................................................................
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();
76 TClientId nCurrent
= aLookup
->first
;
77 OSL_ENSURE( nCurrent
> nBiggestUsedId
, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );
79 if ( nCurrent
- nBiggestUsedId
> 1 )
81 nFreeId
= nBiggestUsedId
+ 1;
85 nBiggestUsedId
= nCurrent
;
89 nFreeId
= nBiggestUsedId
+ 1;
91 OSL_ENSURE( rClients
.end() == rClients
.find( nFreeId
),
92 "AccessibleEventNotifier::generateId: algorithm broken!" );
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 ...
113 Clients::get().insert( ClientMap::value_type( nNewClientId
, pNewListeners
) );
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
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
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
);
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
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
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();
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
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
259 //.........................................................................
260 } // namespace comphelper
261 //.........................................................................