XULListboxAccessible.cpp (14879B)
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 "XULListboxAccessible.h" 7 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" 14 15 #include "nsComponentManagerUtils.h" 16 #include "nsIAutoCompletePopup.h" 17 #include "nsIDOMXULMenuListElement.h" 18 #include "nsIDOMXULMultSelectCntrlEl.h" 19 #include "nsIDOMXULSelectCntrlItemEl.h" 20 #include "nsINodeList.h" 21 22 using namespace mozilla::a11y; 23 24 //////////////////////////////////////////////////////////////////////////////// 25 // XULColumAccessible 26 //////////////////////////////////////////////////////////////////////////////// 27 28 XULColumAccessible::XULColumAccessible(nsIContent* aContent, 29 DocAccessible* aDoc) 30 : AccessibleWrap(aContent, aDoc) {} 31 32 role XULColumAccessible::NativeRole() const { return roles::LIST; } 33 34 uint64_t XULColumAccessible::NativeState() const { return states::READONLY; } 35 36 //////////////////////////////////////////////////////////////////////////////// 37 // XULColumnItemAccessible 38 //////////////////////////////////////////////////////////////////////////////// 39 40 XULColumnItemAccessible::XULColumnItemAccessible(nsIContent* aContent, 41 DocAccessible* aDoc) 42 : LeafAccessible(aContent, aDoc) {} 43 44 role XULColumnItemAccessible::NativeRole() const { return roles::COLUMNHEADER; } 45 46 uint64_t XULColumnItemAccessible::NativeState() const { 47 return states::READONLY; 48 } 49 50 bool XULColumnItemAccessible::HasPrimaryAction() const { return true; } 51 52 void XULColumnItemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) { 53 if (aIndex == eAction_Click) aName.AssignLiteral("click"); 54 } 55 56 //////////////////////////////////////////////////////////////////////////////// 57 // XULListboxAccessible 58 //////////////////////////////////////////////////////////////////////////////// 59 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; 68 } 69 70 if (IsMulticolumn()) mGenericTypes |= eTable; 71 } 72 73 //////////////////////////////////////////////////////////////////////////////// 74 // XULListboxAccessible: LocalAccessible 75 76 uint64_t XULListboxAccessible::NativeState() const { 77 // As a XULListboxAccessible we can have the following states: 78 // FOCUSED, READONLY, FOCUSABLE 79 80 // Get focus status from base class 81 uint64_t states = LocalAccessible::NativeState(); 82 83 // see if we are multiple select if so set ourselves as such 84 85 if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::seltype, 86 nsGkAtoms::multiple, eCaseMatters)) { 87 states |= states::MULTISELECTABLE | states::EXTSELECTABLE; 88 } 89 90 return states; 91 } 92 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; 99 } 100 101 return IsMulticolumn() ? roles::TABLE : roles::LISTBOX; 102 } 103 104 //////////////////////////////////////////////////////////////////////////////// 105 // XULListboxAccessible: Table 106 107 uint32_t XULListboxAccessible::ColCount() const { return 0; } 108 109 uint32_t XULListboxAccessible::RowCount() { 110 nsCOMPtr<nsIDOMXULSelectControlElement> element = Elm()->AsXULSelectControl(); 111 112 uint32_t itemCount = 0; 113 if (element) element->GetItemCount(&itemCount); 114 115 return itemCount; 116 } 117 118 LocalAccessible* XULListboxAccessible::CellAt(uint32_t aRowIndex, 119 uint32_t aColumnIndex) { 120 nsCOMPtr<nsIDOMXULSelectControlElement> control = Elm()->AsXULSelectControl(); 121 NS_ENSURE_TRUE(control, nullptr); 122 123 RefPtr<dom::Element> element; 124 control->GetItemAtIndex(aRowIndex, getter_AddRefs(element)); 125 if (!element) return nullptr; 126 127 LocalAccessible* row = mDoc->GetAccessible(element); 128 NS_ENSURE_TRUE(row, nullptr); 129 130 return row->LocalChildAt(aColumnIndex); 131 } 132 133 bool XULListboxAccessible::IsColSelected(uint32_t aColIdx) { 134 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = 135 Elm()->AsXULMultiSelectControl(); 136 NS_ASSERTION(control, 137 "Doesn't implement nsIDOMXULMultiSelectControlElement."); 138 139 int32_t selectedrowCount = 0; 140 nsresult rv = control->GetSelectedCount(&selectedrowCount); 141 NS_ENSURE_SUCCESS(rv, false); 142 143 return selectedrowCount == static_cast<int32_t>(RowCount()); 144 } 145 146 bool XULListboxAccessible::IsRowSelected(uint32_t aRowIdx) { 147 nsCOMPtr<nsIDOMXULSelectControlElement> control = Elm()->AsXULSelectControl(); 148 NS_ASSERTION(control, "Doesn't implement nsIDOMXULSelectControlElement."); 149 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; 155 } 156 157 nsCOMPtr<nsIDOMXULSelectControlItemElement> item = 158 element->AsXULSelectControlItem(); 159 160 bool isSelected = false; 161 item->GetSelected(&isSelected); 162 return isSelected; 163 } 164 165 bool XULListboxAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) { 166 return IsRowSelected(aRowIdx); 167 } 168 169 uint32_t XULListboxAccessible::SelectedCellCount() { 170 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = 171 Elm()->AsXULMultiSelectControl(); 172 NS_ASSERTION(control, 173 "Doesn't implement nsIDOMXULMultiSelectControlElement."); 174 175 nsCOMPtr<nsINodeList> selectedItems; 176 control->GetSelectedItems(getter_AddRefs(selectedItems)); 177 if (!selectedItems) return 0; 178 179 uint32_t selectedItemsCount = selectedItems->Length(); 180 181 return selectedItemsCount * ColCount(); 182 } 183 184 uint32_t XULListboxAccessible::SelectedColCount() { 185 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = 186 Elm()->AsXULMultiSelectControl(); 187 NS_ASSERTION(control, 188 "Doesn't implement nsIDOMXULMultiSelectControlElement."); 189 190 int32_t selectedRowCount = 0; 191 nsresult rv = control->GetSelectedCount(&selectedRowCount); 192 NS_ENSURE_SUCCESS(rv, 0); 193 194 return selectedRowCount > 0 && 195 selectedRowCount == static_cast<int32_t>(RowCount()) 196 ? ColCount() 197 : 0; 198 } 199 200 uint32_t XULListboxAccessible::SelectedRowCount() { 201 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = 202 Elm()->AsXULMultiSelectControl(); 203 NS_ASSERTION(control, 204 "Doesn't implement nsIDOMXULMultiSelectControlElement."); 205 206 int32_t selectedRowCount = 0; 207 nsresult rv = control->GetSelectedCount(&selectedRowCount); 208 NS_ENSURE_SUCCESS(rv, 0); 209 210 return selectedRowCount >= 0 ? selectedRowCount : 0; 211 } 212 213 void XULListboxAccessible::SelectedCells(nsTArray<Accessible*>* aCells) { 214 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = 215 Elm()->AsXULMultiSelectControl(); 216 NS_ASSERTION(control, 217 "Doesn't implement nsIDOMXULMultiSelectControlElement."); 218 219 nsCOMPtr<nsINodeList> selectedItems; 220 control->GetSelectedItems(getter_AddRefs(selectedItems)); 221 if (!selectedItems) return; 222 223 uint32_t selectedItemsCount = selectedItems->Length(); 224 225 for (uint32_t index = 0; index < selectedItemsCount; index++) { 226 nsIContent* itemContent = selectedItems->Item(index); 227 LocalAccessible* item = mDoc->GetAccessible(itemContent); 228 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); 234 } 235 } 236 } 237 } 238 239 void XULListboxAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells) { 240 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = 241 Elm()->AsXULMultiSelectControl(); 242 NS_ASSERTION(control, 243 "Doesn't implement nsIDOMXULMultiSelectControlElement."); 244 245 nsCOMPtr<nsINodeList> selectedItems; 246 control->GetSelectedItems(getter_AddRefs(selectedItems)); 247 if (!selectedItems) return; 248 249 uint32_t selectedItemsCount = selectedItems->Length(); 250 251 uint32_t colCount = ColCount(); 252 aCells->SetCapacity(selectedItemsCount * colCount); 253 aCells->AppendElements(selectedItemsCount * colCount); 254 255 for (uint32_t selItemsIdx = 0, cellsIdx = 0; selItemsIdx < selectedItemsCount; 256 selItemsIdx++) { 257 nsIContent* itemContent = selectedItems->Item(selItemsIdx); 258 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; 267 } 268 } 269 } 270 } 271 } 272 273 void XULListboxAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols) { 274 uint32_t selColCount = SelectedColCount(); 275 aCols->SetCapacity(selColCount); 276 277 for (uint32_t colIdx = 0; colIdx < selColCount; colIdx++) { 278 aCols->AppendElement(colIdx); 279 } 280 } 281 282 void XULListboxAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows) { 283 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = 284 Elm()->AsXULMultiSelectControl(); 285 NS_ASSERTION(control, 286 "Doesn't implement nsIDOMXULMultiSelectControlElement."); 287 288 nsCOMPtr<nsINodeList> selectedItems; 289 control->GetSelectedItems(getter_AddRefs(selectedItems)); 290 if (!selectedItems) return; 291 292 uint32_t rowCount = selectedItems->Length(); 293 294 if (!rowCount) return; 295 296 aRows->SetCapacity(rowCount); 297 aRows->AppendElements(rowCount); 298 299 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) { 300 nsIContent* itemContent = selectedItems->Item(rowIdx); 301 nsCOMPtr<nsIDOMXULSelectControlItemElement> item = 302 itemContent->AsElement()->AsXULSelectControlItem(); 303 304 if (item) { 305 int32_t itemIdx = -1; 306 control->GetIndexOfItem(item, &itemIdx); 307 if (itemIdx >= 0) aRows->ElementAt(rowIdx) = itemIdx; 308 } 309 } 310 } 311 312 //////////////////////////////////////////////////////////////////////////////// 313 // XULListboxAccessible: Widgets 314 315 bool XULListboxAccessible::IsWidget() const { return true; } 316 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; 327 } 328 } 329 } 330 return FocusMgr()->HasDOMFocus(mContent); 331 } 332 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; 343 } 344 } 345 } 346 return true; 347 } 348 349 LocalAccessible* XULListboxAccessible::ContainerWidget() const { 350 return nullptr; 351 } 352 353 //////////////////////////////////////////////////////////////////////////////// 354 // XULListitemAccessible 355 //////////////////////////////////////////////////////////////////////////////// 356 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; 363 } 364 365 XULListitemAccessible::~XULListitemAccessible() {} 366 367 LocalAccessible* XULListitemAccessible::GetListAccessible() const { 368 if (IsDefunct()) return nullptr; 369 370 nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem = 371 Elm()->AsXULSelectControlItem(); 372 if (!listItem) return nullptr; 373 374 RefPtr<dom::Element> listElement; 375 listItem->GetControl(getter_AddRefs(listElement)); 376 if (!listElement) return nullptr; 377 378 return mDoc->GetAccessible(listElement); 379 } 380 381 //////////////////////////////////////////////////////////////////////////////// 382 // XULListitemAccessible LocalAccessible 383 384 EDescriptionValueFlag XULListitemAccessible::Description( 385 nsString& aDesc) const { 386 return AccessibleWrap::Description(aDesc); 387 } 388 389 //////////////////////////////////////////////////////////////////////////////// 390 // XULListitemAccessible: LocalAccessible 391 392 /** 393 * Get the name from GetXULName. 394 */ 395 ENameValueFlag XULListitemAccessible::NativeName(nsString& aName) const { 396 return LocalAccessible::NativeName(aName); 397 } 398 399 role XULListitemAccessible::NativeRole() const { 400 LocalAccessible* list = GetListAccessible(); 401 if (!list) { 402 NS_ERROR("No list accessible for listitem accessible!"); 403 return roles::NOTHING; 404 } 405 406 if (list->Role() == roles::TABLE) return roles::ROW; 407 408 if (mIsCheckbox) return roles::CHECK_RICH_OPTION; 409 410 if (mParent && mParent->Role() == roles::COMBOBOX_LIST) { 411 return roles::COMBOBOX_OPTION; 412 } 413 414 return roles::RICH_OPTION; 415 } 416 417 uint64_t XULListitemAccessible::NativeState() const { 418 if (mIsCheckbox) return XULMenuitemAccessible::NativeState(); 419 420 uint64_t states = NativeInteractiveState(); 421 422 nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem = 423 Elm()->AsXULSelectControlItem(); 424 if (listItem) { 425 bool isSelected; 426 listItem->GetSelected(&isSelected); 427 if (isSelected) states |= states::SELECTED; 428 429 if (FocusMgr()->IsFocused(this)) states |= states::FOCUSED; 430 } 431 432 return states; 433 } 434 435 uint64_t XULListitemAccessible::NativeInteractiveState() const { 436 return NativelyUnavailable() || (mParent && mParent->NativelyUnavailable()) 437 ? states::UNAVAILABLE 438 : states::FOCUSABLE | states::SELECTABLE; 439 } 440 441 void XULListitemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) { 442 if (aIndex == eAction_Click && mIsCheckbox) { 443 uint64_t states = NativeState(); 444 if (states & states::CHECKED) { 445 aName.AssignLiteral("uncheck"); 446 } else { 447 aName.AssignLiteral("check"); 448 } 449 } 450 } 451 452 //////////////////////////////////////////////////////////////////////////////// 453 // XULListitemAccessible: Widgets 454 455 LocalAccessible* XULListitemAccessible::ContainerWidget() const { 456 return LocalParent(); 457 }