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 0 : IMutex::~IMutex() {}
37 :
38 :
39 : //= OContextHelper_Impl
40 :
41 : /** implementation class for OAccessibleContextHelper. No own thread safety!
42 : */
43 0 : 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 0 : inline IMutex* getExternalLock( ) { return m_pExternalLock; }
57 0 : inline void setExternalLock( IMutex* _pLock ) { m_pExternalLock = _pLock; }
58 :
59 : inline AccessibleEventNotifier::TClientId
60 0 : getClientId() const { return m_nClientId; }
61 0 : inline void setClientId( const AccessibleEventNotifier::TClientId _nId )
62 0 : { m_nClientId = _nId; }
63 :
64 : public:
65 0 : OContextHelper_Impl()
66 : :m_pExternalLock( NULL )
67 0 : ,m_nClientId( 0 )
68 : {
69 0 : }
70 : };
71 :
72 :
73 0 : inline void OContextHelper_Impl::setCreator( const Reference< XAccessible >& _rAcc )
74 : {
75 0 : m_aCreator = _rAcc;
76 0 : }
77 :
78 :
79 : //= OAccessibleContextHelper
80 :
81 :
82 0 : OAccessibleContextHelper::OAccessibleContextHelper( IMutex* _pExternalLock )
83 0 : :OAccessibleContextHelper_Base( GetMutex() )
84 0 : ,m_pImpl( NULL )
85 : {
86 : assert(_pExternalLock);
87 0 : m_pImpl = new OContextHelper_Impl();
88 0 : m_pImpl->setExternalLock( _pExternalLock );
89 0 : }
90 :
91 :
92 0 : void OAccessibleContextHelper::forgetExternalLock()
93 : {
94 0 : m_pImpl->setExternalLock( NULL );
95 0 : }
96 :
97 :
98 0 : OAccessibleContextHelper::~OAccessibleContextHelper( )
99 : {
100 0 : forgetExternalLock();
101 : // this ensures that the lock, which may be already destroyed as part of the derivee,
102 : // is not used anymore
103 :
104 0 : ensureDisposed();
105 :
106 0 : delete m_pImpl;
107 0 : m_pImpl = NULL;
108 0 : }
109 :
110 :
111 0 : IMutex* OAccessibleContextHelper::getExternalLock( )
112 : {
113 0 : return m_pImpl->getExternalLock();
114 : }
115 :
116 :
117 0 : void SAL_CALL OAccessibleContextHelper::disposing()
118 : {
119 : // rhbz#1001768: de facto this class is locked by SolarMutex;
120 : // do not lock m_Mutex because it may cause deadlock
121 0 : OMutexGuard aGuard( getExternalLock() );
122 :
123 0 : if ( m_pImpl->getClientId( ) )
124 : {
125 0 : AccessibleEventNotifier::revokeClientNotifyDisposing( m_pImpl->getClientId( ), *this );
126 0 : m_pImpl->setClientId( 0 );
127 0 : }
128 0 : }
129 :
130 :
131 0 : void SAL_CALL OAccessibleContextHelper::addAccessibleEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException, std::exception)
132 : {
133 0 : OMutexGuard aGuard( getExternalLock() );
134 : // don't use the OContextEntryGuard - it will throw an exception if we're not alive
135 : // anymore, while the most recent specification for XComponent states that we should
136 : // silently ignore the call in such a situation
137 0 : if ( !isAlive() )
138 : {
139 0 : if ( _rxListener.is() )
140 0 : _rxListener->disposing( EventObject( *this ) );
141 0 : return;
142 : }
143 :
144 0 : if ( _rxListener.is() )
145 : {
146 0 : if ( !m_pImpl->getClientId( ) )
147 0 : m_pImpl->setClientId( AccessibleEventNotifier::registerClient( ) );
148 :
149 0 : AccessibleEventNotifier::addEventListener( m_pImpl->getClientId( ), _rxListener );
150 0 : }
151 : }
152 :
153 :
154 0 : void SAL_CALL OAccessibleContextHelper::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException, std::exception)
155 : {
156 0 : OMutexGuard aGuard( getExternalLock() );
157 : // don't use the OContextEntryGuard - it will throw an exception if we're not alive
158 : // anymore, while the most recent specification for XComponent states that we should
159 : // silently ignore the call in such a situation
160 0 : if ( !isAlive() )
161 0 : return;
162 :
163 0 : if ( _rxListener.is() )
164 : {
165 0 : sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( m_pImpl->getClientId( ), _rxListener );
166 0 : if ( !nListenerCount )
167 : {
168 : // no listeners anymore
169 : // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
170 : // and at least to us not firing any events anymore, in case somebody calls
171 : // NotifyAccessibleEvent, again
172 0 : AccessibleEventNotifier::revokeClient( m_pImpl->getClientId( ) );
173 0 : m_pImpl->setClientId( 0 );
174 : }
175 0 : }
176 : }
177 :
178 :
179 0 : void OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId,
180 : const Any& _rOldValue, const Any& _rNewValue )
181 : {
182 0 : if ( !m_pImpl->getClientId( ) )
183 : // if we don't have a client id for the notifier, then we don't have listeners, then
184 : // we don't need to notify anything
185 0 : return;
186 :
187 : // build an event object
188 0 : AccessibleEventObject aEvent;
189 0 : aEvent.Source = *this;
190 0 : aEvent.EventId = _nEventId;
191 0 : aEvent.OldValue = _rOldValue;
192 0 : aEvent.NewValue = _rNewValue;
193 :
194 : // let the notifier handle this event
195 0 : AccessibleEventNotifier::addEvent( m_pImpl->getClientId( ), aEvent );
196 : }
197 :
198 :
199 0 : bool OAccessibleContextHelper::isAlive() const
200 : {
201 0 : return !GetBroadcastHelper().bDisposed && !GetBroadcastHelper().bInDispose;
202 : }
203 :
204 :
205 0 : void OAccessibleContextHelper::ensureAlive() const SAL_THROW( ( DisposedException ) )
206 : {
207 0 : if( !isAlive() )
208 0 : throw DisposedException();
209 0 : }
210 :
211 :
212 0 : void OAccessibleContextHelper::ensureDisposed( )
213 : {
214 0 : if ( !GetBroadcastHelper().bDisposed )
215 : {
216 : OSL_ENSURE( 0 == m_refCount, "OAccessibleContextHelper::ensureDisposed: this method _has_ to be called from without your dtor only!" );
217 0 : acquire();
218 0 : dispose();
219 : }
220 0 : }
221 :
222 :
223 0 : void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible )
224 : {
225 0 : m_pImpl->setCreator( _rxAccessible );
226 0 : }
227 :
228 :
229 0 : Reference< XAccessible > OAccessibleContextHelper::getAccessibleCreator( ) const
230 : {
231 0 : return m_pImpl->getCreator();
232 : }
233 :
234 :
235 0 : sal_Int32 SAL_CALL OAccessibleContextHelper::getAccessibleIndexInParent( ) throw (RuntimeException, std::exception)
236 : {
237 0 : OExternalLockGuard aGuard( this );
238 :
239 : // -1 for child not found/no parent (according to specification)
240 0 : sal_Int32 nRet = -1;
241 :
242 : try
243 : {
244 :
245 0 : Reference< XAccessibleContext > xParentContext( implGetParentContext() );
246 :
247 : // iterate over parent's children and search for this object
248 0 : if ( xParentContext.is() )
249 : {
250 : // our own XAccessible for comparing with the children of our parent
251 0 : Reference< XAccessible > xCreator( m_pImpl->getCreator() );
252 :
253 : OSL_ENSURE( xCreator.is(), "OAccessibleContextHelper::getAccessibleIndexInParent: invalid creator!" );
254 : // two ideas why this could be NULL:
255 : // * nobody called our late ctor (init), so we never had a creator at all -> bad
256 : // * the creator is already dead. In this case, we should have been disposed, and
257 : // never survived the above OContextEntryGuard.
258 : // in all other situations the creator should be non-NULL
259 :
260 0 : if ( xCreator.is() )
261 : {
262 0 : sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
263 0 : for ( sal_Int32 nChild = 0; ( nChild < nChildCount ) && ( -1 == nRet ); ++nChild )
264 : {
265 0 : Reference< XAccessible > xChild( xParentContext->getAccessibleChild( nChild ) );
266 0 : if ( xChild.get() == xCreator.get() )
267 0 : nRet = nChild;
268 0 : }
269 0 : }
270 0 : }
271 : }
272 0 : catch( const Exception& )
273 : {
274 : OSL_FAIL( "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" );
275 : }
276 :
277 0 : return nRet;
278 : }
279 :
280 :
281 0 : Locale SAL_CALL OAccessibleContextHelper::getLocale( ) throw (IllegalAccessibleComponentStateException, RuntimeException, std::exception)
282 : {
283 : // simply ask the parent
284 0 : Reference< XAccessible > xParent = getAccessibleParent();
285 0 : Reference< XAccessibleContext > xParentContext;
286 0 : if ( xParent.is() )
287 0 : xParentContext = xParent->getAccessibleContext();
288 :
289 0 : if ( !xParentContext.is() )
290 0 : throw IllegalAccessibleComponentStateException( OUString(), *this );
291 :
292 0 : return xParentContext->getLocale();
293 : }
294 :
295 :
296 0 : Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext() SAL_THROW( ( RuntimeException ) )
297 : {
298 0 : Reference< XAccessible > xParent = getAccessibleParent();
299 0 : Reference< XAccessibleContext > xParentContext;
300 0 : if ( xParent.is() )
301 0 : xParentContext = xParent->getAccessibleContext();
302 0 : return xParentContext;
303 : }
304 :
305 :
306 : } // namespace comphelper
307 :
308 :
309 :
310 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|