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