1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 
31 //------------------------------------------------------------------------
32 //
33 // Global header
34 //
35 //------------------------------------------------------------------------
36 
37 #include <limits.h>
38 #include <memory>
39 #include <algorithm>
40 #include <deque>
41 #include <vos/mutex.hxx>
42 #include <com/sun/star/uno/Any.hxx>
43 #include <com/sun/star/uno/Reference.hxx>
44 #include <cppuhelper/weakref.hxx>
45 #include <com/sun/star/awt/Point.hpp>
46 #include <com/sun/star/awt/Rectangle.hpp>
47 #include <com/sun/star/lang/DisposedException.hpp>
48 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
49 #include <com/sun/star/accessibility/XAccessible.hpp>
50 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
51 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
52 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
53 #include <comphelper/accessibleeventnotifier.hxx>
54 #include <unotools/accessiblestatesethelper.hxx>
55 #include <vcl/unohelp.hxx>
56 #include <vcl/svapp.hxx>
57 
58 //------------------------------------------------------------------------
59 //
60 // Project-local header
61 //
62 //------------------------------------------------------------------------
63 #include "AccessibleTextEventQueue.hxx"
64 #include <svx/AccessibleTextHelper.hxx>
65 #include <svx/unoshape.hxx>
66 #include "editeng/unolingu.hxx"
67 #include <editeng/unotext.hxx>
68 
69 #include "editeng/unoedhlp.hxx"
70 #include "editeng/unopracc.hxx"
71 #include "editeng/AccessibleParaManager.hxx"
72 #include "editeng/AccessibleEditableTextPara.hxx"
73 #include <svx/svdmodel.hxx>
74 #include <svx/svdpntv.hxx>
75 #include <editeng/editdata.hxx>
76 #include <editeng/editeng.hxx>
77 #include <editeng/editview.hxx>
78 
79 using namespace ::com::sun::star;
80 using namespace ::com::sun::star::accessibility;
81 
82 namespace accessibility
83 {
84 
85 //------------------------------------------------------------------------
86 //
87 // AccessibleTextHelper_Impl declaration
88 //
89 //------------------------------------------------------------------------
90 
91     DBG_NAME( AccessibleTextHelper_Impl )
92 
93     template < typename first_type, typename second_type >
94 	    ::std::pair< first_type, second_type > makeSortedPair( first_type 	first,
95                                                                                  second_type 	second	)
96     {
97         if( first > second )
98             return ::std::make_pair( second, first );
99         else
100             return ::std::make_pair( first, second );
101     }
102 
103     class AccessibleTextHelper_Impl : public SfxListener
104     {
105 
106     public:
107         typedef ::std::vector< sal_Int16 > VectorOfStates;
108 
109         // receive pointer to our frontend class and view window
110         AccessibleTextHelper_Impl();
111         ~AccessibleTextHelper_Impl();
112 
113         // XAccessibleContext child handling methods
114         sal_Int32 SAL_CALL getAccessibleChildCount() SAL_THROW((uno::RuntimeException));
115         uno::Reference< XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException));
116 
117         // XAccessibleEventBroadcaster child related methods
118         void SAL_CALL addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException));
119         void SAL_CALL removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException));
120 
121         // XAccessibleComponent child related methods
122         uno::Reference< XAccessible > SAL_CALL getAccessibleAtPoint( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException));
123 
124         SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException));
125         void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException));
126 
127         void SetEventSource( const uno::Reference< XAccessible >& rInterface )
128         {
129             DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
130             mxFrontEnd = rInterface;
131         }
132         uno::Reference< XAccessible > GetEventSource() const
133         {
134             DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
135             return mxFrontEnd;
136         }
137 
138         void SetOffset( const Point& );
139         Point GetOffset() const
140         {
141             DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
142             ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset );
143             return aPoint;
144         }
145 
146         void SetStartIndex( sal_Int32 nOffset );
147         sal_Int32 GetStartIndex() const
148         {
149             DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
150 			// Strictly correct only with locked solar mutex, // but
151 			// here we rely on the fact that sal_Int32 access is
152 			// atomic
153             return mnStartIndex;
154         }
155 
156         void SetAdditionalChildStates( const VectorOfStates& rChildStates );
157         const VectorOfStates& GetAdditionalChildStates() const;
158 
159         sal_Bool IsSelected() const;
160 
161         void Dispose();
162 
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;
166 
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));
172 
173 #ifdef DBG_UTIL
174         void CheckInvariants() const;
175 #endif
176 
177         // checks all children for visibility, throws away invisible ones
178         void UpdateVisibleChildren( bool bBroadcastEvents=true );
179 
180         // check all children for changes in posit�on and size
181         void UpdateBoundRect();
182 
183         // calls SetSelection on the forwarder and updates maLastSelection
184         // cache.
185         void UpdateSelection();
186 
187     private:
188 
189         // Process event queue
190         void ProcessQueue();
191 
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 ); }
195 
196         // shutdown usage of current edit source on myself and the children.
197         void ShutdownEditSource() SAL_THROW((uno::RuntimeException));
198 
199         void ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast );
200 
201         virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
202 
203         int getNotifierClientId() const { return mnNotifierClientId; }
204 
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));
211 
212         // are we in edit mode?
213         sal_Bool IsActive() const SAL_THROW((uno::RuntimeException));
214 
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;
219 
220         // a wrapper for the text forwarders (guarded by solar mutex)
221         mutable SvxEditSourceAdapter maEditSource;
222 
223         // store last selection (to correctly report selection changes, guarded by solar mutex)
224         ESelection maLastSelection;
225 
226         // cache range of visible children (guarded by solar mutex)
227         sal_Int32 mnFirstVisibleChild;
228         sal_Int32 mnLastVisibleChild;
229 
230         // offset to add to all our children (unguarded, relying on
231         // the fact that sal_Int32 access is atomic)
232         sal_Int32 mnStartIndex;
233 
234         // the object handling our children (guarded by solar mutex)
235         ::accessibility::AccessibleParaManager maParaManager;
236 
237         // number of not-yet-closed event frames (BEGIN/END sequences) (guarded by solar mutex)
238         sal_Int32 maEventOpenFrames;
239 
240         // Queued events from Notify() (guarded by solar mutex)
241         AccessibleTextEventQueue maEventQueue;
242 
243         // spin lock to prevent notify in notify (guarded by solar mutex)
244         sal_Bool mbInNotify;
245 
246         // whether the object or it's children has the focus set (guarded by solar mutex)
247         sal_Bool mbGroupHasFocus;
248 
249         // whether we (this object) has the focus set (guarded by solar mutex)
250         sal_Bool mbThisHasFocus;
251 
252         mutable ::osl::Mutex maMutex;
253 
254         /// our current offset to the containing shape/cell (guarded by maMutex)
255         Point maOffset;
256 
257         /// client Id from AccessibleEventNotifier
258         int mnNotifierClientId;
259     };
260 
261 	//------------------------------------------------------------------------
262 	//
263 	// AccessibleTextHelper_Impl implementation
264 	//
265 	//------------------------------------------------------------------------
266 
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())
284     {
285         DBG_CTOR( AccessibleTextHelper_Impl, NULL );
286 
287 #ifdef DBG_UTIL
288         OSL_TRACE( "AccessibleTextHelper_Impl received ID: %d", mnNotifierClientId );
289 #endif
290     }
291 
292     AccessibleTextHelper_Impl::~AccessibleTextHelper_Impl()
293     {
294         DBG_DTOR( AccessibleTextHelper_Impl, NULL );
295 
296         ::vos::OGuard aGuard( Application::GetSolarMutex() );
297 
298         try
299         {
300             // call Dispose here, too, since we've some resources not
301             // automatically freed otherwise
302             Dispose();
303         }
304         catch( const uno::Exception& ) {}
305     }
306 
307     SvxTextForwarder& AccessibleTextHelper_Impl::GetTextForwarder() const SAL_THROW((uno::RuntimeException))
308     {
309         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
310 
311         if( !maEditSource.IsValid() )
312             throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
313 
314         SvxTextForwarder* pTextForwarder = maEditSource.GetTextForwarder();
315 
316         if( !pTextForwarder )
317             throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch text forwarder, model might be dead")), mxFrontEnd);
318 
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);
323     }
324 
325     SvxViewForwarder& AccessibleTextHelper_Impl::GetViewForwarder() const SAL_THROW((uno::RuntimeException))
326     {
327         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
328 
329         if( !maEditSource.IsValid() )
330             throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
331 
332         SvxViewForwarder* pViewForwarder = maEditSource.GetViewForwarder();
333 
334         if( !pViewForwarder )
335             throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch view forwarder, model might be dead")), mxFrontEnd);
336 
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);
341     }
342 
343     SvxEditViewForwarder& AccessibleTextHelper_Impl::GetEditViewForwarder( sal_Bool bCreate ) const SAL_THROW((uno::RuntimeException))
344     {
345         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
346 
347         if( !maEditSource.IsValid() )
348             throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
349 
350         SvxEditViewForwarder* pViewForwarder = maEditSource.GetEditViewForwarder( bCreate );
351 
352         if( !pViewForwarder )
353         {
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);
358         }
359 
360         if( pViewForwarder->IsValid() )
361             return *pViewForwarder;
362         else
363         {
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);
368         }
369     }
370 
371     SvxEditSourceAdapter& AccessibleTextHelper_Impl::GetEditSource() const SAL_THROW((uno::RuntimeException))
372     {
373         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
374 
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 );
379     }
380 
381     sal_Bool AccessibleTextHelper_Impl::IsSelected() const
382     {
383         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
384 
385         sal_Bool bRet = sal_False;
386 
387         try
388         {
389             ESelection aSelection;
390             bRet = GetEditViewForwarder().GetSelection( aSelection );
391         }
392         catch( const uno::Exception& ) {}
393 
394         return bRet;
395     }
396 
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 >
399     {
400     public:
401         AccessibleTextHelper_OffsetChildIndex( sal_Int32 nDifference ) : mnDifference(nDifference) {}
402         void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
403         {
404             rPara.SetIndexInParent( rPara.GetIndexInParent() + mnDifference );
405         }
406 
407     private:
408         const sal_Int32 mnDifference;
409     };
410 
411     void AccessibleTextHelper_Impl::SetStartIndex( sal_Int32 nOffset )
412     {
413         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
414 
415         sal_Int32 nOldOffset( mnStartIndex );
416 
417         mnStartIndex = nOffset;
418 
419         if( nOldOffset != nOffset )
420         {
421             // update children
422             AccessibleTextHelper_OffsetChildIndex aFunctor( nOffset - nOldOffset );
423 
424             ::std::for_each( maParaManager.begin(), maParaManager.end(),
425                              AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_OffsetChildIndex > (aFunctor) );
426         }
427     }
428 
429     void AccessibleTextHelper_Impl::SetAdditionalChildStates( const VectorOfStates& rChildStates )
430     {
431         maParaManager.SetAdditionalChildStates( rChildStates );
432     }
433 
434     const AccessibleTextHelper_Impl::VectorOfStates& AccessibleTextHelper_Impl::GetAdditionalChildStates() const
435     {
436         return maParaManager.GetAdditionalChildStates();
437     }
438 
439     void AccessibleTextHelper_Impl::SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
440     {
441         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
442 
443         if( bHaveFocus )
444         {
445             if( mbThisHasFocus )
446                 SetShapeFocus( sal_False );
447 
448             maParaManager.SetFocus( nChild );
449 
450             // we just received the focus, also send caret event then
451             UpdateSelection();
452 
453             DBG_TRACE1("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d received focus", nChild );
454         }
455         else
456         {
457             maParaManager.SetFocus( -1 );
458 
459             DBG_TRACE1("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d lost focus", nChild );
460 
461             if( mbGroupHasFocus )
462                 SetShapeFocus( sal_True );
463         }
464     }
465 
466     void AccessibleTextHelper_Impl::ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException))
467     {
468         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
469 
470         if( mbThisHasFocus )
471             SetShapeFocus( sal_False );
472 
473         mbGroupHasFocus = sal_True;
474         maParaManager.SetFocus( nNewChild );
475 
476         DBG_TRACE1("AccessibleTextHelper_Impl::ChangeChildFocus(): Paragraph %d received focus", nNewChild );
477     }
478 
479     void AccessibleTextHelper_Impl::SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
480     {
481         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
482 
483         sal_Bool bOldFocus( mbThisHasFocus );
484 
485         mbThisHasFocus = bHaveFocus;
486 
487         if( bOldFocus != bHaveFocus )
488         {
489             if( bHaveFocus )
490             {
491                 GotPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
492                 DBG_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object received focus" );
493             }
494             else
495             {
496                 LostPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
497                 DBG_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object lost focus" );
498             }
499         }
500     }
501 
502     void AccessibleTextHelper_Impl::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
503     {
504         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
505 
506         sal_Bool bOldFocus( mbGroupHasFocus );
507 
508         mbGroupHasFocus = bHaveFocus;
509 
510         if( IsActive() )
511         {
512             try
513             {
514                 // find the one with the cursor and get/set focus accordingly
515                 ESelection aSelection;
516                 if( GetEditViewForwarder().GetSelection( aSelection ) )
517                     SetChildFocus( aSelection.nEndPara, bHaveFocus );
518             }
519             catch( const uno::Exception& ) {}
520         }
521         else if( bOldFocus != bHaveFocus )
522         {
523             SetShapeFocus( bHaveFocus );
524         }
525 
526         DBG_TRACE2("AccessibleTextHelper_Impl::SetFocus: focus changed, Object %d, state: %s", this, bHaveFocus ? "focused" : "not focused");
527     }
528 
529     sal_Bool AccessibleTextHelper_Impl::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException))
530     {
531         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
532 
533         // No locking of solar mutex here, since we rely on the fact
534         // that sal_Bool access is atomic
535         return mbThisHasFocus;
536     }
537 
538     sal_Bool AccessibleTextHelper_Impl::IsActive() const SAL_THROW((uno::RuntimeException))
539     {
540         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
541 
542         try
543         {
544             SvxEditSource& rEditSource = GetEditSource();
545             SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder();
546 
547             if( !pViewForwarder )
548                 return sal_False;
549 
550             if( pViewForwarder->IsValid() )
551                 return sal_True;
552             else
553                 return sal_False;
554         }
555         catch( const uno::RuntimeException& )
556         {
557             return sal_False;
558         }
559     }
560 
561     void AccessibleTextHelper_Impl::UpdateSelection()
562     {
563         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
564 
565         try
566         {
567             ESelection aSelection;
568             if( GetEditViewForwarder().GetSelection( aSelection ) )
569             {
570                 if( !maLastSelection.IsEqual( aSelection ) &&
571                     aSelection.nEndPara < maParaManager.GetNum() )
572                 {
573                     // #103998# Not that important, changed from assertion to trace
574                     if( mbThisHasFocus )
575                     {
576                         DBG_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): Parent has focus!");
577                     }
578 
579                     sal_uInt16 nMaxValidParaIndex( static_cast< sal_uInt16 >( GetTextForwarder().GetParagraphCount() ) - 1 );
580 
581                     // notify all affected paragraphs (TODO: may be suboptimal,
582                     // since some paragraphs might stay selected)
583                     if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND )
584                     {
585                         // Did the caret move from one paragraph to another?
586                         // #100530# no caret events if not focused.
587                         if( mbGroupHasFocus &&
588                             maLastSelection.nEndPara != aSelection.nEndPara )
589                         {
590                             if( maLastSelection.nEndPara < maParaManager.GetNum() )
591                             {
592 								maParaManager.FireEvent( ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ),
593 														 ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex )+1,
594 														 AccessibleEventId::CARET_CHANGED,
595 														 uno::makeAny(static_cast<sal_Int32>(-1)),
596 														 uno::makeAny(static_cast<sal_Int32>(maLastSelection.nEndPos)) );
597                             }
598 
599                             ChangeChildFocus( aSelection.nEndPara );
600 
601                             DBG_TRACE3("AccessibleTextHelper_Impl::UpdateSelection(): focus changed, Object: %d, Paragraph: %d, Last paragraph: %d",
602                                        this, aSelection.nEndPara, maLastSelection.nEndPara);
603                         }
604                     }
605 
606                     // #100530# no caret events if not focused.
607                     if( mbGroupHasFocus )
608                     {
609                         uno::Any aOldCursor;
610 
611                         // #i13705# The old cursor can only contain valid
612                         // values if it's the same paragraph!
613                         if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND &&
614                             maLastSelection.nEndPara == aSelection.nEndPara )
615                         {
616                             aOldCursor <<= static_cast<sal_Int32>(maLastSelection.nEndPos);
617                         }
618                         else
619                         {
620                             aOldCursor <<= static_cast<sal_Int32>(-1);
621                         }
622 
623                         maParaManager.FireEvent( aSelection.nEndPara,
624                                                  aSelection.nEndPara+1,
625                                                  AccessibleEventId::CARET_CHANGED,
626                                                  uno::makeAny(static_cast<sal_Int32>(aSelection.nEndPos)),
627                                                  aOldCursor );
628                     }
629 
630                     DBG_TRACE5("AccessibleTextHelper_Impl::UpdateSelection(): caret changed, Object: %d, New pos: %d, Old pos: %d, New para: %d, Old para: %d",
631                                this, aSelection.nEndPos, maLastSelection.nEndPos, aSelection.nEndPara, maLastSelection.nEndPara);
632 
633                     // #108947# Sort new range before calling FireEvent
634                     ::std::pair< xub_StrLen, xub_StrLen > sortedSelection(
635                         makeSortedPair(::std::min( aSelection.nStartPara, nMaxValidParaIndex ),
636                                        ::std::min( aSelection.nEndPara, nMaxValidParaIndex ) ) );
637 
638                     // #108947# Sort last range before calling FireEvent
639                     ::std::pair< xub_StrLen, xub_StrLen > sortedLastSelection(
640                         makeSortedPair(::std::min( maLastSelection.nStartPara, nMaxValidParaIndex ),
641                                        ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ) ) );
642 
643                     // --> OD 2005-12-15 #i27299#
644                     // event TEXT_SELECTION_CHANGED has to be submitted.
645                     const sal_Int16 nTextSelChgEventId =
646                                     AccessibleEventId::TEXT_SELECTION_CHANGED;
647                     // <--
648                     // #107037# notify selection change
649                     if( maLastSelection.nStartPara == EE_PARA_NOT_FOUND )
650                     {
651                         // last selection is undefined
652                         // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()>
653                         if ( aSelection.HasRange() )
654                         // <--
655                         {
656                             // selection was undefined, now is on
657                             maParaManager.FireEvent( sortedSelection.first,
658                                                      sortedSelection.second+1,
659                                                      nTextSelChgEventId );
660                         }
661                     }
662                     else
663                     {
664                         // last selection is valid
665                         // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()>
666                         if ( maLastSelection.HasRange() &&
667                              !aSelection.HasRange() )
668                         // <--
669                         {
670                             // selection was on, now is empty
671                             maParaManager.FireEvent( sortedLastSelection.first,
672                                                      sortedLastSelection.second+1,
673                                                      nTextSelChgEventId );
674                         }
675                         // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()>
676                         else if( !maLastSelection.HasRange() &&
677                                  aSelection.HasRange() )
678                         // <--
679                         {
680                             // selection was empty, now is on
681                             maParaManager.FireEvent( sortedSelection.first,
682                                                      sortedSelection.second+1,
683                                                      nTextSelChgEventId );
684                         }
685                         // --> OD 2005-12-15 #i27299#
686                         // - no event TEXT_SELECTION_CHANGED event, if new and
687                         //   last selection are empty.
688                         else if ( maLastSelection.HasRange() &&
689                                   aSelection.HasRange() )
690                         // <--
691                         {
692                             // --> OD 2005-12-16 #i27299#
693                             // - send event TEXT_SELECTION_CHANGED for difference
694                             //   between last and new selection.
695 //                            // selection was on, now is different: take union of ranges
696 //                            maParaManager.FireEvent( ::std::min(sortedSelection.first,
697 //                                                           sortedLastSelection.second),
698 //                                                     ::std::max(sortedSelection.first,
699 //                                                           sortedLastSelection.second)+1,
700 //                                                     nTextSelChgEventId );
701                             // use sorted last and new selection
702                             ESelection aTmpLastSel( maLastSelection );
703                             aTmpLastSel.Adjust();
704                             ESelection aTmpSel( aSelection );
705                             aTmpSel.Adjust();
706                             // first submit event for new and changed selection
707                             sal_uInt32 nPara = aTmpSel.nStartPara;
708                             for ( ; nPara <= aTmpSel.nEndPara; ++nPara )
709                             {
710                                 if ( nPara < aTmpLastSel.nStartPara ||
711                                      nPara > aTmpLastSel.nEndPara )
712                                 {
713                                     // new selection on paragraph <nPara>
714                                     maParaManager.FireEvent( nPara,
715                                                              nTextSelChgEventId );
716                                 }
717                                 else
718                                 {
719                                     // check for changed selection on paragraph <nPara>
720                                     const xub_StrLen nParaStartPos =
721                                             nPara == aTmpSel.nStartPara
722                                             ? aTmpSel.nStartPos : 0;
723                                     const xub_StrLen nParaEndPos =
724                                             nPara == aTmpSel.nEndPara
725                                             ? aTmpSel.nEndPos : STRING_LEN;
726                                     const xub_StrLen nLastParaStartPos =
727                                             nPara == aTmpLastSel.nStartPara
728                                             ? aTmpLastSel.nStartPos : 0;
729                                     const xub_StrLen nLastParaEndPos =
730                                             nPara == aTmpLastSel.nEndPara
731                                             ? aTmpLastSel.nEndPos : STRING_LEN;
732                                     if ( nParaStartPos != nLastParaStartPos ||
733                                          nParaEndPos != nLastParaEndPos )
734                                     {
735                                         maParaManager.FireEvent(
736                                                     nPara, nTextSelChgEventId );
737                                     }
738                                 }
739                             }
740                             // second submit event for 'old' selections
741                             nPara = aTmpLastSel.nStartPara;
742                             for ( ; nPara <= aTmpLastSel.nEndPara; ++nPara )
743                             {
744                                 if ( nPara < aTmpSel.nStartPara ||
745                                      nPara > aTmpSel.nEndPara )
746                                 {
747                                     maParaManager.FireEvent( nPara,
748                                                              nTextSelChgEventId );
749                                 }
750                             }
751                         }
752                     }
753 
754                     maLastSelection = aSelection;
755                 }
756             }
757         }
758         // no selection? no update actions
759         catch( const uno::RuntimeException& ) {}
760     }
761 
762     void AccessibleTextHelper_Impl::ShutdownEditSource() SAL_THROW((uno::RuntimeException))
763     {
764         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
765 
766         // This should only be called with solar mutex locked, i.e. from the main office thread
767 
768         // This here is somewhat clumsy: As soon as our children have
769         // a NULL EditSource (maParaManager.SetEditSource()), they
770         // enter the disposed state and cannot be reanimated. Thus, it
771         // is unavoidable and a hard requirement to let go and create
772         // from scratch each and every child.
773 
774         // invalidate children
775         maParaManager.Dispose();
776         maParaManager.SetNum(0);
777 
778         // lost all children
779         if( mxFrontEnd.is() )
780             FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
781 
782         // quit listen on stale edit source
783         if( maEditSource.IsValid() )
784             EndListening( maEditSource.GetBroadcaster() );
785 
786         maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) );
787     }
788 
789     void AccessibleTextHelper_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
790     {
791         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
792 
793         // This should only be called with solar mutex locked, i.e. from the main office thread
794 
795         // shutdown old edit source
796         ShutdownEditSource();
797 
798         // set new edit source
799         maEditSource.SetEditSource( pEditSource );
800 
801         // init child vector to the current child count
802         if( maEditSource.IsValid() )
803         {
804             maParaManager.SetNum( GetTextForwarder().GetParagraphCount() );
805 
806             // listen on new edit source
807             StartListening( maEditSource.GetBroadcaster() );
808 
809             UpdateVisibleChildren();
810         }
811     }
812 
813     void AccessibleTextHelper_Impl::SetOffset( const Point& rPoint )
814     {
815         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
816 
817         // guard against non-atomic access to maOffset data structure
818         {
819             ::osl::MutexGuard aGuard( maMutex );
820             maOffset = rPoint;
821         }
822 
823         maParaManager.SetEEOffset( rPoint );
824 
825         // in all cases, check visibility afterwards.
826         UpdateVisibleChildren();
827         UpdateBoundRect();
828     }
829 
830     void AccessibleTextHelper_Impl::UpdateVisibleChildren( bool bBroadcastEvents )
831     {
832         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
833 
834         try
835         {
836             SvxTextForwarder& rCacheTF = GetTextForwarder();
837             SvxViewForwarder& rCacheVF = GetViewForwarder();
838 
839             Rectangle aViewArea = rCacheVF.GetVisArea();
840 
841             if( IsActive() )
842             {
843                 // maybe the edit view scrolls, adapt aViewArea
844                 Rectangle aEditViewArea = GetEditViewForwarder().GetVisArea();
845                 aViewArea += aEditViewArea.TopLeft();
846 
847                 // now determine intersection
848                 aViewArea.Intersection( aEditViewArea );
849             }
850 
851             Rectangle aTmpBB, aParaBB;
852             sal_Bool bFirstChild = sal_True;
853             sal_Int32 nCurrPara;
854             sal_Int32 nParas=rCacheTF.GetParagraphCount();
855 
856             mnFirstVisibleChild = -1;
857             mnLastVisibleChild = -2;
858 
859             for( nCurrPara=0; nCurrPara<nParas; ++nCurrPara )
860             {
861                 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX,
862                            "AccessibleTextHelper_Impl::UpdateVisibleChildren: index value overflow");
863 
864                 aTmpBB = rCacheTF.GetParaBounds( static_cast< sal_uInt16 >( nCurrPara ) );
865 
866                 // convert to screen coordinates
867                 aParaBB = ::accessibility::AccessibleEditableTextPara::LogicToPixel( aTmpBB, rCacheTF.GetMapMode(), rCacheVF );
868 
869                 if( aParaBB.IsOver( aViewArea ) )
870                 {
871                     // at least partially visible
872                     if( bFirstChild )
873                     {
874                         bFirstChild = sal_False;
875                         mnFirstVisibleChild = nCurrPara;
876                     }
877 
878                     mnLastVisibleChild = nCurrPara;
879 
880                     // child not yet created?
881                     ::accessibility::AccessibleParaManager::WeakChild aChild( maParaManager.GetChild(nCurrPara) );
882                     if( aChild.second.Width == 0 &&
883                         aChild.second.Height == 0 &&
884                         mxFrontEnd.is() &&
885                         bBroadcastEvents )
886                     {
887                         GotPropertyEvent( uno::makeAny( maParaManager.CreateChild( nCurrPara - mnFirstVisibleChild,
888                                                                                    mxFrontEnd, GetEditSource(), nCurrPara ).first ),
889                                           AccessibleEventId::CHILD );
890                     }
891                 }
892                 else
893                 {
894                     // not or no longer visible
895                     if( maParaManager.IsReferencable( nCurrPara ) )
896                     {
897                         if( bBroadcastEvents )
898                             LostPropertyEvent( uno::makeAny( maParaManager.GetChild( nCurrPara ).first.get().getRef() ),
899                                                AccessibleEventId::CHILD );
900 
901                         // clear reference
902                         maParaManager.Release( nCurrPara );
903                     }
904                 }
905             }
906         }
907         catch( const uno::Exception& )
908         {
909             DBG_ERROR("AccessibleTextHelper_Impl::UpdateVisibleChildren error while determining visible children");
910 
911             // something failed - currently no children
912             mnFirstVisibleChild = -1;
913             mnLastVisibleChild = -2;
914             maParaManager.SetNum(0);
915 
916             // lost all children
917             if( bBroadcastEvents )
918                 FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
919         }
920     }
921 
922 	// functor for checking changes in paragraph bounding boxes (no stand-alone function, maybe not inlined)
923     class AccessibleTextHelper_UpdateChildBounds : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&,
924         ::accessibility::AccessibleParaManager::WeakChild >
925     {
926     public:
927         AccessibleTextHelper_UpdateChildBounds( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
928         ::accessibility::AccessibleParaManager::WeakChild operator()( const ::accessibility::AccessibleParaManager::WeakChild& rChild )
929         {
930             // retrieve hard reference from weak one
931             ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rChild.first.get() );
932 
933             if( aHardRef.is() )
934             {
935                 awt::Rectangle  		aNewRect = aHardRef->getBounds();
936                 const awt::Rectangle& 	aOldRect = rChild.second;
937 
938                 if( aNewRect.X != aOldRect.X ||
939                     aNewRect.Y != aOldRect.Y ||
940                     aNewRect.Width != aOldRect.Width ||
941                     aNewRect.Height != aOldRect.Height )
942                 {
943                     // visible data changed
944                     aHardRef->FireEvent( AccessibleEventId::BOUNDRECT_CHANGED );
945 
946                     // update internal bounds
947                     return ::accessibility::AccessibleParaManager::WeakChild( rChild.first, aNewRect );
948                 }
949             }
950 
951             // identity transform
952             return rChild;
953         }
954 
955     private:
956         AccessibleTextHelper_Impl&	mrImpl;
957     };
958 
959     void AccessibleTextHelper_Impl::UpdateBoundRect()
960     {
961         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
962 
963         // send BOUNDRECT_CHANGED to affected children
964         AccessibleTextHelper_UpdateChildBounds aFunctor( *this );
965         ::std::transform( maParaManager.begin(), maParaManager.end(), maParaManager.begin(), aFunctor );
966     }
967 
968 #ifdef DBG_UTIL
969     void AccessibleTextHelper_Impl::CheckInvariants() const
970     {
971         if( mnFirstVisibleChild >= 0 &&
972             mnFirstVisibleChild > mnLastVisibleChild )
973         {
974             DBG_ERROR( "AccessibleTextHelper: range invalid" );
975         }
976     }
977 #endif
978 
979 	// functor for sending child events (no stand-alone function, they are maybe not inlined)
980     class AccessibleTextHelper_LostChildEvent : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&, void >
981     {
982     public:
983         AccessibleTextHelper_LostChildEvent( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
984         void operator()( const ::accessibility::AccessibleParaManager::WeakChild& rPara )
985         {
986             // retrieve hard reference from weak one
987             ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rPara.first.get() );
988 
989             if( aHardRef.is() )
990                 mrImpl.FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( aHardRef.getRef() ) );
991         }
992 
993     private:
994         AccessibleTextHelper_Impl&	mrImpl;
995     };
996 
997     void AccessibleTextHelper_Impl::ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast )
998     {
999         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1000 
1001         const sal_Int32 nParas = GetTextForwarder().GetParagraphCount();
1002 
1003         /* rotate paragraphs
1004          * =================
1005          *
1006          * Three cases:
1007          *
1008          * 1.
1009          *   ... nParagraph ... nParam1 ... nParam2 ...
1010          *       |______________[xxxxxxxxxxx]
1011          *              becomes
1012          *       [xxxxxxxxxxx]|______________
1013          *
1014          * tail is 0
1015          *
1016          * 2.
1017          *   ... nParam1 ... nParagraph ... nParam2 ...
1018          *       [xxxxxxxxxxx|xxxxxxxxxxxxxx]____________
1019          *              becomes
1020          *       ____________[xxxxxxxxxxx|xxxxxxxxxxxxxx]
1021          *
1022          * tail is nParagraph - nParam1
1023          *
1024          * 3.
1025          *   ... nParam1 ... nParam2 ... nParagraph ...
1026          *       [xxxxxxxxxxx]___________|____________
1027          *              becomes
1028          *       ___________|____________[xxxxxxxxxxx]
1029          *
1030          * tail is nParam2 - nParam1
1031          */
1032 
1033         // sort nParagraph, nParam1 and nParam2 in ascending order, calc range
1034         if( nMiddle < nFirst )
1035         {
1036             ::std::swap(nFirst, nMiddle);
1037         }
1038         else if( nMiddle < nLast )
1039         {
1040             nLast = nLast + nMiddle - nFirst;
1041         }
1042         else
1043         {
1044             ::std::swap(nMiddle, nLast);
1045             nLast = nLast + nMiddle - nFirst;
1046         }
1047 
1048         if( nFirst < nParas && nMiddle < nParas && nLast < nParas )
1049         {
1050             // since we have no "paragraph index
1051             // changed" event on UAA, remove
1052             // [first,last] and insert again later (in
1053             // UpdateVisibleChildren)
1054 
1055             // maParaManager.Rotate( nFirst, nMiddle, nLast );
1056 
1057             // send CHILD_EVENT to affected children
1058             ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
1059             ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
1060 
1061             ::std::advance( begin, nFirst );
1062             ::std::advance( end, nLast+1 );
1063 
1064             // TODO: maybe optimize here in the following way.  If the
1065             // number of removed children exceeds a certain threshold,
1066             // use INVALIDATE_CHILDREN
1067             AccessibleTextHelper_LostChildEvent aFunctor( *this );
1068 
1069             ::std::for_each( begin, end, aFunctor );
1070 
1071             maParaManager.Release(nFirst, nLast+1);
1072             // should be no need for UpdateBoundRect, since all affected children are cleared.
1073         }
1074     }
1075 
1076 	// functor for sending child events (no stand-alone function, they are maybe not inlined)
1077     class AccessibleTextHelper_ChildrenTextChanged : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
1078     {
1079     public:
1080         void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
1081         {
1082             rPara.TextChanged();
1083         }
1084     };
1085 
1086 	/** functor processing queue events
1087 
1088     	Reacts on TEXT_HINT_PARAINSERTED/REMOVED events and stores
1089     	their content
1090      */
1091     class AccessibleTextHelper_QueueFunctor : public ::std::unary_function< const SfxHint*, void >
1092     {
1093     public:
1094         AccessibleTextHelper_QueueFunctor() :
1095             mnParasChanged( 0 ),
1096             mnParaIndex(-1),
1097             mnHintId(-1)
1098         {}
1099         void operator()( const SfxHint* pEvent )
1100         {
1101             if( pEvent &&
1102                 mnParasChanged != -1 )
1103             {
1104                 // determine hint type
1105                 const TextHint* pTextHint = PTR_CAST( TextHint, pEvent );
1106                 const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, pEvent );
1107 
1108                 if( !pEditSourceHint && pTextHint &&
1109                     (pTextHint->GetId() == TEXT_HINT_PARAINSERTED ||
1110                      pTextHint->GetId() == TEXT_HINT_PARAREMOVED ) )
1111                 {
1112                     if( pTextHint->GetValue() == EE_PARA_ALL )
1113                     {
1114                         mnParasChanged = -1;
1115                     }
1116                     else
1117                     {
1118                         mnHintId = pTextHint->GetId();
1119                         mnParaIndex = pTextHint->GetValue();
1120                         ++mnParasChanged;
1121                     }
1122                 }
1123             }
1124         }
1125 
1126         /** Query number of paragraphs changed during queue processing.
1127 
1128         	@return number of changed paragraphs, -1 for
1129             "every paragraph changed"
1130         */
1131         int GetNumberOfParasChanged() { return mnParasChanged; }
1132         /** Query index of last added/removed paragraph
1133 
1134         	@return index of lastly added paragraphs, -1 for none
1135         	added so far.
1136         */
1137         int GetParaIndex() { return mnParaIndex; }
1138         /** Query hint id of last interesting event
1139 
1140         	@return hint id of last interesting event (REMOVED/INSERTED).
1141         */
1142         int GetHintId() { return mnHintId; }
1143 
1144     private:
1145         /** number of paragraphs changed during queue processing. -1 for
1146             "every paragraph changed"
1147         */
1148         int mnParasChanged;
1149         /// index of paragraph added/removed last
1150         int mnParaIndex;
1151         /// TextHint ID (removed/inserted) of last interesting event
1152         int mnHintId;
1153     };
1154 
1155     void AccessibleTextHelper_Impl::ProcessQueue()
1156     {
1157         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1158 
1159         // inspect queue for paragraph insert/remove events. If there
1160         // is exactly _one_ of those in the queue, and the number of
1161         // paragraphs has changed by exactly one, use that event to
1162         // determine a priori which paragraph was added/removed. This
1163         // is necessary, since I must sync right here with the
1164         // EditEngine state (number of paragraphs etc.), since I'm
1165         // potentially sending listener events right away.
1166         AccessibleTextHelper_QueueFunctor aFunctor;
1167         maEventQueue.ForEach( aFunctor );
1168 
1169         const sal_Int32 nNewParas( GetTextForwarder().GetParagraphCount() );
1170         const sal_Int32 nCurrParas( maParaManager.GetNum() );
1171 
1172         // whether every paragraph already is updated (no need to
1173         // repeat that later on, e.g. for PARA_MOVED events)
1174         bool			bEverythingUpdated( false );
1175 
1176         if( labs( nNewParas - nCurrParas ) == 1 &&
1177             aFunctor.GetNumberOfParasChanged() == 1 )
1178         {
1179             // #103483# Exactly one paragraph added/removed. This is
1180             // the normal case, optimize event handling here.
1181 
1182             if( aFunctor.GetHintId() == TEXT_HINT_PARAINSERTED )
1183             {
1184                 // update num of paras
1185                 maParaManager.SetNum( nNewParas );
1186 
1187                 // release everything from the insertion position until the end
1188                 maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas);
1189 
1190                 // TODO: Clarify whether this behaviour _really_ saves
1191                 // anybody anything!
1192                 // update children, _don't_ broadcast
1193                 UpdateVisibleChildren( false );
1194                 UpdateBoundRect();
1195 
1196                 // send insert event
1197                 // #109864# Enforce creation of this paragraph
1198                 try
1199                 {
1200                     GotPropertyEvent( uno::makeAny( getAccessibleChild( aFunctor.GetParaIndex() -
1201                                                                         mnFirstVisibleChild + GetStartIndex() ) ),
1202                                       AccessibleEventId::CHILD );
1203                 }
1204                 catch( const uno::Exception& )
1205                 {
1206                     DBG_ERROR("AccessibleTextHelper_Impl::ProcessQueue: could not create new paragraph");
1207                 }
1208             }
1209             else if( aFunctor.GetHintId() == TEXT_HINT_PARAREMOVED )
1210             {
1211                 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
1212                 ::std::advance( begin, aFunctor.GetParaIndex() );
1213                 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
1214                 ::std::advance( end, 1 );
1215 
1216 				// #i61812# remember para to be removed for later notification
1217 				// AFTER the new state is applied (that after the para got removed)
1218 				::uno::Reference< XAccessible > xPara;
1219 				::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( begin->first.get() );
1220 				if( aHardRef.is() )
1221 					xPara = ::uno::Reference< XAccessible >( aHardRef.getRef(), ::uno::UNO_QUERY );
1222 
1223                 // release everything from the remove position until the end
1224                 maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas);
1225 
1226                 // update num of paras
1227                 maParaManager.SetNum( nNewParas );
1228 
1229                 // TODO: Clarify whether this behaviour _really_ saves
1230                 // anybody anything!
1231                 // update children, _don't_ broadcast
1232                 UpdateVisibleChildren( false );
1233                 UpdateBoundRect();
1234 
1235 				// #i61812# notification for removed para
1236 				if (xPara.is())
1237 	            	FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( xPara) );
1238             }
1239 #ifdef DBG_UTIL
1240             else
1241                 DBG_ERROR("AccessibleTextHelper_Impl::ProcessQueue() invalid hint id");
1242 #endif
1243         }
1244         else if( nNewParas != nCurrParas )
1245         {
1246             // release all paras
1247             maParaManager.Release(0, nCurrParas);
1248 
1249             // update num of paras
1250             maParaManager.SetNum( nNewParas );
1251 
1252             // #109864# create from scratch, don't broadcast
1253             UpdateVisibleChildren( false );
1254             UpdateBoundRect();
1255 
1256             // number of paragraphs somehow changed - but we have no
1257             // chance determining how. Thus, throw away everything and
1258             // create from scratch.
1259 			// (child events should be broadcast after the changes are done...)
1260             FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
1261 
1262             // no need for further updates later on
1263             bEverythingUpdated = true;
1264         }
1265 
1266         while( !maEventQueue.IsEmpty() )
1267         {
1268             ::std::auto_ptr< SfxHint > pHint( maEventQueue.PopFront() );
1269             if( pHint.get() )
1270             {
1271                 const SfxHint& rHint = *(pHint.get());
1272 
1273                 // determine hint type
1274                 const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint );
1275                 const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint );
1276                 const TextHint* pTextHint = PTR_CAST( TextHint, &rHint );
1277                 const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint );
1278                 const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint );
1279 
1280                 try
1281                 {
1282                     const sal_Int32 nParas = GetTextForwarder().GetParagraphCount();
1283 
1284                     if( pEditSourceHint )
1285                     {
1286                         switch( pEditSourceHint->GetId() )
1287                         {
1288                             case EDITSOURCE_HINT_PARASMOVED:
1289                             {
1290                                 DBG_ASSERT( pEditSourceHint->GetStartValue() < GetTextForwarder().GetParagraphCount() &&
1291                                             pEditSourceHint->GetEndValue() < GetTextForwarder().GetParagraphCount(),
1292                                             "AccessibleTextHelper_Impl::NotifyHdl: Invalid notification");
1293 
1294                                 if( !bEverythingUpdated )
1295                                 {
1296                                     ParagraphsMoved(pEditSourceHint->GetStartValue(),
1297                                                     pEditSourceHint->GetValue(),
1298                                                     pEditSourceHint->GetEndValue());
1299 
1300                                     // in all cases, check visibility afterwards.
1301                                     UpdateVisibleChildren();
1302                                 }
1303                                 break;
1304                             }
1305 
1306                             case EDITSOURCE_HINT_SELECTIONCHANGED:
1307                                 // notify listeners
1308                                 try
1309                                 {
1310                                     UpdateSelection();
1311                                 }
1312                                 // maybe we're not in edit mode (this is not an error)
1313                                 catch( const uno::Exception& ) {}
1314                                 break;
1315                         }
1316                     }
1317                     else if( pTextHint )
1318                     {
1319                         switch( pTextHint->GetId() )
1320                         {
1321                             case TEXT_HINT_MODIFIED:
1322                             {
1323                                 // notify listeners
1324                                 sal_Int32 nPara( pTextHint->GetValue() );
1325 
1326                                 // #108900# Delegate change event to children
1327                                 AccessibleTextHelper_ChildrenTextChanged aNotifyChildrenFunctor;
1328 
1329                                 if( nPara == static_cast<sal_Int32>(EE_PARA_ALL) )
1330                                 {
1331                                     // #108900# Call every child
1332                                     ::std::for_each( maParaManager.begin(), maParaManager.end(),
1333                                                      AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
1334                                 }
1335                                 else
1336                                     if( nPara < nParas )
1337                                     {
1338                                         // #108900# Call child at index nPara
1339                                         ::std::for_each( maParaManager.begin()+nPara, maParaManager.begin()+nPara+1,
1340                                                          AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
1341                                     }
1342                                 break;
1343                             }
1344 
1345                             case TEXT_HINT_PARAINSERTED:
1346                                 // already happened above
1347                                 break;
1348 
1349                             case TEXT_HINT_PARAREMOVED:
1350                                 // already happened above
1351                                 break;
1352 
1353                             case TEXT_HINT_TEXTHEIGHTCHANGED:
1354                                 // visibility changed, done below
1355                                 break;
1356 
1357                             case TEXT_HINT_VIEWSCROLLED:
1358                                 // visibility changed, done below
1359                                 break;
1360                         }
1361 
1362                         // in all cases, check visibility afterwards.
1363                         UpdateVisibleChildren();
1364                         UpdateBoundRect();
1365                     }
1366                     else if( pViewHint )
1367                     {
1368                         switch( pViewHint->GetHintType() )
1369                         {
1370                             case SvxViewHint::SVX_HINT_VIEWCHANGED:
1371                                 // just check visibility
1372                                 UpdateVisibleChildren();
1373                                 UpdateBoundRect();
1374                                 break;
1375                         }
1376                     }
1377                     else if( pSdrHint )
1378                     {
1379                         switch( pSdrHint->GetKind() )
1380                         {
1381                             case HINT_BEGEDIT:
1382                             {
1383                                 // change children state
1384                                 maParaManager.SetActive();
1385 
1386                                 // per definition, edit mode text has the focus
1387                                 SetFocus( sal_True );
1388                                 break;
1389                             }
1390 
1391                             case HINT_ENDEDIT:
1392                             {
1393                                 // focused child now looses focus
1394                                 ESelection aSelection;
1395                                 if( GetEditViewForwarder().GetSelection( aSelection ) )
1396                                     SetChildFocus( aSelection.nEndPara, sal_False );
1397 
1398                                 // change children state
1399                                 maParaManager.SetActive( sal_False );
1400 
1401                                 maLastSelection = ESelection( EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND,
1402                                                               EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND);
1403                                 break;
1404                             }
1405                             default:
1406                                 break;
1407                         }
1408                     }
1409                     // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above!
1410                     else if( pSimpleHint )
1411                     {
1412                         switch( pSimpleHint->GetId() )
1413                         {
1414                             case SFX_HINT_DYING:
1415                                 // edit source is dying under us, become defunc then
1416                                 try
1417                                 {
1418                                     // make edit source inaccessible
1419                                     // Note: cannot destroy it here, since we're called from there!
1420                                     ShutdownEditSource();
1421                                 }
1422                                 catch( const uno::Exception& ) {}
1423 
1424                                 break;
1425                         }
1426                     }
1427                 }
1428                 catch( const uno::Exception& )
1429                 {
1430 #ifdef DBG_UTIL
1431                     OSL_TRACE("AccessibleTextHelper_Impl::ProcessQueue: Unhandled exception.");
1432 #endif
1433                 }
1434             }
1435         }
1436     }
1437 
1438     void AccessibleTextHelper_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1439     {
1440         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1441 
1442         // precondition: solar mutex locked
1443         DBG_TESTSOLARMUTEX();
1444 
1445         // precondition: not in a recursion
1446         if( mbInNotify )
1447             return;
1448 
1449         mbInNotify = sal_True;
1450 
1451         // determine hint type
1452         const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint );
1453         const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint );
1454         const TextHint* pTextHint = PTR_CAST( TextHint, &rHint );
1455         const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint );
1456         const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint );
1457 
1458         try
1459         {
1460             // Process notification event
1461             if( pEditSourceHint )
1462             {
1463                 maEventQueue.Append( *pEditSourceHint );
1464                 // --> OD 2005-12-19 #i27299#
1465                 if( maEventOpenFrames == 0 )
1466                     ProcessQueue();
1467                 // <--
1468             }
1469             else if( pTextHint )
1470             {
1471                 switch( pTextHint->GetId() )
1472                 {
1473                     case TEXT_HINT_BLOCKNOTIFICATION_END:
1474                     case TEXT_HINT_INPUT_END:
1475                         --maEventOpenFrames;
1476 
1477                         if( maEventOpenFrames == 0 )
1478                         {
1479                             // #103483#
1480                             /* All information should have arrived
1481                              * now, process queue. As stated in the
1482                              * above bug, we can often avoid throwing
1483                              * away all paragraphs by looking forward
1484                              * in the event queue (searching for
1485                              * PARAINSERT/REMOVE events). Furthermore,
1486                              * processing the event queue only at the
1487                              * end of an interaction cycle, ensures
1488                              * that the EditEngine state and the
1489                              * AccessibleText state are the same
1490                              * (well, mostly. If there are _multiple_
1491                              * interaction cycles in the EE queues, it
1492                              * can still happen that EE state is
1493                              * different. That's so to say broken by
1494                              * design with that delayed EE event
1495                              * concept).
1496                              */
1497                             ProcessQueue();
1498                         }
1499                         break;
1500 
1501                     case TEXT_HINT_BLOCKNOTIFICATION_START:
1502                     case TEXT_HINT_INPUT_START:
1503                         ++maEventOpenFrames;
1504                         // --> OD 2005-12-19 #i27299# - no FALLTROUGH
1505                         // reason: event will not be processes, thus appending
1506                         // the event isn't necessary.
1507                         break;
1508                         // <--
1509                     default:
1510                         maEventQueue.Append( *pTextHint );
1511                         // --> OD 2005-12-19 #i27299#
1512                         if( maEventOpenFrames == 0 )
1513                             ProcessQueue();
1514                         // <--
1515                         break;
1516                 }
1517             }
1518             else if( pViewHint )
1519             {
1520                 maEventQueue.Append( *pViewHint );
1521 
1522                 // process visibility right away, if not within an
1523                 // open EE notification frame. Otherwise, event
1524                 // processing would be delayed until next EE
1525                 // notification sequence.
1526                 if( maEventOpenFrames == 0 )
1527                     ProcessQueue();
1528             }
1529             else if( pSdrHint )
1530             {
1531                 maEventQueue.Append( *pSdrHint );
1532 
1533                 // process drawing layer events right away, if not
1534                 // within an open EE notification frame. Otherwise,
1535                 // event processing would be delayed until next EE
1536                 // notification sequence.
1537                 if( maEventOpenFrames == 0 )
1538                     ProcessQueue();
1539             }
1540             // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above!
1541             else if( pSimpleHint )
1542             {
1543                 // handle this event _at once_, because after that, objects are invalid
1544                 switch( pSimpleHint->GetId() )
1545                 {
1546                     case SFX_HINT_DYING:
1547                         // edit source is dying under us, become defunc then
1548                         maEventQueue.Clear();
1549                         try
1550                         {
1551                             // make edit source inaccessible
1552                             // Note: cannot destroy it here, since we're called from there!
1553                             ShutdownEditSource();
1554                         }
1555                         catch( const uno::Exception& ) {}
1556 
1557                         break;
1558                 }
1559             }
1560         }
1561         catch( const uno::Exception& )
1562         {
1563 #ifdef DBG_UTIL
1564             OSL_TRACE("AccessibleTextHelper_Impl::Notify: Unhandled exception.");
1565 #endif
1566             mbInNotify = sal_False;
1567         }
1568 
1569         mbInNotify = sal_False;
1570     }
1571 
1572     void AccessibleTextHelper_Impl::Dispose()
1573     {
1574         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1575 
1576         if( getNotifierClientId() != -1 )
1577         {
1578             try
1579             {
1580                 // #106234# Unregister from EventNotifier
1581                 ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() );
1582 #ifdef DBG_UTIL
1583                 OSL_TRACE( "AccessibleTextHelper_Impl disposed ID: %d", mnNotifierClientId );
1584 #endif
1585             }
1586             catch( const uno::Exception& ) {}
1587 
1588             mnNotifierClientId = -1;
1589         }
1590 
1591         try
1592         {
1593             // dispose children
1594             maParaManager.Dispose();
1595         }
1596         catch( const uno::Exception& ) {}
1597 
1598         // quit listen on stale edit source
1599         if( maEditSource.IsValid() )
1600             EndListening( maEditSource.GetBroadcaster() );
1601 
1602         // clear references
1603         maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) );
1604         mxFrontEnd = NULL;
1605     }
1606 
1607     void AccessibleTextHelper_Impl::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const
1608     {
1609         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1610 
1611 		// -- object locked --
1612         ::osl::ClearableMutexGuard aGuard( maMutex );
1613 
1614         AccessibleEventObject aEvent;
1615 
1616         DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper::FireEvent: no event source set" );
1617 
1618         if( mxFrontEnd.is() )
1619             aEvent = AccessibleEventObject(mxFrontEnd->getAccessibleContext(), nEventId, rNewValue, rOldValue);
1620         else
1621             aEvent = AccessibleEventObject(uno::Reference< uno::XInterface >(), nEventId, rNewValue, rOldValue);
1622 
1623         // no locking necessary, FireEvent internally copies listeners
1624         // if someone removes/adds in between Further locking,
1625         // actually, might lead to deadlocks, since we're calling out
1626         // of this object
1627         aGuard.clear();
1628 		// -- until here --
1629 
1630         FireEvent(aEvent);
1631     }
1632 
1633     void AccessibleTextHelper_Impl::FireEvent( const AccessibleEventObject& rEvent ) const
1634     {
1635         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1636 
1637         // #102261# Call global queue for focus events
1638         if( rEvent.EventId == AccessibleStateType::FOCUSED )
1639             vcl::unohelper::NotifyAccessibleStateEventGlobally( rEvent );
1640 
1641         // #106234# Delegate to EventNotifier
1642         ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(),
1643                                                          rEvent );
1644     }
1645 
1646 	// XAccessibleContext
1647     sal_Int32 SAL_CALL AccessibleTextHelper_Impl::getAccessibleChildCount() SAL_THROW((uno::RuntimeException))
1648     {
1649         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1650 
1651         return mnLastVisibleChild - mnFirstVisibleChild + 1;
1652     }
1653 
1654     uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException))
1655     {
1656         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1657 
1658         i -= GetStartIndex();
1659 
1660         if( 0 > i || i >= getAccessibleChildCount() ||
1661             GetTextForwarder().GetParagraphCount() <= i )
1662         {
1663             throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid child index")), mxFrontEnd);
1664         }
1665 
1666         DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper_Impl::UpdateVisibleChildren: no frontend set");
1667 
1668         if( mxFrontEnd.is() )
1669             return maParaManager.CreateChild( i, mxFrontEnd, GetEditSource(), mnFirstVisibleChild + i ).first;
1670         else
1671             return NULL;
1672     }
1673 
1674     void SAL_CALL AccessibleTextHelper_Impl::addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
1675     {
1676         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1677 
1678         if( getNotifierClientId() != -1 )
1679             ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener );
1680     }
1681 
1682     void SAL_CALL AccessibleTextHelper_Impl::removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
1683     {
1684         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1685 
1686         if( getNotifierClientId() != -1 )
1687             ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener );
1688     }
1689 
1690     uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleAtPoint( const awt::Point& _aPoint ) SAL_THROW((uno::RuntimeException))
1691     {
1692         DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1693 
1694         // make given position relative
1695         if( !mxFrontEnd.is() )
1696             throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd );
1697 
1698         uno::Reference< XAccessibleContext > xFrontEndContext = mxFrontEnd->getAccessibleContext();
1699 
1700         if( !xFrontEndContext.is() )
1701             throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd );
1702 
1703         uno::Reference< XAccessibleComponent > xFrontEndComponent( xFrontEndContext, uno::UNO_QUERY );
1704 
1705         if( !xFrontEndComponent.is() )
1706             throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend is no XAccessibleComponent")),
1707                                         mxFrontEnd );
1708 
1709         // #103862# No longer need to make given position relative
1710         Point aPoint( _aPoint.X, _aPoint.Y );
1711 
1712         // respect EditEngine offset to surrounding shape/cell
1713         aPoint -= GetOffset();
1714 
1715         // convert to EditEngine coordinate system
1716         SvxTextForwarder& rCacheTF = GetTextForwarder();
1717         Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) );
1718 
1719         // iterate over all visible children (including those not yet created)
1720         sal_Int32 nChild;
1721         for( nChild=mnFirstVisibleChild; nChild <= mnLastVisibleChild; ++nChild )
1722         {
1723             DBG_ASSERT(nChild >= 0 && nChild <= USHRT_MAX,
1724                        "AccessibleTextHelper_Impl::getAccessibleAt: index value overflow");
1725 
1726             Rectangle aParaBounds( rCacheTF.GetParaBounds( static_cast< sal_uInt16 > (nChild) ) );
1727 
1728             if( aParaBounds.IsInside( aLogPoint ) )
1729                 return getAccessibleChild( nChild - mnFirstVisibleChild + GetStartIndex() );
1730         }
1731 
1732         // found none
1733         return NULL;
1734     }
1735 
1736 	//------------------------------------------------------------------------
1737 	//
1738 	// AccessibleTextHelper implementation (simply forwards to impl)
1739 	//
1740 	//------------------------------------------------------------------------
1741 
1742     AccessibleTextHelper::AccessibleTextHelper( ::std::auto_ptr< SvxEditSource > pEditSource ) :
1743         mpImpl( new AccessibleTextHelper_Impl() )
1744     {
1745         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1746 
1747         SetEditSource( pEditSource );
1748     }
1749 
1750     AccessibleTextHelper::~AccessibleTextHelper()
1751     {
1752     }
1753 
1754     const SvxEditSource& AccessibleTextHelper::GetEditSource() const SAL_THROW((uno::RuntimeException))
1755     {
1756 #ifdef DBG_UTIL
1757         mpImpl->CheckInvariants();
1758 
1759         const SvxEditSource& aEditSource = mpImpl->GetEditSource();
1760 
1761         mpImpl->CheckInvariants();
1762 
1763         return aEditSource;
1764 #else
1765         return mpImpl->GetEditSource();
1766 #endif
1767     }
1768 
1769     void AccessibleTextHelper::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
1770     {
1771 #ifdef DBG_UTIL
1772         // precondition: solar mutex locked
1773         DBG_TESTSOLARMUTEX();
1774 
1775         mpImpl->CheckInvariants();
1776 #endif
1777 
1778         mpImpl->SetEditSource( pEditSource );
1779 
1780 #ifdef DBG_UTIL
1781         mpImpl->CheckInvariants();
1782 #endif
1783     }
1784 
1785     void AccessibleTextHelper::SetEventSource( const uno::Reference< XAccessible >& rInterface )
1786     {
1787 #ifdef DBG_UTIL
1788         mpImpl->CheckInvariants();
1789 #endif
1790 
1791         mpImpl->SetEventSource( rInterface );
1792 
1793 #ifdef DBG_UTIL
1794         mpImpl->CheckInvariants();
1795 #endif
1796     }
1797 
1798     uno::Reference< XAccessible > AccessibleTextHelper::GetEventSource() const
1799     {
1800 #ifdef DBG_UTIL
1801         mpImpl->CheckInvariants();
1802 
1803         uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
1804 
1805         mpImpl->CheckInvariants();
1806 
1807         return xRet;
1808 #else
1809         return mpImpl->GetEventSource();
1810 #endif
1811     }
1812 
1813     void AccessibleTextHelper::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
1814     {
1815 #ifdef DBG_UTIL
1816         // precondition: solar mutex locked
1817         DBG_TESTSOLARMUTEX();
1818 
1819         mpImpl->CheckInvariants();
1820 #endif
1821 
1822         mpImpl->SetFocus( bHaveFocus );
1823 
1824 #ifdef DBG_UTIL
1825         mpImpl->CheckInvariants();
1826 #endif
1827     }
1828 
1829     sal_Bool AccessibleTextHelper::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException))
1830     {
1831 #ifdef DBG_UTIL
1832         mpImpl->CheckInvariants();
1833 
1834         sal_Bool bRet( mpImpl->HaveFocus() );
1835 
1836         mpImpl->CheckInvariants();
1837 
1838         return bRet;
1839 #else
1840         return mpImpl->HaveFocus();
1841 #endif
1842     }
1843 
1844     void AccessibleTextHelper::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const
1845     {
1846 #ifdef DBG_UTIL
1847         mpImpl->CheckInvariants();
1848 #endif
1849 
1850         mpImpl->FireEvent( nEventId, rNewValue, rOldValue );
1851 
1852 #ifdef DBG_UTIL
1853         mpImpl->CheckInvariants();
1854 #endif
1855     }
1856 
1857     void AccessibleTextHelper::FireEvent( const AccessibleEventObject& rEvent ) const
1858     {
1859 #ifdef DBG_UTIL
1860         mpImpl->CheckInvariants();
1861 #endif
1862 
1863         mpImpl->FireEvent( rEvent );
1864 
1865 #ifdef DBG_UTIL
1866         mpImpl->CheckInvariants();
1867 #endif
1868     }
1869 
1870     void AccessibleTextHelper::SetOffset( const Point& rPoint )
1871     {
1872 #ifdef DBG_UTIL
1873         // precondition: solar mutex locked
1874         DBG_TESTSOLARMUTEX();
1875 
1876         mpImpl->CheckInvariants();
1877 #endif
1878 
1879         mpImpl->SetOffset( rPoint );
1880 
1881 #ifdef DBG_UTIL
1882         mpImpl->CheckInvariants();
1883 #endif
1884     }
1885 
1886     Point AccessibleTextHelper::GetOffset() const
1887     {
1888 #ifdef DBG_UTIL
1889         mpImpl->CheckInvariants();
1890 
1891         Point aPoint( mpImpl->GetOffset() );
1892 
1893         mpImpl->CheckInvariants();
1894 
1895         return aPoint;
1896 #else
1897         return mpImpl->GetOffset();
1898 #endif
1899     }
1900 
1901     void AccessibleTextHelper::SetStartIndex( sal_Int32 nOffset )
1902     {
1903 #ifdef DBG_UTIL
1904         // precondition: solar mutex locked
1905         DBG_TESTSOLARMUTEX();
1906 
1907         mpImpl->CheckInvariants();
1908 #endif
1909 
1910         mpImpl->SetStartIndex( nOffset );
1911 
1912 #ifdef DBG_UTIL
1913         mpImpl->CheckInvariants();
1914 #endif
1915     }
1916 
1917     sal_Int32 AccessibleTextHelper::GetStartIndex() const
1918     {
1919 #ifdef DBG_UTIL
1920         mpImpl->CheckInvariants();
1921 
1922         sal_Int32 nOffset = mpImpl->GetStartIndex();
1923 
1924         mpImpl->CheckInvariants();
1925 
1926         return nOffset;
1927 #else
1928         return mpImpl->GetStartIndex();
1929 #endif
1930     }
1931 
1932     void AccessibleTextHelper::SetAdditionalChildStates( const VectorOfStates& rChildStates )
1933     {
1934         mpImpl->SetAdditionalChildStates( rChildStates );
1935     }
1936 
1937     const AccessibleTextHelper::VectorOfStates& AccessibleTextHelper::GetAdditionalChildStates() const
1938     {
1939         return mpImpl->GetAdditionalChildStates();
1940     }
1941 
1942     void AccessibleTextHelper::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
1943     {
1944 #ifdef DBG_UTIL
1945         // precondition: solar mutex locked
1946         DBG_TESTSOLARMUTEX();
1947 
1948         mpImpl->CheckInvariants();
1949 #endif
1950 
1951         mpImpl->UpdateVisibleChildren();
1952         mpImpl->UpdateBoundRect();
1953 
1954         mpImpl->UpdateSelection();
1955 
1956 #ifdef DBG_UTIL
1957         mpImpl->CheckInvariants();
1958 #endif
1959     }
1960 
1961     void AccessibleTextHelper::Dispose()
1962     {
1963         // As Dispose calls ShutdownEditSource, which in turn
1964         // deregisters as listener on the edit source, have to lock
1965         // here
1966         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1967 
1968 #ifdef DBG_UTIL
1969         mpImpl->CheckInvariants();
1970 #endif
1971 
1972         mpImpl->Dispose();
1973 
1974 #ifdef DBG_UTIL
1975         mpImpl->CheckInvariants();
1976 #endif
1977     }
1978 
1979     sal_Bool AccessibleTextHelper::IsSelected() const
1980     {
1981         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1982 
1983 #ifdef DBG_UTIL
1984         mpImpl->CheckInvariants();
1985 
1986         sal_Bool aRet = mpImpl->IsSelected();
1987 
1988         mpImpl->CheckInvariants();
1989 
1990         return aRet;
1991 #else
1992         return mpImpl->IsSelected();
1993 #endif
1994     }
1995 
1996 	// XAccessibleContext
1997     sal_Int32 AccessibleTextHelper::GetChildCount() SAL_THROW((uno::RuntimeException))
1998     {
1999         ::vos::OGuard aGuard( Application::GetSolarMutex() );
2000 
2001 #ifdef DBG_UTIL
2002         mpImpl->CheckInvariants();
2003 
2004         sal_Int32 nRet = mpImpl->getAccessibleChildCount();
2005 
2006         mpImpl->CheckInvariants();
2007 
2008         return nRet;
2009 #else
2010         return mpImpl->getAccessibleChildCount();
2011 #endif
2012     }
2013 
2014     uno::Reference< XAccessible > AccessibleTextHelper::GetChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException))
2015     {
2016         ::vos::OGuard aGuard( Application::GetSolarMutex() );
2017 
2018 #ifdef DBG_UTIL
2019         mpImpl->CheckInvariants();
2020 
2021         uno::Reference< XAccessible > xRet = mpImpl->getAccessibleChild( i );
2022 
2023         mpImpl->CheckInvariants();
2024 
2025         return xRet;
2026 #else
2027         return mpImpl->getAccessibleChild( i );
2028 #endif
2029     }
2030 
2031     void AccessibleTextHelper::AddEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
2032     {
2033 #ifdef DBG_UTIL
2034         mpImpl->CheckInvariants();
2035 
2036         mpImpl->addEventListener( xListener );
2037 
2038         mpImpl->CheckInvariants();
2039 #else
2040         mpImpl->addEventListener( xListener );
2041 #endif
2042     }
2043 
2044     void AccessibleTextHelper::RemoveEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
2045     {
2046 #ifdef DBG_UTIL
2047         mpImpl->CheckInvariants();
2048 
2049         mpImpl->removeEventListener( xListener );
2050 
2051         mpImpl->CheckInvariants();
2052 #else
2053         mpImpl->removeEventListener( xListener );
2054 #endif
2055     }
2056 
2057 	// XAccessibleComponent
2058     uno::Reference< XAccessible > AccessibleTextHelper::GetAt( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException))
2059     {
2060         ::vos::OGuard aGuard( Application::GetSolarMutex() );
2061 
2062 #ifdef DBG_UTIL
2063         mpImpl->CheckInvariants();
2064 
2065         uno::Reference< XAccessible > xChild = mpImpl->getAccessibleAtPoint( aPoint );
2066 
2067         mpImpl->CheckInvariants();
2068 
2069         return xChild;
2070 #else
2071         return mpImpl->getAccessibleAtPoint( aPoint );
2072 #endif
2073     }
2074 
2075 } // end of namespace accessibility
2076 
2077 //------------------------------------------------------------------------
2078