Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <comphelper/accessiblecontexthelper.hxx>
21 : #include <osl/diagnose.h>
22 : #include <cppuhelper/weakref.hxx>
23 : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
24 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
25 : #include <comphelper/accessibleeventnotifier.hxx>
26 :
27 : //.........................................................................
28 : namespace comphelper
29 : {
30 : //.........................................................................
31 :
32 : using namespace ::com::sun::star::uno;
33 : using namespace ::com::sun::star::lang;
34 : using namespace ::com::sun::star::accessibility;
35 :
36 2662 : IMutex::~IMutex() {}
37 :
38 : //=====================================================================
39 : //= OContextHelper_Impl
40 : //=====================================================================
41 : /** implementation class for OAccessibleContextHelper. No own thread safety!
42 : */
43 2691 : class OContextHelper_Impl
44 : {
45 : private:
46 : IMutex* m_pExternalLock; // the optional additional external lock
47 :
48 : WeakReference< XAccessible > m_aCreator; // the XAccessible which created our XAccessibleContext
49 :
50 : AccessibleEventNotifier::TClientId m_nClientId;
51 :
52 : public:
53 0 : inline Reference< XAccessible > getCreator( ) const { return m_aCreator; }
54 : inline void setCreator( const Reference< XAccessible >& _rAcc );
55 :
56 45704 : inline IMutex* getExternalLock( ) { return m_pExternalLock; }
57 8078 : inline void setExternalLock( IMutex* _pLock ) { m_pExternalLock = _pLock; }
58 :
59 : inline AccessibleEventNotifier::TClientId
60 4082 : getClientId() const { return m_nClientId; }
61 58 : inline void setClientId( const AccessibleEventNotifier::TClientId _nId )
62 58 : { m_nClientId = _nId; }
63 :
64 : public:
65 2725 : OContextHelper_Impl()
66 : :m_pExternalLock( NULL )
67 2725 : ,m_nClientId( 0 )
68 : {
69 2725 : }
70 : };
71 :
72 : //---------------------------------------------------------------------
73 283 : inline void OContextHelper_Impl::setCreator( const Reference< XAccessible >& _rAcc )
74 : {
75 283 : m_aCreator = _rAcc;
76 283 : }
77 :
78 : //=====================================================================
79 : //= OAccessibleContextHelper
80 : //=====================================================================
81 : //---------------------------------------------------------------------
82 29 : OAccessibleContextHelper::OAccessibleContextHelper( )
83 29 : :OAccessibleContextHelper_Base( GetMutex() )
84 58 : ,m_pImpl( NULL )
85 : {
86 29 : m_pImpl = new OContextHelper_Impl();
87 29 : }
88 :
89 : //---------------------------------------------------------------------
90 2696 : OAccessibleContextHelper::OAccessibleContextHelper( IMutex* _pExternalLock )
91 2696 : :OAccessibleContextHelper_Base( GetMutex() )
92 5392 : ,m_pImpl( NULL )
93 : {
94 2696 : m_pImpl = new OContextHelper_Impl();
95 2696 : m_pImpl->setExternalLock( _pExternalLock );
96 2696 : }
97 :
98 : //---------------------------------------------------------------------
99 5382 : void OAccessibleContextHelper::forgetExternalLock()
100 : {
101 5382 : m_pImpl->setExternalLock( NULL );
102 5382 : }
103 :
104 : //---------------------------------------------------------------------
105 5382 : OAccessibleContextHelper::~OAccessibleContextHelper( )
106 : {
107 2691 : forgetExternalLock();
108 : // this ensures that the lock, which may be already destroyed as part of the derivee,
109 : // is not used anymore
110 :
111 2691 : ensureDisposed();
112 :
113 2691 : delete m_pImpl;
114 2691 : m_pImpl = NULL;
115 2691 : }
116 :
117 : //---------------------------------------------------------------------
118 45704 : IMutex* OAccessibleContextHelper::getExternalLock( )
119 : {
120 45704 : return m_pImpl->getExternalLock();
121 : }
122 :
123 : //---------------------------------------------------------------------
124 2749 : void SAL_CALL OAccessibleContextHelper::disposing()
125 : {
126 2749 : ::osl::ClearableMutexGuard aGuard( GetMutex() );
127 :
128 2749 : if ( m_pImpl->getClientId( ) )
129 : {
130 15 : AccessibleEventNotifier::revokeClientNotifyDisposing( m_pImpl->getClientId( ), *this );
131 15 : m_pImpl->setClientId( 0 );
132 2749 : }
133 2749 : }
134 :
135 : //---------------------------------------------------------------------
136 28 : void SAL_CALL OAccessibleContextHelper::addAccessibleEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
137 : {
138 28 : OMutexGuard aGuard( getExternalLock() );
139 : // don't use the OContextEntryGuard - it will throw an exception if we're not alive
140 : // anymore, while the most recent specification for XComponent states that we should
141 : // silently ignore the call in such a situation
142 28 : if ( !isAlive() )
143 : {
144 0 : if ( _rxListener.is() )
145 0 : _rxListener->disposing( EventObject( *this ) );
146 28 : return;
147 : }
148 :
149 28 : if ( _rxListener.is() )
150 : {
151 28 : if ( !m_pImpl->getClientId( ) )
152 28 : m_pImpl->setClientId( AccessibleEventNotifier::registerClient( ) );
153 :
154 28 : AccessibleEventNotifier::addEventListener( m_pImpl->getClientId( ), _rxListener );
155 28 : }
156 : }
157 :
158 : //---------------------------------------------------------------------
159 30 : void SAL_CALL OAccessibleContextHelper::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
160 : {
161 30 : OMutexGuard aGuard( getExternalLock() );
162 : // don't use the OContextEntryGuard - it will throw an exception if we're not alive
163 : // anymore, while the most recent specification for XComponent states that we should
164 : // silently ignore the call in such a situation
165 30 : if ( !isAlive() )
166 45 : return;
167 :
168 15 : if ( _rxListener.is() )
169 : {
170 15 : sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( m_pImpl->getClientId( ), _rxListener );
171 15 : if ( !nListenerCount )
172 : {
173 : // no listeners anymore
174 : // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
175 : // and at least to us not firing any events anymore, in case somebody calls
176 : // NotifyAccessibleEvent, again
177 15 : AccessibleEventNotifier::revokeClient( m_pImpl->getClientId( ) );
178 15 : m_pImpl->setClientId( 0 );
179 : }
180 15 : }
181 : }
182 :
183 : //---------------------------------------------------------------------
184 1191 : void SAL_CALL OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId,
185 : const Any& _rOldValue, const Any& _rNewValue )
186 : {
187 1191 : if ( !m_pImpl->getClientId( ) )
188 : // if we don't have a client id for the notifier, then we don't have listeners, then
189 : // we don't need to notify anything
190 2341 : return;
191 :
192 : // build an event object
193 41 : AccessibleEventObject aEvent;
194 41 : aEvent.Source = *this;
195 41 : aEvent.EventId = _nEventId;
196 41 : aEvent.OldValue = _rOldValue;
197 41 : aEvent.NewValue = _rNewValue;
198 :
199 : // let the notifier handle this event
200 41 : AccessibleEventNotifier::addEvent( m_pImpl->getClientId( ), aEvent );
201 : }
202 :
203 : //---------------------------------------------------------------------
204 43722 : sal_Bool OAccessibleContextHelper::isAlive() const
205 : {
206 43722 : return !GetBroadcastHelper().bDisposed && !GetBroadcastHelper().bInDispose;
207 : }
208 :
209 : //---------------------------------------------------------------------
210 43654 : void OAccessibleContextHelper::ensureAlive() const SAL_THROW( ( DisposedException ) )
211 : {
212 43654 : if( !isAlive() )
213 0 : throw DisposedException();
214 43654 : }
215 :
216 : //---------------------------------------------------------------------
217 2949 : void OAccessibleContextHelper::ensureDisposed( )
218 : {
219 2949 : if ( !GetBroadcastHelper().bDisposed )
220 : {
221 : OSL_ENSURE( 0 == m_refCount, "OAccessibleContextHelper::ensureDisposed: this method _has_ to be called from without your dtor only!" );
222 0 : acquire();
223 0 : dispose();
224 : }
225 2949 : }
226 :
227 : //---------------------------------------------------------------------
228 283 : void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible )
229 : {
230 283 : m_pImpl->setCreator( _rxAccessible );
231 283 : }
232 :
233 : //---------------------------------------------------------------------
234 0 : Reference< XAccessible > OAccessibleContextHelper::getAccessibleCreator( ) const
235 : {
236 0 : return m_pImpl->getCreator();
237 : }
238 :
239 : //---------------------------------------------------------------------
240 0 : sal_Int32 SAL_CALL OAccessibleContextHelper::getAccessibleIndexInParent( ) throw (RuntimeException)
241 : {
242 0 : OExternalLockGuard aGuard( this );
243 :
244 : // -1 for child not found/no parent (according to specification)
245 0 : sal_Int32 nRet = -1;
246 :
247 : try
248 : {
249 :
250 0 : Reference< XAccessibleContext > xParentContext( implGetParentContext() );
251 :
252 : // iterate over parent's children and search for this object
253 0 : if ( xParentContext.is() )
254 : {
255 : // our own XAccessible for comparing with the children of our parent
256 0 : Reference< XAccessible > xCreator( m_pImpl->getCreator() );
257 :
258 : OSL_ENSURE( xCreator.is(), "OAccessibleContextHelper::getAccessibleIndexInParent: invalid creator!" );
259 : // two ideas why this could be NULL:
260 : // * nobody called our late ctor (init), so we never had a creator at all -> bad
261 : // * the creator is already dead. In this case, we should have been disposed, and
262 : // never survived the above OContextEntryGuard.
263 : // in all other situations the creator should be non-NULL
264 :
265 0 : if ( xCreator.is() )
266 : {
267 0 : sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
268 0 : for ( sal_Int32 nChild = 0; ( nChild < nChildCount ) && ( -1 == nRet ); ++nChild )
269 : {
270 0 : Reference< XAccessible > xChild( xParentContext->getAccessibleChild( nChild ) );
271 0 : if ( xChild.get() == xCreator.get() )
272 0 : nRet = nChild;
273 0 : }
274 0 : }
275 0 : }
276 : }
277 0 : catch( const Exception& )
278 : {
279 : OSL_FAIL( "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" );
280 : }
281 :
282 0 : return nRet;
283 : }
284 :
285 : //---------------------------------------------------------------------
286 0 : Locale SAL_CALL OAccessibleContextHelper::getLocale( ) throw (IllegalAccessibleComponentStateException, RuntimeException)
287 : {
288 : // simply ask the parent
289 0 : Reference< XAccessible > xParent = getAccessibleParent();
290 0 : Reference< XAccessibleContext > xParentContext;
291 0 : if ( xParent.is() )
292 0 : xParentContext = xParent->getAccessibleContext();
293 :
294 0 : if ( !xParentContext.is() )
295 0 : throw IllegalAccessibleComponentStateException( OUString(), *this );
296 :
297 0 : return xParentContext->getLocale();
298 : }
299 :
300 : //---------------------------------------------------------------------
301 675 : Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext() SAL_THROW( ( RuntimeException ) )
302 : {
303 675 : Reference< XAccessible > xParent = getAccessibleParent();
304 675 : Reference< XAccessibleContext > xParentContext;
305 675 : if ( xParent.is() )
306 675 : xParentContext = xParent->getAccessibleContext();
307 675 : return xParentContext;
308 : }
309 :
310 : //.........................................................................
311 : } // namespace comphelper
312 : //.........................................................................
313 :
314 :
315 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|