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