1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #ifndef COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX 25 #define COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX 26 27 #include <cppuhelper/compbase2.hxx> 28 #include <com/sun/star/accessibility/XAccessibleContext.hpp> 29 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> 30 #include <com/sun/star/lang/DisposedException.hpp> 31 #include <comphelper/broadcasthelper.hxx> 32 #include "comphelper/comphelperdllapi.h" 33 34 //......................................................................... 35 namespace comphelper 36 { 37 //......................................................................... 38 39 class AccessibleEventBuffer; 40 41 //===================================================================== 42 //= IMutex 43 //===================================================================== 44 45 // This whole thingie here (own mutex classes and such) is a HACK. I hate the SolarMutex. 46 // See below for more explanations .... 47 48 /** abstract interface for implementing a mutex 49 */ 50 class IMutex 51 { 52 public: 53 virtual void acquire() = 0; 54 virtual void release() = 0; 55 }; 56 57 //===================================================================== 58 //= OMutexGuard 59 //===================================================================== 60 61 class OMutexGuard 62 { 63 IMutex* m_pMutex; 64 public: OMutexGuard(IMutex * _pMutex)65 inline OMutexGuard( IMutex* _pMutex ) 66 :m_pMutex( _pMutex ) 67 { 68 if ( m_pMutex ) 69 m_pMutex->acquire(); 70 } 71 ~OMutexGuard()72 inline ~OMutexGuard( ) 73 { 74 if ( m_pMutex ) 75 m_pMutex->release(); 76 } 77 }; 78 79 //===================================================================== 80 //= OAccessibleContextHelper 81 //===================================================================== 82 83 class OContextHelper_Impl; 84 typedef ::cppu::WeakAggComponentImplHelper2 < ::com::sun::star::accessibility::XAccessibleContext, 85 ::com::sun::star::accessibility::XAccessibleEventBroadcaster 86 > OAccessibleContextHelper_Base; 87 88 /** helper class for implementing an AccessibleContext 89 */ 90 class COMPHELPER_DLLPUBLIC OAccessibleContextHelper 91 :public ::comphelper::OBaseMutex 92 ,public OAccessibleContextHelper_Base 93 { 94 private: 95 OContextHelper_Impl* m_pImpl; 96 97 protected: 98 OAccessibleContextHelper( ); 99 ~OAccessibleContextHelper( ); 100 101 /** ctor 102 103 <p>If you need additional object safety for your class, and want to ensure that your own 104 mutex is locked before the mutex this class provides is, than use this ctor.</p> 105 106 <p>Beware that this is a hack. Unfortunately, OpenOffice.org has two different mutex hierarchies, 107 which are not compatible. In addition, wide parts of the code (especially VCL) is not thread-safe, 108 but instead relies on a <em>single global mutex</em>. As a consequence, components using 109 directly or indirectly such code need to care for this global mutex. Yes, this is as ugly as 110 anything.</p> 111 112 <p>Note that the external lock is used as additional lock, not as the only one. The own mutex of the 113 instance is used for internal actions, and every action which potentially involves external code 114 (for instance every call to a virtual method overridden by derivees) is <em>additionally</em> and 115 <em>first</em> guarded by with the external lock.</p> 116 117 <p>Beware of the lifetime of the lock - you must ensure that the lock exists at least as long as 118 the context does. A good approach to implement the lock may be to derive you own context 119 not only from OAccessibleContextHelper, but also from IMutex.</p> 120 121 <p>One more note. This lock is definitely not used once the dtor is reached. Means whatever 122 the dtor implementation does, it does <em>not</em> guard the external lock. See this as a contract. 123 <br/>You should ensure the same thing for own derivees which do not supply the lock themself, 124 but get them from yet another derivee.</p> 125 @see forgetExternalLock 126 */ 127 OAccessibleContextHelper( IMutex* _pExternalLock ); 128 129 /** late construction 130 @param _rxAccessible 131 the Accessible object which created this context. 132 <p>If your derived implementation implements the XAccessible (and does not follow the proposed 133 separation of XAccessible from XAccessibleContext), you may pass <code>this</code> here.</p> 134 135 <p>The object is hold weak, so it's life time is not affected.</p> 136 137 <p>The object is needed for performance reasons: for <method>getAccessibleIndexInParent</method>, 138 all children (which are XAccessible's theirself) of our parent have to be asked. If we know our 139 XAccessible, we can compare it with all the children, instead of asking all children for their 140 context and comparing this context with ourself.</p> 141 */ 142 void lateInit( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& _rxAccessible ); 143 144 /** retrieves the creator previously set with <method>lateInit</method> 145 */ 146 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > 147 getAccessibleCreator( ) const; 148 149 /** forgets the reference to the external lock, if present. 150 151 <p>This means any further locking will not be guard the external lock anymore, never.</p> 152 153 <p>To be used in derived classes which do not supply the external lock themself, but instead get 154 them passed from own derivees (or clients).</p> 155 */ 156 void forgetExternalLock(); 157 158 public: 159 // XAccessibleEventBroadcaster 160 using WeakAggComponentImplHelperBase::addEventListener; 161 virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); 162 using WeakAggComponentImplHelperBase::removeEventListener; 163 virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); 164 165 // XAccessibleContext - still waiting to be overwritten 166 virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException) = 0; 167 virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) = 0; 168 virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) throw (::com::sun::star::uno::RuntimeException) = 0; 169 virtual sal_Int16 SAL_CALL getAccessibleRole( ) throw (::com::sun::star::uno::RuntimeException) = 0; 170 virtual ::rtl::OUString SAL_CALL getAccessibleDescription( ) throw (::com::sun::star::uno::RuntimeException) = 0; 171 virtual ::rtl::OUString SAL_CALL getAccessibleName( ) throw (::com::sun::star::uno::RuntimeException) = 0; 172 virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) throw (::com::sun::star::uno::RuntimeException) = 0; 173 virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) throw (::com::sun::star::uno::RuntimeException) = 0; 174 175 // XAccessibleContext - default implementations 176 /** default implementation for retrieving the index of this object within the parent 177 <p>This basic implementation here returns the index <code>i</code> of the child for which 178 <code><parent>.getAccessibleChild( i )</code> equals our creator.</p> 179 */ 180 virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) throw (::com::sun::star::uno::RuntimeException); 181 /** default implementation for retrieving the locale 182 <p>This basic implementation returns the locale of the parent context, 183 as retrieved via getAccessibleParent()->getAccessibleContext.</p> 184 */ 185 virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); 186 187 public: 188 // helper struct for granting selective access rights 189 struct OAccessControl 190 { 191 friend class OContextEntryGuard; 192 friend class OContextHelper_Impl; 193 friend class OExternalLockGuard; 194 private: OAccessControlcomphelper::OAccessibleContextHelper::OAccessControl195 OAccessControl() { } 196 }; 197 198 // ensures that the object is alive 199 inline void ensureAlive( const OAccessControl& ) const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) ); 200 inline IMutex* getExternalLock( const OAccessControl& ); 201 inline ::osl::Mutex& GetMutex( const OAccessControl& ); 202 203 protected: 204 // OComponentHelper 205 virtual void SAL_CALL disposing(); 206 207 protected: 208 // helper 209 /** notifies all AccessibleEventListeners of a certain event 210 211 @precond not too be called with our mutex locked 212 @param _nEventId 213 the id of the even. See AccessibleEventType 214 @param _rOldValue 215 the old value to be notified 216 @param _rNewValue 217 the new value to be notified 218 */ 219 virtual void SAL_CALL NotifyAccessibleEvent( 220 const sal_Int16 _nEventId, 221 const ::com::sun::star::uno::Any& _rOldValue, 222 const ::com::sun::star::uno::Any& _rNewValue 223 ); 224 225 /** records a certain event so that all AccessibleEventListeners can 226 be notified later on. 227 228 Can even be called with our mutex locked. 229 230 @param _nEventId 231 the id of the even. See AccessibleEventType 232 @param _rOldValue 233 the old value to be notified 234 @param _rNewValue 235 the new value to be notified 236 @param _rBuffer 237 the buffer that records the event 238 */ 239 virtual void SAL_CALL BufferAccessibleEvent( 240 const sal_Int16 _nEventId, 241 const ::com::sun::star::uno::Any& _rOldValue, 242 const ::com::sun::star::uno::Any& _rNewValue, 243 AccessibleEventBuffer & _rBuffer 244 ); 245 246 // life time control 247 /// checks whether the object is alive (returns <TRUE/> then) or disposed 248 sal_Bool isAlive() const; 249 /// checks for being alive. If the object is already disposed (i.e. not alive), an exception is thrown. 250 void ensureAlive() const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) ); 251 252 /** ensures that the object is disposed. 253 @precond 254 to be called from within the destructor of your derived class only! 255 */ 256 void ensureDisposed( ); 257 258 /** shortcut for retrieving the context of the parent (returned by getAccessibleParent) 259 */ 260 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > 261 implGetParentContext() SAL_THROW( ( ::com::sun::star::uno::RuntimeException ) ); 262 263 // access to the base class' broadcast helper/mutex GetBroadcastHelper()264 ::cppu::OBroadcastHelper& GetBroadcastHelper() { return rBHelper; } GetBroadcastHelper() const265 const ::cppu::OBroadcastHelper& GetBroadcastHelper() const { return rBHelper; } GetMutex()266 ::osl::Mutex& GetMutex() { return m_aMutex; } 267 IMutex* getExternalLock( ); 268 }; 269 270 //--------------------------------------------------------------------- ensureAlive(const OAccessControl &) const271 inline void OAccessibleContextHelper::ensureAlive( const OAccessControl& ) const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) ) 272 { 273 ensureAlive(); 274 } 275 276 //--------------------------------------------------------------------- getExternalLock(const OAccessControl &)277 inline IMutex* OAccessibleContextHelper::getExternalLock( const OAccessControl& ) 278 { 279 return getExternalLock(); 280 } 281 282 //--------------------------------------------------------------------- GetMutex(const OAccessControl &)283 inline ::osl::Mutex& OAccessibleContextHelper::GetMutex( const OAccessControl& ) 284 { 285 return GetMutex(); 286 } 287 288 //===================================================================== 289 //= OContextEntryGuard 290 //===================================================================== 291 typedef ::osl::ClearableMutexGuard OContextEntryGuard_Base; 292 /** helper class for guarding the entry into OAccessibleContextHelper methods. 293 294 <p>The class has two responsibilities: 295 <ul><li>it locks the mutex of an OAccessibleContextHelper instance, as long as the guard lives</li> 296 <li>it checks if an given OAccessibleContextHelper instance is alive, else an exception is thrown 297 our of the constructor of the guard</li> 298 </ul> 299 <br/> 300 This makes it your first choice (hopefully :) for guarding any interface method implementations of 301 you derived class. 302 </p> 303 */ 304 class OContextEntryGuard : public OContextEntryGuard_Base 305 { 306 public: 307 /** constructs the guard 308 309 <p>The given context (it's mutex, respectively) is locked, and an exception is thrown if the context 310 is not alive anymore. In the latter case, of course, the mutex is freed, again.</p> 311 312 @param _pContext 313 the context which shall be guarded 314 @precond <arg>_pContext</arg> != NULL 315 */ 316 inline OContextEntryGuard( OAccessibleContextHelper* _pContext ); 317 318 /** destructs the guard. 319 <p>The context (it's mutex, respectively) is unlocked.</p> 320 */ 321 inline ~OContextEntryGuard(); 322 }; 323 324 //..................................................................... OContextEntryGuard(OAccessibleContextHelper * _pContext)325 inline OContextEntryGuard::OContextEntryGuard( OAccessibleContextHelper* _pContext ) 326 :OContextEntryGuard_Base( _pContext->GetMutex( OAccessibleContextHelper::OAccessControl() ) ) 327 { 328 _pContext->ensureAlive( OAccessibleContextHelper::OAccessControl() ); 329 } 330 331 //..................................................................... ~OContextEntryGuard()332 inline OContextEntryGuard::~OContextEntryGuard() 333 { 334 } 335 336 //===================================================================== 337 //= OExternalLockGuard 338 //===================================================================== 339 class OExternalLockGuard 340 :public OMutexGuard 341 ,public OContextEntryGuard 342 { 343 public: 344 inline OExternalLockGuard( OAccessibleContextHelper* _pContext ); 345 inline ~OExternalLockGuard( ); 346 }; 347 348 //..................................................................... OExternalLockGuard(OAccessibleContextHelper * _pContext)349 inline OExternalLockGuard::OExternalLockGuard( OAccessibleContextHelper* _pContext ) 350 :OMutexGuard( _pContext->getExternalLock( OAccessibleContextHelper::OAccessControl() ) ) 351 ,OContextEntryGuard( _pContext ) 352 { 353 // #102438# 354 // Only lock the external mutex, 355 // release the ::osl::Mutex of the OAccessibleContextHelper instance. 356 // If you call into another UNO object with locked ::osl::Mutex, 357 // this may lead to dead locks. 358 clear(); 359 } 360 361 //..................................................................... ~OExternalLockGuard()362 inline OExternalLockGuard::~OExternalLockGuard( ) 363 { 364 } 365 366 //......................................................................... 367 } // namespace comphelper 368 //......................................................................... 369 370 #endif // COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX 371 372 373