Line data Source code
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 "Accessible-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 "nsIAutoCompleteInput.h"
16 : #include "nsIDOMXULMenuListElement.h"
17 : #include "nsIDOMXULSelectCntrlItemEl.h"
18 :
19 : using namespace mozilla::a11y;
20 :
21 : ////////////////////////////////////////////////////////////////////////////////
22 : // XULComboboxAccessible
23 : ////////////////////////////////////////////////////////////////////////////////
24 :
25 0 : XULComboboxAccessible::
26 0 : XULComboboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
27 0 : AccessibleWrap(aContent, aDoc)
28 : {
29 0 : if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
30 : nsGkAtoms::autocomplete, eIgnoreCase))
31 0 : mGenericTypes |= eAutoComplete;
32 : else
33 0 : mGenericTypes |= eCombobox;
34 :
35 : // Both the XUL <textbox type="autocomplete"> and <menulist editable="true">
36 : // widgets use XULComboboxAccessible. We need to walk the anonymous children
37 : // for these so that the entry field is a child. Otherwise no XBL children.
38 0 : if (!mContent->NodeInfo()->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL) &&
39 0 : !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
40 : nsGkAtoms::_true, eIgnoreCase)) {
41 0 : mStateFlags |= eNoXBLKids;
42 : }
43 0 : }
44 :
45 : role
46 0 : XULComboboxAccessible::NativeRole()
47 : {
48 0 : return IsAutoComplete() ? roles::AUTOCOMPLETE : roles::COMBOBOX;
49 : }
50 :
51 : uint64_t
52 0 : XULComboboxAccessible::NativeState()
53 : {
54 : // As a nsComboboxAccessible we can have the following states:
55 : // STATE_FOCUSED
56 : // STATE_FOCUSABLE
57 : // STATE_HASPOPUP
58 : // STATE_EXPANDED
59 : // STATE_COLLAPSED
60 :
61 : // Get focus status from base class
62 0 : uint64_t state = Accessible::NativeState();
63 :
64 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
65 0 : if (menuList) {
66 0 : bool isOpen = false;
67 0 : menuList->GetOpen(&isOpen);
68 0 : if (isOpen)
69 0 : state |= states::EXPANDED;
70 : else
71 0 : state |= states::COLLAPSED;
72 : }
73 :
74 0 : return state | states::HASPOPUP;
75 : }
76 :
77 : void
78 0 : XULComboboxAccessible::Description(nsString& aDescription)
79 : {
80 0 : aDescription.Truncate();
81 : // Use description of currently focused option
82 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuListElm(do_QueryInterface(mContent));
83 0 : if (!menuListElm)
84 0 : return;
85 :
86 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> focusedOptionItem;
87 0 : menuListElm->GetSelectedItem(getter_AddRefs(focusedOptionItem));
88 : nsCOMPtr<nsIContent> focusedOptionContent =
89 0 : do_QueryInterface(focusedOptionItem);
90 0 : if (focusedOptionContent && mDoc) {
91 0 : Accessible* focusedOptionAcc = mDoc->GetAccessible(focusedOptionContent);
92 0 : if (focusedOptionAcc)
93 0 : focusedOptionAcc->Description(aDescription);
94 : }
95 : }
96 :
97 : void
98 0 : XULComboboxAccessible::Value(nsString& aValue)
99 : {
100 0 : aValue.Truncate();
101 :
102 : // The value is the option or text shown entered in the combobox.
103 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
104 0 : if (menuList)
105 0 : menuList->GetLabel(aValue);
106 0 : }
107 :
108 : uint8_t
109 0 : XULComboboxAccessible::ActionCount()
110 : {
111 : // Just one action (click).
112 0 : return 1;
113 : }
114 :
115 : bool
116 0 : XULComboboxAccessible::DoAction(uint8_t aIndex)
117 : {
118 0 : if (aIndex != XULComboboxAccessible::eAction_Click)
119 0 : return false;
120 :
121 : // Programmaticaly toggle the combo box.
122 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
123 0 : if (!menuList)
124 0 : return false;
125 :
126 0 : bool isDroppedDown = false;
127 0 : menuList->GetOpen(&isDroppedDown);
128 0 : menuList->SetOpen(!isDroppedDown);
129 0 : return true;
130 : }
131 :
132 : void
133 0 : XULComboboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
134 : {
135 0 : aName.Truncate();
136 0 : if (aIndex != XULComboboxAccessible::eAction_Click)
137 0 : return;
138 :
139 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
140 0 : if (!menuList)
141 0 : return;
142 :
143 0 : bool isDroppedDown = false;
144 0 : menuList->GetOpen(&isDroppedDown);
145 0 : if (isDroppedDown)
146 0 : aName.AssignLiteral("close");
147 : else
148 0 : aName.AssignLiteral("open");
149 : }
150 :
151 : ////////////////////////////////////////////////////////////////////////////////
152 : // Widgets
153 :
154 : bool
155 0 : XULComboboxAccessible::IsActiveWidget() const
156 : {
157 0 : if (IsAutoComplete() ||
158 0 : mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
159 : nsGkAtoms::_true, eIgnoreCase)) {
160 0 : int32_t childCount = mChildren.Length();
161 0 : for (int32_t idx = 0; idx < childCount; idx++) {
162 0 : Accessible* child = mChildren[idx];
163 0 : if (child->Role() == roles::ENTRY)
164 0 : return FocusMgr()->HasDOMFocus(child->GetContent());
165 : }
166 0 : return false;
167 : }
168 :
169 0 : return FocusMgr()->HasDOMFocus(mContent);
170 : }
171 :
172 : bool
173 0 : XULComboboxAccessible::AreItemsOperable() const
174 : {
175 0 : if (IsAutoComplete()) {
176 : nsCOMPtr<nsIAutoCompleteInput> autoCompleteInputElm =
177 0 : do_QueryInterface(mContent);
178 0 : if (autoCompleteInputElm) {
179 0 : bool isOpen = false;
180 0 : autoCompleteInputElm->GetPopupOpen(&isOpen);
181 0 : return isOpen;
182 : }
183 0 : return false;
184 : }
185 :
186 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuListElm = do_QueryInterface(mContent);
187 0 : if (menuListElm) {
188 0 : bool isOpen = false;
189 0 : menuListElm->GetOpen(&isOpen);
190 0 : return isOpen;
191 : }
192 :
193 0 : return false;
194 : }
|