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 //.........................................................................
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
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
;
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
; }
76 OContextHelper_Impl( OAccessibleContextHelper
* _pAntiImpl
)
77 :m_pAntiImpl( _pAntiImpl
)
78 ,m_pExternalLock( NULL
)
79 ,m_pEventListeners( NULL
)
85 //---------------------------------------------------------------------
86 inline void OContextHelper_Impl::setCreator( const Reference
< XAccessible
>& _rAcc
)
91 //=====================================================================
92 //= OAccessibleContextHelper
93 //=====================================================================
94 //---------------------------------------------------------------------
95 OAccessibleContextHelper::OAccessibleContextHelper( )
96 :OAccessibleContextHelper_Base( GetMutex() )
99 m_pImpl
= new OContextHelper_Impl( this );
102 //---------------------------------------------------------------------
103 OAccessibleContextHelper::OAccessibleContextHelper( IMutex
* _pExternalLock
)
104 :OAccessibleContextHelper_Base( GetMutex() )
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
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
157 if ( _rxListener
.is() )
158 _rxListener
->disposing( EventObject( *this ) );
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
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
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
) )
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!" );
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)
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
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() )
319 catch( const Exception
& )
321 OSL_ENSURE( sal_False
, "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" );
327 //---------------------------------------------------------------------
328 Locale SAL_CALL
OAccessibleContextHelper::getLocale( ) throw (IllegalAccessibleComponentStateException
, RuntimeException
)
330 // simply ask the parent
331 Reference
< XAccessible
> xParent
= getAccessibleParent();
332 Reference
< XAccessibleContext
> xParentContext
;
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
;
348 xParentContext
= xParent
->getAccessibleContext();
349 return xParentContext
;
352 //.........................................................................
353 } // namespace comphelper
354 //.........................................................................