summaryrefslogtreecommitdiff
path: root/svx/source/accessibility/AccessibleTextHelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/accessibility/AccessibleTextHelper.cxx')
-rw-r--r--svx/source/accessibility/AccessibleTextHelper.cxx2084
1 files changed, 2084 insertions, 0 deletions
diff --git a/svx/source/accessibility/AccessibleTextHelper.cxx b/svx/source/accessibility/AccessibleTextHelper.cxx
new file mode 100644
index 000000000000..5b632115c93c
--- /dev/null
+++ b/svx/source/accessibility/AccessibleTextHelper.cxx
@@ -0,0 +1,2084 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: AccessibleTextHelper.cxx,v $
+ * $Revision: 1.48 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svx.hxx"
+
+//------------------------------------------------------------------------
+//
+// Global header
+//
+//------------------------------------------------------------------------
+
+#include <limits.h>
+#include <memory>
+#include <algorithm>
+#include <deque>
+#include <vos/mutex.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <comphelper/accessibleeventnotifier.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <vcl/unohelp.hxx>
+#include <vcl/svapp.hxx>
+
+//------------------------------------------------------------------------
+//
+// Project-local header
+//
+//------------------------------------------------------------------------
+#include "AccessibleTextEventQueue.hxx"
+#include <svx/AccessibleTextHelper.hxx>
+#include <svx/unoshape.hxx>
+#include "unolingu.hxx"
+#include <svx/unotext.hxx>
+
+#include "unoedhlp.hxx"
+#include "unopracc.hxx"
+#include "AccessibleParaManager.hxx"
+#include "AccessibleEditableTextPara.hxx"
+#include <svx/svdmodel.hxx>
+#include <svx/svdpntv.hxx>
+#include <svx/editdata.hxx>
+#include <svx/editeng.hxx>
+#include <svx/editview.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility
+{
+
+//------------------------------------------------------------------------
+//
+// AccessibleTextHelper_Impl declaration
+//
+//------------------------------------------------------------------------
+
+ DBG_NAME( AccessibleTextHelper_Impl )
+
+ template < typename first_type, typename second_type >
+ ::std::pair< first_type, second_type > makeSortedPair( first_type first,
+ second_type second )
+ {
+ if( first > second )
+ return ::std::make_pair( second, first );
+ else
+ return ::std::make_pair( first, second );
+ }
+
+ class AccessibleTextHelper_Impl : public SfxListener
+ {
+
+ public:
+ typedef ::std::vector< sal_Int16 > VectorOfStates;
+
+ // receive pointer to our frontend class and view window
+ AccessibleTextHelper_Impl();
+ ~AccessibleTextHelper_Impl();
+
+ // XAccessibleContext child handling methods
+ sal_Int32 SAL_CALL getAccessibleChildCount() SAL_THROW((uno::RuntimeException));
+ uno::Reference< XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException));
+
+ // XAccessibleEventBroadcaster child related methods
+ void SAL_CALL addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException));
+ void SAL_CALL removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException));
+
+ // XAccessibleComponent child related methods
+ uno::Reference< XAccessible > SAL_CALL getAccessibleAtPoint( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException));
+
+ 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 )
+ {
+ 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
+ {
+ 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
+ return mnStartIndex;
+ }
+
+ void SetAdditionalChildStates( const VectorOfStates& rChildStates );
+ const VectorOfStates& GetAdditionalChildStates() const;
+
+ sal_Bool IsSelected() const;
+
+ void Dispose();
+
+ // do NOT hold object mutex when calling this! Danger of deadlock
+ void FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue = uno::Any(), const uno::Any& rOldValue = uno::Any() ) const;
+ void FireEvent( const AccessibleEventObject& rEvent ) const;
+
+ void SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
+ sal_Bool HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException));
+ void SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
+ void SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
+ void ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException));
+
+#ifdef DBG_UTIL
+ void CheckInvariants() const;
+#endif
+
+ // checks all children for visibility, throws away invisible ones
+ void UpdateVisibleChildren( bool bBroadcastEvents=true );
+
+ // check all children for changes in positíon and size
+ void UpdateBoundRect();
+
+ // calls SetSelection on the forwarder and updates maLastSelection
+ // cache.
+ void UpdateSelection();
+
+ 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 ); }
+
+ // shutdown usage of current edit source on myself and the children.
+ void ShutdownEditSource() SAL_THROW((uno::RuntimeException));
+
+ void ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast );
+
+ 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
+ SvxViewForwarder& GetViewForwarder() const SAL_THROW((uno::RuntimeException));
+ // lock solar mutex before
+ SvxEditViewForwarder& GetEditViewForwarder( sal_Bool bCreate = sal_False ) const SAL_THROW((uno::RuntimeException));
+
+ // are we in edit mode?
+ sal_Bool IsActive() const SAL_THROW((uno::RuntimeException));
+
+ // our frontend class (the one implementing the actual
+ // interface). That's not necessarily the one containing the impl
+ // pointer!
+ uno::Reference< XAccessible > mxFrontEnd;
+
+ // a wrapper for the text forwarders (guarded by solar mutex)
+ mutable SvxEditSourceAdapter maEditSource;
+
+ // store last selection (to correctly report selection changes, guarded by solar mutex)
+ ESelection maLastSelection;
+
+ // cache range of visible children (guarded by solar mutex)
+ sal_Int32 mnFirstVisibleChild;
+ sal_Int32 mnLastVisibleChild;
+
+ // offset to add to all our children (unguarded, relying on
+ // the fact that sal_Int32 access is atomic)
+ sal_Int32 mnStartIndex;
+
+ // 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;
+
+ // whether the object or it's children has the focus set (guarded by solar mutex)
+ sal_Bool mbGroupHasFocus;
+
+ // whether we (this object) has the focus set (guarded by solar mutex)
+ sal_Bool mbThisHasFocus;
+
+ mutable ::osl::Mutex maMutex;
+
+ /// our current offset to the containing shape/cell (guarded by maMutex)
+ Point maOffset;
+
+ /// client Id from AccessibleEventNotifier
+ int mnNotifierClientId;
+ };
+
+ //------------------------------------------------------------------------
+ //
+ // AccessibleTextHelper_Impl implementation
+ //
+ //------------------------------------------------------------------------
+
+ AccessibleTextHelper_Impl::AccessibleTextHelper_Impl() :
+ mxFrontEnd( NULL ),
+ maLastSelection( EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND ),
+ mnFirstVisibleChild( -1 ),
+ mnLastVisibleChild( -2 ),
+ mnStartIndex( 0 ),
+ maEventOpenFrames( 0 ),
+ mbInNotify( sal_False ),
+ mbGroupHasFocus( sal_False ),
+ mbThisHasFocus( sal_False ),
+ maOffset(0,0),
+ // 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& ) {}
+ }
+
+ 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);
+
+ SvxTextForwarder* pTextForwarder = maEditSource.GetTextForwarder();
+
+ if( !pTextForwarder )
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch text forwarder, model might be dead")), mxFrontEnd);
+
+ if( pTextForwarder->IsValid() )
+ return *pTextForwarder;
+ else
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Text forwarder is invalid, model might be dead")), mxFrontEnd);
+ }
+
+ 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);
+
+ SvxViewForwarder* pViewForwarder = maEditSource.GetViewForwarder();
+
+ if( !pViewForwarder )
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch view forwarder, model might be dead")), mxFrontEnd);
+
+ if( pViewForwarder->IsValid() )
+ return *pViewForwarder;
+ else
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, model might be dead")), mxFrontEnd);
+ }
+
+ 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);
+
+ SvxEditViewForwarder* pViewForwarder = maEditSource.GetEditViewForwarder( bCreate );
+
+ if( !pViewForwarder )
+ {
+ if( bCreate )
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch edit view forwarder, model might be dead")), mxFrontEnd);
+ else
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No edit view forwarder, object not in edit mode")), mxFrontEnd);
+ }
+
+ if( pViewForwarder->IsValid() )
+ return *pViewForwarder;
+ else
+ {
+ if( bCreate )
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, model might be dead")), mxFrontEnd);
+ else
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, object not in edit mode")), mxFrontEnd);
+ }
+ }
+
+ SvxEditSourceAdapter& AccessibleTextHelper_Impl::GetEditSource() const SAL_THROW((uno::RuntimeException))
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ if( maEditSource.IsValid() )
+ return maEditSource;
+ else
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::GetEditSource: no edit source")), mxFrontEnd );
+ }
+
+ sal_Bool AccessibleTextHelper_Impl::IsSelected() const
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ sal_Bool bRet = sal_False;
+
+ try
+ {
+ ESelection aSelection;
+ bRet = GetEditViewForwarder().GetSelection( aSelection );
+ }
+ catch( const uno::Exception& ) {}
+
+ return bRet;
+ }
+
+ // functor for sending child events (no stand-alone function, they are maybe not inlined)
+ class AccessibleTextHelper_OffsetChildIndex : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
+ {
+ public:
+ AccessibleTextHelper_OffsetChildIndex( sal_Int32 nDifference ) : mnDifference(nDifference) {}
+ void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
+ {
+ rPara.SetIndexInParent( rPara.GetIndexInParent() + mnDifference );
+ }
+
+ private:
+ const sal_Int32 mnDifference;
+ };
+
+ void AccessibleTextHelper_Impl::SetStartIndex( sal_Int32 nOffset )
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ sal_Int32 nOldOffset( mnStartIndex );
+
+ mnStartIndex = nOffset;
+
+ if( nOldOffset != nOffset )
+ {
+ // update children
+ AccessibleTextHelper_OffsetChildIndex aFunctor( nOffset - nOldOffset );
+
+ ::std::for_each( maParaManager.begin(), maParaManager.end(),
+ AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_OffsetChildIndex > (aFunctor) );
+ }
+ }
+
+ void AccessibleTextHelper_Impl::SetAdditionalChildStates( const VectorOfStates& rChildStates )
+ {
+ maParaManager.SetAdditionalChildStates( rChildStates );
+ }
+
+ const AccessibleTextHelper_Impl::VectorOfStates& AccessibleTextHelper_Impl::GetAdditionalChildStates() const
+ {
+ return maParaManager.GetAdditionalChildStates();
+ }
+
+ 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 )
+ SetShapeFocus( sal_False );
+
+ maParaManager.SetFocus( nChild );
+
+ // we just received the focus, also send caret event then
+ UpdateSelection();
+
+ DBG_TRACE1("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d received focus", nChild );
+ }
+ else
+ {
+ maParaManager.SetFocus( -1 );
+
+ DBG_TRACE1("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d lost focus", nChild );
+
+ if( mbGroupHasFocus )
+ SetShapeFocus( sal_True );
+ }
+ }
+
+ void AccessibleTextHelper_Impl::ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException))
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ if( mbThisHasFocus )
+ SetShapeFocus( sal_False );
+
+ mbGroupHasFocus = sal_True;
+ maParaManager.SetFocus( nNewChild );
+
+ DBG_TRACE1("AccessibleTextHelper_Impl::ChangeChildFocus(): Paragraph %d received focus", nNewChild );
+ }
+
+ 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;
+
+ if( bOldFocus != bHaveFocus )
+ {
+ if( bHaveFocus )
+ {
+ GotPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
+ DBG_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object received focus" );
+ }
+ else
+ {
+ LostPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
+ DBG_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object lost focus" );
+ }
+ }
+ }
+
+ 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;
+
+ if( IsActive() )
+ {
+ try
+ {
+ // find the one with the cursor and get/set focus accordingly
+ ESelection aSelection;
+ if( GetEditViewForwarder().GetSelection( aSelection ) )
+ SetChildFocus( aSelection.nEndPara, bHaveFocus );
+ }
+ catch( const uno::Exception& ) {}
+ }
+ else if( bOldFocus != bHaveFocus )
+ {
+ SetShapeFocus( bHaveFocus );
+ }
+
+ DBG_TRACE2("AccessibleTextHelper_Impl::SetFocus: focus changed, Object %d, state: %s", this, bHaveFocus ? "focused" : "not focused");
+ }
+
+ 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;
+ }
+
+ sal_Bool AccessibleTextHelper_Impl::IsActive() const SAL_THROW((uno::RuntimeException))
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ try
+ {
+ SvxEditSource& rEditSource = GetEditSource();
+ SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder();
+
+ if( !pViewForwarder )
+ return sal_False;
+
+ if( pViewForwarder->IsValid() )
+ return sal_True;
+ else
+ return sal_False;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ return sal_False;
+ }
+ }
+
+ void AccessibleTextHelper_Impl::UpdateSelection()
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ try
+ {
+ ESelection aSelection;
+ if( GetEditViewForwarder().GetSelection( 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 nMaxValidParaIndex( static_cast< USHORT >( GetTextForwarder().GetParagraphCount() ) - 1 );
+
+ // notify all affected paragraphs (TODO: may be suboptimal,
+ // since some paragraphs might stay selected)
+ if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND )
+ {
+ // Did the caret move from one paragraph to another?
+ // #100530# no caret events if not focused.
+ if( mbGroupHasFocus &&
+ maLastSelection.nEndPara != aSelection.nEndPara )
+ {
+ if( maLastSelection.nEndPara < maParaManager.GetNum() )
+ {
+ maParaManager.FireEvent( ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ),
+ ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex )+1,
+ AccessibleEventId::CARET_CHANGED,
+ uno::makeAny(static_cast<sal_Int32>(-1)),
+ uno::makeAny(static_cast<sal_Int32>(maLastSelection.nEndPos)) );
+ }
+
+ ChangeChildFocus( aSelection.nEndPara );
+
+ DBG_TRACE3("AccessibleTextHelper_Impl::UpdateSelection(): focus changed, Object: %d, Paragraph: %d, Last paragraph: %d",
+ this, aSelection.nEndPara, maLastSelection.nEndPara);
+ }
+ }
+
+ // #100530# no caret events if not focused.
+ if( mbGroupHasFocus )
+ {
+ uno::Any aOldCursor;
+
+ // #i13705# The old cursor can only contain valid
+ // values if it's the same paragraph!
+ if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND &&
+ maLastSelection.nEndPara == aSelection.nEndPara )
+ {
+ aOldCursor <<= static_cast<sal_Int32>(maLastSelection.nEndPos);
+ }
+ else
+ {
+ aOldCursor <<= static_cast<sal_Int32>(-1);
+ }
+
+ maParaManager.FireEvent( aSelection.nEndPara,
+ aSelection.nEndPara+1,
+ AccessibleEventId::CARET_CHANGED,
+ uno::makeAny(static_cast<sal_Int32>(aSelection.nEndPos)),
+ aOldCursor );
+ }
+
+ 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);
+
+ // #108947# Sort new range before calling FireEvent
+ ::std::pair< xub_StrLen, xub_StrLen > sortedSelection(
+ makeSortedPair(::std::min( aSelection.nStartPara, nMaxValidParaIndex ),
+ ::std::min( aSelection.nEndPara, nMaxValidParaIndex ) ) );
+
+ // #108947# Sort last range before calling FireEvent
+ ::std::pair< xub_StrLen, xub_StrLen > sortedLastSelection(
+ makeSortedPair(::std::min( maLastSelection.nStartPara, nMaxValidParaIndex ),
+ ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ) ) );
+
+ // --> OD 2005-12-15 #i27299#
+ // event TEXT_SELECTION_CHANGED has to be submitted.
+ const sal_Int16 nTextSelChgEventId =
+ AccessibleEventId::TEXT_SELECTION_CHANGED;
+ // <--
+ // #107037# notify selection change
+ if( maLastSelection.nStartPara == EE_PARA_NOT_FOUND )
+ {
+ // last selection is undefined
+ // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()>
+ if ( aSelection.HasRange() )
+ // <--
+ {
+ // selection was undefined, now is on
+ maParaManager.FireEvent( sortedSelection.first,
+ sortedSelection.second+1,
+ nTextSelChgEventId );
+ }
+ }
+ else
+ {
+ // last selection is valid
+ // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()>
+ if ( maLastSelection.HasRange() &&
+ !aSelection.HasRange() )
+ // <--
+ {
+ // selection was on, now is empty
+ maParaManager.FireEvent( sortedLastSelection.first,
+ sortedLastSelection.second+1,
+ nTextSelChgEventId );
+ }
+ // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()>
+ else if( !maLastSelection.HasRange() &&
+ aSelection.HasRange() )
+ // <--
+ {
+ // selection was empty, now is on
+ maParaManager.FireEvent( sortedSelection.first,
+ sortedSelection.second+1,
+ nTextSelChgEventId );
+ }
+ // --> OD 2005-12-15 #i27299#
+ // - no event TEXT_SELECTION_CHANGED event, if new and
+ // last selection are empty.
+ else if ( maLastSelection.HasRange() &&
+ aSelection.HasRange() )
+ // <--
+ {
+ // --> OD 2005-12-16 #i27299#
+ // - send event TEXT_SELECTION_CHANGED for difference
+ // between last and new selection.
+// // selection was on, now is different: take union of ranges
+// maParaManager.FireEvent( ::std::min(sortedSelection.first,
+// sortedLastSelection.second),
+// ::std::max(sortedSelection.first,
+// sortedLastSelection.second)+1,
+// nTextSelChgEventId );
+ // use sorted last and new selection
+ ESelection aTmpLastSel( maLastSelection );
+ aTmpLastSel.Adjust();
+ ESelection aTmpSel( aSelection );
+ aTmpSel.Adjust();
+ // first submit event for new and changed selection
+ sal_uInt32 nPara = aTmpSel.nStartPara;
+ for ( ; nPara <= aTmpSel.nEndPara; ++nPara )
+ {
+ if ( nPara < aTmpLastSel.nStartPara ||
+ nPara > aTmpLastSel.nEndPara )
+ {
+ // new selection on paragraph <nPara>
+ maParaManager.FireEvent( nPara,
+ nTextSelChgEventId );
+ }
+ else
+ {
+ // check for changed selection on paragraph <nPara>
+ const xub_StrLen nParaStartPos =
+ nPara == aTmpSel.nStartPara
+ ? aTmpSel.nStartPos : 0;
+ const xub_StrLen nParaEndPos =
+ nPara == aTmpSel.nEndPara
+ ? aTmpSel.nEndPos : STRING_LEN;
+ const xub_StrLen nLastParaStartPos =
+ nPara == aTmpLastSel.nStartPara
+ ? aTmpLastSel.nStartPos : 0;
+ const xub_StrLen nLastParaEndPos =
+ nPara == aTmpLastSel.nEndPara
+ ? aTmpLastSel.nEndPos : STRING_LEN;
+ if ( nParaStartPos != nLastParaStartPos ||
+ nParaEndPos != nLastParaEndPos )
+ {
+ maParaManager.FireEvent(
+ nPara, nTextSelChgEventId );
+ }
+ }
+ }
+ // second submit event for 'old' selections
+ nPara = aTmpLastSel.nStartPara;
+ for ( ; nPara <= aTmpLastSel.nEndPara; ++nPara )
+ {
+ if ( nPara < aTmpSel.nStartPara ||
+ nPara > aTmpSel.nEndPara )
+ {
+ maParaManager.FireEvent( nPara,
+ nTextSelChgEventId );
+ }
+ }
+ }
+ }
+
+ maLastSelection = aSelection;
+ }
+ }
+ }
+ // no selection? no update actions
+ catch( const uno::RuntimeException& ) {}
+ }
+
+ 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
+ // a NULL EditSource (maParaManager.SetEditSource()), they
+ // enter the disposed state and cannot be reanimated. Thus, it
+ // is unavoidable and a hard requirement to let go and create
+ // from scratch each and every child.
+
+ // invalidate children
+ maParaManager.Dispose();
+ maParaManager.SetNum(0);
+
+ // lost all children
+ if( mxFrontEnd.is() )
+ FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
+
+ // quit listen on stale edit source
+ if( maEditSource.IsValid() )
+ EndListening( maEditSource.GetBroadcaster() );
+
+ maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) );
+ }
+
+ 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
+ ShutdownEditSource();
+
+ // set new edit source
+ maEditSource.SetEditSource( pEditSource );
+
+ // init child vector to the current child count
+ if( maEditSource.IsValid() )
+ {
+ maParaManager.SetNum( GetTextForwarder().GetParagraphCount() );
+
+ // listen on new edit source
+ StartListening( maEditSource.GetBroadcaster() );
+
+ UpdateVisibleChildren();
+ }
+ }
+
+ 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 );
+ maOffset = rPoint;
+ }
+
+ maParaManager.SetEEOffset( rPoint );
+
+ // in all cases, check visibility afterwards.
+ UpdateVisibleChildren();
+ UpdateBoundRect();
+ }
+
+ void AccessibleTextHelper_Impl::UpdateVisibleChildren( bool bBroadcastEvents )
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ try
+ {
+ SvxTextForwarder& rCacheTF = GetTextForwarder();
+ SvxViewForwarder& rCacheVF = GetViewForwarder();
+
+ Rectangle aViewArea = rCacheVF.GetVisArea();
+
+ if( IsActive() )
+ {
+ // maybe the edit view scrolls, adapt aViewArea
+ Rectangle aEditViewArea = GetEditViewForwarder().GetVisArea();
+ aViewArea += aEditViewArea.TopLeft();
+
+ // now determine intersection
+ aViewArea.Intersection( aEditViewArea );
+ }
+
+ Rectangle aTmpBB, aParaBB;
+ sal_Bool bFirstChild = sal_True;
+ sal_Int32 nCurrPara;
+ sal_Int32 nParas=rCacheTF.GetParagraphCount();
+
+ mnFirstVisibleChild = -1;
+ mnLastVisibleChild = -2;
+
+ for( nCurrPara=0; nCurrPara<nParas; ++nCurrPara )
+ {
+ DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX,
+ "AccessibleTextHelper_Impl::UpdateVisibleChildren: index value overflow");
+
+ aTmpBB = rCacheTF.GetParaBounds( static_cast< USHORT >( nCurrPara ) );
+
+ // convert to screen coordinates
+ aParaBB = ::accessibility::AccessibleEditableTextPara::LogicToPixel( aTmpBB, rCacheTF.GetMapMode(), rCacheVF );
+
+ if( aParaBB.IsOver( aViewArea ) )
+ {
+ // at least partially visible
+ if( bFirstChild )
+ {
+ bFirstChild = sal_False;
+ mnFirstVisibleChild = nCurrPara;
+ }
+
+ mnLastVisibleChild = nCurrPara;
+
+ // child not yet created?
+ ::accessibility::AccessibleParaManager::WeakChild aChild( maParaManager.GetChild(nCurrPara) );
+ if( aChild.second.Width == 0 &&
+ aChild.second.Height == 0 &&
+ mxFrontEnd.is() &&
+ bBroadcastEvents )
+ {
+ GotPropertyEvent( uno::makeAny( maParaManager.CreateChild( nCurrPara - mnFirstVisibleChild,
+ mxFrontEnd, GetEditSource(), nCurrPara ).first ),
+ AccessibleEventId::CHILD );
+ }
+ }
+ else
+ {
+ // not or no longer visible
+ if( maParaManager.IsReferencable( nCurrPara ) )
+ {
+ if( bBroadcastEvents )
+ LostPropertyEvent( uno::makeAny( maParaManager.GetChild( nCurrPara ).first.get().getRef() ),
+ AccessibleEventId::CHILD );
+
+ // clear reference
+ maParaManager.Release( nCurrPara );
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_ERROR("AccessibleTextHelper_Impl::UpdateVisibleChildren error while determining visible children");
+
+ // something failed - currently no children
+ mnFirstVisibleChild = -1;
+ mnLastVisibleChild = -2;
+ maParaManager.SetNum(0);
+
+ // lost all children
+ if( bBroadcastEvents )
+ FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
+ }
+ }
+
+ // functor for checking changes in paragraph bounding boxes (no stand-alone function, maybe not inlined)
+ class AccessibleTextHelper_UpdateChildBounds : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&,
+ ::accessibility::AccessibleParaManager::WeakChild >
+ {
+ public:
+ AccessibleTextHelper_UpdateChildBounds( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
+ ::accessibility::AccessibleParaManager::WeakChild operator()( const ::accessibility::AccessibleParaManager::WeakChild& rChild )
+ {
+ // retrieve hard reference from weak one
+ ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rChild.first.get() );
+
+ if( aHardRef.is() )
+ {
+ awt::Rectangle aNewRect = aHardRef->getBounds();
+ const awt::Rectangle& aOldRect = rChild.second;
+
+ if( aNewRect.X != aOldRect.X ||
+ aNewRect.Y != aOldRect.Y ||
+ aNewRect.Width != aOldRect.Width ||
+ aNewRect.Height != aOldRect.Height )
+ {
+ // visible data changed
+ aHardRef->FireEvent( AccessibleEventId::BOUNDRECT_CHANGED );
+
+ // update internal bounds
+ return ::accessibility::AccessibleParaManager::WeakChild( rChild.first, aNewRect );
+ }
+ }
+
+ // identity transform
+ return rChild;
+ }
+
+ private:
+ AccessibleTextHelper_Impl& mrImpl;
+ };
+
+ void AccessibleTextHelper_Impl::UpdateBoundRect()
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ // send BOUNDRECT_CHANGED to affected children
+ AccessibleTextHelper_UpdateChildBounds aFunctor( *this );
+ ::std::transform( maParaManager.begin(), maParaManager.end(), maParaManager.begin(), aFunctor );
+ }
+
+#ifdef DBG_UTIL
+ void AccessibleTextHelper_Impl::CheckInvariants() const
+ {
+ if( mnFirstVisibleChild >= 0 &&
+ mnFirstVisibleChild > mnLastVisibleChild )
+ {
+ DBG_ERROR( "AccessibleTextHelper: range invalid" );
+ }
+ }
+#endif
+
+ // functor for sending child events (no stand-alone function, they are maybe not inlined)
+ class AccessibleTextHelper_LostChildEvent : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&, void >
+ {
+ public:
+ AccessibleTextHelper_LostChildEvent( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
+ void operator()( const ::accessibility::AccessibleParaManager::WeakChild& rPara )
+ {
+ // retrieve hard reference from weak one
+ ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rPara.first.get() );
+
+ if( aHardRef.is() )
+ mrImpl.FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( aHardRef.getRef() ) );
+ }
+
+ private:
+ AccessibleTextHelper_Impl& mrImpl;
+ };
+
+ 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
+ * =================
+ *
+ * Three cases:
+ *
+ * 1.
+ * ... nParagraph ... nParam1 ... nParam2 ...
+ * |______________[xxxxxxxxxxx]
+ * becomes
+ * [xxxxxxxxxxx]|______________
+ *
+ * tail is 0
+ *
+ * 2.
+ * ... nParam1 ... nParagraph ... nParam2 ...
+ * [xxxxxxxxxxx|xxxxxxxxxxxxxx]____________
+ * becomes
+ * ____________[xxxxxxxxxxx|xxxxxxxxxxxxxx]
+ *
+ * tail is nParagraph - nParam1
+ *
+ * 3.
+ * ... nParam1 ... nParam2 ... nParagraph ...
+ * [xxxxxxxxxxx]___________|____________
+ * becomes
+ * ___________|____________[xxxxxxxxxxx]
+ *
+ * tail is nParam2 - nParam1
+ */
+
+ // sort nParagraph, nParam1 and nParam2 in ascending order, calc range
+ if( nMiddle < nFirst )
+ {
+ ::std::swap(nFirst, nMiddle);
+ }
+ else if( nMiddle < nLast )
+ {
+ nLast = nLast + nMiddle - nFirst;
+ }
+ else
+ {
+ ::std::swap(nMiddle, nLast);
+ nLast = nLast + nMiddle - nFirst;
+ }
+
+ if( nFirst < nParas && nMiddle < nParas && nLast < nParas )
+ {
+ // since we have no "paragraph index
+ // changed" event on UAA, remove
+ // [first,last] and insert again later (in
+ // UpdateVisibleChildren)
+
+ // maParaManager.Rotate( nFirst, nMiddle, nLast );
+
+ // send CHILD_EVENT to affected children
+ ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
+ ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
+
+ ::std::advance( begin, nFirst );
+ ::std::advance( end, nLast+1 );
+
+ // TODO: maybe optimize here in the following way. If the
+ // number of removed children exceeds a certain threshold,
+ // use INVALIDATE_CHILDREN
+ AccessibleTextHelper_LostChildEvent aFunctor( *this );
+
+ ::std::for_each( begin, end, aFunctor );
+
+ maParaManager.Release(nFirst, nLast+1);
+ // should be no need for UpdateBoundRect, since all affected children are cleared.
+ }
+ }
+
+ // functor for sending child events (no stand-alone function, they are maybe not inlined)
+ class AccessibleTextHelper_ChildrenTextChanged : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
+ {
+ public:
+ void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
+ {
+ rPara.TextChanged();
+ }
+ };
+
+ /** 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 >
+ {
+ 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 );
+
+ 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;
+ }
+ }
+ }
+ }
+
+ /** Query number of paragraphs changed during queue processing.
+
+ @return number of changed paragraphs, -1 for
+ "every paragraph changed"
+ */
+ int GetNumberOfParasChanged() { return mnParasChanged; }
+ /** Query index of last added/removed paragraph
+
+ @return index of lastly added paragraphs, -1 for none
+ added so far.
+ */
+ int GetParaIndex() { return mnParaIndex; }
+ /** Query hint id of last interesting event
+
+ @return hint id of last interesting event (REMOVED/INSERTED).
+ */
+ int GetHintId() { return mnHintId; }
+
+ 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;
+ };
+
+ 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
+ // 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
+ // #109864# Enforce creation of this paragraph
+ try
+ {
+ GotPropertyEvent( uno::makeAny( getAccessibleChild( aFunctor.GetParaIndex() -
+ mnFirstVisibleChild + GetStartIndex() ) ),
+ AccessibleEventId::CHILD );
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_ERROR("AccessibleTextHelper_Impl::ProcessQueue: could not create new paragraph");
+ }
+ }
+ 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 );
+
+ // #i61812# remember para to be removed for later notification
+ // AFTER the new state is applied (that after the para got removed)
+ ::uno::Reference< XAccessible > xPara;
+ ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( begin->first.get() );
+ if( aHardRef.is() )
+ xPara = ::uno::Reference< XAccessible >( aHardRef.getRef(), ::uno::UNO_QUERY );
+
+ // release everything from the remove position until the end
+ 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();
+
+ // #i61812# notification for removed para
+ if (xPara.is())
+ FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( xPara) );
+ }
+#ifdef DBG_UTIL
+ else
+ DBG_ERROR("AccessibleTextHelper_Impl::ProcessQueue() invalid hint id");
+#endif
+ }
+ else if( nNewParas != nCurrParas )
+ {
+ // release all paras
+ maParaManager.Release(0, nCurrParas);
+
+ // update num of paras
+ maParaManager.SetNum( nNewParas );
+
+ // #109864# create from scratch, don't broadcast
+ UpdateVisibleChildren( false );
+ UpdateBoundRect();
+
+ // number of paragraphs somehow changed - but we have no
+ // chance determining how. Thus, throw away everything and
+ // create from scratch.
+ // (child events should be broadcast after the changes are done...)
+ FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
+
+ // no need for further updates later on
+ bEverythingUpdated = true;
+ }
+
+ while( !maEventQueue.IsEmpty() )
+ {
+ ::std::auto_ptr< SfxHint > pHint( maEventQueue.PopFront() );
+ if( pHint.get() )
+ {
+ const SfxHint& rHint = *(pHint.get());
+
+ // 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();
+
+ 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() );
+
+ // #108900# Delegate change event to children
+ AccessibleTextHelper_ChildrenTextChanged aNotifyChildrenFunctor;
+
+ if( nPara == static_cast<sal_Int32>(EE_PARA_ALL) )
+ {
+ // #108900# Call every child
+ ::std::for_each( maParaManager.begin(), maParaManager.end(),
+ AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
+ }
+ else
+ if( nPara < nParas )
+ {
+ // #108900# Call child at index nPara
+ ::std::for_each( maParaManager.begin()+nPara, maParaManager.begin()+nPara+1,
+ AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
+ }
+ 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;
+ }
+
+ // in all cases, check visibility afterwards.
+ UpdateVisibleChildren();
+ UpdateBoundRect();
+ }
+ else if( pViewHint )
+ {
+ switch( pViewHint->GetHintType() )
+ {
+ case SvxViewHint::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;
+ }
+ default:
+ 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 )
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ // precondition: not in a recursion
+ if( mbInNotify )
+ return;
+
+ mbInNotify = sal_True;
+
+ // 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
+ {
+ // Process notification event
+ if( pEditSourceHint )
+ {
+ maEventQueue.Append( *pEditSourceHint );
+ // --> OD 2005-12-19 #i27299#
+ if( maEventOpenFrames == 0 )
+ ProcessQueue();
+ // <--
+ }
+ else if( pTextHint )
+ {
+ switch( pTextHint->GetId() )
+ {
+ case TEXT_HINT_BLOCKNOTIFICATION_END:
+ case TEXT_HINT_INPUT_END:
+ --maEventOpenFrames;
+
+ 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_BLOCKNOTIFICATION_START:
+ case TEXT_HINT_INPUT_START:
+ ++maEventOpenFrames;
+ // --> OD 2005-12-19 #i27299# - no FALLTROUGH
+ // reason: event will not be processes, thus appending
+ // the event isn't necessary.
+ break;
+ // <--
+ default:
+ maEventQueue.Append( *pTextHint );
+ // --> OD 2005-12-19 #i27299#
+ if( maEventOpenFrames == 0 )
+ ProcessQueue();
+ // <--
+ break;
+ }
+ }
+ else if( pViewHint )
+ {
+ 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 )
+ {
+ 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
+ // 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::Notify: Unhandled exception.");
+#endif
+ mbInNotify = sal_False;
+ }
+
+ mbInNotify = sal_False;
+ }
+
+ void AccessibleTextHelper_Impl::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() )
+ EndListening( maEditSource.GetBroadcaster() );
+
+ // clear references
+ maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) );
+ mxFrontEnd = NULL;
+ }
+
+ 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 );
+
+ AccessibleEventObject aEvent;
+
+ DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper::FireEvent: no event source set" );
+
+ if( mxFrontEnd.is() )
+ aEvent = AccessibleEventObject(mxFrontEnd->getAccessibleContext(), nEventId, rNewValue, rOldValue);
+ else
+ aEvent = AccessibleEventObject(uno::Reference< uno::XInterface >(), nEventId, rNewValue, rOldValue);
+
+ // 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 --
+
+ FireEvent(aEvent);
+ }
+
+ void AccessibleTextHelper_Impl::FireEvent( const AccessibleEventObject& rEvent ) const
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ // #102261# Call global queue for focus events
+ if( rEvent.EventId == AccessibleStateType::FOCUSED )
+ vcl::unohelper::NotifyAccessibleStateEventGlobally( rEvent );
+
+ // #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() ||
+ GetTextForwarder().GetParagraphCount() <= i )
+ {
+ throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid child index")), mxFrontEnd);
+ }
+
+ DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper_Impl::UpdateVisibleChildren: no frontend set");
+
+ if( mxFrontEnd.is() )
+ return maParaManager.CreateChild( i, mxFrontEnd, GetEditSource(), mnFirstVisibleChild + i ).first;
+ else
+ return NULL;
+ }
+
+ void SAL_CALL AccessibleTextHelper_Impl::addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
+ {
+ 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))
+ {
+ DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
+
+ if( getNotifierClientId() != -1 )
+ ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener );
+ }
+
+ uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleAtPoint( 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 );
+
+ uno::Reference< XAccessibleContext > xFrontEndContext = mxFrontEnd->getAccessibleContext();
+
+ if( !xFrontEndContext.is() )
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd );
+
+ uno::Reference< XAccessibleComponent > xFrontEndComponent( xFrontEndContext, uno::UNO_QUERY );
+
+ if( !xFrontEndComponent.is() )
+ throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend is no XAccessibleComponent")),
+ mxFrontEnd );
+
+ // #103862# No longer need to make given position relative
+ Point aPoint( _aPoint.X, _aPoint.Y );
+
+ // respect EditEngine offset to surrounding shape/cell
+ aPoint -= GetOffset();
+
+ // convert to EditEngine coordinate system
+ SvxTextForwarder& rCacheTF = GetTextForwarder();
+ Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) );
+
+ // iterate over all visible children (including those not yet created)
+ sal_Int32 nChild;
+ for( nChild=mnFirstVisibleChild; nChild <= mnLastVisibleChild; ++nChild )
+ {
+ DBG_ASSERT(nChild >= 0 && nChild <= USHRT_MAX,
+ "AccessibleTextHelper_Impl::getAccessibleAt: index value overflow");
+
+ Rectangle aParaBounds( rCacheTF.GetParaBounds( static_cast< USHORT > (nChild) ) );
+
+ if( aParaBounds.IsInside( aLogPoint ) )
+ return getAccessibleChild( nChild - mnFirstVisibleChild + GetStartIndex() );
+ }
+
+ // found none
+ return NULL;
+ }
+
+ //------------------------------------------------------------------------
+ //
+ // AccessibleTextHelper implementation (simply forwards to impl)
+ //
+ //------------------------------------------------------------------------
+
+ AccessibleTextHelper::AccessibleTextHelper( ::std::auto_ptr< SvxEditSource > pEditSource ) :
+ mpImpl( new AccessibleTextHelper_Impl() )
+ {
+ ::vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ SetEditSource( pEditSource );
+ }
+
+ AccessibleTextHelper::~AccessibleTextHelper()
+ {
+ }
+
+ const SvxEditSource& AccessibleTextHelper::GetEditSource() const SAL_THROW((uno::RuntimeException))
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ const SvxEditSource& aEditSource = mpImpl->GetEditSource();
+
+ mpImpl->CheckInvariants();
+
+ return aEditSource;
+#else
+ return mpImpl->GetEditSource();
+#endif
+ }
+
+ void AccessibleTextHelper::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetEditSource( pEditSource );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ void AccessibleTextHelper::SetEventSource( const uno::Reference< XAccessible >& rInterface )
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetEventSource( rInterface );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ uno::Reference< XAccessible > AccessibleTextHelper::GetEventSource() const
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
+
+ mpImpl->CheckInvariants();
+
+ return xRet;
+#else
+ return mpImpl->GetEventSource();
+#endif
+ }
+
+ void AccessibleTextHelper::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetFocus( bHaveFocus );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ sal_Bool AccessibleTextHelper::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException))
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ sal_Bool bRet( mpImpl->HaveFocus() );
+
+ mpImpl->CheckInvariants();
+
+ return bRet;
+#else
+ return mpImpl->HaveFocus();
+#endif
+ }
+
+ void AccessibleTextHelper::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->FireEvent( nEventId, rNewValue, rOldValue );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ void AccessibleTextHelper::FireEvent( const AccessibleEventObject& rEvent ) const
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->FireEvent( rEvent );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ void AccessibleTextHelper::SetOffset( const Point& rPoint )
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetOffset( rPoint );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ Point AccessibleTextHelper::GetOffset() const
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ Point aPoint( mpImpl->GetOffset() );
+
+ mpImpl->CheckInvariants();
+
+ return aPoint;
+#else
+ return mpImpl->GetOffset();
+#endif
+ }
+
+ void AccessibleTextHelper::SetStartIndex( sal_Int32 nOffset )
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetStartIndex( nOffset );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ sal_Int32 AccessibleTextHelper::GetStartIndex() const
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ sal_Int32 nOffset = mpImpl->GetStartIndex();
+
+ mpImpl->CheckInvariants();
+
+ return nOffset;
+#else
+ return mpImpl->GetStartIndex();
+#endif
+ }
+
+ void AccessibleTextHelper::SetAdditionalChildStates( const VectorOfStates& rChildStates )
+ {
+ mpImpl->SetAdditionalChildStates( rChildStates );
+ }
+
+ const AccessibleTextHelper::VectorOfStates& AccessibleTextHelper::GetAdditionalChildStates() const
+ {
+ return mpImpl->GetAdditionalChildStates();
+ }
+
+ void AccessibleTextHelper::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->UpdateVisibleChildren();
+ mpImpl->UpdateBoundRect();
+
+ mpImpl->UpdateSelection();
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ void AccessibleTextHelper::Dispose()
+ {
+ // As Dispose calls ShutdownEditSource, which in turn
+ // deregisters as listener on the edit source, have to lock
+ // here
+ ::vos::OGuard aGuard( Application::GetSolarMutex() );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->Dispose();
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ sal_Bool AccessibleTextHelper::IsSelected() const
+ {
+ ::vos::OGuard aGuard( Application::GetSolarMutex() );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ sal_Bool aRet = mpImpl->IsSelected();
+
+ mpImpl->CheckInvariants();
+
+ return aRet;
+#else
+ return mpImpl->IsSelected();
+#endif
+ }
+
+ // XAccessibleContext
+ sal_Int32 AccessibleTextHelper::GetChildCount() SAL_THROW((uno::RuntimeException))
+ {
+ ::vos::OGuard aGuard( Application::GetSolarMutex() );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ sal_Int32 nRet = mpImpl->getAccessibleChildCount();
+
+ mpImpl->CheckInvariants();
+
+ return nRet;
+#else
+ return mpImpl->getAccessibleChildCount();
+#endif
+ }
+
+ uno::Reference< XAccessible > AccessibleTextHelper::GetChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException))
+ {
+ ::vos::OGuard aGuard( Application::GetSolarMutex() );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ uno::Reference< XAccessible > xRet = mpImpl->getAccessibleChild( i );
+
+ mpImpl->CheckInvariants();
+
+ return xRet;
+#else
+ return mpImpl->getAccessibleChild( i );
+#endif
+ }
+
+ void AccessibleTextHelper::AddEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ mpImpl->addEventListener( xListener );
+
+ mpImpl->CheckInvariants();
+#else
+ mpImpl->addEventListener( xListener );
+#endif
+ }
+
+ void AccessibleTextHelper::RemoveEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ mpImpl->removeEventListener( xListener );
+
+ mpImpl->CheckInvariants();
+#else
+ mpImpl->removeEventListener( xListener );
+#endif
+ }
+
+ // XAccessibleComponent
+ uno::Reference< XAccessible > AccessibleTextHelper::GetAt( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException))
+ {
+ ::vos::OGuard aGuard( Application::GetSolarMutex() );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ uno::Reference< XAccessible > xChild = mpImpl->getAccessibleAtPoint( aPoint );
+
+ mpImpl->CheckInvariants();
+
+ return xChild;
+#else
+ return mpImpl->getAccessibleAtPoint( aPoint );
+#endif
+ }
+
+} // end of namespace accessibility
+
+//------------------------------------------------------------------------