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 .
31 #include <boost/ref.hpp>
32 #include <osl/mutex.hxx>
33 #include <vcl/window.hxx>
34 #include <vcl/svapp.hxx>
35 #include <comphelper/sequence.hxx>
36 #include <com/sun/star/uno/Any.hxx>
37 #include <com/sun/star/uno/Reference.hxx>
38 #include <com/sun/star/awt/Point.hpp>
39 #include <com/sun/star/awt/Rectangle.hpp>
40 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
44 // Project-local header
48 #include <editeng/editdata.hxx>
49 #include <editeng/unopracc.hxx>
50 #include "editeng/unoedprx.hxx"
51 #include <editeng/AccessibleStaticTextBase.hxx>
52 #include "editeng/AccessibleEditableTextPara.hxx"
55 using namespace ::com::sun::star
;
56 using namespace ::com::sun::star::accessibility
;
61 - separate adapter functionality from AccessibleStaticText class
63 - refactor common loops into templates, using mem_fun
67 namespace accessibility
69 typedef ::std::vector
< beans::PropertyValue
> PropertyValueVector
;
71 class PropertyValueEqualFunctor
: public ::std::binary_function
< beans::PropertyValue
, beans::PropertyValue
, bool >
74 PropertyValueEqualFunctor()
76 bool operator() ( const beans::PropertyValue
& lhs
, const beans::PropertyValue
& rhs
) const
78 return ( lhs
.Name
== rhs
.Name
&& lhs
.Value
== rhs
.Value
);
81 sal_Unicode
cNewLine(0x0a);
87 ESelection
MakeSelection( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
88 sal_Int32 nEndPara
, sal_Int32 nEndIndex
)
90 DBG_ASSERT(nStartPara
>= 0 && nStartPara
<= SAL_MAX_INT32
&&
91 nStartIndex
>= 0 && nStartIndex
<= USHRT_MAX
&&
92 nEndPara
>= 0 && nEndPara
<= SAL_MAX_INT32
&&
93 nEndIndex
>= 0 && nEndIndex
<= USHRT_MAX
,
94 "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow");
96 return ESelection(nStartPara
, nStartIndex
, nEndPara
, nEndIndex
);
101 // AccessibleStaticTextBase_Impl declaration
106 /** AccessibleStaticTextBase_Impl
108 This class implements the AccessibleStaticTextBase
109 functionality, mainly by forwarding the calls to an aggregated
110 AccessibleEditableTextPara. As this is a therefore non-trivial
111 adapter, factoring out the common functionality from
112 AccessibleEditableTextPara might be a profitable future task.
114 class AccessibleStaticTextBase_Impl
116 friend class AccessibleStaticTextBase
;
119 // receive pointer to our frontend class and view window
120 AccessibleStaticTextBase_Impl();
121 ~AccessibleStaticTextBase_Impl();
123 void SetEditSource( ::std::unique_ptr
< SvxEditSource
> && pEditSource
);
125 void SetEventSource( const uno::Reference
< XAccessible
>& rInterface
)
131 void SetOffset( const Point
& );
135 AccessibleEditableTextPara
& GetParagraph( sal_Int32 nPara
) const;
136 sal_Int32
GetParagraphCount() const;
138 EPosition
Index2Internal( sal_Int32 nFlatIndex
) const
141 return ImpCalcInternal( nFlatIndex
, false );
144 EPosition
Range2Internal( sal_Int32 nFlatIndex
) const
147 return ImpCalcInternal( nFlatIndex
, true );
150 sal_Int32
Internal2Index( EPosition nEEIndex
) const;
152 void CorrectTextSegment( TextSegment
& aTextSegment
,
155 bool SetSelection( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
156 sal_Int32 nEndPara
, sal_Int32 nEndIndex
);
157 bool CopyText( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
158 sal_Int32 nEndPara
, sal_Int32 nEndIndex
);
160 Rectangle
GetParagraphBoundingBox() const;
161 bool RemoveLineBreakCount( sal_Int32
& rIndex
);
165 EPosition
ImpCalcInternal( sal_Int32 nFlatIndex
, bool bExclusive
) const;
167 // our frontend class (the one implementing the actual
168 // interface). That's not necessarily the one containing the impl
170 uno::Reference
< XAccessible
> mxThis
;
172 // implements our functionality, we're just an adapter (guarded by solar mutex)
173 mutable AccessibleEditableTextPara
* mpTextParagraph
;
175 uno::Reference
< XAccessible
> mxParagraph
;
177 // a wrapper for the text forwarders (guarded by solar mutex)
178 mutable SvxEditSourceAdapter maEditSource
;
180 // guard for maOffset
181 mutable ::osl::Mutex maMutex
;
183 /// our current offset to the containing shape/cell (guarded by maMutex)
190 // AccessibleStaticTextBase_Impl implementation
194 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
196 mpTextParagraph( new AccessibleEditableTextPara(NULL
) ),
197 mxParagraph( mpTextParagraph
),
203 // TODO: this is still somewhat of a hack, all the more since
204 // now the maTextParagraph has an empty parent reference set
207 AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl()
211 void AccessibleStaticTextBase_Impl::SetEditSource( ::std::unique_ptr
< SvxEditSource
> && pEditSource
)
214 maEditSource
.SetEditSource( std::move(pEditSource
) );
215 if( mpTextParagraph
)
216 mpTextParagraph
->SetEditSource( &maEditSource
);
219 void AccessibleStaticTextBase_Impl::SetOffset( const Point
& rPoint
)
222 // guard against non-atomic access to maOffset data structure
224 ::osl::MutexGuard
aGuard( maMutex
);
228 if( mpTextParagraph
)
229 mpTextParagraph
->SetEEOffset( rPoint
);
232 void AccessibleStaticTextBase_Impl::Dispose()
235 // we're the owner of the paragraph, so destroy it, too
236 if( mpTextParagraph
)
237 mpTextParagraph
->Dispose();
242 mpTextParagraph
= NULL
;
245 AccessibleEditableTextPara
& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara
) const
248 if( !mpTextParagraph
)
249 throw lang::DisposedException ("object has been already disposed", mxThis
);
251 // TODO: Have a different method on AccessibleEditableTextPara
252 // that does not care about state changes
253 mpTextParagraph
->SetParagraphIndex( nPara
);
255 return *mpTextParagraph
;
258 sal_Int32
AccessibleStaticTextBase_Impl::GetParagraphCount() const
261 if( !mpTextParagraph
)
264 return mpTextParagraph
->GetTextForwarder().GetParagraphCount();
267 sal_Int32
AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex
) const
269 // XXX checks for overflow and returns maximum if so
271 for(sal_Int32 i
=0; i
<nEEIndex
.nPara
; ++i
)
273 sal_Int32 nCount
= GetParagraph(i
).getCharacterCount();
274 if (SAL_MAX_INT32
- aRes
> nCount
)
275 return SAL_MAX_INT32
;
279 if (SAL_MAX_INT32
- aRes
> nEEIndex
.nIndex
)
280 return SAL_MAX_INT32
;
281 return aRes
+ nEEIndex
.nIndex
;
284 void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment
& aTextSegment
,
287 // Keep 'invalid' values at the TextSegment
288 if( aTextSegment
.SegmentStart
!= -1 &&
289 aTextSegment
.SegmentEnd
!= -1 )
291 // #112814# Correct TextSegment by paragraph offset
292 sal_Int32
nOffset(0);
294 for(i
=0; i
<nPara
; ++i
)
295 nOffset
+= GetParagraph(i
).getCharacterCount();
297 aTextSegment
.SegmentStart
+= nOffset
;
298 aTextSegment
.SegmentEnd
+= nOffset
;
302 EPosition
AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex
, bool bExclusive
) const
306 throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
308 // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually
310 sal_Int32 nCurrPara
, nCurrIndex
, nParas
, nCurrCount
;
311 for( nCurrPara
=0, nParas
=GetParagraphCount(), nCurrCount
=0, nCurrIndex
=0; nCurrPara
<nParas
; ++nCurrPara
)
313 nCurrCount
= GetParagraph( nCurrPara
).getCharacterCount();
314 nCurrIndex
+= nCurrCount
;
315 if( nCurrIndex
>= nFlatIndex
)
318 DBG_ASSERT(nCurrPara
>= 0 && nCurrPara
<= SAL_MAX_INT32
&&
319 nFlatIndex
- nCurrIndex
+ nCurrCount
>= 0 && nFlatIndex
- nCurrIndex
+ nCurrCount
<= USHRT_MAX
,
320 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
322 return EPosition(nCurrPara
, nFlatIndex
- nCurrIndex
+ nCurrCount
);
326 // #102170# Allow one-past the end for ranges
327 if( bExclusive
&& nCurrIndex
== nFlatIndex
)
330 DBG_ASSERT(nCurrPara
> 0 && nCurrPara
<= SAL_MAX_INT32
&&
331 nFlatIndex
- nCurrIndex
+ nCurrCount
>= 0 && nFlatIndex
- nCurrIndex
+ nCurrCount
<= USHRT_MAX
,
332 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
334 return EPosition(nCurrPara
-1, nFlatIndex
- nCurrIndex
+ nCurrCount
);
337 // not found? Out of bounds
338 throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
342 bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
343 sal_Int32 nEndPara
, sal_Int32 nEndIndex
)
346 if( !mpTextParagraph
)
351 SvxEditViewForwarder
& rCacheVF
= mpTextParagraph
->GetEditViewForwarder( true );
352 return rCacheVF
.SetSelection( MakeSelection(nStartPara
, nStartIndex
, nEndPara
, nEndIndex
) );
354 catch( const uno::RuntimeException
& )
360 bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
361 sal_Int32 nEndPara
, sal_Int32 nEndIndex
)
364 if( !mpTextParagraph
)
369 SvxEditViewForwarder
& rCacheVF
= mpTextParagraph
->GetEditViewForwarder( true );
370 mpTextParagraph
->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
373 // save current selection
374 ESelection aOldSelection
;
376 rCacheVF
.GetSelection( aOldSelection
);
377 rCacheVF
.SetSelection( MakeSelection(nStartPara
, nStartIndex
, nEndPara
, nEndIndex
) );
378 aRetVal
= rCacheVF
.Copy();
379 rCacheVF
.SetSelection( aOldSelection
); // restore
383 catch( const uno::RuntimeException
& )
389 Rectangle
AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
392 if( mpTextParagraph
)
394 awt::Rectangle aAwtRect
= mpTextParagraph
->getBounds();
395 aRect
= Rectangle( Point( aAwtRect
.X
, aAwtRect
.Y
), Size( aAwtRect
.Width
, aAwtRect
.Height
) );
403 //the input argument is the index(including "\n" ) in the string.
404 //the function will calculate the actual index(not including "\n") in the string.
405 //and return true if the index is just at a "\n"
406 bool AccessibleStaticTextBase_Impl::RemoveLineBreakCount( sal_Int32
& rIndex
)
408 // get the total char number inside the cell.
409 sal_Int32 i
, nCount
, nParas
;
410 for( i
=0, nCount
=0, nParas
=GetParagraphCount(); i
<nParas
; ++i
)
411 nCount
+= GetParagraph(i
).getCharacterCount();
412 nCount
= nCount
+ (nParas
-1);
413 if( nCount
== 0 && rIndex
== 0) return false;
416 sal_Int32 nCurrPara
, nCurrCount
;
417 sal_Int32 nLineBreakPos
= 0, nLineBreakCount
= 0;
418 sal_Int32 nParaCount
= GetParagraphCount();
419 for ( nCurrCount
= 0, nCurrPara
= 0; nCurrPara
< nParaCount
; nCurrPara
++ )
421 nCurrCount
+= GetParagraph( nCurrPara
).getCharacterCount();
422 nLineBreakPos
= nCurrCount
++;
423 if ( rIndex
== nLineBreakPos
)
425 rIndex
-= (++nLineBreakCount
);//(++nLineBreakCount);
430 //if the index is at the last position of the last paragraph
431 //there is no "\n" , so we should increase rIndex by 1 and return false.
432 if ( (nCurrPara
+1) == nParaCount
)
442 else if ( rIndex
< nLineBreakPos
)
444 rIndex
-= nLineBreakCount
;
456 // AccessibleStaticTextBase implementation
458 AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::unique_ptr
< SvxEditSource
> && pEditSource
) :
459 mpImpl( new AccessibleStaticTextBase_Impl() )
461 SolarMutexGuard aGuard
;
463 SetEditSource( std::move(pEditSource
) );
466 AccessibleStaticTextBase::~AccessibleStaticTextBase()
470 void AccessibleStaticTextBase::SetEditSource( ::std::unique_ptr
< SvxEditSource
> && pEditSource
)
473 // precondition: solar mutex locked
474 DBG_TESTSOLARMUTEX();
476 mpImpl
->SetEditSource( std::move(pEditSource
) );
479 mpImpl
->SetEditSource( std::move(pEditSource
) );
483 void AccessibleStaticTextBase::SetEventSource( const uno::Reference
< XAccessible
>& rInterface
)
485 mpImpl
->SetEventSource( rInterface
);
489 void AccessibleStaticTextBase::SetOffset( const Point
& rPoint
)
492 // precondition: solar mutex locked
493 DBG_TESTSOLARMUTEX();
495 mpImpl
->SetOffset( rPoint
);
498 mpImpl
->SetOffset( rPoint
);
502 void AccessibleStaticTextBase::Dispose()
508 // XAccessibleContext
509 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException
, std::exception
)
511 // no children at all
515 uno::Reference
< XAccessible
> SAL_CALL
AccessibleStaticTextBase::getAccessibleChild( sal_Int32
/*i*/ ) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
517 // no children at all
518 return uno::Reference
< XAccessible
>();
521 uno::Reference
< XAccessible
> SAL_CALL
AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point
& /*_aPoint*/ ) throw (uno::RuntimeException
, std::exception
)
523 // no children at all
524 return uno::Reference
< XAccessible
>();
528 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException
, std::exception
)
530 SolarMutexGuard aGuard
;
532 sal_Int32 i
, nPos
, nParas
;
533 for( i
=0, nPos
=-1, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
535 if( (nPos
=mpImpl
->GetParagraph(i
).getCaretPosition()) != -1 )
542 sal_Bool SAL_CALL
AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
544 return setSelection(nIndex
, nIndex
);
547 sal_Unicode SAL_CALL
AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
549 SolarMutexGuard aGuard
;
551 EPosition
aPos( mpImpl
->Index2Internal(nIndex
) );
553 return mpImpl
->GetParagraph( aPos
.nPara
).getCharacter( aPos
.nIndex
);
556 uno::Sequence
< beans::PropertyValue
> SAL_CALL
AccessibleStaticTextBase::getCharacterAttributes( sal_Int32 nIndex
, const ::com::sun::star::uno::Sequence
< OUString
>& aRequestedAttributes
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
558 SolarMutexGuard aGuard
;
560 //get the actual index without "\n"
561 mpImpl
->RemoveLineBreakCount( nIndex
);
563 EPosition
aPos( mpImpl
->Index2Internal(nIndex
) );
565 return mpImpl
->GetParagraph( aPos
.nPara
).getCharacterAttributes( aPos
.nIndex
, aRequestedAttributes
);
568 awt::Rectangle SAL_CALL
AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
570 SolarMutexGuard aGuard
;
572 // #108900# Allow ranges for nIndex, as one-past-the-end
573 // values are now legal, too.
574 EPosition
aPos( mpImpl
->Range2Internal(nIndex
) );
576 // #i70916# Text in spread sheet cells return the wrong extents
577 AccessibleEditableTextPara
& rPara
= mpImpl
->GetParagraph( aPos
.nPara
);
578 awt::Rectangle
aParaBounds( rPara
.getBounds() );
579 awt::Rectangle
aBounds( rPara
.getCharacterBounds( aPos
.nIndex
) );
580 aBounds
.X
+= aParaBounds
.X
;
581 aBounds
.Y
+= aParaBounds
.Y
;
586 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException
, std::exception
)
588 SolarMutexGuard aGuard
;
590 sal_Int32 i
, nCount
, nParas
;
591 for( i
=0, nCount
=0, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
592 nCount
+= mpImpl
->GetParagraph(i
).getCharacterCount();
593 //count on the number of "\n" which equals number of paragraphs decrease 1.
594 nCount
= nCount
+ (nParas
-1);
598 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getIndexAtPoint( const awt::Point
& rPoint
) throw (uno::RuntimeException
, std::exception
)
600 SolarMutexGuard aGuard
;
602 const sal_Int32
nParas( mpImpl
->GetParagraphCount() );
605 for( i
=0; i
<nParas
; ++i
)
607 // TODO: maybe exploit the fact that paragraphs are
608 // ordered vertically for early exit
610 // #i70916# Text in spread sheet cells return the wrong extents
611 AccessibleEditableTextPara
& rPara
= mpImpl
->GetParagraph( i
);
612 awt::Rectangle
aParaBounds( rPara
.getBounds() );
613 awt::Point
aPoint( rPoint
);
614 aPoint
.X
-= aParaBounds
.X
;
615 aPoint
.Y
-= aParaBounds
.Y
;
617 // #112814# Use correct index offset
618 if ( ( nIndex
= rPara
.getIndexAtPoint( aPoint
) ) != -1 )
619 return mpImpl
->Internal2Index(EPosition(i
, nIndex
));
625 OUString SAL_CALL
AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException
, std::exception
)
627 SolarMutexGuard aGuard
;
629 sal_Int32
nStart( getSelectionStart() );
630 sal_Int32
nEnd( getSelectionEnd() );
632 // #104481# Return the empty string for 'no selection'
633 if( nStart
< 0 || nEnd
< 0 )
636 return getTextRange( nStart
, nEnd
);
639 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException
, std::exception
)
641 SolarMutexGuard aGuard
;
643 sal_Int32 i
, nPos
, nParas
;
644 for( i
=0, nPos
=-1, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
646 if( (nPos
=mpImpl
->GetParagraph(i
).getSelectionStart()) != -1 )
653 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException
, std::exception
)
655 SolarMutexGuard aGuard
;
657 sal_Int32 i
, nPos
, nParas
;
658 for( i
=0, nPos
=-1, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
660 if( (nPos
=mpImpl
->GetParagraph(i
).getSelectionEnd()) != -1 )
667 sal_Bool SAL_CALL
AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
669 SolarMutexGuard aGuard
;
671 EPosition
aStartIndex( mpImpl
->Range2Internal(nStartIndex
) );
672 EPosition
aEndIndex( mpImpl
->Range2Internal(nEndIndex
) );
674 return mpImpl
->SetSelection( aStartIndex
.nPara
, aStartIndex
.nIndex
,
675 aEndIndex
.nPara
, aEndIndex
.nIndex
);
678 OUString SAL_CALL
AccessibleStaticTextBase::getText() throw (uno::RuntimeException
, std::exception
)
680 SolarMutexGuard aGuard
;
684 for( i
=0, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
685 aRes
+= mpImpl
->GetParagraph(i
).getText();
690 OUString SAL_CALL
AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
692 SolarMutexGuard aGuard
;
694 if( nStartIndex
> nEndIndex
)
695 ::std::swap(nStartIndex
, nEndIndex
);
696 //if startindex equals endindex we will get nothing. So return an empty string directly.
697 if ( nStartIndex
== nEndIndex
)
701 bool bStart
= mpImpl
->RemoveLineBreakCount( nStartIndex
);
702 //if the start index is just at a "\n", we need to begin from the next char
707 //we need to find out whether the previous position of the current endindex is at "\n" or not
708 //if yes we need to mark it and add "\n" at the end of the result
709 sal_Int32 nTemp
= nEndIndex
- 1;
710 bool bEnd
= mpImpl
->RemoveLineBreakCount( nTemp
);
711 bool bTemp
= mpImpl
->RemoveLineBreakCount( nEndIndex
);
712 //if the below condition is true it indicates an empty paragraph with just a "\n"
713 //so we need to set one "\n" flag to avoid duplication.
714 if ( bStart
&& bEnd
&& ( nStartIndex
== nEndIndex
) )
718 //if the current endindex is at a "\n", we need to increase endindex by 1 to make sure
719 //the char before "\n" is included. Because string returned by this function will not include
720 //the char at the endindex.
726 EPosition
aStartIndex( mpImpl
->Range2Internal(nStartIndex
) );
727 EPosition
aEndIndex( mpImpl
->Range2Internal(nEndIndex
) );
729 // #102170# Special case: start and end paragraph are identical
730 if( aStartIndex
.nPara
== aEndIndex
.nPara
)
732 //we don't return the string directly now for that we have to do some further process for "\n"
733 aRes
= mpImpl
->GetParagraph( aStartIndex
.nPara
).getTextRange( aStartIndex
.nIndex
, aEndIndex
.nIndex
);
737 sal_Int32
i( aStartIndex
.nPara
);
738 aRes
= mpImpl
->GetParagraph(i
).getTextRange( aStartIndex
.nIndex
,
739 mpImpl
->GetParagraph(i
).getCharacterCount()/*-1*/);
742 // paragraphs inbetween are fully included
743 for( ; i
<aEndIndex
.nPara
; ++i
)
745 aRes
+= OUString(cNewLine
);
746 aRes
+= mpImpl
->GetParagraph(i
).getText();
749 if( i
<=aEndIndex
.nPara
)
751 //if the below condition is mathed it means the endindex is at mid of the last paragraph
752 //we need to add a "\n" before we add the last part of the string.
753 if ( !bEnd
&& aEndIndex
.nIndex
)
755 aRes
+= OUString(cNewLine
);
757 aRes
+= mpImpl
->GetParagraph(i
).getTextRange( 0, aEndIndex
.nIndex
);
760 //According to the flag we marked before, we have to add "\n" at the beginning
761 //or at the end of the result string.
764 aRes
= OUString(cNewLine
) + aRes
;
768 aRes
+= OUString(cNewLine
);
773 ::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
, std::exception
)
775 SolarMutexGuard aGuard
;
777 bool bLineBreak
= mpImpl
->RemoveLineBreakCount( nIndex
);
778 EPosition
aPos( mpImpl
->Range2Internal(nIndex
) );
780 ::com::sun::star::accessibility::TextSegment aResult
;
782 if( AccessibleTextType::PARAGRAPH
== aTextType
)
784 // #106393# Special casing one behind last paragraph is
785 // not necessary, since then, we return the content and
786 // boundary of that last paragraph. Range2Internal is
787 // tolerant against that, and returns the last paragraph
790 // retrieve full text of the paragraph
791 aResult
.SegmentText
= mpImpl
->GetParagraph( aPos
.nPara
).getText();
793 // #112814# Adapt the start index with the paragraph offset
794 aResult
.SegmentStart
= mpImpl
->Internal2Index( EPosition( aPos
.nPara
, 0 ) );
795 aResult
.SegmentEnd
= aResult
.SegmentStart
+ aResult
.SegmentText
.getLength();
797 else if ( AccessibleTextType::ATTRIBUTE_RUN
== aTextType
)
799 SvxAccessibleTextAdapter
& rTextForwarder
= mpImpl
->GetParagraph( aPos
.nIndex
).GetTextForwarder();
800 sal_Int32 nStartIndex
, nEndIndex
;
801 if ( rTextForwarder
.GetAttributeRun( nStartIndex
, nEndIndex
, aPos
.nPara
, aPos
.nIndex
, true ) )
803 aResult
.SegmentText
= getTextRange( nStartIndex
, nEndIndex
);
804 aResult
.SegmentStart
= nStartIndex
;
805 aResult
.SegmentEnd
= nEndIndex
;
810 // No special handling required, forward to wrapped class
811 aResult
= mpImpl
->GetParagraph( aPos
.nPara
).getTextAtIndex( aPos
.nIndex
, aTextType
);
813 // #112814# Adapt the start index with the paragraph offset
814 mpImpl
->CorrectTextSegment( aResult
, aPos
.nPara
);
817 aResult
.SegmentText
= OUString(cNewLine
);
824 ::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
, std::exception
)
826 SolarMutexGuard aGuard
;
828 sal_Int32 nOldIdx
= nIndex
;
829 bool bLineBreak
= mpImpl
->RemoveLineBreakCount( nIndex
);
830 EPosition
aPos( mpImpl
->Range2Internal(nIndex
) );
832 ::com::sun::star::accessibility::TextSegment aResult
;
834 if( AccessibleTextType::PARAGRAPH
== aTextType
)
836 if( aPos
.nIndex
== mpImpl
->GetParagraph( aPos
.nPara
).getCharacterCount() )
838 // #103589# Special casing one behind the last paragraph
839 aResult
.SegmentText
= mpImpl
->GetParagraph( aPos
.nPara
).getText();
841 // #112814# Adapt the start index with the paragraph offset
842 aResult
.SegmentStart
= mpImpl
->Internal2Index( EPosition( aPos
.nPara
, 0 ) );
844 else if( aPos
.nPara
> 0 )
846 aResult
.SegmentText
= mpImpl
->GetParagraph( aPos
.nPara
- 1 ).getText();
848 // #112814# Adapt the start index with the paragraph offset
849 aResult
.SegmentStart
= mpImpl
->Internal2Index( EPosition( aPos
.nPara
- 1, 0 ) );
852 aResult
.SegmentEnd
= aResult
.SegmentStart
+ aResult
.SegmentText
.getLength();
856 // No special handling required, forward to wrapped class
857 aResult
= mpImpl
->GetParagraph( aPos
.nPara
).getTextBeforeIndex( aPos
.nIndex
, aTextType
);
859 // #112814# Adapt the start index with the paragraph offset
860 mpImpl
->CorrectTextSegment( aResult
, aPos
.nPara
);
861 if ( bLineBreak
&& (nOldIdx
-1) >= 0)
863 aResult
= getTextAtIndex( nOldIdx
-1, aTextType
);
870 ::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
, std::exception
)
872 SolarMutexGuard aGuard
;
874 sal_Int32 nTemp
= nIndex
+1;
875 bool bLineBreak
= mpImpl
->RemoveLineBreakCount( nTemp
);
876 mpImpl
->RemoveLineBreakCount( nIndex
);
877 EPosition
aPos( mpImpl
->Range2Internal(nIndex
) );
879 ::com::sun::star::accessibility::TextSegment aResult
;
881 if( AccessibleTextType::PARAGRAPH
== aTextType
)
883 // Special casing one behind the last paragraph is not
884 // necessary, this case is invalid here for
885 // getTextBehindIndex
886 if( aPos
.nPara
+ 1 < mpImpl
->GetParagraphCount() )
888 aResult
.SegmentText
= mpImpl
->GetParagraph( aPos
.nPara
+ 1 ).getText();
890 // #112814# Adapt the start index with the paragraph offset
891 aResult
.SegmentStart
= mpImpl
->Internal2Index( EPosition( aPos
.nPara
+ 1, 0 ) );
892 aResult
.SegmentEnd
= aResult
.SegmentStart
+ aResult
.SegmentText
.getLength();
897 // No special handling required, forward to wrapped class
898 aResult
= mpImpl
->GetParagraph( aPos
.nPara
).getTextBehindIndex( aPos
.nIndex
, aTextType
);
900 // #112814# Adapt the start index with the paragraph offset
901 mpImpl
->CorrectTextSegment( aResult
, aPos
.nPara
);
904 aResult
.SegmentText
= OUString(cNewLine
) + aResult
.SegmentText
;
911 sal_Bool SAL_CALL
AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
913 SolarMutexGuard aGuard
;
915 if( nStartIndex
> nEndIndex
)
916 ::std::swap(nStartIndex
, nEndIndex
);
918 EPosition
aStartIndex( mpImpl
->Range2Internal(nStartIndex
) );
919 EPosition
aEndIndex( mpImpl
->Range2Internal(nEndIndex
) );
921 return mpImpl
->CopyText( aStartIndex
.nPara
, aStartIndex
.nIndex
,
922 aEndIndex
.nPara
, aEndIndex
.nIndex
);
925 // XAccessibleTextAttributes
926 uno::Sequence
< beans::PropertyValue
> AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence
< OUString
>& RequestedAttributes
) throw (uno::RuntimeException
, std::exception
)
928 // get the intersection of the default attributes of all paragraphs
930 SolarMutexGuard aGuard
;
932 PropertyValueVector
aDefAttrVec(
933 comphelper::sequenceToContainer
<PropertyValueVector
>(mpImpl
->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes
)) );
935 const sal_Int32 nParaCount
= mpImpl
->GetParagraphCount();
936 for ( sal_Int32 nPara
= 1; nPara
< nParaCount
; ++nPara
)
938 uno::Sequence
< beans::PropertyValue
> aSeq
= mpImpl
->GetParagraph( nPara
).getDefaultAttributes( RequestedAttributes
);
939 PropertyValueVector aIntersectionVec
;
941 PropertyValueVector::const_iterator aEnd
= aDefAttrVec
.end();
942 for ( PropertyValueVector::const_iterator aItr
= aDefAttrVec
.begin(); aItr
!= aEnd
; ++aItr
)
944 const beans::PropertyValue
* pItr
= aSeq
.getConstArray();
945 const beans::PropertyValue
* pEnd
= pItr
+ aSeq
.getLength();
946 const beans::PropertyValue
* pFind
= ::std::find_if( pItr
, pEnd
, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr
) ) );
949 aIntersectionVec
.push_back( *pFind
);
953 aDefAttrVec
.swap( aIntersectionVec
);
955 if ( aDefAttrVec
.empty() )
961 return comphelper::containerToSequence(aDefAttrVec
);
964 uno::Sequence
< beans::PropertyValue
> SAL_CALL
AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex
, const uno::Sequence
< OUString
>& RequestedAttributes
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
, std::exception
)
966 // get those default attributes of the paragraph, which are not part
967 // of the intersection of all paragraphs and add them to the run attributes
969 SolarMutexGuard aGuard
;
971 EPosition
aPos( mpImpl
->Index2Internal( nIndex
) );
972 AccessibleEditableTextPara
& rPara
= mpImpl
->GetParagraph( aPos
.nPara
);
973 uno::Sequence
< beans::PropertyValue
> aDefAttrSeq
= rPara
.getDefaultAttributes( RequestedAttributes
);
974 uno::Sequence
< beans::PropertyValue
> aRunAttrSeq
= rPara
.getRunAttributes( aPos
.nIndex
, RequestedAttributes
);
975 uno::Sequence
< beans::PropertyValue
> aIntersectionSeq
= getDefaultAttributes( RequestedAttributes
);
976 PropertyValueVector aDiffVec
;
978 const beans::PropertyValue
* pDefAttr
= aDefAttrSeq
.getConstArray();
979 const sal_Int32 nLength
= aDefAttrSeq
.getLength();
980 for ( sal_Int32 i
= 0; i
< nLength
; ++i
)
982 const beans::PropertyValue
* pItr
= aIntersectionSeq
.getConstArray();
983 const beans::PropertyValue
* pEnd
= pItr
+ aIntersectionSeq
.getLength();
984 const beans::PropertyValue
* pFind
= ::std::find_if( pItr
, pEnd
, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr
[i
] ) ) );
985 if ( pFind
== pEnd
&& pDefAttr
[i
].Handle
!= 0)
987 aDiffVec
.push_back( pDefAttr
[i
] );
991 return ::comphelper::concatSequences( aRunAttrSeq
, comphelper::containerToSequence(aDiffVec
) );
994 Rectangle
AccessibleStaticTextBase::GetParagraphBoundingBox() const
996 return mpImpl
->GetParagraphBoundingBox();
999 } // end of namespace accessibility
1003 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */