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/vclxaccessibletoolboxitem.hxx>
21 #include <helper/accresmgr.hxx>
22 #include <strings.hrc>
23 #include <com/sun/star/awt/Rectangle.hpp>
25 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
26 #include <com/sun/star/accessibility/AccessibleRole.hpp>
27 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
28 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
29 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
30 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
31 #include <comphelper/accessiblecontexthelper.hxx>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <vcl/accessibility/strings.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/toolbox.hxx>
36 #include <vcl/unohelp.hxx>
37 #include <vcl/unohelp2.hxx>
38 #include <vcl/help.hxx>
39 #include <vcl/settings.hxx>
40 #include <unotools/accessiblerelationsethelper.hxx>
41 #include <sal/log.hxx>
42 #include <i18nlangtag/languagetag.hxx>
44 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
48 // class VCLXAccessibleToolBoxItem ------------------------------------------
50 using namespace ::com::sun::star::accessibility
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star::beans
;
53 using namespace ::com::sun::star::lang
;
54 using namespace ::com::sun::star
;
55 using namespace ::comphelper
;
60 VCLXAccessibleToolBoxItem::VCLXAccessibleToolBoxItem( ToolBox
* _pToolBox
, sal_Int32 _nPos
) :
61 m_pToolBox ( _pToolBox
),
62 m_nIndexInParent( _nPos
),
63 m_nRole ( AccessibleRole::PUSH_BUTTON
),
65 m_bHasFocus ( false ),
66 m_bIsChecked ( false ),
67 m_bIndeterminate( false )
71 m_nItemId
= m_pToolBox
->GetItemId( m_nIndexInParent
);
72 m_sOldName
= implGetAccessibleName();
73 m_bIsChecked
= m_pToolBox
->IsItemChecked( m_nItemId
);
74 m_bIndeterminate
= ( m_pToolBox
->GetItemState( m_nItemId
) == TRISTATE_INDET
);
75 ToolBoxItemType eType
= m_pToolBox
->GetItemType( m_nIndexInParent
);
78 case ToolBoxItemType::BUTTON
:
80 ToolBoxItemBits nBits
= m_pToolBox
->GetItemBits( m_nItemId
);
82 (( nBits
& ToolBoxItemBits::DROPDOWN
) == ToolBoxItemBits::DROPDOWN
) ||
83 (( nBits
& ToolBoxItemBits::DROPDOWNONLY
) == ToolBoxItemBits::DROPDOWNONLY
)
85 m_nRole
= AccessibleRole::BUTTON_DROPDOWN
;
87 ( ( nBits
& ToolBoxItemBits::CHECKABLE
) == ToolBoxItemBits::CHECKABLE
) ||
88 ( ( nBits
& ToolBoxItemBits::RADIOCHECK
) == ToolBoxItemBits::RADIOCHECK
) ||
89 ( ( nBits
& ToolBoxItemBits::AUTOCHECK
) == ToolBoxItemBits::AUTOCHECK
)
91 m_nRole
= AccessibleRole::TOGGLE_BUTTON
;
92 else if ( m_pToolBox
->GetItemWindow( m_nItemId
) )
93 m_nRole
= AccessibleRole::PANEL
;
97 case ToolBoxItemType::SPACE
:
98 m_nRole
= AccessibleRole::FILLER
;
101 case ToolBoxItemType::SEPARATOR
:
102 case ToolBoxItemType::BREAK
:
103 m_nRole
= AccessibleRole::SEPARATOR
;
108 SAL_WARN( "accessibility", "unsupported toolbox itemtype" );
113 VCLXAccessibleToolBoxItem::~VCLXAccessibleToolBoxItem()
117 void VCLXAccessibleToolBoxItem::SetFocus( bool _bFocus
)
119 if ( m_bHasFocus
!= _bFocus
)
124 aOldValue
<<= AccessibleStateType::FOCUSED
;
126 aNewValue
<<= AccessibleStateType::FOCUSED
;
127 m_bHasFocus
= _bFocus
;
128 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
132 void VCLXAccessibleToolBoxItem::SetChecked( bool _bCheck
)
134 if( m_nRole
== AccessibleRole::PANEL
)
136 if ( m_bIsChecked
!= _bCheck
)
141 aOldValue
<<= AccessibleStateType::CHECKED
;
143 aNewValue
<<= AccessibleStateType::CHECKED
;
144 m_bIsChecked
= _bCheck
;
145 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
149 void VCLXAccessibleToolBoxItem::SetIndeterminate( bool _bIndeterminate
)
151 if ( m_bIndeterminate
!= _bIndeterminate
)
153 Any aOldValue
, aNewValue
;
154 if ( m_bIndeterminate
)
155 aOldValue
<<= AccessibleStateType::INDETERMINATE
;
157 aNewValue
<<= AccessibleStateType::INDETERMINATE
;
158 m_bIndeterminate
= _bIndeterminate
;
159 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
163 void VCLXAccessibleToolBoxItem::NameChanged()
165 OUString sNewName
= implGetAccessibleName();
166 if ( sNewName
!= m_sOldName
)
168 Any aOldValue
, aNewValue
;
169 aOldValue
<<= m_sOldName
;
170 // save new name as old name for next change
171 m_sOldName
= sNewName
;
172 aNewValue
<<= m_sOldName
;
173 NotifyAccessibleEvent( AccessibleEventId::NAME_CHANGED
, aOldValue
, aNewValue
);
177 void VCLXAccessibleToolBoxItem::SetChild( const Reference
< XAccessible
>& _xChild
)
182 void VCLXAccessibleToolBoxItem::NotifyChildEvent( const Reference
< XAccessible
>& _xChild
, bool _bShow
)
184 Any aOld
= _bShow
? Any() : Any( _xChild
);
185 Any aNew
= _bShow
? Any( _xChild
) : Any();
186 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOld
, aNew
);
189 void VCLXAccessibleToolBoxItem::ToggleEnableState()
191 std::array
<Any
, 2> aOldValue
, aNewValue
;
192 if ( m_pToolBox
->IsItemEnabled( m_nItemId
) )
194 aNewValue
[0] <<= AccessibleStateType::SENSITIVE
;
195 aNewValue
[1] <<= AccessibleStateType::ENABLED
;
199 aOldValue
[0] <<= AccessibleStateType::ENABLED
;
200 aOldValue
[1] <<= AccessibleStateType::SENSITIVE
;
203 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[0], aNewValue
[0] );
204 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
[1], aNewValue
[1] );
207 awt::Rectangle
VCLXAccessibleToolBoxItem::implGetBounds( )
209 awt::Rectangle aRect
;
211 aRect
= vcl::unohelper::ConvertToAWTRect(m_pToolBox
->GetItemPosRect(m_nIndexInParent
));
216 OUString
VCLXAccessibleToolBoxItem::implGetText()
218 // no text for separators and spaces
219 if (!m_pToolBox
|| m_nItemId
<= ToolBoxItemId(0))
222 return m_pToolBox
->GetItemText(m_nItemId
);
225 Locale
VCLXAccessibleToolBoxItem::implGetLocale()
227 return Application::GetSettings().GetUILanguageTag().getLocale();
230 void VCLXAccessibleToolBoxItem::implGetSelection( sal_Int32
& nStartIndex
, sal_Int32
& nEndIndex
)
238 Any SAL_CALL
VCLXAccessibleToolBoxItem::queryInterface( const Type
& _rType
)
240 // #i33611# - toolbox buttons without text don't support XAccessibleText
241 if ( _rType
== cppu::UnoType
<XAccessibleText
>::get()
242 && ( !m_pToolBox
|| m_pToolBox
->GetButtonType() == ButtonType::SYMBOLONLY
) )
245 return ImplInheritanceHelper::queryInterface( _rType
);
250 void SAL_CALL
VCLXAccessibleToolBoxItem::disposing()
252 comphelper::OAccessibleTextHelper::disposing();
253 m_pToolBox
= nullptr;
258 OUString
VCLXAccessibleToolBoxItem::getImplementationName()
260 return u
"com.sun.star.comp.toolkit.AccessibleToolBoxItem"_ustr
;
263 sal_Bool
VCLXAccessibleToolBoxItem::supportsService( const OUString
& rServiceName
)
265 return cppu::supportsService(this, rServiceName
);
268 Sequence
< OUString
> VCLXAccessibleToolBoxItem::getSupportedServiceNames()
270 return {u
"com.sun.star.accessibility.AccessibleContext"_ustr
,
271 u
"com.sun.star.accessibility.AccessibleComponent"_ustr
,
272 u
"com.sun.star.accessibility.AccessibleExtendedComponent"_ustr
,
273 u
"com.sun.star.accessibility.AccessibleToolBoxItem"_ustr
};
278 Reference
< XAccessibleContext
> SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleContext( )
283 // XAccessibleContext
285 sal_Int64 SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleChildCount( )
287 OContextEntryGuard
aGuard( this );
289 return m_xChild
.is() ? 1 : 0;
292 Reference
< XAccessible
> SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleChild( sal_Int64 i
)
294 OContextEntryGuard
aGuard( this );
296 // no child -> so index is out of bounds
297 if ( !m_xChild
.is() || i
!= 0 )
298 throw IndexOutOfBoundsException();
303 Reference
< XAccessible
> SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleParent( )
305 OContextEntryGuard
aGuard( this );
307 return m_pToolBox
->GetAccessible();
310 sal_Int64 SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleIndexInParent( )
312 OContextEntryGuard
aGuard( this );
314 return m_nIndexInParent
;
317 sal_Int16 SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleRole( )
319 OContextEntryGuard
aGuard( this );
324 OUString SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleDescription( )
326 OExternalLockGuard
aGuard( this );
328 if (m_nRole
== AccessibleRole::PANEL
&& m_xChild
.is())
330 return AccResId( RID_STR_ACC_PANEL_DESCRIPTION
);
334 OUString sDescription
;
336 sDescription
= m_pToolBox
->GetHelpText( m_nItemId
);
341 OUString
VCLXAccessibleToolBoxItem::implGetAccessibleName()
343 OUString sRet
= m_pToolBox
->GetAccessibleName(m_nItemId
);
347 sRet
= implGetText();
351 sRet
= m_pToolBox
->GetQuickHelpText( m_nItemId
);
355 vcl::Window
* pItemWindow
= m_pToolBox
->GetItemWindow( m_nItemId
);
356 if ( m_nRole
== AccessibleRole::PANEL
&& pItemWindow
&& pItemWindow
->GetAccessible().is() &&
357 pItemWindow
->GetAccessible()->getAccessibleContext().is() )
359 sRet
= pItemWindow
->GetAccessible()->getAccessibleContext()->getAccessibleName();
364 OUString SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleName( )
366 OExternalLockGuard
aGuard( this );
367 return implGetAccessibleName();
370 Reference
< XAccessibleRelationSet
> SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleRelationSet( )
372 OContextEntryGuard
aGuard( this );
374 return new utl::AccessibleRelationSetHelper
;
377 sal_Int64 SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleStateSet( )
379 OExternalLockGuard
aGuard( this );
381 sal_Int64 nStateSet
= 0;
383 if ( m_pToolBox
&& !rBHelper
.bDisposed
&& !rBHelper
.bInDispose
)
385 nStateSet
|= AccessibleStateType::FOCUSABLE
;
386 if (m_pToolBox
->GetItemBits(m_nItemId
) & ToolBoxItemBits::CHECKABLE
)
387 nStateSet
|= AccessibleStateType::CHECKABLE
;
388 if ( m_bIsChecked
&& m_nRole
!= AccessibleRole::PANEL
)
389 nStateSet
|= AccessibleStateType::CHECKED
;
390 if ( m_bIndeterminate
)
391 nStateSet
|= AccessibleStateType::INDETERMINATE
;
392 if ( m_pToolBox
->IsEnabled() && m_pToolBox
->IsItemEnabled( m_nItemId
) )
394 nStateSet
|= AccessibleStateType::ENABLED
;
395 nStateSet
|= AccessibleStateType::SENSITIVE
;
397 if ( m_pToolBox
->IsItemVisible( m_nItemId
) )
398 nStateSet
|= AccessibleStateType::VISIBLE
;
399 if ( m_pToolBox
->IsItemReallyVisible( m_nItemId
) )
400 nStateSet
|= AccessibleStateType::SHOWING
;
402 nStateSet
|= AccessibleStateType::FOCUSED
;
405 nStateSet
|= AccessibleStateType::DEFUNC
;
412 OUString
VCLXAccessibleToolBoxItem::getText()
414 OExternalLockGuard
aGuard( this );
416 return implGetText();
419 sal_Int32
VCLXAccessibleToolBoxItem::getCharacterCount()
421 return implGetText().getLength();
424 sal_Unicode
VCLXAccessibleToolBoxItem::getCharacter( sal_Int32 nIndex
)
426 OExternalLockGuard
aGuard( this );
428 return OCommonAccessibleText::implGetCharacter(implGetText(), nIndex
);
431 OUString
VCLXAccessibleToolBoxItem::getTextRange( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
433 OExternalLockGuard
aGuard( this );
435 return OCommonAccessibleText::implGetTextRange(implGetText(), nStartIndex
, nEndIndex
);
438 sal_Int32 SAL_CALL
VCLXAccessibleToolBoxItem::getCaretPosition()
443 sal_Bool SAL_CALL
VCLXAccessibleToolBoxItem::setCaretPosition( sal_Int32 nIndex
)
445 OExternalLockGuard
aGuard( this );
447 if (!implIsValidRange(nIndex
, nIndex
, implGetText().getLength()))
448 throw IndexOutOfBoundsException();
453 Sequence
< PropertyValue
> SAL_CALL
VCLXAccessibleToolBoxItem::getCharacterAttributes( sal_Int32 nIndex
, const Sequence
< OUString
>& )
455 OExternalLockGuard
aGuard( this );
457 OUString
sText( implGetText() );
459 if ( !implIsValidIndex( nIndex
, sText
.getLength() ) )
460 throw IndexOutOfBoundsException();
462 return Sequence
< PropertyValue
>();
465 awt::Rectangle SAL_CALL
VCLXAccessibleToolBoxItem::getCharacterBounds( sal_Int32 nIndex
)
467 OExternalLockGuard
aGuard( this );
469 OUString
sText( implGetText() );
471 if ( !implIsValidIndex( nIndex
, sText
.getLength() ) )
472 throw IndexOutOfBoundsException();
474 awt::Rectangle
aBounds( 0, 0, 0, 0 );
475 if ( m_pToolBox
&& m_pToolBox
->GetButtonType() != ButtonType::SYMBOLONLY
) // symbol buttons have no character bounds
477 tools::Rectangle aCharRect
= m_pToolBox
->GetCharacterBounds( m_nItemId
, nIndex
);
478 tools::Rectangle aItemRect
= m_pToolBox
->GetItemRect( m_nItemId
);
479 aCharRect
.Move( -aItemRect
.Left(), -aItemRect
.Top() );
480 aBounds
= vcl::unohelper::ConvertToAWTRect(aCharRect
);
486 sal_Int32 SAL_CALL
VCLXAccessibleToolBoxItem::getIndexAtPoint( const awt::Point
& aPoint
)
488 OExternalLockGuard
aGuard( this );
490 sal_Int32 nIndex
= -1;
491 if ( m_pToolBox
&& m_pToolBox
->GetButtonType() != ButtonType::SYMBOLONLY
) // symbol buttons have no character bounds
493 ToolBoxItemId nItemId
;
494 tools::Rectangle aItemRect
= m_pToolBox
->GetItemRect( m_nItemId
);
495 Point
aPnt(vcl::unohelper::ConvertToVCLPoint(aPoint
));
496 aPnt
+= aItemRect
.TopLeft();
497 sal_Int32 nIdx
= m_pToolBox
->GetIndexForPoint( aPnt
, nItemId
);
498 if ( nIdx
!= -1 && nItemId
== m_nItemId
)
505 sal_Bool SAL_CALL
VCLXAccessibleToolBoxItem::setSelection( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
507 OExternalLockGuard
aGuard( this );
509 if ( !implIsValidRange( nStartIndex
, nEndIndex
, implGetText().getLength() ) )
510 throw IndexOutOfBoundsException();
515 sal_Bool SAL_CALL
VCLXAccessibleToolBoxItem::copyText( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
)
517 OExternalLockGuard
aGuard( this );
519 if ( !implIsValidRange( nStartIndex
, nEndIndex
, implGetText().getLength() ) )
520 throw IndexOutOfBoundsException();
522 bool bReturn
= false;
526 Reference
< datatransfer::clipboard::XClipboard
> xClipboard
= m_pToolBox
->GetClipboard();
527 if ( xClipboard
.is() )
529 OUString
sText( OCommonAccessibleText::implGetTextRange( implGetText(), nStartIndex
, nEndIndex
) );
531 rtl::Reference
<vcl::unohelper::TextDataObject
> pDataObj
= new vcl::unohelper::TextDataObject( sText
);
533 SolarMutexReleaser aReleaser
;
534 xClipboard
->setContents( pDataObj
, nullptr );
536 Reference
< datatransfer::clipboard::XFlushableClipboard
> xFlushableClipboard( xClipboard
, uno::UNO_QUERY
);
537 if( xFlushableClipboard
.is() )
538 xFlushableClipboard
->flushClipboard();
547 sal_Bool
VCLXAccessibleToolBoxItem::scrollSubstringTo( sal_Int32
, sal_Int32
, AccessibleScrollType
)
552 // XAccessibleComponent
554 Reference
< XAccessible
> SAL_CALL
VCLXAccessibleToolBoxItem::getAccessibleAtPoint( const awt::Point
& )
556 return Reference
< XAccessible
>();
559 void SAL_CALL
VCLXAccessibleToolBoxItem::grabFocus( )
561 Reference
< XAccessible
> xParent(getAccessibleParent());
565 Reference
< XAccessibleSelection
> rxAccessibleSelection(xParent
->getAccessibleContext(), UNO_QUERY
);
567 if ( rxAccessibleSelection
.is() )
569 rxAccessibleSelection
-> selectAccessibleChild ( getAccessibleIndexInParent() );
574 sal_Int32 SAL_CALL
VCLXAccessibleToolBoxItem::getForeground( )
576 OExternalLockGuard
aGuard( this );
580 nColor
= m_pToolBox
->GetControlForeground();
582 return sal_Int32(nColor
);
585 sal_Int32 SAL_CALL
VCLXAccessibleToolBoxItem::getBackground( )
587 OExternalLockGuard
aGuard( this );
591 nColor
= m_pToolBox
->GetControlBackground();
593 return sal_Int32(nColor
);
596 // XAccessibleExtendedComponent
598 OUString SAL_CALL
VCLXAccessibleToolBoxItem::getTitledBorderText( )
600 OExternalLockGuard
aGuard( this );
604 sRet
= m_pToolBox
->GetItemText( m_nItemId
);
609 OUString SAL_CALL
VCLXAccessibleToolBoxItem::getToolTipText( )
611 OExternalLockGuard
aGuard( this );
616 if ( Help::IsExtHelpEnabled() )
617 sRet
= m_pToolBox
->GetHelpText( m_nItemId
);
619 sRet
= m_pToolBox
->GetQuickHelpText( m_nItemId
);
620 if ( sRet
.isEmpty() )
621 // no help text set, so use item text
622 sRet
= m_pToolBox
->GetItemText( m_nItemId
);
629 sal_Int32
VCLXAccessibleToolBoxItem::getAccessibleActionCount( )
631 // "Click" and maybe "Toggle Popup"
632 return ( m_pToolBox
&& m_pToolBox
->ItemHasDropdown( m_nItemId
) ? 2 : 1 );
635 sal_Bool
VCLXAccessibleToolBoxItem::doAccessibleAction ( sal_Int32 nIndex
)
637 OExternalLockGuard
aGuard( this );
643 m_pToolBox
->TriggerItem( m_nItemId
);
646 if ( m_pToolBox
&& m_pToolBox
->ItemHasDropdown( m_nItemId
) )
647 m_pToolBox
->TriggerItemDropdown( m_nItemId
);
650 throw IndexOutOfBoundsException();
656 OUString
VCLXAccessibleToolBoxItem::getAccessibleActionDescription ( sal_Int32 nIndex
)
658 OExternalLockGuard
aGuard( this );
663 return RID_STR_ACC_ACTION_CLICK
;
665 return RID_STR_ACC_ACTION_TOGGLEPOPUP
;
667 throw IndexOutOfBoundsException();
671 Reference
< XAccessibleKeyBinding
> VCLXAccessibleToolBoxItem::getAccessibleActionKeyBinding( sal_Int32 nIndex
)
673 OContextEntryGuard
aGuard( this );
675 if (nIndex
< 0 || nIndex
>= getAccessibleActionCount())
676 throw IndexOutOfBoundsException();
678 return Reference
< XAccessibleKeyBinding
>();
683 Any
VCLXAccessibleToolBoxItem::getCurrentValue( )
685 OExternalLockGuard
aGuard( this );
689 aValue
<<= static_cast<sal_Int32
>(m_pToolBox
->IsItemChecked( m_nItemId
));
691 if( m_nRole
== AccessibleRole::PANEL
)
692 aValue
<<= sal_Int32(0);
696 sal_Bool
VCLXAccessibleToolBoxItem::setCurrentValue( const Any
& aNumber
)
698 OExternalLockGuard
aGuard( this );
700 bool bReturn
= false;
704 sal_Int32 nValue
= 0;
705 OSL_VERIFY( aNumber
>>= nValue
);
709 else if ( nValue
> 1 )
712 m_pToolBox
->CheckItem( m_nItemId
, nValue
== 1 );
719 Any
VCLXAccessibleToolBoxItem::getMaximumValue( )
721 return Any(sal_Int32(1));
724 Any
VCLXAccessibleToolBoxItem::getMinimumValue( )
726 return Any(sal_Int32(0));
729 Any
VCLXAccessibleToolBoxItem::getMinimumIncrement( )
731 return Any(sal_Int32(1));
735 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */