From 2f79d5f4794ec7f076bb290702b4c9c0afb2a6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Sch=C3=B6nheit?= Date: Tue, 23 Apr 2002 10:10:30 +0000 Subject: [PATCH] initial checkin - helper for implementing an XAccessibleContext --- .../comphelper/accessiblecontexthelper.hxx | 259 +++++++++++++ .../source/misc/accessiblecontexthelper.cxx | 361 ++++++++++++++++++ 2 files changed, 620 insertions(+) create mode 100644 comphelper/inc/comphelper/accessiblecontexthelper.hxx create mode 100644 comphelper/source/misc/accessiblecontexthelper.cxx diff --git a/comphelper/inc/comphelper/accessiblecontexthelper.hxx b/comphelper/inc/comphelper/accessiblecontexthelper.hxx new file mode 100644 index 000000000000..67083425da1d --- /dev/null +++ b/comphelper/inc/comphelper/accessiblecontexthelper.hxx @@ -0,0 +1,259 @@ +/************************************************************************* + * + * $RCSfile: accessiblecontexthelper.hxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: fs $ $Date: 2002-04-23 11:07:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc.. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX +#define COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX + +#ifndef _CPPUHELPER_COMPBASE2_HXX_ +#include +#endif +#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLECONTEXT_HPP_ +#include +#endif +#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEVENTBROADCASTER_HPP_ +#include +#endif +#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_ +#include +#endif +#ifndef _COMPHELPER_BROADCASTHELPER_HXX_ +#include +#endif + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + //===================================================================== + //= OAccessibleContextHelper + //===================================================================== + + class OContextHelper_Impl; + typedef ::cppu::WeakAggComponentImplHelper2 < ::drafts::com::sun::star::accessibility::XAccessibleContext, + ::drafts::com::sun::star::accessibility::XAccessibleEventBroadcaster + > OAccessibleContextHelper_Base; + + /** helper class for implementing an AccessibleContext + */ + class OAccessibleContextHelper + :public ::comphelper::OMutexAndBroadcastHelper + ,public OAccessibleContextHelper_Base + { + private: + OContextHelper_Impl* m_pImpl; + + protected: + OAccessibleContextHelper( ); + ~OAccessibleContextHelper( ); + + /** late construction + @param _rxAccessible + the Accessible object which created this context. +

If your derived implementation implements the XAccessible (and does not follow the proposed + separation of XAccessible from XAccessibleContext), you may pass this here.

+ +

The object is hold weak, so it's life time is not affected.

+ +

The object is needed for performance reasons: for getAccessibleIndexInParent, + all children (which are XAccessible's theirself) of our parent have to be asked. If we know our + XAccessible, we can compare it with all the children, instead of asking all children for their + context and comparing this context with ourself.

+ */ + void lateInit( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible >& _rxAccessible ); + + public: + // XAccessibleEventBroadcaster + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleContext - still waiting to be overwritten + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException) = 0; + virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) = 0; + virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) throw (::com::sun::star::uno::RuntimeException) = 0; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) throw (::com::sun::star::uno::RuntimeException) = 0; + virtual ::rtl::OUString SAL_CALL getAccessibleDescription( ) throw (::com::sun::star::uno::RuntimeException) = 0; + virtual ::rtl::OUString SAL_CALL getAccessibleName( ) throw (::com::sun::star::uno::RuntimeException) = 0; + virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) throw (::com::sun::star::uno::RuntimeException) = 0; + virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) throw (::com::sun::star::uno::RuntimeException) = 0; + + // XAccessibleContext - default implementations + /** default implementation for retrieving the index of this object within the parent +

This basic implementation here returns the index i of the child for which + <parent>.getAccessibleChild( i ) equals our creator.

+ */ + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) throw (::com::sun::star::uno::RuntimeException); + /** default implementation for retrieving the locale +

This basic implementation returns the locale of the parent context, + as retrieved via getAccessibleParent()->getAccessibleContext.

+ */ + virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::drafts::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + public: + // helper struct for granting selective access rights + struct OAccessControl { friend class OContextEntryGuard; }; + + // ensures that the object is alive + void ensureAlive( const OAccessControl& _rAccessControl ) const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) ); + + protected: + // OComponentHelper + virtual void SAL_CALL disposing(); + + protected: + // helper + /** notifies all AccessibleEventListeners of a certain event + + @precond not too be called with our mutex locked + @param _nEventId + the id of the even. See AccessibleEventType + @param _rOldValue + the old value to be notified + @param _rNewValue + the new value to be notified + */ + void SAL_CALL NotifyAccessibleEvent( + const sal_Int16 _nEventId, + const ::com::sun::star::uno::Any& _rOldValue, + const ::com::sun::star::uno::Any& _rNewValue + ); + + // life time control + /// checks whether the object is alive (returns then) or disposed + sal_Bool isAlive() const; + /// checks for beeing alive. If the object is already disposed (i.e. not alive), an exception is thrown. + void ensureAlive() const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) ); + + /** ensures that the object is disposed. + @precond + to be called from within the destructor of your derived class only! + */ + void ensureDisposed( ); + + /** shortcut for retrieving the context of the parent (returned by getAccessibleParent) + */ + ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleContext > + implGetParentContext() SAL_THROW( ( ::com::sun::star::uno::RuntimeException ) ); + + }; + + //===================================================================== + //= OContextEntryGuard + //===================================================================== + typedef ::osl::ClearableMutexGuard OContextEntryGuard_Base; + /** helper class for guarding the entry into OAccessibleContextHelper methods. + +

The class has two responsibilities: +

  • it locks the mutex of an OAccessibleContextHelper instance, as long as the guard lives
  • +
  • it checks if an given OAccessibleContextHelper instance is alive, else an exception is thrown + our of the constructor of the guard
  • +
+
+ This makes it your first choice (hopefully :) for guarding any interface method implementations of + you derived class. +

+ */ + class OContextEntryGuard : public OContextEntryGuard_Base + { + public: + /** constructs the guard + +

The given context (it's mutex, respectively) is locked, and an exception is thrown if the context + is not alive anymore. In the latter case, of course, the mutex is freed, again.

+ + @param _pContext + the context which shall be guarded + @precond _pContext != NULL + */ + inline OContextEntryGuard( OAccessibleContextHelper* _pContext ); + + /** destructs the guard. +

The context (it's mutex, respectively) is unlocked.

+ */ + inline ~OContextEntryGuard(); + }; + + //..................................................................... + inline OContextEntryGuard::OContextEntryGuard( OAccessibleContextHelper* _pContext ) + :OContextEntryGuard_Base( _pContext->GetMutex() ) + { + _pContext->ensureAlive( OAccessibleContextHelper::OAccessControl() ); + } + + //..................................................................... + inline OContextEntryGuard::~OContextEntryGuard() + { + } + + +//......................................................................... +} // namespace comphelper +//......................................................................... + +#endif // COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX + +/************************************************************************* + * history: + * $Log: not supported by cvs2svn $ + * + * Revision 1.0 17.04.2002 15:47:54 fs + ************************************************************************/ + diff --git a/comphelper/source/misc/accessiblecontexthelper.cxx b/comphelper/source/misc/accessiblecontexthelper.cxx new file mode 100644 index 000000000000..2b1834520da0 --- /dev/null +++ b/comphelper/source/misc/accessiblecontexthelper.cxx @@ -0,0 +1,361 @@ +/************************************************************************* + * + * $RCSfile: accessiblecontexthelper.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: fs $ $Date: 2002-04-23 11:10:30 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc.. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX +#include +#endif +#ifndef _OSL_DIAGNOSE_H_ +#include +#endif +#ifndef _CPPUHELPER_WEAKREF_HXX_ +#include +#endif +#ifndef _SV_SVAPP_HXX +#include +#endif +#ifndef _VOS_MUTEX_HXX_ +#include +#endif + +#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEEVENTID_HPP_ +#include +#endif +#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLESTATETYPE_HPP_ +#include +#endif + +//......................................................................... +namespace comphelper +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::drafts::com::sun::star::accessibility; + + //===================================================================== + //= OContextHelper_Impl + //===================================================================== + /** implementation class for OAccessibleContextHelper. No own thread safety! + */ + class OContextHelper_Impl + { + private: + OAccessibleContextHelper* m_pAntiImpl; // the owning instance + + ::cppu::OInterfaceContainerHelper* m_pEventListeners; + WeakReference< XAccessible > m_aCreator; // the XAccessible which created our XAccessibleContext + + public: + ::cppu::OInterfaceContainerHelper* getListenerContainer( sal_Bool _bCreate = sal_True ); + // not const - will create if necessary + + inline Reference< XAccessible > getCreator( ) const { return m_aCreator; } + inline void setCreator( const Reference< XAccessible >& _rAcc ); + + public: + OContextHelper_Impl( OAccessibleContextHelper* _pAntiImpl ) + :m_pAntiImpl( _pAntiImpl ) + ,m_pEventListeners( NULL ) + { + } + }; + + //--------------------------------------------------------------------- + inline void OContextHelper_Impl::setCreator( const Reference< XAccessible >& _rAcc ) + { + m_aCreator = _rAcc; + } + + //--------------------------------------------------------------------- + ::cppu::OInterfaceContainerHelper* OContextHelper_Impl::getListenerContainer( sal_Bool _bCreate ) + { + if ( !m_pEventListeners && _bCreate ) + m_pEventListeners = new ::cppu::OInterfaceContainerHelper( m_pAntiImpl->GetMutex() ); + return m_pEventListeners; + } + + //===================================================================== + //= OAccessibleContextHelper + //===================================================================== + //--------------------------------------------------------------------- + OAccessibleContextHelper::OAccessibleContextHelper( ) + :OAccessibleContextHelper_Base( GetMutex() ) + ,m_pImpl( NULL ) + { + m_pImpl = new OContextHelper_Impl( this ); + } + + //--------------------------------------------------------------------- + OAccessibleContextHelper::~OAccessibleContextHelper( ) + { + ensureDisposed(); + + delete m_pImpl; + m_pImpl = NULL; + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::disposing() + { + // notify our listeners that we're going to be defunc + NotifyAccessibleEvent( + AccessibleEventId::ACCESSIBLE_STATE_EVENT, + Any(), + makeAny( AccessibleStateType::DEFUNC ) + ); + + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + ::cppu::OInterfaceContainerHelper* pListeners = m_pImpl->getListenerContainer( sal_False ); + if ( pListeners ) + { + EventObject aDisposee( *this ); + aGuard.clear(); + pListeners->disposeAndClear( aDisposee ); + } + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::addEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException) + { + OContextEntryGuard( this ); + if ( _rxListener.is() ) + m_pImpl->getListenerContainer()->addInterface( _rxListener ); + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::removeEventListener( const Reference< XAccessibleEventListener >& _rxListener ) throw (RuntimeException) + { + OContextEntryGuard( this ); + if ( _rxListener.is() ) + m_pImpl->getListenerContainer()->removeInterface( _rxListener ); + } + + //--------------------------------------------------------------------- + void SAL_CALL OAccessibleContextHelper::NotifyAccessibleEvent( const sal_Int16 _nEventId, + const Any& _rOldValue, const Any& _rNewValue ) + { + // copy our current listeners + ::cppu::OInterfaceContainerHelper* pListeners = m_pImpl->getListenerContainer( sal_False ); + Sequence< Reference< XInterface > > aListeners; + if ( pListeners ) + aListeners = pListeners->getElements(); + + if ( aListeners.getLength() ) + { + AccessibleEventObject aEvent; + aEvent.Source = *this; + aEvent.EventId = _nEventId; + aEvent.OldValue = _rOldValue; + aEvent.NewValue = _rNewValue; + + const Reference< XInterface >* pLoop = aListeners.getConstArray(); + const Reference< XInterface >* pLoopEnd = pLoop + aListeners.getLength(); + + while ( pLoop != pLoopEnd ) + { + try + { + while ( pLoop != pLoopEnd ) + { + XAccessibleEventListener* pListener = static_cast< XAccessibleEventListener* > ( + pLoop->get() ); + // note that this cast is valid: + // We added the interface to our listener container, and at this time it was an + // XAccessibleEventListener. As we did not query for XInterface, but instead used + // the XInterface which is the base of XAccessibleEventListener, we can now safely + // cast. + + if ( pListener ) + pListener->notifyEvent( aEvent ); + + ++pLoop; + } + } + catch( const Exception& e ) + { + e; // make compiler happy + // skip this listener and continue with the next one + } + + ++pLoop; + } + } + } + + //--------------------------------------------------------------------- + sal_Bool OAccessibleContextHelper::isAlive() const + { + return !GetBroadcastHelper().bDisposed && !GetBroadcastHelper().bInDispose; + } + + //--------------------------------------------------------------------- + void OAccessibleContextHelper::ensureAlive() const SAL_THROW( ( DisposedException ) ) + { + if( !isAlive() ) + throw DisposedException(); + } + + //--------------------------------------------------------------------- + void OAccessibleContextHelper::ensureAlive( const OAccessControl& _rAccessControl ) const SAL_THROW( ( DisposedException ) ) + { + ensureAlive(); + } + + //--------------------------------------------------------------------- + void OAccessibleContextHelper::ensureDisposed( ) + { + if ( !GetBroadcastHelper().bDisposed ) + { + OSL_ENSURE( 0 == m_refCount, "OAccessibleContextHelper::ensureDisposed: this method _has_ to be called from without your dtor only!" ); + acquire(); + dispose(); + } + } + + //--------------------------------------------------------------------- + void OAccessibleContextHelper::lateInit( const Reference< XAccessible >& _rxAccessible ) + { + m_pImpl->setCreator( _rxAccessible ); + } + + //--------------------------------------------------------------------- + sal_Int32 SAL_CALL OAccessibleContextHelper::getAccessibleIndexInParent( ) throw (RuntimeException) + { + OContextEntryGuard aGuard( this ); + + // -1 for child not found/no parent (according to specification) + sal_Int32 nRet = -1; + + try + { + + Reference< XAccessibleContext > xParentContext( implGetParentContext() ); + + // iterate over parent's children and search for this object + if ( xParentContext.is() ) + { + // our own XAccessible for comparing with the children of our parent + Reference< XAccessible > xCreator( m_pImpl->getCreator() ); + + OSL_ENSURE( xCreator.is(), "OAccessibleContextHelper::getAccessibleIndexInParent: invalid creator!" ); + // two ideas why this could be NULL: + // * nobody called our late ctor (init), so we never had a creator at all -> bad + // * the creator is already dead. In this case, we should have been disposed, and + // never survived the above OContextEntryGuard. + // in all other situations the creator should be non-NULL + + if ( xCreator.is() ) + { + sal_Int32 nChildCount = xParentContext->getAccessibleChildCount(); + for ( sal_Int32 nChild = 0; ( nChild < nChildCount ) && ( -1 == nRet ); ++nChild ) + { + Reference< XAccessible > xChild( xParentContext->getAccessibleChild( nChild ) ); + if ( xChild.get() == xCreator.get() ) + nRet = nChild; + } + } + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "OAccessibleContextHelper::getAccessibleIndexInParent: caught an exception!" ); + } + + return nRet; + } + + //--------------------------------------------------------------------- + Locale SAL_CALL OAccessibleContextHelper::getLocale( ) throw (IllegalAccessibleComponentStateException, RuntimeException) + { + // simply ask the parent + Reference< XAccessible > xParent = getAccessibleParent(); + Reference< XAccessibleContext > xParentContext; + if ( xParent.is() ) + xParentContext = xParent->getAccessibleContext(); + + if ( !xParentContext.is() ) + throw IllegalAccessibleComponentStateException( ::rtl::OUString(), *this ); + + return xParentContext->getLocale(); + } + + //--------------------------------------------------------------------- + Reference< XAccessibleContext > OAccessibleContextHelper::implGetParentContext() SAL_THROW( ( RuntimeException ) ) + { + Reference< XAccessible > xParent = getAccessibleParent(); + Reference< XAccessibleContext > xParentContext; + if ( xParent.is() ) + xParentContext = xParent->getAccessibleContext(); + return xParentContext; + } + +//......................................................................... +} // namespace comphelper +//......................................................................... + +/************************************************************************* + * history: + * $Log: not supported by cvs2svn $ + * + * Revision 1.0 17.04.2002 16:06:46 fs + ************************************************************************/ +