summaryrefslogtreecommitdiffstats
path: root/accessible/xul/XULComboboxAccessible.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/xul/XULComboboxAccessible.cpp')
-rw-r--r--accessible/xul/XULComboboxAccessible.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/accessible/xul/XULComboboxAccessible.cpp b/accessible/xul/XULComboboxAccessible.cpp
new file mode 100644
index 000000000..1bca6d58e
--- /dev/null
+++ b/accessible/xul/XULComboboxAccessible.cpp
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "XULComboboxAccessible.h"
+
+#include "Accessible-inl.h"
+#include "nsAccessibilityService.h"
+#include "DocAccessible.h"
+#include "nsCoreUtils.h"
+#include "Role.h"
+#include "States.h"
+
+#include "nsIAutoCompleteInput.h"
+#include "nsIDOMXULMenuListElement.h"
+#include "nsIDOMXULSelectCntrlItemEl.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// XULComboboxAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+XULComboboxAccessible::
+ XULComboboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
+ AccessibleWrap(aContent, aDoc)
+{
+ if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
+ nsGkAtoms::autocomplete, eIgnoreCase))
+ mGenericTypes |= eAutoComplete;
+ else
+ mGenericTypes |= eCombobox;
+
+ // Both the XUL <textbox type="autocomplete"> and <menulist editable="true">
+ // widgets use XULComboboxAccessible. We need to walk the anonymous children
+ // for these so that the entry field is a child. Otherwise no XBL children.
+ if (!mContent->NodeInfo()->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL) &&
+ !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
+ nsGkAtoms::_true, eIgnoreCase)) {
+ mStateFlags |= eNoXBLKids;
+ }
+}
+
+role
+XULComboboxAccessible::NativeRole()
+{
+ return IsAutoComplete() ? roles::AUTOCOMPLETE : roles::COMBOBOX;
+}
+
+uint64_t
+XULComboboxAccessible::NativeState()
+{
+ // As a nsComboboxAccessible we can have the following states:
+ // STATE_FOCUSED
+ // STATE_FOCUSABLE
+ // STATE_HASPOPUP
+ // STATE_EXPANDED
+ // STATE_COLLAPSED
+
+ // Get focus status from base class
+ uint64_t state = Accessible::NativeState();
+
+ nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
+ if (menuList) {
+ bool isOpen = false;
+ menuList->GetOpen(&isOpen);
+ if (isOpen)
+ state |= states::EXPANDED;
+ else
+ state |= states::COLLAPSED;
+ }
+
+ return state | states::HASPOPUP;
+}
+
+void
+XULComboboxAccessible::Description(nsString& aDescription)
+{
+ aDescription.Truncate();
+ // Use description of currently focused option
+ nsCOMPtr<nsIDOMXULMenuListElement> menuListElm(do_QueryInterface(mContent));
+ if (!menuListElm)
+ return;
+
+ nsCOMPtr<nsIDOMXULSelectControlItemElement> focusedOptionItem;
+ menuListElm->GetSelectedItem(getter_AddRefs(focusedOptionItem));
+ nsCOMPtr<nsIContent> focusedOptionContent =
+ do_QueryInterface(focusedOptionItem);
+ if (focusedOptionContent && mDoc) {
+ Accessible* focusedOptionAcc = mDoc->GetAccessible(focusedOptionContent);
+ if (focusedOptionAcc)
+ focusedOptionAcc->Description(aDescription);
+ }
+}
+
+void
+XULComboboxAccessible::Value(nsString& aValue)
+{
+ aValue.Truncate();
+
+ // The value is the option or text shown entered in the combobox.
+ nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
+ if (menuList)
+ menuList->GetLabel(aValue);
+}
+
+uint8_t
+XULComboboxAccessible::ActionCount()
+{
+ // Just one action (click).
+ return 1;
+}
+
+bool
+XULComboboxAccessible::DoAction(uint8_t aIndex)
+{
+ if (aIndex != XULComboboxAccessible::eAction_Click)
+ return false;
+
+ // Programmaticaly toggle the combo box.
+ nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
+ if (!menuList)
+ return false;
+
+ bool isDroppedDown = false;
+ menuList->GetOpen(&isDroppedDown);
+ menuList->SetOpen(!isDroppedDown);
+ return true;
+}
+
+void
+XULComboboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
+{
+ aName.Truncate();
+ if (aIndex != XULComboboxAccessible::eAction_Click)
+ return;
+
+ nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
+ if (!menuList)
+ return;
+
+ bool isDroppedDown = false;
+ menuList->GetOpen(&isDroppedDown);
+ if (isDroppedDown)
+ aName.AssignLiteral("close");
+ else
+ aName.AssignLiteral("open");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widgets
+
+bool
+XULComboboxAccessible::IsActiveWidget() const
+{
+ if (IsAutoComplete() ||
+ mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
+ nsGkAtoms::_true, eIgnoreCase)) {
+ int32_t childCount = mChildren.Length();
+ for (int32_t idx = 0; idx < childCount; idx++) {
+ Accessible* child = mChildren[idx];
+ if (child->Role() == roles::ENTRY)
+ return FocusMgr()->HasDOMFocus(child->GetContent());
+ }
+ return false;
+ }
+
+ return FocusMgr()->HasDOMFocus(mContent);
+}
+
+bool
+XULComboboxAccessible::AreItemsOperable() const
+{
+ if (IsAutoComplete()) {
+ nsCOMPtr<nsIAutoCompleteInput> autoCompleteInputElm =
+ do_QueryInterface(mContent);
+ if (autoCompleteInputElm) {
+ bool isOpen = false;
+ autoCompleteInputElm->GetPopupOpen(&isOpen);
+ return isOpen;
+ }
+ return false;
+ }
+
+ nsCOMPtr<nsIDOMXULMenuListElement> menuListElm = do_QueryInterface(mContent);
+ if (menuListElm) {
+ bool isOpen = false;
+ menuListElm->GetOpen(&isOpen);
+ return isOpen;
+ }
+
+ return false;
+}