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"
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 ////////////////////////////////////////////////////////////////////////////////
26 ////////////////////////////////////////////////////////////////////////////////
28 XULColumAccessible::XULColumAccessible(nsIContent
* aContent
,
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
,
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
,
62 : XULSelectControlAccessible(aContent
, aDoc
) {
63 dom::Element
* parentEl
= mContent
->GetParentElement();
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
;
93 role
XULListboxAccessible::NativeRole() const {
94 // A richlistbox is used with the new autocomplete URL bar, and has a parent
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
);
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);
157 nsCOMPtr
<nsIDOMXULSelectControlItemElement
> item
=
158 element
->AsXULSelectControlItem();
160 bool isSelected
= false;
161 item
->GetSelected(&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())
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
);
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
;
257 nsIContent
* itemContent
= selectedItems
->Item(selItemsIdx
);
259 nsCOMPtr
<nsIDOMXULSelectControlItemElement
> item
=
260 itemContent
->AsElement()->AsXULSelectControlItem();
262 int32_t itemIdx
= -1;
263 control
->GetIndexOfItem(item
, &itemIdx
);
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();
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();
321 nsCOMPtr
<nsIAutoCompletePopup
> autoCompletePopupElm
=
322 parentContent
->AsElement()->AsAutoCompletePopup();
323 if (autoCompletePopupElm
) {
325 autoCompletePopupElm
->GetPopupOpen(&isOpen
);
330 return FocusMgr()->HasDOMFocus(mContent
);
333 bool XULListboxAccessible::AreItemsOperable() const {
334 if (IsAutoCompletePopup()) {
335 nsIContent
* parentContent
= mContent
->GetParent();
337 nsCOMPtr
<nsIAutoCompletePopup
> autoCompletePopupElm
=
338 parentContent
->AsElement()->AsAutoCompletePopup();
339 if (autoCompletePopupElm
) {
341 autoCompletePopupElm
->GetPopupOpen(&isOpen
);
349 LocalAccessible
* XULListboxAccessible::ContainerWidget() const {
353 ////////////////////////////////////////////////////////////////////////////////
354 // XULListitemAccessible
355 ////////////////////////////////////////////////////////////////////////////////
357 XULListitemAccessible::XULListitemAccessible(nsIContent
* aContent
,
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();
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();
425 listItem
->GetSelected(&isSelected
);
426 if (isSelected
) states
|= states::SELECTED
;
428 if (FocusMgr()->IsFocused(this)) states
|= states::FOCUSED
;
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");
446 aName
.AssignLiteral("check");
451 ////////////////////////////////////////////////////////////////////////////////
452 // XULListitemAccessible: Widgets
454 LocalAccessible
* XULListitemAccessible::ContainerWidget() const {
455 return LocalParent();