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