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: accessiblecontexthelper.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/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 //.........................................................................
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
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
;
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
; }
79 OContextHelper_Impl( OAccessibleContextHelper
* _pAntiImpl
)
80 :m_pAntiImpl( _pAntiImpl
)
81 ,m_pExternalLock( NULL
)
82 ,m_pEventListeners( NULL
)
88 //---------------------------------------------------------------------
89 inline void OContextHelper_Impl::setCreator( const Reference
< XAccessible
>& _rAcc
)
94 //=====================================================================
95 //= OAccessibleContextHelper
96 //=====================================================================
97 //---------------------------------------------------------------------
98 OAccessibleContextHelper::OAccessibleContextHelper( )
99 :OAccessibleContextHelper_Base( GetMutex() )
102 m_pImpl
= new OContextHelper_Impl( this );
105 //---------------------------------------------------------------------
106 OAccessibleContextHelper::OAccessibleContextHelper( IMutex
* _pExternalLock
)
107 :OAccessibleContextHelper_Base( GetMutex() )
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
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
160 if ( _rxListener
.is() )
161 _rxListener
->disposing( EventObject( *this ) );
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
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
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
) )
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!" );
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)
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
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() )
322 catch( const Exception
& )
324 OSL_ENSURE( sal_False
, "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" );
330 //---------------------------------------------------------------------
331 Locale SAL_CALL
OAccessibleContextHelper::getLocale( ) throw (IllegalAccessibleComponentStateException
, RuntimeException
)
333 // simply ask the parent
334 Reference
< XAccessible
> xParent
= getAccessibleParent();
335 Reference
< XAccessibleContext
> xParentContext
;
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
;
351 xParentContext
= xParent
->getAccessibleContext();
352 return xParentContext
;
355 //.........................................................................
356 } // namespace comphelper
357 //.........................................................................