LibreOffice Module comphelper (master)  1
accessiblecontexthelper.cxx
Go to the documentation of this file.
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 
21 #include <osl/diagnose.h>
22 #include <cppuhelper/weakref.hxx>
23 #include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
26 
27 
28 namespace comphelper
29 {
30  using namespace ::com::sun::star::uno;
31  using namespace ::com::sun::star::lang;
32  using namespace ::com::sun::star::accessibility;
33 
37  {
38  private:
39  WeakReference< XAccessible > m_aCreator; // the XAccessible which created our XAccessibleContext
40 
42 
43  public:
44  Reference< XAccessible > getCreator( ) const { return m_aCreator; }
45  inline void setCreator( const Reference< XAccessible >& _rAcc );
46 
48  getClientId() const { return m_nClientId; }
50  { m_nClientId = _nId; }
51 
52  public:
54  :m_nClientId( 0 )
55  {
56  }
57  };
58 
59 
60  inline void OContextHelper_Impl::setCreator( const Reference< XAccessible >& _rAcc )
61  {
62  m_aCreator = _rAcc;
63  }
64 
66  :OAccessibleContextHelper_Base( GetMutex() )
68  {
69  }
70 
71 
73  {
74  // this ensures that the lock, which may be already destroyed as part of the derivee,
75  // is not used anymore
76 
78  }
79 
80 
82  {
83  // rhbz#1001768: de facto this class is locked by SolarMutex;
84  // do not lock m_Mutex because it may cause deadlock
85  osl::Guard<SolarMutex> aGuard(SolarMutex::get());
86 
87  if ( m_pImpl->getClientId( ) )
88  {
90  m_pImpl->setClientId( 0 );
91  }
92  }
93 
94 
95  void SAL_CALL OAccessibleContextHelper::addAccessibleEventListener( const Reference< XAccessibleEventListener >& _rxListener )
96  {
97  osl::Guard<SolarMutex> aGuard(SolarMutex::get());
98  // don't use the OContextEntryGuard - it will throw an exception if we're not alive
99  // anymore, while the most recent specification for XComponent states that we should
100  // silently ignore the call in such a situation
101  if ( !isAlive() )
102  {
103  if ( _rxListener.is() )
104  _rxListener->disposing( EventObject( *this ) );
105  return;
106  }
107 
108  if ( _rxListener.is() )
109  {
110  if ( !m_pImpl->getClientId( ) )
112 
113  AccessibleEventNotifier::addEventListener( m_pImpl->getClientId( ), _rxListener );
114  }
115  }
116 
117 
118  void SAL_CALL OAccessibleContextHelper::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& _rxListener )
119  {
120  osl::Guard<SolarMutex> aGuard(SolarMutex::get());
121  // don't use the OContextEntryGuard - it will throw an exception if we're not alive
122  // anymore, while the most recent specification for XComponent states that we should
123  // silently ignore the call in such a situation
124  if ( !isAlive() )
125  return;
126 
127  if ( !(_rxListener.is() && m_pImpl->getClientId()) )
128  return;
129 
130  sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( m_pImpl->getClientId( ), _rxListener );
131  if ( !nListenerCount )
132  {
133  // no listeners anymore
134  // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
135  // and at least to us not firing any events anymore, in case somebody calls
136  // NotifyAccessibleEvent, again
138  m_pImpl->setClientId( 0 );
139  }
140  }
141 
142 
143  void OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId,
144  const Any& _rOldValue, const Any& _rNewValue )
145  {
146  if ( !m_pImpl->getClientId( ) )
147  // if we don't have a client id for the notifier, then we don't have listeners, then
148  // we don't need to notify anything
149  return;
150 
151  // build an event object
152  AccessibleEventObject aEvent;
153  aEvent.Source = *this;
154  aEvent.EventId = _nEventId;
155  aEvent.OldValue = _rOldValue;
156  aEvent.NewValue = _rNewValue;
157 
158  // let the notifier handle this event
160  }
161 
162 
164  {
165  return !rBHelper.bDisposed && !rBHelper.bInDispose;
166  }
167 
168 
170  {
171  if( !isAlive() )
172  throw DisposedException();
173  }
174 
175 
177  {
178  if ( !rBHelper.bDisposed )
179  {
180  OSL_ENSURE( 0 == m_refCount, "OAccessibleContextHelper::ensureDisposed: this method _has_ to be called from without your dtor only!" );
181  acquire();
182  dispose();
183  }
184  }
185 
186 
187  void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible )
188  {
189  m_pImpl->setCreator( _rxAccessible );
190  }
191 
192 
193  Reference< XAccessible > OAccessibleContextHelper::getAccessibleCreator( ) const
194  {
195  return m_pImpl->getCreator();
196  }
197 
198 
200  {
201  return OUString();
202  }
203 
204 
206  {
207  OExternalLockGuard aGuard( this );
208 
209  // -1 for child not found/no parent (according to specification)
210  sal_Int32 nRet = -1;
211 
212  try
213  {
214 
215  Reference< XAccessibleContext > xParentContext( implGetParentContext() );
216 
217  // iterate over parent's children and search for this object
218  if ( xParentContext.is() )
219  {
220  // our own XAccessible for comparing with the children of our parent
221  Reference< XAccessible > xCreator( m_pImpl->getCreator() );
222 
223  OSL_ENSURE( xCreator.is(), "OAccessibleContextHelper::getAccessibleIndexInParent: invalid creator!" );
224  // two ideas why this could be NULL:
225  // * nobody called our late ctor (init), so we never had a creator at all -> bad
226  // * the creator is already dead. In this case, we should have been disposed, and
227  // never survived the above OContextEntryGuard.
228  // in all other situations the creator should be non-NULL
229 
230  if ( xCreator.is() )
231  {
232  sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
233  for ( sal_Int32 nChild = 0; ( nChild < nChildCount ) && ( -1 == nRet ); ++nChild )
234  {
235  Reference< XAccessible > xChild( xParentContext->getAccessibleChild( nChild ) );
236  if ( xChild.get() == xCreator.get() )
237  nRet = nChild;
238  }
239  }
240  }
241  }
242  catch( const Exception& )
243  {
244  OSL_FAIL( "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" );
245  }
246 
247  return nRet;
248  }
249 
250 
252  {
253  // simply ask the parent
254  Reference< XAccessible > xParent = getAccessibleParent();
255  Reference< XAccessibleContext > xParentContext;
256  if ( xParent.is() )
257  xParentContext = xParent->getAccessibleContext();
258 
259  if ( !xParentContext.is() )
260  throw IllegalAccessibleComponentStateException( OUString(), *this );
261 
262  return xParentContext->getLocale();
263  }
264 
265 
266  Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext()
267  {
268  Reference< XAccessible > xParent = getAccessibleParent();
269  Reference< XAccessibleContext > xParentContext;
270  if ( xParent.is() )
271  xParentContext = xParent->getAccessibleContext();
272  return xParentContext;
273  }
274 
275 
276 } // namespace comphelper
277 
278 
279 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
WeakReference< XAccessible > m_aCreator
std::unique_ptr< OContextHelper_Impl > m_pImpl
css::uno::Reference< css::accessibility::XAccessibleContext > implGetParentContext()
shortcut for retrieving the context of the parent (returned by getAccessibleParent) ...
void ensureDisposed()
ensures that the object is disposed.
ULONG m_refCount
virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override
default implementation for retrieving the index of this object within the parent
virtual void SAL_CALL disposing() override
virtual void SAL_CALL acquire() SAL_OVERRIDE
Reference< XAccessible > getCreator() const
AccessibleEventNotifier::TClientId getClientId() const
css::uno::Reference< css::accessibility::XAccessible > getAccessibleCreator() const
retrieves the creator previously set with lateInit
bool isAlive() const
checks whether the object is alive (returns then) or disposed
virtual css::lang::Locale SAL_CALL getLocale() override
default implementation for retrieving the locale
virtual void SAL_CALL addAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) override
void lateInit(const css::uno::Reference< css::accessibility::XAccessible > &_rxAccessible)
late construction
static sal_Int32 removeEventListener(const TClientId _nClient, const css::uno::Reference< css::accessibility::XAccessibleEventListener > &_rxListener)
revokes a listener for the given client
virtual void SAL_CALL removeAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) override
static void revokeClientNotifyDisposing(const TClientId _nClient, const css::uno::Reference< css::uno::XInterface > &_rxEventSource)
revokes a client, with additionally notifying a disposing event to all listeners registered for this ...
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override=0
static void revokeClient(const TClientId _nClient)
revokes a broadcaster of AccessibleEvents
static SolarMutex * get()
Help components to get the SolarMutex easily.
Definition: solarmutex.cxx:34
void setClientId(const AccessibleEventNotifier::TClientId _nId)
void ensureAlive() const
checks for being alive. If the object is already disposed (i.e. not alive), an exception is thrown...
static void addEvent(const TClientId _nClient, const css::accessibility::AccessibleEventObject &_rEvent)
adds an event, which is to be broadcasted, to the queue
void dispose()
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
virtual OUString SAL_CALL getAccessibleId() override
static TClientId registerClient()
registers a client of this class, means a broadcaster of AccessibleEvents
AccessibleEventNotifier::TClientId m_nClientId
void setCreator(const Reference< XAccessible > &_rAcc)
AnyEventRef aEvent
implementation class for OAccessibleContextHelper.
static sal_Int32 addEventListener(const TClientId _nClient, const css::uno::Reference< css::accessibility::XAccessibleEventListener > &_rxListener)
registers a listener for the given client
void NotifyAccessibleEvent(const sal_Int16 _nEventId, const css::uno::Any &_rOldValue, const css::uno::Any &_rNewValue)
notifies all AccessibleEventListeners of a certain event