bump product version to 5.0.4.1
[LibreOffice.git] / editeng / source / accessibility / AccessibleStaticTextBase.cxx
blob6a1c21c362c581603bbbf7ca0ef0d7ba5c52243c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 // Global header
27 #include <limits.h>
28 #include <utility>
29 #include <vector>
30 #include <algorithm>
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;
58 /* TODO:
59 =====
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 >
73 public:
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);
84 // Static Helper
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;
117 public:
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 )
128 mxThis = rInterface;
131 void SetOffset( const Point& );
133 void Dispose();
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,
153 int nPara ) const;
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 );
163 private:
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
169 // pointer
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)
184 Point maOffset;
190 // AccessibleStaticTextBase_Impl implementation
194 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
195 mxThis( NULL ),
196 mpTextParagraph( new AccessibleEditableTextPara(NULL) ),
197 mxParagraph( mpTextParagraph ),
198 maEditSource(),
199 maMutex(),
200 maOffset(0,0)
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 );
225 maOffset = rPoint;
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();
239 // drop references
240 mxParagraph = NULL;
241 mxThis = NULL;
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 )
262 return 0;
263 else
264 return mpTextParagraph->GetTextForwarder().GetParagraphCount();
267 sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const
269 // XXX checks for overflow and returns maximum if so
270 sal_Int32 aRes(0);
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;
276 aRes += nCount;
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,
285 int nPara ) const
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);
293 int i;
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
305 if( nFlatIndex < 0 )
306 throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
307 mxThis);
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 )
317 // check overflow
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 )
329 // check overflow
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",
339 mxThis);
342 bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
343 sal_Int32 nEndPara, sal_Int32 nEndIndex )
346 if( !mpTextParagraph )
347 return false;
351 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( true );
352 return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
354 catch( const uno::RuntimeException& )
356 return false;
360 bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
361 sal_Int32 nEndPara, sal_Int32 nEndIndex )
364 if( !mpTextParagraph )
365 return false;
369 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( true );
370 mpTextParagraph->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
371 bool aRetVal;
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
381 return aRetVal;
383 catch( const uno::RuntimeException& )
385 return false;
389 Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
391 Rectangle aRect;
392 if( mpTextParagraph )
394 awt::Rectangle aAwtRect = mpTextParagraph->getBounds();
395 aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) );
397 else
399 aRect.SetEmpty();
401 return aRect;
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);
426 if ( rIndex < 0)
428 rIndex = 0;
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 )
434 rIndex++;
435 return false;
437 else
439 return true;
442 else if ( rIndex < nLineBreakPos )
444 rIndex -= nLineBreakCount;
445 return false;
447 else
449 nLineBreakCount++;
452 return false;
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 )
472 #ifdef DBG_UTIL
473 // precondition: solar mutex locked
474 DBG_TESTSOLARMUTEX();
476 mpImpl->SetEditSource( std::move(pEditSource) );
478 #else
479 mpImpl->SetEditSource( std::move(pEditSource) );
480 #endif
483 void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface )
485 mpImpl->SetEventSource( rInterface );
489 void AccessibleStaticTextBase::SetOffset( const Point& rPoint )
491 #ifdef DBG_UTIL
492 // precondition: solar mutex locked
493 DBG_TESTSOLARMUTEX();
495 mpImpl->SetOffset( rPoint );
497 #else
498 mpImpl->SetOffset( rPoint );
499 #endif
502 void AccessibleStaticTextBase::Dispose()
504 mpImpl->Dispose();
508 // XAccessibleContext
509 sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException, std::exception)
511 // no children at all
512 return 0;
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 >();
527 // XAccessibleText
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 )
536 return nPos;
539 return nPos;
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;
583 return aBounds;
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);
595 return nCount;
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() );
603 sal_Int32 nIndex;
604 int i;
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));
622 return -1;
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 )
634 return OUString();
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 )
647 return nPos;
650 return nPos;
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 )
661 return nPos;
664 return nPos;
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;
682 sal_Int32 i, nParas;
683 OUString aRes;
684 for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
685 aRes += mpImpl->GetParagraph(i).getText();
687 return aRes;
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 )
699 return OUString();
701 bool bStart = mpImpl->RemoveLineBreakCount( nStartIndex );
702 //if the start index is just at a "\n", we need to begin from the next char
703 if ( bStart )
705 nStartIndex++;
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) )
716 bEnd = false;
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.
721 if ( bTemp )
723 nEndIndex++;
725 OUString aRes;
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 );
735 else
737 sal_Int32 i( aStartIndex.nPara );
738 aRes = mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex,
739 mpImpl->GetParagraph(i).getCharacterCount()/*-1*/);
740 ++i;
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.
762 if ( bStart )
764 aRes = OUString(cNewLine) + aRes;
766 if ( bEnd )
768 aRes += OUString(cNewLine);
770 return aRes;
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
788 // in aPos.nPara.
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;
808 else
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 );
815 if ( bLineBreak )
817 aResult.SegmentText = OUString(cNewLine);
821 return aResult;
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();
854 else
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 );
867 return aResult;
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();
895 else
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 );
902 if ( bLineBreak )
904 aResult.SegmentText = OUString(cNewLine) + aResult.SegmentText;
908 return aResult;
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 ) ) );
947 if ( pFind != pEnd )
949 aIntersectionVec.push_back( *pFind );
953 aDefAttrVec.swap( aIntersectionVec );
955 if ( aDefAttrVec.empty() )
957 break;
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: */