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( )
83 0 : :OAccessibleContextHelper_Base( GetMutex() )
84 0 : ,m_pImpl( NULL )
85 : {
86 0 : m_pImpl = new OContextHelper_Impl();
87 0 : }
88 :
89 : //---------------------------------------------------------------------
90 0 : OAccessibleContextHelper::OAccessibleContextHelper( IMutex* _pExternalLock )
91 0 : :OAccessibleContextHelper_Base( GetMutex() )
92 0 : ,m_pImpl( NULL )
93 : {
94 0 : m_pImpl = new OContextHelper_Impl();
95 0 : m_pImpl->setExternalLock( _pExternalLock );
96 0 : }
97 :
98 : //---------------------------------------------------------------------
99 0 : void OAccessibleContextHelper::forgetExternalLock()
100 : {
101 0 : m_pImpl->setExternalLock( NULL );
102 0 : }
103 :
104 : //---------------------------------------------------------------------
105 0 : OAccessibleContextHelper::~OAccessibleContextHelper( )
106 : {
107 0 : forgetExternalLock();
108 : // this ensures that the lock, which may be already destroyed as part of the derivee,
109 : // is not used anymore
110 :
111 0 : ensureDisposed();
112 :
113 0 : delete m_pImpl;
114 0 : m_pImpl = NULL;
115 0 : }
116 :
117 : //---------------------------------------------------------------------
118 0 : IMutex* OAccessibleContextHelper::getExternalLock( )
119 : {
120 0 : return m_pImpl->getExternalLock();
121 : }
122 :
123 : //---------------------------------------------------------------------
124 0 : void SAL_CALL OAccessibleContextHelper::disposing()
125 : {
126 0 : ::osl::ClearableMutexGuard aGuard( GetMutex() );
127 :
128 0 : if ( m_pImpl->getClientId( ) )
129 : {
130 0 : AccessibleEventNotifier::revokeClientNotifyDisposing( m_pImpl->getClientId( ), *this );
131 0 : m_pImpl->setClientId( 0 );
132 0 : }
133 0 : }
134 :
135 : //---------------------------------------------------------------------
136 0 : void SAL_CALL OAccessibleContextHelper::addAccessibleEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
137 : {
138 0 : 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 0 : if ( !isAlive() )
143 : {
144 0 : if ( _rxListener.is() )
145 0 : _rxListener->disposing( EventObject( *this ) );
146 0 : return;
147 : }
148 :
149 0 : if ( _rxListener.is() )
150 : {
151 0 : if ( !m_pImpl->getClientId( ) )
152 0 : m_pImpl->setClientId( AccessibleEventNotifier::registerClient( ) );
153 :
154 0 : AccessibleEventNotifier::addEventListener( m_pImpl->getClientId( ), _rxListener );
155 0 : }
156 : }
157 :
158 : //---------------------------------------------------------------------
159 0 : void SAL_CALL OAccessibleContextHelper::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException)
160 : {
161 0 : 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 0 : if ( !isAlive() )
166 0 : return;
167 :
168 0 : if ( _rxListener.is() )
169 : {
170 0 : sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( m_pImpl->getClientId( ), _rxListener );
171 0 : 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 0 : AccessibleEventNotifier::revokeClient( m_pImpl->getClientId( ) );
178 0 : m_pImpl->setClientId( 0 );
179 : }
180 0 : }
181 : }
182 :
183 : //---------------------------------------------------------------------
184 0 : void SAL_CALL OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId,
185 : const Any& _rOldValue, const Any& _rNewValue )
186 : {
187 0 : 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 0 : return;
191 :
192 : // build an event object
193 0 : AccessibleEventObject aEvent;
194 0 : aEvent.Source = *this;
195 0 : aEvent.EventId = _nEventId;
196 0 : aEvent.OldValue = _rOldValue;
197 0 : aEvent.NewValue = _rNewValue;
198 :
199 : // let the notifier handle this event
200 0 : AccessibleEventNotifier::addEvent( m_pImpl->getClientId( ), aEvent );
201 : }
202 :
203 : //---------------------------------------------------------------------
204 0 : sal_Bool OAccessibleContextHelper::isAlive() const
205 : {
206 0 : return !GetBroadcastHelper().bDisposed && !GetBroadcastHelper().bInDispose;
207 : }
208 :
209 : //---------------------------------------------------------------------
210 0 : void OAccessibleContextHelper::ensureAlive() const SAL_THROW( ( DisposedException ) )
211 : {
212 0 : if( !isAlive() )
213 0 : throw DisposedException();
214 0 : }
215 :
216 : //---------------------------------------------------------------------
217 0 : void OAccessibleContextHelper::ensureDisposed( )
218 : {
219 0 : 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 0 : }
226 :
227 : //---------------------------------------------------------------------
228 0 : void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible )
229 : {
230 0 : m_pImpl->setCreator( _rxAccessible );
231 0 : }
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 0 : Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext() SAL_THROW( ( RuntimeException ) )
302 : {
303 0 : Reference< XAccessible > xParent = getAccessibleParent();
304 0 : Reference< XAccessibleContext > xParentContext;
305 0 : if ( xParent.is() )
306 0 : xParentContext = xParent->getAccessibleContext();
307 0 : return xParentContext;
308 : }
309 :
310 : //.........................................................................
311 : } // namespace comphelper
312 : //.........................................................................
313 :
314 :
315 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|