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 <accessibility/standard/vclxaccessibleedit.hxx>
22 #include <toolkit/awt/vclxwindows.hxx>
23 #include <toolkit/helper/convert.hxx>
24 #include <accessibility/helper/accresmgr.hxx>
25 #include <accessibility/helper/accessiblestrings.hrc>
27 #include <unotools/accessiblestatesethelper.hxx>
28 #include <unotools/accessiblerelationsethelper.hxx>
29 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
30 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
31 #include <com/sun/star/accessibility/AccessibleRole.hpp>
32 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
33 #include <cppuhelper/typeprovider.hxx>
34 #include <comphelper/sequence.hxx>
35 #include <comphelper/string.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/window.hxx>
38 #include <vcl/edit.hxx>
39 #include <sot/exchange.hxx>
40 #include <sot/formats.hxx>
44 using namespace ::com::sun::star
;
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::lang
;
47 using namespace ::com::sun::star::beans
;
48 using namespace ::com::sun::star::accessibility
;
49 using namespace ::comphelper
;
52 // -----------------------------------------------------------------------------
54 // -----------------------------------------------------------------------------
56 VCLXAccessibleEdit::VCLXAccessibleEdit( VCLXWindow
* pVCLWindow
)
57 :VCLXAccessibleTextComponent( pVCLWindow
)
59 m_nSelectionStart
= getSelectionStart();
60 m_nCaretPosition
= getCaretPosition();
63 // -----------------------------------------------------------------------------
65 VCLXAccessibleEdit::~VCLXAccessibleEdit()
69 // -----------------------------------------------------------------------------
71 void VCLXAccessibleEdit::ProcessWindowEvent( const VclWindowEvent
& rVclWindowEvent
)
73 switch ( rVclWindowEvent
.GetId() )
75 case VCLEVENT_EDIT_MODIFY
:
77 SetText( implGetText() );
80 case VCLEVENT_EDIT_SELECTIONCHANGED
:
82 sal_Int32 nOldCaretPosition
= m_nCaretPosition
;
83 sal_Int32 nOldSelectionStart
= m_nSelectionStart
;
85 m_nCaretPosition
= getCaretPosition();
86 m_nSelectionStart
= getSelectionStart();
88 Window
* pWindow
= GetWindow();
89 if ( pWindow
&& pWindow
->HasChildPathFocus() )
91 if ( m_nCaretPosition
!= nOldCaretPosition
)
93 Any aOldValue
, aNewValue
;
94 aOldValue
<<= (sal_Int32
) nOldCaretPosition
;
95 aNewValue
<<= (sal_Int32
) m_nCaretPosition
;
96 NotifyAccessibleEvent( AccessibleEventId::CARET_CHANGED
, aOldValue
, aNewValue
);
99 // #i104470# VCL only has SELECTION_CHANGED, but UAA distinguishes between SELECTION_CHANGED and CARET_CHANGED
100 sal_Bool bHasSelection
= ( m_nSelectionStart
!= m_nCaretPosition
);
101 sal_Bool bHadSelection
= ( nOldSelectionStart
!= nOldCaretPosition
);
102 if ( ( bHasSelection
!= bHadSelection
) || ( bHasSelection
&& ( ( m_nCaretPosition
!= nOldCaretPosition
) || ( m_nSelectionStart
!= nOldSelectionStart
) ) ) )
104 NotifyAccessibleEvent( AccessibleEventId::TEXT_SELECTION_CHANGED
, Any(), Any() );
111 VCLXAccessibleTextComponent::ProcessWindowEvent( rVclWindowEvent
);
115 // -----------------------------------------------------------------------------
117 void VCLXAccessibleEdit::FillAccessibleStateSet( utl::AccessibleStateSetHelper
& rStateSet
)
119 VCLXAccessibleTextComponent::FillAccessibleStateSet( rStateSet
);
121 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
124 rStateSet
.AddState( AccessibleStateType::FOCUSABLE
);
125 rStateSet
.AddState( AccessibleStateType::SINGLE_LINE
);
126 if ( pVCLXEdit
->isEditable() )
127 rStateSet
.AddState( AccessibleStateType::EDITABLE
);
131 // -----------------------------------------------------------------------------
132 // OCommonAccessibleText
133 // -----------------------------------------------------------------------------
135 OUString
VCLXAccessibleEdit::implGetText()
139 Edit
* pEdit
= static_cast< Edit
* >( GetWindow() );
142 aText
= OutputDevice::GetNonMnemonicString( pEdit
->GetText() );
144 if ( getAccessibleRole() == AccessibleRole::PASSWORD_TEXT
)
146 sal_Unicode cEchoChar
= pEdit
->GetEchoChar();
150 aText
= comphelper::string::padToLength(sTmp
, aText
.getLength(),
151 cEchoChar
).makeStringAndClear();
158 // -----------------------------------------------------------------------------
160 void VCLXAccessibleEdit::implGetSelection( sal_Int32
& nStartIndex
, sal_Int32
& nEndIndex
)
162 awt::Selection aSelection
;
163 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
165 aSelection
= pVCLXEdit
->getSelection();
167 nStartIndex
= aSelection
.Min
;
168 nEndIndex
= aSelection
.Max
;
171 // -----------------------------------------------------------------------------
173 // -----------------------------------------------------------------------------
175 IMPLEMENT_FORWARD_XINTERFACE2( VCLXAccessibleEdit
, VCLXAccessibleTextComponent
, VCLXAccessibleEdit_BASE
)
177 // -----------------------------------------------------------------------------
179 // -----------------------------------------------------------------------------
181 IMPLEMENT_FORWARD_XTYPEPROVIDER2( VCLXAccessibleEdit
, VCLXAccessibleTextComponent
, VCLXAccessibleEdit_BASE
)
183 // -----------------------------------------------------------------------------
185 // -----------------------------------------------------------------------------
187 OUString
VCLXAccessibleEdit::getImplementationName() throw (RuntimeException
)
189 return OUString( "com.sun.star.comp.toolkit.AccessibleEdit" );
192 // -----------------------------------------------------------------------------
194 Sequence
< OUString
> VCLXAccessibleEdit::getSupportedServiceNames() throw (RuntimeException
)
196 Sequence
< OUString
> aNames(1);
197 aNames
[0] = "com.sun.star.awt.AccessibleEdit";
201 // -----------------------------------------------------------------------------
202 // XAccessibleContext
203 // -----------------------------------------------------------------------------
205 sal_Int32
VCLXAccessibleEdit::getAccessibleChildCount() throw (RuntimeException
)
207 OExternalLockGuard
aGuard( this );
212 // -----------------------------------------------------------------------------
214 Reference
< XAccessible
> VCLXAccessibleEdit::getAccessibleChild( sal_Int32 i
) throw (IndexOutOfBoundsException
, RuntimeException
)
216 OExternalLockGuard
aGuard( this );
218 if ( i
< 0 || i
>= getAccessibleChildCount() )
219 throw IndexOutOfBoundsException();
221 return Reference
< XAccessible
>();
224 // -----------------------------------------------------------------------------
226 sal_Int16
VCLXAccessibleEdit::getAccessibleRole( ) throw (RuntimeException
)
228 OExternalLockGuard
aGuard( this );
231 Edit
* pEdit
= static_cast< Edit
* >( GetWindow() );
232 if ( pEdit
&& ( ( pEdit
->GetStyle() & WB_PASSWORD
) || pEdit
->GetEchoChar() ) )
233 nRole
= AccessibleRole::PASSWORD_TEXT
;
235 nRole
= AccessibleRole::TEXT
;
240 // -----------------------------------------------------------------------------
242 // -----------------------------------------------------------------------------
244 sal_Int32
VCLXAccessibleEdit::getAccessibleActionCount( ) throw (RuntimeException
)
246 OExternalLockGuard
aGuard( this );
248 // There is one action: activate
252 // -----------------------------------------------------------------------------
254 sal_Bool
VCLXAccessibleEdit::doAccessibleAction ( sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
256 OExternalLockGuard
aGuard( this );
258 if ( nIndex
< 0 || nIndex
>= getAccessibleActionCount() )
259 throw IndexOutOfBoundsException();
261 sal_Bool bDoAction
= sal_False
;
262 Window
* pWindow
= GetWindow();
265 pWindow
->GrabFocus();
266 bDoAction
= sal_True
;
272 // -----------------------------------------------------------------------------
274 OUString
VCLXAccessibleEdit::getAccessibleActionDescription ( sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
276 OExternalLockGuard
aGuard( this );
278 if ( nIndex
< 0 || nIndex
>= getAccessibleActionCount() )
279 throw IndexOutOfBoundsException();
281 static const OUString
sAction( "activate" );
285 // -----------------------------------------------------------------------------
287 Reference
< XAccessibleKeyBinding
> VCLXAccessibleEdit::getAccessibleActionKeyBinding( sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
289 OExternalLockGuard
aGuard( this );
291 if ( nIndex
< 0 || nIndex
>= getAccessibleActionCount() )
292 throw IndexOutOfBoundsException();
294 return Reference
< XAccessibleKeyBinding
>();
297 // -----------------------------------------------------------------------------
299 // -----------------------------------------------------------------------------
301 sal_Int32
VCLXAccessibleEdit::getCaretPosition( ) throw (RuntimeException
)
303 return getSelectionEnd();
306 // -----------------------------------------------------------------------------
308 sal_Bool
VCLXAccessibleEdit::setCaretPosition( sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
310 return setSelection( nIndex
, nIndex
);
313 // -----------------------------------------------------------------------------
315 sal_Unicode
VCLXAccessibleEdit::getCharacter( sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
317 OExternalLockGuard
aGuard( this );
319 return VCLXAccessibleTextComponent::getCharacter( nIndex
);
322 // -----------------------------------------------------------------------------
324 Sequence
< PropertyValue
> VCLXAccessibleEdit::getCharacterAttributes( sal_Int32 nIndex
, const Sequence
< OUString
>& aRequestedAttributes
) throw (IndexOutOfBoundsException
, RuntimeException
)
326 OExternalLockGuard
aGuard( this );
328 return VCLXAccessibleTextComponent::getCharacterAttributes( nIndex
, aRequestedAttributes
);
331 // -----------------------------------------------------------------------------
333 awt::Rectangle
VCLXAccessibleEdit::getCharacterBounds( sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
335 OExternalLockGuard
aGuard( this );
337 awt::Rectangle
aBounds( 0, 0, 0, 0 );
338 sal_Int32 nLength
= implGetText().getLength();
340 if ( !implIsValidRange( nIndex
, nIndex
, nLength
) )
341 throw IndexOutOfBoundsException();
343 Control
* pControl
= static_cast< Control
* >( GetWindow() );
346 if ( nIndex
== nLength
)
348 // #108914# calculate virtual bounding rectangle
349 for ( sal_Int32 i
= 0; i
< nLength
; ++i
)
351 Rectangle aRect
= pControl
->GetCharacterBounds( i
);
352 sal_Int32 nHeight
= aRect
.GetHeight();
353 if ( aBounds
.Height
< nHeight
)
355 aBounds
.Y
= aRect
.Top();
356 aBounds
.Height
= nHeight
;
358 if ( i
== nLength
- 1 )
360 aBounds
.X
= aRect
.Right() + 1;
367 aBounds
= AWTRectangle( pControl
->GetCharacterBounds( nIndex
) );
374 // -----------------------------------------------------------------------------
376 sal_Int32
VCLXAccessibleEdit::getCharacterCount( ) throw (RuntimeException
)
378 OExternalLockGuard
aGuard( this );
380 return VCLXAccessibleTextComponent::getCharacterCount();
383 // -----------------------------------------------------------------------------
385 sal_Int32
VCLXAccessibleEdit::getIndexAtPoint( const awt::Point
& aPoint
) throw (RuntimeException
)
387 OExternalLockGuard
aGuard( this );
389 return VCLXAccessibleTextComponent::getIndexAtPoint( aPoint
);
392 // -----------------------------------------------------------------------------
394 OUString
VCLXAccessibleEdit::getSelectedText( ) throw (RuntimeException
)
396 OExternalLockGuard
aGuard( this );
398 return VCLXAccessibleTextComponent::getSelectedText();
401 // -----------------------------------------------------------------------------
403 sal_Int32
VCLXAccessibleEdit::getSelectionStart( ) throw (RuntimeException
)
405 OExternalLockGuard
aGuard( this );
407 return VCLXAccessibleTextComponent::getSelectionStart();
410 // -----------------------------------------------------------------------------
412 sal_Int32
VCLXAccessibleEdit::getSelectionEnd( ) throw (RuntimeException
)
414 OExternalLockGuard
aGuard( this );
416 return VCLXAccessibleTextComponent::getSelectionEnd();
419 // -----------------------------------------------------------------------------
421 sal_Bool
VCLXAccessibleEdit::setSelection( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
423 OExternalLockGuard
aGuard( this );
425 sal_Bool bReturn
= sal_False
;
426 OUString
sText( implGetText() );
428 if ( !implIsValidRange( nStartIndex
, nEndIndex
, sText
.getLength() ) )
429 throw IndexOutOfBoundsException();
431 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
432 Edit
* pEdit
= static_cast< Edit
* >( GetWindow() );
433 if ( pVCLXEdit
&& pEdit
&& pEdit
->IsEnabled() )
435 pVCLXEdit
->setSelection( awt::Selection( nStartIndex
, nEndIndex
) );
442 // -----------------------------------------------------------------------------
444 OUString
VCLXAccessibleEdit::getText( ) throw (RuntimeException
)
446 OExternalLockGuard
aGuard( this );
448 return VCLXAccessibleTextComponent::getText();
451 // -----------------------------------------------------------------------------
453 OUString
VCLXAccessibleEdit::getTextRange( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
455 OExternalLockGuard
aGuard( this );
457 return VCLXAccessibleTextComponent::getTextRange( nStartIndex
, nEndIndex
);
460 // -----------------------------------------------------------------------------
462 ::com::sun::star::accessibility::TextSegment
VCLXAccessibleEdit::getTextAtIndex( sal_Int32 nIndex
, sal_Int16 aTextType
) throw (::com::sun::star::lang::IndexOutOfBoundsException
, ::com::sun::star::lang::IllegalArgumentException
, ::com::sun::star::uno::RuntimeException
)
464 OExternalLockGuard
aGuard( this );
466 return VCLXAccessibleTextComponent::getTextAtIndex( nIndex
, aTextType
);
469 // -----------------------------------------------------------------------------
471 ::com::sun::star::accessibility::TextSegment
VCLXAccessibleEdit::getTextBeforeIndex( sal_Int32 nIndex
, sal_Int16 aTextType
) throw (::com::sun::star::lang::IndexOutOfBoundsException
, ::com::sun::star::lang::IllegalArgumentException
, ::com::sun::star::uno::RuntimeException
)
473 OExternalLockGuard
aGuard( this );
475 return VCLXAccessibleTextComponent::getTextBeforeIndex( nIndex
, aTextType
);
478 // -----------------------------------------------------------------------------
480 ::com::sun::star::accessibility::TextSegment
VCLXAccessibleEdit::getTextBehindIndex( sal_Int32 nIndex
, sal_Int16 aTextType
) throw (::com::sun::star::lang::IndexOutOfBoundsException
, ::com::sun::star::lang::IllegalArgumentException
, ::com::sun::star::uno::RuntimeException
)
482 OExternalLockGuard
aGuard( this );
484 return VCLXAccessibleTextComponent::getTextBehindIndex( nIndex
, aTextType
);
487 // -----------------------------------------------------------------------------
489 sal_Bool
VCLXAccessibleEdit::copyText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
491 OExternalLockGuard
aGuard( this );
493 return VCLXAccessibleTextComponent::copyText( nStartIndex
, nEndIndex
);
496 // -----------------------------------------------------------------------------
497 // XAccessibleEditableText
498 // -----------------------------------------------------------------------------
500 sal_Bool
VCLXAccessibleEdit::cutText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
502 OExternalLockGuard
aGuard( this );
504 return copyText( nStartIndex
, nEndIndex
) && deleteText( nStartIndex
, nEndIndex
);
507 // -----------------------------------------------------------------------------
509 sal_Bool
VCLXAccessibleEdit::pasteText( sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
511 OExternalLockGuard
aGuard( this );
513 sal_Bool bReturn
= sal_False
;
517 Reference
< datatransfer::clipboard::XClipboard
> xClipboard
= GetWindow()->GetClipboard();
518 if ( xClipboard
.is() )
520 const sal_uInt32 nRef
= Application::ReleaseSolarMutex();
521 Reference
< datatransfer::XTransferable
> xDataObj
= xClipboard
->getContents();
522 Application::AcquireSolarMutex( nRef
);
525 datatransfer::DataFlavor aFlavor
;
526 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING
, aFlavor
);
527 if ( xDataObj
->isDataFlavorSupported( aFlavor
) )
529 Any aData
= xDataObj
->getTransferData( aFlavor
);
532 bReturn
= replaceText( nIndex
, nIndex
, sText
);
541 // -----------------------------------------------------------------------------
543 sal_Bool
VCLXAccessibleEdit::deleteText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
545 OExternalLockGuard
aGuard( this );
547 return replaceText( nStartIndex
, nEndIndex
, OUString() );
550 // -----------------------------------------------------------------------------
552 sal_Bool
VCLXAccessibleEdit::insertText( const OUString
& sText
, sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
554 OExternalLockGuard
aGuard( this );
556 return replaceText( nIndex
, nIndex
, sText
);
559 // -----------------------------------------------------------------------------
561 sal_Bool
VCLXAccessibleEdit::replaceText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
, const OUString
& sReplacement
) throw (IndexOutOfBoundsException
, RuntimeException
)
563 OExternalLockGuard
aGuard( this );
565 sal_Bool bReturn
= sal_False
;
566 OUString
sText( implGetText() );
568 if ( !implIsValidRange( nStartIndex
, nEndIndex
, sText
.getLength() ) )
569 throw IndexOutOfBoundsException();
571 sal_Int32 nMinIndex
= ::std::min( nStartIndex
, nEndIndex
);
572 sal_Int32 nMaxIndex
= ::std::max( nStartIndex
, nEndIndex
);
574 VCLXEdit
* pVCLXEdit
= static_cast< VCLXEdit
* >( GetVCLXWindow() );
575 if ( pVCLXEdit
&& pVCLXEdit
->isEditable() )
577 pVCLXEdit
->setText( sText
.replaceAt( nMinIndex
, nMaxIndex
- nMinIndex
, sReplacement
) );
578 sal_Int32 nIndex
= nMinIndex
+ sReplacement
.getLength();
579 setSelection( nIndex
, nIndex
);
586 // -----------------------------------------------------------------------------
588 sal_Bool
VCLXAccessibleEdit::setAttributes( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
, const Sequence
<PropertyValue
>& ) throw (IndexOutOfBoundsException
, RuntimeException
)
590 OExternalLockGuard
aGuard( this );
592 if ( !implIsValidRange( nStartIndex
, nEndIndex
, implGetText().getLength() ) )
593 throw IndexOutOfBoundsException();
595 return sal_False
; // attributes cannot be set for an edit
598 // -----------------------------------------------------------------------------
600 sal_Bool
VCLXAccessibleEdit::setText( const OUString
& sText
) throw (RuntimeException
)
602 OExternalLockGuard
aGuard( this );
604 sal_Bool bSuccess
= sal_False
;
607 bSuccess
= replaceText( 0, implGetText().getLength(), sText
);
609 catch( const IndexOutOfBoundsException
& )
611 OSL_FAIL( "VCLXAccessibleText::setText: caught an exception!" );
616 // -----------------------------------------------------------------------------
618 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */