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 //------------------------------------------------------------------------
34 //------------------------------------------------------------------------
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
;
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 >
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 //------------------------------------------------------------------------
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
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
);
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
);
149 uno::Reference
< XAccessible
> GetEventSource() const
151 DBG_CHKTHIS( AccessibleStaticTextBase_Impl
, NULL
);
156 void SetOffset( const Point
& );
157 Point
GetOffset() const
159 DBG_CHKTHIS( AccessibleStaticTextBase_Impl
, NULL
);
161 ::osl::MutexGuard
aGuard( maMutex
); Point
aPoint( maOffset
);
165 void UpdateChildren();
169 void CheckInvariants() const;
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
,
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;
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
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)
226 //------------------------------------------------------------------------
228 // AccessibleStaticTextBase_Impl implementation
230 //------------------------------------------------------------------------
232 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
234 mpTextParagraph( new AccessibleEditableTextPara(NULL
) ),
235 mxParagraph( mpTextParagraph
),
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
);
272 if( mpTextParagraph
)
273 mpTextParagraph
->SetEEOffset( rPoint
);
275 // in all cases, check visibility afterwards.
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();
297 mpTextParagraph
= NULL
;
301 void AccessibleStaticTextBase_Impl::CheckInvariants() const
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
)
329 return mpTextParagraph
->GetTextForwarder().GetParagraphCount();
332 sal_Int32
AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex
) const
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
,
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);
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
);
365 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
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
)
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
)
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")),
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
)
412 SvxEditViewForwarder
& rCacheVF
= mpTextParagraph
->GetEditViewForwarder( sal_True
);
413 return rCacheVF
.SetSelection( MakeSelection(nStartPara
, nStartIndex
, nEndPara
, nEndIndex
) );
415 catch( const uno::RuntimeException
& )
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
)
431 SvxEditViewForwarder
& rCacheVF
= mpTextParagraph
->GetEditViewForwarder( sal_True
);
432 mpTextParagraph
->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
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
445 catch( const uno::RuntimeException
& )
451 Rectangle
AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
454 if( mpTextParagraph
)
456 awt::Rectangle aAwtRect
= mpTextParagraph
->getBounds();
457 aRect
= Rectangle( Point( aAwtRect
.X
, aAwtRect
.Y
), Size( aAwtRect
.Width
, aAwtRect
.Height
) );
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
))
489 mpImpl
->CheckInvariants();
491 const SvxEditSource
& aEditSource
= mpImpl
->GetEditSource();
493 mpImpl
->CheckInvariants();
497 return mpImpl
->GetEditSource();
501 SAL_WNODEPRECATED_DECLARATIONS_PUSH
502 void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr
< SvxEditSource
> pEditSource
) SAL_THROW((::com::sun::star::uno::RuntimeException
))
505 // precondition: solar mutex locked
506 DBG_TESTSOLARMUTEX();
508 mpImpl
->CheckInvariants();
510 mpImpl
->SetEditSource( pEditSource
);
512 mpImpl
->CheckInvariants();
514 mpImpl
->SetEditSource( pEditSource
);
517 SAL_WNODEPRECATED_DECLARATIONS_POP
519 void AccessibleStaticTextBase::SetEventSource( const uno::Reference
< XAccessible
>& rInterface
)
522 mpImpl
->CheckInvariants();
525 mpImpl
->SetEventSource( rInterface
);
528 mpImpl
->CheckInvariants();
532 uno::Reference
< XAccessible
> AccessibleStaticTextBase::GetEventSource() const
535 mpImpl
->CheckInvariants();
537 uno::Reference
< XAccessible
> xRet( mpImpl
->GetEventSource() );
539 mpImpl
->CheckInvariants();
543 return mpImpl
->GetEventSource();
547 void AccessibleStaticTextBase::SetOffset( const Point
& rPoint
)
550 // precondition: solar mutex locked
551 DBG_TESTSOLARMUTEX();
553 mpImpl
->CheckInvariants();
555 mpImpl
->SetOffset( rPoint
);
557 mpImpl
->CheckInvariants();
559 mpImpl
->SetOffset( rPoint
);
563 Point
AccessibleStaticTextBase::GetOffset() const
566 mpImpl
->CheckInvariants();
568 Point
aPoint( mpImpl
->GetOffset() );
570 mpImpl
->CheckInvariants();
574 return mpImpl
->GetOffset();
578 void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException
))
581 // precondition: solar mutex locked
582 DBG_TESTSOLARMUTEX();
584 mpImpl
->CheckInvariants();
586 mpImpl
->UpdateChildren();
588 mpImpl
->CheckInvariants();
590 mpImpl
->UpdateChildren();
594 void AccessibleStaticTextBase::Dispose()
597 mpImpl
->CheckInvariants();
603 mpImpl
->CheckInvariants();
607 // XAccessibleContext
608 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException
)
610 // no children at all
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
>();
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 )
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
;
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();
693 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getIndexAtPoint( const awt::Point
& rPoint
) throw (uno::RuntimeException
)
695 SolarMutexGuard aGuard
;
697 const sal_Int32
nParas( mpImpl
->GetParagraphCount() );
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
)) );
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 )
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 )
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
;
779 ::rtl::OUString aRes
;
780 for( i
=0, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
781 aRes
+= mpImpl
->GetParagraph(i
).getText();
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
);
803 sal_Int32
i( aStartIndex
.nPara
);
804 ::rtl::OUString
aRes( mpImpl
->GetParagraph(i
).getTextRange( aStartIndex
.nIndex
,
805 mpImpl
->GetParagraph(i
).getCharacterCount()-1) );
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
);
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
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();
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
);
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();
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
);
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();
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
);
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
) ) );
965 aIntersectionVec
.push_back( *pFind
);
969 aDefAttrVec
.swap( aIntersectionVec
);
971 if ( aDefAttrVec
.empty() )
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: */