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/vclxaccessiblebox.hxx>
21 #include <accessibility/standard/vclxaccessibletextfield.hxx>
22 #include <accessibility/standard/vclxaccessibleedit.hxx>
23 #include <accessibility/standard/vclxaccessiblelist.hxx>
24 #include <accessibility/helper/listboxhelper.hxx>
26 #include <unotools/accessiblestatesethelper.hxx>
27 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
28 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
29 #include <com/sun/star/accessibility/AccessibleRole.hpp>
30 #include <vcl/svapp.hxx>
31 #include <vcl/combobox.hxx>
32 #include <vcl/lstbox.hxx>
33 #include <accessibility/helper/accresmgr.hxx>
34 #include <accessibility/helper/accessiblestrings.hrc>
36 using namespace ::com::sun::star
;
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star::lang
;
39 using namespace ::com::sun::star::beans
;
40 using namespace ::com::sun::star::accessibility
;
42 VCLXAccessibleBox::VCLXAccessibleBox (VCLXWindow
* pVCLWindow
, BoxType aType
, bool bIsDropDownBox
)
43 : VCLXAccessibleComponent (pVCLWindow
),
45 m_bIsDropDownBox (bIsDropDownBox
),
46 m_nIndexInParent (DEFAULT_INDEX_IN_PARENT
)
48 // Set up the flags that indicate which children this object has.
49 m_bHasListChild
= true;
51 // A text field is not present for non drop down list boxes.
52 if ((m_aBoxType
==LISTBOX
) && ! m_bIsDropDownBox
)
53 m_bHasTextChild
= false;
55 m_bHasTextChild
= true;
58 VCLXAccessibleBox::~VCLXAccessibleBox()
62 void VCLXAccessibleBox::ProcessWindowChildEvent( const VclWindowEvent
& rVclWindowEvent
)
64 uno::Any aOldValue
, aNewValue
;
65 uno::Reference
<XAccessible
> xAcc
;
67 switch ( rVclWindowEvent
.GetId() )
69 case VCLEVENT_WINDOW_SHOW
:
70 case VCLEVENT_WINDOW_HIDE
:
72 vcl::Window
* pChildWindow
= static_cast<vcl::Window
*>(rVclWindowEvent
.GetData());
73 // Just compare to the combo box text field. All other children
74 // are identical to this object in which case this object will
75 // be removed in a short time.
76 if (m_aBoxType
==COMBOBOX
)
78 VclPtr
< ComboBox
> pComboBox
= GetAs
< ComboBox
>();
79 if ( ( pComboBox
!= nullptr ) && ( pChildWindow
!= NULL
) )
80 if (pChildWindow
== pComboBox
->GetSubEdit())
82 if (rVclWindowEvent
.GetId() == VCLEVENT_WINDOW_SHOW
)
84 // Instantiate text field.
85 getAccessibleChild (0);
86 aNewValue
<<= m_xText
;
90 // Release text field.
91 aOldValue
<<= m_xText
;
94 // Tell the listeners about the new/removed child.
95 NotifyAccessibleEvent (
96 AccessibleEventId::CHILD
,
97 aOldValue
, aNewValue
);
105 VCLXAccessibleComponent::ProcessWindowChildEvent (rVclWindowEvent
);
109 void VCLXAccessibleBox::ProcessWindowEvent (const VclWindowEvent
& rVclWindowEvent
)
111 switch ( rVclWindowEvent
.GetId() )
113 case VCLEVENT_DROPDOWN_SELECT
:
114 case VCLEVENT_LISTBOX_SELECT
:
115 case VCLEVENT_LISTBOX_FOCUSITEMCHANGED
:
117 // Forward the call to the list child.
118 VCLXAccessibleList
* pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
121 getAccessibleChild ( m_bHasTextChild
? 1 : 0 );
122 pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
126 pList
->ProcessWindowEvent (rVclWindowEvent
, m_bIsDropDownBox
);
128 if (m_bIsDropDownBox
)
130 NotifyAccessibleEvent(AccessibleEventId::VALUE_CHANGED
, Any(), Any());
136 case VCLEVENT_DROPDOWN_OPEN
:
138 VCLXAccessibleList
* pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
141 getAccessibleChild ( m_bHasTextChild
? 1 : 0 );
142 pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
146 pList
->ProcessWindowEvent (rVclWindowEvent
);
147 pList
->HandleDropOpen();
151 case VCLEVENT_DROPDOWN_CLOSE
:
153 VCLXAccessibleList
* pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
156 getAccessibleChild ( m_bHasTextChild
? 1 : 0 );
157 pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
161 pList
->ProcessWindowEvent (rVclWindowEvent
);
163 vcl::Window
* pWindow
= GetWindow();
164 if( pWindow
&& (pWindow
->HasFocus() || pWindow
->HasChildPathFocus()) )
166 Any aOldValue
, aNewValue
;
167 aNewValue
<<= AccessibleStateType::FOCUSED
;
168 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
172 case VCLEVENT_COMBOBOX_SELECT
:
174 VCLXAccessibleList
* pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
175 if (pList
!= NULL
&& m_xText
.is())
177 Reference
<XAccessibleText
> xText (m_xText
->getAccessibleContext(), UNO_QUERY
);
180 OUString sText
= xText
->getSelectedText();
181 if ( sText
.isEmpty() )
182 sText
= xText
->getText();
183 pList
->UpdateSelection_Acc(sText
, m_bIsDropDownBox
);
185 if (m_bIsDropDownBox
|| ( !m_bIsDropDownBox
&& m_aBoxType
==COMBOBOX
))
186 NotifyAccessibleEvent(AccessibleEventId::VALUE_CHANGED
, Any(), Any());
192 //case VCLEVENT_DROPDOWN_OPEN:
193 //case VCLEVENT_DROPDOWN_CLOSE:
194 case VCLEVENT_LISTBOX_DOUBLECLICK
:
195 case VCLEVENT_LISTBOX_SCROLLED
:
196 //case VCLEVENT_LISTBOX_SELECT:
197 case VCLEVENT_LISTBOX_ITEMADDED
:
198 case VCLEVENT_LISTBOX_ITEMREMOVED
:
199 case VCLEVENT_COMBOBOX_ITEMADDED
:
200 case VCLEVENT_COMBOBOX_ITEMREMOVED
:
201 case VCLEVENT_COMBOBOX_SCROLLED
:
203 // Forward the call to the list child.
204 VCLXAccessibleList
* pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
207 getAccessibleChild ( m_bHasTextChild
? 1 : 0 );
208 pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
211 pList
->ProcessWindowEvent (rVclWindowEvent
);
215 //case VCLEVENT_COMBOBOX_SELECT:
216 case VCLEVENT_COMBOBOX_DESELECT
:
218 // Selection is handled by VCLXAccessibleList which operates on
219 // the same VCL object as this box does. In case of the
220 // combobox, however, we have to help by providing the list with
221 // the text of the currently selected item.
222 VCLXAccessibleList
* pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
223 if (pList
!= NULL
&& m_xText
.is())
225 Reference
<XAccessibleText
> xText (m_xText
->getAccessibleContext(), UNO_QUERY
);
228 OUString sText
= xText
->getSelectedText();
229 if ( sText
.isEmpty() )
230 sText
= xText
->getText();
231 pList
->UpdateSelection (sText
);
237 case VCLEVENT_EDIT_MODIFY
:
238 case VCLEVENT_EDIT_SELECTIONCHANGED
:
239 // case VCLEVENT_EDIT_CARETCHANGED:
240 // Modify/Selection events are handled by the combo box instead of
241 // directly by the edit field (Why?). Therefore, delegate this
242 // call to the edit field.
243 if (m_aBoxType
==COMBOBOX
)
247 Reference
<XAccessibleContext
> xContext
= m_xText
->getAccessibleContext();
248 VCLXAccessibleEdit
* pEdit
= static_cast<VCLXAccessibleEdit
*>(xContext
.get());
250 pEdit
->ProcessWindowEvent (rVclWindowEvent
);
255 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent
);
259 IMPLEMENT_FORWARD_XINTERFACE2(VCLXAccessibleBox
, VCLXAccessibleComponent
, VCLXAccessibleBox_BASE
)
260 IMPLEMENT_FORWARD_XTYPEPROVIDER2(VCLXAccessibleBox
, VCLXAccessibleComponent
, VCLXAccessibleBox_BASE
)
262 //===== XAccessible =========================================================
264 Reference
< XAccessibleContext
> SAL_CALL
VCLXAccessibleBox::getAccessibleContext( )
265 throw (RuntimeException
, std::exception
)
267 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
272 //===== XAccessibleContext ==================================================
274 sal_Int32 SAL_CALL
VCLXAccessibleBox::getAccessibleChildCount()
275 throw (RuntimeException
, std::exception
)
277 SolarMutexGuard aSolarGuard
;
278 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
280 // Usually a box has a text field and a list of items as its children.
281 // Non drop down list boxes have no text field. Additionally check
282 // whether the object is valid.
283 sal_Int32 nCount
= 0;
285 nCount
+= (m_bHasTextChild
?1:0) + (m_bHasListChild
?1:0);
288 // Object not valid anymore. Release references to children.
289 m_bHasTextChild
= false;
291 m_bHasListChild
= false;
298 Reference
<XAccessible
> SAL_CALL
VCLXAccessibleBox::getAccessibleChild (sal_Int32 i
)
299 throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
301 SolarMutexGuard aSolarGuard
;
302 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
304 if (i
<0 || i
>=getAccessibleChildCount())
305 throw IndexOutOfBoundsException();
307 Reference
< XAccessible
> xChild
;
310 if (i
==1 || ! m_bHasTextChild
)
315 VCLXAccessibleList
* pList
= new VCLXAccessibleList ( GetVCLXWindow(),
316 (m_aBoxType
== LISTBOX
? VCLXAccessibleList::LISTBOX
: VCLXAccessibleList::COMBOBOX
),
318 pList
->SetIndexInParent (i
);
328 if (m_aBoxType
==COMBOBOX
)
330 VclPtr
< ComboBox
> pComboBox
= GetAs
< ComboBox
>();
331 if (pComboBox
!=nullptr && pComboBox
->GetSubEdit()!=NULL
)
332 //Set the edit's acc name the same as parent
334 pComboBox
->GetSubEdit()->SetAccessibleName(getAccessibleName());
335 m_xText
= pComboBox
->GetSubEdit()->GetAccessible();
338 else if (m_bIsDropDownBox
)
339 m_xText
= new VCLXAccessibleTextField (GetVCLXWindow(),this);
348 sal_Int16 SAL_CALL
VCLXAccessibleBox::getAccessibleRole() throw (RuntimeException
, std::exception
)
350 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
352 // Return the role <const>COMBO_BOX</const> for both VCL combo boxes and
353 // VCL list boxes in DropDown-Mode else <const>PANEL</const>.
354 // This way the Java bridge has not to handle both independently.
355 //return m_bIsDropDownBox ? AccessibleRole::COMBO_BOX : AccessibleRole::PANEL;
356 if (m_bIsDropDownBox
|| (!m_bIsDropDownBox
&& m_aBoxType
== COMBOBOX
))
357 return AccessibleRole::COMBO_BOX
;
359 return AccessibleRole::PANEL
;
362 sal_Int32 SAL_CALL
VCLXAccessibleBox::getAccessibleIndexInParent()
363 throw (::com::sun::star::uno::RuntimeException
, std::exception
)
365 if (m_nIndexInParent
!= DEFAULT_INDEX_IN_PARENT
)
366 return m_nIndexInParent
;
368 return VCLXAccessibleComponent::getAccessibleIndexInParent();
371 //===== XAccessibleAction ===================================================
373 sal_Int32 SAL_CALL
VCLXAccessibleBox::getAccessibleActionCount()
374 throw (RuntimeException
, std::exception
)
376 ::osl::Guard
< ::osl::Mutex
> aGuard (GetMutex());
378 // There is one action for drop down boxes (toggle popup) and none for
380 return m_bIsDropDownBox
? 1 : 0;
383 sal_Bool SAL_CALL
VCLXAccessibleBox::doAccessibleAction (sal_Int32 nIndex
)
384 throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
386 bool bNotify
= false;
389 SolarMutexGuard aSolarGuard
;
390 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
392 if (nIndex
<0 || nIndex
>=getAccessibleActionCount())
393 throw ::com::sun::star::lang::IndexOutOfBoundsException(
394 ("VCLXAccessibleBox::doAccessibleAction: index "
395 + OUString::number(nIndex
) + " not among 0.."
396 + OUString::number(getAccessibleActionCount())),
397 static_cast<OWeakObject
*>(this));
399 if (m_aBoxType
== COMBOBOX
)
401 VclPtr
< ComboBox
> pComboBox
= GetAs
< ComboBox
>();
402 if (pComboBox
!= nullptr)
404 pComboBox
->ToggleDropDown();
408 else if (m_aBoxType
== LISTBOX
)
410 VclPtr
< ListBox
> pListBox
= GetAs
< ListBox
>();
411 if (pListBox
!= nullptr)
413 pListBox
->ToggleDropDown();
420 NotifyAccessibleEvent (AccessibleEventId::ACTION_CHANGED
, Any(), Any());
425 OUString SAL_CALL
VCLXAccessibleBox::getAccessibleActionDescription (sal_Int32 nIndex
)
426 throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
428 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
429 if (nIndex
<0 || nIndex
>=getAccessibleActionCount())
430 throw ::com::sun::star::lang::IndexOutOfBoundsException();
432 if (m_bIsDropDownBox
)
433 return TK_RES_STRING(RID_STR_ACC_ACTION_TOGGLEPOPUP
);
438 Reference
< XAccessibleKeyBinding
> VCLXAccessibleBox::getAccessibleActionKeyBinding( sal_Int32 nIndex
)
439 throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
441 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
443 Reference
< XAccessibleKeyBinding
> xRet
;
445 if (nIndex
<0 || nIndex
>=getAccessibleActionCount())
446 throw ::com::sun::star::lang::IndexOutOfBoundsException();
452 //===== XComponent ==========================================================
454 void SAL_CALL
VCLXAccessibleBox::disposing()
456 VCLXAccessibleComponent::disposing();
459 // ===== XAccessibleValue ===============================================
460 Any
VCLXAccessibleBox::getCurrentValue( )
461 throw( RuntimeException
, std::exception
)
463 SolarMutexGuard aSolarGuard
;
464 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
467 if( m_xList
.is() && m_xText
.is())
469 // VCLXAccessibleList* pList = static_cast<VCLXAccessibleList*>(m_xList.get());
470 Reference
<XAccessibleText
> xText (m_xText
->getAccessibleContext(), UNO_QUERY
);
473 OUString sText
= xText
->getText();
477 if (m_aBoxType
== LISTBOX
&& m_bIsDropDownBox
&& m_xList
.is() )
480 VCLXAccessibleList
* pList
= static_cast<VCLXAccessibleList
*>(m_xList
.get());
481 if(pList
->IsInDropDown())
483 if(pList
->getSelectedAccessibleChildCount()>0)
485 Reference
<XAccessibleContext
> xName (pList
->getSelectedAccessibleChild((sal_Int32
)(0)), UNO_QUERY
);
488 aAny
<<= xName
->getAccessibleName();
497 sal_Bool
VCLXAccessibleBox::setCurrentValue( const Any
& aNumber
)
498 throw( RuntimeException
, std::exception
)
500 SolarMutexGuard aSolarGuard
;
501 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
504 bool bValid
= (aNumber
>>= fValue
);
513 Any
VCLXAccessibleBox::getMaximumValue( )
514 throw( RuntimeException
, std::exception
)
520 Any
VCLXAccessibleBox::getMinimumValue( )
521 throw( RuntimeException
, std::exception
)
527 // Set the INDETERMINATE state when there is no selected item for combobox
528 void VCLXAccessibleBox::FillAccessibleStateSet( utl::AccessibleStateSetHelper
& rStateSet
)
530 VCLXAccessibleComponent::FillAccessibleStateSet(rStateSet
);
531 if (m_aBoxType
== COMBOBOX
)
534 sal_Int32 nEntryCount
= 0;
535 VclPtr
< ComboBox
> pComboBox
= GetAs
< ComboBox
>();
536 if (pComboBox
!= nullptr)
538 Edit
* pSubEdit
= pComboBox
->GetSubEdit();
540 sText
= pSubEdit
->GetText();
541 nEntryCount
= pComboBox
->GetEntryCount();
543 if ( sText
.isEmpty() && nEntryCount
> 0 )
544 rStateSet
.AddState(AccessibleStateType::INDETERMINATE
);
546 else if (m_aBoxType
== LISTBOX
&& m_bIsDropDownBox
)
548 sal_Int32 nSelectedEntryCount
= 0;
549 VclPtr
< ListBox
> pListBox
= GetAs
< ListBox
>();
550 if (pListBox
!= nullptr && pListBox
->GetEntryCount() > 0)
552 nSelectedEntryCount
= pListBox
->GetSelectEntryCount();
553 if ( nSelectedEntryCount
== 0)
554 rStateSet
.AddState(AccessibleStateType::INDETERMINATE
);
559 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */