bump product version to 6.4.0.3
[LibreOffice.git] / editeng / source / accessibility / AccessibleEditableTextPara.cxx
blobc68c79ebea8f411c9b5a89c882da7d211dbe71a9
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 .
21 // Global header
24 #include <limits.h>
25 #include <vector>
26 #include <algorithm>
27 #include <vcl/window.hxx>
28 #include <vcl/svapp.hxx>
29 #include <tools/diagnose_ex.h>
30 #include <sal/log.hxx>
31 #include <editeng/flditem.hxx>
32 #include <com/sun/star/uno/Any.hxx>
33 #include <com/sun/star/uno/Reference.hxx>
34 #include <com/sun/star/awt/Point.hpp>
35 #include <com/sun/star/awt/Rectangle.hpp>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/lang/DisposedException.hpp>
38 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
39 #include <com/sun/star/i18n/Boundary.hpp>
40 #include <com/sun/star/accessibility/AccessibleRole.hpp>
41 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
42 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
43 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
44 #include <comphelper/accessibleeventnotifier.hxx>
45 #include <comphelper/sequenceashashmap.hxx>
46 #include <cppuhelper/supportsservice.hxx>
47 #include <unotools/accessiblestatesethelper.hxx>
48 #include <unotools/accessiblerelationsethelper.hxx>
49 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
50 #include <vcl/unohelp.hxx>
51 #include <vcl/settings.hxx>
52 #include <i18nlangtag/languagetag.hxx>
54 #include <editeng/AccessibleImageBullet.hxx>
55 #include <editeng/editeng.hxx>
56 #include <editeng/unoprnms.hxx>
57 #include <editeng/unoipset.hxx>
58 #include <editeng/outliner.hxx>
59 #include <editeng/unoedprx.hxx>
60 #include <editeng/unoedsrc.hxx>
61 #include <svl/intitem.hxx>
62 #include <svl/eitem.hxx>
65 // Project-local header
68 #include <com/sun/star/beans/PropertyState.hpp>
70 #include <editeng/unolingu.hxx>
71 #include <editeng/unopracc.hxx>
72 #include <editeng/AccessibleEditableTextPara.hxx>
73 #include "AccessibleHyperlink.hxx"
75 #include <svtools/colorcfg.hxx>
76 using namespace std;
77 #include <editeng/editrids.hrc>
78 #include <editeng/eerdll.hxx>
79 #include <editeng/numitem.hxx>
80 #include <memory>
82 using namespace ::com::sun::star;
83 using namespace ::com::sun::star::beans;
84 using namespace ::com::sun::star::accessibility;
87 // AccessibleEditableTextPara implementation
90 namespace accessibility
92 static const SvxItemPropertySet* ImplGetSvxCharAndParaPropertiesSet()
94 // PropertyMap for character and paragraph properties
95 static const SfxItemPropertyMapEntry aPropMap[] =
97 SVX_UNOEDIT_OUTLINER_PROPERTIES,
98 SVX_UNOEDIT_CHAR_PROPERTIES,
99 SVX_UNOEDIT_PARA_PROPERTIES,
100 SVX_UNOEDIT_NUMBERING_PROPERTIE,
101 { OUString("TextUserDefinedAttributes"), EE_CHAR_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
102 { OUString("ParaUserDefinedAttributes"), EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
103 { OUString(), 0, css::uno::Type(), 0, 0 }
105 static SvxItemPropertySet aPropSet( aPropMap, EditEngine::GetGlobalItemPool() );
106 return &aPropSet;
109 // #i27138# - add parameter <_pParaManager>
110 AccessibleEditableTextPara::AccessibleEditableTextPara(
111 const uno::Reference< XAccessible >& rParent,
112 const AccessibleParaManager* _pParaManager )
113 : AccessibleTextParaInterfaceBase( m_aMutex ),
114 mnParagraphIndex( 0 ),
115 mnIndexInParent( 0 ),
116 mpEditSource( nullptr ),
117 maEEOffset( 0, 0 ),
118 mxParent( rParent ),
119 // well, that's strictly (UNO) exception safe, though not
120 // really robust. We rely on the fact that this member is
121 // constructed last, and that the constructor body catches
122 // exceptions, thus no chance for exceptions once the Id is
123 // fetched. Nevertheless, normally should employ RAII here...
124 mnNotifierClientId(::comphelper::AccessibleEventNotifier::registerClient()),
125 // #i27138#
126 mpParaManager( _pParaManager )
131 // Create the state set.
132 ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper ();
133 mxStateSet = pStateSet;
135 // these are always on
136 pStateSet->AddState( AccessibleStateType::MULTI_LINE );
137 pStateSet->AddState( AccessibleStateType::FOCUSABLE );
138 pStateSet->AddState( AccessibleStateType::VISIBLE );
139 pStateSet->AddState( AccessibleStateType::SHOWING );
140 pStateSet->AddState( AccessibleStateType::ENABLED );
141 pStateSet->AddState( AccessibleStateType::SENSITIVE );
143 catch (const uno::Exception&)
148 AccessibleEditableTextPara::~AccessibleEditableTextPara()
150 // sign off from event notifier
151 if( getNotifierClientId() != -1 )
155 ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() );
157 catch (const uno::Exception&)
163 OUString AccessibleEditableTextPara::implGetText()
165 return GetTextRange( 0, GetTextLen() );
168 css::lang::Locale AccessibleEditableTextPara::implGetLocale()
170 DBG_ASSERT(GetParagraphIndex() >= 0,
171 "AccessibleEditableTextPara::getLocale: paragraph index value overflow");
173 // return locale of first character in the paragraph
174 return LanguageTag(GetTextForwarder().GetLanguage( GetParagraphIndex(), 0 )).getLocale();
177 void AccessibleEditableTextPara::implGetSelection( sal_Int32& nStartIndex, sal_Int32& nEndIndex )
179 sal_Int32 nStart, nEnd;
181 if( GetSelection( nStart, nEnd ) )
183 nStartIndex = nStart;
184 nEndIndex = nEnd;
186 else
188 // #102234# No exception, just set to 'invalid'
189 nStartIndex = -1;
190 nEndIndex = -1;
194 void AccessibleEditableTextPara::implGetParagraphBoundary( const OUString& rText, css::i18n::Boundary& rBoundary, sal_Int32 /*nIndex*/ )
196 SAL_INFO( "editeng", "AccessibleEditableTextPara::implGetParagraphBoundary: only a base implementation, ignoring the index" );
198 rBoundary.startPos = 0;
199 rBoundary.endPos = rText.getLength();
202 void AccessibleEditableTextPara::implGetLineBoundary( const OUString&, css::i18n::Boundary& rBoundary, sal_Int32 nIndex )
204 SvxTextForwarder& rCacheTF = GetTextForwarder();
205 const sal_Int32 nParaIndex = GetParagraphIndex();
207 DBG_ASSERT(nParaIndex >= 0,
208 "AccessibleEditableTextPara::implGetLineBoundary: paragraph index value overflow");
210 const sal_Int32 nTextLen = rCacheTF.GetTextLen( nParaIndex );
212 CheckPosition(nIndex);
214 rBoundary.startPos = rBoundary.endPos = -1;
216 const sal_Int32 nLineCount=rCacheTF.GetLineCount( nParaIndex );
218 if( nIndex == nTextLen )
220 // #i17014# Special-casing one-behind-the-end character
221 if( nLineCount <= 1 )
222 rBoundary.startPos = 0;
223 else
224 rBoundary.startPos = nTextLen - rCacheTF.GetLineLen( nParaIndex,
225 nLineCount-1 );
227 rBoundary.endPos = nTextLen;
229 else
231 // normal line search
232 sal_Int32 nLine;
233 sal_Int32 nCurIndex;
234 for( nLine=0, nCurIndex=0; nLine<nLineCount; ++nLine )
236 nCurIndex += rCacheTF.GetLineLen( nParaIndex, nLine);
238 if( nCurIndex > nIndex )
240 rBoundary.startPos = nCurIndex - rCacheTF.GetLineLen( nParaIndex, nLine);
241 rBoundary.endPos = nCurIndex;
242 break;
249 void AccessibleEditableTextPara::SetIndexInParent( sal_Int32 nIndex )
251 mnIndexInParent = nIndex;
255 void AccessibleEditableTextPara::SetParagraphIndex( sal_Int32 nIndex )
257 sal_Int32 nOldIndex = mnParagraphIndex;
259 mnParagraphIndex = nIndex;
261 auto aChild( maImageBullet.get() );
262 if( aChild.is() )
263 aChild->SetParagraphIndex(mnParagraphIndex);
267 if( nOldIndex != nIndex )
269 uno::Any aOldDesc;
270 uno::Any aOldName;
274 aOldDesc <<= getAccessibleDescription();
275 aOldName <<= getAccessibleName();
277 catch (const uno::Exception&) // optional behaviour
280 // index and therefore description changed
281 FireEvent( AccessibleEventId::DESCRIPTION_CHANGED, uno::makeAny( getAccessibleDescription() ), aOldDesc );
282 FireEvent( AccessibleEventId::NAME_CHANGED, uno::makeAny( getAccessibleName() ), aOldName );
285 catch (const uno::Exception&) // optional behaviour
291 void AccessibleEditableTextPara::Dispose()
293 int nClientId( getNotifierClientId() );
295 // #108212# drop all references before notifying dispose
296 mxParent = nullptr;
297 mnNotifierClientId = -1;
298 mpEditSource = nullptr;
300 // notify listeners
301 if( nClientId != -1 )
305 uno::Reference < XAccessibleContext > xThis = getAccessibleContext();
307 // #106234# Delegate to EventNotifier
308 ::comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nClientId, xThis );
310 catch (const uno::Exception&)
316 void AccessibleEditableTextPara::SetEditSource( SvxEditSourceAdapter* pEditSource )
318 auto aChild( maImageBullet.get() );
319 if( aChild.is() )
320 aChild->SetEditSource(pEditSource);
322 if( !pEditSource )
324 // going defunc
325 UnSetState( AccessibleStateType::SHOWING );
326 UnSetState( AccessibleStateType::VISIBLE );
327 SetState( AccessibleStateType::INVALID );
328 SetState( AccessibleStateType::DEFUNC );
330 Dispose();
332 mpEditSource = pEditSource;
333 // #108900# Init last text content
336 TextChanged();
338 catch (const uno::RuntimeException&)
343 ESelection AccessibleEditableTextPara::MakeSelection( sal_Int32 nStartEEIndex, sal_Int32 nEndEEIndex )
345 // check overflow
346 DBG_ASSERT(nStartEEIndex >= 0 &&
347 nEndEEIndex >= 0 &&
348 GetParagraphIndex() >= 0,
349 "AccessibleEditableTextPara::MakeSelection: index value overflow");
351 sal_Int32 nParaIndex = GetParagraphIndex();
352 return ESelection(nParaIndex, nStartEEIndex, nParaIndex, nEndEEIndex);
355 ESelection AccessibleEditableTextPara::MakeSelection( sal_Int32 nEEIndex )
357 return MakeSelection( nEEIndex, nEEIndex+1 );
360 ESelection AccessibleEditableTextPara::MakeCursor( sal_Int32 nEEIndex )
362 return MakeSelection( nEEIndex, nEEIndex );
365 void AccessibleEditableTextPara::CheckIndex( sal_Int32 nIndex )
367 if( nIndex < 0 || nIndex >= getCharacterCount() )
368 throw lang::IndexOutOfBoundsException("AccessibleEditableTextPara: character index out of bounds",
369 uno::Reference< uno::XInterface >
370 ( static_cast< ::cppu::OWeakObject* > (this) ) ); // disambiguate hierarchy
373 void AccessibleEditableTextPara::CheckPosition( sal_Int32 nIndex )
375 if( nIndex < 0 || nIndex > getCharacterCount() )
376 throw lang::IndexOutOfBoundsException("AccessibleEditableTextPara: character position out of bounds",
377 uno::Reference< uno::XInterface >
378 ( static_cast< ::cppu::OWeakObject* > (this) ) ); // disambiguate hierarchy
381 void AccessibleEditableTextPara::CheckRange( sal_Int32 nStart, sal_Int32 nEnd )
383 CheckPosition( nStart );
384 CheckPosition( nEnd );
387 bool AccessibleEditableTextPara::GetSelection(sal_Int32 &nStartPos, sal_Int32 &nEndPos)
389 ESelection aSelection;
390 sal_Int32 nPara = GetParagraphIndex();
391 if( !GetEditViewForwarder().GetSelection( aSelection ) )
392 return false;
394 if( aSelection.nStartPara < aSelection.nEndPara )
396 if( aSelection.nStartPara > nPara ||
397 aSelection.nEndPara < nPara )
398 return false;
400 if( nPara == aSelection.nStartPara )
401 nStartPos = aSelection.nStartPos;
402 else
403 nStartPos = 0;
405 if( nPara == aSelection.nEndPara )
406 nEndPos = aSelection.nEndPos;
407 else
408 nEndPos = GetTextLen();
410 else
412 if( aSelection.nStartPara < nPara ||
413 aSelection.nEndPara > nPara )
414 return false;
416 if( nPara == aSelection.nStartPara )
417 nStartPos = aSelection.nStartPos;
418 else
419 nStartPos = GetTextLen();
421 if( nPara == aSelection.nEndPara )
422 nEndPos = aSelection.nEndPos;
423 else
424 nEndPos = 0;
427 return true;
430 OUString AccessibleEditableTextPara::GetTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
432 return GetTextForwarder().GetText( MakeSelection(nStartIndex, nEndIndex) );
435 sal_Int32 AccessibleEditableTextPara::GetTextLen() const
437 return GetTextForwarder().GetTextLen(GetParagraphIndex());
440 SvxEditSourceAdapter& AccessibleEditableTextPara::GetEditSource() const
442 if( !mpEditSource )
443 throw uno::RuntimeException("No edit source, object is defunct",
444 uno::Reference< uno::XInterface >
445 ( static_cast< ::cppu::OWeakObject* >
446 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
447 return *mpEditSource;
450 SvxAccessibleTextAdapter& AccessibleEditableTextPara::GetTextForwarder() const
452 SvxEditSourceAdapter& rEditSource = GetEditSource();
453 SvxAccessibleTextAdapter* pTextForwarder = rEditSource.GetTextForwarderAdapter();
455 if( !pTextForwarder )
456 throw uno::RuntimeException("Unable to fetch text forwarder, object is defunct",
457 uno::Reference< uno::XInterface >
458 ( static_cast< ::cppu::OWeakObject* >
459 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
461 if( !pTextForwarder->IsValid() )
462 throw uno::RuntimeException("Text forwarder is invalid, object is defunct",
463 uno::Reference< uno::XInterface >
464 ( static_cast< ::cppu::OWeakObject* >
465 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
466 return *pTextForwarder;
469 SvxViewForwarder& AccessibleEditableTextPara::GetViewForwarder() const
471 SvxEditSource& rEditSource = GetEditSource();
472 SvxViewForwarder* pViewForwarder = rEditSource.GetViewForwarder();
474 if( !pViewForwarder )
476 throw uno::RuntimeException("Unable to fetch view forwarder, object is defunct",
477 uno::Reference< uno::XInterface >
478 ( static_cast< ::cppu::OWeakObject* >
479 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
482 if( !pViewForwarder->IsValid() )
483 throw uno::RuntimeException("View forwarder is invalid, object is defunct",
484 uno::Reference< uno::XInterface >
485 ( static_cast< ::cppu::OWeakObject* >
486 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
487 return *pViewForwarder;
490 SvxAccessibleTextEditViewAdapter& AccessibleEditableTextPara::GetEditViewForwarder( bool bCreate ) const
492 SvxEditSourceAdapter& rEditSource = GetEditSource();
493 SvxAccessibleTextEditViewAdapter* pTextEditViewForwarder = rEditSource.GetEditViewForwarderAdapter( bCreate );
495 if( !pTextEditViewForwarder )
497 if( bCreate )
498 throw uno::RuntimeException("Unable to fetch view forwarder, object is defunct",
499 uno::Reference< uno::XInterface >
500 ( static_cast< ::cppu::OWeakObject* >
501 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
502 else
503 throw uno::RuntimeException("No view forwarder, object not in edit mode",
504 uno::Reference< uno::XInterface >
505 ( static_cast< ::cppu::OWeakObject* >
506 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
509 if( pTextEditViewForwarder->IsValid() )
510 return *pTextEditViewForwarder;
511 else
513 if( bCreate )
514 throw uno::RuntimeException("View forwarder is invalid, object is defunct",
515 uno::Reference< uno::XInterface >
516 ( static_cast< ::cppu::OWeakObject* >
517 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
518 else
519 throw uno::RuntimeException("View forwarder is invalid, object not in edit mode",
520 uno::Reference< uno::XInterface >
521 ( static_cast< ::cppu::OWeakObject* >
522 ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy
526 bool AccessibleEditableTextPara::HaveEditView() const
528 SvxEditSource& rEditSource = GetEditSource();
529 SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder();
531 if( !pViewForwarder )
532 return false;
534 if( !pViewForwarder->IsValid() )
535 return false;
537 return true;
540 bool AccessibleEditableTextPara::HaveChildren()
542 DBG_ASSERT(GetParagraphIndex() >= 0,
543 "AccessibleEditableTextPara::HaveChildren: paragraph index value overflow");
545 return GetTextForwarder().HaveImageBullet( GetParagraphIndex() );
548 tools::Rectangle AccessibleEditableTextPara::LogicToPixel( const tools::Rectangle& rRect, const MapMode& rMapMode, SvxViewForwarder const & rForwarder )
550 // convert to screen coordinates
551 return tools::Rectangle( rForwarder.LogicToPixel( rRect.TopLeft(), rMapMode ),
552 rForwarder.LogicToPixel( rRect.BottomRight(), rMapMode ) );
556 void AccessibleEditableTextPara::SetEEOffset( const Point& rOffset )
558 auto aChild( maImageBullet.get() );
559 if( aChild.is() )
560 aChild->SetEEOffset(rOffset);
562 maEEOffset = rOffset;
565 void AccessibleEditableTextPara::FireEvent(const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue) const
567 uno::Reference < XAccessibleContext > xThis( const_cast< AccessibleEditableTextPara* > (this)->getAccessibleContext() );
569 AccessibleEventObject aEvent(xThis, nEventId, rNewValue, rOldValue);
571 // #102261# Call global queue for focus events
572 if( nEventId == AccessibleEventId::STATE_CHANGED )
573 vcl::unohelper::NotifyAccessibleStateEventGlobally( aEvent );
575 // #106234# Delegate to EventNotifier
576 if( getNotifierClientId() != -1 )
577 ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(),
578 aEvent );
581 void AccessibleEditableTextPara::SetState( const sal_Int16 nStateId )
583 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
584 if( pStateSet != nullptr &&
585 !pStateSet->contains(nStateId) )
587 pStateSet->AddState( nStateId );
588 FireEvent( AccessibleEventId::STATE_CHANGED, uno::makeAny( nStateId ) );
592 void AccessibleEditableTextPara::UnSetState( const sal_Int16 nStateId )
594 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
595 if( pStateSet != nullptr &&
596 pStateSet->contains(nStateId) )
598 pStateSet->RemoveState( nStateId );
599 FireEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), uno::makeAny( nStateId ) );
603 void AccessibleEditableTextPara::TextChanged()
605 OUString aCurrentString( implGetText() );
606 uno::Any aDeleted;
607 uno::Any aInserted;
608 if( OCommonAccessibleText::implInitTextChangedEvent( maLastTextString, aCurrentString,
609 aDeleted, aInserted) )
611 FireEvent( AccessibleEventId::TEXT_CHANGED, aInserted, aDeleted );
612 maLastTextString = aCurrentString;
616 bool AccessibleEditableTextPara::GetAttributeRun( sal_Int32& nStartIndex, sal_Int32& nEndIndex, sal_Int32 nIndex )
618 DBG_ASSERT(nIndex >= 0,
619 "AccessibleEditableTextPara::GetAttributeRun: index value overflow");
621 DBG_ASSERT(GetParagraphIndex() >= 0,
622 "AccessibleEditableTextPara::getLocale: paragraph index value overflow");
624 return GetTextForwarder().GetAttributeRun( nStartIndex,
625 nEndIndex,
626 GetParagraphIndex(),
627 nIndex );
630 uno::Any SAL_CALL AccessibleEditableTextPara::queryInterface (const uno::Type & rType)
632 uno::Any aRet;
634 // must provide XAccessibleText by hand, since it comes publicly inherited by XAccessibleEditableText
635 if ( rType == cppu::UnoType<XAccessibleText>::get())
637 uno::Reference< XAccessibleText > aAccText = static_cast< XAccessibleEditableText * >(this);
638 aRet <<= aAccText;
640 else if ( rType == cppu::UnoType<XAccessibleEditableText>::get())
642 uno::Reference< XAccessibleEditableText > aAccEditText = this;
643 aRet <<= aAccEditText;
645 else if ( rType == cppu::UnoType<XAccessibleHypertext>::get())
647 uno::Reference< XAccessibleHypertext > aAccHyperText = this;
648 aRet <<= aAccHyperText;
650 else
652 aRet = AccessibleTextParaInterfaceBase::queryInterface(rType);
655 return aRet;
658 // XAccessible
659 uno::Reference< XAccessibleContext > SAL_CALL AccessibleEditableTextPara::getAccessibleContext()
661 // We implement the XAccessibleContext interface in the same object
662 return uno::Reference< XAccessibleContext > ( this );
665 // XAccessibleContext
666 sal_Int32 SAL_CALL AccessibleEditableTextPara::getAccessibleChildCount()
668 SolarMutexGuard aGuard;
670 return HaveChildren() ? 1 : 0;
673 uno::Reference< XAccessible > SAL_CALL AccessibleEditableTextPara::getAccessibleChild( sal_Int32 i )
675 SolarMutexGuard aGuard;
677 if( !HaveChildren() )
678 throw lang::IndexOutOfBoundsException("No children available",
679 uno::Reference< uno::XInterface >
680 ( static_cast< ::cppu::OWeakObject* > (this) ) ); // static_cast: disambiguate hierarchy
682 if( i != 0 )
683 throw lang::IndexOutOfBoundsException("Invalid child index",
684 uno::Reference< uno::XInterface >
685 ( static_cast< ::cppu::OWeakObject* > (this) ) ); // static_cast: disambiguate hierarchy
687 auto aChild( maImageBullet.get() );
689 if( !aChild.is() )
691 // there is no hard reference available, create object then
692 aChild = new AccessibleImageBullet(this);
694 aChild->SetEditSource( &GetEditSource() );
695 aChild->SetParagraphIndex( GetParagraphIndex() );
696 aChild->SetIndexInParent( i );
698 maImageBullet = aChild;
701 return aChild.get();
704 uno::Reference< XAccessible > SAL_CALL AccessibleEditableTextPara::getAccessibleParent()
706 SAL_WARN_IF(!mxParent.is(), "editeng", "AccessibleEditableTextPara::getAccessibleParent: no frontend set, did somebody forgot to call AccessibleTextHelper::SetEventSource()?");
708 return mxParent;
711 sal_Int32 SAL_CALL AccessibleEditableTextPara::getAccessibleIndexInParent()
713 return mnIndexInParent;
716 sal_Int16 SAL_CALL AccessibleEditableTextPara::getAccessibleRole()
718 return AccessibleRole::PARAGRAPH;
721 OUString SAL_CALL AccessibleEditableTextPara::getAccessibleDescription()
723 SolarMutexGuard aGuard;
725 // append first 40 characters from text, or first line, if shorter
726 // (writer takes first sentence here, but that's not supported
727 // from EditEngine)
728 // throws if defunc
729 OUString aLine;
731 if( getCharacterCount() )
732 aLine = getTextAtIndex(0, AccessibleTextType::LINE).SegmentText;
734 // Get the string from the resource for the specified id.
735 OUString sStr(EditResId(RID_SVXSTR_A11Y_PARAGRAPH_DESCRIPTION));
736 OUString sParaIndex = OUString::number(GetParagraphIndex());
737 sStr = sStr.replaceFirst("$(ARG)", sParaIndex);
739 if( aLine.getLength() > MaxDescriptionLen )
741 OUString aCurrWord;
742 sal_Int32 i;
744 // search backward from MaxDescriptionLen for previous word start
745 for( aCurrWord=getTextAtIndex(MaxDescriptionLen, AccessibleTextType::WORD).SegmentText,
746 i=MaxDescriptionLen,
747 aLine=OUString();
748 i>=0;
749 --i )
751 if( getTextAtIndex(i, AccessibleTextType::WORD).SegmentText != aCurrWord )
753 if( i == 0 )
754 // prevent completely empty string
755 aLine = getTextAtIndex(0, AccessibleTextType::WORD).SegmentText;
756 else
757 aLine = getTextRange(0, i);
762 return sStr + aLine;
765 OUString SAL_CALL AccessibleEditableTextPara::getAccessibleName()
767 //See tdf#101003 before implementing a body
768 return OUString();
771 uno::Reference< XAccessibleRelationSet > SAL_CALL AccessibleEditableTextPara::getAccessibleRelationSet()
773 // #i27138# - provide relations CONTENT_FLOWS_FROM
774 // and CONTENT_FLOWS_TO
775 if ( mpParaManager )
777 utl::AccessibleRelationSetHelper* pAccRelSetHelper =
778 new utl::AccessibleRelationSetHelper();
779 sal_Int32 nMyParaIndex( GetParagraphIndex() );
780 // relation CONTENT_FLOWS_FROM
781 if ( nMyParaIndex > 0 &&
782 mpParaManager->IsReferencable( nMyParaIndex - 1 ) )
784 uno::Sequence<uno::Reference<XInterface> > aSequence
785 { static_cast<cppu::OWeakObject *>(mpParaManager->GetChild( nMyParaIndex - 1 ).first.get().get()) };
786 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM,
787 aSequence );
788 pAccRelSetHelper->AddRelation( aAccRel );
791 // relation CONTENT_FLOWS_TO
792 if ( (nMyParaIndex + 1) < mpParaManager->GetNum() &&
793 mpParaManager->IsReferencable( nMyParaIndex + 1 ) )
795 uno::Sequence<uno::Reference<XInterface> > aSequence
796 { static_cast<cppu::OWeakObject *>(mpParaManager->GetChild( nMyParaIndex + 1 ).first.get().get()) };
797 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO,
798 aSequence );
799 pAccRelSetHelper->AddRelation( aAccRel );
802 return pAccRelSetHelper;
804 else
806 // no relations, therefore empty
807 return uno::Reference< XAccessibleRelationSet >();
811 static uno::Sequence< OUString > const & getAttributeNames()
813 static const uno::Sequence<OUString> aNames{
814 "CharColor",
815 "CharContoured",
816 "CharEmphasis",
817 "CharEscapement",
818 "CharFontName",
819 "CharHeight",
820 "CharPosture",
821 "CharShadowed",
822 "CharStrikeout",
823 "CharCaseMap",
824 "CharUnderline",
825 "CharUnderlineColor",
826 "CharWeight",
827 "NumberingLevel",
828 "NumberingRules",
829 "ParaAdjust",
830 "ParaBottomMargin",
831 "ParaFirstLineIndent",
832 "ParaLeftMargin",
833 "ParaLineSpacing",
834 "ParaRightMargin",
835 "ParaTabStops"};
837 return aNames;
840 struct IndexCompare
842 const PropertyValue* pValues;
843 explicit IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {}
844 bool operator() ( sal_Int32 a, sal_Int32 b ) const
846 return pValues[a].Name < pValues[b].Name;
851 namespace
853 OUString GetFieldTypeNameFromField(EFieldInfo const &ree)
855 OUString strFldType;
856 sal_Int32 nFieldType = -1;
857 if (ree.pFieldItem)
859 // So we get a field, check its type now.
860 nFieldType = ree.pFieldItem->GetField()->GetClassId() ;
862 switch (nFieldType)
864 case text::textfield::Type::DATE:
866 const SvxDateField* pDateField = static_cast< const SvxDateField* >(ree.pFieldItem->GetField());
867 if (pDateField)
869 if (pDateField->GetType() == SvxDateType::Fix)
870 strFldType = "date (fixed)";
871 else if (pDateField->GetType() == SvxDateType::Var)
872 strFldType = "date (variable)";
874 break;
876 case text::textfield::Type::PAGE:
877 strFldType = "page-number";
878 break;
879 //support the sheet name & pages fields
880 case text::textfield::Type::PAGES:
881 strFldType = "page-count";
882 break;
883 case text::textfield::Type::TABLE:
884 strFldType = "sheet-name";
885 break;
886 //End
887 case text::textfield::Type::TIME:
888 strFldType = "time";
889 break;
890 case text::textfield::Type::EXTENDED_TIME:
892 const SvxExtTimeField* pTimeField = static_cast< const SvxExtTimeField* >(ree.pFieldItem->GetField());
893 if (pTimeField)
895 if (pTimeField->GetType() == SvxTimeType::Fix)
896 strFldType = "time (fixed)";
897 else if (pTimeField->GetType() == SvxTimeType::Var)
898 strFldType = "time (variable)";
900 break;
902 case text::textfield::Type::AUTHOR:
903 strFldType = "author";
904 break;
905 case text::textfield::Type::EXTENDED_FILE:
906 case text::textfield::Type::DOCINFO_TITLE:
907 strFldType = "file name";
908 break;
909 case text::textfield::Type::DOCINFO_CUSTOM:
910 strFldType = "custom document property";
911 break;
912 default:
913 break;
915 return strFldType;
919 namespace accessibility
921 OUString AccessibleEditableTextPara::GetFieldTypeNameAtIndex(sal_Int32 nIndex)
923 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder();
924 //For field object info
925 sal_Int32 nParaIndex = GetParagraphIndex();
926 sal_Int32 nAllFieldLen = 0;
927 sal_Int32 nField = rCacheTF.GetFieldCount(nParaIndex);
928 for (sal_Int32 j = 0; j < nField; ++j)
930 EFieldInfo ree = rCacheTF.GetFieldInfo(nParaIndex, j);
931 sal_Int32 reeBegin = ree.aPosition.nIndex + nAllFieldLen;
932 sal_Int32 reeEnd = reeBegin + ree.aCurrentText.getLength();
933 nAllFieldLen += (ree.aCurrentText.getLength() - 1);
934 if (nIndex < reeBegin)
935 break;
936 if (nIndex < reeEnd)
937 return GetFieldTypeNameFromField(ree);
939 return OUString();
942 uno::Reference< XAccessibleStateSet > SAL_CALL AccessibleEditableTextPara::getAccessibleStateSet()
944 SolarMutexGuard aGuard;
946 // Create a copy of the state set and return it.
947 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
949 if( !pStateSet )
950 return uno::Reference<XAccessibleStateSet>();
951 uno::Reference<XAccessibleStateSet> xParentStates;
952 if (getAccessibleParent().is())
954 uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
955 xParentStates = xParentContext->getAccessibleStateSet();
957 if (xParentStates.is() && xParentStates->contains(AccessibleStateType::EDITABLE) )
959 pStateSet->AddState(AccessibleStateType::EDITABLE);
961 return uno::Reference<XAccessibleStateSet>( new ::utl::AccessibleStateSetHelper (*pStateSet) );
964 lang::Locale SAL_CALL AccessibleEditableTextPara::getLocale()
966 SolarMutexGuard aGuard;
968 return implGetLocale();
971 void SAL_CALL AccessibleEditableTextPara::addAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
973 if( getNotifierClientId() != -1 )
974 ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener );
977 void SAL_CALL AccessibleEditableTextPara::removeAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
979 if( getNotifierClientId() != -1 )
981 const sal_Int32 nListenerCount = ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener );
982 if ( !nListenerCount )
984 // no listeners anymore
985 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
986 // and at least to us not firing any events anymore, in case somebody calls
987 // NotifyAccessibleEvent, again
988 ::comphelper::AccessibleEventNotifier::TClientId nId( getNotifierClientId() );
989 mnNotifierClientId = -1;
990 ::comphelper::AccessibleEventNotifier::revokeClient( nId );
995 // XAccessibleComponent
996 sal_Bool SAL_CALL AccessibleEditableTextPara::containsPoint( const awt::Point& aTmpPoint )
998 SolarMutexGuard aGuard;
1000 DBG_ASSERT(GetParagraphIndex() >= 0,
1001 "AccessibleEditableTextPara::contains: index value overflow");
1003 awt::Rectangle aTmpRect = getBounds();
1004 tools::Rectangle aRect( Point(aTmpRect.X, aTmpRect.Y), Size(aTmpRect.Width, aTmpRect.Height) );
1005 Point aPoint( aTmpPoint.X, aTmpPoint.Y );
1007 return aRect.IsInside( aPoint );
1010 uno::Reference< XAccessible > SAL_CALL AccessibleEditableTextPara::getAccessibleAtPoint( const awt::Point& _aPoint )
1012 SolarMutexGuard aGuard;
1014 if( HaveChildren() )
1016 // #103862# No longer need to make given position relative
1017 Point aPoint( _aPoint.X, _aPoint.Y );
1019 // respect EditEngine offset to surrounding shape/cell
1020 aPoint -= GetEEOffset();
1022 // convert to EditEngine coordinate system
1023 SvxTextForwarder& rCacheTF = GetTextForwarder();
1024 Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) );
1026 EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo(GetParagraphIndex());
1028 if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND &&
1029 aBulletInfo.bVisible &&
1030 aBulletInfo.nType == SVX_NUM_BITMAP )
1032 tools::Rectangle aRect = aBulletInfo.aBounds;
1034 if( aRect.IsInside( aLogPoint ) )
1035 return getAccessibleChild(0);
1039 // no children at all, or none at given position
1040 return uno::Reference< XAccessible >();
1043 awt::Rectangle SAL_CALL AccessibleEditableTextPara::getBounds()
1045 SolarMutexGuard aGuard;
1047 DBG_ASSERT(GetParagraphIndex() >= 0,
1048 "AccessibleEditableTextPara::getBounds: index value overflow");
1050 SvxTextForwarder& rCacheTF = GetTextForwarder();
1051 tools::Rectangle aRect = rCacheTF.GetParaBounds( GetParagraphIndex() );
1053 // convert to screen coordinates
1054 tools::Rectangle aScreenRect = AccessibleEditableTextPara::LogicToPixel( aRect,
1055 rCacheTF.GetMapMode(),
1056 GetViewForwarder() );
1058 // offset from shape/cell
1059 Point aOffset = GetEEOffset();
1061 return awt::Rectangle( aScreenRect.Left() + aOffset.X(),
1062 aScreenRect.Top() + aOffset.Y(),
1063 aScreenRect.GetSize().Width(),
1064 aScreenRect.GetSize().Height() );
1067 awt::Point SAL_CALL AccessibleEditableTextPara::getLocation( )
1069 SolarMutexGuard aGuard;
1071 awt::Rectangle aRect = getBounds();
1073 return awt::Point( aRect.X, aRect.Y );
1076 awt::Point SAL_CALL AccessibleEditableTextPara::getLocationOnScreen( )
1078 SolarMutexGuard aGuard;
1080 // relate us to parent
1081 uno::Reference< XAccessible > xParent = getAccessibleParent();
1082 if( xParent.is() )
1084 uno::Reference< XAccessibleComponent > xParentComponent( xParent, uno::UNO_QUERY );
1085 if( xParentComponent.is() )
1087 awt::Point aRefPoint = xParentComponent->getLocationOnScreen();
1088 awt::Point aPoint = getLocation();
1089 aPoint.X += aRefPoint.X;
1090 aPoint.Y += aRefPoint.Y;
1092 return aPoint;
1094 // #i88070#
1095 // fallback to parent's <XAccessibleContext> instance
1096 else
1098 uno::Reference< XAccessibleContext > xParentContext = xParent->getAccessibleContext();
1099 if ( xParentContext.is() )
1101 uno::Reference< XAccessibleComponent > xParentContextComponent( xParentContext, uno::UNO_QUERY );
1102 if( xParentContextComponent.is() )
1104 awt::Point aRefPoint = xParentContextComponent->getLocationOnScreen();
1105 awt::Point aPoint = getLocation();
1106 aPoint.X += aRefPoint.X;
1107 aPoint.Y += aRefPoint.Y;
1109 return aPoint;
1115 throw uno::RuntimeException("Cannot access parent",
1116 uno::Reference< uno::XInterface >
1117 ( static_cast< XAccessible* > (this) ) ); // disambiguate hierarchy
1120 awt::Size SAL_CALL AccessibleEditableTextPara::getSize( )
1122 SolarMutexGuard aGuard;
1124 awt::Rectangle aRect = getBounds();
1126 return awt::Size( aRect.Width, aRect.Height );
1129 void SAL_CALL AccessibleEditableTextPara::grabFocus( )
1131 // set cursor to this paragraph
1132 setSelection(0,0);
1135 sal_Int32 SAL_CALL AccessibleEditableTextPara::getForeground( )
1137 // #104444# Added to XAccessibleComponent interface
1138 svtools::ColorConfig aColorConfig;
1139 Color nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
1140 return static_cast<sal_Int32>(nColor);
1143 sal_Int32 SAL_CALL AccessibleEditableTextPara::getBackground( )
1145 // #104444# Added to XAccessibleComponent interface
1146 Color aColor( Application::GetSettings().GetStyleSettings().GetWindowColor() );
1148 // the background is transparent
1149 aColor.SetTransparency( 0xFF);
1151 return static_cast<sal_Int32>( aColor );
1154 // XAccessibleText
1155 sal_Int32 SAL_CALL AccessibleEditableTextPara::getCaretPosition()
1157 SolarMutexGuard aGuard;
1159 if( !HaveEditView() )
1160 return -1;
1162 ESelection aSelection;
1163 if( GetEditViewForwarder().GetSelection( aSelection ) &&
1164 GetParagraphIndex() == aSelection.nEndPara )
1166 // caret is always nEndPara,nEndPos
1167 EBulletInfo aBulletInfo = GetTextForwarder().GetBulletInfo(GetParagraphIndex());
1168 if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND &&
1169 aBulletInfo.bVisible &&
1170 aBulletInfo.nType != SVX_NUM_BITMAP )
1172 sal_Int32 nBulletLen = aBulletInfo.aText.getLength();
1173 if( aSelection.nEndPos - nBulletLen >= 0 )
1174 return aSelection.nEndPos - nBulletLen;
1176 return aSelection.nEndPos;
1179 // not within this paragraph
1180 return -1;
1183 sal_Bool SAL_CALL AccessibleEditableTextPara::setCaretPosition( sal_Int32 nIndex )
1185 return setSelection(nIndex, nIndex);
1188 sal_Unicode SAL_CALL AccessibleEditableTextPara::getCharacter( sal_Int32 nIndex )
1190 SolarMutexGuard aGuard;
1192 DBG_ASSERT(GetParagraphIndex() >= 0,
1193 "AccessibleEditableTextPara::getCharacter: index value overflow");
1195 return OCommonAccessibleText::implGetCharacter( implGetText(), nIndex );
1198 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleEditableTextPara::getCharacterAttributes( sal_Int32 nIndex, const css::uno::Sequence< OUString >& rRequestedAttributes )
1200 SolarMutexGuard aGuard;
1202 //Skip the bullet range to ignore the bullet text
1203 SvxTextForwarder& rCacheTF = GetTextForwarder();
1204 EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo(GetParagraphIndex());
1205 if (aBulletInfo.bVisible)
1206 nIndex += aBulletInfo.aText.getLength();
1207 CheckIndex(nIndex); // may throw IndexOutOfBoundsException
1209 bool bSupplementalMode = false;
1210 uno::Sequence< OUString > aPropertyNames = rRequestedAttributes;
1211 if (!aPropertyNames.hasElements())
1213 bSupplementalMode = true;
1214 aPropertyNames = getAttributeNames();
1217 // get default attributes...
1218 ::comphelper::SequenceAsHashMap aPropHashMap( getDefaultAttributes( aPropertyNames ) );
1220 // ... and override them with the direct attributes from the specific position
1221 const uno::Sequence< beans::PropertyValue > aRunAttribs( getRunAttributes( nIndex, aPropertyNames ) );
1222 for (auto const& rRunAttrib : aRunAttribs)
1224 aPropHashMap[ rRunAttrib.Name ] = rRunAttrib.Value; //!! should not only be the value !!
1227 // get resulting sequence
1228 uno::Sequence< beans::PropertyValue > aRes;
1229 aPropHashMap >> aRes;
1231 // since SequenceAsHashMap ignores property handles and property state
1232 // we have to restore the property state here (property handles are
1233 // of no use to the accessibility API).
1234 for (beans::PropertyValue & rRes : aRes)
1236 bool bIsDirectVal = false;
1237 for (auto const& rRunAttrib : aRunAttribs)
1239 bIsDirectVal = rRes.Name == rRunAttrib.Name;
1240 if (bIsDirectVal)
1241 break;
1243 rRes.Handle = -1;
1244 rRes.State = bIsDirectVal ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
1246 if( bSupplementalMode )
1248 _correctValues( aRes );
1249 // NumberingPrefix
1250 sal_Int32 nRes = aRes.getLength();
1251 aRes.realloc( nRes + 1 );
1252 beans::PropertyValue &rRes = aRes[nRes];
1253 rRes.Name = "NumberingPrefix";
1254 OUString numStr;
1255 if (aBulletInfo.nType != SVX_NUM_CHAR_SPECIAL && aBulletInfo.nType != SVX_NUM_BITMAP)
1256 numStr = aBulletInfo.aText;
1257 rRes.Value <<= numStr;
1258 rRes.Handle = -1;
1259 rRes.State = PropertyState_DIRECT_VALUE;
1260 //For field object.
1261 OUString strFieldType = GetFieldTypeNameAtIndex(nIndex);
1262 if (!strFieldType.isEmpty())
1264 nRes = aRes.getLength();
1265 aRes.realloc( nRes + 1 );
1266 beans::PropertyValue &rResField = aRes[nRes];
1267 rResField.Name = "FieldType";
1268 rResField.Value <<= strFieldType.toAsciiLowerCase();
1269 rResField.Handle = -1;
1270 rResField.State = PropertyState_DIRECT_VALUE;
1272 //sort property values
1273 // build sorted index array
1274 sal_Int32 nLength = aRes.getLength();
1275 const beans::PropertyValue* pPairs = aRes.getConstArray();
1276 std::unique_ptr<sal_Int32[]> pIndices(new sal_Int32[nLength]);
1277 sal_Int32 i = 0;
1278 for( i = 0; i < nLength; i++ )
1279 pIndices[i] = i;
1280 sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
1281 // create sorted sequences according to index array
1282 uno::Sequence<beans::PropertyValue> aNewValues( nLength );
1283 beans::PropertyValue* pNewValues = aNewValues.getArray();
1284 for( i = 0; i < nLength; i++ )
1286 pNewValues[i] = pPairs[pIndices[i]];
1289 return aNewValues;
1291 return aRes;
1294 awt::Rectangle SAL_CALL AccessibleEditableTextPara::getCharacterBounds( sal_Int32 nIndex )
1296 SolarMutexGuard aGuard;
1298 DBG_ASSERT(GetParagraphIndex() >= 0,
1299 "AccessibleEditableTextPara::getCharacterBounds: index value overflow");
1301 // #108900# Have position semantics now for nIndex, as
1302 // one-past-the-end values are legal, too.
1303 CheckPosition( nIndex );
1305 SvxTextForwarder& rCacheTF = GetTextForwarder();
1306 tools::Rectangle aRect = rCacheTF.GetCharBounds(GetParagraphIndex(), nIndex);
1308 // convert to screen
1309 tools::Rectangle aScreenRect = AccessibleEditableTextPara::LogicToPixel( aRect,
1310 rCacheTF.GetMapMode(),
1311 GetViewForwarder() );
1312 // #109864# offset from parent (paragraph), but in screen
1313 // coordinates. This makes sure the internal text offset in
1314 // the outline view forwarder gets cancelled out here
1315 awt::Rectangle aParaRect( getBounds() );
1316 aScreenRect.Move( -aParaRect.X, -aParaRect.Y );
1318 // offset from shape/cell
1319 Point aOffset = GetEEOffset();
1321 return awt::Rectangle( aScreenRect.Left() + aOffset.X(),
1322 aScreenRect.Top() + aOffset.Y(),
1323 aScreenRect.GetSize().Width(),
1324 aScreenRect.GetSize().Height() );
1327 sal_Int32 SAL_CALL AccessibleEditableTextPara::getCharacterCount()
1329 SolarMutexGuard aGuard;
1331 DBG_ASSERT(GetParagraphIndex() >= 0,
1332 "AccessibleEditableTextPara::getCharacterCount: index value overflow");
1334 return implGetText().getLength();
1337 sal_Int32 SAL_CALL AccessibleEditableTextPara::getIndexAtPoint( const awt::Point& rPoint )
1339 SolarMutexGuard aGuard;
1341 sal_Int32 nPara;
1342 sal_Int32 nIndex;
1344 // offset from surrounding cell/shape
1345 Point aOffset( GetEEOffset() );
1346 Point aPoint( rPoint.X - aOffset.X(), rPoint.Y - aOffset.Y() );
1348 // convert to logical coordinates
1349 SvxTextForwarder& rCacheTF = GetTextForwarder();
1350 Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) );
1352 // re-offset to parent (paragraph)
1353 tools::Rectangle aParaRect = rCacheTF.GetParaBounds( GetParagraphIndex() );
1354 aLogPoint.Move( aParaRect.Left(), aParaRect.Top() );
1356 if( rCacheTF.GetIndexAtPoint( aLogPoint, nPara, nIndex ) &&
1357 GetParagraphIndex() == nPara )
1359 // #102259# Double-check if we're _really_ on the given character
1362 awt::Rectangle aRect1( getCharacterBounds(nIndex) );
1363 tools::Rectangle aRect2( aRect1.X, aRect1.Y,
1364 aRect1.Width + aRect1.X, aRect1.Height + aRect1.Y );
1365 if( aRect2.IsInside( Point( rPoint.X, rPoint.Y ) ) )
1366 return nIndex;
1367 else
1368 return -1;
1370 catch (const lang::IndexOutOfBoundsException&)
1372 // #103927# Don't throw for invalid nIndex values
1373 return -1;
1376 else
1378 // not within our paragraph
1379 return -1;
1383 OUString SAL_CALL AccessibleEditableTextPara::getSelectedText()
1385 SolarMutexGuard aGuard;
1387 DBG_ASSERT(GetParagraphIndex() >= 0,
1388 "AccessibleEditableTextPara::getSelectedText: index value overflow");
1390 if( !HaveEditView() )
1391 return OUString();
1393 return OCommonAccessibleText::getSelectedText();
1396 sal_Int32 SAL_CALL AccessibleEditableTextPara::getSelectionStart()
1398 SolarMutexGuard aGuard;
1400 DBG_ASSERT(GetParagraphIndex() >= 0,
1401 "AccessibleEditableTextPara::getSelectionStart: index value overflow");
1403 if( !HaveEditView() )
1404 return -1;
1406 return OCommonAccessibleText::getSelectionStart();
1409 sal_Int32 SAL_CALL AccessibleEditableTextPara::getSelectionEnd()
1411 SolarMutexGuard aGuard;
1413 DBG_ASSERT(GetParagraphIndex() >= 0,
1414 "AccessibleEditableTextPara::getSelectionEnd: index value overflow");
1416 if( !HaveEditView() )
1417 return -1;
1419 return OCommonAccessibleText::getSelectionEnd();
1422 sal_Bool SAL_CALL AccessibleEditableTextPara::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1424 SolarMutexGuard aGuard;
1426 DBG_ASSERT(GetParagraphIndex() >= 0,
1427 "AccessibleEditableTextPara::setSelection: paragraph index value overflow");
1429 CheckRange(nStartIndex, nEndIndex);
1433 SvxEditViewForwarder& rCacheVF = GetEditViewForwarder( true );
1434 return rCacheVF.SetSelection( MakeSelection(nStartIndex, nEndIndex) );
1436 catch (const uno::RuntimeException&)
1438 return false;
1442 OUString SAL_CALL AccessibleEditableTextPara::getText()
1444 SolarMutexGuard aGuard;
1446 DBG_ASSERT(GetParagraphIndex() >= 0,
1447 "AccessibleEditableTextPara::getText: paragraph index value overflow");
1449 return implGetText();
1452 OUString SAL_CALL AccessibleEditableTextPara::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1454 SolarMutexGuard aGuard;
1456 DBG_ASSERT(GetParagraphIndex() >= 0,
1457 "AccessibleEditableTextPara::getTextRange: paragraph index value overflow");
1459 return OCommonAccessibleText::implGetTextRange(implGetText(), nStartIndex, nEndIndex);
1462 void AccessibleEditableTextPara::_correctValues( uno::Sequence< PropertyValue >& rValues)
1464 SvxTextForwarder& rCacheTF = GetTextForwarder();
1465 sal_Int32 nRes = rValues.getLength();
1466 beans::PropertyValue *pRes = rValues.getArray();
1467 for (sal_Int32 i = 0; i < nRes; ++i)
1469 beans::PropertyValue &rRes = pRes[i];
1470 // Char color
1471 if (rRes.Name == "CharColor")
1473 uno::Any &anyChar = rRes.Value;
1474 Color crChar = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
1475 if (COL_AUTO == crChar )
1477 uno::Reference< css::accessibility::XAccessibleComponent > xComponent(mxParent,uno::UNO_QUERY);
1478 if (xComponent.is())
1480 uno::Reference< css::accessibility::XAccessibleContext > xContext(xComponent,uno::UNO_QUERY);
1481 if (xContext->getAccessibleRole() == AccessibleRole::SHAPE
1482 || xContext->getAccessibleRole() == AccessibleRole::TABLE_CELL)
1484 anyChar <<= COL_BLACK;
1486 else
1488 Color cr(xComponent->getBackground());
1489 crChar = cr.IsDark() ? COL_WHITE : COL_BLACK;
1490 anyChar <<= crChar;
1494 continue;
1496 // Underline
1497 if (rRes.Name == "CharUnderline")
1499 continue;
1501 // Underline color && Mis-spell
1502 if (rRes.Name == "CharUnderlineColor")
1504 uno::Any &anyCharUnderLine = rRes.Value;
1505 Color crCharUnderLine = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>( anyCharUnderLine.pReserved));
1506 if (COL_AUTO == crCharUnderLine )
1508 uno::Reference< css::accessibility::XAccessibleComponent > xComponent(mxParent,uno::UNO_QUERY);
1509 if (xComponent.is())
1511 uno::Reference< css::accessibility::XAccessibleContext > xContext(xComponent,uno::UNO_QUERY);
1512 if (xContext->getAccessibleRole() == AccessibleRole::SHAPE
1513 || xContext->getAccessibleRole() == AccessibleRole::TABLE_CELL)
1515 anyCharUnderLine <<= COL_BLACK;
1517 else
1519 Color cr(xComponent->getBackground());
1520 crCharUnderLine = cr.IsDark() ? COL_WHITE : COL_BLACK;
1521 anyCharUnderLine <<= crCharUnderLine;
1525 continue;
1527 // NumberingLevel
1528 if (rRes.Name == "NumberingLevel")
1530 const SvxNumBulletItem& rNumBullet = rCacheTF.GetParaAttribs(GetParagraphIndex()).Get(EE_PARA_NUMBULLET);
1531 if(rNumBullet.GetNumRule()->GetLevelCount()==0)
1533 rRes.Value <<= sal_Int16(-1);
1534 rRes.Handle = -1;
1535 rRes.State = PropertyState_DIRECT_VALUE;
1537 else
1539 // SvxAccessibleTextPropertySet aPropSet( &GetEditSource(),
1540 // ImplGetSvxCharAndParaPropertiesMap() );
1541 // MT IA2 TODO: Check if this is the correct replacement for ImplGetSvxCharAndParaPropertiesMap
1542 rtl::Reference< SvxAccessibleTextPropertySet > xPropSet( new SvxAccessibleTextPropertySet( &GetEditSource(), ImplGetSvxTextPortionSvxPropertySet() ) );
1544 xPropSet->SetSelection( MakeSelection( 0, GetTextLen() ) );
1545 rRes.Value = xPropSet->_getPropertyValue( rRes.Name, mnParagraphIndex );
1546 rRes.State = xPropSet->_getPropertyState( rRes.Name, mnParagraphIndex );
1547 rRes.Handle = -1;
1549 continue;
1551 // NumberingRules
1552 if (rRes.Name == "NumberingRules")
1554 SfxItemSet aAttribs = rCacheTF.GetParaAttribs(GetParagraphIndex());
1555 bool bVis = aAttribs.Get( EE_PARA_BULLETSTATE ).GetValue();
1556 if(bVis)
1558 rRes.Value <<= sal_Int16(-1);
1559 rRes.Handle = -1;
1560 rRes.State = PropertyState_DIRECT_VALUE;
1562 else
1564 // MT IA2 TODO: Check if this is the correct replacement for ImplGetSvxCharAndParaPropertiesMap
1565 rtl::Reference< SvxAccessibleTextPropertySet > xPropSet( new SvxAccessibleTextPropertySet( &GetEditSource(), ImplGetSvxTextPortionSvxPropertySet() ) );
1566 xPropSet->SetSelection( MakeSelection( 0, GetTextLen() ) );
1567 rRes.Value = xPropSet->_getPropertyValue( rRes.Name, mnParagraphIndex );
1568 rRes.State = xPropSet->_getPropertyState( rRes.Name, mnParagraphIndex );
1569 rRes.Handle = -1;
1571 continue;
1575 sal_Int32 AccessibleEditableTextPara::SkipField(sal_Int32 nIndex, bool bForward)
1577 sal_Int32 nParaIndex = GetParagraphIndex();
1578 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder();
1579 sal_Int32 nAllFieldLen = 0;
1580 sal_Int32 nField = rCacheTF.GetFieldCount(nParaIndex), nFoundFieldIndex = -1;
1581 sal_Int32 reeBegin=0, reeEnd=0;
1582 for (sal_Int32 j = 0; j < nField; ++j)
1584 EFieldInfo ree = rCacheTF.GetFieldInfo(nParaIndex, j);
1585 reeBegin = ree.aPosition.nIndex + nAllFieldLen;
1586 reeEnd = reeBegin + ree.aCurrentText.getLength();
1587 nAllFieldLen += (ree.aCurrentText.getLength() - 1);
1588 if (nIndex < reeBegin)
1589 break;
1590 if (!ree.pFieldItem)
1591 continue;
1592 if (nIndex < reeEnd)
1594 if (ree.pFieldItem->GetField()->GetClassId() != text::textfield::Type::URL)
1596 nFoundFieldIndex = j;
1597 break;
1601 if( nFoundFieldIndex >= 0 )
1603 if( bForward )
1604 return reeEnd - 1;
1605 else
1606 return reeBegin;
1608 return nIndex;
1610 void AccessibleEditableTextPara::ExtendByField( css::accessibility::TextSegment& Segment )
1612 sal_Int32 nParaIndex = GetParagraphIndex();
1613 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder();
1614 sal_Int32 nAllFieldLen = 0;
1615 sal_Int32 nField = rCacheTF.GetFieldCount(nParaIndex), nFoundFieldIndex = -1;
1616 sal_Int32 reeBegin=0, reeEnd=0;
1617 for (sal_Int32 j = 0; j < nField; ++j)
1619 EFieldInfo ree = rCacheTF.GetFieldInfo(nParaIndex, j);
1620 reeBegin = ree.aPosition.nIndex + nAllFieldLen;
1621 reeEnd = reeBegin + ree.aCurrentText.getLength();
1622 nAllFieldLen += (ree.aCurrentText.getLength() - 1);
1623 if( reeBegin > Segment.SegmentEnd )
1625 break;
1627 if (!ree.pFieldItem)
1628 continue;
1629 if( (Segment.SegmentEnd > reeBegin && Segment.SegmentEnd <= reeEnd) ||
1630 (Segment.SegmentStart >= reeBegin && Segment.SegmentStart < reeEnd) )
1632 if(ree.pFieldItem->GetField()->GetClassId() != text::textfield::Type::URL)
1634 nFoundFieldIndex = j;
1635 break;
1639 if( nFoundFieldIndex >= 0 )
1641 bool bExtend = false;
1642 if( Segment.SegmentEnd < reeEnd )
1644 Segment.SegmentEnd = reeEnd;
1645 bExtend = true;
1647 if( Segment.SegmentStart > reeBegin )
1649 Segment.SegmentStart = reeBegin;
1650 bExtend = true;
1652 if( bExtend )
1654 //If there is a bullet before the field, should add the bullet length into the segment.
1655 EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo(nParaIndex);
1656 sal_Int32 nBulletLen = aBulletInfo.aText.getLength();
1657 if (nBulletLen > 0)
1659 Segment.SegmentEnd += nBulletLen;
1660 if (nFoundFieldIndex > 0)
1661 Segment.SegmentStart += nBulletLen;
1662 Segment.SegmentText = GetTextRange(Segment.SegmentStart, Segment.SegmentEnd);
1663 //After get the correct field name, should restore the offset value which don't contain the bullet.
1664 Segment.SegmentEnd -= nBulletLen;
1665 if (nFoundFieldIndex > 0)
1666 Segment.SegmentStart -= nBulletLen;
1668 else
1669 Segment.SegmentText = GetTextRange(Segment.SegmentStart, Segment.SegmentEnd);
1674 css::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType )
1676 SolarMutexGuard aGuard;
1678 DBG_ASSERT(GetParagraphIndex() >= 0,
1679 "AccessibleEditableTextPara::getTextAtIndex: paragraph index value overflow");
1681 css::accessibility::TextSegment aResult;
1682 aResult.SegmentStart = -1;
1683 aResult.SegmentEnd = -1;
1685 switch( aTextType )
1687 case AccessibleTextType::CHARACTER:
1688 case AccessibleTextType::WORD:
1690 aResult = OCommonAccessibleText::getTextAtIndex( nIndex, aTextType );
1691 ExtendByField( aResult );
1692 break;
1694 // Not yet handled by OCommonAccessibleText. Missing
1695 // implGetAttributeRunBoundary() method there
1696 case AccessibleTextType::ATTRIBUTE_RUN:
1698 const sal_Int32 nTextLen = GetTextForwarder().GetTextLen( GetParagraphIndex() );
1700 if( nIndex == nTextLen )
1702 // #i17014# Special-casing one-behind-the-end character
1703 aResult.SegmentStart = aResult.SegmentEnd = nTextLen;
1705 else
1707 sal_Int32 nStartIndex, nEndIndex;
1708 //For the bullet paragraph, the bullet string is ignored for IAText::attributes() function.
1709 SvxTextForwarder& rCacheTF = GetTextForwarder();
1710 // MT IA2: Not used? sal_Int32 nBulletLen = 0;
1711 EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo(GetParagraphIndex());
1712 if (aBulletInfo.bVisible)
1713 nIndex += aBulletInfo.aText.getLength();
1714 if (nIndex != 0 && nIndex >= getCharacterCount())
1715 nIndex = getCharacterCount()-1;
1716 CheckPosition(nIndex);
1717 if( GetAttributeRun(nStartIndex, nEndIndex, nIndex) )
1719 aResult.SegmentText = GetTextRange(nStartIndex, nEndIndex);
1720 if (aBulletInfo.bVisible)
1722 nStartIndex -= aBulletInfo.aText.getLength();
1723 nEndIndex -= aBulletInfo.aText.getLength();
1725 aResult.SegmentStart = nStartIndex;
1726 aResult.SegmentEnd = nEndIndex;
1729 break;
1731 case AccessibleTextType::LINE:
1733 SvxTextForwarder& rCacheTF = GetTextForwarder();
1734 sal_Int32 nParaIndex = GetParagraphIndex();
1735 CheckPosition(nIndex);
1736 if (nIndex != 0 && nIndex == getCharacterCount())
1737 --nIndex;
1738 sal_Int32 nLine, nLineCount=rCacheTF.GetLineCount( nParaIndex );
1739 sal_Int32 nCurIndex;
1740 //the problem is that rCacheTF.GetLineLen() will include the bullet length. But for the bullet line,
1741 //the text value doesn't contain the bullet characters. all of the bullet and numbering info are exposed
1742 //by the IAText::attributes(). So here must do special support for bullet line.
1743 sal_Int32 nBulletLen = 0;
1744 for( nLine=0, nCurIndex=0; nLine<nLineCount; ++nLine )
1746 if (nLine == 0)
1748 EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo( nParaIndex );
1749 if (aBulletInfo.bVisible)
1751 //in bullet or numbering;
1752 nBulletLen = aBulletInfo.aText.getLength();
1755 sal_Int32 nLineLen = rCacheTF.GetLineLen(nParaIndex, nLine);
1756 if (nLine == 0)
1757 nCurIndex += nLineLen - nBulletLen;
1758 else
1759 nCurIndex += nLineLen;
1760 if( nCurIndex > nIndex )
1762 if (nLine ==0)
1764 aResult.SegmentStart = 0;
1765 aResult.SegmentEnd = nCurIndex;
1766 aResult.SegmentText = GetTextRange( aResult.SegmentStart, aResult.SegmentEnd + nBulletLen);
1767 break;
1769 else
1771 aResult.SegmentStart = nCurIndex - nLineLen;
1772 aResult.SegmentEnd = nCurIndex;
1773 //aResult.SegmentText = GetTextRange( aResult.SegmentStart, aResult.SegmentEnd );
1774 aResult.SegmentText = GetTextRange( aResult.SegmentStart + nBulletLen, aResult.SegmentEnd + nBulletLen);
1775 break;
1779 break;
1781 default:
1782 aResult = OCommonAccessibleText::getTextAtIndex( nIndex, aTextType );
1783 break;
1784 } /* end of switch( aTextType ) */
1786 return aResult;
1789 css::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType )
1791 SolarMutexGuard aGuard;
1793 DBG_ASSERT(GetParagraphIndex() >= 0,
1794 "AccessibleEditableTextPara::getTextBeforeIndex: paragraph index value overflow");
1796 css::accessibility::TextSegment aResult;
1797 aResult.SegmentStart = -1;
1798 aResult.SegmentEnd = -1;
1799 i18n::Boundary aBoundary;
1800 switch( aTextType )
1802 // Not yet handled by OCommonAccessibleText. Missing
1803 // implGetAttributeRunBoundary() method there
1804 case AccessibleTextType::ATTRIBUTE_RUN:
1806 const sal_Int32 nTextLen = GetTextForwarder().GetTextLen( GetParagraphIndex() );
1807 sal_Int32 nStartIndex, nEndIndex;
1809 if( nIndex == nTextLen )
1811 // #i17014# Special-casing one-behind-the-end character
1812 if( nIndex > 0 &&
1813 GetAttributeRun(nStartIndex, nEndIndex, nIndex-1) )
1815 aResult.SegmentText = GetTextRange(nStartIndex, nEndIndex);
1816 aResult.SegmentStart = nStartIndex;
1817 aResult.SegmentEnd = nEndIndex;
1820 else
1822 if( GetAttributeRun(nStartIndex, nEndIndex, nIndex) )
1824 // already at the left border? If not, query
1825 // one index further left
1826 if( nStartIndex > 0 &&
1827 GetAttributeRun(nStartIndex, nEndIndex, nStartIndex-1) )
1829 aResult.SegmentText = GetTextRange(nStartIndex, nEndIndex);
1830 aResult.SegmentStart = nStartIndex;
1831 aResult.SegmentEnd = nEndIndex;
1835 break;
1837 case AccessibleTextType::LINE:
1839 SvxTextForwarder& rCacheTF = GetTextForwarder();
1840 sal_Int32 nParaIndex = GetParagraphIndex();
1842 CheckPosition(nIndex);
1844 sal_Int32 nLine, nLineCount=rCacheTF.GetLineCount( nParaIndex );
1845 //the problem is that rCacheTF.GetLineLen() will include the bullet length. But for the bullet line,
1846 //the text value doesn't contain the bullet characters. all of the bullet and numbering info are exposed
1847 //by the IAText::attributes(). So here must do special support for bullet line.
1848 sal_Int32 nCurIndex=0, nLastIndex=0, nCurLineLen=0;
1849 sal_Int32 nLastLineLen = 0, nBulletLen = 0;
1850 // get the line before the line the index points into
1851 for( nLine=0, nCurIndex=0, nLastIndex=0; nLine<nLineCount; ++nLine )
1853 nLastIndex = nCurIndex;
1854 if (nLine == 0)
1856 EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo(nParaIndex);
1857 if (aBulletInfo.bVisible)
1859 //in bullet or numbering;
1860 nBulletLen = aBulletInfo.aText.getLength();
1863 if (nLine == 1)
1864 nLastLineLen = nCurLineLen - nBulletLen;
1865 else
1866 nLastLineLen = nCurLineLen;
1867 nCurLineLen = rCacheTF.GetLineLen( nParaIndex, nLine);
1868 //nCurIndex += nCurLineLen;
1869 if (nLine == 0)
1870 nCurIndex += nCurLineLen - nBulletLen;
1871 else
1872 nCurIndex += nCurLineLen;
1874 //if( nCurIndex > nIndex &&
1875 //nLastIndex > nCurLineLen )
1876 if (nCurIndex > nIndex)
1878 if (nLine == 0)
1880 break;
1882 else if (nLine == 1)
1884 aResult.SegmentStart = 0;
1885 aResult.SegmentEnd = nLastIndex;
1886 aResult.SegmentText = GetTextRange( aResult.SegmentStart, aResult.SegmentEnd + nBulletLen);
1887 break;
1889 else
1891 //aResult.SegmentStart = nLastIndex - nCurLineLen;
1892 aResult.SegmentStart = nLastIndex - nLastLineLen;
1893 aResult.SegmentEnd = nLastIndex;
1894 aResult.SegmentText = GetTextRange( aResult.SegmentStart + nBulletLen, aResult.SegmentEnd + nBulletLen);
1895 break;
1900 break;
1902 case AccessibleTextType::WORD:
1904 nIndex = SkipField( nIndex, false);
1905 OUString sText( implGetText() );
1906 sal_Int32 nLength = sText.getLength();
1908 // get word at index
1909 implGetWordBoundary( sText, aBoundary, nIndex );
1912 //sal_Int32 curWordStart = aBoundary.startPos;
1913 //sal_Int32 preWordStart = curWordStart;
1914 sal_Int32 curWordStart , preWordStart;
1915 if( aBoundary.startPos == -1 || aBoundary.startPos > nIndex)
1916 curWordStart = preWordStart = nIndex;
1917 else
1918 curWordStart = preWordStart = aBoundary.startPos;
1920 // get previous word
1922 bool bWord = false;
1924 //while ( preWordStart > 0 && aBoundary.startPos == curWordStart)
1925 while ( (preWordStart >= 0 && !bWord ) || ( aBoundary.endPos > curWordStart ) )
1927 preWordStart--;
1928 bWord = implGetWordBoundary( sText, aBoundary, preWordStart );
1930 if ( bWord && implIsValidBoundary( aBoundary, nLength ) )
1932 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
1933 aResult.SegmentStart = aBoundary.startPos;
1934 aResult.SegmentEnd = aBoundary.endPos;
1935 ExtendByField( aResult );
1938 break;
1939 case AccessibleTextType::CHARACTER:
1941 nIndex = SkipField( nIndex, false);
1942 aResult = OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType );
1943 ExtendByField( aResult );
1944 break;
1946 default:
1947 aResult = OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType );
1948 break;
1949 } /* end of switch( aTextType ) */
1951 return aResult;
1954 css::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType )
1956 SolarMutexGuard aGuard;
1958 DBG_ASSERT(GetParagraphIndex() >= 0,
1959 "AccessibleEditableTextPara::getTextBehindIndex: paragraph index value overflow");
1961 css::accessibility::TextSegment aResult;
1962 aResult.SegmentStart = -1;
1963 aResult.SegmentEnd = -1;
1964 i18n::Boundary aBoundary;
1965 switch( aTextType )
1967 case AccessibleTextType::ATTRIBUTE_RUN:
1969 sal_Int32 nStartIndex, nEndIndex;
1971 if( GetAttributeRun(nStartIndex, nEndIndex, nIndex) )
1973 // already at the right border?
1974 if( nEndIndex < GetTextLen() )
1976 if( GetAttributeRun(nStartIndex, nEndIndex, nEndIndex) )
1978 aResult.SegmentText = GetTextRange(nStartIndex, nEndIndex);
1979 aResult.SegmentStart = nStartIndex;
1980 aResult.SegmentEnd = nEndIndex;
1984 break;
1987 case AccessibleTextType::LINE:
1989 SvxTextForwarder& rCacheTF = GetTextForwarder();
1990 sal_Int32 nParaIndex = GetParagraphIndex();
1992 CheckPosition(nIndex);
1994 sal_Int32 nLine, nLineCount = rCacheTF.GetLineCount( nParaIndex );
1995 sal_Int32 nCurIndex;
1996 //the problem is that rCacheTF.GetLineLen() will include the bullet length. But for the bullet line,
1997 //the text value doesn't contain the bullet characters. all of the bullet and numbering info are exposed
1998 //by the IAText::attributes(). So here must do special support for bullet line.
1999 sal_Int32 nBulletLen = 0;
2000 // get the line after the line the index points into
2001 for( nLine=0, nCurIndex=0; nLine<nLineCount; ++nLine )
2003 if (nLine == 0)
2005 EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo(nParaIndex);
2006 if (aBulletInfo.bVisible)
2008 //in bullet or numbering;
2009 nBulletLen = aBulletInfo.aText.getLength();
2012 sal_Int32 nLineLen = rCacheTF.GetLineLen( nParaIndex, nLine);
2014 if (nLine == 0)
2015 nCurIndex += nLineLen - nBulletLen;
2016 else
2017 nCurIndex += nLineLen;
2019 if( nCurIndex > nIndex &&
2020 nLine < nLineCount-1 )
2022 aResult.SegmentStart = nCurIndex;
2023 aResult.SegmentEnd = nCurIndex + rCacheTF.GetLineLen( nParaIndex, nLine+1);
2024 aResult.SegmentText = GetTextRange( aResult.SegmentStart + nBulletLen, aResult.SegmentEnd + nBulletLen);
2025 break;
2029 break;
2031 case AccessibleTextType::WORD:
2033 nIndex = SkipField( nIndex, true);
2034 OUString sText( implGetText() );
2035 sal_Int32 nLength = sText.getLength();
2037 // get word at index
2038 bool bWord = implGetWordBoundary( sText, aBoundary, nIndex );
2040 // real current world
2041 sal_Int32 nextWord = nIndex;
2042 //if( nIndex >= aBoundary.startPos && nIndex <= aBoundary.endPos )
2043 if( nIndex <= aBoundary.endPos )
2045 nextWord = aBoundary.endPos;
2046 if (nextWord < sText.getLength() && sText[nextWord] == u' ') nextWord++;
2047 bWord = implGetWordBoundary( sText, aBoundary, nextWord );
2050 if ( bWord && implIsValidBoundary( aBoundary, nLength ) )
2052 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
2053 aResult.SegmentStart = aBoundary.startPos;
2054 aResult.SegmentEnd = aBoundary.endPos;
2056 // If the end position of aBoundary is inside a field, extend the result to the end of the field
2058 ExtendByField( aResult );
2061 break;
2063 case AccessibleTextType::CHARACTER:
2065 nIndex = SkipField( nIndex, true);
2066 aResult = OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType );
2067 ExtendByField( aResult );
2068 break;
2070 default:
2071 aResult = OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType );
2072 break;
2073 } /* end of switch( aTextType ) */
2075 return aResult;
2078 sal_Bool SAL_CALL AccessibleEditableTextPara::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2080 SolarMutexGuard aGuard;
2084 SvxEditViewForwarder& rCacheVF = GetEditViewForwarder( true );
2085 GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
2087 bool aRetVal;
2089 DBG_ASSERT(GetParagraphIndex() >= 0,
2090 "AccessibleEditableTextPara::copyText: index value overflow");
2092 CheckRange(nStartIndex, nEndIndex);
2094 //Because bullet may occupy one or more characters, the TextAdapter will include bullet to calculate the selection. Add offset to handle bullet
2095 sal_Int32 nBulletLen = 0;
2096 EBulletInfo aBulletInfo = GetTextForwarder().GetBulletInfo(GetParagraphIndex());
2097 if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && aBulletInfo.bVisible )
2098 nBulletLen = aBulletInfo.aText.getLength();
2099 // save current selection
2100 ESelection aOldSelection;
2102 rCacheVF.GetSelection( aOldSelection );
2103 //rCacheVF.SetSelection( MakeSelection(nStartIndex, nEndIndex) );
2104 rCacheVF.SetSelection( MakeSelection(nStartIndex + nBulletLen, nEndIndex + nBulletLen) );
2105 aRetVal = rCacheVF.Copy();
2106 rCacheVF.SetSelection( aOldSelection ); // restore
2108 return aRetVal;
2110 catch (const uno::RuntimeException&)
2112 return false;
2116 // XAccessibleEditableText
2117 sal_Bool SAL_CALL AccessibleEditableTextPara::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2120 SolarMutexGuard aGuard;
2124 SvxEditViewForwarder& rCacheVF = GetEditViewForwarder( true );
2125 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
2127 DBG_ASSERT(GetParagraphIndex() >= 0,
2128 "AccessibleEditableTextPara::cutText: index value overflow");
2130 CheckRange(nStartIndex, nEndIndex);
2132 // Because bullet may occupy one or more characters, the TextAdapter will include bullet to calculate the selection. Add offset to handle bullet
2133 sal_Int32 nBulletLen = 0;
2134 EBulletInfo aBulletInfo = GetTextForwarder().GetBulletInfo(GetParagraphIndex());
2135 if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && aBulletInfo.bVisible )
2136 nBulletLen = aBulletInfo.aText.getLength();
2137 ESelection aSelection = MakeSelection (nStartIndex + nBulletLen, nEndIndex + nBulletLen);
2138 //if( !rCacheTF.IsEditable( MakeSelection(nStartIndex, nEndIndex) ) )
2139 if( !rCacheTF.IsEditable( aSelection ) )
2140 return false; // non-editable area selected
2142 // don't save selection, might become invalid after cut!
2143 //rCacheVF.SetSelection( MakeSelection(nStartIndex, nEndIndex) );
2144 rCacheVF.SetSelection( aSelection );
2146 return rCacheVF.Cut();
2148 catch (const uno::RuntimeException&)
2150 return false;
2154 sal_Bool SAL_CALL AccessibleEditableTextPara::pasteText( sal_Int32 nIndex )
2157 SolarMutexGuard aGuard;
2161 SvxEditViewForwarder& rCacheVF = GetEditViewForwarder( true );
2162 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
2164 DBG_ASSERT(GetParagraphIndex() >= 0,
2165 "AccessibleEditableTextPara::pasteText: index value overflow");
2167 CheckPosition(nIndex);
2169 // Because bullet may occupy one or more characters, the TextAdapter will include bullet to calculate the selection. Add offset to handle bullet
2170 sal_Int32 nBulletLen = 0;
2171 EBulletInfo aBulletInfo = GetTextForwarder().GetBulletInfo(GetParagraphIndex());
2172 if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && aBulletInfo.bVisible )
2173 nBulletLen = aBulletInfo.aText.getLength();
2174 if( !rCacheTF.IsEditable( MakeSelection(nIndex + nBulletLen) ) )
2175 return false; // non-editable area selected
2177 // #104400# set empty selection (=> cursor) to given index
2178 //rCacheVF.SetSelection( MakeCursor(nIndex) );
2179 rCacheVF.SetSelection( MakeCursor(nIndex + nBulletLen) );
2181 return rCacheVF.Paste();
2183 catch (const uno::RuntimeException&)
2185 return false;
2189 sal_Bool SAL_CALL AccessibleEditableTextPara::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2192 SolarMutexGuard aGuard;
2196 // #102710# Request edit view when doing changes
2197 // AccessibleEmptyEditSource relies on this behaviour
2198 GetEditViewForwarder( true );
2199 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
2201 DBG_ASSERT(GetParagraphIndex() >= 0,
2202 "AccessibleEditableTextPara::deleteText: index value overflow");
2204 CheckRange(nStartIndex, nEndIndex);
2206 // Because bullet may occupy one or more characters, the TextAdapter will include bullet to calculate the selection. Add offset to handle bullet
2207 sal_Int32 nBulletLen = 0;
2208 EBulletInfo aBulletInfo = GetTextForwarder().GetBulletInfo(GetParagraphIndex());
2209 if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && aBulletInfo.bVisible )
2210 nBulletLen = aBulletInfo.aText.getLength();
2211 ESelection aSelection = MakeSelection (nStartIndex + nBulletLen, nEndIndex + nBulletLen);
2213 //if( !rCacheTF.IsEditable( MakeSelection(nStartIndex, nEndIndex) ) )
2214 if( !rCacheTF.IsEditable( aSelection ) )
2215 return false; // non-editable area selected
2217 //sal_Bool bRet = rCacheTF.Delete( MakeSelection(nStartIndex, nEndIndex) );
2218 bool bRet = rCacheTF.Delete( aSelection );
2220 GetEditSource().UpdateData();
2222 return bRet;
2224 catch (const uno::RuntimeException&)
2226 return false;
2230 sal_Bool SAL_CALL AccessibleEditableTextPara::insertText( const OUString& sText, sal_Int32 nIndex )
2233 SolarMutexGuard aGuard;
2237 // #102710# Request edit view when doing changes
2238 // AccessibleEmptyEditSource relies on this behaviour
2239 GetEditViewForwarder( true );
2240 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
2242 DBG_ASSERT(GetParagraphIndex() >= 0,
2243 "AccessibleEditableTextPara::insertText: index value overflow");
2245 CheckPosition(nIndex);
2247 // Because bullet may occupy one or more characters, the TextAdapter will include bullet to calculate the selection. Add offset to handle bullet
2248 sal_Int32 nBulletLen = 0;
2249 EBulletInfo aBulletInfo = GetTextForwarder().GetBulletInfo(GetParagraphIndex());
2250 if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && aBulletInfo.bVisible )
2251 nBulletLen = aBulletInfo.aText.getLength();
2253 if( !rCacheTF.IsEditable( MakeSelection(nIndex + nBulletLen) ) )
2254 return false; // non-editable area selected
2256 // #104400# insert given text at empty selection (=> cursor)
2257 bool bRet = rCacheTF.InsertText( sText, MakeCursor(nIndex + nBulletLen) );
2259 rCacheTF.QuickFormatDoc();
2260 GetEditSource().UpdateData();
2262 return bRet;
2264 catch (const uno::RuntimeException&)
2266 return false;
2270 sal_Bool SAL_CALL AccessibleEditableTextPara::replaceText( sal_Int32 nStartIndex, sal_Int32 nEndIndex, const OUString& sReplacement )
2273 SolarMutexGuard aGuard;
2277 // #102710# Request edit view when doing changes
2278 // AccessibleEmptyEditSource relies on this behaviour
2279 GetEditViewForwarder( true );
2280 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
2282 DBG_ASSERT(GetParagraphIndex() >= 0,
2283 "AccessibleEditableTextPara::replaceText: index value overflow");
2285 CheckRange(nStartIndex, nEndIndex);
2287 // Because bullet may occupy one or more characters, the TextAdapter will include bullet to calculate the selection. Add offset to handle bullet
2288 sal_Int32 nBulletLen = 0;
2289 EBulletInfo aBulletInfo = GetTextForwarder().GetBulletInfo(GetParagraphIndex());
2290 if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && aBulletInfo.bVisible )
2291 nBulletLen = aBulletInfo.aText.getLength();
2292 ESelection aSelection = MakeSelection (nStartIndex + nBulletLen, nEndIndex + nBulletLen);
2294 //if( !rCacheTF.IsEditable( MakeSelection(nStartIndex, nEndIndex) ) )
2295 if( !rCacheTF.IsEditable( aSelection ) )
2296 return false; // non-editable area selected
2298 // insert given text into given range => replace
2299 //sal_Bool bRet = rCacheTF.InsertText( sReplacement, MakeSelection(nStartIndex, nEndIndex) );
2300 bool bRet = rCacheTF.InsertText( sReplacement, aSelection );
2302 rCacheTF.QuickFormatDoc();
2303 GetEditSource().UpdateData();
2305 return bRet;
2307 catch (const uno::RuntimeException&)
2309 return false;
2313 sal_Bool SAL_CALL AccessibleEditableTextPara::setAttributes( sal_Int32 nStartIndex, sal_Int32 nEndIndex, const uno::Sequence< beans::PropertyValue >& aAttributeSet )
2316 SolarMutexGuard aGuard;
2320 // #102710# Request edit view when doing changes
2321 // AccessibleEmptyEditSource relies on this behaviour
2322 GetEditViewForwarder( true );
2323 SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
2324 sal_Int32 nPara = GetParagraphIndex();
2326 DBG_ASSERT(GetParagraphIndex() >= 0,
2327 "AccessibleEditableTextPara::setAttributes: index value overflow");
2329 CheckRange(nStartIndex, nEndIndex);
2331 if( !rCacheTF.IsEditable( MakeSelection(nStartIndex, nEndIndex) ) )
2332 return false; // non-editable area selected
2334 // do the indices span the whole paragraph? Then use the outliner map
2335 // TODO: hold it as a member?
2336 rtl::Reference< SvxAccessibleTextPropertySet > xPropSet( new SvxAccessibleTextPropertySet( &GetEditSource(),
2337 0 == nStartIndex &&
2338 rCacheTF.GetTextLen(nPara) == nEndIndex ?
2339 ImplGetSvxUnoOutlinerTextCursorSvxPropertySet() :
2340 ImplGetSvxTextPortionSvxPropertySet() ) );
2342 xPropSet->SetSelection( MakeSelection(nStartIndex, nEndIndex) );
2344 // convert from PropertyValue to Any
2345 for(const beans::PropertyValue& rProp : aAttributeSet)
2349 xPropSet->setPropertyValue(rProp.Name, rProp.Value);
2351 catch (const uno::Exception&)
2353 OSL_FAIL("AccessibleEditableTextPara::setAttributes exception in setPropertyValue");
2357 rCacheTF.QuickFormatDoc();
2358 GetEditSource().UpdateData();
2360 return true;
2362 catch (const uno::RuntimeException&)
2364 return false;
2368 sal_Bool SAL_CALL AccessibleEditableTextPara::setText( const OUString& sText )
2371 SolarMutexGuard aGuard;
2373 return replaceText(0, getCharacterCount(), sText);
2376 // XAccessibleTextAttributes
2377 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleEditableTextPara::getDefaultAttributes(
2378 const uno::Sequence< OUString >& rRequestedAttributes )
2380 SolarMutexGuard aGuard;
2382 GetTextForwarder();
2384 DBG_ASSERT(GetParagraphIndex() >= 0,
2385 "AccessibleEditableTextPara::getCharacterAttributes: index value overflow");
2387 // get XPropertySetInfo for paragraph attributes and
2388 // character attributes that span all the paragraphs text.
2389 rtl::Reference< SvxAccessibleTextPropertySet > xPropSet( new SvxAccessibleTextPropertySet( &GetEditSource(),
2390 ImplGetSvxCharAndParaPropertiesSet() ) );
2391 xPropSet->SetSelection( MakeSelection( 0, GetTextLen() ) );
2392 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
2393 if (!xPropSetInfo.is())
2394 throw uno::RuntimeException("Cannot query XPropertySetInfo",
2395 uno::Reference< uno::XInterface >
2396 ( static_cast< XAccessible* > (this) ) ); // disambiguate hierarchy
2398 // build sequence of available properties to check
2399 uno::Sequence< beans::Property > aProperties;
2400 if (const sal_Int32 nLenReqAttr = rRequestedAttributes.getLength())
2402 aProperties.realloc( nLenReqAttr );
2403 beans::Property *pProperties = aProperties.getArray();
2404 sal_Int32 nCurLen = 0;
2405 for (const OUString& rRequestedAttribute : rRequestedAttributes)
2407 beans::Property aProp;
2410 aProp = xPropSetInfo->getPropertyByName( rRequestedAttribute );
2412 catch (const beans::UnknownPropertyException&)
2414 continue;
2416 pProperties[ nCurLen++ ] = aProp;
2418 aProperties.realloc( nCurLen );
2420 else
2421 aProperties = xPropSetInfo->getProperties();
2423 // build resulting sequence
2424 uno::Sequence< beans::PropertyValue > aOutSequence( aProperties.getLength() );
2425 beans::PropertyValue* pOutSequence = aOutSequence.getArray();
2426 sal_Int32 nOutLen = 0;
2427 for (const beans::Property& rProperty : std::as_const(aProperties))
2429 // calling implementation functions:
2430 // _getPropertyState and _getPropertyValue (see below) to provide
2431 // the proper paragraph number when retrieving paragraph attributes
2432 PropertyState eState = xPropSet->_getPropertyState( rProperty.Name, mnParagraphIndex );
2433 if ( eState == PropertyState_AMBIGUOUS_VALUE )
2435 OSL_FAIL( "ambiguous property value encountered" );
2438 //if (eState == PropertyState_DIRECT_VALUE)
2439 // per definition all paragraph properties and all character
2440 // properties spanning the whole paragraph should be returned
2441 // and declared as default value
2443 pOutSequence->Name = rProperty.Name;
2444 pOutSequence->Handle = rProperty.Handle;
2445 pOutSequence->Value = xPropSet->_getPropertyValue( rProperty.Name, mnParagraphIndex );
2446 pOutSequence->State = PropertyState_DEFAULT_VALUE;
2448 ++pOutSequence;
2449 ++nOutLen;
2452 aOutSequence.realloc( nOutLen );
2454 return aOutSequence;
2458 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleEditableTextPara::getRunAttributes(
2459 sal_Int32 nIndex,
2460 const uno::Sequence< OUString >& rRequestedAttributes )
2463 SolarMutexGuard aGuard;
2465 GetTextForwarder();
2467 DBG_ASSERT(GetParagraphIndex() >= 0,
2468 "AccessibleEditableTextPara::getCharacterAttributes: index value overflow");
2470 if( getCharacterCount() > 0 )
2471 CheckIndex(nIndex);
2472 else
2473 CheckPosition(nIndex);
2475 rtl::Reference< SvxAccessibleTextPropertySet > xPropSet( new SvxAccessibleTextPropertySet( &GetEditSource(),
2476 ImplGetSvxCharAndParaPropertiesSet() ) );
2477 xPropSet->SetSelection( MakeSelection( nIndex ) );
2478 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
2479 if (!xPropSetInfo.is())
2480 throw uno::RuntimeException("Cannot query XPropertySetInfo",
2481 uno::Reference< uno::XInterface >
2482 ( static_cast< XAccessible* > (this) ) ); // disambiguate hierarchy
2484 // build sequence of available properties to check
2485 uno::Sequence< beans::Property > aProperties;
2486 if (const sal_Int32 nLenReqAttr = rRequestedAttributes.getLength())
2488 aProperties.realloc( nLenReqAttr );
2489 beans::Property *pProperties = aProperties.getArray();
2490 sal_Int32 nCurLen = 0;
2491 for (const OUString& rRequestedAttribute : rRequestedAttributes)
2493 beans::Property aProp;
2496 aProp = xPropSetInfo->getPropertyByName( rRequestedAttribute );
2498 catch (const beans::UnknownPropertyException&)
2500 continue;
2502 pProperties[ nCurLen++ ] = aProp;
2504 aProperties.realloc( nCurLen );
2506 else
2507 aProperties = xPropSetInfo->getProperties();
2509 // build resulting sequence
2510 uno::Sequence< beans::PropertyValue > aOutSequence( aProperties.getLength() );
2511 beans::PropertyValue* pOutSequence = aOutSequence.getArray();
2512 sal_Int32 nOutLen = 0;
2513 for (const beans::Property& rProperty : std::as_const(aProperties))
2515 // calling 'regular' functions that will operate on the selection
2516 PropertyState eState = xPropSet->getPropertyState( rProperty.Name );
2517 if (eState == PropertyState_DIRECT_VALUE)
2519 pOutSequence->Name = rProperty.Name;
2520 pOutSequence->Handle = rProperty.Handle;
2521 pOutSequence->Value = xPropSet->getPropertyValue( rProperty.Name );
2522 pOutSequence->State = eState;
2524 ++pOutSequence;
2525 ++nOutLen;
2528 aOutSequence.realloc( nOutLen );
2530 return aOutSequence;
2533 // XAccessibleHypertext
2534 ::sal_Int32 SAL_CALL AccessibleEditableTextPara::getHyperLinkCount( )
2536 SvxAccessibleTextAdapter& rT = GetTextForwarder();
2537 const sal_Int32 nPara = GetParagraphIndex();
2539 sal_Int32 nHyperLinks = 0;
2540 sal_Int32 nFields = rT.GetFieldCount( nPara );
2541 for (sal_Int32 n = 0; n < nFields; ++n)
2543 EFieldInfo aField = rT.GetFieldInfo( nPara, n );
2544 if ( dynamic_cast<const SvxURLField* >(aField.pFieldItem->GetField() ) != nullptr)
2545 nHyperLinks++;
2547 return nHyperLinks;
2550 css::uno::Reference< css::accessibility::XAccessibleHyperlink > SAL_CALL AccessibleEditableTextPara::getHyperLink( ::sal_Int32 nLinkIndex )
2552 css::uno::Reference< css::accessibility::XAccessibleHyperlink > xRef;
2554 SvxAccessibleTextAdapter& rT = GetTextForwarder();
2555 const sal_Int32 nPara = GetParagraphIndex();
2557 sal_Int32 nHyperLink = 0;
2558 sal_Int32 nFields = rT.GetFieldCount( nPara );
2559 for (sal_Int32 n = 0; n < nFields; ++n)
2561 EFieldInfo aField = rT.GetFieldInfo( nPara, n );
2562 if ( dynamic_cast<const SvxURLField* >(aField.pFieldItem->GetField()) != nullptr )
2564 if ( nHyperLink == nLinkIndex )
2566 sal_Int32 nEEStart = aField.aPosition.nIndex;
2568 // Translate EE Index to accessible index
2569 sal_Int32 nStart = rT.CalcEditEngineIndex( nPara, nEEStart );
2570 sal_Int32 nEnd = nStart + aField.aCurrentText.getLength();
2571 xRef = new AccessibleHyperlink( rT, new SvxFieldItem( *aField.pFieldItem ), nStart, nEnd, aField.aCurrentText );
2572 break;
2574 nHyperLink++;
2578 return xRef;
2581 ::sal_Int32 SAL_CALL AccessibleEditableTextPara::getHyperLinkIndex( ::sal_Int32 nCharIndex )
2583 const sal_Int32 nPara = GetParagraphIndex();
2584 SvxAccessibleTextAdapter& rT = GetTextForwarder();
2586 const sal_Int32 nEEIndex = rT.CalcEditEngineIndex( nPara, nCharIndex );
2587 sal_Int32 nHLIndex = -1; //i123620
2588 sal_Int32 nHyperLink = 0;
2589 sal_Int32 nFields = rT.GetFieldCount( nPara );
2590 for (sal_Int32 n = 0; n < nFields; ++n)
2592 EFieldInfo aField = rT.GetFieldInfo( nPara, n );
2593 if ( dynamic_cast<const SvxURLField* >( aField.pFieldItem->GetField() ) != nullptr)
2595 if ( aField.aPosition.nIndex == nEEIndex )
2597 nHLIndex = nHyperLink;
2598 break;
2600 nHyperLink++;
2604 return nHLIndex;
2607 // XAccessibleMultiLineText
2608 sal_Int32 SAL_CALL AccessibleEditableTextPara::getLineNumberAtIndex( sal_Int32 nIndex )
2611 sal_Int32 nRes = -1;
2612 sal_Int32 nPara = GetParagraphIndex();
2614 SvxTextForwarder &rCacheTF = GetTextForwarder();
2615 const bool bValidPara = 0 <= nPara && nPara < rCacheTF.GetParagraphCount();
2616 DBG_ASSERT( bValidPara, "getLineNumberAtIndex: current paragraph index out of range" );
2617 if (bValidPara)
2619 // we explicitly allow for the index to point at the character right behind the text
2620 if (0 > nIndex || nIndex > rCacheTF.GetTextLen( nPara ))
2621 throw lang::IndexOutOfBoundsException();
2622 nRes = rCacheTF.GetLineNumberAtIndex( nPara, nIndex );
2624 return nRes;
2627 // XAccessibleMultiLineText
2628 css::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextAtLineNumber( sal_Int32 nLineNo )
2631 css::accessibility::TextSegment aResult;
2632 sal_Int32 nPara = GetParagraphIndex();
2633 SvxTextForwarder &rCacheTF = GetTextForwarder();
2634 const bool bValidPara = 0 <= nPara && nPara < rCacheTF.GetParagraphCount();
2635 DBG_ASSERT( bValidPara, "getTextAtLineNumber: current paragraph index out of range" );
2636 if (bValidPara)
2638 if (0 > nLineNo || nLineNo >= rCacheTF.GetLineCount( nPara ))
2639 throw lang::IndexOutOfBoundsException();
2640 sal_Int32 nStart = 0, nEnd = 0;
2641 rCacheTF.GetLineBoundaries( nStart, nEnd, nPara, nLineNo );
2642 if (nStart >= 0 && nEnd >= 0)
2646 aResult.SegmentText = getTextRange( nStart, nEnd );
2647 aResult.SegmentStart = nStart;
2648 aResult.SegmentEnd = nEnd;
2650 catch (const lang::IndexOutOfBoundsException&)
2652 // this is not the exception that should be raised in this function ...
2653 DBG_UNHANDLED_EXCEPTION("editeng");
2657 return aResult;
2660 // XAccessibleMultiLineText
2661 css::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextAtLineWithCaret( )
2664 css::accessibility::TextSegment aResult;
2667 aResult = getTextAtLineNumber( getNumberOfLineWithCaret() );
2669 catch (const lang::IndexOutOfBoundsException&)
2671 // this one needs to be caught since this interface does not allow for it.
2673 return aResult;
2676 // XAccessibleMultiLineText
2677 sal_Int32 SAL_CALL AccessibleEditableTextPara::getNumberOfLineWithCaret( )
2680 sal_Int32 nRes = -1;
2683 nRes = getLineNumberAtIndex( getCaretPosition() );
2685 catch (const lang::IndexOutOfBoundsException&)
2687 // this one needs to be caught since this interface does not allow for it.
2689 return nRes;
2693 // XServiceInfo
2694 OUString SAL_CALL AccessibleEditableTextPara::getImplementationName()
2697 return "AccessibleEditableTextPara";
2700 sal_Bool SAL_CALL AccessibleEditableTextPara::supportsService (const OUString& sServiceName)
2703 return cppu::supportsService(this, sServiceName);
2706 uno::Sequence< OUString> SAL_CALL AccessibleEditableTextPara::getSupportedServiceNames()
2708 // #105185# Using correct service now
2709 return { OUString("com.sun.star.text.AccessibleParagraphView") };
2712 } // end of namespace accessibility
2715 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */