Branch data 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 [ - + ]: 5248 : IMutex::~IMutex() {}
37 : :
38 : : //=====================================================================
39 : : //= OContextHelper_Impl
40 : : //=====================================================================
41 : : /** implementation class for OAccessibleContextHelper. No own thread safety!
42 : : */
43 : 5308 : 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 : 90528 : inline IMutex* getExternalLock( ) { return m_pExternalLock; }
57 : 15920 : inline void setExternalLock( IMutex* _pLock ) { m_pExternalLock = _pLock; }
58 : :
59 : : inline AccessibleEventNotifier::TClientId
60 : 8176 : getClientId() const { return m_nClientId; }
61 : 116 : inline void setClientId( const AccessibleEventNotifier::TClientId _nId )
62 : 116 : { m_nClientId = _nId; }
63 : :
64 : : public:
65 : 5364 : OContextHelper_Impl()
66 : : :m_pExternalLock( NULL )
67 : 5364 : ,m_nClientId( 0 )
68 : : {
69 : 5364 : }
70 : : };
71 : :
72 : : //---------------------------------------------------------------------
73 : 535 : inline void OContextHelper_Impl::setCreator( const Reference< XAccessible >& _rAcc )
74 : : {
75 : 535 : m_aCreator = _rAcc;
76 : 535 : }
77 : :
78 : : //=====================================================================
79 : : //= OAccessibleContextHelper
80 : : //=====================================================================
81 : : //---------------------------------------------------------------------
82 : 60 : OAccessibleContextHelper::OAccessibleContextHelper( )
83 : 60 : :OAccessibleContextHelper_Base( GetMutex() )
84 : 120 : ,m_pImpl( NULL )
85 : : {
86 [ + - ][ + - ]: 60 : m_pImpl = new OContextHelper_Impl();
87 : 60 : }
88 : :
89 : : //---------------------------------------------------------------------
90 : 5304 : OAccessibleContextHelper::OAccessibleContextHelper( IMutex* _pExternalLock )
91 : 5304 : :OAccessibleContextHelper_Base( GetMutex() )
92 : 10608 : ,m_pImpl( NULL )
93 : : {
94 [ + - ][ + - ]: 5304 : m_pImpl = new OContextHelper_Impl();
95 : 5304 : m_pImpl->setExternalLock( _pExternalLock );
96 : 5304 : }
97 : :
98 : : //---------------------------------------------------------------------
99 : 10616 : void OAccessibleContextHelper::forgetExternalLock()
100 : : {
101 : 10616 : m_pImpl->setExternalLock( NULL );
102 : 10616 : }
103 : :
104 : : //---------------------------------------------------------------------
105 [ + - ]: 5308 : OAccessibleContextHelper::~OAccessibleContextHelper( )
106 : : {
107 [ + - ]: 5308 : forgetExternalLock();
108 : : // this ensures that the lock, which may be already destroyed as part of the derivee,
109 : : // is not used anymore
110 : :
111 [ + - ]: 5308 : ensureDisposed();
112 : :
113 [ + - ][ + - ]: 5308 : delete m_pImpl;
114 : 5308 : m_pImpl = NULL;
115 [ - + ]: 5308 : }
116 : :
117 : : //---------------------------------------------------------------------
118 : 90528 : IMutex* OAccessibleContextHelper::getExternalLock( )
119 : : {
120 : 90528 : return m_pImpl->getExternalLock();
121 : : }
122 : :
123 : : //---------------------------------------------------------------------
124 : 5418 : void SAL_CALL OAccessibleContextHelper::disposing()
125 : : {
126 [ + - ]: 5418 : ::osl::ClearableMutexGuard aGuard( GetMutex() );
127 : :
128 [ + + ]: 5418 : if ( m_pImpl->getClientId( ) )
129 : : {
130 [ + - ][ + - ]: 30 : AccessibleEventNotifier::revokeClientNotifyDisposing( m_pImpl->getClientId( ), *this );
131 : 30 : m_pImpl->setClientId( 0 );
132 [ + - ]: 5418 : }
133 : 5418 : }
134 : :
135 : : //---------------------------------------------------------------------
136 : 56 : void SAL_CALL OAccessibleContextHelper::addEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
137 : : {
138 [ + - ][ + - ]: 56 : 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 [ + - ][ - + ]: 56 : if ( !isAlive() )
143 : : {
144 [ # # ]: 0 : if ( _rxListener.is() )
145 [ # # ][ # # ]: 0 : _rxListener->disposing( EventObject( *this ) );
[ # # ][ # # ]
[ # # ]
146 : 56 : return;
147 : : }
148 : :
149 [ + - ]: 56 : if ( _rxListener.is() )
150 : : {
151 [ + - ]: 56 : if ( !m_pImpl->getClientId( ) )
152 [ + - ]: 56 : m_pImpl->setClientId( AccessibleEventNotifier::registerClient( ) );
153 : :
154 [ + - ]: 56 : AccessibleEventNotifier::addEventListener( m_pImpl->getClientId( ), _rxListener );
155 [ + - ][ + - ]: 56 : }
156 : : }
157 : :
158 : : //---------------------------------------------------------------------
159 : 61 : void SAL_CALL OAccessibleContextHelper::removeEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
160 : : {
161 [ + - ][ + - ]: 61 : 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 [ + - ][ + + ]: 61 : if ( !isAlive() )
166 : 61 : return;
167 : :
168 [ + - ]: 31 : if ( _rxListener.is() )
169 : : {
170 [ + - ]: 31 : sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( m_pImpl->getClientId( ), _rxListener );
171 [ + + ]: 31 : 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 [ + - ]: 30 : AccessibleEventNotifier::revokeClient( m_pImpl->getClientId( ) );
178 : 31 : m_pImpl->setClientId( 0 );
179 : : }
180 [ + - ][ + + ]: 61 : }
181 : : }
182 : :
183 : : //---------------------------------------------------------------------
184 : 2460 : void SAL_CALL OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId,
185 : : const Any& _rOldValue, const Any& _rNewValue )
186 : : {
187 [ + + ]: 2460 : 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 : 2460 : return;
191 : :
192 : : // build an event object
193 [ + - ]: 95 : AccessibleEventObject aEvent;
194 [ + - ][ + - ]: 95 : aEvent.Source = *this;
195 : 95 : aEvent.EventId = _nEventId;
196 : 95 : aEvent.OldValue = _rOldValue;
197 : 95 : aEvent.NewValue = _rNewValue;
198 : :
199 : : // let the notifier handle this event
200 [ + - ][ + - ]: 2460 : AccessibleEventNotifier::addEvent( m_pImpl->getClientId( ), aEvent );
201 : : }
202 : :
203 : : //---------------------------------------------------------------------
204 : 86916 : sal_Bool OAccessibleContextHelper::isAlive() const
205 : : {
206 [ + + ][ + + ]: 86916 : return !GetBroadcastHelper().bDisposed && !GetBroadcastHelper().bInDispose;
207 : : }
208 : :
209 : : //---------------------------------------------------------------------
210 : 86767 : void OAccessibleContextHelper::ensureAlive() const SAL_THROW( ( DisposedException ) )
211 : : {
212 [ - + ]: 86767 : if( !isAlive() )
213 [ # # ]: 0 : throw DisposedException();
214 : 86767 : }
215 : :
216 : : //---------------------------------------------------------------------
217 : 5805 : void OAccessibleContextHelper::ensureDisposed( )
218 : : {
219 [ - + ]: 5805 : 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 : 5805 : }
226 : :
227 : : //---------------------------------------------------------------------
228 : 535 : void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible )
229 : : {
230 : 535 : m_pImpl->setCreator( _rxAccessible );
231 : 535 : }
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( ::rtl::OUString(), *this );
296 : :
297 [ # # ][ # # ]: 0 : return xParentContext->getLocale();
298 : : }
299 : :
300 : : //---------------------------------------------------------------------
301 : 1350 : Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext() SAL_THROW( ( RuntimeException ) )
302 : : {
303 [ + - ]: 1350 : Reference< XAccessible > xParent = getAccessibleParent();
304 : 1350 : Reference< XAccessibleContext > xParentContext;
305 [ + - ]: 1350 : if ( xParent.is() )
306 [ + - ][ + - ]: 1350 : xParentContext = xParent->getAccessibleContext();
[ + - ]
307 : 1350 : return xParentContext;
308 : : }
309 : :
310 : : //.........................................................................
311 : : } // namespace comphelper
312 : : //.........................................................................
313 : :
314 : :
315 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|