summaryrefslogtreecommitdiff
path: root/comphelper/source/misc/accessibleeventnotifier.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'comphelper/source/misc/accessibleeventnotifier.cxx')
-rw-r--r--comphelper/source/misc/accessibleeventnotifier.cxx262
1 files changed, 262 insertions, 0 deletions
diff --git a/comphelper/source/misc/accessibleeventnotifier.cxx b/comphelper/source/misc/accessibleeventnotifier.cxx
new file mode 100644
index 000000000000..59d6dc3038a1
--- /dev/null
+++ b/comphelper/source/misc/accessibleeventnotifier.cxx
@@ -0,0 +1,262 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: accessibleeventnotifier.cxx,v $
+ * $Revision: 1.11 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_comphelper.hxx"
+#include <comphelper/accessibleeventnotifier.hxx>
+#include <osl/diagnose.h>
+#include <rtl/instance.hxx>
+#include <comphelper/guarding.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::accessibility;
+using namespace ::comphelper;
+
+//=====================================================================
+//= AccessibleEventNotifier
+//=====================================================================
+//---------------------------------------------------------------------
+namespace
+{
+ struct lclMutex
+ : public rtl::Static< ::osl::Mutex, lclMutex > {};
+ struct Clients
+ : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {};
+}
+
+//.........................................................................
+namespace comphelper
+{
+//.........................................................................
+
+ //---------------------------------------------------------------------
+ AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId()
+ {
+ TClientId nBiggestUsedId = 0;
+ TClientId nFreeId = 0;
+
+ // look through all registered clients until we find a "gap" in the ids
+
+ // Note that the following relies on the fact the elements in the map are traveled with
+ // ascending keys (aka client ids)
+ AccessibleEventNotifier::ClientMap &rClients = Clients::get();
+ for ( ClientMap::const_iterator aLookup = rClients.begin();
+ aLookup != rClients.end();
+ ++aLookup
+ )
+ {
+ TClientId nCurrent = aLookup->first;
+ OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );
+
+ if ( nCurrent - nBiggestUsedId > 1 )
+ { // found a "gap"
+ nFreeId = nBiggestUsedId + 1;
+ break;
+ }
+
+ nBiggestUsedId = nCurrent;
+ }
+
+ if ( !nFreeId )
+ nFreeId = nBiggestUsedId + 1;
+
+ OSL_ENSURE( rClients.end() == rClients.find( nFreeId ),
+ "AccessibleEventNotifier::generateId: algorithm broken!" );
+
+ return nFreeId;
+ }
+
+ //---------------------------------------------------------------------
+ AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( )
+ {
+ ::osl::MutexGuard aGuard( lclMutex::get() );
+
+ // generate a new client id
+ TClientId nNewClientId = generateId( );
+
+ // the event listeners for the new client
+ EventListeners* pNewListeners = new EventListeners( lclMutex::get() );
+ // note that we're using our own mutex here, so the listener containers for all
+ // our clients share this same mutex.
+ // this is a reminiscense to the days where the notifier was asynchronous. Today this is
+ // completely nonsense, and potentially slowing down the Office me thinks ...
+
+ // add the client
+ Clients::get().insert( ClientMap::value_type( nNewClientId, pNewListeners ) );
+
+ // outta here
+ return nNewClientId;
+ }
+
+ //---------------------------------------------------------------------
+ sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos )
+ {
+ // look up this client
+ AccessibleEventNotifier::ClientMap &rClients = Clients::get();
+ _rPos = rClients.find( _nClient );
+ OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );
+
+ return ( rClients.end() != _rPos );
+ }
+
+ //---------------------------------------------------------------------
+ void AccessibleEventNotifier::revokeClient( const TClientId _nClient )
+ {
+ ::osl::MutexGuard aGuard( lclMutex::get() );
+
+ ClientMap::iterator aClientPos;
+ if ( !implLookupClient( _nClient, aClientPos ) )
+ // already asserted in implLookupClient
+ return;
+
+ // remove it from the clients map
+ delete aClientPos->second;
+ Clients::get().erase( aClientPos );
+ }
+
+ //---------------------------------------------------------------------
+ void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient,
+ const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) )
+ {
+ ::osl::MutexGuard aGuard( lclMutex::get() );
+
+ ClientMap::iterator aClientPos;
+ if ( !implLookupClient( _nClient, aClientPos ) )
+ // already asserted in implLookupClient
+ return;
+
+ // notify the "disposing" event for this client
+ EventObject aDisposalEvent;
+ aDisposalEvent.Source = _rxEventSource;
+
+ // notify the listeners
+ EventListeners* pListeners = aClientPos->second;
+
+ // we do not need the entry in the clients map anymore
+ // (do this before actually notifying, because some client implementations have re-entrance
+ // problems and call into revokeClient while we are notifying from hereing)
+ Clients::get().erase( aClientPos );
+
+ // now really do the notification
+ pListeners->disposeAndClear( aDisposalEvent );
+ delete pListeners;
+
+ }
+
+ //---------------------------------------------------------------------
+ sal_Int32 AccessibleEventNotifier::addEventListener(
+ const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
+ {
+ ::osl::MutexGuard aGuard( lclMutex::get() );
+
+ ClientMap::iterator aClientPos;
+ if ( !implLookupClient( _nClient, aClientPos ) )
+ // already asserted in implLookupClient
+ return 0;
+
+ if ( _rxListener.is() )
+ aClientPos->second->addInterface( _rxListener );
+
+ return aClientPos->second->getLength();
+ }
+
+ //---------------------------------------------------------------------
+ sal_Int32 AccessibleEventNotifier::removeEventListener(
+ const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
+ {
+ ::osl::MutexGuard aGuard( lclMutex::get() );
+
+ ClientMap::iterator aClientPos;
+ if ( !implLookupClient( _nClient, aClientPos ) )
+ // already asserted in implLookupClient
+ return 0;
+
+ if ( _rxListener.is() )
+ aClientPos->second->removeInterface( _rxListener );
+
+ return aClientPos->second->getLength();
+ }
+
+ //---------------------------------------------------------------------
+ Sequence< Reference< XInterface > > AccessibleEventNotifier::getEventListeners( const TClientId _nClient ) SAL_THROW( ( ) )
+ {
+ Sequence< Reference< XInterface > > aListeners;
+
+ ::osl::MutexGuard aGuard( lclMutex::get() );
+
+ ClientMap::iterator aClientPos;
+ if ( implLookupClient( _nClient, aClientPos ) )
+ aListeners = aClientPos->second->getElements();
+
+ return aListeners;
+ }
+
+ //---------------------------------------------------------------------
+ void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) )
+ {
+ Sequence< Reference< XInterface > > aListeners;
+
+ // --- <mutex lock> -------------------------------
+ {
+ ::osl::MutexGuard aGuard( lclMutex::get() );
+
+ ClientMap::iterator aClientPos;
+ if ( !implLookupClient( _nClient, aClientPos ) )
+ // already asserted in implLookupClient
+ return;
+
+ // since we're synchronous, again, we want to notify immediately
+ aListeners = aClientPos->second->getElements();
+ }
+ // --- </mutex lock> ------------------------------
+
+ // default handling: loop through all listeners, and notify them
+ const Reference< XInterface >* pListeners = aListeners.getConstArray();
+ const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
+ while ( pListeners != pListenersEnd )
+ {
+ try
+ {
+ static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent );
+ }
+ catch( const Exception& )
+ {
+ // no assertion, because a broken access remote bridge or something like this
+ // can cause this exception
+ }
+ ++pListeners;
+ }
+ }
+
+//.........................................................................
+} // namespace comphelper
+//.........................................................................
+