diff options
Diffstat (limited to 'svx/source/accessibility/AccessibleTextHelper.cxx')
-rw-r--r-- | svx/source/accessibility/AccessibleTextHelper.cxx | 247 |
1 files changed, 192 insertions, 55 deletions
diff --git a/svx/source/accessibility/AccessibleTextHelper.cxx b/svx/source/accessibility/AccessibleTextHelper.cxx index e49bf55a7995..5c1d0913dbb1 100644 --- a/svx/source/accessibility/AccessibleTextHelper.cxx +++ b/svx/source/accessibility/AccessibleTextHelper.cxx @@ -2,9 +2,9 @@ * * $RCSfile: AccessibleTextHelper.cxx,v $ * - * $Revision: 1.31 $ + * $Revision: 1.32 $ * - * last change: $Author: thb $ $Date: 2002-12-12 12:36:51 $ + * last change: $Author: hr $ $Date: 2003-03-27 15:00:26 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -136,6 +136,10 @@ #include <drafts/com/sun/star/accessibility/AccessibleStateType.hpp> #endif +#ifndef COMPHELPER_ACCESSIBLE_EVENT_NOTIFIER +#include <comphelper/accessibleeventnotifier.hxx> +#endif + #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX_ #include <unotools/accessiblestatesethelper.hxx> #endif @@ -192,6 +196,8 @@ namespace accessibility // //------------------------------------------------------------------------ + DBG_NAME( AccessibleTextHelper_Impl ) + class AccessibleTextHelper_Impl : public SfxListener { @@ -215,15 +221,29 @@ namespace accessibility SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException)); void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)); - void SetEventSource( const uno::Reference< XAccessible >& rInterface ) { mxFrontEnd = rInterface; } - uno::Reference< XAccessible > GetEventSource() const { return mxFrontEnd; } + void SetEventSource( const uno::Reference< XAccessible >& rInterface ) + { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + mxFrontEnd = rInterface; + } + uno::Reference< XAccessible > GetEventSource() const + { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + return mxFrontEnd; + } void SetOffset( const Point& ); - Point GetOffset() const { ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset ); return aPoint; } + Point GetOffset() const + { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset ); + return aPoint; + } void SetStartIndex( sal_Int32 nOffset ); sal_Int32 GetStartIndex() const { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); // Strictly correct only with locked solar mutex, // but // here we rely on the fact that sal_Int32 access is // atomic @@ -274,6 +294,8 @@ namespace accessibility virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + int getNotifierClientId() const { return mnNotifierClientId; } + // lock solar mutex before SvxTextForwarder& GetTextForwarder() const SAL_THROW((uno::RuntimeException)); // lock solar mutex before @@ -321,14 +343,13 @@ namespace accessibility // whether we (this object) has the focus set (guarded by solar mutex) sal_Bool mbThisHasFocus; - // must be before maStateListeners, has to live longer mutable ::osl::Mutex maMutex; /// our current offset to the containing shape/cell (guarded by maMutex) Point maOffset; - // handles our event listeners (guarded by maMutex) - ::cppu::OInterfaceContainerHelper maStateListeners; + /// client Id from AccessibleEventNotifier + int mnNotifierClientId; }; @@ -349,16 +370,30 @@ namespace accessibility mbGroupHasFocus( sal_False ), mbThisHasFocus( sal_False ), maOffset(0,0), - maStateListeners( maMutex ) + // well, that's strictly exception safe, though not really + // robust. We rely on the fact that this member is constructed + // last, and that the constructor body is empty, thus no + // chance for exceptions once the Id is fetched. Nevertheless, + // normally should employ RAII here... + mnNotifierClientId(::comphelper::AccessibleEventNotifier::registerClient()) { + DBG_CTOR( AccessibleTextHelper_Impl, NULL ); + +#ifdef DBG_UTIL + OSL_TRACE( "AccessibleTextHelper_Impl received ID: %d", mnNotifierClientId ); +#endif } AccessibleTextHelper_Impl::~AccessibleTextHelper_Impl() { + DBG_DTOR( AccessibleTextHelper_Impl, NULL ); + ::vos::OGuard aGuard( Application::GetSolarMutex() ); try { + // call Dispose here, too, since we've some resources not + // automatically freed otherwise Dispose(); } catch( const uno::Exception& ) {} @@ -366,6 +401,8 @@ namespace accessibility SvxTextForwarder& AccessibleTextHelper_Impl::GetTextForwarder() const SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + if( !maEditSource.IsValid() ) throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd); @@ -382,6 +419,8 @@ namespace accessibility SvxViewForwarder& AccessibleTextHelper_Impl::GetViewForwarder() const SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + if( !maEditSource.IsValid() ) throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd); @@ -398,6 +437,8 @@ namespace accessibility SvxEditViewForwarder& AccessibleTextHelper_Impl::GetEditViewForwarder( sal_Bool bCreate ) const SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + if( !maEditSource.IsValid() ) throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd); @@ -424,6 +465,8 @@ namespace accessibility SvxEditSourceAdapter& AccessibleTextHelper_Impl::GetEditSource() const SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + if( maEditSource.IsValid() ) return maEditSource; else @@ -432,6 +475,8 @@ namespace accessibility sal_Bool AccessibleTextHelper_Impl::IsSelected() const { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + sal_Bool bRet = sal_False; try @@ -460,6 +505,8 @@ namespace accessibility void AccessibleTextHelper_Impl::SetStartIndex( sal_Int32 nOffset ) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + sal_Int32 nOldOffset( mnStartIndex ); mnStartIndex = nOffset; @@ -476,6 +523,8 @@ namespace accessibility void AccessibleTextHelper_Impl::SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + if( bHaveFocus ) { if( mbThisHasFocus ) @@ -501,6 +550,8 @@ namespace accessibility void AccessibleTextHelper_Impl::ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + if( mbThisHasFocus ) SetShapeFocus( sal_False ); @@ -512,6 +563,8 @@ namespace accessibility void AccessibleTextHelper_Impl::SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + sal_Bool bOldFocus( mbThisHasFocus ); mbThisHasFocus = bHaveFocus; @@ -533,6 +586,8 @@ namespace accessibility void AccessibleTextHelper_Impl::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + sal_Bool bOldFocus( mbGroupHasFocus ); mbGroupHasFocus = bHaveFocus; @@ -558,6 +613,8 @@ namespace accessibility sal_Bool AccessibleTextHelper_Impl::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // No locking of solar mutex here, since we rely on the fact // that sal_Bool access is atomic return mbThisHasFocus; @@ -565,6 +622,8 @@ namespace accessibility sal_Bool AccessibleTextHelper_Impl::IsActive() const SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + try { SvxEditSource& rEditSource = GetEditSource(); @@ -586,17 +645,22 @@ namespace accessibility void AccessibleTextHelper_Impl::UpdateSelection() { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + try { ESelection aSelection; if( GetEditViewForwarder().GetSelection( aSelection ) ) { - if( !maLastSelection.IsEqual( aSelection ) ) + if( !maLastSelection.IsEqual( aSelection ) && + aSelection.nEndPara < maParaManager.GetNum() ) { // #103998# Not that important, changed from assertion to trace if( mbThisHasFocus ) DBG_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): Parent has focus!"); + USHORT nParas( static_cast< USHORT >( GetTextForwarder().GetParagraphCount() ) ); + // notify all affected paragraphs (TODO: may be suboptimal, // since some paragraphs might stay selected) if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND ) @@ -606,11 +670,14 @@ namespace accessibility if( mbGroupHasFocus && maLastSelection.nEndPara != aSelection.nEndPara ) { - maParaManager.FireEvent( maLastSelection.nEndPara, - maLastSelection.nEndPara+1, - AccessibleEventId::ACCESSIBLE_CARET_EVENT, - uno::makeAny(static_cast<sal_Int32>(-1)), - uno::makeAny(static_cast<sal_Int32>(maLastSelection.nEndPos)) ); + if( maLastSelection.nEndPara < maParaManager.GetNum() ) + { + maParaManager.FireEvent( ::std::min( maLastSelection.nEndPara, nParas ), + ::std::min( maLastSelection.nEndPara, nParas )+1, + AccessibleEventId::ACCESSIBLE_CARET_EVENT, + uno::makeAny(static_cast<sal_Int32>(-1)), + uno::makeAny(static_cast<sal_Int32>(maLastSelection.nEndPos)) ); + } ChangeChildFocus( aSelection.nEndPara ); @@ -639,6 +706,53 @@ namespace accessibility DBG_TRACE5("AccessibleTextHelper_Impl::UpdateSelection(): caret changed, Object: %d, New pos: %d, Old pos: %d, New para: %d, Old para: %d", this, aSelection.nEndPos, maLastSelection.nEndPos, aSelection.nEndPara, maLastSelection.nEndPara); + // #107037# notify selection change + if( maLastSelection.nStartPara == EE_PARA_NOT_FOUND ) + { + // last selection is undefined + if( aSelection.nStartPos != aSelection.nEndPos || + aSelection.nStartPara != aSelection.nEndPara ) + { + // selection was undefined, now is on + maParaManager.FireEvent( aSelection.nStartPara, + aSelection.nEndPara+1, + AccessibleEventId::ACCESSIBLE_SELECTION_EVENT ); + } + } + else + { + // last selection is valid + if( (maLastSelection.nStartPos != maLastSelection.nEndPos || + maLastSelection.nStartPara != maLastSelection.nEndPara) && + (aSelection.nStartPos == aSelection.nEndPos && + aSelection.nStartPara == aSelection.nEndPara) ) + { + // selection was on, now is empty + maParaManager.FireEvent( ::std::min( maLastSelection.nStartPara, nParas ), + ::std::min( maLastSelection.nEndPara, nParas )+1, + AccessibleEventId::ACCESSIBLE_SELECTION_EVENT ); + } + else if( (maLastSelection.nStartPos == maLastSelection.nEndPos && + maLastSelection.nStartPara == maLastSelection.nEndPara) && + (aSelection.nStartPos != aSelection.nEndPos || + aSelection.nStartPara != aSelection.nEndPara) ) + { + // selection was empty, now is on + maParaManager.FireEvent( aSelection.nStartPara, + aSelection.nEndPara+1, + AccessibleEventId::ACCESSIBLE_SELECTION_EVENT ); + } + else + { + // selection was on, now is different + maParaManager.FireEvent( ::std::min(aSelection.nStartPara, + ::std::min( maLastSelection.nStartPara, nParas )), + ::std::max( aSelection.nEndPara, + static_cast< USHORT >( ::std::min( maLastSelection.nEndPara, nParas )+1 ) ), + AccessibleEventId::ACCESSIBLE_SELECTION_EVENT ); + } + } + maLastSelection = aSelection; } } @@ -649,6 +763,8 @@ namespace accessibility void AccessibleTextHelper_Impl::ShutdownEditSource() SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // This should only be called with solar mutex locked, i.e. from the main office thread // This here is somewhat clumsy: As soon as our children have @@ -674,6 +790,8 @@ namespace accessibility void AccessibleTextHelper_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // This should only be called with solar mutex locked, i.e. from the main office thread // shutdown old edit source @@ -696,6 +814,8 @@ namespace accessibility void AccessibleTextHelper_Impl::SetOffset( const Point& rPoint ) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // guard against non-atomic access to maOffset data structure { ::osl::MutexGuard aGuard( maMutex ); @@ -711,6 +831,8 @@ namespace accessibility void AccessibleTextHelper_Impl::UpdateVisibleChildren( bool bBroadcastEvents ) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + try { SvxTextForwarder& rCacheTF = GetTextForwarder(); @@ -838,6 +960,8 @@ namespace accessibility void AccessibleTextHelper_Impl::UpdateBoundRect() { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // send ACCESSIBLE_BOUNDRECT_EVENT to affected children AccessibleTextHelper_UpdateChildBounds aFunctor( *this ); ::std::transform( maParaManager.begin(), maParaManager.end(), maParaManager.begin(), aFunctor ); @@ -874,6 +998,8 @@ namespace accessibility void AccessibleTextHelper_Impl::ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast ) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + const sal_Int32 nParas = GetTextForwarder().GetParagraphCount(); /* rotate paragraphs @@ -1020,6 +1146,8 @@ namespace accessibility void AccessibleTextHelper_Impl::ProcessQueue() { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // inspect queue for paragraph insert/remove events. If there // is exactly _one_ of those in the queue, and the number of // paragraphs has changed by exactly one, use that event to @@ -1270,6 +1398,8 @@ namespace accessibility void AccessibleTextHelper_Impl::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // precondition: solar mutex locked DBG_TESTSOLARMUTEX(); @@ -1390,8 +1520,29 @@ namespace accessibility void AccessibleTextHelper_Impl::Dispose() { - // dispose children - maParaManager.Dispose(); + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + + if( getNotifierClientId() != -1 ) + { + try + { + // #106234# Unregister from EventNotifier + ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() ); +#ifdef DBG_UTIL + OSL_TRACE( "AccessibleTextHelper_Impl disposed ID: %d", mnNotifierClientId ); +#endif + } + catch( const uno::Exception& ) {} + + mnNotifierClientId = -1; + } + + try + { + // dispose children + maParaManager.Dispose(); + } + catch( const uno::Exception& ) {} // quit listen on stale edit source if( maEditSource.IsValid() ) @@ -1404,6 +1555,8 @@ namespace accessibility void AccessibleTextHelper_Impl::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // -- object locked -- ::osl::ClearableMutexGuard aGuard( maMutex ); @@ -1416,8 +1569,10 @@ namespace accessibility else aEvent = AccessibleEventObject(uno::Reference< uno::XInterface >(), nEventId, rNewValue, rOldValue); - // no locking necessary, OInterfaceIteratorHelper copies listeners if someone removes/adds in between - // Further locking, actually, might lead to deadlocks, since we're calling out of this object + // no locking necessary, FireEvent internally copies listeners + // if someone removes/adds in between Further locking, + // actually, might lead to deadlocks, since we're calling out + // of this object aGuard.clear(); // -- until here -- @@ -1426,55 +1581,29 @@ namespace accessibility void AccessibleTextHelper_Impl::FireEvent( const AccessibleEventObject& rEvent ) const { - // no locking necessary, OInterfaceIteratorHelper copies listeners if someone removes/adds in between - // Further locking, actually, might lead to deadlocks, since we're calling out of this object - ::cppu::OInterfaceIteratorHelper aIter( const_cast< AccessibleTextHelper_Impl* >(this)->maStateListeners ); + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); // #102261# Call global queue for focus events if( rEvent.EventId == AccessibleStateType::FOCUSED ) vcl::unohelper::NotifyAccessibleStateEventGlobally( rEvent ); - while( aIter.hasMoreElements() ) - { - uno::Reference < XAccessibleEventListener > xListener( aIter.next(), uno::UNO_QUERY ); - - if( xListener.is() ) - { - try - { - xListener->notifyEvent (rEvent); - } - catch( const lang::DisposedException& e ) - { - // DisposedExceptions from the listener might indicate a - // broken connection to a different environment. - - OSL_ENSURE(e.Context.is(), "AccessibleTextHelper::FireEvent: caught dispose exception with empty Context field"); - // If the exception stems from the listener then remove it - // from the list of listeners. If the Context field of the - // exception is empty this is interpreted to indicate the - // listener as well. - if (e.Context == xListener - || !e.Context.is()) - aIter.remove(); - } - catch( const uno::Exception& e ) - { - DBG_WARNING1("AccessibleTextHelper::FireEvent: exception %s from listener", - ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_DONTKNOW ).getStr() ); - } - } - } + // #106234# Delegate to EventNotifier + ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(), + rEvent ); } // XAccessibleContext sal_Int32 SAL_CALL AccessibleTextHelper_Impl::getAccessibleChildCount() SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + return mnLastVisibleChild - mnFirstVisibleChild + 1; } uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + i -= GetStartIndex(); if( 0 > i || i >= getAccessibleChildCount() || @@ -1493,16 +1622,24 @@ namespace accessibility void SAL_CALL AccessibleTextHelper_Impl::addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException)) { - maStateListeners.addInterface( xListener ); + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + + if( getNotifierClientId() != -1 ) + ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener ); } void SAL_CALL AccessibleTextHelper_Impl::removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException)) { - maStateListeners.removeInterface( xListener ); + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + + if( getNotifierClientId() != -1 ) + ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener ); } uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleAt( const awt::Point& _aPoint ) SAL_THROW((uno::RuntimeException)) { + DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); + // make given position relative if( !mxFrontEnd.is() ) throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd ); |