Bump version to 4.1-6
[LibreOffice.git] / editeng / source / accessibility / AccessibleStaticTextBase.cxx
blobc7a3c9b2f346383805ee6a620e31278c0be2be25
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 //------------------------------------------------------------------------
23 // Global header
25 //------------------------------------------------------------------------
27 #include <limits.h>
28 #include <vector>
29 #include <algorithm>
30 #include <boost/ref.hpp>
31 #include <osl/mutex.hxx>
32 #include <vcl/window.hxx>
33 #include <vcl/svapp.hxx>
34 #include <comphelper/sequenceasvector.hxx>
35 #include <com/sun/star/uno/Any.hxx>
36 #include <com/sun/star/uno/Reference.hxx>
37 #include <com/sun/star/awt/Point.hpp>
38 #include <com/sun/star/awt/Rectangle.hpp>
39 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
41 //------------------------------------------------------------------------
43 // Project-local header
45 //------------------------------------------------------------------------
47 #include <editeng/editdata.hxx>
48 #include <editeng/unopracc.hxx>
49 #include "editeng/unoedprx.hxx"
50 #include <editeng/AccessibleStaticTextBase.hxx>
51 #include "editeng/AccessibleEditableTextPara.hxx"
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::accessibility;
57 /* TODO:
58 =====
60 - separate adapter functionality from AccessibleStaticText class
62 - refactor common loops into templates, using mem_fun
66 namespace accessibility
68 typedef ::comphelper::SequenceAsVector< beans::PropertyValue > PropertyValueVector;
70 class PropertyValueEqualFunctor : public ::std::binary_function< beans::PropertyValue, beans::PropertyValue, bool >
72 public:
73 PropertyValueEqualFunctor()
75 bool operator() ( const beans::PropertyValue& lhs, const beans::PropertyValue& rhs ) const
77 return ( lhs.Name == rhs.Name && lhs.Value == rhs.Value );
81 //------------------------------------------------------------------------
83 // Static Helper
85 //------------------------------------------------------------------------
86 ESelection MakeSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
87 sal_Int32 nEndPara, sal_Int32 nEndIndex )
89 DBG_ASSERT(nStartPara >= 0 && nStartPara <= SAL_MAX_INT32 &&
90 nStartIndex >= 0 && nStartIndex <= USHRT_MAX &&
91 nEndPara >= 0 && nEndPara <= SAL_MAX_INT32 &&
92 nEndIndex >= 0 && nEndIndex <= USHRT_MAX ,
93 "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow");
95 return ESelection( nStartPara, static_cast< sal_uInt16 >(nStartIndex),
96 nEndPara, static_cast< sal_uInt16 >(nEndIndex) );
99 //------------------------------------------------------------------------
101 // AccessibleStaticTextBase_Impl declaration
103 //------------------------------------------------------------------------
105 DBG_NAME( AccessibleStaticTextBase_Impl );
107 /** AccessibleStaticTextBase_Impl
109 This class implements the AccessibleStaticTextBase
110 functionality, mainly by forwarding the calls to an aggregated
111 AccessibleEditableTextPara. As this is a therefore non-trivial
112 adapter, factoring out the common functionality from
113 AccessibleEditableTextPara might be a profitable future task.
115 class AccessibleStaticTextBase_Impl
118 public:
120 // receive pointer to our frontend class and view window
121 AccessibleStaticTextBase_Impl();
122 ~AccessibleStaticTextBase_Impl();
124 SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException))
126 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
128 return maEditSource;
130 SAL_WNODEPRECATED_DECLARATIONS_PUSH
131 void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException));
132 SAL_WNODEPRECATED_DECLARATIONS_POP
134 void SetEventSource( const uno::Reference< XAccessible >& rInterface )
136 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
138 mxThis = rInterface;
140 uno::Reference< XAccessible > GetEventSource() const
142 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
144 return mxThis;
147 void SetOffset( const Point& );
148 Point GetOffset() const
150 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
152 ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset );
153 return aPoint;
156 void UpdateChildren();
157 void Dispose();
159 #ifdef DBG_UTIL
160 void CheckInvariants() const;
161 #endif
163 AccessibleEditableTextPara& GetParagraph( sal_Int32 nPara ) const;
164 sal_Int32 GetParagraphCount() const;
166 EPosition Index2Internal( sal_Int32 nFlatIndex ) const
168 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
170 return ImpCalcInternal( nFlatIndex, false );
173 EPosition Range2Internal( sal_Int32 nFlatIndex ) const
175 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
177 return ImpCalcInternal( nFlatIndex, true );
180 sal_Int32 Internal2Index( EPosition nEEIndex ) const;
182 void CorrectTextSegment( TextSegment& aTextSegment,
183 int nPara ) const;
185 sal_Bool SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
186 sal_Int32 nEndPara, sal_Int32 nEndIndex );
187 sal_Bool CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
188 sal_Int32 nEndPara, sal_Int32 nEndIndex );
190 Rectangle GetParagraphBoundingBox() const;
192 private:
194 EPosition ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const;
196 // our frontend class (the one implementing the actual
197 // interface). That's not necessarily the one containing the impl
198 // pointer
199 uno::Reference< XAccessible > mxThis;
201 // implements our functionality, we're just an adapter (guarded by solar mutex)
202 mutable AccessibleEditableTextPara* mpTextParagraph;
204 uno::Reference< XAccessible > mxParagraph;
206 // a wrapper for the text forwarders (guarded by solar mutex)
207 mutable SvxEditSourceAdapter maEditSource;
209 // guard for maOffset
210 mutable ::osl::Mutex maMutex;
212 /// our current offset to the containing shape/cell (guarded by maMutex)
213 Point maOffset;
217 //------------------------------------------------------------------------
219 // AccessibleStaticTextBase_Impl implementation
221 //------------------------------------------------------------------------
223 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
224 mxThis( NULL ),
225 mpTextParagraph( new AccessibleEditableTextPara(NULL) ),
226 mxParagraph( mpTextParagraph ),
227 maEditSource(),
228 maMutex(),
229 maOffset(0,0)
231 DBG_CTOR( AccessibleStaticTextBase_Impl, NULL );
233 // TODO: this is still somewhat of a hack, all the more since
234 // now the maTextParagraph has an empty parent reference set
237 AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl()
239 DBG_DTOR( AccessibleStaticTextBase_Impl, NULL );
242 SAL_WNODEPRECATED_DECLARATIONS_PUSH
243 void AccessibleStaticTextBase_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
245 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
247 maEditSource.SetEditSource( pEditSource );
248 if( mpTextParagraph )
249 mpTextParagraph->SetEditSource( &maEditSource );
251 SAL_WNODEPRECATED_DECLARATIONS_POP
253 void AccessibleStaticTextBase_Impl::SetOffset( const Point& rPoint )
255 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
257 // guard against non-atomic access to maOffset data structure
259 ::osl::MutexGuard aGuard( maMutex );
260 maOffset = rPoint;
263 if( mpTextParagraph )
264 mpTextParagraph->SetEEOffset( rPoint );
266 // in all cases, check visibility afterwards.
267 UpdateChildren();
270 void AccessibleStaticTextBase_Impl::UpdateChildren()
272 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
274 // currently no children
277 void AccessibleStaticTextBase_Impl::Dispose()
279 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
281 // we're the owner of the paragraph, so destroy it, too
282 if( mpTextParagraph )
283 mpTextParagraph->Dispose();
285 // drop references
286 mxParagraph = NULL;
287 mxThis = NULL;
288 mpTextParagraph = NULL;
291 #ifdef DBG_UTIL
292 void AccessibleStaticTextBase_Impl::CheckInvariants() const
294 // TODO
296 #endif
298 AccessibleEditableTextPara& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara ) const
300 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
302 if( !mpTextParagraph )
303 throw lang::DisposedException ("object has been already disposed", mxThis );
305 // TODO: Have a different method on AccessibleEditableTextPara
306 // that does not care about state changes
307 mpTextParagraph->SetParagraphIndex( nPara );
309 return *mpTextParagraph;
312 sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphCount() const
314 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
316 if( !mpTextParagraph )
317 return 0;
318 else
319 return mpTextParagraph->GetTextForwarder().GetParagraphCount();
322 sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const
324 // XXX checks for overflow and returns maximum if so
325 sal_Int32 aRes(0);
326 for(sal_Int32 i=0; i<nEEIndex.nPara; ++i)
328 sal_Int32 nCount = GetParagraph(i).getCharacterCount();
329 if (SAL_MAX_INT32 - aRes > nCount)
330 return SAL_MAX_INT32;
331 aRes += nCount;
334 if (SAL_MAX_INT32 - aRes > nEEIndex.nIndex)
335 return SAL_MAX_INT32;
336 return aRes + nEEIndex.nIndex;
339 void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment& aTextSegment,
340 int nPara ) const
342 // Keep 'invalid' values at the TextSegment
343 if( aTextSegment.SegmentStart != -1 &&
344 aTextSegment.SegmentEnd != -1 )
346 // #112814# Correct TextSegment by paragraph offset
347 sal_Int32 nOffset(0);
348 int i;
349 for(i=0; i<nPara; ++i)
350 nOffset += GetParagraph(i).getCharacterCount();
352 aTextSegment.SegmentStart += nOffset;
353 aTextSegment.SegmentEnd += nOffset;
357 EPosition AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const
359 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
361 if( nFlatIndex < 0 )
362 throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
363 mxThis);
364 // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually
366 sal_Int32 nCurrPara, nCurrIndex, nParas, nCurrCount;
367 for( nCurrPara=0, nParas=GetParagraphCount(), nCurrCount=0, nCurrIndex=0; nCurrPara<nParas; ++nCurrPara )
369 nCurrCount = GetParagraph( nCurrPara ).getCharacterCount();
370 nCurrIndex += nCurrCount;
372 if( nCurrIndex > nFlatIndex )
374 // check overflow
375 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= SAL_MAX_INT32 &&
376 nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
377 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
379 return EPosition( nCurrPara, static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
383 // #102170# Allow one-past the end for ranges
384 if( bExclusive && nCurrIndex == nFlatIndex )
386 // check overflow
387 DBG_ASSERT(nCurrPara > 0 && nCurrPara <= SAL_MAX_INT32 &&
388 nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
389 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
391 return EPosition( nCurrPara-1, static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
394 // not found? Out of bounds
395 throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
396 mxThis);
399 sal_Bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
400 sal_Int32 nEndPara, sal_Int32 nEndIndex )
402 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
404 if( !mpTextParagraph )
405 return sal_False;
409 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
410 return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
412 catch( const uno::RuntimeException& )
414 return sal_False;
418 sal_Bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
419 sal_Int32 nEndPara, sal_Int32 nEndIndex )
421 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
423 if( !mpTextParagraph )
424 return sal_False;
428 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
429 mpTextParagraph->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
430 sal_Bool aRetVal;
432 // save current selection
433 ESelection aOldSelection;
435 rCacheVF.GetSelection( aOldSelection );
436 rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
437 aRetVal = rCacheVF.Copy();
438 rCacheVF.SetSelection( aOldSelection ); // restore
440 return aRetVal;
442 catch( const uno::RuntimeException& )
444 return sal_False;
448 Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
450 Rectangle aRect;
451 if( mpTextParagraph )
453 awt::Rectangle aAwtRect = mpTextParagraph->getBounds();
454 aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) );
456 else
458 aRect.SetEmpty();
460 return aRect;
463 //------------------------------------------------------------------------
465 // AccessibleStaticTextBase implementation
467 //------------------------------------------------------------------------
469 SAL_WNODEPRECATED_DECLARATIONS_PUSH
470 AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::auto_ptr< SvxEditSource > pEditSource ) :
471 mpImpl( new AccessibleStaticTextBase_Impl() )
473 SolarMutexGuard aGuard;
475 SetEditSource( pEditSource );
477 SAL_WNODEPRECATED_DECLARATIONS_POP
479 AccessibleStaticTextBase::~AccessibleStaticTextBase()
483 const SvxEditSource& AccessibleStaticTextBase::GetEditSource() const SAL_THROW((::com::sun::star::uno::RuntimeException))
485 #ifdef DBG_UTIL
486 mpImpl->CheckInvariants();
488 const SvxEditSource& aEditSource = mpImpl->GetEditSource();
490 mpImpl->CheckInvariants();
492 return aEditSource;
493 #else
494 return mpImpl->GetEditSource();
495 #endif
498 SAL_WNODEPRECATED_DECLARATIONS_PUSH
499 void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((::com::sun::star::uno::RuntimeException))
501 #ifdef DBG_UTIL
502 // precondition: solar mutex locked
503 DBG_TESTSOLARMUTEX();
505 mpImpl->CheckInvariants();
507 mpImpl->SetEditSource( pEditSource );
509 mpImpl->CheckInvariants();
510 #else
511 mpImpl->SetEditSource( pEditSource );
512 #endif
514 SAL_WNODEPRECATED_DECLARATIONS_POP
516 void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface )
518 #ifdef DBG_UTIL
519 mpImpl->CheckInvariants();
520 #endif
522 mpImpl->SetEventSource( rInterface );
524 #ifdef DBG_UTIL
525 mpImpl->CheckInvariants();
526 #endif
529 uno::Reference< XAccessible > AccessibleStaticTextBase::GetEventSource() const
531 #ifdef DBG_UTIL
532 mpImpl->CheckInvariants();
534 uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
536 mpImpl->CheckInvariants();
538 return xRet;
539 #else
540 return mpImpl->GetEventSource();
541 #endif
544 void AccessibleStaticTextBase::SetOffset( const Point& rPoint )
546 #ifdef DBG_UTIL
547 // precondition: solar mutex locked
548 DBG_TESTSOLARMUTEX();
550 mpImpl->CheckInvariants();
552 mpImpl->SetOffset( rPoint );
554 mpImpl->CheckInvariants();
555 #else
556 mpImpl->SetOffset( rPoint );
557 #endif
560 Point AccessibleStaticTextBase::GetOffset() const
562 #ifdef DBG_UTIL
563 mpImpl->CheckInvariants();
565 Point aPoint( mpImpl->GetOffset() );
567 mpImpl->CheckInvariants();
569 return aPoint;
570 #else
571 return mpImpl->GetOffset();
572 #endif
575 void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
577 #ifdef DBG_UTIL
578 // precondition: solar mutex locked
579 DBG_TESTSOLARMUTEX();
581 mpImpl->CheckInvariants();
583 mpImpl->UpdateChildren();
585 mpImpl->CheckInvariants();
586 #else
587 mpImpl->UpdateChildren();
588 #endif
591 void AccessibleStaticTextBase::Dispose()
593 #ifdef DBG_UTIL
594 mpImpl->CheckInvariants();
595 #endif
597 mpImpl->Dispose();
599 #ifdef DBG_UTIL
600 mpImpl->CheckInvariants();
601 #endif
604 // XAccessibleContext
605 sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException)
607 // no children at all
608 return 0;
611 uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleChild( sal_Int32 /*i*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
613 // no children at all
614 return uno::Reference< XAccessible >();
617 uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) throw (uno::RuntimeException)
619 // no children at all
620 return uno::Reference< XAccessible >();
623 // XAccessibleText
624 sal_Int32 SAL_CALL AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException)
626 SolarMutexGuard aGuard;
628 sal_Int32 i, nPos, nParas;
629 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
631 if( (nPos=mpImpl->GetParagraph(i).getCaretPosition()) != -1 )
632 return nPos;
635 return nPos;
638 sal_Bool SAL_CALL AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
640 return setSelection(nIndex, nIndex);
643 sal_Unicode SAL_CALL AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
645 SolarMutexGuard aGuard;
647 EPosition aPos( mpImpl->Index2Internal(nIndex) );
649 return mpImpl->GetParagraph( aPos.nPara ).getCharacter( aPos.nIndex );
652 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getCharacterAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< OUString >& aRequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
654 SolarMutexGuard aGuard;
656 EPosition aPos( mpImpl->Index2Internal(nIndex) );
658 return mpImpl->GetParagraph( aPos.nPara ).getCharacterAttributes( aPos.nIndex, aRequestedAttributes );
661 awt::Rectangle SAL_CALL AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
663 SolarMutexGuard aGuard;
665 // #108900# Allow ranges for nIndex, as one-past-the-end
666 // values are now legal, too.
667 EPosition aPos( mpImpl->Range2Internal(nIndex) );
669 // #i70916# Text in spread sheet cells return the wrong extents
670 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
671 awt::Rectangle aParaBounds( rPara.getBounds() );
672 awt::Rectangle aBounds( rPara.getCharacterBounds( aPos.nIndex ) );
673 aBounds.X += aParaBounds.X;
674 aBounds.Y += aParaBounds.Y;
676 return aBounds;
679 sal_Int32 SAL_CALL AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException)
681 SolarMutexGuard aGuard;
683 sal_Int32 i, nCount, nParas;
684 for( i=0, nCount=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
685 nCount += mpImpl->GetParagraph(i).getCharacterCount();
687 return nCount;
690 sal_Int32 SAL_CALL AccessibleStaticTextBase::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException)
692 SolarMutexGuard aGuard;
694 const sal_Int32 nParas( mpImpl->GetParagraphCount() );
695 sal_Int32 nIndex;
696 int i;
697 for( i=0; i<nParas; ++i )
699 // TODO: maybe exploit the fact that paragraphs are
700 // ordered vertically for early exit
702 // #i70916# Text in spread sheet cells return the wrong extents
703 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( i );
704 awt::Rectangle aParaBounds( rPara.getBounds() );
705 awt::Point aPoint( rPoint );
706 aPoint.X -= aParaBounds.X;
707 aPoint.Y -= aParaBounds.Y;
709 // #112814# Use correct index offset
710 if ( ( nIndex = rPara.getIndexAtPoint( aPoint ) ) != -1 )
711 return mpImpl->Internal2Index( EPosition(sal::static_int_cast<sal_uInt16>(i),
712 sal::static_int_cast<sal_uInt16>(nIndex)) );
715 return -1;
718 OUString SAL_CALL AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException)
720 SolarMutexGuard aGuard;
722 sal_Int32 nStart( getSelectionStart() );
723 sal_Int32 nEnd( getSelectionEnd() );
725 // #104481# Return the empty string for 'no selection'
726 if( nStart < 0 || nEnd < 0 )
727 return OUString();
729 return getTextRange( nStart, nEnd );
732 sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException)
734 SolarMutexGuard aGuard;
736 sal_Int32 i, nPos, nParas;
737 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
739 if( (nPos=mpImpl->GetParagraph(i).getSelectionStart()) != -1 )
740 return nPos;
743 return nPos;
746 sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException)
748 SolarMutexGuard aGuard;
750 sal_Int32 i, nPos, nParas;
751 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
753 if( (nPos=mpImpl->GetParagraph(i).getSelectionEnd()) != -1 )
754 return nPos;
757 return nPos;
760 sal_Bool SAL_CALL AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
762 SolarMutexGuard aGuard;
764 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
765 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
767 return mpImpl->SetSelection( aStartIndex.nPara, aStartIndex.nIndex,
768 aEndIndex.nPara, aEndIndex.nIndex );
771 OUString SAL_CALL AccessibleStaticTextBase::getText() throw (uno::RuntimeException)
773 SolarMutexGuard aGuard;
775 sal_Int32 i, nParas;
776 OUString aRes;
777 for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
778 aRes += mpImpl->GetParagraph(i).getText();
780 return aRes;
783 OUString SAL_CALL AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
785 SolarMutexGuard aGuard;
787 if( nStartIndex > nEndIndex )
788 ::std::swap(nStartIndex, nEndIndex);
790 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
791 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
793 // #102170# Special case: start and end paragraph are identical
794 if( aStartIndex.nPara == aEndIndex.nPara )
796 return mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex );
798 else
800 sal_Int32 i( aStartIndex.nPara );
801 OUString aRes( mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex,
802 mpImpl->GetParagraph(i).getCharacterCount()-1) );
803 ++i;
805 // paragraphs inbetween are fully included
806 for( ; i<aEndIndex.nPara; ++i )
807 aRes += mpImpl->GetParagraph(i).getText();
809 if( i<=aEndIndex.nPara )
810 aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex );
812 return aRes;
816 ::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)
818 SolarMutexGuard aGuard;
820 EPosition aPos( mpImpl->Range2Internal(nIndex) );
822 ::com::sun::star::accessibility::TextSegment aResult;
824 if( AccessibleTextType::PARAGRAPH == aTextType )
826 // #106393# Special casing one behind last paragraph is
827 // not necessary, since then, we return the content and
828 // boundary of that last paragraph. Range2Internal is
829 // tolerant against that, and returns the last paragraph
830 // in aPos.nPara.
832 // retrieve full text of the paragraph
833 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
835 // #112814# Adapt the start index with the paragraph offset
836 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
837 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
839 else
841 // No special handling required, forward to wrapped class
842 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType );
844 // #112814# Adapt the start index with the paragraph offset
845 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
848 return aResult;
851 ::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)
853 SolarMutexGuard aGuard;
855 EPosition aPos( mpImpl->Range2Internal(nIndex) );
857 ::com::sun::star::accessibility::TextSegment aResult;
859 if( AccessibleTextType::PARAGRAPH == aTextType )
861 if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() )
863 // #103589# Special casing one behind the last paragraph
864 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
866 // #112814# Adapt the start index with the paragraph offset
867 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
869 else if( aPos.nPara > 0 )
871 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText();
873 // #112814# Adapt the start index with the paragraph offset
874 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) );
877 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
879 else
881 // No special handling required, forward to wrapped class
882 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType );
884 // #112814# Adapt the start index with the paragraph offset
885 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
888 return aResult;
891 ::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)
893 SolarMutexGuard aGuard;
895 EPosition aPos( mpImpl->Range2Internal(nIndex) );
897 ::com::sun::star::accessibility::TextSegment aResult;
899 if( AccessibleTextType::PARAGRAPH == aTextType )
901 // Special casing one behind the last paragraph is not
902 // necessary, this case is invalid here for
903 // getTextBehindIndex
904 if( aPos.nPara + 1 < mpImpl->GetParagraphCount() )
906 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText();
908 // #112814# Adapt the start index with the paragraph offset
909 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) );
910 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
913 else
915 // No special handling required, forward to wrapped class
916 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType );
918 // #112814# Adapt the start index with the paragraph offset
919 mpImpl->CorrectTextSegment( aResult, aPos.nPara );
922 return aResult;
925 sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
927 SolarMutexGuard aGuard;
929 if( nStartIndex > nEndIndex )
930 ::std::swap(nStartIndex, nEndIndex);
932 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
933 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
935 return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex,
936 aEndIndex.nPara, aEndIndex.nIndex );
939 // XAccessibleTextAttributes
940 uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< OUString >& RequestedAttributes ) throw (uno::RuntimeException)
942 // get the intersection of the default attributes of all paragraphs
944 SolarMutexGuard aGuard;
946 PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) );
948 const sal_Int32 nParaCount = mpImpl->GetParagraphCount();
949 for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara )
951 uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes );
952 PropertyValueVector aIntersectionVec;
954 PropertyValueVector::const_iterator aEnd = aDefAttrVec.end();
955 for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr )
957 const beans::PropertyValue* pItr = aSeq.getConstArray();
958 const beans::PropertyValue* pEnd = pItr + aSeq.getLength();
959 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) );
960 if ( pFind != pEnd )
962 aIntersectionVec.push_back( *pFind );
966 aDefAttrVec.swap( aIntersectionVec );
968 if ( aDefAttrVec.empty() )
970 break;
974 return aDefAttrVec.getAsConstList();
977 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
979 // get those default attributes of the paragraph, which are not part
980 // of the intersection of all paragraphs and add them to the run attributes
982 SolarMutexGuard aGuard;
984 EPosition aPos( mpImpl->Index2Internal( nIndex ) );
985 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
986 uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes );
987 uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes );
988 uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes );
989 PropertyValueVector aDiffVec;
991 const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray();
992 const sal_Int32 nLength = aDefAttrSeq.getLength();
993 for ( sal_Int32 i = 0; i < nLength; ++i )
995 const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray();
996 const beans::PropertyValue* pEnd = pItr + aIntersectionSeq.getLength();
997 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) );
998 if ( pFind == pEnd && pDefAttr[i].Handle != 0)
1000 aDiffVec.push_back( pDefAttr[i] );
1004 return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() );
1007 Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const
1009 return mpImpl->GetParagraphBoundingBox();
1012 } // end of namespace accessibility
1014 //------------------------------------------------------------------------
1016 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */