1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "XULComboboxAccessible.h"
7
8 #include "LocalAccessible-inl.h"
9 #include "nsAccessibilityService.h"
10 #include "DocAccessible.h"
11 #include "nsCoreUtils.h"
12 #include "Role.h"
13 #include "States.h"
14
15 #include "mozilla/dom/Element.h"
16 #include "nsIDOMXULMenuListElement.h"
17
18 using namespace mozilla::a11y;
19
20 ////////////////////////////////////////////////////////////////////////////////
21 // XULComboboxAccessible
22 ////////////////////////////////////////////////////////////////////////////////
23
XULComboboxAccessible(nsIContent * aContent,DocAccessible * aDoc)24 XULComboboxAccessible::XULComboboxAccessible(nsIContent* aContent,
25 DocAccessible* aDoc)
26 : AccessibleWrap(aContent, aDoc) {
27 mGenericTypes |= eCombobox;
28 }
29
NativeRole() const30 role XULComboboxAccessible::NativeRole() const { return roles::COMBOBOX; }
31
NativeState() const32 uint64_t XULComboboxAccessible::NativeState() const {
33 // As a nsComboboxAccessible we can have the following states:
34 // STATE_FOCUSED
35 // STATE_FOCUSABLE
36 // STATE_HASPOPUP
37 // STATE_EXPANDED
38 // STATE_COLLAPSED
39
40 // Get focus status from base class
41 uint64_t state = LocalAccessible::NativeState();
42
43 nsCOMPtr<nsIDOMXULMenuListElement> menuList = Elm()->AsXULMenuList();
44 if (menuList) {
45 bool isOpen = false;
46 menuList->GetOpen(&isOpen);
47 if (isOpen) {
48 state |= states::EXPANDED;
49 } else {
50 state |= states::COLLAPSED;
51 }
52 }
53
54 return state | states::HASPOPUP;
55 }
56
Description(nsString & aDescription) const57 void XULComboboxAccessible::Description(nsString& aDescription) const {
58 aDescription.Truncate();
59 // Use description of currently focused option
60 nsCOMPtr<nsIDOMXULMenuListElement> menuListElm = Elm()->AsXULMenuList();
61 if (!menuListElm) return;
62
63 nsCOMPtr<dom::Element> focusedOptionItem;
64 menuListElm->GetSelectedItem(getter_AddRefs(focusedOptionItem));
65 if (focusedOptionItem && mDoc) {
66 LocalAccessible* focusedOptionAcc = mDoc->GetAccessible(focusedOptionItem);
67 if (focusedOptionAcc) focusedOptionAcc->Description(aDescription);
68 }
69 }
70
Value(nsString & aValue) const71 void XULComboboxAccessible::Value(nsString& aValue) const {
72 aValue.Truncate();
73
74 // The value is the option or text shown entered in the combobox.
75 nsCOMPtr<nsIDOMXULMenuListElement> menuList = Elm()->AsXULMenuList();
76 if (menuList) menuList->GetLabel(aValue);
77 }
78
HasPrimaryAction() const79 bool XULComboboxAccessible::HasPrimaryAction() const { return true; }
80
DoAction(uint8_t aIndex) const81 bool XULComboboxAccessible::DoAction(uint8_t aIndex) const {
82 if (aIndex != XULComboboxAccessible::eAction_Click) return false;
83
84 // Programmaticaly toggle the combo box.
85 nsCOMPtr<nsIDOMXULMenuListElement> menuList = Elm()->AsXULMenuList();
86 if (!menuList) return false;
87
88 bool isDroppedDown = false;
89 menuList->GetOpen(&isDroppedDown);
90 menuList->SetOpen(!isDroppedDown);
91 return true;
92 }
93
ActionNameAt(uint8_t aIndex,nsAString & aName)94 void XULComboboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
95 aName.Truncate();
96 if (aIndex != XULComboboxAccessible::eAction_Click) return;
97
98 nsCOMPtr<nsIDOMXULMenuListElement> menuList = Elm()->AsXULMenuList();
99 if (!menuList) return;
100
101 bool isDroppedDown = false;
102 menuList->GetOpen(&isDroppedDown);
103 if (isDroppedDown) {
104 aName.AssignLiteral("close");
105 } else {
106 aName.AssignLiteral("open");
107 }
108 }
109
110 ////////////////////////////////////////////////////////////////////////////////
111 // Widgets
112
IsActiveWidget() const113 bool XULComboboxAccessible::IsActiveWidget() const {
114 if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
115 nsGkAtoms::_true, eIgnoreCase)) {
116 int32_t childCount = mChildren.Length();
117 for (int32_t idx = 0; idx < childCount; idx++) {
118 LocalAccessible* child = mChildren[idx];
119 if (child->Role() == roles::ENTRY) {
120 return FocusMgr()->HasDOMFocus(child->GetContent());
121 }
122 }
123 return false;
124 }
125
126 return FocusMgr()->HasDOMFocus(mContent);
127 }
128
AreItemsOperable() const129 bool XULComboboxAccessible::AreItemsOperable() const {
130 nsCOMPtr<nsIDOMXULMenuListElement> menuListElm = Elm()->AsXULMenuList();
131 if (menuListElm) {
132 bool isOpen = false;
133 menuListElm->GetOpen(&isOpen);
134 return isOpen;
135 }
136
137 return false;
138 }
139