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_editeng.hxx"
26 
27 //------------------------------------------------------------------------
28 //
29 // Global header
30 //
31 //------------------------------------------------------------------------
32 
33 #include <limits.h>
34 #include <vector>
35 #include <algorithm>
36 #include <boost/bind.hpp>
37 #include <vos/mutex.hxx>
38 #include <vcl/window.hxx>
39 #include <vcl/svapp.hxx>
40 #include <comphelper/sequenceasvector.hxx>
41 #include <com/sun/star/uno/Any.hxx>
42 #include <com/sun/star/uno/Reference.hxx>
43 #include <com/sun/star/awt/Point.hpp>
44 #include <com/sun/star/awt/Rectangle.hpp>
45 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
46 
47 //------------------------------------------------------------------------
48 //
49 // Project-local header
50 //
51 //------------------------------------------------------------------------
52 
53 #include <editeng/editdata.hxx>
54 #include <editeng/unopracc.hxx>
55 #include "editeng/unoedprx.hxx"
56 #include <editeng/AccessibleStaticTextBase.hxx>
57 #include "editeng/AccessibleEditableTextPara.hxx"
58 
59 
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::accessibility;
62 
63 /* TODO:
64    =====
65 
66    - separate adapter functionality from AccessibleStaticText class
67 
68    - refactor common loops into templates, using mem_fun
69 
70  */
71 
72 namespace accessibility
73 {
74     typedef ::comphelper::SequenceAsVector< beans::PropertyValue > PropertyValueVector;
75 
76     class PropertyValueEqualFunctor : public ::std::binary_function< beans::PropertyValue, beans::PropertyValue, bool >
77     {
78     public:
79         PropertyValueEqualFunctor()
80         {}
81         bool operator() ( const beans::PropertyValue& lhs, const beans::PropertyValue& rhs ) const
82         {
83             return ( lhs.Name == rhs.Name && lhs.Value == rhs.Value );
84         }
85     };
86 sal_Unicode cNewLine(0x0a);
87 	//------------------------------------------------------------------------
88 	//
89 	// Static Helper
90 	//
91 	//------------------------------------------------------------------------
92     ESelection MakeSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
93                               sal_Int32 nEndPara, sal_Int32 nEndIndex )
94     {
95         DBG_ASSERT(nStartPara >= 0 && nStartPara <= USHRT_MAX &&
96                    nStartIndex >= 0 && nStartIndex <= USHRT_MAX &&
97                    nEndPara >= 0 && nEndPara <= USHRT_MAX &&
98                    nEndIndex >= 0 && nEndIndex <= USHRT_MAX ,
99                    "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow");
100 
101         return ESelection( static_cast< sal_uInt16 >(nStartPara), static_cast< sal_uInt16 >(nStartIndex),
102                            static_cast< sal_uInt16 >(nEndPara), static_cast< sal_uInt16 >(nEndIndex) );
103     }
104 
105 	//------------------------------------------------------------------------
106 	//
107 	// AccessibleStaticTextBase_Impl declaration
108 	//
109 	//------------------------------------------------------------------------
110 
111     DBG_NAME( AccessibleStaticTextBase_Impl );
112 
113     /** AccessibleStaticTextBase_Impl
114 
115     	This class implements the AccessibleStaticTextBase
116     	functionality, mainly by forwarding the calls to an aggregated
117     	AccessibleEditableTextPara. As this is a therefore non-trivial
118     	adapter, factoring out the common functionality from
119     	AccessibleEditableTextPara might be a profitable future task.
120      */
121     class AccessibleStaticTextBase_Impl
122     {
123 		friend class AccessibleStaticTextBase;
124     public:
125 
126         // receive pointer to our frontend class and view window
127         AccessibleStaticTextBase_Impl();
128         ~AccessibleStaticTextBase_Impl();
129 
130         SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException))
131         {
132             DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
133 
134             return maEditSource;
135         }
136         void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException));
137 
138         void SetEventSource( const uno::Reference< XAccessible >& rInterface )
139         {
140             DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
141 
142             mxThis = rInterface;
143         }
144         uno::Reference< XAccessible > GetEventSource() const
145         {
146             DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
147 
148             return mxThis;
149         }
150 
151         void SetOffset( const Point& );
152         Point GetOffset() const
153         {
154             DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
155 
156             ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset );
157             return aPoint;
158         }
159 
160         void UpdateChildren();
161         void Dispose();
162 
163 #ifdef DBG_UTIL
164         void CheckInvariants() const;
165 #endif
166 
167         AccessibleEditableTextPara& GetParagraph( sal_Int32 nPara ) const;
168         sal_Int32 					GetParagraphCount() const;
169         sal_Int32                   GetParagraphIndex() const;
170         sal_Int32                   GetLineCount( sal_Int32 nParagraph ) const;
171 
172         EPosition                   Index2Internal( sal_Int32 nFlatIndex ) const
173         {
174             DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
175 
176             return ImpCalcInternal( nFlatIndex, false );
177         }
178 
179         EPosition                   Range2Internal( sal_Int32 nFlatIndex ) const
180         {
181             DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
182 
183             return ImpCalcInternal( nFlatIndex, true );
184         }
185 
186         sal_Int32					Internal2Index( EPosition nEEIndex ) const;
187 
188         void						CorrectTextSegment( TextSegment&	aTextSegment,
189                                                         int				nPara	) const;
190 
191         sal_Bool					SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
192                                                   sal_Int32 nEndPara, sal_Int32 nEndIndex );
193         sal_Bool					CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
194                                               sal_Int32 nEndPara, sal_Int32 nEndIndex );
195 
196         Rectangle                   GetParagraphBoundingBox() const;
197 		sal_Bool					RemoveLineBreakCount( sal_Int32& rIndex );
198 
199     private:
200 
201         EPosition 					ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const;
202 
203         // our frontend class (the one implementing the actual
204         // interface). That's not necessarily the one containing the impl
205         // pointer
206         uno::Reference< XAccessible > mxThis;
207 
208         // implements our functionality, we're just an adapter (guarded by solar mutex)
209         mutable AccessibleEditableTextPara* mpTextParagraph;
210 
211         uno::Reference< XAccessible > mxParagraph;
212 
213         // a wrapper for the text forwarders (guarded by solar mutex)
214         mutable SvxEditSourceAdapter maEditSource;
215 
216         // guard for maOffset
217         mutable ::osl::Mutex maMutex;
218 
219         /// our current offset to the containing shape/cell (guarded by maMutex)
220         Point maOffset;
221 
222     };
223 
224 	//------------------------------------------------------------------------
225 	//
226 	// AccessibleStaticTextBase_Impl implementation
227 	//
228 	//------------------------------------------------------------------------
229 
230     AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
231         mxThis( NULL ),
232         mpTextParagraph( new AccessibleEditableTextPara(NULL) ),
233         mxParagraph( mpTextParagraph ),
234         maEditSource(),
235         maMutex(),
236         maOffset(0,0)
237     {
238         DBG_CTOR( AccessibleStaticTextBase_Impl, NULL );
239 
240         // TODO: this is still somewhat of a hack, all the more since
241         // now the maTextParagraph has an empty parent reference set
242     }
243 
244     AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl()
245     {
246         DBG_DTOR( AccessibleStaticTextBase_Impl, NULL );
247     }
248 
249     void AccessibleStaticTextBase_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
250     {
251         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
252 
253         maEditSource.SetEditSource( pEditSource );
254         if( mpTextParagraph )
255             mpTextParagraph->SetEditSource( &maEditSource );
256     }
257 
258     void AccessibleStaticTextBase_Impl::SetOffset( const Point& rPoint )
259     {
260         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
261 
262         // guard against non-atomic access to maOffset data structure
263         {
264             ::osl::MutexGuard aGuard( maMutex );
265             maOffset = rPoint;
266         }
267 
268         if( mpTextParagraph )
269             mpTextParagraph->SetEEOffset( rPoint );
270 
271         // in all cases, check visibility afterwards.
272         UpdateChildren();
273     }
274 
275     void AccessibleStaticTextBase_Impl::UpdateChildren()
276     {
277         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
278 
279         // currently no children
280     }
281 
282     void AccessibleStaticTextBase_Impl::Dispose()
283     {
284         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
285 
286         // we're the owner of the paragraph, so destroy it, too
287         if( mpTextParagraph )
288             mpTextParagraph->Dispose();
289 
290         // drop references
291         mxParagraph = NULL;
292         mxThis = NULL;
293         mpTextParagraph = NULL;
294     }
295 
296 #ifdef DBG_UTIL
297     void AccessibleStaticTextBase_Impl::CheckInvariants() const
298     {
299         // TODO
300     }
301 #endif
302 
303     AccessibleEditableTextPara& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara ) const
304     {
305         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
306 
307         if( !mpTextParagraph )
308             throw lang::DisposedException (
309                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), mxThis );
310 
311         // TODO: Have a different method on AccessibleEditableTextPara
312         // that does not care about state changes
313         mpTextParagraph->SetParagraphIndex( nPara );
314 
315         return *mpTextParagraph;
316     }
317 
318     sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphCount() const
319     {
320         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
321 
322         if( !mpTextParagraph )
323             return 0;
324         else
325             return mpTextParagraph->GetTextForwarder().GetParagraphCount();
326     }
327 
328     sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphIndex() const
329     {
330         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
331 
332         sal_Int32 nIndex = -1;
333         if( mpTextParagraph )
334             nIndex = mpTextParagraph->GetParagraphIndex();
335         return nIndex;
336     }
337 
338     sal_Int32 AccessibleStaticTextBase_Impl::GetLineCount( sal_Int32 nParagraph ) const
339     {
340         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
341 
342         sal_Int32 nIndex = 0;
343         if( mpTextParagraph )
344             nIndex = mpTextParagraph->GetTextForwarder().GetLineCount( static_cast< sal_uInt16 >(nParagraph) );
345         return nIndex;
346     }
347 
348     sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const
349     {
350         sal_Int32 aRes(0);
351         int i;
352         for(i=0; i<nEEIndex.nPara; ++i)
353             aRes += GetParagraph(i).getCharacterCount();
354 
355         return aRes + nEEIndex.nIndex;
356     }
357 
358     void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment&	aTextSegment,
359                                                             int				nPara	) const
360     {
361         // Keep 'invalid' values at the TextSegment
362         if( aTextSegment.SegmentStart != -1 &&
363             aTextSegment.SegmentEnd != -1 )
364         {
365             // #112814# Correct TextSegment by paragraph offset
366             sal_Int32 nOffset(0);
367             int i;
368             for(i=0; i<nPara; ++i)
369                 nOffset += GetParagraph(i).getCharacterCount();
370 
371             aTextSegment.SegmentStart += nOffset;
372             aTextSegment.SegmentEnd += nOffset;
373         }
374     }
375 
376     EPosition AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const
377     {
378         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
379 
380         if( nFlatIndex < 0 )
381             throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
382                                                   mxThis);
383         // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually
384 
385         sal_Int32 nCurrPara, nCurrIndex, nParas, nCurrCount;
386         for( nCurrPara=0, nParas=GetParagraphCount(), nCurrCount=0, nCurrIndex=0; nCurrPara<nParas; ++nCurrPara )
387         {
388             nCurrCount = GetParagraph( nCurrPara ).getCharacterCount();
389             nCurrIndex += nCurrCount;
390             if( nCurrIndex >= nFlatIndex )
391             {
392                 // check overflow
393                 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX &&
394                            nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
395                            "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
396 
397                 return EPosition( static_cast< sal_uInt16 >(nCurrPara), static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
398             }
399         }
400 
401         // #102170# Allow one-past the end for ranges
402         if( bExclusive && nCurrIndex == nFlatIndex )
403         {
404             // check overflow
405             DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX &&
406                        nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
407                        "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
408 
409             return EPosition( static_cast< sal_uInt16 >(nCurrPara-1), static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
410         }
411 
412         // not found? Out of bounds
413         throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
414                                               mxThis);
415     }
416 
417     sal_Bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
418                                                           sal_Int32 nEndPara, sal_Int32 nEndIndex )
419     {
420         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
421 
422         if( !mpTextParagraph )
423             return sal_False;
424 
425         try
426         {
427             SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
428             return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
429         }
430         catch( const uno::RuntimeException& )
431         {
432             return sal_False;
433         }
434     }
435 
436     sal_Bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
437                                                       sal_Int32 nEndPara, sal_Int32 nEndIndex )
438     {
439         DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
440 
441         if( !mpTextParagraph )
442             return sal_False;
443 
444         try
445         {
446             SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
447             mpTextParagraph->GetTextForwarder();	// MUST be after GetEditViewForwarder(), see method docs
448             sal_Bool aRetVal;
449 
450             // save current selection
451             ESelection aOldSelection;
452 
453             rCacheVF.GetSelection( aOldSelection );
454             rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
455             aRetVal = rCacheVF.Copy();
456             rCacheVF.SetSelection( aOldSelection ); // restore
457 
458             return aRetVal;
459         }
460         catch( const uno::RuntimeException& )
461         {
462             return sal_False;
463         }
464     }
465 
466     Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
467     {
468         Rectangle aRect;
469         if( mpTextParagraph )
470         {
471             awt::Rectangle aAwtRect = mpTextParagraph->getBounds();
472             aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) );
473         }
474         else
475         {
476             aRect.SetEmpty();
477         }
478         return aRect;
479     }
480 	//the input argument is the index(including "\n" ) in the string.
481 	//the function will calculate the actual index(not including "\n") in the string.
482 	//and return true if the index is just at a "\n"
483 	sal_Bool AccessibleStaticTextBase_Impl::RemoveLineBreakCount( sal_Int32& rIndex )
484 	{
485 		// get the total char number inside the cell.
486 		sal_Int32 i, nCount, nParas;
487         for( i=0, nCount=0, nParas=GetParagraphCount(); i<nParas; ++i )
488             nCount += GetParagraph(i).getCharacterCount();
489 		nCount = nCount + (nParas-1);
490 		if( nCount == 0 &&  rIndex == 0) return sal_False;
491 
492 
493 		sal_Int32 nCurrPara, nCurrCount;
494 		sal_Int32 nLineBreakPos = 0, nLineBreakCount = 0;
495 		sal_Int32 nParaCount = GetParagraphCount();
496 		for ( nCurrCount = 0, nCurrPara = 0; nCurrPara < nParaCount; nCurrPara++ )
497 		{
498 			nCurrCount += GetParagraph( nCurrPara ).getCharacterCount();
499 			nLineBreakPos = nCurrCount++;
500 			if ( rIndex == nLineBreakPos )
501 			{
502 				rIndex -= (++nLineBreakCount);//(++nLineBreakCount);
503 				if ( rIndex < 0)
504 				{
505 					rIndex = 0;
506 				}
507 				//if the index is at the last position of the last paragraph
508 				//there is no "\n" , so we should increase rIndex by 1 and return false.
509 				if ( (nCurrPara+1) == nParaCount )
510 				{
511 					rIndex++;
512 					return sal_False;
513 				}
514 				else
515 				{
516 					return sal_True;
517 				}
518 			}
519 			else if ( rIndex < nLineBreakPos )
520 			{
521 				rIndex -= nLineBreakCount;
522 				return sal_False;
523 			}
524 			else
525 			{
526 				nLineBreakCount++;
527 			}
528 		}
529 		return sal_False;
530 	}
531 	//------------------------------------------------------------------------
532 	//
533 	// AccessibleStaticTextBase implementation
534 	//
535 	//------------------------------------------------------------------------
536 
537     AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::auto_ptr< SvxEditSource > 		pEditSource ) :
538         mpImpl( new AccessibleStaticTextBase_Impl() )
539     {
540         ::vos::OGuard aGuard( Application::GetSolarMutex() );
541 
542         SetEditSource( pEditSource );
543     }
544 
545     AccessibleStaticTextBase::~AccessibleStaticTextBase()
546     {
547     }
548 
549     const SvxEditSource& AccessibleStaticTextBase::GetEditSource() const SAL_THROW((::com::sun::star::uno::RuntimeException))
550     {
551 #ifdef DBG_UTIL
552         mpImpl->CheckInvariants();
553 
554         const SvxEditSource& aEditSource = mpImpl->GetEditSource();
555 
556         mpImpl->CheckInvariants();
557 
558         return aEditSource;
559 #else
560         return mpImpl->GetEditSource();
561 #endif
562     }
563 
564     void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((::com::sun::star::uno::RuntimeException))
565     {
566 #ifdef DBG_UTIL
567         // precondition: solar mutex locked
568         DBG_TESTSOLARMUTEX();
569 
570         mpImpl->CheckInvariants();
571 
572         mpImpl->SetEditSource( pEditSource );
573 
574         mpImpl->CheckInvariants();
575 #else
576         mpImpl->SetEditSource( pEditSource );
577 #endif
578     }
579 
580     void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface )
581     {
582 #ifdef DBG_UTIL
583         mpImpl->CheckInvariants();
584 #endif
585 
586         mpImpl->SetEventSource( rInterface );
587 
588 #ifdef DBG_UTIL
589         mpImpl->CheckInvariants();
590 #endif
591     }
592 
593     uno::Reference< XAccessible > AccessibleStaticTextBase::GetEventSource() const
594     {
595 #ifdef DBG_UTIL
596         mpImpl->CheckInvariants();
597 
598         uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
599 
600         mpImpl->CheckInvariants();
601 
602         return xRet;
603 #else
604         return mpImpl->GetEventSource();
605 #endif
606     }
607 
608     void AccessibleStaticTextBase::SetOffset( const Point& rPoint )
609     {
610 #ifdef DBG_UTIL
611         // precondition: solar mutex locked
612         DBG_TESTSOLARMUTEX();
613 
614         mpImpl->CheckInvariants();
615 
616         mpImpl->SetOffset( rPoint );
617 
618         mpImpl->CheckInvariants();
619 #else
620         mpImpl->SetOffset( rPoint );
621 #endif
622     }
623 
624     Point AccessibleStaticTextBase::GetOffset() const
625     {
626 #ifdef DBG_UTIL
627         mpImpl->CheckInvariants();
628 
629         Point aPoint( mpImpl->GetOffset() );
630 
631         mpImpl->CheckInvariants();
632 
633         return aPoint;
634 #else
635         return mpImpl->GetOffset();
636 #endif
637     }
638 
639     void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
640     {
641 #ifdef DBG_UTIL
642         // precondition: solar mutex locked
643         DBG_TESTSOLARMUTEX();
644 
645         mpImpl->CheckInvariants();
646 
647         mpImpl->UpdateChildren();
648 
649         mpImpl->CheckInvariants();
650 #else
651         mpImpl->UpdateChildren();
652 #endif
653     }
654 
655     void AccessibleStaticTextBase::Dispose()
656     {
657 #ifdef DBG_UTIL
658         mpImpl->CheckInvariants();
659 #endif
660 
661         mpImpl->Dispose();
662 
663 #ifdef DBG_UTIL
664         mpImpl->CheckInvariants();
665 #endif
666     }
667 
668 	// XAccessibleContext
669     sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException)
670     {
671         // no children at all
672         return 0;
673     }
674 
675     uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleChild( sal_Int32 /*i*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
676     {
677         // no children at all
678         return uno::Reference< XAccessible >();
679     }
680 
681     uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) throw (uno::RuntimeException)
682     {
683         // no children at all
684         return uno::Reference< XAccessible >();
685     }
686 
687 	// XAccessibleText
688     sal_Int32 SAL_CALL AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException)
689     {
690         ::vos::OGuard aGuard( Application::GetSolarMutex() );
691 
692         sal_Int32 i, nPos, nParas;
693         for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
694         {
695             if( (nPos=mpImpl->GetParagraph(i).getCaretPosition()) != -1 )
696                 return nPos;
697         }
698 
699         return nPos;
700     }
701 
702     sal_Bool SAL_CALL AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
703     {
704         return setSelection(nIndex, nIndex);
705     }
706 
707     sal_Unicode SAL_CALL AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
708     {
709         ::vos::OGuard aGuard( Application::GetSolarMutex() );
710 
711         EPosition aPos( mpImpl->Index2Internal(nIndex) );
712 
713         return mpImpl->GetParagraph( aPos.nPara ).getCharacter( aPos.nIndex );
714     }
715 
716     uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getCharacterAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
717     {
718         ::vos::OGuard aGuard( Application::GetSolarMutex() );
719 		//get the actual index without "\n"
720 		mpImpl->RemoveLineBreakCount( nIndex );
721 
722         EPosition aPos( mpImpl->Index2Internal(nIndex) );
723 
724         return mpImpl->GetParagraph( aPos.nPara ).getCharacterAttributes( aPos.nIndex, aRequestedAttributes );
725     }
726 
727     awt::Rectangle SAL_CALL AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
728     {
729         ::vos::OGuard aGuard( Application::GetSolarMutex() );
730 
731         // #108900# Allow ranges for nIndex, as one-past-the-end
732         // values are now legal, too.
733         EPosition aPos( mpImpl->Range2Internal(nIndex) );
734 
735         // #i70916# Text in spread sheet cells return the wrong extents
736         AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
737         awt::Rectangle aParaBounds( rPara.getBounds() );
738         awt::Rectangle aBounds( rPara.getCharacterBounds( aPos.nIndex ) );
739         aBounds.X += aParaBounds.X;
740         aBounds.Y += aParaBounds.Y;
741 
742         return aBounds;
743     }
744 
745     sal_Int32 SAL_CALL AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException)
746     {
747         ::vos::OGuard aGuard( Application::GetSolarMutex() );
748 
749         sal_Int32 i, nCount, nParas;
750         for( i=0, nCount=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
751             nCount += mpImpl->GetParagraph(i).getCharacterCount();
752 		//count on the number of "\n" which equals number of paragraphs decrease 1.
753 		nCount = nCount + (nParas-1);
754         return nCount;
755     }
756 
757     sal_Int32 SAL_CALL AccessibleStaticTextBase::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException)
758     {
759         ::vos::OGuard aGuard( Application::GetSolarMutex() );
760 
761         const sal_Int32 nParas( mpImpl->GetParagraphCount() );
762         sal_Int32 nIndex;
763         int i;
764         for( i=0; i<nParas; ++i )
765         {
766             // TODO: maybe exploit the fact that paragraphs are
767             // ordered vertically for early exit
768 
769             // #i70916# Text in spread sheet cells return the wrong extents
770             AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( i );
771             awt::Rectangle aParaBounds( rPara.getBounds() );
772             awt::Point aPoint( rPoint );
773             aPoint.X -= aParaBounds.X;
774             aPoint.Y -= aParaBounds.Y;
775 
776             // #112814# Use correct index offset
777             if ( ( nIndex = rPara.getIndexAtPoint( aPoint ) ) != -1 )
778                 return mpImpl->Internal2Index( EPosition(sal::static_int_cast<sal_uInt16>(i),
779                                                          sal::static_int_cast<sal_uInt16>(nIndex)) );
780         }
781 
782         return -1;
783     }
784 
785     ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException)
786     {
787         ::vos::OGuard aGuard( Application::GetSolarMutex() );
788 
789         sal_Int32 nStart( getSelectionStart() );
790         sal_Int32 nEnd( getSelectionEnd() );
791 
792         // #104481# Return the empty string for 'no selection'
793         if( nStart < 0 || nEnd < 0 )
794             return ::rtl::OUString();
795 
796         return getTextRange( nStart, nEnd );
797     }
798 
799     sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException)
800     {
801         ::vos::OGuard aGuard( Application::GetSolarMutex() );
802 
803         sal_Int32 i, nPos, nParas;
804         for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
805         {
806             if( (nPos=mpImpl->GetParagraph(i).getSelectionStart()) != -1 )
807                 return nPos;
808         }
809 
810         return nPos;
811     }
812 
813     sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException)
814     {
815         ::vos::OGuard aGuard( Application::GetSolarMutex() );
816 
817         sal_Int32 i, nPos, nParas;
818         for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
819         {
820             if( (nPos=mpImpl->GetParagraph(i).getSelectionEnd()) != -1 )
821                 return nPos;
822         }
823 
824         return nPos;
825     }
826 
827     sal_Bool SAL_CALL AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
828     {
829         ::vos::OGuard aGuard( Application::GetSolarMutex() );
830 
831         EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
832         EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
833 
834         return mpImpl->SetSelection( aStartIndex.nPara, aStartIndex.nIndex,
835                                      aEndIndex.nPara, aEndIndex.nIndex );
836     }
837 
838     ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getText() throw (uno::RuntimeException)
839     {
840         ::vos::OGuard aGuard( Application::GetSolarMutex() );
841 
842         sal_Int32 i, nParas;
843         ::rtl::OUString aRes;
844         for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
845             aRes += mpImpl->GetParagraph(i).getText();
846 
847         return aRes;
848     }
849 
850     ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
851     {
852         ::vos::OGuard aGuard( Application::GetSolarMutex() );
853 
854         if( nStartIndex > nEndIndex )
855             ::std::swap(nStartIndex, nEndIndex);
856 		//if startindex equals endindex we will get nothing. So return an empty string directly.
857 		if ( nStartIndex == nEndIndex )
858 		{
859 			::rtl::OUString sEmptyStr;
860 			return sEmptyStr;
861 		}
862 		sal_Bool bStart = mpImpl->RemoveLineBreakCount( nStartIndex );
863 		//if the start index is just at a "\n", we need to begin from the next char
864 		if ( bStart )
865 		{
866 			nStartIndex++;
867 		}
868 		//we need to find out whether the previous position of the current endindex is at "\n" or not
869 		//if yes we need to mark it and add "\n" at the end of the result
870 		sal_Int32 nTemp = nEndIndex - 1;
871 		sal_Bool bEnd = mpImpl->RemoveLineBreakCount( nTemp );
872 		sal_Bool bTemp = mpImpl->RemoveLineBreakCount( nEndIndex );
873 		//if the below condition is true it indicates an empty paragraph with just a "\n"
874 		//so we need to set one "\n" flag to avoid duplication.
875 		if ( bStart && bEnd && ( nStartIndex == nEndIndex) )
876 		{
877 			bEnd = sal_False;
878 		}
879 		//if the current endindex is at a "\n", we need to increase endindex by 1 to make sure
880 		//the char before "\n" is included. Because string returned by this function will not include
881 		//the char at the endindex.
882 		if ( bTemp )
883 		{
884 			nEndIndex++;
885 		}
886 		::rtl::OUString aRes;
887         EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
888         EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
889 
890         // #102170# Special case: start and end paragraph are identical
891         if( aStartIndex.nPara == aEndIndex.nPara )
892         {
893 			//we don't return the string directly now for that we have to do some further process for "\n"
894 			aRes = mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex );
895         }
896         else
897         {
898             sal_Int32 i( aStartIndex.nPara );
899 	            aRes = mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex,
900                                                                         mpImpl->GetParagraph(i).getCharacterCount()/*-1*/);
901             ++i;
902 
903             // paragraphs inbetween are fully included
904             for( ; i<aEndIndex.nPara; ++i )
905 			{
906 				aRes += rtl::OUString(cNewLine);
907                 aRes += mpImpl->GetParagraph(i).getText();
908 			}
909 
910             if( i<=aEndIndex.nPara )
911 			{
912 				//if the below condition is mathed it means the endindex is at mid of the last paragraph
913 				//we need to add a "\n" before we add the last part of the string.
914 				if ( !bEnd && aEndIndex.nIndex )
915 				{
916 					aRes += rtl::OUString(cNewLine);
917 				}
918                 aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex );
919 			}
920             //return aRes;
921         }
922 		//According to the flag we marked before, we have to add "\n" at the beginning
923 		//or at the end of the result string.
924 		if ( bStart )
925 		{
926 			aRes = rtl::OUString(cNewLine) + aRes;
927 		}
928 		if ( bEnd )
929 		{
930 			aRes += rtl::OUString(cNewLine);
931 		}
932 		return aRes;
933     }
934 
935     ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
936     {
937         ::vos::OGuard aGuard( Application::GetSolarMutex() );
938 
939 		sal_Bool bLineBreak = mpImpl->RemoveLineBreakCount( nIndex );
940         EPosition aPos( mpImpl->Range2Internal(nIndex) );
941 
942         ::com::sun::star::accessibility::TextSegment aResult;
943 
944         if( AccessibleTextType::PARAGRAPH == aTextType )
945         {
946             // #106393# Special casing one behind last paragraph is
947             // not necessary, since then, we return the content and
948             // boundary of that last paragraph. Range2Internal is
949             // tolerant against that, and returns the last paragraph
950             // in aPos.nPara.
951 
952             // retrieve full text of the paragraph
953             aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
954 
955             // #112814# Adapt the start index with the paragraph offset
956             aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
957             aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
958         }
959         else if ( AccessibleTextType::ATTRIBUTE_RUN == aTextType )
960         {
961               SvxAccessibleTextAdapter& rTextForwarder = mpImpl->GetParagraph( aPos.nIndex ).GetTextForwarder();
962               sal_uInt16 nStartIndex, nEndIndex;
963               if ( rTextForwarder.GetAttributeRun( nStartIndex, nEndIndex, aPos.nPara, aPos.nIndex, sal_True ) )
964               {
965                      aResult.SegmentText = getTextRange( nStartIndex, nEndIndex );
966                      aResult.SegmentStart = nStartIndex;
967                      aResult.SegmentEnd = nEndIndex;
968               }
969         }
970         else
971         {
972             // No special handling required, forward to wrapped class
973             aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType );
974 
975             // #112814# Adapt the start index with the paragraph offset
976             mpImpl->CorrectTextSegment( aResult, aPos.nPara );
977 			if ( bLineBreak )
978 			{
979 				aResult.SegmentText = rtl::OUString(cNewLine);
980 			}
981         }
982 
983         return aResult;
984     }
985 
986     ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
987     {
988         ::vos::OGuard aGuard( Application::GetSolarMutex() );
989 		sal_Int32 nOldIdx = nIndex;
990 		sal_Bool bLineBreak =  mpImpl->RemoveLineBreakCount( nIndex );
991         EPosition aPos( mpImpl->Range2Internal(nIndex) );
992 
993         ::com::sun::star::accessibility::TextSegment aResult;
994 
995         if( AccessibleTextType::PARAGRAPH == aTextType )
996         {
997             if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() )
998             {
999                 // #103589# Special casing one behind the last paragraph
1000                 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
1001 
1002                 // #112814# Adapt the start index with the paragraph offset
1003                 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
1004             }
1005             else if( aPos.nPara > 0 )
1006             {
1007                 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText();
1008 
1009                 // #112814# Adapt the start index with the paragraph offset
1010                 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) );
1011             }
1012 
1013             aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
1014         }
1015         else
1016         {
1017             // No special handling required, forward to wrapped class
1018             aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType );
1019 
1020             // #112814# Adapt the start index with the paragraph offset
1021             mpImpl->CorrectTextSegment( aResult, aPos.nPara );
1022 			if ( bLineBreak && (nOldIdx-1) >= 0)
1023 			{
1024 				aResult = getTextAtIndex( nOldIdx-1, aTextType );
1025 			}
1026         }
1027 
1028         return aResult;
1029     }
1030 
1031     ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
1032     {
1033         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1034 		sal_Int32 nTemp = nIndex+1;
1035 		sal_Bool bLineBreak = mpImpl->RemoveLineBreakCount( nTemp );
1036 		mpImpl->RemoveLineBreakCount( nIndex );
1037         EPosition aPos( mpImpl->Range2Internal(nIndex) );
1038 
1039         ::com::sun::star::accessibility::TextSegment aResult;
1040 
1041         if( AccessibleTextType::PARAGRAPH == aTextType )
1042         {
1043             // Special casing one behind the last paragraph is not
1044             // necessary, this case is invalid here for
1045             // getTextBehindIndex
1046             if( aPos.nPara + 1 < mpImpl->GetParagraphCount() )
1047             {
1048                 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText();
1049 
1050                 // #112814# Adapt the start index with the paragraph offset
1051                 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) );
1052                 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
1053             }
1054         }
1055         else
1056         {
1057             // No special handling required, forward to wrapped class
1058             aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType );
1059 
1060             // #112814# Adapt the start index with the paragraph offset
1061             mpImpl->CorrectTextSegment( aResult, aPos.nPara );
1062 			if ( bLineBreak )
1063 			{
1064 				aResult.SegmentText = rtl::OUString(cNewLine) + aResult.SegmentText;
1065 			}
1066        }
1067 
1068         return aResult;
1069     }
1070 
1071     sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1072     {
1073         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1074 
1075         if( nStartIndex > nEndIndex )
1076             ::std::swap(nStartIndex, nEndIndex);
1077 
1078         EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
1079         EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
1080 
1081         return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex,
1082                                  aEndIndex.nPara, aEndIndex.nIndex );
1083     }
1084 
1085     // XAccessibleTextAttributes
1086     uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (uno::RuntimeException)
1087     {
1088         // get the intersection of the default attributes of all paragraphs
1089 
1090         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1091 
1092         PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) );
1093 
1094         const sal_Int32 nParaCount = mpImpl->GetParagraphCount();
1095         for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara )
1096         {
1097             uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes );
1098             PropertyValueVector aIntersectionVec;
1099 
1100             PropertyValueVector::const_iterator aEnd = aDefAttrVec.end();
1101             for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr )
1102             {
1103                 const beans::PropertyValue* pItr = aSeq.getConstArray();
1104                 const beans::PropertyValue* pEnd  = pItr + aSeq.getLength();
1105                 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) );
1106                 if ( pFind != pEnd )
1107                 {
1108                     aIntersectionVec.push_back( *pFind );
1109                 }
1110             }
1111 
1112             aDefAttrVec.swap( aIntersectionVec );
1113 
1114             if ( aDefAttrVec.empty() )
1115             {
1116                 break;
1117             }
1118         }
1119 
1120         return aDefAttrVec.getAsConstList();
1121     }
1122 
1123     uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1124     {
1125         // get those default attributes of the paragraph, which are not part
1126         // of the intersection of all paragraphs and add them to the run attributes
1127 
1128         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1129 
1130         EPosition aPos( mpImpl->Index2Internal( nIndex ) );
1131         AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
1132         uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes );
1133         uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes );
1134         uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes );
1135         PropertyValueVector aDiffVec;
1136 
1137         const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray();
1138         const sal_Int32 nLength = aDefAttrSeq.getLength();
1139         for ( sal_Int32 i = 0; i < nLength; ++i )
1140         {
1141             const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray();
1142             const beans::PropertyValue* pEnd  = pItr + aIntersectionSeq.getLength();
1143             const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) );
1144             if ( pFind == pEnd && pDefAttr[i].Handle != 0)
1145             {
1146                 aDiffVec.push_back( pDefAttr[i] );
1147             }
1148         }
1149 
1150         return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() );
1151     }
1152 
1153     Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const
1154     {
1155         return mpImpl->GetParagraphBoundingBox();
1156     }
1157 
1158     sal_Int32 AccessibleStaticTextBase::GetParagraphIndex() const
1159     {
1160         return mpImpl->GetParagraphIndex();
1161     }
1162 
1163     sal_Int32 AccessibleStaticTextBase::GetParagraphCount() const
1164     {
1165         return mpImpl->GetParagraphCount();
1166     }
1167 
1168     sal_Int32 AccessibleStaticTextBase::GetLineCount( sal_Int32 nParagraph ) const
1169     {
1170         return mpImpl->GetLineCount( nParagraph );
1171     }
1172 
1173 }  // end of namespace accessibility
1174 
1175 //------------------------------------------------------------------------
1176