no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / accessible / xul / XULListboxAccessible.cpp
blobd80bac1ca030e8ea87fba00bd7da176bae991110
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/. */
6 #include "XULListboxAccessible.h"
8 #include "LocalAccessible-inl.h"
9 #include "nsAccessibilityService.h"
10 #include "nsAccUtils.h"
11 #include "DocAccessible.h"
12 #include "mozilla/a11y/Role.h"
13 #include "States.h"
15 #include "nsComponentManagerUtils.h"
16 #include "nsIAutoCompletePopup.h"
17 #include "nsIDOMXULMenuListElement.h"
18 #include "nsIDOMXULMultSelectCntrlEl.h"
19 #include "nsIDOMXULSelectCntrlItemEl.h"
20 #include "nsINodeList.h"
22 using namespace mozilla::a11y;
24 ////////////////////////////////////////////////////////////////////////////////
25 // XULColumAccessible
26 ////////////////////////////////////////////////////////////////////////////////
28 XULColumAccessible::XULColumAccessible(nsIContent* aContent,
29 DocAccessible* aDoc)
30 : AccessibleWrap(aContent, aDoc) {}
32 role XULColumAccessible::NativeRole() const { return roles::LIST; }
34 uint64_t XULColumAccessible::NativeState() const { return states::READONLY; }
36 ////////////////////////////////////////////////////////////////////////////////
37 // XULColumnItemAccessible
38 ////////////////////////////////////////////////////////////////////////////////
40 XULColumnItemAccessible::XULColumnItemAccessible(nsIContent* aContent,
41 DocAccessible* aDoc)
42 : LeafAccessible(aContent, aDoc) {}
44 role XULColumnItemAccessible::NativeRole() const { return roles::COLUMNHEADER; }
46 uint64_t XULColumnItemAccessible::NativeState() const {
47 return states::READONLY;
50 bool XULColumnItemAccessible::HasPrimaryAction() const { return true; }
52 void XULColumnItemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
53 if (aIndex == eAction_Click) aName.AssignLiteral("click");
56 ////////////////////////////////////////////////////////////////////////////////
57 // XULListboxAccessible
58 ////////////////////////////////////////////////////////////////////////////////
60 XULListboxAccessible::XULListboxAccessible(nsIContent* aContent,
61 DocAccessible* aDoc)
62 : XULSelectControlAccessible(aContent, aDoc) {
63 dom::Element* parentEl = mContent->GetParentElement();
64 if (parentEl) {
65 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
66 parentEl->AsAutoCompletePopup();
67 if (autoCompletePopupElm) mGenericTypes |= eAutoCompletePopup;
70 if (IsMulticolumn()) mGenericTypes |= eTable;
73 ////////////////////////////////////////////////////////////////////////////////
74 // XULListboxAccessible: LocalAccessible
76 uint64_t XULListboxAccessible::NativeState() const {
77 // As a XULListboxAccessible we can have the following states:
78 // FOCUSED, READONLY, FOCUSABLE
80 // Get focus status from base class
81 uint64_t states = LocalAccessible::NativeState();
83 // see if we are multiple select if so set ourselves as such
85 if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::seltype,
86 nsGkAtoms::multiple, eCaseMatters)) {
87 states |= states::MULTISELECTABLE | states::EXTSELECTABLE;
90 return states;
93 role XULListboxAccessible::NativeRole() const {
94 // A richlistbox is used with the new autocomplete URL bar, and has a parent
95 // popup <panel>.
96 if (mContent->GetParent() &&
97 mContent->GetParent()->IsXULElement(nsGkAtoms::panel)) {
98 return roles::COMBOBOX_LIST;
101 return IsMulticolumn() ? roles::TABLE : roles::LISTBOX;
104 ////////////////////////////////////////////////////////////////////////////////
105 // XULListboxAccessible: Table
107 uint32_t XULListboxAccessible::ColCount() const { return 0; }
109 uint32_t XULListboxAccessible::RowCount() {
110 nsCOMPtr<nsIDOMXULSelectControlElement> element = Elm()->AsXULSelectControl();
112 uint32_t itemCount = 0;
113 if (element) element->GetItemCount(&itemCount);
115 return itemCount;
118 LocalAccessible* XULListboxAccessible::CellAt(uint32_t aRowIndex,
119 uint32_t aColumnIndex) {
120 nsCOMPtr<nsIDOMXULSelectControlElement> control = Elm()->AsXULSelectControl();
121 NS_ENSURE_TRUE(control, nullptr);
123 RefPtr<dom::Element> element;
124 control->GetItemAtIndex(aRowIndex, getter_AddRefs(element));
125 if (!element) return nullptr;
127 LocalAccessible* row = mDoc->GetAccessible(element);
128 NS_ENSURE_TRUE(row, nullptr);
130 return row->LocalChildAt(aColumnIndex);
133 bool XULListboxAccessible::IsColSelected(uint32_t aColIdx) {
134 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
135 Elm()->AsXULMultiSelectControl();
136 NS_ASSERTION(control,
137 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
139 int32_t selectedrowCount = 0;
140 nsresult rv = control->GetSelectedCount(&selectedrowCount);
141 NS_ENSURE_SUCCESS(rv, false);
143 return selectedrowCount == static_cast<int32_t>(RowCount());
146 bool XULListboxAccessible::IsRowSelected(uint32_t aRowIdx) {
147 nsCOMPtr<nsIDOMXULSelectControlElement> control = Elm()->AsXULSelectControl();
148 NS_ASSERTION(control, "Doesn't implement nsIDOMXULSelectControlElement.");
150 RefPtr<dom::Element> element;
151 nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(element));
152 NS_ENSURE_SUCCESS(rv, false);
153 if (!element) {
154 return false;
157 nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
158 element->AsXULSelectControlItem();
160 bool isSelected = false;
161 item->GetSelected(&isSelected);
162 return isSelected;
165 bool XULListboxAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
166 return IsRowSelected(aRowIdx);
169 uint32_t XULListboxAccessible::SelectedCellCount() {
170 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
171 Elm()->AsXULMultiSelectControl();
172 NS_ASSERTION(control,
173 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
175 nsCOMPtr<nsINodeList> selectedItems;
176 control->GetSelectedItems(getter_AddRefs(selectedItems));
177 if (!selectedItems) return 0;
179 uint32_t selectedItemsCount = selectedItems->Length();
181 return selectedItemsCount * ColCount();
184 uint32_t XULListboxAccessible::SelectedColCount() {
185 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
186 Elm()->AsXULMultiSelectControl();
187 NS_ASSERTION(control,
188 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
190 int32_t selectedRowCount = 0;
191 nsresult rv = control->GetSelectedCount(&selectedRowCount);
192 NS_ENSURE_SUCCESS(rv, 0);
194 return selectedRowCount > 0 &&
195 selectedRowCount == static_cast<int32_t>(RowCount())
196 ? ColCount()
197 : 0;
200 uint32_t XULListboxAccessible::SelectedRowCount() {
201 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
202 Elm()->AsXULMultiSelectControl();
203 NS_ASSERTION(control,
204 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
206 int32_t selectedRowCount = 0;
207 nsresult rv = control->GetSelectedCount(&selectedRowCount);
208 NS_ENSURE_SUCCESS(rv, 0);
210 return selectedRowCount >= 0 ? selectedRowCount : 0;
213 void XULListboxAccessible::SelectedCells(nsTArray<Accessible*>* aCells) {
214 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
215 Elm()->AsXULMultiSelectControl();
216 NS_ASSERTION(control,
217 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
219 nsCOMPtr<nsINodeList> selectedItems;
220 control->GetSelectedItems(getter_AddRefs(selectedItems));
221 if (!selectedItems) return;
223 uint32_t selectedItemsCount = selectedItems->Length();
225 for (uint32_t index = 0; index < selectedItemsCount; index++) {
226 nsIContent* itemContent = selectedItems->Item(index);
227 LocalAccessible* item = mDoc->GetAccessible(itemContent);
229 if (item) {
230 uint32_t cellCount = item->ChildCount();
231 for (uint32_t cellIdx = 0; cellIdx < cellCount; cellIdx++) {
232 LocalAccessible* cell = mChildren[cellIdx];
233 if (cell->Role() == roles::CELL) aCells->AppendElement(cell);
239 void XULListboxAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells) {
240 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
241 Elm()->AsXULMultiSelectControl();
242 NS_ASSERTION(control,
243 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
245 nsCOMPtr<nsINodeList> selectedItems;
246 control->GetSelectedItems(getter_AddRefs(selectedItems));
247 if (!selectedItems) return;
249 uint32_t selectedItemsCount = selectedItems->Length();
251 uint32_t colCount = ColCount();
252 aCells->SetCapacity(selectedItemsCount * colCount);
253 aCells->AppendElements(selectedItemsCount * colCount);
255 for (uint32_t selItemsIdx = 0, cellsIdx = 0; selItemsIdx < selectedItemsCount;
256 selItemsIdx++) {
257 nsIContent* itemContent = selectedItems->Item(selItemsIdx);
259 nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
260 itemContent->AsElement()->AsXULSelectControlItem();
261 if (item) {
262 int32_t itemIdx = -1;
263 control->GetIndexOfItem(item, &itemIdx);
264 if (itemIdx >= 0) {
265 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++, cellsIdx++) {
266 aCells->ElementAt(cellsIdx) = itemIdx * colCount + colIdx;
273 void XULListboxAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols) {
274 uint32_t selColCount = SelectedColCount();
275 aCols->SetCapacity(selColCount);
277 for (uint32_t colIdx = 0; colIdx < selColCount; colIdx++) {
278 aCols->AppendElement(colIdx);
282 void XULListboxAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows) {
283 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
284 Elm()->AsXULMultiSelectControl();
285 NS_ASSERTION(control,
286 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
288 nsCOMPtr<nsINodeList> selectedItems;
289 control->GetSelectedItems(getter_AddRefs(selectedItems));
290 if (!selectedItems) return;
292 uint32_t rowCount = selectedItems->Length();
294 if (!rowCount) return;
296 aRows->SetCapacity(rowCount);
297 aRows->AppendElements(rowCount);
299 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
300 nsIContent* itemContent = selectedItems->Item(rowIdx);
301 nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
302 itemContent->AsElement()->AsXULSelectControlItem();
304 if (item) {
305 int32_t itemIdx = -1;
306 control->GetIndexOfItem(item, &itemIdx);
307 if (itemIdx >= 0) aRows->ElementAt(rowIdx) = itemIdx;
312 ////////////////////////////////////////////////////////////////////////////////
313 // XULListboxAccessible: Widgets
315 bool XULListboxAccessible::IsWidget() const { return true; }
317 bool XULListboxAccessible::IsActiveWidget() const {
318 if (IsAutoCompletePopup()) {
319 nsIContent* parentContent = mContent->GetParent();
320 if (parentContent) {
321 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
322 parentContent->AsElement()->AsAutoCompletePopup();
323 if (autoCompletePopupElm) {
324 bool isOpen = false;
325 autoCompletePopupElm->GetPopupOpen(&isOpen);
326 return isOpen;
330 return FocusMgr()->HasDOMFocus(mContent);
333 bool XULListboxAccessible::AreItemsOperable() const {
334 if (IsAutoCompletePopup()) {
335 nsIContent* parentContent = mContent->GetParent();
336 if (parentContent) {
337 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
338 parentContent->AsElement()->AsAutoCompletePopup();
339 if (autoCompletePopupElm) {
340 bool isOpen = false;
341 autoCompletePopupElm->GetPopupOpen(&isOpen);
342 return isOpen;
346 return true;
349 LocalAccessible* XULListboxAccessible::ContainerWidget() const {
350 return nullptr;
353 ////////////////////////////////////////////////////////////////////////////////
354 // XULListitemAccessible
355 ////////////////////////////////////////////////////////////////////////////////
357 XULListitemAccessible::XULListitemAccessible(nsIContent* aContent,
358 DocAccessible* aDoc)
359 : XULMenuitemAccessible(aContent, aDoc) {
360 mIsCheckbox = mContent->AsElement()->AttrValueIs(
361 kNameSpaceID_None, nsGkAtoms::type, nsGkAtoms::checkbox, eCaseMatters);
362 mType = eXULListItemType;
365 XULListitemAccessible::~XULListitemAccessible() {}
367 LocalAccessible* XULListitemAccessible::GetListAccessible() const {
368 if (IsDefunct()) return nullptr;
370 nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
371 Elm()->AsXULSelectControlItem();
372 if (!listItem) return nullptr;
374 RefPtr<dom::Element> listElement;
375 listItem->GetControl(getter_AddRefs(listElement));
376 if (!listElement) return nullptr;
378 return mDoc->GetAccessible(listElement);
381 ////////////////////////////////////////////////////////////////////////////////
382 // XULListitemAccessible LocalAccessible
384 void XULListitemAccessible::Description(nsString& aDesc) const {
385 AccessibleWrap::Description(aDesc);
388 ////////////////////////////////////////////////////////////////////////////////
389 // XULListitemAccessible: LocalAccessible
392 * Get the name from GetXULName.
394 ENameValueFlag XULListitemAccessible::NativeName(nsString& aName) const {
395 return LocalAccessible::NativeName(aName);
398 role XULListitemAccessible::NativeRole() const {
399 LocalAccessible* list = GetListAccessible();
400 if (!list) {
401 NS_ERROR("No list accessible for listitem accessible!");
402 return roles::NOTHING;
405 if (list->Role() == roles::TABLE) return roles::ROW;
407 if (mIsCheckbox) return roles::CHECK_RICH_OPTION;
409 if (mParent && mParent->Role() == roles::COMBOBOX_LIST) {
410 return roles::COMBOBOX_OPTION;
413 return roles::RICH_OPTION;
416 uint64_t XULListitemAccessible::NativeState() const {
417 if (mIsCheckbox) return XULMenuitemAccessible::NativeState();
419 uint64_t states = NativeInteractiveState();
421 nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
422 Elm()->AsXULSelectControlItem();
423 if (listItem) {
424 bool isSelected;
425 listItem->GetSelected(&isSelected);
426 if (isSelected) states |= states::SELECTED;
428 if (FocusMgr()->IsFocused(this)) states |= states::FOCUSED;
431 return states;
434 uint64_t XULListitemAccessible::NativeInteractiveState() const {
435 return NativelyUnavailable() || (mParent && mParent->NativelyUnavailable())
436 ? states::UNAVAILABLE
437 : states::FOCUSABLE | states::SELECTABLE;
440 void XULListitemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
441 if (aIndex == eAction_Click && mIsCheckbox) {
442 uint64_t states = NativeState();
443 if (states & states::CHECKED) {
444 aName.AssignLiteral("uncheck");
445 } else {
446 aName.AssignLiteral("check");
451 ////////////////////////////////////////////////////////////////////////////////
452 // XULListitemAccessible: Widgets
454 LocalAccessible* XULListitemAccessible::ContainerWidget() const {
455 return LocalParent();