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