Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / svx / source / accessibility / AccessibleTextHelper.cxx
blobe642b2438a00a67ab672155af65347cbd8ec71f0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 //------------------------------------------------------------------------
32 // Global header
34 //------------------------------------------------------------------------
36 #include <limits.h>
37 #include <memory>
38 #include <algorithm>
39 #include <deque>
40 #include <osl/mutex.hxx>
41 #include <com/sun/star/uno/Any.hxx>
42 #include <com/sun/star/uno/Reference.hxx>
43 #include <cppuhelper/weakref.hxx>
44 #include <com/sun/star/awt/Point.hpp>
45 #include <com/sun/star/awt/Rectangle.hpp>
46 #include <com/sun/star/lang/DisposedException.hpp>
47 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
48 #include <com/sun/star/accessibility/XAccessible.hpp>
49 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
50 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
51 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
52 #include <comphelper/accessibleeventnotifier.hxx>
53 #include <unotools/accessiblestatesethelper.hxx>
54 #include <vcl/unohelp.hxx>
55 #include <vcl/svapp.hxx>
57 //------------------------------------------------------------------------
59 // Project-local header
61 //------------------------------------------------------------------------
62 #include "AccessibleTextEventQueue.hxx"
63 #include <svx/AccessibleTextHelper.hxx>
64 #include <svx/unoshape.hxx>
65 #include "editeng/unolingu.hxx"
66 #include <editeng/unotext.hxx>
68 #include "editeng/unoedhlp.hxx"
69 #include "editeng/unopracc.hxx"
70 #include "editeng/AccessibleParaManager.hxx"
71 #include "editeng/AccessibleEditableTextPara.hxx"
72 #include <svx/svdmodel.hxx>
73 #include <svx/svdpntv.hxx>
74 #include <editeng/editdata.hxx>
75 #include <editeng/editeng.hxx>
76 #include <editeng/editview.hxx>
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::accessibility;
81 namespace accessibility
84 //------------------------------------------------------------------------
86 // AccessibleTextHelper_Impl declaration
88 //------------------------------------------------------------------------
90 DBG_NAME( AccessibleTextHelper_Impl )
92 template < typename first_type, typename second_type >
93 ::std::pair< first_type, second_type > makeSortedPair( first_type first,
94 second_type second )
96 if( first > second )
97 return ::std::make_pair( second, first );
98 else
99 return ::std::make_pair( first, second );
102 class AccessibleTextHelper_Impl : public SfxListener
105 public:
106 typedef ::std::vector< sal_Int16 > VectorOfStates;
108 // receive pointer to our frontend class and view window
109 AccessibleTextHelper_Impl();
110 ~AccessibleTextHelper_Impl();
112 // XAccessibleContext child handling methods
113 sal_Int32 SAL_CALL getAccessibleChildCount() SAL_THROW((uno::RuntimeException));
114 uno::Reference< XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException));
116 // XAccessibleEventBroadcaster child related methods
117 void SAL_CALL addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException));
118 void SAL_CALL removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException));
120 // XAccessibleComponent child related methods
121 uno::Reference< XAccessible > SAL_CALL getAccessibleAtPoint( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException));
123 SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException));
124 SAL_WNODEPRECATED_DECLARATIONS_PUSH
125 void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException));
126 SAL_WNODEPRECATED_DECLARATIONS_POP
128 void SetEventSource( const uno::Reference< XAccessible >& rInterface )
130 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
131 mxFrontEnd = rInterface;
133 uno::Reference< XAccessible > GetEventSource() const
135 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
136 return mxFrontEnd;
139 void SetOffset( const Point& );
140 Point GetOffset() const
142 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
143 ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset );
144 return aPoint;
147 void SetStartIndex( sal_Int32 nOffset );
148 sal_Int32 GetStartIndex() const
150 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
151 // Strictly correct only with locked solar mutex, // but
152 // here we rely on the fact that sal_Int32 access is
153 // atomic
154 return mnStartIndex;
157 void SetAdditionalChildStates( const VectorOfStates& rChildStates );
159 sal_Bool IsSelected() const;
161 void Dispose();
163 // do NOT hold object mutex when calling this! Danger of deadlock
164 void FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue = uno::Any(), const uno::Any& rOldValue = uno::Any() ) const;
165 void FireEvent( const AccessibleEventObject& rEvent ) const;
167 void SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
168 sal_Bool HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException));
169 void SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
170 void SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
171 void ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException));
173 #ifdef DBG_UTIL
174 void CheckInvariants() const;
175 #endif
177 // checks all children for visibility, throws away invisible ones
178 void UpdateVisibleChildren( bool bBroadcastEvents=true );
180 // check all children for changes in position and size
181 void UpdateBoundRect();
183 // calls SetSelection on the forwarder and updates maLastSelection
184 // cache.
185 void UpdateSelection();
187 private:
189 // Process event queue
190 void ProcessQueue();
192 // syntactic sugar for FireEvent
193 void GotPropertyEvent( const uno::Any& rNewValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, rNewValue ); }
194 void LostPropertyEvent( const uno::Any& rOldValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, uno::Any(), rOldValue ); }
196 // shutdown usage of current edit source on myself and the children.
197 void ShutdownEditSource() SAL_THROW((uno::RuntimeException));
199 void ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast );
201 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
203 int getNotifierClientId() const { return mnNotifierClientId; }
205 // lock solar mutex before
206 SvxTextForwarder& GetTextForwarder() const SAL_THROW((uno::RuntimeException));
207 // lock solar mutex before
208 SvxViewForwarder& GetViewForwarder() const SAL_THROW((uno::RuntimeException));
209 // lock solar mutex before
210 SvxEditViewForwarder& GetEditViewForwarder( sal_Bool bCreate = sal_False ) const SAL_THROW((uno::RuntimeException));
212 // are we in edit mode?
213 sal_Bool IsActive() const SAL_THROW((uno::RuntimeException));
215 // our frontend class (the one implementing the actual
216 // interface). That's not necessarily the one containing the impl
217 // pointer!
218 uno::Reference< XAccessible > mxFrontEnd;
220 // a wrapper for the text forwarders (guarded by solar mutex)
221 mutable SvxEditSourceAdapter maEditSource;
223 // store last selection (to correctly report selection changes, guarded by solar mutex)
224 ESelection maLastSelection;
226 // cache range of visible children (guarded by solar mutex)
227 sal_Int32 mnFirstVisibleChild;
228 sal_Int32 mnLastVisibleChild;
230 // offset to add to all our children (unguarded, relying on
231 // the fact that sal_Int32 access is atomic)
232 sal_Int32 mnStartIndex;
234 // the object handling our children (guarded by solar mutex)
235 ::accessibility::AccessibleParaManager maParaManager;
237 // number of not-yet-closed event frames (BEGIN/END sequences) (guarded by solar mutex)
238 sal_Int32 maEventOpenFrames;
240 // Queued events from Notify() (guarded by solar mutex)
241 AccessibleTextEventQueue maEventQueue;
243 // spin lock to prevent notify in notify (guarded by solar mutex)
244 sal_Bool mbInNotify;
246 // whether the object or it's children has the focus set (guarded by solar mutex)
247 sal_Bool mbGroupHasFocus;
249 // whether we (this object) has the focus set (guarded by solar mutex)
250 sal_Bool mbThisHasFocus;
252 mutable ::osl::Mutex maMutex;
254 /// our current offset to the containing shape/cell (guarded by maMutex)
255 Point maOffset;
257 /// client Id from AccessibleEventNotifier
258 int mnNotifierClientId;
261 //------------------------------------------------------------------------
263 // AccessibleTextHelper_Impl implementation
265 //------------------------------------------------------------------------
267 AccessibleTextHelper_Impl::AccessibleTextHelper_Impl() :
268 mxFrontEnd( NULL ),
269 maLastSelection( EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND ),
270 mnFirstVisibleChild( -1 ),
271 mnLastVisibleChild( -2 ),
272 mnStartIndex( 0 ),
273 maEventOpenFrames( 0 ),
274 mbInNotify( sal_False ),
275 mbGroupHasFocus( sal_False ),
276 mbThisHasFocus( sal_False ),
277 maOffset(0,0),
278 // well, that's strictly exception safe, though not really
279 // robust. We rely on the fact that this member is constructed
280 // last, and that the constructor body is empty, thus no
281 // chance for exceptions once the Id is fetched. Nevertheless,
282 // normally should employ RAII here...
283 mnNotifierClientId(::comphelper::AccessibleEventNotifier::registerClient())
285 DBG_CTOR( AccessibleTextHelper_Impl, NULL );
287 #ifdef DBG_UTIL
288 OSL_TRACE( "AccessibleTextHelper_Impl received ID: %d", mnNotifierClientId );
289 #endif
292 AccessibleTextHelper_Impl::~AccessibleTextHelper_Impl()
294 DBG_DTOR( AccessibleTextHelper_Impl, NULL );
296 SolarMutexGuard aGuard;
300 // call Dispose here, too, since we've some resources not
301 // automatically freed otherwise
302 Dispose();
304 catch( const uno::Exception& ) {}
307 SvxTextForwarder& AccessibleTextHelper_Impl::GetTextForwarder() const SAL_THROW((uno::RuntimeException))
309 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
311 if( !maEditSource.IsValid() )
312 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
314 SvxTextForwarder* pTextForwarder = maEditSource.GetTextForwarder();
316 if( !pTextForwarder )
317 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch text forwarder, model might be dead")), mxFrontEnd);
319 if( pTextForwarder->IsValid() )
320 return *pTextForwarder;
321 else
322 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Text forwarder is invalid, model might be dead")), mxFrontEnd);
325 SvxViewForwarder& AccessibleTextHelper_Impl::GetViewForwarder() const SAL_THROW((uno::RuntimeException))
327 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
329 if( !maEditSource.IsValid() )
330 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
332 SvxViewForwarder* pViewForwarder = maEditSource.GetViewForwarder();
334 if( !pViewForwarder )
335 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch view forwarder, model might be dead")), mxFrontEnd);
337 if( pViewForwarder->IsValid() )
338 return *pViewForwarder;
339 else
340 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, model might be dead")), mxFrontEnd);
343 SvxEditViewForwarder& AccessibleTextHelper_Impl::GetEditViewForwarder( sal_Bool bCreate ) const SAL_THROW((uno::RuntimeException))
345 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
347 if( !maEditSource.IsValid() )
348 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
350 SvxEditViewForwarder* pViewForwarder = maEditSource.GetEditViewForwarder( bCreate );
352 if( !pViewForwarder )
354 if( bCreate )
355 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch edit view forwarder, model might be dead")), mxFrontEnd);
356 else
357 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No edit view forwarder, object not in edit mode")), mxFrontEnd);
360 if( pViewForwarder->IsValid() )
361 return *pViewForwarder;
362 else
364 if( bCreate )
365 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, model might be dead")), mxFrontEnd);
366 else
367 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, object not in edit mode")), mxFrontEnd);
371 SvxEditSourceAdapter& AccessibleTextHelper_Impl::GetEditSource() const SAL_THROW((uno::RuntimeException))
373 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
375 if( maEditSource.IsValid() )
376 return maEditSource;
377 else
378 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::GetEditSource: no edit source")), mxFrontEnd );
381 sal_Bool AccessibleTextHelper_Impl::IsSelected() const
383 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
385 sal_Bool bRet = sal_False;
389 ESelection aSelection;
390 bRet = GetEditViewForwarder().GetSelection( aSelection );
392 catch( const uno::Exception& ) {}
394 return bRet;
397 // functor for sending child events (no stand-alone function, they are maybe not inlined)
398 class AccessibleTextHelper_OffsetChildIndex : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
400 public:
401 AccessibleTextHelper_OffsetChildIndex( sal_Int32 nDifference ) : mnDifference(nDifference) {}
402 void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
404 rPara.SetIndexInParent( rPara.GetIndexInParent() + mnDifference );
407 private:
408 const sal_Int32 mnDifference;
411 void AccessibleTextHelper_Impl::SetStartIndex( sal_Int32 nOffset )
413 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
415 sal_Int32 nOldOffset( mnStartIndex );
417 mnStartIndex = nOffset;
419 if( nOldOffset != nOffset )
421 // update children
422 AccessibleTextHelper_OffsetChildIndex aFunctor( nOffset - nOldOffset );
424 ::std::for_each( maParaManager.begin(), maParaManager.end(),
425 AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_OffsetChildIndex > (aFunctor) );
429 void AccessibleTextHelper_Impl::SetAdditionalChildStates( const VectorOfStates& rChildStates )
431 maParaManager.SetAdditionalChildStates( rChildStates );
434 void AccessibleTextHelper_Impl::SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
436 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
438 if( bHaveFocus )
440 if( mbThisHasFocus )
441 SetShapeFocus( sal_False );
443 maParaManager.SetFocus( nChild );
445 // we just received the focus, also send caret event then
446 UpdateSelection();
448 OSL_TRACE("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d received focus", nChild );
450 else
452 maParaManager.SetFocus( -1 );
454 OSL_TRACE("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d lost focus", nChild );
456 if( mbGroupHasFocus )
457 SetShapeFocus( sal_True );
461 void AccessibleTextHelper_Impl::ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException))
463 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
465 if( mbThisHasFocus )
466 SetShapeFocus( sal_False );
468 mbGroupHasFocus = sal_True;
469 maParaManager.SetFocus( nNewChild );
471 OSL_TRACE("AccessibleTextHelper_Impl::ChangeChildFocus(): Paragraph %d received focus", nNewChild );
474 void AccessibleTextHelper_Impl::SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
476 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
478 sal_Bool bOldFocus( mbThisHasFocus );
480 mbThisHasFocus = bHaveFocus;
482 if( bOldFocus != bHaveFocus )
484 if( bHaveFocus )
486 GotPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
487 OSL_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object received focus" );
489 else
491 LostPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
492 OSL_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object lost focus" );
497 void AccessibleTextHelper_Impl::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
499 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
501 sal_Bool bOldFocus( mbGroupHasFocus );
503 mbGroupHasFocus = bHaveFocus;
505 if( IsActive() )
509 // find the one with the cursor and get/set focus accordingly
510 ESelection aSelection;
511 if( GetEditViewForwarder().GetSelection( aSelection ) )
512 SetChildFocus( aSelection.nEndPara, bHaveFocus );
514 catch( const uno::Exception& ) {}
516 else if( bOldFocus != bHaveFocus )
518 SetShapeFocus( bHaveFocus );
521 OSL_TRACE("AccessibleTextHelper_Impl::SetFocus: focus changed, Object %d, state: %s", this, bHaveFocus ? "focused" : "not focused");
524 sal_Bool AccessibleTextHelper_Impl::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException))
526 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
528 // No locking of solar mutex here, since we rely on the fact
529 // that sal_Bool access is atomic
530 return mbThisHasFocus;
533 sal_Bool AccessibleTextHelper_Impl::IsActive() const SAL_THROW((uno::RuntimeException))
535 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
539 SvxEditSource& rEditSource = GetEditSource();
540 SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder();
542 if( !pViewForwarder )
543 return sal_False;
545 if( pViewForwarder->IsValid() )
546 return sal_True;
547 else
548 return sal_False;
550 catch( const uno::RuntimeException& )
552 return sal_False;
556 void AccessibleTextHelper_Impl::UpdateSelection()
558 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
562 ESelection aSelection;
563 if( GetEditViewForwarder().GetSelection( aSelection ) )
565 if( !maLastSelection.IsEqual( aSelection ) &&
566 aSelection.nEndPara < maParaManager.GetNum() )
568 // #103998# Not that important, changed from assertion to trace
569 if( mbThisHasFocus )
571 OSL_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): Parent has focus!");
574 sal_uInt16 nMaxValidParaIndex( static_cast< sal_uInt16 >( GetTextForwarder().GetParagraphCount() ) - 1 );
576 // notify all affected paragraphs (TODO: may be suboptimal,
577 // since some paragraphs might stay selected)
578 if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND )
580 // Did the caret move from one paragraph to another?
581 // #100530# no caret events if not focused.
582 if( mbGroupHasFocus &&
583 maLastSelection.nEndPara != aSelection.nEndPara )
585 if( maLastSelection.nEndPara < maParaManager.GetNum() )
587 maParaManager.FireEvent( ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ),
588 ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex )+1,
589 AccessibleEventId::CARET_CHANGED,
590 uno::makeAny(static_cast<sal_Int32>(-1)),
591 uno::makeAny(static_cast<sal_Int32>(maLastSelection.nEndPos)) );
594 ChangeChildFocus( aSelection.nEndPara );
596 OSL_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): focus changed, Object: %d, Paragraph: %d, Last paragraph: %d",
597 this, aSelection.nEndPara, maLastSelection.nEndPara);
601 // #100530# no caret events if not focused.
602 if( mbGroupHasFocus )
604 uno::Any aOldCursor;
606 // #i13705# The old cursor can only contain valid
607 // values if it's the same paragraph!
608 if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND &&
609 maLastSelection.nEndPara == aSelection.nEndPara )
611 aOldCursor <<= static_cast<sal_Int32>(maLastSelection.nEndPos);
613 else
615 aOldCursor <<= static_cast<sal_Int32>(-1);
618 maParaManager.FireEvent( aSelection.nEndPara,
619 aSelection.nEndPara+1,
620 AccessibleEventId::CARET_CHANGED,
621 uno::makeAny(static_cast<sal_Int32>(aSelection.nEndPos)),
622 aOldCursor );
625 OSL_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): caret changed, Object: %d, New pos: %d, Old pos: %d, New para: %d, Old para: %d",
626 this, aSelection.nEndPos, maLastSelection.nEndPos, aSelection.nEndPara, maLastSelection.nEndPara);
628 // #108947# Sort new range before calling FireEvent
629 ::std::pair< xub_StrLen, xub_StrLen > sortedSelection(
630 makeSortedPair(::std::min( aSelection.nStartPara, nMaxValidParaIndex ),
631 ::std::min( aSelection.nEndPara, nMaxValidParaIndex ) ) );
633 // #108947# Sort last range before calling FireEvent
634 ::std::pair< xub_StrLen, xub_StrLen > sortedLastSelection(
635 makeSortedPair(::std::min( maLastSelection.nStartPara, nMaxValidParaIndex ),
636 ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ) ) );
638 // event TEXT_SELECTION_CHANGED has to be submitted. (#i27299#)
639 const sal_Int16 nTextSelChgEventId =
640 AccessibleEventId::TEXT_SELECTION_CHANGED;
641 // #107037# notify selection change
642 if( maLastSelection.nStartPara == EE_PARA_NOT_FOUND )
644 // last selection is undefined
645 // use method <ESelection::HasRange()> (#i27299#)
646 if ( aSelection.HasRange() )
648 // selection was undefined, now is on
649 maParaManager.FireEvent( sortedSelection.first,
650 sortedSelection.second+1,
651 nTextSelChgEventId );
654 else
656 // last selection is valid
657 // use method <ESelection::HasRange()> (#i27299#)
658 if ( maLastSelection.HasRange() &&
659 !aSelection.HasRange() )
661 // selection was on, now is empty
662 maParaManager.FireEvent( sortedLastSelection.first,
663 sortedLastSelection.second+1,
664 nTextSelChgEventId );
666 // use method <ESelection::HasRange()> (#i27299#)
667 else if( !maLastSelection.HasRange() &&
668 aSelection.HasRange() )
670 // selection was empty, now is on
671 maParaManager.FireEvent( sortedSelection.first,
672 sortedSelection.second+1,
673 nTextSelChgEventId );
675 // no event TEXT_SELECTION_CHANGED event, if new and
676 // last selection are empty. (#i27299#)
677 else if ( maLastSelection.HasRange() &&
678 aSelection.HasRange() )
680 // use sorted last and new selection
681 ESelection aTmpLastSel( maLastSelection );
682 aTmpLastSel.Adjust();
683 ESelection aTmpSel( aSelection );
684 aTmpSel.Adjust();
685 // first submit event for new and changed selection
686 sal_uInt32 nPara = aTmpSel.nStartPara;
687 for ( ; nPara <= aTmpSel.nEndPara; ++nPara )
689 if ( nPara < aTmpLastSel.nStartPara ||
690 nPara > aTmpLastSel.nEndPara )
692 // new selection on paragraph <nPara>
693 maParaManager.FireEvent( nPara,
694 nTextSelChgEventId );
696 else
698 // check for changed selection on paragraph <nPara>
699 const xub_StrLen nParaStartPos =
700 nPara == aTmpSel.nStartPara
701 ? aTmpSel.nStartPos : 0;
702 const xub_StrLen nParaEndPos =
703 nPara == aTmpSel.nEndPara
704 ? aTmpSel.nEndPos : STRING_LEN;
705 const xub_StrLen nLastParaStartPos =
706 nPara == aTmpLastSel.nStartPara
707 ? aTmpLastSel.nStartPos : 0;
708 const xub_StrLen nLastParaEndPos =
709 nPara == aTmpLastSel.nEndPara
710 ? aTmpLastSel.nEndPos : STRING_LEN;
711 if ( nParaStartPos != nLastParaStartPos ||
712 nParaEndPos != nLastParaEndPos )
714 maParaManager.FireEvent(
715 nPara, nTextSelChgEventId );
719 // second submit event for 'old' selections
720 nPara = aTmpLastSel.nStartPara;
721 for ( ; nPara <= aTmpLastSel.nEndPara; ++nPara )
723 if ( nPara < aTmpSel.nStartPara ||
724 nPara > aTmpSel.nEndPara )
726 maParaManager.FireEvent( nPara,
727 nTextSelChgEventId );
733 maLastSelection = aSelection;
737 // no selection? no update actions
738 catch( const uno::RuntimeException& ) {}
741 void AccessibleTextHelper_Impl::ShutdownEditSource() SAL_THROW((uno::RuntimeException))
743 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
745 // This should only be called with solar mutex locked, i.e. from the main office thread
747 // This here is somewhat clumsy: As soon as our children have
748 // a NULL EditSource (maParaManager.SetEditSource()), they
749 // enter the disposed state and cannot be reanimated. Thus, it
750 // is unavoidable and a hard requirement to let go and create
751 // from scratch each and every child.
753 // invalidate children
754 maParaManager.Dispose();
755 maParaManager.SetNum(0);
757 // lost all children
758 if( mxFrontEnd.is() )
759 FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
761 // quit listen on stale edit source
762 if( maEditSource.IsValid() )
763 EndListening( maEditSource.GetBroadcaster() );
765 SAL_WNODEPRECATED_DECLARATIONS_PUSH
766 maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) );
767 SAL_WNODEPRECATED_DECLARATIONS_POP
770 SAL_WNODEPRECATED_DECLARATIONS_PUSH
771 void AccessibleTextHelper_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
773 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
775 // This should only be called with solar mutex locked, i.e. from the main office thread
777 // shutdown old edit source
778 ShutdownEditSource();
780 // set new edit source
781 maEditSource.SetEditSource( pEditSource );
783 // init child vector to the current child count
784 if( maEditSource.IsValid() )
786 maParaManager.SetNum( GetTextForwarder().GetParagraphCount() );
788 // listen on new edit source
789 StartListening( maEditSource.GetBroadcaster() );
791 UpdateVisibleChildren();
794 SAL_WNODEPRECATED_DECLARATIONS_POP
796 void AccessibleTextHelper_Impl::SetOffset( const Point& rPoint )
798 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
800 // guard against non-atomic access to maOffset data structure
802 ::osl::MutexGuard aGuard( maMutex );
803 maOffset = rPoint;
806 maParaManager.SetEEOffset( rPoint );
808 // in all cases, check visibility afterwards.
809 UpdateVisibleChildren();
810 UpdateBoundRect();
813 void AccessibleTextHelper_Impl::UpdateVisibleChildren( bool bBroadcastEvents )
815 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
819 SvxTextForwarder& rCacheTF = GetTextForwarder();
820 SvxViewForwarder& rCacheVF = GetViewForwarder();
822 Rectangle aViewArea = rCacheVF.GetVisArea();
824 if( IsActive() )
826 // maybe the edit view scrolls, adapt aViewArea
827 Rectangle aEditViewArea = GetEditViewForwarder().GetVisArea();
828 aViewArea += aEditViewArea.TopLeft();
830 // now determine intersection
831 aViewArea.Intersection( aEditViewArea );
834 Rectangle aTmpBB, aParaBB;
835 sal_Bool bFirstChild = sal_True;
836 sal_Int32 nCurrPara;
837 sal_Int32 nParas=rCacheTF.GetParagraphCount();
839 mnFirstVisibleChild = -1;
840 mnLastVisibleChild = -2;
842 for( nCurrPara=0; nCurrPara<nParas; ++nCurrPara )
844 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX,
845 "AccessibleTextHelper_Impl::UpdateVisibleChildren: index value overflow");
847 aTmpBB = rCacheTF.GetParaBounds( static_cast< sal_uInt16 >( nCurrPara ) );
849 // convert to screen coordinates
850 aParaBB = ::accessibility::AccessibleEditableTextPara::LogicToPixel( aTmpBB, rCacheTF.GetMapMode(), rCacheVF );
852 if( aParaBB.IsOver( aViewArea ) )
854 // at least partially visible
855 if( bFirstChild )
857 bFirstChild = sal_False;
858 mnFirstVisibleChild = nCurrPara;
861 mnLastVisibleChild = nCurrPara;
863 // child not yet created?
864 ::accessibility::AccessibleParaManager::WeakChild aChild( maParaManager.GetChild(nCurrPara) );
865 if( aChild.second.Width == 0 &&
866 aChild.second.Height == 0 &&
867 mxFrontEnd.is() &&
868 bBroadcastEvents )
870 GotPropertyEvent( uno::makeAny( maParaManager.CreateChild( nCurrPara - mnFirstVisibleChild,
871 mxFrontEnd, GetEditSource(), nCurrPara ).first ),
872 AccessibleEventId::CHILD );
875 else
877 // not or no longer visible
878 if( maParaManager.IsReferencable( nCurrPara ) )
880 if( bBroadcastEvents )
881 LostPropertyEvent( uno::makeAny( maParaManager.GetChild( nCurrPara ).first.get().getRef() ),
882 AccessibleEventId::CHILD );
884 // clear reference
885 maParaManager.Release( nCurrPara );
890 catch( const uno::Exception& )
892 OSL_FAIL("AccessibleTextHelper_Impl::UpdateVisibleChildren error while determining visible children");
894 // something failed - currently no children
895 mnFirstVisibleChild = -1;
896 mnLastVisibleChild = -2;
897 maParaManager.SetNum(0);
899 // lost all children
900 if( bBroadcastEvents )
901 FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
905 // functor for checking changes in paragraph bounding boxes (no stand-alone function, maybe not inlined)
906 class AccessibleTextHelper_UpdateChildBounds : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&,
907 ::accessibility::AccessibleParaManager::WeakChild >
909 public:
910 AccessibleTextHelper_UpdateChildBounds( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
911 ::accessibility::AccessibleParaManager::WeakChild operator()( const ::accessibility::AccessibleParaManager::WeakChild& rChild )
913 // retrieve hard reference from weak one
914 ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rChild.first.get() );
916 if( aHardRef.is() )
918 awt::Rectangle aNewRect = aHardRef->getBounds();
919 const awt::Rectangle& aOldRect = rChild.second;
921 if( aNewRect.X != aOldRect.X ||
922 aNewRect.Y != aOldRect.Y ||
923 aNewRect.Width != aOldRect.Width ||
924 aNewRect.Height != aOldRect.Height )
926 // visible data changed
927 aHardRef->FireEvent( AccessibleEventId::BOUNDRECT_CHANGED );
929 // update internal bounds
930 return ::accessibility::AccessibleParaManager::WeakChild( rChild.first, aNewRect );
934 // identity transform
935 return rChild;
938 private:
939 AccessibleTextHelper_Impl& mrImpl;
942 void AccessibleTextHelper_Impl::UpdateBoundRect()
944 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
946 // send BOUNDRECT_CHANGED to affected children
947 AccessibleTextHelper_UpdateChildBounds aFunctor( *this );
948 ::std::transform( maParaManager.begin(), maParaManager.end(), maParaManager.begin(), aFunctor );
951 #ifdef DBG_UTIL
952 void AccessibleTextHelper_Impl::CheckInvariants() const
954 if( mnFirstVisibleChild >= 0 &&
955 mnFirstVisibleChild > mnLastVisibleChild )
957 OSL_FAIL( "AccessibleTextHelper: range invalid" );
960 #endif
962 // functor for sending child events (no stand-alone function, they are maybe not inlined)
963 class AccessibleTextHelper_LostChildEvent : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&, void >
965 public:
966 AccessibleTextHelper_LostChildEvent( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
967 void operator()( const ::accessibility::AccessibleParaManager::WeakChild& rPara )
969 // retrieve hard reference from weak one
970 ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rPara.first.get() );
972 if( aHardRef.is() )
973 mrImpl.FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( aHardRef.getRef() ) );
976 private:
977 AccessibleTextHelper_Impl& mrImpl;
980 void AccessibleTextHelper_Impl::ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast )
982 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
984 const sal_Int32 nParas = GetTextForwarder().GetParagraphCount();
986 /* rotate paragraphs
987 * =================
989 * Three cases:
991 * 1.
992 * ... nParagraph ... nParam1 ... nParam2 ...
993 * |______________[xxxxxxxxxxx]
994 * becomes
995 * [xxxxxxxxxxx]|______________
997 * tail is 0
999 * 2.
1000 * ... nParam1 ... nParagraph ... nParam2 ...
1001 * [xxxxxxxxxxx|xxxxxxxxxxxxxx]____________
1002 * becomes
1003 * ____________[xxxxxxxxxxx|xxxxxxxxxxxxxx]
1005 * tail is nParagraph - nParam1
1007 * 3.
1008 * ... nParam1 ... nParam2 ... nParagraph ...
1009 * [xxxxxxxxxxx]___________|____________
1010 * becomes
1011 * ___________|____________[xxxxxxxxxxx]
1013 * tail is nParam2 - nParam1
1016 // sort nParagraph, nParam1 and nParam2 in ascending order, calc range
1017 if( nMiddle < nFirst )
1019 ::std::swap(nFirst, nMiddle);
1021 else if( nMiddle < nLast )
1023 nLast = nLast + nMiddle - nFirst;
1025 else
1027 ::std::swap(nMiddle, nLast);
1028 nLast = nLast + nMiddle - nFirst;
1031 if( nFirst < nParas && nMiddle < nParas && nLast < nParas )
1033 // since we have no "paragraph index
1034 // changed" event on UAA, remove
1035 // [first,last] and insert again later (in
1036 // UpdateVisibleChildren)
1038 // maParaManager.Rotate( nFirst, nMiddle, nLast );
1040 // send CHILD_EVENT to affected children
1041 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
1042 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
1044 ::std::advance( begin, nFirst );
1045 ::std::advance( end, nLast+1 );
1047 // TODO: maybe optimize here in the following way. If the
1048 // number of removed children exceeds a certain threshold,
1049 // use INVALIDATE_CHILDREN
1050 AccessibleTextHelper_LostChildEvent aFunctor( *this );
1052 ::std::for_each( begin, end, aFunctor );
1054 maParaManager.Release(nFirst, nLast+1);
1055 // should be no need for UpdateBoundRect, since all affected children are cleared.
1059 // functor for sending child events (no stand-alone function, they are maybe not inlined)
1060 class AccessibleTextHelper_ChildrenTextChanged : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
1062 public:
1063 void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
1065 rPara.TextChanged();
1069 /** functor processing queue events
1071 Reacts on TEXT_HINT_PARAINSERTED/REMOVED events and stores
1072 their content
1074 class AccessibleTextHelper_QueueFunctor : public ::std::unary_function< const SfxHint*, void >
1076 public:
1077 AccessibleTextHelper_QueueFunctor() :
1078 mnParasChanged( 0 ),
1079 mnParaIndex(-1),
1080 mnHintId(-1)
1082 void operator()( const SfxHint* pEvent )
1084 if( pEvent &&
1085 mnParasChanged != -1 )
1087 // determine hint type
1088 const TextHint* pTextHint = PTR_CAST( TextHint, pEvent );
1089 const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, pEvent );
1091 if( !pEditSourceHint && pTextHint &&
1092 (pTextHint->GetId() == TEXT_HINT_PARAINSERTED ||
1093 pTextHint->GetId() == TEXT_HINT_PARAREMOVED ) )
1095 if( pTextHint->GetValue() == EE_PARA_ALL )
1097 mnParasChanged = -1;
1099 else
1101 mnHintId = pTextHint->GetId();
1102 mnParaIndex = pTextHint->GetValue();
1103 ++mnParasChanged;
1109 /** Query number of paragraphs changed during queue processing.
1111 @return number of changed paragraphs, -1 for
1112 "every paragraph changed"
1114 int GetNumberOfParasChanged() { return mnParasChanged; }
1115 /** Query index of last added/removed paragraph
1117 @return index of lastly added paragraphs, -1 for none
1118 added so far.
1120 int GetParaIndex() { return mnParaIndex; }
1121 /** Query hint id of last interesting event
1123 @return hint id of last interesting event (REMOVED/INSERTED).
1125 int GetHintId() { return mnHintId; }
1127 private:
1128 /** number of paragraphs changed during queue processing. -1 for
1129 "every paragraph changed"
1131 int mnParasChanged;
1132 /// index of paragraph added/removed last
1133 int mnParaIndex;
1134 /// TextHint ID (removed/inserted) of last interesting event
1135 int mnHintId;
1138 void AccessibleTextHelper_Impl::ProcessQueue()
1140 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1142 // inspect queue for paragraph insert/remove events. If there
1143 // is exactly _one_ of those in the queue, and the number of
1144 // paragraphs has changed by exactly one, use that event to
1145 // determine a priori which paragraph was added/removed. This
1146 // is necessary, since I must sync right here with the
1147 // EditEngine state (number of paragraphs etc.), since I'm
1148 // potentially sending listener events right away.
1149 AccessibleTextHelper_QueueFunctor aFunctor;
1150 maEventQueue.ForEach( aFunctor );
1152 const sal_Int32 nNewParas( GetTextForwarder().GetParagraphCount() );
1153 const sal_Int32 nCurrParas( maParaManager.GetNum() );
1155 // whether every paragraph already is updated (no need to
1156 // repeat that later on, e.g. for PARA_MOVED events)
1157 bool bEverythingUpdated( false );
1159 if( labs( nNewParas - nCurrParas ) == 1 &&
1160 aFunctor.GetNumberOfParasChanged() == 1 )
1162 // #103483# Exactly one paragraph added/removed. This is
1163 // the normal case, optimize event handling here.
1165 if( aFunctor.GetHintId() == TEXT_HINT_PARAINSERTED )
1167 // update num of paras
1168 maParaManager.SetNum( nNewParas );
1170 // release everything from the insertion position until the end
1171 maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas);
1173 // TODO: Clarify whether this behaviour _really_ saves
1174 // anybody anything!
1175 // update children, _don't_ broadcast
1176 UpdateVisibleChildren( false );
1177 UpdateBoundRect();
1179 // send insert event
1180 // #109864# Enforce creation of this paragraph
1183 GotPropertyEvent( uno::makeAny( getAccessibleChild( aFunctor.GetParaIndex() -
1184 mnFirstVisibleChild + GetStartIndex() ) ),
1185 AccessibleEventId::CHILD );
1187 catch( const uno::Exception& )
1189 OSL_FAIL("AccessibleTextHelper_Impl::ProcessQueue: could not create new paragraph");
1192 else if( aFunctor.GetHintId() == TEXT_HINT_PARAREMOVED )
1194 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
1195 ::std::advance( begin, aFunctor.GetParaIndex() );
1196 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
1197 ::std::advance( end, 1 );
1199 // #i61812# remember para to be removed for later notification
1200 // AFTER the new state is applied (that after the para got removed)
1201 ::uno::Reference< XAccessible > xPara;
1202 ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( begin->first.get() );
1203 if( aHardRef.is() )
1204 xPara = ::uno::Reference< XAccessible >( aHardRef.getRef(), ::uno::UNO_QUERY );
1206 // release everything from the remove position until the end
1207 maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas);
1209 // update num of paras
1210 maParaManager.SetNum( nNewParas );
1212 // TODO: Clarify whether this behaviour _really_ saves
1213 // anybody anything!
1214 // update children, _don't_ broadcast
1215 UpdateVisibleChildren( false );
1216 UpdateBoundRect();
1218 // #i61812# notification for removed para
1219 if (xPara.is())
1220 FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( xPara) );
1222 #ifdef DBG_UTIL
1223 else
1224 OSL_FAIL("AccessibleTextHelper_Impl::ProcessQueue() invalid hint id");
1225 #endif
1227 else if( nNewParas != nCurrParas )
1229 // release all paras
1230 maParaManager.Release(0, nCurrParas);
1232 // update num of paras
1233 maParaManager.SetNum( nNewParas );
1235 // #109864# create from scratch, don't broadcast
1236 UpdateVisibleChildren( false );
1237 UpdateBoundRect();
1239 // number of paragraphs somehow changed - but we have no
1240 // chance determining how. Thus, throw away everything and
1241 // create from scratch.
1242 // (child events should be broadcast after the changes are done...)
1243 FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
1245 // no need for further updates later on
1246 bEverythingUpdated = true;
1249 while( !maEventQueue.IsEmpty() )
1251 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1252 ::std::auto_ptr< SfxHint > pHint( maEventQueue.PopFront() );
1253 SAL_WNODEPRECATED_DECLARATIONS_POP
1254 if( pHint.get() )
1256 const SfxHint& rHint = *(pHint.get());
1258 // determine hint type
1259 const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint );
1260 const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint );
1261 const TextHint* pTextHint = PTR_CAST( TextHint, &rHint );
1262 const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint );
1263 const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint );
1267 const sal_Int32 nParas = GetTextForwarder().GetParagraphCount();
1269 if( pEditSourceHint )
1271 switch( pEditSourceHint->GetId() )
1273 case EDITSOURCE_HINT_PARASMOVED:
1275 DBG_ASSERT( pEditSourceHint->GetStartValue() < GetTextForwarder().GetParagraphCount() &&
1276 pEditSourceHint->GetEndValue() < GetTextForwarder().GetParagraphCount(),
1277 "AccessibleTextHelper_Impl::NotifyHdl: Invalid notification");
1279 if( !bEverythingUpdated )
1281 ParagraphsMoved(pEditSourceHint->GetStartValue(),
1282 pEditSourceHint->GetValue(),
1283 pEditSourceHint->GetEndValue());
1285 // in all cases, check visibility afterwards.
1286 UpdateVisibleChildren();
1288 break;
1291 case EDITSOURCE_HINT_SELECTIONCHANGED:
1292 // notify listeners
1295 UpdateSelection();
1297 // maybe we're not in edit mode (this is not an error)
1298 catch( const uno::Exception& ) {}
1299 break;
1302 else if( pTextHint )
1304 switch( pTextHint->GetId() )
1306 case TEXT_HINT_MODIFIED:
1308 // notify listeners
1309 sal_Int32 nPara( pTextHint->GetValue() );
1311 // #108900# Delegate change event to children
1312 AccessibleTextHelper_ChildrenTextChanged aNotifyChildrenFunctor;
1314 if( nPara == static_cast<sal_Int32>(EE_PARA_ALL) )
1316 // #108900# Call every child
1317 ::std::for_each( maParaManager.begin(), maParaManager.end(),
1318 AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
1320 else
1321 if( nPara < nParas )
1323 // #108900# Call child at index nPara
1324 ::std::for_each( maParaManager.begin()+nPara, maParaManager.begin()+nPara+1,
1325 AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
1327 break;
1330 case TEXT_HINT_PARAINSERTED:
1331 // already happened above
1332 break;
1334 case TEXT_HINT_PARAREMOVED:
1335 // already happened above
1336 break;
1338 case TEXT_HINT_TEXTHEIGHTCHANGED:
1339 // visibility changed, done below
1340 break;
1342 case TEXT_HINT_VIEWSCROLLED:
1343 // visibility changed, done below
1344 break;
1347 // in all cases, check visibility afterwards.
1348 UpdateVisibleChildren();
1349 UpdateBoundRect();
1351 else if( pViewHint )
1353 switch( pViewHint->GetHintType() )
1355 case SvxViewHint::SVX_HINT_VIEWCHANGED:
1356 // just check visibility
1357 UpdateVisibleChildren();
1358 UpdateBoundRect();
1359 break;
1362 else if( pSdrHint )
1364 switch( pSdrHint->GetKind() )
1366 case HINT_BEGEDIT:
1368 // change children state
1369 maParaManager.SetActive();
1371 // per definition, edit mode text has the focus
1372 SetFocus( sal_True );
1373 break;
1376 case HINT_ENDEDIT:
1378 // focused child now looses focus
1379 ESelection aSelection;
1380 if( GetEditViewForwarder().GetSelection( aSelection ) )
1381 SetChildFocus( aSelection.nEndPara, sal_False );
1383 // change children state
1384 maParaManager.SetActive( sal_False );
1386 maLastSelection = ESelection( EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND,
1387 EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND);
1388 break;
1390 default:
1391 break;
1394 // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above!
1395 else if( pSimpleHint )
1397 switch( pSimpleHint->GetId() )
1399 case SFX_HINT_DYING:
1400 // edit source is dying under us, become defunc then
1403 // make edit source inaccessible
1404 // Note: cannot destroy it here, since we're called from there!
1405 ShutdownEditSource();
1407 catch( const uno::Exception& ) {}
1409 break;
1413 catch( const uno::Exception& )
1415 #ifdef DBG_UTIL
1416 OSL_TRACE("AccessibleTextHelper_Impl::ProcessQueue: Unhandled exception.");
1417 #endif
1423 void AccessibleTextHelper_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1425 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1427 // precondition: solar mutex locked
1428 DBG_TESTSOLARMUTEX();
1430 // precondition: not in a recursion
1431 if( mbInNotify )
1432 return;
1434 mbInNotify = sal_True;
1436 // determine hint type
1437 const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint );
1438 const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint );
1439 const TextHint* pTextHint = PTR_CAST( TextHint, &rHint );
1440 const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint );
1441 const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint );
1445 // Process notification event
1446 if( pEditSourceHint )
1448 maEventQueue.Append( *pEditSourceHint );
1449 // EditEngine should emit TEXT_SELECTION_CHANGED events (#i27299#)
1450 if( maEventOpenFrames == 0 )
1451 ProcessQueue();
1453 else if( pTextHint )
1455 switch( pTextHint->GetId() )
1457 case TEXT_HINT_BLOCKNOTIFICATION_END:
1458 case TEXT_HINT_INPUT_END:
1459 --maEventOpenFrames;
1461 if( maEventOpenFrames == 0 )
1463 // #103483#
1464 /* All information should have arrived
1465 * now, process queue. As stated in the
1466 * above bug, we can often avoid throwing
1467 * away all paragraphs by looking forward
1468 * in the event queue (searching for
1469 * PARAINSERT/REMOVE events). Furthermore,
1470 * processing the event queue only at the
1471 * end of an interaction cycle, ensures
1472 * that the EditEngine state and the
1473 * AccessibleText state are the same
1474 * (well, mostly. If there are _multiple_
1475 * interaction cycles in the EE queues, it
1476 * can still happen that EE state is
1477 * different. That's so to say broken by
1478 * design with that delayed EE event
1479 * concept).
1481 ProcessQueue();
1483 break;
1485 case TEXT_HINT_BLOCKNOTIFICATION_START:
1486 case TEXT_HINT_INPUT_START:
1487 ++maEventOpenFrames;
1488 // no FALLTHROUGH reason: event will not be processed,
1489 // thus appending the event isn't necessary. (#i27299#)
1490 break;
1491 default:
1492 maEventQueue.Append( *pTextHint );
1493 // EditEngine should emit TEXT_SELECTION_CHANGED events (#i27299#)
1494 if( maEventOpenFrames == 0 )
1495 ProcessQueue();
1496 break;
1499 else if( pViewHint )
1501 maEventQueue.Append( *pViewHint );
1503 // process visibility right away, if not within an
1504 // open EE notification frame. Otherwise, event
1505 // processing would be delayed until next EE
1506 // notification sequence.
1507 if( maEventOpenFrames == 0 )
1508 ProcessQueue();
1510 else if( pSdrHint )
1512 maEventQueue.Append( *pSdrHint );
1514 // process drawing layer events right away, if not
1515 // within an open EE notification frame. Otherwise,
1516 // event processing would be delayed until next EE
1517 // notification sequence.
1518 if( maEventOpenFrames == 0 )
1519 ProcessQueue();
1521 // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above!
1522 else if( pSimpleHint )
1524 // handle this event _at once_, because after that, objects are invalid
1525 switch( pSimpleHint->GetId() )
1527 case SFX_HINT_DYING:
1528 // edit source is dying under us, become defunc then
1529 maEventQueue.Clear();
1532 // make edit source inaccessible
1533 // Note: cannot destroy it here, since we're called from there!
1534 ShutdownEditSource();
1536 catch( const uno::Exception& ) {}
1538 break;
1542 catch( const uno::Exception& )
1544 #ifdef DBG_UTIL
1545 OSL_TRACE("AccessibleTextHelper_Impl::Notify: Unhandled exception.");
1546 #endif
1547 mbInNotify = sal_False;
1550 mbInNotify = sal_False;
1553 void AccessibleTextHelper_Impl::Dispose()
1555 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1557 if( getNotifierClientId() != -1 )
1561 // #106234# Unregister from EventNotifier
1562 ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() );
1563 #ifdef DBG_UTIL
1564 OSL_TRACE( "AccessibleTextHelper_Impl disposed ID: %d", mnNotifierClientId );
1565 #endif
1567 catch( const uno::Exception& ) {}
1569 mnNotifierClientId = -1;
1574 // dispose children
1575 maParaManager.Dispose();
1577 catch( const uno::Exception& ) {}
1579 // quit listen on stale edit source
1580 if( maEditSource.IsValid() )
1581 EndListening( maEditSource.GetBroadcaster() );
1583 // clear references
1584 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1585 maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) );
1586 SAL_WNODEPRECATED_DECLARATIONS_POP
1587 mxFrontEnd = NULL;
1590 void AccessibleTextHelper_Impl::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const
1592 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1594 // -- object locked --
1595 ::osl::ClearableMutexGuard aGuard( maMutex );
1597 AccessibleEventObject aEvent;
1599 DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper::FireEvent: no event source set" );
1601 if( mxFrontEnd.is() )
1602 aEvent = AccessibleEventObject(mxFrontEnd->getAccessibleContext(), nEventId, rNewValue, rOldValue);
1603 else
1604 aEvent = AccessibleEventObject(uno::Reference< uno::XInterface >(), nEventId, rNewValue, rOldValue);
1606 // no locking necessary, FireEvent internally copies listeners
1607 // if someone removes/adds in between Further locking,
1608 // actually, might lead to deadlocks, since we're calling out
1609 // of this object
1610 aGuard.clear();
1611 // -- until here --
1613 FireEvent(aEvent);
1616 void AccessibleTextHelper_Impl::FireEvent( const AccessibleEventObject& rEvent ) const
1618 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1620 // #102261# Call global queue for focus events
1621 if( rEvent.EventId == AccessibleStateType::FOCUSED )
1622 vcl::unohelper::NotifyAccessibleStateEventGlobally( rEvent );
1624 // #106234# Delegate to EventNotifier
1625 ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(),
1626 rEvent );
1629 // XAccessibleContext
1630 sal_Int32 SAL_CALL AccessibleTextHelper_Impl::getAccessibleChildCount() SAL_THROW((uno::RuntimeException))
1632 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1634 return mnLastVisibleChild - mnFirstVisibleChild + 1;
1637 uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException))
1639 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1641 i -= GetStartIndex();
1643 if( 0 > i || i >= getAccessibleChildCount() ||
1644 GetTextForwarder().GetParagraphCount() <= i )
1646 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid child index")), mxFrontEnd);
1649 DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper_Impl::UpdateVisibleChildren: no frontend set");
1651 if( mxFrontEnd.is() )
1652 return maParaManager.CreateChild( i, mxFrontEnd, GetEditSource(), mnFirstVisibleChild + i ).first;
1653 else
1654 return NULL;
1657 void SAL_CALL AccessibleTextHelper_Impl::addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
1659 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1661 if( getNotifierClientId() != -1 )
1662 ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener );
1665 void SAL_CALL AccessibleTextHelper_Impl::removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
1667 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1669 if( getNotifierClientId() != -1 )
1670 ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener );
1673 uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleAtPoint( const awt::Point& _aPoint ) SAL_THROW((uno::RuntimeException))
1675 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1677 // make given position relative
1678 if( !mxFrontEnd.is() )
1679 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd );
1681 uno::Reference< XAccessibleContext > xFrontEndContext = mxFrontEnd->getAccessibleContext();
1683 if( !xFrontEndContext.is() )
1684 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd );
1686 uno::Reference< XAccessibleComponent > xFrontEndComponent( xFrontEndContext, uno::UNO_QUERY );
1688 if( !xFrontEndComponent.is() )
1689 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend is no XAccessibleComponent")),
1690 mxFrontEnd );
1692 // #103862# No longer need to make given position relative
1693 Point aPoint( _aPoint.X, _aPoint.Y );
1695 // respect EditEngine offset to surrounding shape/cell
1696 aPoint -= GetOffset();
1698 // convert to EditEngine coordinate system
1699 SvxTextForwarder& rCacheTF = GetTextForwarder();
1700 Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) );
1702 // iterate over all visible children (including those not yet created)
1703 sal_Int32 nChild;
1704 for( nChild=mnFirstVisibleChild; nChild <= mnLastVisibleChild; ++nChild )
1706 DBG_ASSERT(nChild >= 0 && nChild <= USHRT_MAX,
1707 "AccessibleTextHelper_Impl::getAccessibleAt: index value overflow");
1709 Rectangle aParaBounds( rCacheTF.GetParaBounds( static_cast< sal_uInt16 > (nChild) ) );
1711 if( aParaBounds.IsInside( aLogPoint ) )
1712 return getAccessibleChild( nChild - mnFirstVisibleChild + GetStartIndex() );
1715 // found none
1716 return NULL;
1719 //------------------------------------------------------------------------
1721 // AccessibleTextHelper implementation (simply forwards to impl)
1723 //------------------------------------------------------------------------
1725 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1726 AccessibleTextHelper::AccessibleTextHelper( ::std::auto_ptr< SvxEditSource > pEditSource ) :
1727 mpImpl( new AccessibleTextHelper_Impl() )
1729 SolarMutexGuard aGuard;
1731 SetEditSource( pEditSource );
1733 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1735 AccessibleTextHelper::~AccessibleTextHelper()
1739 const SvxEditSource& AccessibleTextHelper::GetEditSource() const SAL_THROW((uno::RuntimeException))
1741 #ifdef DBG_UTIL
1742 mpImpl->CheckInvariants();
1744 const SvxEditSource& aEditSource = mpImpl->GetEditSource();
1746 mpImpl->CheckInvariants();
1748 return aEditSource;
1749 #else
1750 return mpImpl->GetEditSource();
1751 #endif
1754 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1755 void AccessibleTextHelper::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
1757 #ifdef DBG_UTIL
1758 // precondition: solar mutex locked
1759 DBG_TESTSOLARMUTEX();
1761 mpImpl->CheckInvariants();
1762 #endif
1764 mpImpl->SetEditSource( pEditSource );
1766 #ifdef DBG_UTIL
1767 mpImpl->CheckInvariants();
1768 #endif
1770 SAL_WNODEPRECATED_DECLARATIONS_POP
1772 void AccessibleTextHelper::SetEventSource( const uno::Reference< XAccessible >& rInterface )
1774 #ifdef DBG_UTIL
1775 mpImpl->CheckInvariants();
1776 #endif
1778 mpImpl->SetEventSource( rInterface );
1780 #ifdef DBG_UTIL
1781 mpImpl->CheckInvariants();
1782 #endif
1785 uno::Reference< XAccessible > AccessibleTextHelper::GetEventSource() const
1787 #ifdef DBG_UTIL
1788 mpImpl->CheckInvariants();
1790 uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
1792 mpImpl->CheckInvariants();
1794 return xRet;
1795 #else
1796 return mpImpl->GetEventSource();
1797 #endif
1800 void AccessibleTextHelper::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
1802 #ifdef DBG_UTIL
1803 // precondition: solar mutex locked
1804 DBG_TESTSOLARMUTEX();
1806 mpImpl->CheckInvariants();
1807 #endif
1809 mpImpl->SetFocus( bHaveFocus );
1811 #ifdef DBG_UTIL
1812 mpImpl->CheckInvariants();
1813 #endif
1816 sal_Bool AccessibleTextHelper::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException))
1818 #ifdef DBG_UTIL
1819 mpImpl->CheckInvariants();
1821 sal_Bool bRet( mpImpl->HaveFocus() );
1823 mpImpl->CheckInvariants();
1825 return bRet;
1826 #else
1827 return mpImpl->HaveFocus();
1828 #endif
1831 void AccessibleTextHelper::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const
1833 #ifdef DBG_UTIL
1834 mpImpl->CheckInvariants();
1835 #endif
1837 mpImpl->FireEvent( nEventId, rNewValue, rOldValue );
1839 #ifdef DBG_UTIL
1840 mpImpl->CheckInvariants();
1841 #endif
1844 void AccessibleTextHelper::FireEvent( const AccessibleEventObject& rEvent ) const
1846 #ifdef DBG_UTIL
1847 mpImpl->CheckInvariants();
1848 #endif
1850 mpImpl->FireEvent( rEvent );
1852 #ifdef DBG_UTIL
1853 mpImpl->CheckInvariants();
1854 #endif
1857 void AccessibleTextHelper::SetOffset( const Point& rPoint )
1859 #ifdef DBG_UTIL
1860 // precondition: solar mutex locked
1861 DBG_TESTSOLARMUTEX();
1863 mpImpl->CheckInvariants();
1864 #endif
1866 mpImpl->SetOffset( rPoint );
1868 #ifdef DBG_UTIL
1869 mpImpl->CheckInvariants();
1870 #endif
1873 Point AccessibleTextHelper::GetOffset() const
1875 #ifdef DBG_UTIL
1876 mpImpl->CheckInvariants();
1878 Point aPoint( mpImpl->GetOffset() );
1880 mpImpl->CheckInvariants();
1882 return aPoint;
1883 #else
1884 return mpImpl->GetOffset();
1885 #endif
1888 void AccessibleTextHelper::SetStartIndex( sal_Int32 nOffset )
1890 #ifdef DBG_UTIL
1891 // precondition: solar mutex locked
1892 DBG_TESTSOLARMUTEX();
1894 mpImpl->CheckInvariants();
1895 #endif
1897 mpImpl->SetStartIndex( nOffset );
1899 #ifdef DBG_UTIL
1900 mpImpl->CheckInvariants();
1901 #endif
1904 sal_Int32 AccessibleTextHelper::GetStartIndex() const
1906 #ifdef DBG_UTIL
1907 mpImpl->CheckInvariants();
1909 sal_Int32 nOffset = mpImpl->GetStartIndex();
1911 mpImpl->CheckInvariants();
1913 return nOffset;
1914 #else
1915 return mpImpl->GetStartIndex();
1916 #endif
1919 void AccessibleTextHelper::SetAdditionalChildStates( const VectorOfStates& rChildStates )
1921 mpImpl->SetAdditionalChildStates( rChildStates );
1924 void AccessibleTextHelper::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
1926 #ifdef DBG_UTIL
1927 // precondition: solar mutex locked
1928 DBG_TESTSOLARMUTEX();
1930 mpImpl->CheckInvariants();
1931 #endif
1933 mpImpl->UpdateVisibleChildren();
1934 mpImpl->UpdateBoundRect();
1936 mpImpl->UpdateSelection();
1938 #ifdef DBG_UTIL
1939 mpImpl->CheckInvariants();
1940 #endif
1943 void AccessibleTextHelper::Dispose()
1945 // As Dispose calls ShutdownEditSource, which in turn
1946 // deregisters as listener on the edit source, have to lock
1947 // here
1948 SolarMutexGuard aGuard;
1950 #ifdef DBG_UTIL
1951 mpImpl->CheckInvariants();
1952 #endif
1954 mpImpl->Dispose();
1956 #ifdef DBG_UTIL
1957 mpImpl->CheckInvariants();
1958 #endif
1961 sal_Bool AccessibleTextHelper::IsSelected() const
1963 SolarMutexGuard aGuard;
1965 #ifdef DBG_UTIL
1966 mpImpl->CheckInvariants();
1968 sal_Bool aRet = mpImpl->IsSelected();
1970 mpImpl->CheckInvariants();
1972 return aRet;
1973 #else
1974 return mpImpl->IsSelected();
1975 #endif
1978 // XAccessibleContext
1979 sal_Int32 AccessibleTextHelper::GetChildCount() SAL_THROW((uno::RuntimeException))
1981 SolarMutexGuard aGuard;
1983 #ifdef DBG_UTIL
1984 mpImpl->CheckInvariants();
1986 sal_Int32 nRet = mpImpl->getAccessibleChildCount();
1988 mpImpl->CheckInvariants();
1990 return nRet;
1991 #else
1992 return mpImpl->getAccessibleChildCount();
1993 #endif
1996 uno::Reference< XAccessible > AccessibleTextHelper::GetChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException))
1998 SolarMutexGuard aGuard;
2000 #ifdef DBG_UTIL
2001 mpImpl->CheckInvariants();
2003 uno::Reference< XAccessible > xRet = mpImpl->getAccessibleChild( i );
2005 mpImpl->CheckInvariants();
2007 return xRet;
2008 #else
2009 return mpImpl->getAccessibleChild( i );
2010 #endif
2013 void AccessibleTextHelper::AddEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
2015 #ifdef DBG_UTIL
2016 mpImpl->CheckInvariants();
2018 mpImpl->addEventListener( xListener );
2020 mpImpl->CheckInvariants();
2021 #else
2022 mpImpl->addEventListener( xListener );
2023 #endif
2026 void AccessibleTextHelper::RemoveEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
2028 #ifdef DBG_UTIL
2029 mpImpl->CheckInvariants();
2031 mpImpl->removeEventListener( xListener );
2033 mpImpl->CheckInvariants();
2034 #else
2035 mpImpl->removeEventListener( xListener );
2036 #endif
2039 // XAccessibleComponent
2040 uno::Reference< XAccessible > AccessibleTextHelper::GetAt( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException))
2042 SolarMutexGuard aGuard;
2044 #ifdef DBG_UTIL
2045 mpImpl->CheckInvariants();
2047 uno::Reference< XAccessible > xChild = mpImpl->getAccessibleAtPoint( aPoint );
2049 mpImpl->CheckInvariants();
2051 return xChild;
2052 #else
2053 return mpImpl->getAccessibleAtPoint( aPoint );
2054 #endif
2057 } // end of namespace accessibility
2059 //------------------------------------------------------------------------
2061 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */