1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 //------------------------------------------------------------------------
25 //------------------------------------------------------------------------
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
;
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 >
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 //------------------------------------------------------------------------
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
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
);
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
);
140 uno::Reference
< XAccessible
> GetEventSource() const
142 DBG_CHKTHIS( AccessibleStaticTextBase_Impl
, NULL
);
147 void SetOffset( const Point
& );
148 Point
GetOffset() const
150 DBG_CHKTHIS( AccessibleStaticTextBase_Impl
, NULL
);
152 ::osl::MutexGuard
aGuard( maMutex
); Point
aPoint( maOffset
);
156 void UpdateChildren();
160 void CheckInvariants() const;
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
,
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;
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
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)
217 //------------------------------------------------------------------------
219 // AccessibleStaticTextBase_Impl implementation
221 //------------------------------------------------------------------------
223 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
225 mpTextParagraph( new AccessibleEditableTextPara(NULL
) ),
226 mxParagraph( mpTextParagraph
),
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
);
263 if( mpTextParagraph
)
264 mpTextParagraph
->SetEEOffset( rPoint
);
266 // in all cases, check visibility afterwards.
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();
288 mpTextParagraph
= NULL
;
292 void AccessibleStaticTextBase_Impl::CheckInvariants() const
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
)
319 return mpTextParagraph
->GetTextForwarder().GetParagraphCount();
322 sal_Int32
AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex
) const
324 // XXX checks for overflow and returns maximum if so
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
;
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
,
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);
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
);
362 throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
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
)
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
)
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",
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
)
409 SvxEditViewForwarder
& rCacheVF
= mpTextParagraph
->GetEditViewForwarder( sal_True
);
410 return rCacheVF
.SetSelection( MakeSelection(nStartPara
, nStartIndex
, nEndPara
, nEndIndex
) );
412 catch( const uno::RuntimeException
& )
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
)
428 SvxEditViewForwarder
& rCacheVF
= mpTextParagraph
->GetEditViewForwarder( sal_True
);
429 mpTextParagraph
->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
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
442 catch( const uno::RuntimeException
& )
448 Rectangle
AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
451 if( mpTextParagraph
)
453 awt::Rectangle aAwtRect
= mpTextParagraph
->getBounds();
454 aRect
= Rectangle( Point( aAwtRect
.X
, aAwtRect
.Y
), Size( aAwtRect
.Width
, aAwtRect
.Height
) );
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
))
486 mpImpl
->CheckInvariants();
488 const SvxEditSource
& aEditSource
= mpImpl
->GetEditSource();
490 mpImpl
->CheckInvariants();
494 return mpImpl
->GetEditSource();
498 SAL_WNODEPRECATED_DECLARATIONS_PUSH
499 void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr
< SvxEditSource
> pEditSource
) SAL_THROW((::com::sun::star::uno::RuntimeException
))
502 // precondition: solar mutex locked
503 DBG_TESTSOLARMUTEX();
505 mpImpl
->CheckInvariants();
507 mpImpl
->SetEditSource( pEditSource
);
509 mpImpl
->CheckInvariants();
511 mpImpl
->SetEditSource( pEditSource
);
514 SAL_WNODEPRECATED_DECLARATIONS_POP
516 void AccessibleStaticTextBase::SetEventSource( const uno::Reference
< XAccessible
>& rInterface
)
519 mpImpl
->CheckInvariants();
522 mpImpl
->SetEventSource( rInterface
);
525 mpImpl
->CheckInvariants();
529 uno::Reference
< XAccessible
> AccessibleStaticTextBase::GetEventSource() const
532 mpImpl
->CheckInvariants();
534 uno::Reference
< XAccessible
> xRet( mpImpl
->GetEventSource() );
536 mpImpl
->CheckInvariants();
540 return mpImpl
->GetEventSource();
544 void AccessibleStaticTextBase::SetOffset( const Point
& rPoint
)
547 // precondition: solar mutex locked
548 DBG_TESTSOLARMUTEX();
550 mpImpl
->CheckInvariants();
552 mpImpl
->SetOffset( rPoint
);
554 mpImpl
->CheckInvariants();
556 mpImpl
->SetOffset( rPoint
);
560 Point
AccessibleStaticTextBase::GetOffset() const
563 mpImpl
->CheckInvariants();
565 Point
aPoint( mpImpl
->GetOffset() );
567 mpImpl
->CheckInvariants();
571 return mpImpl
->GetOffset();
575 void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException
))
578 // precondition: solar mutex locked
579 DBG_TESTSOLARMUTEX();
581 mpImpl
->CheckInvariants();
583 mpImpl
->UpdateChildren();
585 mpImpl
->CheckInvariants();
587 mpImpl
->UpdateChildren();
591 void AccessibleStaticTextBase::Dispose()
594 mpImpl
->CheckInvariants();
600 mpImpl
->CheckInvariants();
604 // XAccessibleContext
605 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException
)
607 // no children at all
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
>();
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 )
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
;
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();
690 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getIndexAtPoint( const awt::Point
& rPoint
) throw (uno::RuntimeException
)
692 SolarMutexGuard aGuard
;
694 const sal_Int32
nParas( mpImpl
->GetParagraphCount() );
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
)) );
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 )
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 )
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 )
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
;
777 for( i
=0, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
778 aRes
+= mpImpl
->GetParagraph(i
).getText();
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
);
800 sal_Int32
i( aStartIndex
.nPara
);
801 OUString
aRes( mpImpl
->GetParagraph(i
).getTextRange( aStartIndex
.nIndex
,
802 mpImpl
->GetParagraph(i
).getCharacterCount()-1) );
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
);
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
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();
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
);
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();
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
);
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();
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
);
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
) ) );
962 aIntersectionVec
.push_back( *pFind
);
966 aDefAttrVec
.swap( aIntersectionVec
);
968 if ( aDefAttrVec
.empty() )
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: */