Update ooo320-m1
[ooovba.git] / comphelper / source / misc / accessiblecontexthelper.cxx
blobe899592962879a012c1f358f251dd0a4928590af
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: accessiblecontexthelper.cxx,v $
10 * $Revision: 1.16 $
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/accessiblecontexthelper.hxx>
34 #include <comphelper/accessibleeventbuffer.hxx>
35 #include <osl/diagnose.h>
36 #include <cppuhelper/weakref.hxx>
37 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
38 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
39 #include <comphelper/accessibleeventnotifier.hxx>
41 //.........................................................................
42 namespace comphelper
44 //.........................................................................
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::lang;
48 using namespace ::com::sun::star::accessibility;
50 //=====================================================================
51 //= OContextHelper_Impl
52 //=====================================================================
53 /** implementation class for OAccessibleContextHelper. No own thread safety!
55 class OContextHelper_Impl
57 private:
58 OAccessibleContextHelper* m_pAntiImpl; // the owning instance
59 IMutex* m_pExternalLock; // the optional additional external lock
61 ::cppu::OInterfaceContainerHelper* m_pEventListeners;
62 WeakReference< XAccessible > m_aCreator; // the XAccessible which created our XAccessibleContext
64 AccessibleEventNotifier::TClientId m_nClientId;
66 public:
67 inline Reference< XAccessible > getCreator( ) const { return m_aCreator; }
68 inline void setCreator( const Reference< XAccessible >& _rAcc );
70 inline IMutex* getExternalLock( ) { return m_pExternalLock; }
71 inline void setExternalLock( IMutex* _pLock ) { m_pExternalLock = _pLock; }
73 inline AccessibleEventNotifier::TClientId
74 getClientId() const { return m_nClientId; }
75 inline void setClientId( const AccessibleEventNotifier::TClientId _nId )
76 { m_nClientId = _nId; }
78 public:
79 OContextHelper_Impl( OAccessibleContextHelper* _pAntiImpl )
80 :m_pAntiImpl( _pAntiImpl )
81 ,m_pExternalLock( NULL )
82 ,m_pEventListeners( NULL )
83 ,m_nClientId( 0 )
88 //---------------------------------------------------------------------
89 inline void OContextHelper_Impl::setCreator( const Reference< XAccessible >& _rAcc )
91 m_aCreator = _rAcc;
94 //=====================================================================
95 //= OAccessibleContextHelper
96 //=====================================================================
97 //---------------------------------------------------------------------
98 OAccessibleContextHelper::OAccessibleContextHelper( )
99 :OAccessibleContextHelper_Base( GetMutex() )
100 ,m_pImpl( NULL )
102 m_pImpl = new OContextHelper_Impl( this );
105 //---------------------------------------------------------------------
106 OAccessibleContextHelper::OAccessibleContextHelper( IMutex* _pExternalLock )
107 :OAccessibleContextHelper_Base( GetMutex() )
108 ,m_pImpl( NULL )
110 m_pImpl = new OContextHelper_Impl( this );
111 m_pImpl->setExternalLock( _pExternalLock );
114 //---------------------------------------------------------------------
115 void OAccessibleContextHelper::forgetExternalLock()
117 m_pImpl->setExternalLock( NULL );
120 //---------------------------------------------------------------------
121 OAccessibleContextHelper::~OAccessibleContextHelper( )
123 forgetExternalLock();
124 // this ensures that the lock, which may be already destroyed as part of the derivee,
125 // is not used anymore
127 ensureDisposed();
129 delete m_pImpl;
130 m_pImpl = NULL;
133 //---------------------------------------------------------------------
134 IMutex* OAccessibleContextHelper::getExternalLock( )
136 return m_pImpl->getExternalLock();
139 //---------------------------------------------------------------------
140 void SAL_CALL OAccessibleContextHelper::disposing()
142 ::osl::ClearableMutexGuard aGuard( GetMutex() );
144 if ( m_pImpl->getClientId( ) )
146 AccessibleEventNotifier::revokeClientNotifyDisposing( m_pImpl->getClientId( ), *this );
147 m_pImpl->setClientId( 0 );
151 //---------------------------------------------------------------------
152 void SAL_CALL OAccessibleContextHelper::addEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
154 OMutexGuard aGuard( getExternalLock() );
155 // don't use the OContextEntryGuard - it will throw an exception if we're not alive
156 // anymore, while the most recent specification for XComponent states that we should
157 // silently ignore the call in such a situation
158 if ( !isAlive() )
160 if ( _rxListener.is() )
161 _rxListener->disposing( EventObject( *this ) );
162 return;
165 if ( _rxListener.is() )
167 if ( !m_pImpl->getClientId( ) )
168 m_pImpl->setClientId( AccessibleEventNotifier::registerClient( ) );
170 AccessibleEventNotifier::addEventListener( m_pImpl->getClientId( ), _rxListener );
174 //---------------------------------------------------------------------
175 void SAL_CALL OAccessibleContextHelper::removeEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
177 OMutexGuard aGuard( getExternalLock() );
178 // don't use the OContextEntryGuard - it will throw an exception if we're not alive
179 // anymore, while the most recent specification for XComponent states that we should
180 // silently ignore the call in such a situation
181 if ( !isAlive() )
182 return;
184 if ( _rxListener.is() )
186 sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( m_pImpl->getClientId( ), _rxListener );
187 if ( !nListenerCount )
189 // no listeners anymore
190 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
191 // and at least to us not firing any events anymore, in case somebody calls
192 // NotifyAccessibleEvent, again
193 AccessibleEventNotifier::revokeClient( m_pImpl->getClientId( ) );
194 m_pImpl->setClientId( 0 );
199 //---------------------------------------------------------------------
200 void SAL_CALL OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId,
201 const Any& _rOldValue, const Any& _rNewValue )
203 if ( !m_pImpl->getClientId( ) )
204 // if we don't have a client id for the notifier, then we don't have listeners, then
205 // we don't need to notify anything
206 return;
208 // build an event object
209 AccessibleEventObject aEvent;
210 aEvent.Source = *this;
211 aEvent.EventId = _nEventId;
212 aEvent.OldValue = _rOldValue;
213 aEvent.NewValue = _rNewValue;
215 // let the notifier handle this event
216 AccessibleEventNotifier::addEvent( m_pImpl->getClientId( ), aEvent );
219 //---------------------------------------------------------------------
220 void SAL_CALL OAccessibleContextHelper::BufferAccessibleEvent( const sal_Int16 _nEventId,
221 const Any& _rOldValue, const Any& _rNewValue,
222 AccessibleEventBuffer & _rBuffer )
224 // TODO: this whole method (as well as the class AccessibleEventBuffer) should be removed
225 // The reasons why they have been introduces id that we needed to collect a set of events
226 // before notifying them alltogether (after releasing our mutex). With the other
227 // NotifyAccessibleEvent being asynchronous now, this should not be necessary anymore
228 // - clients could use the other version now.
230 // copy our current listeners
231 Sequence< Reference< XInterface > > aListeners;
232 if ( m_pImpl->getClientId( ) )
233 aListeners = AccessibleEventNotifier::getEventListeners( m_pImpl->getClientId( ) );
235 if ( aListeners.getLength() )
237 AccessibleEventObject aEvent;
238 aEvent.Source = *this;
239 OSL_ENSURE( aEvent.Source.is(), "OAccessibleContextHelper::BufferAccessibleEvent: invalid creator!" );
240 aEvent.EventId = _nEventId;
241 aEvent.OldValue = _rOldValue;
242 aEvent.NewValue = _rNewValue;
244 _rBuffer.addEvent( aEvent, aListeners );
248 //---------------------------------------------------------------------
249 sal_Bool OAccessibleContextHelper::isAlive() const
251 return !GetBroadcastHelper().bDisposed && !GetBroadcastHelper().bInDispose;
254 //---------------------------------------------------------------------
255 void OAccessibleContextHelper::ensureAlive() const SAL_THROW( ( DisposedException ) )
257 if( !isAlive() )
258 throw DisposedException();
261 //---------------------------------------------------------------------
262 void OAccessibleContextHelper::ensureDisposed( )
264 if ( !GetBroadcastHelper().bDisposed )
266 OSL_ENSURE( 0 == m_refCount, "OAccessibleContextHelper::ensureDisposed: this method _has_ to be called from without your dtor only!" );
267 acquire();
268 dispose();
272 //---------------------------------------------------------------------
273 void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible )
275 m_pImpl->setCreator( _rxAccessible );
278 //---------------------------------------------------------------------
279 Reference< XAccessible > OAccessibleContextHelper::getAccessibleCreator( ) const
281 return m_pImpl->getCreator();
284 //---------------------------------------------------------------------
285 sal_Int32 SAL_CALL OAccessibleContextHelper::getAccessibleIndexInParent( ) throw (RuntimeException)
287 OExternalLockGuard aGuard( this );
289 // -1 for child not found/no parent (according to specification)
290 sal_Int32 nRet = -1;
295 Reference< XAccessibleContext > xParentContext( implGetParentContext() );
297 // iterate over parent's children and search for this object
298 if ( xParentContext.is() )
300 // our own XAccessible for comparing with the children of our parent
301 Reference< XAccessible > xCreator( m_pImpl->getCreator() );
303 OSL_ENSURE( xCreator.is(), "OAccessibleContextHelper::getAccessibleIndexInParent: invalid creator!" );
304 // two ideas why this could be NULL:
305 // * nobody called our late ctor (init), so we never had a creator at all -> bad
306 // * the creator is already dead. In this case, we should have been disposed, and
307 // never survived the above OContextEntryGuard.
308 // in all other situations the creator should be non-NULL
310 if ( xCreator.is() )
312 sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
313 for ( sal_Int32 nChild = 0; ( nChild < nChildCount ) && ( -1 == nRet ); ++nChild )
315 Reference< XAccessible > xChild( xParentContext->getAccessibleChild( nChild ) );
316 if ( xChild.get() == xCreator.get() )
317 nRet = nChild;
322 catch( const Exception& )
324 OSL_ENSURE( sal_False, "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" );
327 return nRet;
330 //---------------------------------------------------------------------
331 Locale SAL_CALL OAccessibleContextHelper::getLocale( ) throw (IllegalAccessibleComponentStateException, RuntimeException)
333 // simply ask the parent
334 Reference< XAccessible > xParent = getAccessibleParent();
335 Reference< XAccessibleContext > xParentContext;
336 if ( xParent.is() )
337 xParentContext = xParent->getAccessibleContext();
339 if ( !xParentContext.is() )
340 throw IllegalAccessibleComponentStateException( ::rtl::OUString(), *this );
342 return xParentContext->getLocale();
345 //---------------------------------------------------------------------
346 Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext() SAL_THROW( ( RuntimeException ) )
348 Reference< XAccessible > xParent = getAccessibleParent();
349 Reference< XAccessibleContext > xParentContext;
350 if ( xParent.is() )
351 xParentContext = xParent->getAccessibleContext();
352 return xParentContext;
355 //.........................................................................
356 } // namespace comphelper
357 //.........................................................................