Branch libreoffice-5-0-4
[LibreOffice.git] / accessibility / source / standard / vclxaccessiblebox.cxx
blob1e801a86e8fbd3ff497687ac4adbfeb57beb1189
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 .
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),
44 m_aBoxType (aType),
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;
54 else
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;
88 else
90 // Release text field.
91 aOldValue <<= m_xText;
92 m_xText = NULL;
94 // Tell the listeners about the new/removed child.
95 NotifyAccessibleEvent (
96 AccessibleEventId::CHILD,
97 aOldValue, aNewValue);
102 break;
104 default:
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());
119 if ( pList == NULL )
121 getAccessibleChild ( m_bHasTextChild ? 1 : 0 );
122 pList = static_cast<VCLXAccessibleList*>(m_xList.get());
124 if ( pList != NULL )
126 pList->ProcessWindowEvent (rVclWindowEvent, m_bIsDropDownBox);
127 #if defined WNT
128 if (m_bIsDropDownBox)
130 NotifyAccessibleEvent(AccessibleEventId::VALUE_CHANGED, Any(), Any());
132 #endif
134 break;
136 case VCLEVENT_DROPDOWN_OPEN:
138 VCLXAccessibleList* pList = static_cast<VCLXAccessibleList*>(m_xList.get());
139 if ( pList == NULL )
141 getAccessibleChild ( m_bHasTextChild ? 1 : 0 );
142 pList = static_cast<VCLXAccessibleList*>(m_xList.get());
144 if ( pList != NULL )
146 pList->ProcessWindowEvent (rVclWindowEvent);
147 pList->HandleDropOpen();
149 break;
151 case VCLEVENT_DROPDOWN_CLOSE:
153 VCLXAccessibleList* pList = static_cast<VCLXAccessibleList*>(m_xList.get());
154 if ( pList == NULL )
156 getAccessibleChild ( m_bHasTextChild ? 1 : 0 );
157 pList = static_cast<VCLXAccessibleList*>(m_xList.get());
159 if ( pList != NULL )
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 );
170 break;
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);
178 if ( xText.is() )
180 OUString sText = xText->getSelectedText();
181 if ( sText.isEmpty() )
182 sText = xText->getText();
183 pList->UpdateSelection_Acc(sText, m_bIsDropDownBox);
184 #if defined WNT
185 if (m_bIsDropDownBox || ( !m_bIsDropDownBox && m_aBoxType==COMBOBOX))
186 NotifyAccessibleEvent(AccessibleEventId::VALUE_CHANGED, Any(), Any());
187 #endif
190 break;
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());
205 if ( pList == NULL )
207 getAccessibleChild ( m_bHasTextChild ? 1 : 0 );
208 pList = static_cast<VCLXAccessibleList*>(m_xList.get());
210 if ( pList != NULL )
211 pList->ProcessWindowEvent (rVclWindowEvent);
212 break;
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);
226 if ( xText.is() )
228 OUString sText = xText->getSelectedText();
229 if ( sText.isEmpty() )
230 sText = xText->getText();
231 pList->UpdateSelection (sText);
234 break;
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)
245 if (m_xText.is())
247 Reference<XAccessibleContext> xContext = m_xText->getAccessibleContext();
248 VCLXAccessibleEdit* pEdit = static_cast<VCLXAccessibleEdit*>(xContext.get());
249 if (pEdit != NULL)
250 pEdit->ProcessWindowEvent (rVclWindowEvent);
253 break;
254 default:
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() );
269 return this;
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;
284 if (IsValid())
285 nCount += (m_bHasTextChild?1:0) + (m_bHasListChild?1:0);
286 else
288 // Object not valid anymore. Release references to children.
289 m_bHasTextChild = false;
290 m_xText = NULL;
291 m_bHasListChild = false;
292 m_xList = NULL;
295 return nCount;
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;
308 if (IsValid())
310 if (i==1 || ! m_bHasTextChild)
312 // List.
313 if ( ! m_xList.is())
315 VCLXAccessibleList* pList = new VCLXAccessibleList ( GetVCLXWindow(),
316 (m_aBoxType == LISTBOX ? VCLXAccessibleList::LISTBOX : VCLXAccessibleList::COMBOBOX),
317 this);
318 pList->SetIndexInParent (i);
319 m_xList = pList;
321 xChild = m_xList;
323 else
325 // Text Field.
326 if ( ! m_xText.is())
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);
341 xChild = m_xText;
345 return xChild;
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;
358 else
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;
367 else
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
379 // the other boxes.
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();
405 bNotify = true;
408 else if (m_aBoxType == LISTBOX)
410 VclPtr< ListBox > pListBox = GetAs< ListBox >();
411 if (pListBox != nullptr)
413 pListBox->ToggleDropDown();
414 bNotify = true;
419 if (bNotify)
420 NotifyAccessibleEvent (AccessibleEventId::ACTION_CHANGED, Any(), Any());
422 return bNotify;
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);
435 return OUString();
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();
448 // ... which key?
449 return xRet;
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() );
466 Any aAny;
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);
471 if ( xText.is() )
473 OUString sText = xText->getText();
474 aAny <<= sText;
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);
486 if(xName.is())
488 aAny <<= xName->getAccessibleName();
494 return aAny;
497 sal_Bool VCLXAccessibleBox::setCurrentValue( const Any& aNumber )
498 throw( RuntimeException, std::exception )
500 SolarMutexGuard aSolarGuard;
501 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
503 OUString fValue;
504 bool bValid = (aNumber >>= fValue);
505 if( bValid )
509 return bValid;
513 Any VCLXAccessibleBox::getMaximumValue( )
514 throw( RuntimeException, std::exception )
516 Any aAny;
517 return aAny;
520 Any VCLXAccessibleBox::getMinimumValue( )
521 throw( RuntimeException, std::exception )
523 Any aAny;
524 return aAny;
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 )
533 OUString sText;
534 sal_Int32 nEntryCount = 0;
535 VclPtr< ComboBox > pComboBox = GetAs< ComboBox >();
536 if (pComboBox != nullptr)
538 Edit* pSubEdit = pComboBox->GetSubEdit();
539 if ( pSubEdit)
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: */