1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/xul/XULComboboxAccessible.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,215 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "XULComboboxAccessible.h" 1.10 + 1.11 +#include "Accessible-inl.h" 1.12 +#include "nsAccessibilityService.h" 1.13 +#include "DocAccessible.h" 1.14 +#include "nsCoreUtils.h" 1.15 +#include "Role.h" 1.16 +#include "States.h" 1.17 + 1.18 +#include "nsIAutoCompleteInput.h" 1.19 +#include "nsIDOMXULMenuListElement.h" 1.20 +#include "nsIDOMXULSelectCntrlItemEl.h" 1.21 + 1.22 +using namespace mozilla::a11y; 1.23 + 1.24 +//////////////////////////////////////////////////////////////////////////////// 1.25 +// XULComboboxAccessible 1.26 +//////////////////////////////////////////////////////////////////////////////// 1.27 + 1.28 +XULComboboxAccessible:: 1.29 + XULComboboxAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.30 + AccessibleWrap(aContent, aDoc) 1.31 +{ 1.32 + if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 1.33 + nsGkAtoms::autocomplete, eIgnoreCase)) 1.34 + mGenericTypes |= eAutoComplete; 1.35 + else 1.36 + mGenericTypes |= eCombobox; 1.37 +} 1.38 + 1.39 +role 1.40 +XULComboboxAccessible::NativeRole() 1.41 +{ 1.42 + return IsAutoComplete() ? roles::AUTOCOMPLETE : roles::COMBOBOX; 1.43 +} 1.44 + 1.45 +uint64_t 1.46 +XULComboboxAccessible::NativeState() 1.47 +{ 1.48 + // As a nsComboboxAccessible we can have the following states: 1.49 + // STATE_FOCUSED 1.50 + // STATE_FOCUSABLE 1.51 + // STATE_HASPOPUP 1.52 + // STATE_EXPANDED 1.53 + // STATE_COLLAPSED 1.54 + 1.55 + // Get focus status from base class 1.56 + uint64_t state = Accessible::NativeState(); 1.57 + 1.58 + nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent)); 1.59 + if (menuList) { 1.60 + bool isOpen = false; 1.61 + menuList->GetOpen(&isOpen); 1.62 + if (isOpen) 1.63 + state |= states::EXPANDED; 1.64 + else 1.65 + state |= states::COLLAPSED; 1.66 + } 1.67 + 1.68 + return state | states::HASPOPUP; 1.69 +} 1.70 + 1.71 +void 1.72 +XULComboboxAccessible::Description(nsString& aDescription) 1.73 +{ 1.74 + aDescription.Truncate(); 1.75 + // Use description of currently focused option 1.76 + nsCOMPtr<nsIDOMXULMenuListElement> menuListElm(do_QueryInterface(mContent)); 1.77 + if (!menuListElm) 1.78 + return; 1.79 + 1.80 + nsCOMPtr<nsIDOMXULSelectControlItemElement> focusedOptionItem; 1.81 + menuListElm->GetSelectedItem(getter_AddRefs(focusedOptionItem)); 1.82 + nsCOMPtr<nsIContent> focusedOptionContent = 1.83 + do_QueryInterface(focusedOptionItem); 1.84 + if (focusedOptionContent && mDoc) { 1.85 + Accessible* focusedOptionAcc = mDoc->GetAccessible(focusedOptionContent); 1.86 + if (focusedOptionAcc) 1.87 + focusedOptionAcc->Description(aDescription); 1.88 + } 1.89 +} 1.90 + 1.91 +void 1.92 +XULComboboxAccessible::Value(nsString& aValue) 1.93 +{ 1.94 + aValue.Truncate(); 1.95 + 1.96 + // The value is the option or text shown entered in the combobox. 1.97 + nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent)); 1.98 + if (menuList) 1.99 + menuList->GetLabel(aValue); 1.100 +} 1.101 + 1.102 +bool 1.103 +XULComboboxAccessible::CanHaveAnonChildren() 1.104 +{ 1.105 + if (mContent->NodeInfo()->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL) || 1.106 + mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable, 1.107 + nsGkAtoms::_true, eIgnoreCase)) { 1.108 + // Both the XUL <textbox type="autocomplete"> and <menulist editable="true"> widgets 1.109 + // use XULComboboxAccessible. We need to walk the anonymous children for these 1.110 + // so that the entry field is a child 1.111 + return true; 1.112 + } 1.113 + 1.114 + // Argument of false indicates we don't walk anonymous children for 1.115 + // menuitems 1.116 + return false; 1.117 +} 1.118 + 1.119 +uint8_t 1.120 +XULComboboxAccessible::ActionCount() 1.121 +{ 1.122 + // Just one action (click). 1.123 + return 1; 1.124 +} 1.125 + 1.126 +NS_IMETHODIMP 1.127 +XULComboboxAccessible::DoAction(uint8_t aIndex) 1.128 +{ 1.129 + if (aIndex != XULComboboxAccessible::eAction_Click) { 1.130 + return NS_ERROR_INVALID_ARG; 1.131 + } 1.132 + 1.133 + if (IsDefunct()) 1.134 + return NS_ERROR_FAILURE; 1.135 + 1.136 + // Programmaticaly toggle the combo box. 1.137 + nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent)); 1.138 + if (!menuList) { 1.139 + return NS_ERROR_FAILURE; 1.140 + } 1.141 + bool isDroppedDown; 1.142 + menuList->GetOpen(&isDroppedDown); 1.143 + return menuList->SetOpen(!isDroppedDown); 1.144 +} 1.145 + 1.146 +NS_IMETHODIMP 1.147 +XULComboboxAccessible::GetActionName(uint8_t aIndex, nsAString& aName) 1.148 +{ 1.149 + if (aIndex != XULComboboxAccessible::eAction_Click) { 1.150 + return NS_ERROR_INVALID_ARG; 1.151 + } 1.152 + 1.153 + if (IsDefunct()) 1.154 + return NS_ERROR_FAILURE; 1.155 + 1.156 + // Our action name is the reverse of our state: 1.157 + // if we are close -> open is our name. 1.158 + // if we are open -> close is our name. 1.159 + // Uses the frame to get the state, updated on every click. 1.160 + 1.161 + nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent)); 1.162 + if (!menuList) { 1.163 + return NS_ERROR_FAILURE; 1.164 + } 1.165 + bool isDroppedDown; 1.166 + menuList->GetOpen(&isDroppedDown); 1.167 + if (isDroppedDown) 1.168 + aName.AssignLiteral("close"); 1.169 + else 1.170 + aName.AssignLiteral("open"); 1.171 + 1.172 + return NS_OK; 1.173 +} 1.174 + 1.175 +//////////////////////////////////////////////////////////////////////////////// 1.176 +// Widgets 1.177 + 1.178 +bool 1.179 +XULComboboxAccessible::IsActiveWidget() const 1.180 +{ 1.181 + if (IsAutoComplete() || 1.182 + mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable, 1.183 + nsGkAtoms::_true, eIgnoreCase)) { 1.184 + int32_t childCount = mChildren.Length(); 1.185 + for (int32_t idx = 0; idx < childCount; idx++) { 1.186 + Accessible* child = mChildren[idx]; 1.187 + if (child->Role() == roles::ENTRY) 1.188 + return FocusMgr()->HasDOMFocus(child->GetContent()); 1.189 + } 1.190 + return false; 1.191 + } 1.192 + 1.193 + return FocusMgr()->HasDOMFocus(mContent); 1.194 +} 1.195 + 1.196 +bool 1.197 +XULComboboxAccessible::AreItemsOperable() const 1.198 +{ 1.199 + if (IsAutoComplete()) { 1.200 + nsCOMPtr<nsIAutoCompleteInput> autoCompleteInputElm = 1.201 + do_QueryInterface(mContent); 1.202 + if (autoCompleteInputElm) { 1.203 + bool isOpen = false; 1.204 + autoCompleteInputElm->GetPopupOpen(&isOpen); 1.205 + return isOpen; 1.206 + } 1.207 + return false; 1.208 + } 1.209 + 1.210 + nsCOMPtr<nsIDOMXULMenuListElement> menuListElm = do_QueryInterface(mContent); 1.211 + if (menuListElm) { 1.212 + bool isOpen = false; 1.213 + menuListElm->GetOpen(&isOpen); 1.214 + return isOpen; 1.215 + } 1.216 + 1.217 + return false; 1.218 +}