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 .
30 #include <tools/debug.hxx>
31 #include <vcl/window.hxx>
32 #include <vcl/svapp.hxx>
33 #include <comphelper/sequence.hxx>
34 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
35 #include <com/sun/star/uno/Reference.hxx>
36 #include <com/sun/star/awt/Point.hpp>
37 #include <com/sun/star/awt/Rectangle.hpp>
38 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
41 // Project-local header
44 #include <editeng/editdata.hxx>
45 #include <editeng/unopracc.hxx>
46 #include <editeng/unoedprx.hxx>
47 #include <editeng/AccessibleStaticTextBase.hxx>
48 #include <editeng/AccessibleEditableTextPara.hxx>
51 using namespace ::com::sun::star
;
52 using namespace ::com::sun::star::accessibility
;
57 - separate adapter functionality from AccessibleStaticText class
59 - refactor common loops into templates, using mem_fun
63 namespace accessibility
65 typedef std::vector
< beans::PropertyValue
> PropertyValueVector
;
67 class PropertyValueEqualFunctor
69 const beans::PropertyValue
& m_rPValue
;
72 explicit PropertyValueEqualFunctor(const beans::PropertyValue
& rPValue
)
75 bool operator() ( const beans::PropertyValue
& rhs
) const
77 return ( m_rPValue
.Name
== rhs
.Name
&& m_rPValue
.Value
== rhs
.Value
);
80 sal_Unicode
const cNewLine(0x0a);
86 static ESelection
MakeSelection( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
87 sal_Int32 nEndPara
, sal_Int32 nEndIndex
)
89 DBG_ASSERT(nStartPara
>= 0 &&
93 "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow");
95 return ESelection(nStartPara
, nStartIndex
, nEndPara
, nEndIndex
);
99 // AccessibleStaticTextBase_Impl declaration
102 /** AccessibleStaticTextBase_Impl
104 This class implements the AccessibleStaticTextBase
105 functionality, mainly by forwarding the calls to an aggregated
106 AccessibleEditableTextPara. As this is a therefore non-trivial
107 adapter, factoring out the common functionality from
108 AccessibleEditableTextPara might be a profitable future task.
110 class AccessibleStaticTextBase_Impl
112 friend class AccessibleStaticTextBase
;
115 // receive pointer to our frontend class and view window
116 AccessibleStaticTextBase_Impl();
118 void SetEditSource( std::unique_ptr
< SvxEditSource
> && pEditSource
);
120 void SetEventSource( const uno::Reference
< XAccessible
>& rInterface
)
126 void SetOffset( const Point
& );
130 AccessibleEditableTextPara
& GetParagraph( sal_Int32 nPara
) const;
131 sal_Int32
GetParagraphCount() const;
133 EPosition
Index2Internal( sal_Int32 nFlatIndex
) const
136 return ImpCalcInternal( nFlatIndex
, false );
139 EPosition
Range2Internal( sal_Int32 nFlatIndex
) const
142 return ImpCalcInternal( nFlatIndex
, true );
145 sal_Int32
Internal2Index( EPosition nEEIndex
) const;
147 void CorrectTextSegment( TextSegment
& aTextSegment
,
150 bool SetSelection( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
151 sal_Int32 nEndPara
, sal_Int32 nEndIndex
);
152 bool CopyText( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
153 sal_Int32 nEndPara
, sal_Int32 nEndIndex
);
155 tools::Rectangle
GetParagraphBoundingBox() const;
156 bool RemoveLineBreakCount( sal_Int32
& rIndex
);
160 EPosition
ImpCalcInternal( sal_Int32 nFlatIndex
, bool bExclusive
) const;
162 // our frontend class (the one implementing the actual
163 // interface). That's not necessarily the one containing the impl
165 uno::Reference
< XAccessible
> mxThis
;
167 // implements our functionality, we're just an adapter (guarded by solar mutex)
168 mutable rtl::Reference
<AccessibleEditableTextPara
> mxTextParagraph
;
170 // a wrapper for the text forwarders (guarded by solar mutex)
171 mutable SvxEditSourceAdapter maEditSource
;
175 // AccessibleStaticTextBase_Impl implementation
178 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
179 mxTextParagraph( new AccessibleEditableTextPara(nullptr) ),
183 // TODO: this is still somewhat of a hack, all the more since
184 // now the maTextParagraph has an empty parent reference set
187 void AccessibleStaticTextBase_Impl::SetEditSource( std::unique_ptr
< SvxEditSource
> && pEditSource
)
190 maEditSource
.SetEditSource( std::move(pEditSource
) );
191 if( mxTextParagraph
.is() )
192 mxTextParagraph
->SetEditSource( &maEditSource
);
195 void AccessibleStaticTextBase_Impl::SetOffset( const Point
& rPoint
)
197 if( mxTextParagraph
.is() )
198 mxTextParagraph
->SetEEOffset( rPoint
);
201 void AccessibleStaticTextBase_Impl::Dispose()
204 // we're the owner of the paragraph, so destroy it, too
205 if( mxTextParagraph
.is() )
206 mxTextParagraph
->Dispose();
210 mxTextParagraph
.clear();
213 AccessibleEditableTextPara
& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara
) const
216 if( !mxTextParagraph
.is() )
217 throw lang::DisposedException ("object has been already disposed", mxThis
);
219 // TODO: Have a different method on AccessibleEditableTextPara
220 // that does not care about state changes
221 mxTextParagraph
->SetParagraphIndex( nPara
);
223 return *mxTextParagraph
;
226 sal_Int32
AccessibleStaticTextBase_Impl::GetParagraphCount() const
229 if( !mxTextParagraph
.is() )
232 return mxTextParagraph
->GetTextForwarder().GetParagraphCount();
235 sal_Int32
AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex
) const
237 // XXX checks for overflow and returns maximum if so
239 for(sal_Int32 i
=0; i
<nEEIndex
.nPara
; ++i
)
241 sal_Int32 nCount
= GetParagraph(i
).getCharacterCount();
242 if (SAL_MAX_INT32
- aRes
> nCount
)
243 return SAL_MAX_INT32
;
247 if (SAL_MAX_INT32
- aRes
> nEEIndex
.nIndex
)
248 return SAL_MAX_INT32
;
249 return aRes
+ nEEIndex
.nIndex
;
252 void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment
& aTextSegment
,
255 // Keep 'invalid' values at the TextSegment
256 if( aTextSegment
.SegmentStart
!= -1 &&
257 aTextSegment
.SegmentEnd
!= -1 )
259 // #112814# Correct TextSegment by paragraph offset
260 sal_Int32
nOffset(0);
262 for(i
=0; i
<nPara
; ++i
)
263 nOffset
+= GetParagraph(i
).getCharacterCount();
265 aTextSegment
.SegmentStart
+= nOffset
;
266 aTextSegment
.SegmentEnd
+= nOffset
;
270 EPosition
AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex
, bool bExclusive
) const
274 throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
276 // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually
278 sal_Int32 nCurrPara
, nCurrIndex
, nParas
, nCurrCount
;
279 for( nCurrPara
=0, nParas
=GetParagraphCount(), nCurrCount
=0, nCurrIndex
=0; nCurrPara
<nParas
; ++nCurrPara
)
281 nCurrCount
= GetParagraph( nCurrPara
).getCharacterCount();
282 nCurrIndex
+= nCurrCount
;
283 if( nCurrIndex
>= nFlatIndex
)
286 DBG_ASSERT(nCurrPara
>= 0 &&
287 nFlatIndex
- nCurrIndex
+ nCurrCount
>= 0,
288 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
290 return EPosition(nCurrPara
, nFlatIndex
- nCurrIndex
+ nCurrCount
);
294 // #102170# Allow one-past the end for ranges
295 if( bExclusive
&& nCurrIndex
== nFlatIndex
)
298 DBG_ASSERT(nCurrPara
> 0 &&
299 nFlatIndex
- nCurrIndex
+ nCurrCount
>= 0,
300 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
302 return EPosition(nCurrPara
-1, nFlatIndex
- nCurrIndex
+ nCurrCount
);
305 // not found? Out of bounds
306 throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
310 bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
311 sal_Int32 nEndPara
, sal_Int32 nEndIndex
)
314 if( !mxTextParagraph
.is() )
319 SvxEditViewForwarder
& rCacheVF
= mxTextParagraph
->GetEditViewForwarder( true );
320 return rCacheVF
.SetSelection( MakeSelection(nStartPara
, nStartIndex
, nEndPara
, nEndIndex
) );
322 catch( const uno::RuntimeException
& )
328 bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara
, sal_Int32 nStartIndex
,
329 sal_Int32 nEndPara
, sal_Int32 nEndIndex
)
332 if( !mxTextParagraph
.is() )
337 SvxEditViewForwarder
& rCacheVF
= mxTextParagraph
->GetEditViewForwarder( true );
338 mxTextParagraph
->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
341 // save current selection
342 ESelection aOldSelection
;
344 rCacheVF
.GetSelection( aOldSelection
);
345 rCacheVF
.SetSelection( MakeSelection(nStartPara
, nStartIndex
, nEndPara
, nEndIndex
) );
346 aRetVal
= rCacheVF
.Copy();
347 rCacheVF
.SetSelection( aOldSelection
); // restore
351 catch( const uno::RuntimeException
& )
357 tools::Rectangle
AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
359 tools::Rectangle aRect
;
360 if( mxTextParagraph
.is() )
362 awt::Rectangle aAwtRect
= mxTextParagraph
->getBounds();
363 aRect
= tools::Rectangle( Point( aAwtRect
.X
, aAwtRect
.Y
), Size( aAwtRect
.Width
, aAwtRect
.Height
) );
371 //the input argument is the index(including "\n" ) in the string.
372 //the function will calculate the actual index(not including "\n") in the string.
373 //and return true if the index is just at a "\n"
374 bool AccessibleStaticTextBase_Impl::RemoveLineBreakCount( sal_Int32
& rIndex
)
376 // get the total char number inside the cell.
377 sal_Int32 i
, nCount
, nParas
;
378 for( i
=0, nCount
=0, nParas
=GetParagraphCount(); i
<nParas
; ++i
)
379 nCount
+= GetParagraph(i
).getCharacterCount();
380 nCount
= nCount
+ (nParas
-1);
381 if( nCount
== 0 && rIndex
== 0) return false;
384 sal_Int32 nCurrPara
, nCurrCount
;
385 sal_Int32 nLineBreakPos
= 0, nLineBreakCount
= 0;
386 sal_Int32 nParaCount
= GetParagraphCount();
387 for ( nCurrCount
= 0, nCurrPara
= 0; nCurrPara
< nParaCount
; nCurrPara
++ )
389 nCurrCount
+= GetParagraph( nCurrPara
).getCharacterCount();
390 nLineBreakPos
= nCurrCount
++;
391 if ( rIndex
== nLineBreakPos
)
393 rIndex
-= (++nLineBreakCount
);//(++nLineBreakCount);
398 //if the index is at the last position of the last paragraph
399 //there is no "\n" , so we should increase rIndex by 1 and return false.
400 if ( (nCurrPara
+1) == nParaCount
)
410 else if ( rIndex
< nLineBreakPos
)
412 rIndex
-= nLineBreakCount
;
424 // AccessibleStaticTextBase implementation
426 AccessibleStaticTextBase::AccessibleStaticTextBase( std::unique_ptr
< SvxEditSource
> && pEditSource
) :
427 mpImpl( new AccessibleStaticTextBase_Impl() )
429 SolarMutexGuard aGuard
;
431 SetEditSource( std::move(pEditSource
) );
434 AccessibleStaticTextBase::~AccessibleStaticTextBase()
438 void AccessibleStaticTextBase::SetEditSource( std::unique_ptr
< SvxEditSource
> && pEditSource
)
440 // precondition: solar mutex locked
441 DBG_TESTSOLARMUTEX();
443 mpImpl
->SetEditSource( std::move(pEditSource
) );
446 void AccessibleStaticTextBase::SetEventSource( const uno::Reference
< XAccessible
>& rInterface
)
448 mpImpl
->SetEventSource( rInterface
);
452 void AccessibleStaticTextBase::SetOffset( const Point
& rPoint
)
454 // precondition: solar mutex locked
455 DBG_TESTSOLARMUTEX();
457 mpImpl
->SetOffset( rPoint
);
460 void AccessibleStaticTextBase::Dispose()
466 // XAccessibleContext
467 sal_Int32
AccessibleStaticTextBase::getAccessibleChildCount()
469 // no children at all
473 uno::Reference
< XAccessible
> AccessibleStaticTextBase::getAccessibleChild( sal_Int32
/*i*/ )
475 // no children at all
476 return uno::Reference
< XAccessible
>();
479 uno::Reference
< XAccessible
> AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point
& /*_aPoint*/ )
481 // no children at all
482 return uno::Reference
< XAccessible
>();
486 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getCaretPosition()
488 SolarMutexGuard aGuard
;
490 sal_Int32 i
, nPos
, nParas
;
491 for( i
=0, nPos
=-1, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
493 if( (nPos
=mpImpl
->GetParagraph(i
).getCaretPosition()) != -1 )
500 sal_Bool SAL_CALL
AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex
)
502 return setSelection(nIndex
, nIndex
);
505 sal_Unicode SAL_CALL
AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex
)
507 SolarMutexGuard aGuard
;
509 EPosition
aPos( mpImpl
->Index2Internal(nIndex
) );
511 return mpImpl
->GetParagraph( aPos
.nPara
).getCharacter( aPos
.nIndex
);
514 uno::Sequence
< beans::PropertyValue
> SAL_CALL
AccessibleStaticTextBase::getCharacterAttributes( sal_Int32 nIndex
, const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
516 SolarMutexGuard aGuard
;
518 //get the actual index without "\n"
519 mpImpl
->RemoveLineBreakCount( nIndex
);
521 EPosition
aPos( mpImpl
->Index2Internal(nIndex
) );
523 return mpImpl
->GetParagraph( aPos
.nPara
).getCharacterAttributes( aPos
.nIndex
, aRequestedAttributes
);
526 awt::Rectangle SAL_CALL
AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex
)
528 SolarMutexGuard aGuard
;
530 // #108900# Allow ranges for nIndex, as one-past-the-end
531 // values are now legal, too.
532 EPosition
aPos( mpImpl
->Range2Internal(nIndex
) );
534 // #i70916# Text in spread sheet cells return the wrong extents
535 AccessibleEditableTextPara
& rPara
= mpImpl
->GetParagraph( aPos
.nPara
);
536 awt::Rectangle
aParaBounds( rPara
.getBounds() );
537 awt::Rectangle
aBounds( rPara
.getCharacterBounds( aPos
.nIndex
) );
538 aBounds
.X
+= aParaBounds
.X
;
539 aBounds
.Y
+= aParaBounds
.Y
;
544 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getCharacterCount()
546 SolarMutexGuard aGuard
;
548 sal_Int32 i
, nCount
, nParas
;
549 for( i
=0, nCount
=0, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
550 nCount
+= mpImpl
->GetParagraph(i
).getCharacterCount();
551 //count on the number of "\n" which equals number of paragraphs decrease 1.
552 nCount
= nCount
+ (nParas
-1);
556 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getIndexAtPoint( const awt::Point
& rPoint
)
558 SolarMutexGuard aGuard
;
560 const sal_Int32
nParas( mpImpl
->GetParagraphCount() );
563 for( i
=0; i
<nParas
; ++i
)
565 // TODO: maybe exploit the fact that paragraphs are
566 // ordered vertically for early exit
568 // #i70916# Text in spread sheet cells return the wrong extents
569 AccessibleEditableTextPara
& rPara
= mpImpl
->GetParagraph( i
);
570 awt::Rectangle
aParaBounds( rPara
.getBounds() );
571 awt::Point
aPoint( rPoint
);
572 aPoint
.X
-= aParaBounds
.X
;
573 aPoint
.Y
-= aParaBounds
.Y
;
575 // #112814# Use correct index offset
576 if ( ( nIndex
= rPara
.getIndexAtPoint( aPoint
) ) != -1 )
577 return mpImpl
->Internal2Index(EPosition(i
, nIndex
));
583 OUString SAL_CALL
AccessibleStaticTextBase::getSelectedText()
585 SolarMutexGuard aGuard
;
587 sal_Int32
nStart( getSelectionStart() );
588 sal_Int32
nEnd( getSelectionEnd() );
590 // #104481# Return the empty string for 'no selection'
591 if( nStart
< 0 || nEnd
< 0 )
594 return getTextRange( nStart
, nEnd
);
597 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getSelectionStart()
599 SolarMutexGuard aGuard
;
601 sal_Int32 i
, nPos
, nParas
;
602 for( i
=0, nPos
=-1, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
604 if( (nPos
=mpImpl
->GetParagraph(i
).getSelectionStart()) != -1 )
611 sal_Int32 SAL_CALL
AccessibleStaticTextBase::getSelectionEnd()
613 SolarMutexGuard aGuard
;
615 sal_Int32 i
, nPos
, nParas
;
616 for( i
=0, nPos
=-1, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
618 if( (nPos
=mpImpl
->GetParagraph(i
).getSelectionEnd()) != -1 )
625 sal_Bool SAL_CALL
AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
627 SolarMutexGuard aGuard
;
629 EPosition
aStartIndex( mpImpl
->Range2Internal(nStartIndex
) );
630 EPosition
aEndIndex( mpImpl
->Range2Internal(nEndIndex
) );
632 return mpImpl
->SetSelection( aStartIndex
.nPara
, aStartIndex
.nIndex
,
633 aEndIndex
.nPara
, aEndIndex
.nIndex
);
636 OUString SAL_CALL
AccessibleStaticTextBase::getText()
638 SolarMutexGuard aGuard
;
642 for( i
=0, nParas
=mpImpl
->GetParagraphCount(); i
<nParas
; ++i
)
643 aRes
.append(mpImpl
->GetParagraph(i
).getText());
645 return aRes
.makeStringAndClear();
648 OUString SAL_CALL
AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
650 SolarMutexGuard aGuard
;
652 if( nStartIndex
> nEndIndex
)
653 std::swap(nStartIndex
, nEndIndex
);
654 //if startindex equals endindex we will get nothing. So return an empty string directly.
655 if ( nStartIndex
== nEndIndex
)
659 bool bStart
= mpImpl
->RemoveLineBreakCount( nStartIndex
);
660 //if the start index is just at a "\n", we need to begin from the next char
665 //we need to find out whether the previous position of the current endindex is at "\n" or not
666 //if yes we need to mark it and add "\n" at the end of the result
667 sal_Int32 nTemp
= nEndIndex
- 1;
668 bool bEnd
= mpImpl
->RemoveLineBreakCount( nTemp
);
669 bool bTemp
= mpImpl
->RemoveLineBreakCount( nEndIndex
);
670 //if the below condition is true it indicates an empty paragraph with just a "\n"
671 //so we need to set one "\n" flag to avoid duplication.
672 if ( bStart
&& bEnd
&& ( nStartIndex
== nEndIndex
) )
676 //if the current endindex is at a "\n", we need to increase endindex by 1 to make sure
677 //the char before "\n" is included. Because string returned by this function will not include
678 //the char at the endindex.
684 EPosition
aStartIndex( mpImpl
->Range2Internal(nStartIndex
) );
685 EPosition
aEndIndex( mpImpl
->Range2Internal(nEndIndex
) );
687 // #102170# Special case: start and end paragraph are identical
688 if( aStartIndex
.nPara
== aEndIndex
.nPara
)
690 //we don't return the string directly now for that we have to do some further process for "\n"
691 aRes
= mpImpl
->GetParagraph( aStartIndex
.nPara
).getTextRange( aStartIndex
.nIndex
, aEndIndex
.nIndex
);
695 sal_Int32
i( aStartIndex
.nPara
);
696 aRes
= mpImpl
->GetParagraph(i
).getTextRange( aStartIndex
.nIndex
,
697 mpImpl
->GetParagraph(i
).getCharacterCount()/*-1*/);
700 // paragraphs inbetween are fully included
701 for( ; i
<aEndIndex
.nPara
; ++i
)
703 aRes
.append(cNewLine
);
704 aRes
.append(mpImpl
->GetParagraph(i
).getText());
707 if( i
<=aEndIndex
.nPara
)
709 //if the below condition is matched it means that endindex is at mid of the last paragraph
710 //we need to add a "\n" before we add the last part of the string.
711 if ( !bEnd
&& aEndIndex
.nIndex
)
713 aRes
.append(cNewLine
);
715 aRes
.append(mpImpl
->GetParagraph(i
).getTextRange( 0, aEndIndex
.nIndex
));
718 //According to the flag we marked before, we have to add "\n" at the beginning
719 //or at the end of the result string.
722 aRes
.insert(0, OUStringChar(cNewLine
));
726 aRes
.append(OUStringChar(cNewLine
));
728 return aRes
.makeStringAndClear();
731 css::accessibility::TextSegment SAL_CALL
AccessibleStaticTextBase::getTextAtIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
733 SolarMutexGuard aGuard
;
735 bool bLineBreak
= mpImpl
->RemoveLineBreakCount( nIndex
);
736 EPosition
aPos( mpImpl
->Range2Internal(nIndex
) );
738 css::accessibility::TextSegment aResult
;
740 if( AccessibleTextType::PARAGRAPH
== aTextType
)
742 // #106393# Special casing one behind last paragraph is
743 // not necessary, since then, we return the content and
744 // boundary of that last paragraph. Range2Internal is
745 // tolerant against that, and returns the last paragraph
748 // retrieve full text of the paragraph
749 aResult
.SegmentText
= mpImpl
->GetParagraph( aPos
.nPara
).getText();
751 // #112814# Adapt the start index with the paragraph offset
752 aResult
.SegmentStart
= mpImpl
->Internal2Index( EPosition( aPos
.nPara
, 0 ) );
753 aResult
.SegmentEnd
= aResult
.SegmentStart
+ aResult
.SegmentText
.getLength();
755 else if ( AccessibleTextType::ATTRIBUTE_RUN
== aTextType
)
757 SvxAccessibleTextAdapter
& rTextForwarder
= mpImpl
->GetParagraph( aPos
.nIndex
).GetTextForwarder();
758 sal_Int32 nStartIndex
, nEndIndex
;
759 if ( rTextForwarder
.GetAttributeRun( nStartIndex
, nEndIndex
, aPos
.nPara
, aPos
.nIndex
, true ) )
761 aResult
.SegmentText
= getTextRange( nStartIndex
, nEndIndex
);
762 aResult
.SegmentStart
= nStartIndex
;
763 aResult
.SegmentEnd
= nEndIndex
;
768 // No special handling required, forward to wrapped class
769 aResult
= mpImpl
->GetParagraph( aPos
.nPara
).getTextAtIndex( aPos
.nIndex
, aTextType
);
771 // #112814# Adapt the start index with the paragraph offset
772 mpImpl
->CorrectTextSegment( aResult
, aPos
.nPara
);
775 aResult
.SegmentText
= OUString(cNewLine
);
782 css::accessibility::TextSegment SAL_CALL
AccessibleStaticTextBase::getTextBeforeIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
784 SolarMutexGuard aGuard
;
786 sal_Int32 nOldIdx
= nIndex
;
787 bool bLineBreak
= mpImpl
->RemoveLineBreakCount( nIndex
);
788 EPosition
aPos( mpImpl
->Range2Internal(nIndex
) );
790 css::accessibility::TextSegment aResult
;
792 if( AccessibleTextType::PARAGRAPH
== aTextType
)
794 if( aPos
.nIndex
== mpImpl
->GetParagraph( aPos
.nPara
).getCharacterCount() )
796 // #103589# Special casing one behind the last paragraph
797 aResult
.SegmentText
= mpImpl
->GetParagraph( aPos
.nPara
).getText();
799 // #112814# Adapt the start index with the paragraph offset
800 aResult
.SegmentStart
= mpImpl
->Internal2Index( EPosition( aPos
.nPara
, 0 ) );
802 else if( aPos
.nPara
> 0 )
804 aResult
.SegmentText
= mpImpl
->GetParagraph( aPos
.nPara
- 1 ).getText();
806 // #112814# Adapt the start index with the paragraph offset
807 aResult
.SegmentStart
= mpImpl
->Internal2Index( EPosition( aPos
.nPara
- 1, 0 ) );
810 aResult
.SegmentEnd
= aResult
.SegmentStart
+ aResult
.SegmentText
.getLength();
814 // No special handling required, forward to wrapped class
815 aResult
= mpImpl
->GetParagraph( aPos
.nPara
).getTextBeforeIndex( aPos
.nIndex
, aTextType
);
817 // #112814# Adapt the start index with the paragraph offset
818 mpImpl
->CorrectTextSegment( aResult
, aPos
.nPara
);
819 if ( bLineBreak
&& (nOldIdx
-1) >= 0)
821 aResult
= getTextAtIndex( nOldIdx
-1, aTextType
);
828 css::accessibility::TextSegment SAL_CALL
AccessibleStaticTextBase::getTextBehindIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
830 SolarMutexGuard aGuard
;
832 sal_Int32 nTemp
= nIndex
+1;
833 bool bLineBreak
= mpImpl
->RemoveLineBreakCount( nTemp
);
834 mpImpl
->RemoveLineBreakCount( nIndex
);
835 EPosition
aPos( mpImpl
->Range2Internal(nIndex
) );
837 css::accessibility::TextSegment aResult
;
839 if( AccessibleTextType::PARAGRAPH
== aTextType
)
841 // Special casing one behind the last paragraph is not
842 // necessary, this case is invalid here for
843 // getTextBehindIndex
844 if( aPos
.nPara
+ 1 < mpImpl
->GetParagraphCount() )
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 ) );
850 aResult
.SegmentEnd
= aResult
.SegmentStart
+ aResult
.SegmentText
.getLength();
855 // No special handling required, forward to wrapped class
856 aResult
= mpImpl
->GetParagraph( aPos
.nPara
).getTextBehindIndex( aPos
.nIndex
, aTextType
);
858 // #112814# Adapt the start index with the paragraph offset
859 mpImpl
->CorrectTextSegment( aResult
, aPos
.nPara
);
862 aResult
.SegmentText
= OUStringChar(cNewLine
) + aResult
.SegmentText
;
869 sal_Bool SAL_CALL
AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
871 SolarMutexGuard aGuard
;
873 if( nStartIndex
> nEndIndex
)
874 std::swap(nStartIndex
, nEndIndex
);
876 EPosition
aStartIndex( mpImpl
->Range2Internal(nStartIndex
) );
877 EPosition
aEndIndex( mpImpl
->Range2Internal(nEndIndex
) );
879 return mpImpl
->CopyText( aStartIndex
.nPara
, aStartIndex
.nIndex
,
880 aEndIndex
.nPara
, aEndIndex
.nIndex
);
883 // XAccessibleTextAttributes
884 uno::Sequence
< beans::PropertyValue
> AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence
< OUString
>& RequestedAttributes
)
886 // get the intersection of the default attributes of all paragraphs
888 SolarMutexGuard aGuard
;
890 PropertyValueVector
aDefAttrVec(
891 comphelper::sequenceToContainer
<PropertyValueVector
>(mpImpl
->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes
)) );
893 const sal_Int32 nParaCount
= mpImpl
->GetParagraphCount();
894 for ( sal_Int32 nPara
= 1; nPara
< nParaCount
; ++nPara
)
896 uno::Sequence
< beans::PropertyValue
> aSeq
= mpImpl
->GetParagraph( nPara
).getDefaultAttributes( RequestedAttributes
);
897 PropertyValueVector aIntersectionVec
;
899 for ( const auto& rDefAttr
: aDefAttrVec
)
901 const beans::PropertyValue
* pItr
= aSeq
.getConstArray();
902 const beans::PropertyValue
* pEnd
= pItr
+ aSeq
.getLength();
903 const beans::PropertyValue
* pFind
= std::find_if( pItr
, pEnd
, PropertyValueEqualFunctor(rDefAttr
) );
906 aIntersectionVec
.push_back( *pFind
);
910 aDefAttrVec
.swap( aIntersectionVec
);
912 if ( aDefAttrVec
.empty() )
918 return comphelper::containerToSequence(aDefAttrVec
);
921 uno::Sequence
< beans::PropertyValue
> SAL_CALL
AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex
, const uno::Sequence
< OUString
>& RequestedAttributes
)
923 // get those default attributes of the paragraph, which are not part
924 // of the intersection of all paragraphs and add them to the run attributes
926 SolarMutexGuard aGuard
;
928 EPosition
aPos( mpImpl
->Index2Internal( nIndex
) );
929 AccessibleEditableTextPara
& rPara
= mpImpl
->GetParagraph( aPos
.nPara
);
930 uno::Sequence
< beans::PropertyValue
> aDefAttrSeq
= rPara
.getDefaultAttributes( RequestedAttributes
);
931 uno::Sequence
< beans::PropertyValue
> aRunAttrSeq
= rPara
.getRunAttributes( aPos
.nIndex
, RequestedAttributes
);
932 uno::Sequence
< beans::PropertyValue
> aIntersectionSeq
= getDefaultAttributes( RequestedAttributes
);
933 PropertyValueVector aDiffVec
;
935 const beans::PropertyValue
* pDefAttr
= aDefAttrSeq
.getConstArray();
936 const sal_Int32 nLength
= aDefAttrSeq
.getLength();
937 for ( sal_Int32 i
= 0; i
< nLength
; ++i
)
939 const beans::PropertyValue
* pItr
= aIntersectionSeq
.getConstArray();
940 const beans::PropertyValue
* pEnd
= pItr
+ aIntersectionSeq
.getLength();
941 bool bNone
= std::none_of( pItr
, pEnd
, PropertyValueEqualFunctor( pDefAttr
[i
] ) );
942 if ( bNone
&& pDefAttr
[i
].Handle
!= 0)
944 aDiffVec
.push_back( pDefAttr
[i
] );
948 return ::comphelper::concatSequences( aRunAttrSeq
, comphelper::containerToSequence(aDiffVec
) );
951 tools::Rectangle
AccessibleStaticTextBase::GetParagraphBoundingBox() const
953 return mpImpl
->GetParagraphBoundingBox();
956 } // end of namespace accessibility
959 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */