CWS-TOOLING: integrate CWS os146
[LibreOffice.git] / comphelper / source / misc / accessiblecontexthelper.cxx
blob2e0281848e8cd03b427e1e6055f949eaed2f6e84
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 #include <comphelper/accessiblecontexthelper.hxx>
31 #include <comphelper/accessibleeventbuffer.hxx>
32 #include <osl/diagnose.h>
33 #include <cppuhelper/weakref.hxx>
34 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
35 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
36 #include <comphelper/accessibleeventnotifier.hxx>
38 //.........................................................................
39 namespace comphelper
41 //.........................................................................
43 using namespace ::com::sun::star::uno;
44 using namespace ::com::sun::star::lang;
45 using namespace ::com::sun::star::accessibility;
47 //=====================================================================
48 //= OContextHelper_Impl
49 //=====================================================================
50 /** implementation class for OAccessibleContextHelper. No own thread safety!
52 class OContextHelper_Impl
54 private:
55 OAccessibleContextHelper* m_pAntiImpl; // the owning instance
56 IMutex* m_pExternalLock; // the optional additional external lock
58 ::cppu::OInterfaceContainerHelper* m_pEventListeners;
59 WeakReference< XAccessible > m_aCreator; // the XAccessible which created our XAccessibleContext
61 AccessibleEventNotifier::TClientId m_nClientId;
63 public:
64 inline Reference< XAccessible > getCreator( ) const { return m_aCreator; }
65 inline void setCreator( const Reference< XAccessible >& _rAcc );
67 inline IMutex* getExternalLock( ) { return m_pExternalLock; }
68 inline void setExternalLock( IMutex* _pLock ) { m_pExternalLock = _pLock; }
70 inline AccessibleEventNotifier::TClientId
71 getClientId() const { return m_nClientId; }
72 inline void setClientId( const AccessibleEventNotifier::TClientId _nId )
73 { m_nClientId = _nId; }
75 public:
76 OContextHelper_Impl( OAccessibleContextHelper* _pAntiImpl )
77 :m_pAntiImpl( _pAntiImpl )
78 ,m_pExternalLock( NULL )
79 ,m_pEventListeners( NULL )
80 ,m_nClientId( 0 )
85 //---------------------------------------------------------------------
86 inline void OContextHelper_Impl::setCreator( const Reference< XAccessible >& _rAcc )
88 m_aCreator = _rAcc;
91 //=====================================================================
92 //= OAccessibleContextHelper
93 //=====================================================================
94 //---------------------------------------------------------------------
95 OAccessibleContextHelper::OAccessibleContextHelper( )
96 :OAccessibleContextHelper_Base( GetMutex() )
97 ,m_pImpl( NULL )
99 m_pImpl = new OContextHelper_Impl( this );
102 //---------------------------------------------------------------------
103 OAccessibleContextHelper::OAccessibleContextHelper( IMutex* _pExternalLock )
104 :OAccessibleContextHelper_Base( GetMutex() )
105 ,m_pImpl( NULL )
107 m_pImpl = new OContextHelper_Impl( this );
108 m_pImpl->setExternalLock( _pExternalLock );
111 //---------------------------------------------------------------------
112 void OAccessibleContextHelper::forgetExternalLock()
114 m_pImpl->setExternalLock( NULL );
117 //---------------------------------------------------------------------
118 OAccessibleContextHelper::~OAccessibleContextHelper( )
120 forgetExternalLock();
121 // this ensures that the lock, which may be already destroyed as part of the derivee,
122 // is not used anymore
124 ensureDisposed();
126 delete m_pImpl;
127 m_pImpl = NULL;
130 //---------------------------------------------------------------------
131 IMutex* OAccessibleContextHelper::getExternalLock( )
133 return m_pImpl->getExternalLock();
136 //---------------------------------------------------------------------
137 void SAL_CALL OAccessibleContextHelper::disposing()
139 ::osl::ClearableMutexGuard aGuard( GetMutex() );
141 if ( m_pImpl->getClientId( ) )
143 AccessibleEventNotifier::revokeClientNotifyDisposing( m_pImpl->getClientId( ), *this );
144 m_pImpl->setClientId( 0 );
148 //---------------------------------------------------------------------
149 void SAL_CALL OAccessibleContextHelper::addEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
151 OMutexGuard aGuard( getExternalLock() );
152 // don't use the OContextEntryGuard - it will throw an exception if we're not alive
153 // anymore, while the most recent specification for XComponent states that we should
154 // silently ignore the call in such a situation
155 if ( !isAlive() )
157 if ( _rxListener.is() )
158 _rxListener->disposing( EventObject( *this ) );
159 return;
162 if ( _rxListener.is() )
164 if ( !m_pImpl->getClientId( ) )
165 m_pImpl->setClientId( AccessibleEventNotifier::registerClient( ) );
167 AccessibleEventNotifier::addEventListener( m_pImpl->getClientId( ), _rxListener );
171 //---------------------------------------------------------------------
172 void SAL_CALL OAccessibleContextHelper::removeEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
174 OMutexGuard aGuard( getExternalLock() );
175 // don't use the OContextEntryGuard - it will throw an exception if we're not alive
176 // anymore, while the most recent specification for XComponent states that we should
177 // silently ignore the call in such a situation
178 if ( !isAlive() )
179 return;
181 if ( _rxListener.is() )
183 sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( m_pImpl->getClientId( ), _rxListener );
184 if ( !nListenerCount )
186 // no listeners anymore
187 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
188 // and at least to us not firing any events anymore, in case somebody calls
189 // NotifyAccessibleEvent, again
190 AccessibleEventNotifier::revokeClient( m_pImpl->getClientId( ) );
191 m_pImpl->setClientId( 0 );
196 //---------------------------------------------------------------------
197 void SAL_CALL OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId,
198 const Any& _rOldValue, const Any& _rNewValue )
200 if ( !m_pImpl->getClientId( ) )
201 // if we don't have a client id for the notifier, then we don't have listeners, then
202 // we don't need to notify anything
203 return;
205 // build an event object
206 AccessibleEventObject aEvent;
207 aEvent.Source = *this;
208 aEvent.EventId = _nEventId;
209 aEvent.OldValue = _rOldValue;
210 aEvent.NewValue = _rNewValue;
212 // let the notifier handle this event
213 AccessibleEventNotifier::addEvent( m_pImpl->getClientId( ), aEvent );
216 //---------------------------------------------------------------------
217 void SAL_CALL OAccessibleContextHelper::BufferAccessibleEvent( const sal_Int16 _nEventId,
218 const Any& _rOldValue, const Any& _rNewValue,
219 AccessibleEventBuffer & _rBuffer )
221 // TODO: this whole method (as well as the class AccessibleEventBuffer) should be removed
222 // The reasons why they have been introduces id that we needed to collect a set of events
223 // before notifying them alltogether (after releasing our mutex). With the other
224 // NotifyAccessibleEvent being asynchronous now, this should not be necessary anymore
225 // - clients could use the other version now.
227 // copy our current listeners
228 Sequence< Reference< XInterface > > aListeners;
229 if ( m_pImpl->getClientId( ) )
230 aListeners = AccessibleEventNotifier::getEventListeners( m_pImpl->getClientId( ) );
232 if ( aListeners.getLength() )
234 AccessibleEventObject aEvent;
235 aEvent.Source = *this;
236 OSL_ENSURE( aEvent.Source.is(), "OAccessibleContextHelper::BufferAccessibleEvent: invalid creator!" );
237 aEvent.EventId = _nEventId;
238 aEvent.OldValue = _rOldValue;
239 aEvent.NewValue = _rNewValue;
241 _rBuffer.addEvent( aEvent, aListeners );
245 //---------------------------------------------------------------------
246 sal_Bool OAccessibleContextHelper::isAlive() const
248 return !GetBroadcastHelper().bDisposed && !GetBroadcastHelper().bInDispose;
251 //---------------------------------------------------------------------
252 void OAccessibleContextHelper::ensureAlive() const SAL_THROW( ( DisposedException ) )
254 if( !isAlive() )
255 throw DisposedException();
258 //---------------------------------------------------------------------
259 void OAccessibleContextHelper::ensureDisposed( )
261 if ( !GetBroadcastHelper().bDisposed )
263 OSL_ENSURE( 0 == m_refCount, "OAccessibleContextHelper::ensureDisposed: this method _has_ to be called from without your dtor only!" );
264 acquire();
265 dispose();
269 //---------------------------------------------------------------------
270 void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible )
272 m_pImpl->setCreator( _rxAccessible );
275 //---------------------------------------------------------------------
276 Reference< XAccessible > OAccessibleContextHelper::getAccessibleCreator( ) const
278 return m_pImpl->getCreator();
281 //---------------------------------------------------------------------
282 sal_Int32 SAL_CALL OAccessibleContextHelper::getAccessibleIndexInParent( ) throw (RuntimeException)
284 OExternalLockGuard aGuard( this );
286 // -1 for child not found/no parent (according to specification)
287 sal_Int32 nRet = -1;
292 Reference< XAccessibleContext > xParentContext( implGetParentContext() );
294 // iterate over parent's children and search for this object
295 if ( xParentContext.is() )
297 // our own XAccessible for comparing with the children of our parent
298 Reference< XAccessible > xCreator( m_pImpl->getCreator() );
300 OSL_ENSURE( xCreator.is(), "OAccessibleContextHelper::getAccessibleIndexInParent: invalid creator!" );
301 // two ideas why this could be NULL:
302 // * nobody called our late ctor (init), so we never had a creator at all -> bad
303 // * the creator is already dead. In this case, we should have been disposed, and
304 // never survived the above OContextEntryGuard.
305 // in all other situations the creator should be non-NULL
307 if ( xCreator.is() )
309 sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
310 for ( sal_Int32 nChild = 0; ( nChild < nChildCount ) && ( -1 == nRet ); ++nChild )
312 Reference< XAccessible > xChild( xParentContext->getAccessibleChild( nChild ) );
313 if ( xChild.get() == xCreator.get() )
314 nRet = nChild;
319 catch( const Exception& )
321 OSL_ENSURE( sal_False, "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" );
324 return nRet;
327 //---------------------------------------------------------------------
328 Locale SAL_CALL OAccessibleContextHelper::getLocale( ) throw (IllegalAccessibleComponentStateException, RuntimeException)
330 // simply ask the parent
331 Reference< XAccessible > xParent = getAccessibleParent();
332 Reference< XAccessibleContext > xParentContext;
333 if ( xParent.is() )
334 xParentContext = xParent->getAccessibleContext();
336 if ( !xParentContext.is() )
337 throw IllegalAccessibleComponentStateException( ::rtl::OUString(), *this );
339 return xParentContext->getLocale();
342 //---------------------------------------------------------------------
343 Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext() SAL_THROW( ( RuntimeException ) )
345 Reference< XAccessible > xParent = getAccessibleParent();
346 Reference< XAccessibleContext > xParentContext;
347 if ( xParent.is() )
348 xParentContext = xParent->getAccessibleContext();
349 return xParentContext;
352 //.........................................................................
353 } // namespace comphelper
354 //.........................................................................