diff options
-rw-r--r-- | svx/source/accessibility/AccessibleTextEventQueue.cxx | 154 | ||||
-rw-r--r-- | svx/source/accessibility/AccessibleTextEventQueue.hxx | 141 | ||||
-rw-r--r-- | svx/source/accessibility/AccessibleTextHelper.cxx | 560 | ||||
-rwxr-xr-x | svx/source/accessibility/makefile.mk | 6 |
4 files changed, 675 insertions, 186 deletions
diff --git a/svx/source/accessibility/AccessibleTextEventQueue.cxx b/svx/source/accessibility/AccessibleTextEventQueue.cxx new file mode 100644 index 000000000000..cdc643118394 --- /dev/null +++ b/svx/source/accessibility/AccessibleTextEventQueue.cxx @@ -0,0 +1,154 @@ +/************************************************************************* + * + * $RCSfile: AccessibleTextEventQueue.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: thb $ $Date: 2002-12-12 12:36:50 $ + * + * 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 EXPRESSED 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 _SVX_ACCESSIBLE_TEXT_EVENT_QUEUE_HXX +#include "AccessibleTextEventQueue.hxx" +#endif + +#ifndef _SVX_UNOSHAPE_HXX +#include "unoshape.hxx" +#endif + +#ifndef _UNO_LINGU_HXX +#include "unolingu.hxx" +#endif + +#ifndef _SVX_UNOTEXT_HXX +#include "unotext.hxx" +#endif + +#include "unoedhlp.hxx" +#include "unopracc.hxx" +#include "svdmodel.hxx" +#include "svdpntv.hxx" +#include "editdata.hxx" +#include "editeng.hxx" +#include "editview.hxx" + +namespace accessibility +{ + //------------------------------------------------------------------------ + // + // EventQueue implementation + // + //------------------------------------------------------------------------ + + AccessibleTextEventQueue::AccessibleTextEventQueue() + { + } + + AccessibleTextEventQueue::~AccessibleTextEventQueue() + { + Clear(); + } + + void AccessibleTextEventQueue::Append( const SfxHint& rHint ) + { + maEventQueue.push_back( new SfxHint( rHint ) ); + } + + void AccessibleTextEventQueue::Append( const SdrHint& rHint ) + { + maEventQueue.push_back( new SdrHint( rHint ) ); + } + + void AccessibleTextEventQueue::Append( const SfxSimpleHint& rHint ) + { + maEventQueue.push_back( new SfxSimpleHint( rHint ) ); + } + + void AccessibleTextEventQueue::Append( const TextHint& rHint ) + { + maEventQueue.push_back( new TextHint( rHint ) ); + } + + void AccessibleTextEventQueue::Append( const SvxViewHint& rHint ) + { + maEventQueue.push_back( new SvxViewHint( rHint ) ); + } + + void AccessibleTextEventQueue::Append( const SvxEditSourceHint& rHint ) + { + maEventQueue.push_back( new SvxEditSourceHint( rHint ) ); + } + + ::std::auto_ptr< SfxHint > AccessibleTextEventQueue::PopFront() + { + ::std::auto_ptr< SfxHint > aRes( *(maEventQueue.begin()) ); + maEventQueue.pop_front(); + return aRes; + } + + bool AccessibleTextEventQueue::IsEmpty() const + { + return maEventQueue.empty(); + } + + void AccessibleTextEventQueue::Clear() + { + // clear queue + while( !IsEmpty() ) + PopFront(); + } + +} // end of namespace accessibility + +//------------------------------------------------------------------------ diff --git a/svx/source/accessibility/AccessibleTextEventQueue.hxx b/svx/source/accessibility/AccessibleTextEventQueue.hxx new file mode 100644 index 000000000000..7f6dd717978e --- /dev/null +++ b/svx/source/accessibility/AccessibleTextEventQueue.hxx @@ -0,0 +1,141 @@ +/************************************************************************* + * + * $RCSfile: AccessibleTextEventQueue.hxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: thb $ $Date: 2002-12-12 12:36:51 $ + * + * 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 EXPRESSED 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 _SVX_ACCESSIBLE_TEXT_EVENT_QUEUE_HXX +#define _SVX_ACCESSIBLE_TEXT_EVENT_QUEUE_HXX + +#include <memory> +#include <list> + +#ifndef _SOLAR_H +#include <tools/solar.h> +#endif + +#ifndef _RTTI_HXX +#include <tools/rtti.hxx> +#endif + +class SfxHint; +class SdrHint; +class SfxSimpleHint; +class TextHint; +class SvxViewHint; +class SvxEditSourceHint; + +namespace accessibility +{ + /** This class handles the notification events for the + AccessibleTextHelper class. + + For various reasons, we cannot process EditEngine events as + they arrive, but have to queue and handle them in a batch. + */ + class AccessibleTextEventQueue + { + public: + typedef ::std::list< SfxHint* > EventQueue; + + AccessibleTextEventQueue(); + ~AccessibleTextEventQueue(); + + /// Append event to end of queue + void Append( const SfxHint& rHint ); + /// Append event to end of queue + void Append( const SdrHint& rHint ); + /// Append event to end of queue + void Append( const SfxSimpleHint& rHint ); + /// Append event to end of queue + void Append( const TextHint& rHint ); + /// Append event to end of queue + void Append( const SvxViewHint& rHint ); + /// Append event to end of queue + void Append( const SvxEditSourceHint& rHint ); + + /** Pop first queue element + + return first queue element, ownership transfers to caller + */ + ::std::auto_ptr< SfxHint > PopFront(); + + /** Apply functor to every queue member + + @param rFunctor + Functor to apply. Functor receives queue element as + parameter: void func( const SfxHint* ); + */ + template < typename Functor > void ForEach( Functor& rFunctor ) const + { + ::std::for_each( maEventQueue.begin(), maEventQueue.end(), rFunctor ); + } + + /// Query whether queue is empty + bool IsEmpty() const; + + /// Clear event queue + void Clear(); + + private: + EventQueue maEventQueue; + }; + +} // end of namespace accessibility + +#endif /* _SVX_ACCESSIBLE_TEXT_EVENT_QUEUE_HXX */ diff --git a/svx/source/accessibility/AccessibleTextHelper.cxx b/svx/source/accessibility/AccessibleTextHelper.cxx index 30dd0f6a476a..e49bf55a7995 100644 --- a/svx/source/accessibility/AccessibleTextHelper.cxx +++ b/svx/source/accessibility/AccessibleTextHelper.cxx @@ -2,9 +2,9 @@ * * $RCSfile: AccessibleTextHelper.cxx,v $ * - * $Revision: 1.30 $ + * $Revision: 1.31 $ * - * last change: $Author: thb $ $Date: 2002-11-29 17:56:25 $ + * last change: $Author: thb $ $Date: 2002-12-12 12:36:51 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -70,6 +70,7 @@ #include <limits.h> #include <memory> #include <algorithm> +#include <deque> #ifndef _VOS_MUTEX_HXX_ #include <vos/mutex.hxx> @@ -149,6 +150,10 @@ // //------------------------------------------------------------------------ +#ifndef _SVX_ACCESSIBLE_TEXT_EVENT_QUEUE_HXX +#include "AccessibleTextEventQueue.hxx" +#endif + #ifndef _SVX_ACCESSILE_TEXT_HELPER_HXX_ #include "AccessibleTextHelper.hxx" #endif @@ -244,7 +249,7 @@ namespace accessibility #endif // checks all children for visibility, throws away invisible ones - void UpdateVisibleChildren(); + void UpdateVisibleChildren( bool bBroadcastEvents=true ); // check all children for changes in positon and size void UpdateBoundRect(); @@ -255,6 +260,9 @@ namespace accessibility private: + // Process event queue + void ProcessQueue(); + // syntactic sugar for FireEvent void GotPropertyEvent( const uno::Any& rNewValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, rNewValue ); } void LostPropertyEvent( const uno::Any& rOldValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, uno::Any(), rOldValue ); } @@ -263,8 +271,6 @@ namespace accessibility void ShutdownEditSource() SAL_THROW((uno::RuntimeException)); void ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast ); - void ParagraphsInserted( sal_Int32 nFirst ); - void ParagraphsRemoved( sal_Int32 nFirst ); virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); @@ -300,6 +306,12 @@ namespace accessibility // the object handling our children (guarded by solar mutex) accessibility::AccessibleParaManager maParaManager; + // number of not-yet-closed event frames (BEGIN/END sequences) (guarded by solar mutex) + sal_Int32 maEventOpenFrames; + + // Queued events from Notify() (guarded by solar mutex) + AccessibleTextEventQueue maEventQueue; + // spin lock to prevent notify in notify (guarded by solar mutex) sal_Bool mbInNotify; @@ -332,6 +344,7 @@ namespace accessibility mnFirstVisibleChild( -1 ), mnLastVisibleChild( -2 ), mnStartIndex( 0 ), + maEventOpenFrames( 0 ), mbInNotify( sal_False ), mbGroupHasFocus( sal_False ), mbThisHasFocus( sal_False ), @@ -696,7 +709,7 @@ namespace accessibility UpdateBoundRect(); } - void AccessibleTextHelper_Impl::UpdateVisibleChildren() + void AccessibleTextHelper_Impl::UpdateVisibleChildren( bool bBroadcastEvents ) { try { @@ -748,7 +761,8 @@ namespace accessibility accessibility::AccessibleParaManager::WeakChild aChild( maParaManager.GetChild(nCurrPara) ); if( aChild.second.Width == 0 && aChild.second.Height == 0 && - mxFrontEnd.is() ) + mxFrontEnd.is() && + bBroadcastEvents ) { GotPropertyEvent( uno::makeAny( maParaManager.CreateChild( nCurrPara - mnFirstVisibleChild, mxFrontEnd, GetEditSource(), nCurrPara ).first ), @@ -760,8 +774,9 @@ namespace accessibility // not or no longer visible if( maParaManager.IsReferencable( nCurrPara ) ) { - LostPropertyEvent( uno::makeAny( maParaManager.GetChild( nCurrPara ).first.get().getRef() ), - AccessibleEventId::ACCESSIBLE_CHILD_EVENT ); + if( bBroadcastEvents ) + LostPropertyEvent( uno::makeAny( maParaManager.GetChild( nCurrPara ).first.get().getRef() ), + AccessibleEventId::ACCESSIBLE_CHILD_EVENT ); // clear reference maParaManager.Release( nCurrPara ); @@ -779,7 +794,8 @@ namespace accessibility maParaManager.SetNum(0); // lost all children - FireEvent(AccessibleEventId::ACCESSIBLE_ALL_CHILDREN_CHANGED_EVENT); + if( bBroadcastEvents ) + FireEvent(AccessibleEventId::ACCESSIBLE_ALL_CHILDREN_CHANGED_EVENT); } } @@ -933,76 +949,323 @@ namespace accessibility } } - void AccessibleTextHelper_Impl::ParagraphsInserted( sal_Int32 nFirst ) + /** functor processing queue events + + Reacts on TEXT_HINT_PARAINSERTED/REMOVED events and stores + their content + */ + class AccessibleTextHelper_QueueFunctor : public ::std::unary_function< const SfxHint*, void > { - const sal_Int32 nParas = GetTextForwarder().GetParagraphCount(); - const sal_Int32 nOldNumParas( maParaManager.GetNum() ); - const sal_Int32 nLast( nParas - 1 ); + public: + AccessibleTextHelper_QueueFunctor() : + mnParasChanged( 0 ), + mnParaIndex(-1), + mnHintId(-1) + {} + void operator()( const SfxHint* pEvent ) + { + if( pEvent && + mnParasChanged != -1 ) + { + // determine hint type + const TextHint* pTextHint = PTR_CAST( TextHint, pEvent ); + const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, pEvent ); - // resize child vector to the current child count - maParaManager.SetNum( nParas ); + if( !pEditSourceHint && pTextHint && + (pTextHint->GetId() == TEXT_HINT_PARAINSERTED || + pTextHint->GetId() == TEXT_HINT_PARAREMOVED ) ) + { + if( pTextHint->GetValue() == EE_PARA_ALL ) + { + mnParasChanged = -1; + } + else + { + mnHintId = pTextHint->GetId(); + mnParaIndex = pTextHint->GetValue(); + ++mnParasChanged; + } + } + } + } - if( nFirst < nOldNumParas && nFirst < nParas && nLast < nParas ) - { - // since we have no "paragraph index - // changed" event on UAA, remove - // [first,last] and insert again later (in - // UpdateVisibleChildren) + /** Query number of paragraphs changed during queue processing. - // move successors of inserted paragraph one position further - //maParaManager.MoveRightFrom( pTextHint->GetValue() ); + @return number of changed paragraphs, -1 for + "every paragraph changed" + */ + int GetNumberOfParasChanged() { return mnParasChanged; } + /** Query index of last added/removed paragraph - // send CHILD_EVENT to affected children - ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin(); - ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin; + @return index of lastly added paragraphs, -1 for none + added so far. + */ + int GetParaIndex() { return mnParaIndex; } + /** Query hint id of last interesting event - ::std::advance( begin, nFirst ); - ::std::advance( end, nLast+1 ); + @return hint id of last interesting event (REMOVED/INSERTED). + */ + int GetHintId() { return mnHintId; } - // TODO: maybe optimize here in the following way. If the - // number of removed children exceeds a certain threshold, - // use ACCESSIBLE_ALL_CHILDREN_CHANGED_EVENT - AccessibleTextHelper_LostChildEvent aFunctor( *this ); - ::std::for_each( begin, end, aFunctor ); + private: + /** number of paragraphs changed during queue processing. -1 for + "every paragraph changed" + */ + int mnParasChanged; + /// index of paragraph added/removed last + int mnParaIndex; + /// TextHint ID (removed/inserted) of last interesting event + int mnHintId; + }; - // release everything from the insertion position until the end - // #102235# Perform the release after the CHILD_EVENT notification - maParaManager.Release(nFirst, nLast+1); + void AccessibleTextHelper_Impl::ProcessQueue() + { + // 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 + // determine a priori which paragraph was added/removed. This + // is necessary, since I must sync right here with the + // EditEngine state (number of paragraphs etc.), since I'm + // potentially sending listener events right away. + AccessibleTextHelper_QueueFunctor aFunctor; + maEventQueue.ForEach( aFunctor ); + + const sal_Int32 nNewParas( GetTextForwarder().GetParagraphCount() ); + const sal_Int32 nCurrParas( maParaManager.GetNum() ); + + // whether every paragraph already is updated (no need to + // repeat that later on, e.g. for PARA_MOVED events) + bool bEverythingUpdated( false ); + + if( labs( nNewParas - nCurrParas ) == 1 && + aFunctor.GetNumberOfParasChanged() == 1 ) + { + // #103483# Exactly one paragraph added/removed. This is + // the normal case, optimize event handling here. + + if( aFunctor.GetHintId() == TEXT_HINT_PARAINSERTED ) + { + // update num of paras + maParaManager.SetNum( nNewParas ); + + // release everything from the insertion position until the end + maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas); + + // TODO: Clarify whether this behaviour _really_ saves + // anybody anything! + // update children, _don't_ broadcast + UpdateVisibleChildren( false ); + UpdateBoundRect(); + + // send insert event + AccessibleParaManager::WeakPara::HardRefType aChild( maParaManager.GetChild( aFunctor.GetParaIndex() ).first.get() ); + GotPropertyEvent( uno::makeAny( aChild.getRef() ), + AccessibleEventId::ACCESSIBLE_CHILD_EVENT ); + } + else if( aFunctor.GetHintId() == TEXT_HINT_PARAREMOVED ) + { + ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin(); + ::std::advance( begin, aFunctor.GetParaIndex() ); + ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin; + ::std::advance( end, 1 ); + + // send remove event + AccessibleTextHelper_LostChildEvent aLooseFunctor( *this ); + ::std::for_each( begin, end, aLooseFunctor ); + + // release everything from the remove position until the end + // #102235# Perform the release after the CHILD_EVENT notification + maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas); + + // update num of paras + maParaManager.SetNum( nNewParas ); + + // TODO: Clarify whether this behaviour _really_ saves + // anybody anything! + // update children, _don't_ broadcast + UpdateVisibleChildren( false ); + UpdateBoundRect(); + } +#ifdef DBG_UTIL + else + DBG_ERROR("AccessibleTextHelper_Impl::ProcessQueue() invalid hint id"); +#endif } - } + else if( nNewParas != nCurrParas ) + { + // number of paragraphs somehow changed - but we have no + // chance determining how. Thus, throw away everything and + // create from scratch. + FireEvent(AccessibleEventId::ACCESSIBLE_ALL_CHILDREN_CHANGED_EVENT); - void AccessibleTextHelper_Impl::ParagraphsRemoved( sal_Int32 nFirst ) - { - const sal_Int32 nParas = GetTextForwarder().GetParagraphCount(); - const sal_Int32 nLast( maParaManager.GetNum() - 1 ); + // release all paras + maParaManager.Release(0, nCurrParas); - // since we have no "paragraph index - // changed" event on UAA, remove - // [first,last] and insert again later (in - // UpdateVisibleChildren) + // update num of paras + maParaManager.SetNum( nNewParas ); - // move successors of removed paragraph one position closer - // maParaManager.MoveLeftFrom( pTextHint->GetValue() ); + // create from scratch + UpdateVisibleChildren(); + UpdateBoundRect(); - // send CHILD_EVENT to affected children - ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin(); - ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin; + // no need for further updates later on + bEverythingUpdated = true; + } - ::std::advance( begin, nFirst ); - ::std::advance( end, nLast+1 ); + while( !maEventQueue.IsEmpty() ) + { + ::std::auto_ptr< SfxHint > pHint( maEventQueue.PopFront() ); + if( pHint.get() ) + { + const SfxHint& rHint = *(pHint.get()); - // TODO: maybe optimize here in the following way. If the - // number of removed children exceeds a certain threshold, - // use ACCESSIBLE_ALL_CHILDREN_CHANGED_EVENT - AccessibleTextHelper_LostChildEvent aFunctor( *this ); - ::std::for_each( begin, end, aFunctor ); + // determine hint type + const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint ); + const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint ); + const TextHint* pTextHint = PTR_CAST( TextHint, &rHint ); + const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint ); + const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint ); + + try + { + const sal_Int32 nParas = GetTextForwarder().GetParagraphCount(); - // release everything from the remove position until the end - // #102235# Perform the release after the CHILD_EVENT notification - maParaManager.Release(nFirst, nLast+1); + if( pEditSourceHint ) + { + switch( pEditSourceHint->GetId() ) + { + case EDITSOURCE_HINT_PARASMOVED: + { + DBG_ASSERT( pEditSourceHint->GetStartValue() < GetTextForwarder().GetParagraphCount() && + pEditSourceHint->GetEndValue() < GetTextForwarder().GetParagraphCount(), + "AccessibleTextHelper_Impl::NotifyHdl: Invalid notification"); + + if( !bEverythingUpdated ) + { + ParagraphsMoved(pEditSourceHint->GetStartValue(), + pEditSourceHint->GetValue(), + pEditSourceHint->GetEndValue()); + + // in all cases, check visibility afterwards. + UpdateVisibleChildren(); + } + break; + } + + case EDITSOURCE_HINT_SELECTIONCHANGED: + // notify listeners + try + { + UpdateSelection(); + } + // maybe we're not in edit mode (this is not an error) + catch( const uno::Exception& ) {} + break; + } + } + else if( pTextHint ) + { + switch( pTextHint->GetId() ) + { + case TEXT_HINT_MODIFIED: + { + // notify listeners + sal_Int32 nPara( pTextHint->GetValue() ); + if( nPara == static_cast<sal_Int32>(EE_PARA_ALL) ) + maParaManager.FireEvent( 0, GetTextForwarder().GetParagraphCount(), AccessibleEventId::ACCESSIBLE_TEXT_EVENT ); + else + if( nPara < nParas ) + maParaManager.FireEvent( nPara, AccessibleEventId::ACCESSIBLE_TEXT_EVENT ); + break; + } + + case TEXT_HINT_PARAINSERTED: + // already happened above + break; + + case TEXT_HINT_PARAREMOVED: + // already happened above + break; + + case TEXT_HINT_TEXTHEIGHTCHANGED: + // visibility changed, done below + break; + + case TEXT_HINT_VIEWSCROLLED: + // visibility changed, done below + break; + } - // resize child vector to the current child count - maParaManager.SetNum( nParas ); + // in all cases, check visibility afterwards. + UpdateVisibleChildren(); + UpdateBoundRect(); + } + else if( pViewHint ) + { + switch( pViewHint->GetId() ) + { + case SVX_HINT_VIEWCHANGED: + // just check visibility + UpdateVisibleChildren(); + UpdateBoundRect(); + break; + } + } + else if( pSdrHint ) + { + switch( pSdrHint->GetKind() ) + { + case HINT_BEGEDIT: + { + // change children state + maParaManager.SetActive(); + + // per definition, edit mode text has the focus + SetFocus( sal_True ); + break; + } + + case HINT_ENDEDIT: + // focused child now looses focus + ESelection aSelection; + if( GetEditViewForwarder().GetSelection( aSelection ) ) + SetChildFocus( aSelection.nEndPara, sal_False ); + + // change children state + maParaManager.SetActive( sal_False ); + + maLastSelection = ESelection( EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND, + EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND); + break; + } + } + // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above! + else if( pSimpleHint ) + { + switch( pSimpleHint->GetId() ) + { + case SFX_HINT_DYING: + // edit source is dying under us, become defunc then + try + { + // make edit source inaccessible + // Note: cannot destroy it here, since we're called from there! + ShutdownEditSource(); + } + catch( const uno::Exception& ) {} + + break; + } + } + } + catch( const uno::Exception& ) + { +#ifdef DBG_UTIL + OSL_TRACE("AccessibleTextHelper_Impl::ProcessQueue: Unhandled exception."); +#endif + } + } + } } void AccessibleTextHelper_Impl::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) @@ -1025,154 +1288,83 @@ namespace accessibility try { - const sal_Int32 nParas = GetTextForwarder().GetParagraphCount(); - - // precondition: edit engine and para manager consistent - - /* The problem here is the fact that the EditEngine events - * do not always arrive in a logical order. For example, - * when inserting a paragraph by pressing return at the - * end of a line, currently the TEXT_MODIFIED hint arrives - * before the PARAGRAPH_INSERTED hint. Therefore, we have - * to update our paragraph count proactively here. - */ - sal_Int32 nFirstParaInsert( 0 ); // default range is pessimization, don't know where to add - if( (!pEditSourceHint && pTextHint && pTextHint->GetId() == TEXT_HINT_PARAINSERTED) ) - nFirstParaInsert = pTextHint->GetValue() == EE_PARA_ALL ? 0 : pTextHint->GetValue(); - - if( nFirstParaInsert != 0 || - maParaManager.GetNum() < static_cast<sal_uInt32>(nParas) ) - { - ParagraphsInserted( nFirstParaInsert ); - UpdateVisibleChildren(); - UpdateBoundRect(); - } - - sal_Int32 nFirstParaRemove( 0 ); // default range is pessimization, don't know where to add - if( (!pEditSourceHint && pTextHint && pTextHint->GetId() == TEXT_HINT_PARAREMOVED) ) - nFirstParaRemove = pTextHint->GetValue() == EE_PARA_ALL ? 0 : pTextHint->GetValue(); - - if( nFirstParaRemove != 0 || - maParaManager.GetNum() > static_cast<sal_uInt32>(nParas) ) - { - // remove excess paragraphs (range is pessimization, don't know where to remove) - ParagraphsRemoved( nFirstParaRemove ); - UpdateVisibleChildren(); - UpdateBoundRect(); - } - + // Process notification event if( pEditSourceHint ) { - switch( pEditSourceHint->GetId() ) - { - case EDITSOURCE_HINT_PARASMOVED: - { - DBG_ASSERT( pEditSourceHint->GetStartValue() < GetTextForwarder().GetParagraphCount() && - pEditSourceHint->GetEndValue() < GetTextForwarder().GetParagraphCount(), - "AccessibleTextHelper_Impl::NotifyHdl: Invalid notification"); - - ParagraphsMoved(pEditSourceHint->GetStartValue(), - pEditSourceHint->GetValue(), - pEditSourceHint->GetEndValue()); - - // in all cases, check visibility afterwards. - UpdateVisibleChildren(); - - break; - } - - case EDITSOURCE_HINT_SELECTIONCHANGED: - // notify listeners - try - { - UpdateSelection(); - } - // maybe we're not in edit mode (this is not an error) - catch( const uno::Exception& ) {} - break; - } + maEventQueue.Append( *pEditSourceHint ); } else if( pTextHint ) { switch( pTextHint->GetId() ) { - case TEXT_HINT_MODIFIED: - { - // notify listeners - sal_Int32 nPara( pTextHint->GetValue() ); - if( nPara == static_cast<sal_Int32>(EE_PARA_ALL) ) - maParaManager.FireEvent( 0, GetTextForwarder().GetParagraphCount(), AccessibleEventId::ACCESSIBLE_TEXT_EVENT ); - else - if( nPara < nParas ) - maParaManager.FireEvent( nPara, AccessibleEventId::ACCESSIBLE_TEXT_EVENT ); - break; - } + case TEXT_HINT_BLOCKNOTIFICATION_END: + case TEXT_HINT_INPUT_END: + --maEventOpenFrames; - case TEXT_HINT_PARAINSERTED: - // already happened above - break; - - case TEXT_HINT_PARAREMOVED: - // already happened above + if( maEventOpenFrames == 0 ) + { + // #103483# + /* All information should have arrived + * now, process queue. As stated in the + * above bug, we can often avoid throwing + * away all paragraphs by looking forward + * in the event queue (searching for + * PARAINSERT/REMOVE events). Furthermore, + * processing the event queue only at the + * end of an interaction cycle, ensures + * that the EditEngine state and the + * AccessibleText state are the same + * (well, mostly. If there are _multiple_ + * interaction cycles in the EE queues, it + * can still happen that EE state is + * different. That's so to say broken by + * design with that delayed EE event + * concept). + */ + ProcessQueue(); + } break; - case TEXT_HINT_TEXTHEIGHTCHANGED: - break; + case TEXT_HINT_BLOCKNOTIFICATION_START: + case TEXT_HINT_INPUT_START: + ++maEventOpenFrames; - case TEXT_HINT_VIEWSCROLLED: + default: + maEventQueue.Append( *pTextHint ); break; } - - // in all cases, check visibility afterwards. - UpdateVisibleChildren(); - UpdateBoundRect(); } else if( pViewHint ) { - switch( pViewHint->GetId() ) - { - case SVX_HINT_VIEWCHANGED: - // just check visibility - UpdateVisibleChildren(); - UpdateBoundRect(); - break; - } + maEventQueue.Append( *pViewHint ); + + // process visibility right away, if not within an + // open EE notification frame. Otherwise, event + // processing would be delayed until next EE + // notification sequence. + if( maEventOpenFrames == 0 ) + ProcessQueue(); } else if( pSdrHint ) { - switch( pSdrHint->GetKind() ) - { - case HINT_BEGEDIT: - { - // change children state - maParaManager.SetActive(); - - // per definition, edit mode text has the focus - SetFocus( sal_True ); - break; - } - - case HINT_ENDEDIT: - // focused child now looses focus - ESelection aSelection; - if( GetEditViewForwarder().GetSelection( aSelection ) ) - SetChildFocus( aSelection.nEndPara, sal_False ); - - // change children state - maParaManager.SetActive( sal_False ); - - maLastSelection = ESelection( EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND, - EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND); - break; - } + maEventQueue.Append( *pSdrHint ); + + // process drawing layer events right away, if not + // within an open EE notification frame. Otherwise, + // event processing would be delayed until next EE + // notification sequence. + if( maEventOpenFrames == 0 ) + ProcessQueue(); } // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above! else if( pSimpleHint ) { + // handle this event _at once_, because after that, objects are invalid switch( pSimpleHint->GetId() ) { case SFX_HINT_DYING: // edit source is dying under us, become defunc then + maEventQueue.Clear(); try { // make edit source inaccessible diff --git a/svx/source/accessibility/makefile.mk b/svx/source/accessibility/makefile.mk index 5d07ff8ef1db..87c4c16cee8c 100755 --- a/svx/source/accessibility/makefile.mk +++ b/svx/source/accessibility/makefile.mk @@ -2,9 +2,9 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.15 $ +# $Revision: 1.16 $ # -# last change: $Author: oj $ $Date: 2002-07-30 10:32:22 $ +# last change: $Author: thb $ $Date: 2002-12-12 12:36:51 $ # # The Contents of this file are made available subject to the terms of # either of the following licenses @@ -91,6 +91,7 @@ CXXFILES = \ AccessibleSelectionBase.cxx \ AccessibleShapeTreeInfo.cxx \ AccessibleTextHelper.cxx \ + AccessibleTextEventQueue.cxx \ AccessibleStaticTextBase.cxx \ AccessibleParaManager.cxx \ AccessibleEditableTextPara.cxx \ @@ -115,6 +116,7 @@ SLOFILES = \ $(SLO)$/AccessibleShapeInfo.obj \ $(SLO)$/AccessibleShapeTreeInfo.obj \ $(SLO)$/AccessibleTextHelper.obj \ + $(SLO)$/AccessibleTextEventQueue.obj \ $(SLO)$/AccessibleStaticTextBase.obj \ $(SLO)$/AccessibleParaManager.obj \ $(SLO)$/AccessibleEditableTextPara.obj \ |