Update ooo320-m1
[ooovba.git] / svx / source / accessibility / AccessibleStaticTextBase.cxx
blobc5681a4f0ea6b2bda2f890c840382d0927d5a07f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: AccessibleStaticTextBase.cxx,v $
10 * $Revision: 1.27 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 //------------------------------------------------------------------------
36 // Global header
38 //------------------------------------------------------------------------
40 #include <limits.h>
41 #include <vector>
42 #include <algorithm>
43 #include <boost/bind.hpp>
44 #include <vos/mutex.hxx>
45 #include <vcl/window.hxx>
46 #include <vcl/svapp.hxx>
47 #include <comphelper/sequenceasvector.hxx>
48 #include <com/sun/star/uno/Any.hxx>
49 #include <com/sun/star/uno/Reference.hxx>
50 #include <com/sun/star/awt/Point.hpp>
51 #include <com/sun/star/awt/Rectangle.hpp>
52 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
54 //------------------------------------------------------------------------
56 // Project-local header
58 //------------------------------------------------------------------------
60 #include <svx/editdata.hxx>
61 #include "unopracc.hxx"
62 #include "unoedprx.hxx"
63 #include "AccessibleStaticTextBase.hxx"
64 #include "AccessibleEditableTextPara.hxx"
67 using namespace ::com::sun::star;
68 using namespace ::com::sun::star::accessibility;
70 /* TODO:
71 =====
73 - separate adapter functionality from AccessibleStaticText class
75 - refactor common loops into templates, using mem_fun
79 namespace accessibility
81 typedef ::comphelper::SequenceAsVector< beans::PropertyValue > PropertyValueVector;
83 class PropertyValueEqualFunctor : public ::std::binary_function< beans::PropertyValue, beans::PropertyValue, bool >
85 public:
86 PropertyValueEqualFunctor()
88 bool operator() ( const beans::PropertyValue& lhs, const beans::PropertyValue& rhs ) const
90 return ( lhs.Name == rhs.Name && lhs.Value == rhs.Value );
94 //------------------------------------------------------------------------
96 // Static Helper
98 //------------------------------------------------------------------------
99 ESelection MakeSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
100 sal_Int32 nEndPara, sal_Int32 nEndIndex )
102 DBG_ASSERT(nStartPara >= 0 && nStartPara <= USHRT_MAX &&
103 nStartIndex >= 0 && nStartIndex <= USHRT_MAX &&
104 nEndPara >= 0 && nEndPara <= USHRT_MAX &&
105 nEndIndex >= 0 && nEndIndex <= USHRT_MAX ,
106 "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow");
108 return ESelection( static_cast< USHORT >(nStartPara), static_cast< USHORT >(nStartIndex),
109 static_cast< USHORT >(nEndPara), static_cast< USHORT >(nEndIndex) );
112 //------------------------------------------------------------------------
114 // AccessibleStaticTextBase_Impl declaration
116 //------------------------------------------------------------------------
118 DBG_NAME( AccessibleStaticTextBase_Impl );
120 /** AccessibleStaticTextBase_Impl
122 This class implements the AccessibleStaticTextBase
123 functionality, mainly by forwarding the calls to an aggregated
124 AccessibleEditableTextPara. As this is a therefore non-trivial
125 adapter, factoring out the common functionality from
126 AccessibleEditableTextPara might be a profitable future task.
128 class AccessibleStaticTextBase_Impl
131 public:
133 // receive pointer to our frontend class and view window
134 AccessibleStaticTextBase_Impl();
135 ~AccessibleStaticTextBase_Impl();
137 SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException))
139 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
141 return maEditSource;
143 void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException));
145 void SetEventSource( const uno::Reference< XAccessible >& rInterface )
147 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
149 mxThis = rInterface;
151 uno::Reference< XAccessible > GetEventSource() const
153 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
155 return mxThis;
158 void SetOffset( const Point& );
159 Point GetOffset() const
161 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
163 ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset );
164 return aPoint;
167 void UpdateChildren();
168 void Dispose();
170 #ifdef DBG_UTIL
171 void CheckInvariants() const;
172 #endif
174 AccessibleEditableTextPara& GetParagraph( sal_Int32 nPara ) const;
175 sal_Int32 GetParagraphCount() const;
176 sal_Int32 GetParagraphIndex() const;
177 sal_Int32 GetLineCount( sal_Int32 nParagraph ) const;
179 EPosition Index2Internal( sal_Int32 nFlatIndex ) const
181 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
183 return ImpCalcInternal( nFlatIndex, false );
186 EPosition Range2Internal( sal_Int32 nFlatIndex ) const
188 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
190 return ImpCalcInternal( nFlatIndex, true );
193 sal_Int32 Internal2Index( EPosition nEEIndex ) const;
195 void CorrectTextSegment( TextSegment& aTextSegment,
196 int nPara ) const;
198 sal_Bool SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
199 sal_Int32 nEndPara, sal_Int32 nEndIndex );
200 sal_Bool CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
201 sal_Int32 nEndPara, sal_Int32 nEndIndex );
203 Rectangle GetParagraphBoundingBox() const;
205 private:
207 EPosition ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const;
209 // our frontend class (the one implementing the actual
210 // interface). That's not necessarily the one containing the impl
211 // pointer
212 uno::Reference< XAccessible > mxThis;
214 // implements our functionality, we're just an adapter (guarded by solar mutex)
215 mutable AccessibleEditableTextPara* mpTextParagraph;
217 uno::Reference< XAccessible > mxParagraph;
219 // a wrapper for the text forwarders (guarded by solar mutex)
220 mutable SvxEditSourceAdapter maEditSource;
222 // guard for maOffset
223 mutable ::osl::Mutex maMutex;
225 /// our current offset to the containing shape/cell (guarded by maMutex)
226 Point maOffset;
230 //------------------------------------------------------------------------
232 // AccessibleStaticTextBase_Impl implementation
234 //------------------------------------------------------------------------
236 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
237 mxThis( NULL ),
238 mpTextParagraph( new AccessibleEditableTextPara(NULL) ),
239 mxParagraph( mpTextParagraph ),
240 maEditSource(),
241 maMutex(),
242 maOffset(0,0)
244 DBG_CTOR( AccessibleStaticTextBase_Impl, NULL );
246 // TODO: this is still somewhat of a hack, all the more since
247 // now the maTextParagraph has an empty parent reference set
250 AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl()
252 DBG_DTOR( AccessibleStaticTextBase_Impl, NULL );
255 void AccessibleStaticTextBase_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
257 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
259 maEditSource.SetEditSource( pEditSource );
260 if( mpTextParagraph )
261 mpTextParagraph->SetEditSource( &maEditSource );
264 void AccessibleStaticTextBase_Impl::SetOffset( const Point& rPoint )
266 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
268 // guard against non-atomic access to maOffset data structure
270 ::osl::MutexGuard aGuard( maMutex );
271 maOffset = rPoint;
274 if( mpTextParagraph )
275 mpTextParagraph->SetEEOffset( rPoint );
277 // in all cases, check visibility afterwards.
278 UpdateChildren();
281 void AccessibleStaticTextBase_Impl::UpdateChildren()
283 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
285 // currently no children
288 void AccessibleStaticTextBase_Impl::Dispose()
290 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
292 // we're the owner of the paragraph, so destroy it, too
293 if( mpTextParagraph )
294 mpTextParagraph->Dispose();
296 // drop references
297 mxParagraph = NULL;
298 mxThis = NULL;
299 mpTextParagraph = NULL;
302 #ifdef DBG_UTIL
303 void AccessibleStaticTextBase_Impl::CheckInvariants() const
305 // TODO
307 #endif
309 AccessibleEditableTextPara& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara ) const
311 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
313 if( !mpTextParagraph )
314 throw lang::DisposedException (
315 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), mxThis );
317 // TODO: Have a differnt method on AccessibleEditableTextPara
318 // that does not care about state changes
319 mpTextParagraph->SetParagraphIndex( nPara );
321 return *mpTextParagraph;
324 sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphCount() const
326 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
328 if( !mpTextParagraph )
329 return 0;
330 else
331 return mpTextParagraph->GetTextForwarder().GetParagraphCount();
334 sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphIndex() const
336 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
338 sal_Int32 nIndex = -1;
339 if( mpTextParagraph )
340 nIndex = mpTextParagraph->GetParagraphIndex();
341 return nIndex;
344 sal_Int32 AccessibleStaticTextBase_Impl::GetLineCount( sal_Int32 nParagraph ) const
346 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
348 sal_Int32 nIndex = 0;
349 if( mpTextParagraph )
350 nIndex = mpTextParagraph->GetTextForwarder().GetLineCount( static_cast< USHORT >(nParagraph) );
351 return nIndex;
354 sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const
356 sal_Int32 aRes(0);
357 int i;
358 for(i=0; i<nEEIndex.nPara; ++i)
359 aRes += GetParagraph(i).getCharacterCount();
361 return aRes + nEEIndex.nIndex;
364 void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment& aTextSegment,
365 int nPara ) const
367 // Keep 'invalid' values at the TextSegment
368 if( aTextSegment.SegmentStart != -1 &&
369 aTextSegment.SegmentStart != -1 )
371 // #112814# Correct TextSegment by paragraph offset
372 sal_Int32 nOffset(0);
373 int i;
374 for(i=0; i<nPara; ++i)
375 nOffset += GetParagraph(i).getCharacterCount();
377 aTextSegment.SegmentStart += nOffset;
378 aTextSegment.SegmentEnd += nOffset;
382 EPosition AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const
384 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
386 if( nFlatIndex < 0 )
387 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
388 mxThis);
389 // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually
391 sal_Int32 nCurrPara, nCurrIndex, nParas, nCurrCount;
392 for( nCurrPara=0, nParas=GetParagraphCount(), nCurrCount=0, nCurrIndex=0; nCurrPara<nParas; ++nCurrPara )
394 nCurrCount = GetParagraph( nCurrPara ).getCharacterCount();
395 nCurrIndex += nCurrCount;
397 if( nCurrIndex > nFlatIndex )
399 // check overflow
400 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX &&
401 nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
402 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
404 return EPosition( static_cast< USHORT >(nCurrPara), static_cast< USHORT >(nFlatIndex - nCurrIndex + nCurrCount) );
408 // #102170# Allow one-past the end for ranges
409 if( bExclusive && nCurrIndex == nFlatIndex )
411 // check overflow
412 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX &&
413 nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
414 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
416 return EPosition( static_cast< USHORT >(nCurrPara-1), static_cast< USHORT >(nFlatIndex - nCurrIndex + nCurrCount) );
419 // not found? Out of bounds
420 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
421 mxThis);
424 sal_Bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
425 sal_Int32 nEndPara, sal_Int32 nEndIndex )
427 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
429 if( !mpTextParagraph )
430 return sal_False;
434 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
435 return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
437 catch( const uno::RuntimeException& )
439 return sal_False;
443 sal_Bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
444 sal_Int32 nEndPara, sal_Int32 nEndIndex )
446 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
448 if( !mpTextParagraph )
449 return sal_False;
453 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
454 mpTextParagraph->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
455 sal_Bool aRetVal;
457 // save current selection
458 ESelection aOldSelection;
460 rCacheVF.GetSelection( aOldSelection );
461 rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
462 aRetVal = rCacheVF.Copy();
463 rCacheVF.SetSelection( aOldSelection ); // restore
465 return aRetVal;
467 catch( const uno::RuntimeException& )
469 return sal_False;
473 Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
475 Rectangle aRect;
476 if( mpTextParagraph )
478 awt::Rectangle aAwtRect = mpTextParagraph->getBounds();
479 aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) );
481 else
483 aRect.SetEmpty();
485 return aRect;
488 //------------------------------------------------------------------------
490 // AccessibleStaticTextBase implementation
492 //------------------------------------------------------------------------
494 AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::auto_ptr< SvxEditSource > pEditSource ) :
495 mpImpl( new AccessibleStaticTextBase_Impl() )
497 ::vos::OGuard aGuard( Application::GetSolarMutex() );
499 SetEditSource( pEditSource );
502 AccessibleStaticTextBase::~AccessibleStaticTextBase()
506 const SvxEditSource& AccessibleStaticTextBase::GetEditSource() const SAL_THROW((::com::sun::star::uno::RuntimeException))
508 #ifdef DBG_UTIL
509 mpImpl->CheckInvariants();
511 const SvxEditSource& aEditSource = mpImpl->GetEditSource();
513 mpImpl->CheckInvariants();
515 return aEditSource;
516 #else
517 return mpImpl->GetEditSource();
518 #endif
521 void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((::com::sun::star::uno::RuntimeException))
523 #ifdef DBG_UTIL
524 // precondition: solar mutex locked
525 DBG_TESTSOLARMUTEX();
527 mpImpl->CheckInvariants();
529 mpImpl->SetEditSource( pEditSource );
531 mpImpl->CheckInvariants();
532 #else
533 mpImpl->SetEditSource( pEditSource );
534 #endif
537 void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface )
539 #ifdef DBG_UTIL
540 mpImpl->CheckInvariants();
541 #endif
543 mpImpl->SetEventSource( rInterface );
545 #ifdef DBG_UTIL
546 mpImpl->CheckInvariants();
547 #endif
550 uno::Reference< XAccessible > AccessibleStaticTextBase::GetEventSource() const
552 #ifdef DBG_UTIL
553 mpImpl->CheckInvariants();
555 uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
557 mpImpl->CheckInvariants();
559 return xRet;
560 #else
561 return mpImpl->GetEventSource();
562 #endif
565 void AccessibleStaticTextBase::SetOffset( const Point& rPoint )
567 #ifdef DBG_UTIL
568 // precondition: solar mutex locked
569 DBG_TESTSOLARMUTEX();
571 mpImpl->CheckInvariants();
573 mpImpl->SetOffset( rPoint );
575 mpImpl->CheckInvariants();
576 #else
577 mpImpl->SetOffset( rPoint );
578 #endif
581 Point AccessibleStaticTextBase::GetOffset() const
583 #ifdef DBG_UTIL
584 mpImpl->CheckInvariants();
586 Point aPoint( mpImpl->GetOffset() );
588 mpImpl->CheckInvariants();
590 return aPoint;
591 #else
592 return mpImpl->GetOffset();
593 #endif
596 void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
598 #ifdef DBG_UTIL
599 // precondition: solar mutex locked
600 DBG_TESTSOLARMUTEX();
602 mpImpl->CheckInvariants();
604 mpImpl->UpdateChildren();
606 mpImpl->CheckInvariants();
607 #else
608 mpImpl->UpdateChildren();
609 #endif
612 void AccessibleStaticTextBase::Dispose()
614 #ifdef DBG_UTIL
615 mpImpl->CheckInvariants();
616 #endif
618 mpImpl->Dispose();
620 #ifdef DBG_UTIL
621 mpImpl->CheckInvariants();
622 #endif
625 // XAccessibleContext
626 sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException)
628 // no children at all
629 return 0;
632 uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleChild( sal_Int32 /*i*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
634 // no children at all
635 return uno::Reference< XAccessible >();
638 uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) throw (uno::RuntimeException)
640 // no children at all
641 return uno::Reference< XAccessible >();
644 // XAccessibleText
645 sal_Int32 SAL_CALL AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException)
647 ::vos::OGuard aGuard( Application::GetSolarMutex() );
649 sal_Int32 i, nPos, nParas;
650 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
652 if( (nPos=mpImpl->GetParagraph(i).getCaretPosition()) != -1 )
653 return nPos;
656 return nPos;
659 sal_Bool SAL_CALL AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
661 return setSelection(nIndex, nIndex);
664 sal_Unicode SAL_CALL AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
666 ::vos::OGuard aGuard( Application::GetSolarMutex() );
668 EPosition aPos( mpImpl->Index2Internal(nIndex) );
670 return mpImpl->GetParagraph( aPos.nPara ).getCharacter( aPos.nIndex );
673 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)
675 ::vos::OGuard aGuard( Application::GetSolarMutex() );
677 EPosition aPos( mpImpl->Index2Internal(nIndex) );
679 return mpImpl->GetParagraph( aPos.nPara ).getCharacterAttributes( aPos.nIndex, aRequestedAttributes );
682 awt::Rectangle SAL_CALL AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
684 ::vos::OGuard aGuard( Application::GetSolarMutex() );
686 // #108900# Allow ranges for nIndex, as one-past-the-end
687 // values are now legal, too.
688 EPosition aPos( mpImpl->Range2Internal(nIndex) );
690 // #i70916# Text in spread sheet cells return the wrong extents
691 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
692 awt::Rectangle aParaBounds( rPara.getBounds() );
693 awt::Rectangle aBounds( rPara.getCharacterBounds( aPos.nIndex ) );
694 aBounds.X += aParaBounds.X;
695 aBounds.Y += aParaBounds.Y;
697 return aBounds;
700 sal_Int32 SAL_CALL AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException)
702 ::vos::OGuard aGuard( Application::GetSolarMutex() );
704 sal_Int32 i, nCount, nParas;
705 for( i=0, nCount=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
706 nCount += mpImpl->GetParagraph(i).getCharacterCount();
708 return nCount;
711 sal_Int32 SAL_CALL AccessibleStaticTextBase::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException)
713 ::vos::OGuard aGuard( Application::GetSolarMutex() );
715 const sal_Int32 nParas( mpImpl->GetParagraphCount() );
716 sal_Int32 nIndex;
717 int i;
718 for( i=0; i<nParas; ++i )
720 // TODO: maybe exploit the fact that paragraphs are
721 // ordered vertically for early exit
723 // #i70916# Text in spread sheet cells return the wrong extents
724 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( i );
725 awt::Rectangle aParaBounds( rPara.getBounds() );
726 awt::Point aPoint( rPoint );
727 aPoint.X -= aParaBounds.X;
728 aPoint.Y -= aParaBounds.Y;
730 // #112814# Use correct index offset
731 if ( ( nIndex = rPara.getIndexAtPoint( aPoint ) ) != -1 )
732 return mpImpl->Internal2Index( EPosition(sal::static_int_cast<USHORT>(i),
733 sal::static_int_cast<USHORT>(nIndex)) );
736 return -1;
739 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException)
741 ::vos::OGuard aGuard( Application::GetSolarMutex() );
743 sal_Int32 nStart( getSelectionStart() );
744 sal_Int32 nEnd( getSelectionEnd() );
746 // #104481# Return the empty string for 'no selection'
747 if( nStart < 0 || nEnd < 0 )
748 return ::rtl::OUString();
750 return getTextRange( nStart, nEnd );
753 sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException)
755 ::vos::OGuard aGuard( Application::GetSolarMutex() );
757 sal_Int32 i, nPos, nParas;
758 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
760 if( (nPos=mpImpl->GetParagraph(i).getSelectionStart()) != -1 )
761 return nPos;
764 return nPos;
767 sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException)
769 ::vos::OGuard aGuard( Application::GetSolarMutex() );
771 sal_Int32 i, nPos, nParas;
772 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
774 if( (nPos=mpImpl->GetParagraph(i).getSelectionEnd()) != -1 )
775 return nPos;
778 return nPos;
781 sal_Bool SAL_CALL AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
783 ::vos::OGuard aGuard( Application::GetSolarMutex() );
785 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
786 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
788 return mpImpl->SetSelection( aStartIndex.nPara, aStartIndex.nIndex,
789 aEndIndex.nPara, aEndIndex.nIndex );
792 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getText() throw (uno::RuntimeException)
794 ::vos::OGuard aGuard( Application::GetSolarMutex() );
796 sal_Int32 i, nParas;
797 ::rtl::OUString aRes;
798 for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
799 aRes += mpImpl->GetParagraph(i).getText();
801 return aRes;
804 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
806 ::vos::OGuard aGuard( Application::GetSolarMutex() );
808 if( nStartIndex > nEndIndex )
809 ::std::swap(nStartIndex, nEndIndex);
811 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
812 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
814 // #102170# Special case: start and end paragraph are identical
815 if( aStartIndex.nPara == aEndIndex.nPara )
817 return mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex );
819 else
821 sal_Int32 i( aStartIndex.nPara );
822 ::rtl::OUString aRes( mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex,
823 mpImpl->GetParagraph(i).getCharacterCount()-1) );
824 ++i;
826 // paragraphs inbetween are fully included
827 for( ; i<aEndIndex.nPara; ++i )
828 aRes += mpImpl->GetParagraph(i).getText();
830 if( i<=aEndIndex.nPara )
831 aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex );
833 return aRes;
837 ::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)
839 ::vos::OGuard aGuard( Application::GetSolarMutex() );
841 EPosition aPos( mpImpl->Range2Internal(nIndex) );
843 ::com::sun::star::accessibility::TextSegment aResult;
845 if( AccessibleTextType::PARAGRAPH == aTextType )
847 // #106393# Special casing one behind last paragraph is
848 // not necessary, since then, we return the content and
849 // boundary of that last paragraph. Range2Internal is
850 // tolerant against that, and returns the last paragraph
851 // in aPos.nPara.
853 // retrieve full text of the paragraph
854 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
856 // #112814# Adapt the start index with the paragraph offset
857 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
858 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
860 else
862 // No special handling required, forward to wrapped class
863 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType );
865 // #112814# Adapt the start index with the paragraph offset
866 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
869 return aResult;
872 ::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)
874 ::vos::OGuard aGuard( Application::GetSolarMutex() );
876 EPosition aPos( mpImpl->Range2Internal(nIndex) );
878 ::com::sun::star::accessibility::TextSegment aResult;
880 if( AccessibleTextType::PARAGRAPH == aTextType )
882 if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() )
884 // #103589# Special casing one behind the last paragraph
885 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
887 // #112814# Adapt the start index with the paragraph offset
888 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
890 else if( aPos.nPara > 0 )
892 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText();
894 // #112814# Adapt the start index with the paragraph offset
895 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) );
898 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
900 else
902 // No special handling required, forward to wrapped class
903 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType );
905 // #112814# Adapt the start index with the paragraph offset
906 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
909 return aResult;
912 ::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)
914 ::vos::OGuard aGuard( Application::GetSolarMutex() );
916 EPosition aPos( mpImpl->Range2Internal(nIndex) );
918 ::com::sun::star::accessibility::TextSegment aResult;
920 if( AccessibleTextType::PARAGRAPH == aTextType )
922 // Special casing one behind the last paragraph is not
923 // necessary, this case is invalid here for
924 // getTextBehindIndex
925 if( aPos.nPara + 1 < mpImpl->GetParagraphCount() )
927 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText();
929 // #112814# Adapt the start index with the paragraph offset
930 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) );
931 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
934 else
936 // No special handling required, forward to wrapped class
937 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType );
939 // #112814# Adapt the start index with the paragraph offset
940 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
943 return aResult;
946 sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
948 ::vos::OGuard aGuard( Application::GetSolarMutex() );
950 if( nStartIndex > nEndIndex )
951 ::std::swap(nStartIndex, nEndIndex);
953 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
954 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
956 return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex,
957 aEndIndex.nPara, aEndIndex.nIndex );
960 // XAccessibleTextAttributes
961 uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (uno::RuntimeException)
963 // get the intersection of the default attributes of all paragraphs
965 ::vos::OGuard aGuard( Application::GetSolarMutex() );
967 PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) );
969 const sal_Int32 nParaCount = mpImpl->GetParagraphCount();
970 for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara )
972 uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes );
973 PropertyValueVector aIntersectionVec;
975 PropertyValueVector::const_iterator aEnd = aDefAttrVec.end();
976 for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr )
978 const beans::PropertyValue* pItr = aSeq.getConstArray();
979 const beans::PropertyValue* pEnd = pItr + aSeq.getLength();
980 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) );
981 if ( pFind != pEnd )
983 aIntersectionVec.push_back( *pFind );
987 aDefAttrVec.swap( aIntersectionVec );
989 if ( aDefAttrVec.empty() )
991 break;
995 return aDefAttrVec.getAsConstList();
998 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1000 // get those default attributes of the paragraph, which are not part
1001 // of the intersection of all paragraphs and add them to the run attributes
1003 ::vos::OGuard aGuard( Application::GetSolarMutex() );
1005 EPosition aPos( mpImpl->Index2Internal( nIndex ) );
1006 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
1007 uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes );
1008 uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes );
1009 uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes );
1010 PropertyValueVector aDiffVec;
1012 const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray();
1013 const sal_Int32 nLength = aDefAttrSeq.getLength();
1014 for ( sal_Int32 i = 0; i < nLength; ++i )
1016 const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray();
1017 const beans::PropertyValue* pEnd = pItr + aIntersectionSeq.getLength();
1018 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) );
1019 if ( pFind == pEnd && pFind->Handle != 0)
1021 aDiffVec.push_back( *pFind );
1025 return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() );
1028 Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const
1030 return mpImpl->GetParagraphBoundingBox();
1033 sal_Int32 AccessibleStaticTextBase::GetParagraphIndex() const
1035 return mpImpl->GetParagraphIndex();
1038 sal_Int32 AccessibleStaticTextBase::GetParagraphCount() const
1040 return mpImpl->GetParagraphCount();
1043 sal_Int32 AccessibleStaticTextBase::GetLineCount( sal_Int32 nParagraph ) const
1045 return mpImpl->GetLineCount( nParagraph );
1048 } // end of namespace accessibility
1050 //------------------------------------------------------------------------