1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <standard/vclxaccessibleedit.hxx>
22 #include <toolkit/awt/vclxwindows.hxx>
23 #include <toolkit/helper/convert.hxx>
25 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/accessibility/AccessibleRole.hpp>
28 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
29 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
30 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
31 #include <comphelper/accessiblecontexthelper.hxx>
32 #include <comphelper/string.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/window.hxx>
35 #include <vcl/mnemonic.hxx>
36 #include <vcl/settings.hxx>
37 #include <vcl/toolkit/edit.hxx>
38 #include <vcl/toolkit/vclmedit.hxx>
39 #include <vcl/textdata.hxx>
40 #include <vcl/txtattr.hxx>
41 #include <vcl/xtextedt.hxx>
42 #include <sot/exchange.hxx>
43 #include <sot/formats.hxx>
47 using namespace ::com::sun::star
;
48 using namespace ::com::sun::star::uno
;
49 using namespace ::com::sun::star::lang
;
50 using namespace ::com::sun::star::beans
;
51 using namespace ::com::sun::star::accessibility
;
52 using namespace ::comphelper
;
58 VCLXAccessibleEdit::VCLXAccessibleEdit( VCLXWindow
* pVCLWindow
)
59 :ImplInheritanceHelper( pVCLWindow
)
61 m_nCaretPosition
= getCaretPosition();
65 void VCLXAccessibleEdit::ProcessWindowEvent( const VclWindowEvent
& rVclWindowEvent
)
67 switch ( rVclWindowEvent
.GetId() )
69 case VclEventId::EditModify
:
71 SetText( implGetText() );
74 case VclEventId::EditCaretChanged
:
76 sal_Int32 nOldCaretPosition
= m_nCaretPosition
;
77 m_nCaretPosition
= getCaretPosition();
79 VclPtr
<vcl::Window
> pWindow
= GetWindow();
80 if (pWindow
&& pWindow
->HasChildPathFocus())
82 if (m_nCaretPosition
!= nOldCaretPosition
)
84 Any aOldValue
, aNewValue
;
85 aOldValue
<<= nOldCaretPosition
;
86 aNewValue
<<= m_nCaretPosition
;
87 NotifyAccessibleEvent( AccessibleEventId::CARET_CHANGED
, aOldValue
, aNewValue
);
92 case VclEventId::EditSelectionChanged
:
94 VclPtr
<vcl::Window
> pWindow
= GetWindow();
95 if (pWindow
&& pWindow
->HasChildPathFocus())
97 NotifyAccessibleEvent( AccessibleEventId::TEXT_SELECTION_CHANGED
, Any(), Any() );
102 VCLXAccessibleTextComponent::ProcessWindowEvent( rVclWindowEvent
);
107 void VCLXAccessibleEdit::FillAccessibleStateSet( sal_Int64
& rStateSet
)
109 VCLXAccessibleTextComponent::FillAccessibleStateSet( rStateSet
);
111 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
114 rStateSet
|= AccessibleStateType::FOCUSABLE
;
115 rStateSet
|= AccessibleStateType::SINGLE_LINE
;
116 if ( pVCLXEdit
->isEditable() )
117 rStateSet
|= AccessibleStateType::EDITABLE
;
122 // OCommonAccessibleText
125 OUString
VCLXAccessibleEdit::implGetText()
129 VclPtr
< Edit
> pEdit
= GetAs
< Edit
>();
132 aText
= removeMnemonicFromString( pEdit
->GetText() );
134 if ( implGetAccessibleRole() == AccessibleRole::PASSWORD_TEXT
)
136 sal_Unicode cEchoChar
= pEdit
->GetEchoChar();
139 OUStringBuffer
sTmp(aText
.getLength());
140 aText
= comphelper::string::padToLength(sTmp
, aText
.getLength(),
141 cEchoChar
).makeStringAndClear();
149 void VCLXAccessibleEdit::implGetSelection( sal_Int32
& nStartIndex
, sal_Int32
& nEndIndex
)
151 awt::Selection aSelection
;
152 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
154 aSelection
= pVCLXEdit
->getSelection();
156 nStartIndex
= aSelection
.Min
;
157 nEndIndex
= aSelection
.Max
;
164 OUString
VCLXAccessibleEdit::getImplementationName()
166 return "com.sun.star.comp.toolkit.AccessibleEdit";
170 Sequence
< OUString
> VCLXAccessibleEdit::getSupportedServiceNames()
172 return { "com.sun.star.awt.AccessibleEdit" };
176 // XAccessibleContext
179 sal_Int64
VCLXAccessibleEdit::getAccessibleChildCount()
181 OExternalLockGuard
aGuard( this );
187 Reference
< XAccessible
> VCLXAccessibleEdit::getAccessibleChild( sal_Int64
)
189 throw IndexOutOfBoundsException();
193 sal_Int16
VCLXAccessibleEdit::getAccessibleRole( )
195 OExternalLockGuard
aGuard( this );
197 return implGetAccessibleRole();
200 sal_Int16
VCLXAccessibleEdit::implGetAccessibleRole( )
203 VclPtr
< Edit
> pEdit
= GetAs
< Edit
>();
204 if ( pEdit
&& ( pEdit
->IsPassword() || pEdit
->GetEchoChar() ) )
205 nRole
= AccessibleRole::PASSWORD_TEXT
;
206 else if ( pEdit
&& ( pEdit
->GetStyle() & WB_READONLY
) )
207 nRole
= AccessibleRole::STATIC
;
209 nRole
= AccessibleRole::TEXT
;
218 sal_Int32
VCLXAccessibleEdit::getAccessibleActionCount( )
220 OExternalLockGuard
aGuard( this );
222 // There is one action: activate
227 sal_Bool
VCLXAccessibleEdit::doAccessibleAction ( sal_Int32 nIndex
)
229 OExternalLockGuard
aGuard( this );
232 throw IndexOutOfBoundsException();
234 bool bDoAction
= false;
235 VclPtr
<vcl::Window
> pWindow
= GetWindow();
238 pWindow
->GrabFocus();
246 OUString
VCLXAccessibleEdit::getAccessibleActionDescription ( sal_Int32 nIndex
)
248 OExternalLockGuard
aGuard( this );
251 throw IndexOutOfBoundsException();
257 Reference
< XAccessibleKeyBinding
> VCLXAccessibleEdit::getAccessibleActionKeyBinding( sal_Int32 nIndex
)
259 OExternalLockGuard
aGuard( this );
262 throw IndexOutOfBoundsException();
264 return Reference
< XAccessibleKeyBinding
>();
271 sal_Int32
VCLXAccessibleEdit::getCaretPosition( )
273 return getSelectionEnd();
277 sal_Bool
VCLXAccessibleEdit::setCaretPosition( sal_Int32 nIndex
)
279 return setSelection( nIndex
, nIndex
);
283 sal_Unicode
VCLXAccessibleEdit::getCharacter( sal_Int32 nIndex
)
285 return VCLXAccessibleTextComponent::getCharacter( nIndex
);
289 Sequence
< PropertyValue
> VCLXAccessibleEdit::getCharacterAttributes( sal_Int32 nIndex
, const Sequence
< OUString
>& aRequestedAttributes
)
291 OExternalLockGuard
aGuard( this );
292 Sequence
< PropertyValue
> aProperties
= VCLXAccessibleTextComponent::getCharacterAttributes( nIndex
, aRequestedAttributes
);
293 auto aNonConstRange
= asNonConstRange(aProperties
);
295 // Handle multiline edit character properties
296 VclPtr
<VclMultiLineEdit
> pMulitLineEdit
= GetAsDynamic
< VclMultiLineEdit
>();
297 if ( pMulitLineEdit
)
299 ExtTextEngine
* pTextEngine
= pMulitLineEdit
->GetTextEngine();
300 TextPaM
aCursor( 0, nIndex
);
301 const TextAttribFontColor
* pFontColor
= static_cast<const TextAttribFontColor
* >(pTextEngine
->FindAttrib( aCursor
, TEXTATTR_FONTCOLOR
));
304 for (PropertyValue
& aValue
: aNonConstRange
)
306 if (aValue
.Name
== "CharColor")
308 aValue
.Value
<<= pFontColor
->GetColor().GetRGBColor();
315 // Set default character color if it is not set yet to a valid value
316 for (PropertyValue
& aValue
: aNonConstRange
)
318 if (aValue
.Name
== "CharColor")
320 if ( aValue
.Value
== sal_Int32(-1) )
322 OutputDevice
* pDev
= Application::GetDefaultDevice();
325 aValue
.Value
<<= pDev
->GetSettings().GetStyleSettings().GetFieldTextColor();
336 awt::Rectangle
VCLXAccessibleEdit::getCharacterBounds( sal_Int32 nIndex
)
338 OExternalLockGuard
aGuard( this );
340 awt::Rectangle
aBounds( 0, 0, 0, 0 );
341 sal_Int32 nLength
= implGetText().getLength();
343 if ( !implIsValidRange( nIndex
, nIndex
, nLength
) )
344 throw IndexOutOfBoundsException();
346 VclPtr
< Control
> pControl
= GetAs
< Control
>();
349 if ( nIndex
== nLength
)
351 // #108914# calculate virtual bounding rectangle
352 for ( sal_Int32 i
= 0; i
< nLength
; ++i
)
354 tools::Rectangle aRect
= pControl
->GetCharacterBounds( i
);
355 sal_Int32 nHeight
= aRect
.GetHeight();
356 if ( aBounds
.Height
< nHeight
)
358 aBounds
.Y
= aRect
.Top();
359 aBounds
.Height
= nHeight
;
361 if ( i
== nLength
- 1 )
363 aBounds
.X
= aRect
.Right() + 1;
370 aBounds
= AWTRectangle( pControl
->GetCharacterBounds( nIndex
) );
378 sal_Int32
VCLXAccessibleEdit::getCharacterCount( )
380 return VCLXAccessibleTextComponent::getCharacterCount();
384 sal_Int32
VCLXAccessibleEdit::getIndexAtPoint( const awt::Point
& aPoint
)
386 return VCLXAccessibleTextComponent::getIndexAtPoint( aPoint
);
390 OUString
VCLXAccessibleEdit::getSelectedText( )
392 return VCLXAccessibleTextComponent::getSelectedText();
396 sal_Int32
VCLXAccessibleEdit::getSelectionStart( )
398 return VCLXAccessibleTextComponent::getSelectionStart();
402 sal_Int32
VCLXAccessibleEdit::getSelectionEnd( )
404 return VCLXAccessibleTextComponent::getSelectionEnd();
408 sal_Bool
VCLXAccessibleEdit::setSelection( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
410 OExternalLockGuard
aGuard( this );
412 bool bReturn
= false;
413 OUString
sText( implGetText() );
415 if ( !implIsValidRange( nStartIndex
, nEndIndex
, sText
.getLength() ) )
416 throw IndexOutOfBoundsException();
418 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
419 VclPtr
< Edit
> pEdit
= GetAs
< Edit
>();
420 if ( pVCLXEdit
&& pEdit
&& pEdit
->IsEnabled() )
422 pVCLXEdit
->setSelection( awt::Selection( nStartIndex
, nEndIndex
) );
430 OUString
VCLXAccessibleEdit::getText( )
432 return VCLXAccessibleTextComponent::getText();
436 OUString
VCLXAccessibleEdit::getTextRange( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
438 return VCLXAccessibleTextComponent::getTextRange( nStartIndex
, nEndIndex
);
442 css::accessibility::TextSegment
VCLXAccessibleEdit::getTextAtIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
444 OExternalLockGuard
aGuard( this );
445 // Override general text component behavior: MultiLineEdit can have more text portions
446 if ( aTextType
== AccessibleTextType::ATTRIBUTE_RUN
)
448 VclPtr
<VclMultiLineEdit
> pMulitLineEdit
= GetAsDynamic
< VclMultiLineEdit
>();
449 if ( pMulitLineEdit
)
451 ExtTextEngine
* pTextEngine
= pMulitLineEdit
->GetTextEngine();
452 TextPaM
aCursor( 0, nIndex
);
454 pTextEngine
->GetTextPortionRange( aCursor
, aResult
.SegmentStart
, aResult
.SegmentEnd
);
459 return VCLXAccessibleTextComponent::getTextAtIndex( nIndex
, aTextType
);
463 css::accessibility::TextSegment
VCLXAccessibleEdit::getTextBeforeIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
465 return VCLXAccessibleTextComponent::getTextBeforeIndex( nIndex
, aTextType
);
469 css::accessibility::TextSegment
VCLXAccessibleEdit::getTextBehindIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
471 return VCLXAccessibleTextComponent::getTextBehindIndex( nIndex
, aTextType
);
475 sal_Bool
VCLXAccessibleEdit::copyText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
477 return VCLXAccessibleTextComponent::copyText( nStartIndex
, nEndIndex
);
480 sal_Bool
VCLXAccessibleEdit::scrollSubstringTo( sal_Int32
, sal_Int32
, AccessibleScrollType
)
485 // XAccessibleEditableText
488 sal_Bool
VCLXAccessibleEdit::cutText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
490 return copyText( nStartIndex
, nEndIndex
) && deleteText( nStartIndex
, nEndIndex
);
494 sal_Bool
VCLXAccessibleEdit::pasteText( sal_Int32 nIndex
)
496 OExternalLockGuard
aGuard( this );
498 bool bReturn
= false;
502 Reference
< datatransfer::clipboard::XClipboard
> xClipboard
= GetWindow()->GetClipboard();
503 if ( xClipboard
.is() )
505 Reference
< datatransfer::XTransferable
> xDataObj
;
507 SolarMutexReleaser aReleaser
;
508 xDataObj
= xClipboard
->getContents();
512 datatransfer::DataFlavor aFlavor
;
513 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING
, aFlavor
);
514 if ( xDataObj
->isDataFlavorSupported( aFlavor
) )
516 Any aData
= xDataObj
->getTransferData( aFlavor
);
519 bReturn
= replaceText( nIndex
, nIndex
, sText
);
529 sal_Bool
VCLXAccessibleEdit::deleteText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
531 return replaceText( nStartIndex
, nEndIndex
, OUString() );
535 sal_Bool
VCLXAccessibleEdit::insertText( const OUString
& sText
, sal_Int32 nIndex
)
537 return replaceText( nIndex
, nIndex
, sText
);
541 sal_Bool
VCLXAccessibleEdit::replaceText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
, const OUString
& sReplacement
)
543 OExternalLockGuard
aGuard( this );
545 bool bReturn
= false;
546 OUString
sText( implGetText() );
548 if ( !implIsValidRange( nStartIndex
, nEndIndex
, sText
.getLength() ) )
549 throw IndexOutOfBoundsException();
551 sal_Int32 nMinIndex
= std::min( nStartIndex
, nEndIndex
);
552 sal_Int32 nMaxIndex
= std::max( nStartIndex
, nEndIndex
);
554 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
555 if ( pVCLXEdit
&& pVCLXEdit
->isEditable() )
557 pVCLXEdit
->setText( sText
.replaceAt( nMinIndex
, nMaxIndex
- nMinIndex
, sReplacement
) );
558 sal_Int32 nIndex
= nMinIndex
+ sReplacement
.getLength();
559 setSelection( nIndex
, nIndex
);
567 sal_Bool
VCLXAccessibleEdit::setAttributes( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
, const Sequence
<PropertyValue
>& )
569 OExternalLockGuard
aGuard( this );
571 if ( !implIsValidRange( nStartIndex
, nEndIndex
, implGetText().getLength() ) )
572 throw IndexOutOfBoundsException();
574 return false; // attributes cannot be set for an edit
578 sal_Bool
VCLXAccessibleEdit::setText( const OUString
& sText
)
580 OExternalLockGuard
aGuard( this );
582 bool bReturn
= false;
584 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
585 if ( pVCLXEdit
&& pVCLXEdit
->isEditable() )
587 pVCLXEdit
->setText( sText
);
588 sal_Int32 nSize
= sText
.getLength();
589 pVCLXEdit
->setSelection( awt::Selection( nSize
, nSize
) );
597 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */