Bump for 3.6-28
[LibreOffice.git] / editeng / source / accessibility / AccessibleStaticTextBase.cxx
blob45c20de438c754d9fcaf7021882f945bebd5a1cb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 //------------------------------------------------------------------------
32 // Global header
34 //------------------------------------------------------------------------
36 #include <limits.h>
37 #include <vector>
38 #include <algorithm>
39 #include <boost/ref.hpp>
40 #include <osl/mutex.hxx>
41 #include <vcl/window.hxx>
42 #include <vcl/svapp.hxx>
43 #include <comphelper/sequenceasvector.hxx>
44 #include <com/sun/star/uno/Any.hxx>
45 #include <com/sun/star/uno/Reference.hxx>
46 #include <com/sun/star/awt/Point.hpp>
47 #include <com/sun/star/awt/Rectangle.hpp>
48 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
50 //------------------------------------------------------------------------
52 // Project-local header
54 //------------------------------------------------------------------------
56 #include <editeng/editdata.hxx>
57 #include <editeng/unopracc.hxx>
58 #include "editeng/unoedprx.hxx"
59 #include <editeng/AccessibleStaticTextBase.hxx>
60 #include "editeng/AccessibleEditableTextPara.hxx"
63 using namespace ::com::sun::star;
64 using namespace ::com::sun::star::accessibility;
66 /* TODO:
67 =====
69 - separate adapter functionality from AccessibleStaticText class
71 - refactor common loops into templates, using mem_fun
75 namespace accessibility
77 typedef ::comphelper::SequenceAsVector< beans::PropertyValue > PropertyValueVector;
79 class PropertyValueEqualFunctor : public ::std::binary_function< beans::PropertyValue, beans::PropertyValue, bool >
81 public:
82 PropertyValueEqualFunctor()
84 bool operator() ( const beans::PropertyValue& lhs, const beans::PropertyValue& rhs ) const
86 return ( lhs.Name == rhs.Name && lhs.Value == rhs.Value );
90 //------------------------------------------------------------------------
92 // Static Helper
94 //------------------------------------------------------------------------
95 ESelection MakeSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
96 sal_Int32 nEndPara, sal_Int32 nEndIndex )
98 DBG_ASSERT(nStartPara >= 0 && nStartPara <= USHRT_MAX &&
99 nStartIndex >= 0 && nStartIndex <= USHRT_MAX &&
100 nEndPara >= 0 && nEndPara <= USHRT_MAX &&
101 nEndIndex >= 0 && nEndIndex <= USHRT_MAX ,
102 "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow");
104 return ESelection( static_cast< sal_uInt16 >(nStartPara), static_cast< sal_uInt16 >(nStartIndex),
105 static_cast< sal_uInt16 >(nEndPara), static_cast< sal_uInt16 >(nEndIndex) );
108 //------------------------------------------------------------------------
110 // AccessibleStaticTextBase_Impl declaration
112 //------------------------------------------------------------------------
114 DBG_NAME( AccessibleStaticTextBase_Impl );
116 /** AccessibleStaticTextBase_Impl
118 This class implements the AccessibleStaticTextBase
119 functionality, mainly by forwarding the calls to an aggregated
120 AccessibleEditableTextPara. As this is a therefore non-trivial
121 adapter, factoring out the common functionality from
122 AccessibleEditableTextPara might be a profitable future task.
124 class AccessibleStaticTextBase_Impl
127 public:
129 // receive pointer to our frontend class and view window
130 AccessibleStaticTextBase_Impl();
131 ~AccessibleStaticTextBase_Impl();
133 SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException))
135 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
137 return maEditSource;
139 SAL_WNODEPRECATED_DECLARATIONS_PUSH
140 void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException));
141 SAL_WNODEPRECATED_DECLARATIONS_POP
143 void SetEventSource( const uno::Reference< XAccessible >& rInterface )
145 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
147 mxThis = rInterface;
149 uno::Reference< XAccessible > GetEventSource() const
151 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
153 return mxThis;
156 void SetOffset( const Point& );
157 Point GetOffset() const
159 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
161 ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset );
162 return aPoint;
165 void UpdateChildren();
166 void Dispose();
168 #ifdef DBG_UTIL
169 void CheckInvariants() const;
170 #endif
172 AccessibleEditableTextPara& GetParagraph( sal_Int32 nPara ) const;
173 sal_Int32 GetParagraphCount() const;
175 EPosition Index2Internal( sal_Int32 nFlatIndex ) const
177 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
179 return ImpCalcInternal( nFlatIndex, false );
182 EPosition Range2Internal( sal_Int32 nFlatIndex ) const
184 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
186 return ImpCalcInternal( nFlatIndex, true );
189 sal_Int32 Internal2Index( EPosition nEEIndex ) const;
191 void CorrectTextSegment( TextSegment& aTextSegment,
192 int nPara ) const;
194 sal_Bool SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
195 sal_Int32 nEndPara, sal_Int32 nEndIndex );
196 sal_Bool CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
197 sal_Int32 nEndPara, sal_Int32 nEndIndex );
199 Rectangle GetParagraphBoundingBox() const;
201 private:
203 EPosition ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const;
205 // our frontend class (the one implementing the actual
206 // interface). That's not necessarily the one containing the impl
207 // pointer
208 uno::Reference< XAccessible > mxThis;
210 // implements our functionality, we're just an adapter (guarded by solar mutex)
211 mutable AccessibleEditableTextPara* mpTextParagraph;
213 uno::Reference< XAccessible > mxParagraph;
215 // a wrapper for the text forwarders (guarded by solar mutex)
216 mutable SvxEditSourceAdapter maEditSource;
218 // guard for maOffset
219 mutable ::osl::Mutex maMutex;
221 /// our current offset to the containing shape/cell (guarded by maMutex)
222 Point maOffset;
226 //------------------------------------------------------------------------
228 // AccessibleStaticTextBase_Impl implementation
230 //------------------------------------------------------------------------
232 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
233 mxThis( NULL ),
234 mpTextParagraph( new AccessibleEditableTextPara(NULL) ),
235 mxParagraph( mpTextParagraph ),
236 maEditSource(),
237 maMutex(),
238 maOffset(0,0)
240 DBG_CTOR( AccessibleStaticTextBase_Impl, NULL );
242 // TODO: this is still somewhat of a hack, all the more since
243 // now the maTextParagraph has an empty parent reference set
246 AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl()
248 DBG_DTOR( AccessibleStaticTextBase_Impl, NULL );
251 SAL_WNODEPRECATED_DECLARATIONS_PUSH
252 void AccessibleStaticTextBase_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
254 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
256 maEditSource.SetEditSource( pEditSource );
257 if( mpTextParagraph )
258 mpTextParagraph->SetEditSource( &maEditSource );
260 SAL_WNODEPRECATED_DECLARATIONS_POP
262 void AccessibleStaticTextBase_Impl::SetOffset( const Point& rPoint )
264 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
266 // guard against non-atomic access to maOffset data structure
268 ::osl::MutexGuard aGuard( maMutex );
269 maOffset = rPoint;
272 if( mpTextParagraph )
273 mpTextParagraph->SetEEOffset( rPoint );
275 // in all cases, check visibility afterwards.
276 UpdateChildren();
279 void AccessibleStaticTextBase_Impl::UpdateChildren()
281 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
283 // currently no children
286 void AccessibleStaticTextBase_Impl::Dispose()
288 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
290 // we're the owner of the paragraph, so destroy it, too
291 if( mpTextParagraph )
292 mpTextParagraph->Dispose();
294 // drop references
295 mxParagraph = NULL;
296 mxThis = NULL;
297 mpTextParagraph = NULL;
300 #ifdef DBG_UTIL
301 void AccessibleStaticTextBase_Impl::CheckInvariants() const
303 // TODO
305 #endif
307 AccessibleEditableTextPara& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara ) const
309 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
311 if( !mpTextParagraph )
312 throw lang::DisposedException (
313 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), mxThis );
315 // TODO: Have a differnt method on AccessibleEditableTextPara
316 // that does not care about state changes
317 mpTextParagraph->SetParagraphIndex( nPara );
319 return *mpTextParagraph;
322 sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphCount() const
324 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
326 if( !mpTextParagraph )
327 return 0;
328 else
329 return mpTextParagraph->GetTextForwarder().GetParagraphCount();
332 sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const
334 sal_Int32 aRes(0);
335 int i;
336 for(i=0; i<nEEIndex.nPara; ++i)
337 aRes += GetParagraph(i).getCharacterCount();
339 return aRes + nEEIndex.nIndex;
342 void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment& aTextSegment,
343 int nPara ) const
345 // Keep 'invalid' values at the TextSegment
346 if( aTextSegment.SegmentStart != -1 &&
347 aTextSegment.SegmentEnd != -1 )
349 // #112814# Correct TextSegment by paragraph offset
350 sal_Int32 nOffset(0);
351 int i;
352 for(i=0; i<nPara; ++i)
353 nOffset += GetParagraph(i).getCharacterCount();
355 aTextSegment.SegmentStart += nOffset;
356 aTextSegment.SegmentEnd += nOffset;
360 EPosition AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const
362 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
364 if( nFlatIndex < 0 )
365 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
366 mxThis);
367 // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually
369 sal_Int32 nCurrPara, nCurrIndex, nParas, nCurrCount;
370 for( nCurrPara=0, nParas=GetParagraphCount(), nCurrCount=0, nCurrIndex=0; nCurrPara<nParas; ++nCurrPara )
372 nCurrCount = GetParagraph( nCurrPara ).getCharacterCount();
373 nCurrIndex += nCurrCount;
375 if( nCurrIndex > nFlatIndex )
377 // check overflow
378 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX &&
379 nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
380 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
382 return EPosition( static_cast< sal_uInt16 >(nCurrPara), static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
386 // #102170# Allow one-past the end for ranges
387 if( bExclusive && nCurrIndex == nFlatIndex )
389 // check overflow
390 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX &&
391 nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
392 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
394 return EPosition( static_cast< sal_uInt16 >(nCurrPara-1), static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
397 // not found? Out of bounds
398 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
399 mxThis);
402 sal_Bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
403 sal_Int32 nEndPara, sal_Int32 nEndIndex )
405 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
407 if( !mpTextParagraph )
408 return sal_False;
412 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
413 return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
415 catch( const uno::RuntimeException& )
417 return sal_False;
421 sal_Bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
422 sal_Int32 nEndPara, sal_Int32 nEndIndex )
424 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
426 if( !mpTextParagraph )
427 return sal_False;
431 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
432 mpTextParagraph->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
433 sal_Bool aRetVal;
435 // save current selection
436 ESelection aOldSelection;
438 rCacheVF.GetSelection( aOldSelection );
439 rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
440 aRetVal = rCacheVF.Copy();
441 rCacheVF.SetSelection( aOldSelection ); // restore
443 return aRetVal;
445 catch( const uno::RuntimeException& )
447 return sal_False;
451 Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
453 Rectangle aRect;
454 if( mpTextParagraph )
456 awt::Rectangle aAwtRect = mpTextParagraph->getBounds();
457 aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) );
459 else
461 aRect.SetEmpty();
463 return aRect;
466 //------------------------------------------------------------------------
468 // AccessibleStaticTextBase implementation
470 //------------------------------------------------------------------------
472 SAL_WNODEPRECATED_DECLARATIONS_PUSH
473 AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::auto_ptr< SvxEditSource > pEditSource ) :
474 mpImpl( new AccessibleStaticTextBase_Impl() )
476 SolarMutexGuard aGuard;
478 SetEditSource( pEditSource );
480 SAL_WNODEPRECATED_DECLARATIONS_POP
482 AccessibleStaticTextBase::~AccessibleStaticTextBase()
486 const SvxEditSource& AccessibleStaticTextBase::GetEditSource() const SAL_THROW((::com::sun::star::uno::RuntimeException))
488 #ifdef DBG_UTIL
489 mpImpl->CheckInvariants();
491 const SvxEditSource& aEditSource = mpImpl->GetEditSource();
493 mpImpl->CheckInvariants();
495 return aEditSource;
496 #else
497 return mpImpl->GetEditSource();
498 #endif
501 SAL_WNODEPRECATED_DECLARATIONS_PUSH
502 void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((::com::sun::star::uno::RuntimeException))
504 #ifdef DBG_UTIL
505 // precondition: solar mutex locked
506 DBG_TESTSOLARMUTEX();
508 mpImpl->CheckInvariants();
510 mpImpl->SetEditSource( pEditSource );
512 mpImpl->CheckInvariants();
513 #else
514 mpImpl->SetEditSource( pEditSource );
515 #endif
517 SAL_WNODEPRECATED_DECLARATIONS_POP
519 void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface )
521 #ifdef DBG_UTIL
522 mpImpl->CheckInvariants();
523 #endif
525 mpImpl->SetEventSource( rInterface );
527 #ifdef DBG_UTIL
528 mpImpl->CheckInvariants();
529 #endif
532 uno::Reference< XAccessible > AccessibleStaticTextBase::GetEventSource() const
534 #ifdef DBG_UTIL
535 mpImpl->CheckInvariants();
537 uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
539 mpImpl->CheckInvariants();
541 return xRet;
542 #else
543 return mpImpl->GetEventSource();
544 #endif
547 void AccessibleStaticTextBase::SetOffset( const Point& rPoint )
549 #ifdef DBG_UTIL
550 // precondition: solar mutex locked
551 DBG_TESTSOLARMUTEX();
553 mpImpl->CheckInvariants();
555 mpImpl->SetOffset( rPoint );
557 mpImpl->CheckInvariants();
558 #else
559 mpImpl->SetOffset( rPoint );
560 #endif
563 Point AccessibleStaticTextBase::GetOffset() const
565 #ifdef DBG_UTIL
566 mpImpl->CheckInvariants();
568 Point aPoint( mpImpl->GetOffset() );
570 mpImpl->CheckInvariants();
572 return aPoint;
573 #else
574 return mpImpl->GetOffset();
575 #endif
578 void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
580 #ifdef DBG_UTIL
581 // precondition: solar mutex locked
582 DBG_TESTSOLARMUTEX();
584 mpImpl->CheckInvariants();
586 mpImpl->UpdateChildren();
588 mpImpl->CheckInvariants();
589 #else
590 mpImpl->UpdateChildren();
591 #endif
594 void AccessibleStaticTextBase::Dispose()
596 #ifdef DBG_UTIL
597 mpImpl->CheckInvariants();
598 #endif
600 mpImpl->Dispose();
602 #ifdef DBG_UTIL
603 mpImpl->CheckInvariants();
604 #endif
607 // XAccessibleContext
608 sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException)
610 // no children at all
611 return 0;
614 uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleChild( sal_Int32 /*i*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
616 // no children at all
617 return uno::Reference< XAccessible >();
620 uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) throw (uno::RuntimeException)
622 // no children at all
623 return uno::Reference< XAccessible >();
626 // XAccessibleText
627 sal_Int32 SAL_CALL AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException)
629 SolarMutexGuard aGuard;
631 sal_Int32 i, nPos, nParas;
632 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
634 if( (nPos=mpImpl->GetParagraph(i).getCaretPosition()) != -1 )
635 return nPos;
638 return nPos;
641 sal_Bool SAL_CALL AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
643 return setSelection(nIndex, nIndex);
646 sal_Unicode SAL_CALL AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
648 SolarMutexGuard aGuard;
650 EPosition aPos( mpImpl->Index2Internal(nIndex) );
652 return mpImpl->GetParagraph( aPos.nPara ).getCharacter( aPos.nIndex );
655 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)
657 SolarMutexGuard aGuard;
659 EPosition aPos( mpImpl->Index2Internal(nIndex) );
661 return mpImpl->GetParagraph( aPos.nPara ).getCharacterAttributes( aPos.nIndex, aRequestedAttributes );
664 awt::Rectangle SAL_CALL AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
666 SolarMutexGuard aGuard;
668 // #108900# Allow ranges for nIndex, as one-past-the-end
669 // values are now legal, too.
670 EPosition aPos( mpImpl->Range2Internal(nIndex) );
672 // #i70916# Text in spread sheet cells return the wrong extents
673 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
674 awt::Rectangle aParaBounds( rPara.getBounds() );
675 awt::Rectangle aBounds( rPara.getCharacterBounds( aPos.nIndex ) );
676 aBounds.X += aParaBounds.X;
677 aBounds.Y += aParaBounds.Y;
679 return aBounds;
682 sal_Int32 SAL_CALL AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException)
684 SolarMutexGuard aGuard;
686 sal_Int32 i, nCount, nParas;
687 for( i=0, nCount=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
688 nCount += mpImpl->GetParagraph(i).getCharacterCount();
690 return nCount;
693 sal_Int32 SAL_CALL AccessibleStaticTextBase::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException)
695 SolarMutexGuard aGuard;
697 const sal_Int32 nParas( mpImpl->GetParagraphCount() );
698 sal_Int32 nIndex;
699 int i;
700 for( i=0; i<nParas; ++i )
702 // TODO: maybe exploit the fact that paragraphs are
703 // ordered vertically for early exit
705 // #i70916# Text in spread sheet cells return the wrong extents
706 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( i );
707 awt::Rectangle aParaBounds( rPara.getBounds() );
708 awt::Point aPoint( rPoint );
709 aPoint.X -= aParaBounds.X;
710 aPoint.Y -= aParaBounds.Y;
712 // #112814# Use correct index offset
713 if ( ( nIndex = rPara.getIndexAtPoint( aPoint ) ) != -1 )
714 return mpImpl->Internal2Index( EPosition(sal::static_int_cast<sal_uInt16>(i),
715 sal::static_int_cast<sal_uInt16>(nIndex)) );
718 return -1;
721 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException)
723 SolarMutexGuard aGuard;
725 sal_Int32 nStart( getSelectionStart() );
726 sal_Int32 nEnd( getSelectionEnd() );
728 // #104481# Return the empty string for 'no selection'
729 if( nStart < 0 || nEnd < 0 )
730 return ::rtl::OUString();
732 return getTextRange( nStart, nEnd );
735 sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException)
737 SolarMutexGuard aGuard;
739 sal_Int32 i, nPos, nParas;
740 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
742 if( (nPos=mpImpl->GetParagraph(i).getSelectionStart()) != -1 )
743 return nPos;
746 return nPos;
749 sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException)
751 SolarMutexGuard aGuard;
753 sal_Int32 i, nPos, nParas;
754 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
756 if( (nPos=mpImpl->GetParagraph(i).getSelectionEnd()) != -1 )
757 return nPos;
760 return nPos;
763 sal_Bool SAL_CALL AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
765 SolarMutexGuard aGuard;
767 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
768 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
770 return mpImpl->SetSelection( aStartIndex.nPara, aStartIndex.nIndex,
771 aEndIndex.nPara, aEndIndex.nIndex );
774 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getText() throw (uno::RuntimeException)
776 SolarMutexGuard aGuard;
778 sal_Int32 i, nParas;
779 ::rtl::OUString aRes;
780 for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
781 aRes += mpImpl->GetParagraph(i).getText();
783 return aRes;
786 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
788 SolarMutexGuard aGuard;
790 if( nStartIndex > nEndIndex )
791 ::std::swap(nStartIndex, nEndIndex);
793 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
794 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
796 // #102170# Special case: start and end paragraph are identical
797 if( aStartIndex.nPara == aEndIndex.nPara )
799 return mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex );
801 else
803 sal_Int32 i( aStartIndex.nPara );
804 ::rtl::OUString aRes( mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex,
805 mpImpl->GetParagraph(i).getCharacterCount()-1) );
806 ++i;
808 // paragraphs inbetween are fully included
809 for( ; i<aEndIndex.nPara; ++i )
810 aRes += mpImpl->GetParagraph(i).getText();
812 if( i<=aEndIndex.nPara )
813 aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex );
815 return aRes;
819 ::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)
821 SolarMutexGuard aGuard;
823 EPosition aPos( mpImpl->Range2Internal(nIndex) );
825 ::com::sun::star::accessibility::TextSegment aResult;
827 if( AccessibleTextType::PARAGRAPH == aTextType )
829 // #106393# Special casing one behind last paragraph is
830 // not necessary, since then, we return the content and
831 // boundary of that last paragraph. Range2Internal is
832 // tolerant against that, and returns the last paragraph
833 // in aPos.nPara.
835 // retrieve full text of the paragraph
836 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
838 // #112814# Adapt the start index with the paragraph offset
839 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
840 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
842 else
844 // No special handling required, forward to wrapped class
845 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType );
847 // #112814# Adapt the start index with the paragraph offset
848 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
851 return aResult;
854 ::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)
856 SolarMutexGuard aGuard;
858 EPosition aPos( mpImpl->Range2Internal(nIndex) );
860 ::com::sun::star::accessibility::TextSegment aResult;
862 if( AccessibleTextType::PARAGRAPH == aTextType )
864 if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() )
866 // #103589# Special casing one behind the last paragraph
867 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
869 // #112814# Adapt the start index with the paragraph offset
870 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
872 else if( aPos.nPara > 0 )
874 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText();
876 // #112814# Adapt the start index with the paragraph offset
877 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) );
880 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
882 else
884 // No special handling required, forward to wrapped class
885 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType );
887 // #112814# Adapt the start index with the paragraph offset
888 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
891 return aResult;
894 ::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)
896 SolarMutexGuard aGuard;
898 EPosition aPos( mpImpl->Range2Internal(nIndex) );
900 ::com::sun::star::accessibility::TextSegment aResult;
902 if( AccessibleTextType::PARAGRAPH == aTextType )
904 // Special casing one behind the last paragraph is not
905 // necessary, this case is invalid here for
906 // getTextBehindIndex
907 if( aPos.nPara + 1 < mpImpl->GetParagraphCount() )
909 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText();
911 // #112814# Adapt the start index with the paragraph offset
912 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) );
913 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
916 else
918 // No special handling required, forward to wrapped class
919 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType );
921 // #112814# Adapt the start index with the paragraph offset
922 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
925 return aResult;
928 sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
930 SolarMutexGuard aGuard;
932 if( nStartIndex > nEndIndex )
933 ::std::swap(nStartIndex, nEndIndex);
935 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
936 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
938 return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex,
939 aEndIndex.nPara, aEndIndex.nIndex );
942 // XAccessibleTextAttributes
943 uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (uno::RuntimeException)
945 // get the intersection of the default attributes of all paragraphs
947 SolarMutexGuard aGuard;
949 PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) );
951 const sal_Int32 nParaCount = mpImpl->GetParagraphCount();
952 for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara )
954 uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes );
955 PropertyValueVector aIntersectionVec;
957 PropertyValueVector::const_iterator aEnd = aDefAttrVec.end();
958 for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr )
960 const beans::PropertyValue* pItr = aSeq.getConstArray();
961 const beans::PropertyValue* pEnd = pItr + aSeq.getLength();
962 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) );
963 if ( pFind != pEnd )
965 aIntersectionVec.push_back( *pFind );
969 aDefAttrVec.swap( aIntersectionVec );
971 if ( aDefAttrVec.empty() )
973 break;
977 return aDefAttrVec.getAsConstList();
980 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
982 // get those default attributes of the paragraph, which are not part
983 // of the intersection of all paragraphs and add them to the run attributes
985 SolarMutexGuard aGuard;
987 EPosition aPos( mpImpl->Index2Internal( nIndex ) );
988 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
989 uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes );
990 uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes );
991 uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes );
992 PropertyValueVector aDiffVec;
994 const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray();
995 const sal_Int32 nLength = aDefAttrSeq.getLength();
996 for ( sal_Int32 i = 0; i < nLength; ++i )
998 const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray();
999 const beans::PropertyValue* pEnd = pItr + aIntersectionSeq.getLength();
1000 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) );
1001 if ( pFind == pEnd && pDefAttr[i].Handle != 0)
1003 aDiffVec.push_back( pDefAttr[i] );
1007 return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() );
1010 Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const
1012 return mpImpl->GetParagraphBoundingBox();
1015 } // end of namespace accessibility
1017 //------------------------------------------------------------------------
1019 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */