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 differnt 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.SegmentStart != -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             //return mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex );
896         }
897         else
898         {
899             sal_Int32 i( aStartIndex.nPara );
900 	            aRes = mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex,
901                                                                         mpImpl->GetParagraph(i).getCharacterCount()/*-1*/);
902             ++i;
903 
904             // paragraphs inbetween are fully included
905             for( ; i<aEndIndex.nPara; ++i )
906 			{
907 				aRes += rtl::OUString(cNewLine);
908                 aRes += mpImpl->GetParagraph(i).getText();
909 			}
910 
911             if( i<=aEndIndex.nPara )
912 			{
913 				//if the below condition is mathed it means the endindex is at mid of the last paragraph
914 				//we need to add a "\n" before we add the last part of the string.
915 				if ( !bEnd && aEndIndex.nIndex )
916 				{
917 					aRes += rtl::OUString(cNewLine);
918 				}
919                 aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex );
920 			}
921             //return aRes;
922         }
923 		//According the the flag we marked before, we have to add "\n" at the beginning
924 		//or at the end of the result string.
925 		if ( bStart )
926 		{
927 			aRes = rtl::OUString(cNewLine) + aRes;
928 		}
929 		if ( bEnd )
930 		{
931 			aRes += rtl::OUString(cNewLine);
932 		}
933 		return aRes;
934     }
935 
936     ::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)
937     {
938         ::vos::OGuard aGuard( Application::GetSolarMutex() );
939 
940 		sal_Bool bLineBreak = mpImpl->RemoveLineBreakCount( nIndex );
941         EPosition aPos( mpImpl->Range2Internal(nIndex) );
942 
943         ::com::sun::star::accessibility::TextSegment aResult;
944 
945         if( AccessibleTextType::PARAGRAPH == aTextType )
946         {
947             // #106393# Special casing one behind last paragraph is
948             // not necessary, since then, we return the content and
949             // boundary of that last paragraph. Range2Internal is
950             // tolerant against that, and returns the last paragraph
951             // in aPos.nPara.
952 
953             // retrieve full text of the paragraph
954             aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
955 
956             // #112814# Adapt the start index with the paragraph offset
957             aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
958             aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
959         }
960         else if ( AccessibleTextType::ATTRIBUTE_RUN == aTextType )
961         {
962               SvxAccessibleTextAdapter& rTextForwarder = mpImpl->GetParagraph( aPos.nIndex ).GetTextForwarder();
963               sal_uInt16 nStartIndex, nEndIndex;
964               if ( rTextForwarder.GetAttributeRun( nStartIndex, nEndIndex, aPos.nPara, aPos.nIndex, sal_True ) )
965               {
966                      aResult.SegmentText = getTextRange( nStartIndex, nEndIndex );
967                      aResult.SegmentStart = nStartIndex;
968                      aResult.SegmentEnd = nEndIndex;
969               }
970         }
971         else
972         {
973             // No special handling required, forward to wrapped class
974             aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType );
975 
976             // #112814# Adapt the start index with the paragraph offset
977             mpImpl->CorrectTextSegment( aResult, aPos.nPara );
978 			if ( bLineBreak )
979 			{
980 				aResult.SegmentText = rtl::OUString(cNewLine);
981 			}
982         }
983 
984         return aResult;
985     }
986 
987     ::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)
988     {
989         ::vos::OGuard aGuard( Application::GetSolarMutex() );
990 		sal_Int32 nOldIdx = nIndex;
991 		sal_Bool bLineBreak =  mpImpl->RemoveLineBreakCount( nIndex );
992         EPosition aPos( mpImpl->Range2Internal(nIndex) );
993 
994         ::com::sun::star::accessibility::TextSegment aResult;
995 
996         if( AccessibleTextType::PARAGRAPH == aTextType )
997         {
998             if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() )
999             {
1000                 // #103589# Special casing one behind the last paragraph
1001                 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
1002 
1003                 // #112814# Adapt the start index with the paragraph offset
1004                 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
1005             }
1006             else if( aPos.nPara > 0 )
1007             {
1008                 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText();
1009 
1010                 // #112814# Adapt the start index with the paragraph offset
1011                 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) );
1012             }
1013 
1014             aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
1015         }
1016         else
1017         {
1018             // No special handling required, forward to wrapped class
1019             aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType );
1020 
1021             // #112814# Adapt the start index with the paragraph offset
1022             mpImpl->CorrectTextSegment( aResult, aPos.nPara );
1023 			if ( bLineBreak && (nOldIdx-1) >= 0)
1024 			{
1025 				aResult = getTextAtIndex( nOldIdx-1, aTextType );
1026 			}
1027         }
1028 
1029         return aResult;
1030     }
1031 
1032     ::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)
1033     {
1034         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1035 		sal_Int32 nTemp = nIndex+1;
1036 		sal_Bool bLineBreak = mpImpl->RemoveLineBreakCount( nTemp );
1037 		mpImpl->RemoveLineBreakCount( nIndex );
1038         EPosition aPos( mpImpl->Range2Internal(nIndex) );
1039 
1040         ::com::sun::star::accessibility::TextSegment aResult;
1041 
1042         if( AccessibleTextType::PARAGRAPH == aTextType )
1043         {
1044             // Special casing one behind the last paragraph is not
1045             // necessary, this case is invalid here for
1046             // getTextBehindIndex
1047             if( aPos.nPara + 1 < mpImpl->GetParagraphCount() )
1048             {
1049                 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText();
1050 
1051                 // #112814# Adapt the start index with the paragraph offset
1052                 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) );
1053                 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
1054             }
1055         }
1056         else
1057         {
1058             // No special handling required, forward to wrapped class
1059             aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType );
1060 
1061             // #112814# Adapt the start index with the paragraph offset
1062             mpImpl->CorrectTextSegment( aResult, aPos.nPara );
1063 			if ( bLineBreak )
1064 			{
1065 				aResult.SegmentText = rtl::OUString(cNewLine) + aResult.SegmentText;
1066 			}
1067        }
1068 
1069         return aResult;
1070     }
1071 
1072     sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1073     {
1074         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1075 
1076         if( nStartIndex > nEndIndex )
1077             ::std::swap(nStartIndex, nEndIndex);
1078 
1079         EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
1080         EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
1081 
1082         return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex,
1083                                  aEndIndex.nPara, aEndIndex.nIndex );
1084     }
1085 
1086     // XAccessibleTextAttributes
1087     uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (uno::RuntimeException)
1088     {
1089         // get the intersection of the default attributes of all paragraphs
1090 
1091         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1092 
1093         PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) );
1094 
1095         const sal_Int32 nParaCount = mpImpl->GetParagraphCount();
1096         for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara )
1097         {
1098             uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes );
1099             PropertyValueVector aIntersectionVec;
1100 
1101             PropertyValueVector::const_iterator aEnd = aDefAttrVec.end();
1102             for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr )
1103             {
1104                 const beans::PropertyValue* pItr = aSeq.getConstArray();
1105                 const beans::PropertyValue* pEnd  = pItr + aSeq.getLength();
1106                 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) );
1107                 if ( pFind != pEnd )
1108                 {
1109                     aIntersectionVec.push_back( *pFind );
1110                 }
1111             }
1112 
1113             aDefAttrVec.swap( aIntersectionVec );
1114 
1115             if ( aDefAttrVec.empty() )
1116             {
1117                 break;
1118             }
1119         }
1120 
1121         return aDefAttrVec.getAsConstList();
1122     }
1123 
1124     uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1125     {
1126         // get those default attributes of the paragraph, which are not part
1127         // of the intersection of all paragraphs and add them to the run attributes
1128 
1129         ::vos::OGuard aGuard( Application::GetSolarMutex() );
1130 
1131         EPosition aPos( mpImpl->Index2Internal( nIndex ) );
1132         AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
1133         uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes );
1134         uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes );
1135         uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes );
1136         PropertyValueVector aDiffVec;
1137 
1138         const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray();
1139         const sal_Int32 nLength = aDefAttrSeq.getLength();
1140         for ( sal_Int32 i = 0; i < nLength; ++i )
1141         {
1142             const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray();
1143             const beans::PropertyValue* pEnd  = pItr + aIntersectionSeq.getLength();
1144             const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) );
1145             if ( pFind == pEnd && pDefAttr[i].Handle != 0)
1146             {
1147                 aDiffVec.push_back( pDefAttr[i] );
1148             }
1149         }
1150 
1151         return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() );
1152     }
1153 
1154     Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const
1155     {
1156         return mpImpl->GetParagraphBoundingBox();
1157     }
1158 
1159     sal_Int32 AccessibleStaticTextBase::GetParagraphIndex() const
1160     {
1161         return mpImpl->GetParagraphIndex();
1162     }
1163 
1164     sal_Int32 AccessibleStaticTextBase::GetParagraphCount() const
1165     {
1166         return mpImpl->GetParagraphCount();
1167     }
1168 
1169     sal_Int32 AccessibleStaticTextBase::GetLineCount( sal_Int32 nParagraph ) const
1170     {
1171         return mpImpl->GetLineCount( nParagraph );
1172     }
1173 
1174 }  // end of namespace accessibility
1175 
1176 //------------------------------------------------------------------------
1177