From b59f3bb4bec6c164c90a3bb2da6aa384de74500c Mon Sep 17 00:00:00 2001 From: "aaronleventhal%moonset.net" Date: Fri, 9 Feb 2007 02:03:08 +0000 Subject: [PATCH] Bug 363955. Combobox doesn't have good mechanism to provide the selected item. Editable menulist without dropdown button should be expose as textbox. r=surkov, r=nian.liu, r=mano --- accessible/src/base/nsAccessibilityAtomList.h | 2 + .../src/html/nsHTMLSelectAccessible.cpp | 2 +- accessible/src/html/nsHTMLSelectAccessible.h | 2 +- .../src/xul/nsXULFormControlAccessible.cpp | 66 ++-- .../src/xul/nsXULFormControlAccessible.h | 2 + accessible/src/xul/nsXULMenuAccessible.cpp | 301 +++++++++++++++--- accessible/src/xul/nsXULMenuAccessible.h | 32 +- accessible/src/xul/nsXULSelectAccessible.cpp | 250 +-------------- accessible/src/xul/nsXULSelectAccessible.h | 33 +- toolkit/content/widgets/menulist.xml | 5 +- 10 files changed, 361 insertions(+), 334 deletions(-) diff --git a/accessible/src/base/nsAccessibilityAtomList.h b/accessible/src/base/nsAccessibilityAtomList.h index af7cf549177d..5d13c8dec9e9 100755 --- a/accessible/src/base/nsAccessibilityAtomList.h +++ b/accessible/src/base/nsAccessibilityAtomList.h @@ -146,6 +146,7 @@ ACCESSIBILITY_ATOM(alt, "alt") ACCESSIBILITY_ATOM(control, "control") ACCESSIBILITY_ATOM(data, "data") ACCESSIBILITY_ATOM(disabled, "disabled") +ACCESSIBILITY_ATOM(editable, "editable") ACCESSIBILITY_ATOM(_for, "for") ACCESSIBILITY_ATOM(href, "href") ACCESSIBILITY_ATOM(id, "id") @@ -164,6 +165,7 @@ ACCESSIBILITY_ATOM(value, "value") // DHTML accessibility attributes ACCESSIBILITY_ATOM(checked, "checked") +ACCESSIBILITY_ATOM(droppable, "droppable") ACCESSIBILITY_ATOM(expanded, "expanded") ACCESSIBILITY_ATOM(invalid, "invalid") ACCESSIBILITY_ATOM(level, "level") diff --git a/accessible/src/html/nsHTMLSelectAccessible.cpp b/accessible/src/html/nsHTMLSelectAccessible.cpp index f235eeb59e7c..e72642f4fa7f 100644 --- a/accessible/src/html/nsHTMLSelectAccessible.cpp +++ b/accessible/src/html/nsHTMLSelectAccessible.cpp @@ -801,7 +801,7 @@ NS_IMETHODIMP nsHTMLSelectOptGroupAccessible::GetNumActions(PRUint8 *_retval) /** ----- nsHTMLComboboxAccessible ----- */ nsHTMLComboboxAccessible::nsHTMLComboboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell): -nsHTMLSelectableAccessible(aDOMNode, aShell) +nsAccessibleWrap(aDOMNode, aShell) { } diff --git a/accessible/src/html/nsHTMLSelectAccessible.h b/accessible/src/html/nsHTMLSelectAccessible.h index 9792acdd7663..78a61de126a7 100644 --- a/accessible/src/html/nsHTMLSelectAccessible.h +++ b/accessible/src/html/nsHTMLSelectAccessible.h @@ -193,7 +193,7 @@ public: /* * A class the represents the HTML Combobox widget. */ -class nsHTMLComboboxAccessible : public nsHTMLSelectableAccessible +class nsHTMLComboboxAccessible : public nsAccessibleWrap { public: enum { eAction_Click = 0 }; diff --git a/accessible/src/xul/nsXULFormControlAccessible.cpp b/accessible/src/xul/nsXULFormControlAccessible.cpp index 252018c22d10..cacfd82fd1b4 100644 --- a/accessible/src/xul/nsXULFormControlAccessible.cpp +++ b/accessible/src/xul/nsXULFormControlAccessible.cpp @@ -42,6 +42,7 @@ #include "nsHTMLFormControlAccessible.h" #include "nsAccessibilityAtoms.h" #include "nsAccessibleTreeWalker.h" +#include "nsXULMenuAccessible.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMNSEditableElement.h" #include "nsIDOMXULButtonElement.h" @@ -662,6 +663,10 @@ NS_IMETHODIMP nsXULTextFieldAccessible::GetValue(nsAString& aValue) if (textBox) { return textBox->GetValue(aValue); } + nsCOMPtr menuList(do_QueryInterface(mDOMNode)); + if (menuList) { + return menuList->GetLabel(aValue); + } return NS_ERROR_FAILURE; } @@ -687,16 +692,30 @@ NS_IMETHODIMP nsXULTextFieldAccessible::GetExtState(PRUint32 *aExtState) return NS_OK; } +already_AddRefed nsXULTextFieldAccessible::GetInputField() +{ + nsIDOMNode *inputField = nsnull; + nsCOMPtr textBox = do_QueryInterface(mDOMNode); + if (textBox) { + textBox->GetInputField(&inputField); + return inputField; + } + nsCOMPtr menuList = do_QueryInterface(mDOMNode); + if (menuList) { // + menuList->GetInputField(&inputField); + } + NS_ASSERTION(inputField, "No input field for nsXULTextFieldAccessible"); + return inputField; +} + NS_IMETHODIMP nsXULTextFieldAccessible::GetState(PRUint32 *aState) { - nsCOMPtr textBox(do_QueryInterface(mDOMNode)); - if (!textBox) { + if (!mDOMNode) { return NS_ERROR_FAILURE; } nsHyperTextAccessible::GetState(aState); - nsCOMPtr inputField; - textBox->GetInputField(getter_AddRefs(inputField)); + nsCOMPtr inputField = GetInputField(); if (!inputField) { return NS_ERROR_FAILURE; } @@ -710,15 +729,26 @@ NS_IMETHODIMP nsXULTextFieldAccessible::GetState(PRUint32 *aState) } nsCOMPtr content(do_QueryInterface(mDOMNode)); - NS_ASSERTION(content, "Not possible since we are a nsIDOMXULTextBoxElement"); - if (content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type, - nsAccessibilityAtoms::password, eIgnoreCase)) { - *aState |= STATE_PROTECTED; - } + NS_ASSERTION(content, "Not possible since we have an mDOMNode"); - if (content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::readonly, - nsAccessibilityAtoms::_true, eIgnoreCase)) { - *aState |= STATE_READONLY; + nsCOMPtr menuList(do_QueryInterface(mDOMNode)); + if (menuList) { + // + if (!content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::editable, + nsAccessibilityAtoms::_true, eIgnoreCase)) { + *aState |= STATE_READONLY; + } + } + else { + // + if (content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type, + nsAccessibilityAtoms::password, eIgnoreCase)) { + *aState |= STATE_PROTECTED; + } + if (content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::readonly, + nsAccessibilityAtoms::_true, eIgnoreCase)) { + *aState |= STATE_READONLY; + } } return rv; @@ -791,17 +821,7 @@ void nsXULTextFieldAccessible::SetEditor(nsIEditor* aEditor) void nsXULTextFieldAccessible::CheckForEditor() { - nsCOMPtr textBox(do_QueryInterface(mDOMNode)); - if (!textBox) { - return; - } - - nsCOMPtr inputField; - textBox->GetInputField(getter_AddRefs(inputField)); - if (!inputField) { - return; - } - + nsCOMPtr inputField = GetInputField(); nsCOMPtr editableElt(do_QueryInterface(inputField)); if (!editableElt) { return; diff --git a/accessible/src/xul/nsXULFormControlAccessible.h b/accessible/src/xul/nsXULFormControlAccessible.h index 6551e6450169..bcd0a83d47aa 100644 --- a/accessible/src/xul/nsXULFormControlAccessible.h +++ b/accessible/src/xul/nsXULFormControlAccessible.h @@ -169,6 +169,8 @@ public: NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren); protected: + already_AddRefed GetInputField(); + // Editor helpers, subclasses of nsHyperTextAccessible may have editor virtual void SetEditor(nsIEditor *aEditor); virtual already_AddRefed GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; } diff --git a/accessible/src/xul/nsXULMenuAccessible.cpp b/accessible/src/xul/nsXULMenuAccessible.cpp index a68b82ac6e3c..74b207e719c9 100644 --- a/accessible/src/xul/nsXULMenuAccessible.cpp +++ b/accessible/src/xul/nsXULMenuAccessible.cpp @@ -39,7 +39,9 @@ #include "nsXULMenuAccessible.h" #include "nsIDOMElement.h" #include "nsIDOMXULElement.h" +#include "nsIMutableArray.h" #include "nsIDOMXULSelectCntrlItemEl.h" +#include "nsIDOMXULMultSelectCntrlEl.h" #include "nsIDOMKeyEvent.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" @@ -49,6 +51,211 @@ #include "nsGUIEvent.h" #include "nsXULFormControlAccessible.h" + +/** ------------------------------------------------------ */ +/** Impl. of nsXULSelectableAccessible */ +/** ------------------------------------------------------ */ + +// Helper methos +nsXULSelectableAccessible::nsXULSelectableAccessible(nsIDOMNode* aDOMNode, + nsIWeakReference* aShell): +nsAccessibleWrap(aDOMNode, aShell) +{ + mSelectControl = do_QueryInterface(aDOMNode); +} + +NS_IMPL_ISUPPORTS_INHERITED1(nsXULSelectableAccessible, nsAccessible, nsIAccessibleSelectable) + +NS_IMETHODIMP nsXULSelectableAccessible::Shutdown() +{ + mSelectControl = nsnull; + return nsAccessibleWrap::Shutdown(); +} + +nsresult nsXULSelectableAccessible::ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState) +{ + *aSelState = PR_FALSE; + + if (!mSelectControl) { + return NS_ERROR_FAILURE; + } + nsCOMPtr childAcc; + GetChildAt(aIndex, getter_AddRefs(childAcc)); + nsCOMPtr accNode = do_QueryInterface(childAcc); + NS_ENSURE_TRUE(accNode, NS_ERROR_FAILURE); + + nsCOMPtr childNode; + accNode->GetDOMNode(getter_AddRefs(childNode)); + nsCOMPtr item(do_QueryInterface(childNode)); + NS_ENSURE_TRUE(item, NS_ERROR_FAILURE); + + item->GetSelected(aSelState); + if (eSelection_GetState == aMethod) { + return NS_OK; + } + + nsCOMPtr xulMultiSelect = + do_QueryInterface(mSelectControl); + + if (eSelection_Add == aMethod && !(*aSelState)) { + return xulMultiSelect ? xulMultiSelect->AddItemToSelection(item) : + mSelectControl->SetSelectedItem(item); + } + if (eSelection_Remove == aMethod && (*aSelState)) { + return xulMultiSelect ? xulMultiSelect->RemoveItemFromSelection(item) : + mSelectControl->SetSelectedItem(nsnull); + } + return NS_ERROR_FAILURE; +} + +// Interface methods +NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildren) +{ + *aChildren = nsnull; + if (!mSelectControl) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr accService = GetAccService(); + NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE); + + nsCOMPtr selectedAccessibles = + do_CreateInstance(NS_ARRAY_CONTRACTID); + NS_ENSURE_STATE(selectedAccessibles); + + // For XUL multi-select control + nsCOMPtr xulMultiSelect = + do_QueryInterface(mSelectControl); + nsCOMPtr selectedAccessible; + if (xulMultiSelect) { + PRInt32 length = 0; + xulMultiSelect->GetSelectedCount(&length); + for (PRInt32 index = 0; index < length; index++) { + nsCOMPtr selectedItem; + xulMultiSelect->GetSelectedItem(index, getter_AddRefs(selectedItem)); + nsCOMPtr selectedNode(do_QueryInterface(selectedItem)); + accService->GetAccessibleInWeakShell(selectedNode, mWeakShell, + getter_AddRefs(selectedAccessible)); + if (selectedAccessible) + selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE); + } + } + else { // Single select? + nsCOMPtr selectedItem; + mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem)); + nsCOMPtr selectedNode(do_QueryInterface(selectedItem)); + if(selectedNode) { + accService->GetAccessibleInWeakShell(selectedNode, mWeakShell, + getter_AddRefs(selectedAccessible)); + if (selectedAccessible) + selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE); + } + } + + PRUint32 uLength = 0; + selectedAccessibles->GetLength(&uLength); + if (uLength != 0) { // length of nsIArray containing selected options + NS_ADDREF(*aChildren = selectedAccessibles); + } + + return NS_OK; +} + +// return the nth selected child's nsIAccessible object +NS_IMETHODIMP nsXULSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccessible **aAccessible) +{ + *aAccessible = nsnull; + if (!mSelectControl) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr selectedItem; + nsCOMPtr xulMultiSelect = + do_QueryInterface(mSelectControl); + if (xulMultiSelect) + xulMultiSelect->GetSelectedItem(aIndex, getter_AddRefs(selectedItem)); + + if (aIndex == 0) + mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem)); + + if (selectedItem) { + nsCOMPtr accService = GetAccService(); + if (accService) { + accService->GetAccessibleInWeakShell(selectedItem, mWeakShell, aAccessible); + if (*aAccessible) { + NS_ADDREF(*aAccessible); + return NS_OK; + } + } + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsXULSelectableAccessible::GetSelectionCount(PRInt32 *aSelectionCount) +{ + *aSelectionCount = 0; + if (!mSelectControl) { + return NS_ERROR_FAILURE; + } + + // For XUL multi-select control + nsCOMPtr xulMultiSelect = + do_QueryInterface(mSelectControl); + if (xulMultiSelect) + return xulMultiSelect->GetSelectedCount(aSelectionCount); + + // For XUL single-select control/menulist + PRInt32 index; + mSelectControl->GetSelectedIndex(&index); + if (index >= 0) + *aSelectionCount = 1; + return NS_OK; +} + +NS_IMETHODIMP nsXULSelectableAccessible::AddChildToSelection(PRInt32 aIndex) +{ + PRBool isSelected; + return ChangeSelection(aIndex, eSelection_Add, &isSelected); +} + +NS_IMETHODIMP nsXULSelectableAccessible::RemoveChildFromSelection(PRInt32 aIndex) +{ + PRBool isSelected; + return ChangeSelection(aIndex, eSelection_Remove, &isSelected); +} + +NS_IMETHODIMP nsXULSelectableAccessible::IsChildSelected(PRInt32 aIndex, PRBool *aIsSelected) +{ + *aIsSelected = PR_FALSE; + return ChangeSelection(aIndex, eSelection_GetState, aIsSelected); +} + +NS_IMETHODIMP nsXULSelectableAccessible::ClearSelection() +{ + if (!mSelectControl) { + return NS_ERROR_FAILURE; + } + nsCOMPtr xulMultiSelect = + do_QueryInterface(mSelectControl); + return xulMultiSelect ? xulMultiSelect->ClearSelection() : mSelectControl->SetSelectedIndex(-1); +} + +NS_IMETHODIMP nsXULSelectableAccessible::SelectAllSelection(PRBool *aSucceeded) +{ + *aSucceeded = PR_TRUE; + + nsCOMPtr xulMultiSelect = + do_QueryInterface(mSelectControl); + if (xulMultiSelect) + return xulMultiSelect->SelectAll(); + + // otherwise, don't support this method + *aSucceeded = PR_FALSE; + return NS_ERROR_NOT_IMPLEMENTED; +} + + // ------------------------ Menu Item ----------------------------- nsXULMenuitemAccessible::nsXULMenuitemAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell): @@ -56,6 +263,13 @@ nsAccessibleWrap(aDOMNode, aShell) { } +NS_IMETHODIMP nsXULMenuitemAccessible::Init() +{ + nsresult rv = nsAccessibleWrap::Init(); + nsXULMenupopupAccessible::GenerateMenu(mDOMNode); + return rv; +} + NS_IMETHODIMP nsXULMenuitemAccessible::GetState(PRUint32 *_retval) { nsAccessible::GetState(_retval); @@ -216,47 +430,6 @@ NS_IMETHODIMP nsXULMenuitemAccessible::GetRole(PRUint32 *aRole) return NS_OK; } -void nsXULMenuitemAccessible::CacheChildren() -{ - if (!mWeakShell) { - // This node has been shut down - mAccChildCount = eChildCountUninitialized; - return; - } - - if (mAccChildCount != eChildCountUninitialized) { - return; - } - - // Set menugenerated="true" on the menupopup node to generate the - // sub-menu items if they have not been generated - PRUint32 childIndex, numChildren = 0; - nsCOMPtr childNode; - nsCOMPtr nodeList; - mDOMNode->GetChildNodes(getter_AddRefs(nodeList)); - if (nodeList && NS_OK == nodeList->GetLength(&numChildren)) { - for (childIndex = 0; childIndex < numChildren; childIndex++) { - nodeList->Item(childIndex, getter_AddRefs(childNode)); - nsCOMPtr content = do_QueryInterface(childNode); - if (content->NodeInfo()->Equals(nsAccessibilityAtoms::menupopup, kNameSpaceID_XUL)) { - break; - } - } - - if (childIndex < numChildren) { - nsCOMPtr element(do_QueryInterface(childNode)); - if (element) { - nsAutoString attr; - element->GetAttribute(NS_LITERAL_STRING("menugenerated"), attr); - if (!attr.EqualsLiteral("true")) { - element->SetAttribute(NS_LITERAL_STRING("menugenerated"), NS_LITERAL_STRING("true")); - } - } - } - } - nsAccessibleWrap::CacheChildren(); -} - NS_IMETHODIMP nsXULMenuitemAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren) { @@ -337,8 +510,12 @@ NS_IMETHODIMP nsXULMenuSeparatorAccessible::GetNumActions(PRUint8 *_retval) // ------------------------ Menu Popup ----------------------------- nsXULMenupopupAccessible::nsXULMenupopupAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell): - nsAccessibleWrap(aDOMNode, aShell) + nsXULSelectableAccessible(aDOMNode, aShell) { + // May be the anonymous inside (a combobox) + nsCOMPtr parentNode; + aDOMNode->GetParentNode(getter_AddRefs(parentNode)); + mSelectControl = do_QueryInterface(parentNode); } NS_IMETHODIMP nsXULMenupopupAccessible::GetState(PRUint32 *_retval) @@ -366,6 +543,46 @@ NS_IMETHODIMP nsXULMenupopupAccessible::GetState(PRUint32 *_retval) return NS_OK; } +already_AddRefed +nsXULMenupopupAccessible::FindInNodeList(nsIDOMNodeList *aNodeList, + nsIAtom *aAtom, PRUint32 aNameSpaceID) +{ + PRUint32 numChildren; + if (!aNodeList || NS_FAILED(aNodeList->GetLength(&numChildren))) { + return nsnull; + } + nsCOMPtr childNode; + for (PRUint32 childIndex = 0; childIndex < numChildren; childIndex++) { + aNodeList->Item(childIndex, getter_AddRefs(childNode)); + nsCOMPtr content = do_QueryInterface(childNode); + if (content && content->NodeInfo()->Equals(aAtom, kNameSpaceID_XUL)) { + nsIDOMNode *matchNode = childNode; + NS_ADDREF(matchNode); + return matchNode; + } + } + return nsnull; +} + +void nsXULMenupopupAccessible::GenerateMenu(nsIDOMNode *aNode) +{ + // Set menugenerated="true" on the menupopup node to generate the + // sub-menu items if they have not been generated + nsCOMPtr nodeList; + aNode->GetChildNodes(getter_AddRefs(nodeList)); + + nsCOMPtr menuPopup = FindInNodeList(nodeList, nsAccessibilityAtoms::menupopup, + kNameSpaceID_XUL); + nsCOMPtr popupElement(do_QueryInterface(menuPopup)); + if (popupElement) { + nsAutoString attr; + popupElement->GetAttribute(NS_LITERAL_STRING("menugenerated"), attr); + if (!attr.EqualsLiteral("true")) { + popupElement->SetAttribute(NS_LITERAL_STRING("menugenerated"), NS_LITERAL_STRING("true")); + } + } +} + NS_IMETHODIMP nsXULMenupopupAccessible::GetName(nsAString& _retval) { nsCOMPtr element(do_QueryInterface(mDOMNode)); diff --git a/accessible/src/xul/nsXULMenuAccessible.h b/accessible/src/xul/nsXULMenuAccessible.h index 1c1fc73c0f3c..7195251736a8 100644 --- a/accessible/src/xul/nsXULMenuAccessible.h +++ b/accessible/src/xul/nsXULMenuAccessible.h @@ -41,6 +41,31 @@ #include "nsAccessibleWrap.h" #include "nsAccessibleTreeWalker.h" +#include "nsIAccessibleSelectable.h" +#include "nsIDOMXULSelectCntrlEl.h" + +/* + * The basic implemetation of nsIAccessibleSelectable. + */ +class nsXULSelectableAccessible : public nsAccessibleWrap +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIACCESSIBLESELECTABLE + + nsXULSelectableAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell); + virtual ~nsXULSelectableAccessible() {} + NS_IMETHOD Shutdown(); + +protected: + nsresult ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState); + nsresult AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString) + { return NS_OK; } // Overrides base impl in nsAccessible + + // nsIDOMXULMultiSelectControlElement inherits from this, so we'll always have + // one of these if the widget is valid and not defunct + nsCOMPtr mSelectControl; +}; /* Accessible for supporting XUL menus */ @@ -51,6 +76,7 @@ public: enum { eAction_Click = 0 }; nsXULMenuitemAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell); + NS_IMETHOD Init(); NS_IMETHOD GetName(nsAString& _retval); NS_IMETHOD GetDescription(nsAString& aDescription); NS_IMETHOD GetKeyboardShortcut(nsAString& _retval); @@ -61,7 +87,6 @@ public: NS_IMETHOD GetActionName(PRUint8 index, nsAString& _retval); NS_IMETHOD GetNumActions(PRUint8 *_retval); NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren); - void CacheChildren(); }; class nsXULMenuSeparatorAccessible : public nsXULMenuitemAccessible @@ -76,13 +101,16 @@ public: NS_IMETHOD GetNumActions(PRUint8 *_retval); }; -class nsXULMenupopupAccessible : public nsAccessibleWrap +class nsXULMenupopupAccessible : public nsXULSelectableAccessible { public: nsXULMenupopupAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell); NS_IMETHOD GetName(nsAString& _retval); NS_IMETHOD GetState(PRUint32 *_retval); NS_IMETHOD GetRole(PRUint32 *_retval); + static already_AddRefed FindInNodeList(nsIDOMNodeList *aNodeList, + nsIAtom *aAtom, PRUint32 aNameSpaceID); + static void GenerateMenu(nsIDOMNode *aNode); }; class nsXULMenubarAccessible : public nsAccessibleWrap diff --git a/accessible/src/xul/nsXULSelectAccessible.cpp b/accessible/src/xul/nsXULSelectAccessible.cpp index 3bcffb0addd5..6233c4ddb2a4 100644 --- a/accessible/src/xul/nsXULSelectAccessible.cpp +++ b/accessible/src/xul/nsXULSelectAccessible.cpp @@ -39,10 +39,8 @@ #include "nsXULSelectAccessible.h" #include "nsAccessibilityService.h" -#include "nsIMutableArray.h" #include "nsIContent.h" #include "nsIDOMXULMenuListElement.h" -#include "nsIDOMXULMultSelectCntrlEl.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsIDOMXULSelectCntrlEl.h" #include "nsIDOMXULTextboxElement.h" @@ -67,194 +65,6 @@ * - nsXULMenuitemAccessible */ -/** ------------------------------------------------------ */ -/** Impl. of nsXULSelectableAccessible */ -/** ------------------------------------------------------ */ - -// Helper methos -nsXULSelectableAccessible::nsXULSelectableAccessible(nsIDOMNode* aDOMNode, - nsIWeakReference* aShell): -nsAccessibleWrap(aDOMNode, aShell) -{ -} - -NS_IMETHODIMP nsXULSelectableAccessible::GetName(nsAString& aName) -{ - return GetXULName(aName, PR_FALSE); -} - -NS_IMPL_ISUPPORTS_INHERITED1(nsXULSelectableAccessible, nsAccessible, nsIAccessibleSelectable) - -NS_IMETHODIMP nsXULSelectableAccessible::ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState) -{ - nsCOMPtr childAcc; - GetChildAt(aIndex, getter_AddRefs(childAcc)); - nsCOMPtr accNode = do_QueryInterface(childAcc); - NS_ENSURE_TRUE(accNode, NS_ERROR_FAILURE); - - nsCOMPtr childNode; - accNode->GetDOMNode(getter_AddRefs(childNode)); - nsCOMPtr item(do_QueryInterface(childNode)); - NS_ENSURE_TRUE(item, NS_ERROR_FAILURE); - - *aSelState = PR_FALSE; - - nsCOMPtr xulSelect(do_QueryInterface(mDOMNode)); - nsCOMPtr xulMultiSelect(do_QueryInterface(mDOMNode)); - - if (xulSelect || xulMultiSelect) { - item->GetSelected(aSelState); - if (eSelection_Add == aMethod && !(*aSelState)) { - if (xulMultiSelect) - return xulMultiSelect->AddItemToSelection(item); - else if (xulSelect) - return xulSelect->SetSelectedItem(item); - } - else if (eSelection_Remove == aMethod && (*aSelState)) { - if (xulMultiSelect) - return xulMultiSelect->RemoveItemFromSelection(item); - else if (xulSelect) - return xulSelect->SetSelectedIndex(-1); - } - } - - return NS_ERROR_FAILURE; -} - -// Interface methods -NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **_retval) -{ - *_retval = nsnull; - - nsCOMPtr accService(do_GetService("@mozilla.org/accessibilityService;1")); - if (!accService) - return NS_ERROR_FAILURE; - - nsCOMPtr selectedAccessibles = - do_CreateInstance(NS_ARRAY_CONTRACTID); - NS_ENSURE_STATE(selectedAccessibles); - - // For XUL multi-select control - nsCOMPtr xulMultiSelect(do_QueryInterface(mDOMNode)); - if (xulMultiSelect) { - PRInt32 length = 0; - xulMultiSelect->GetSelectedCount(&length); - for (PRInt32 index = 0; index < length; index++) { - nsCOMPtr tempAccessible; - nsCOMPtr tempNode; - xulMultiSelect->GetSelectedItem(index, getter_AddRefs(tempNode)); - nsCOMPtr tempDOMNode (do_QueryInterface(tempNode)); - accService->GetAccessibleInWeakShell(tempDOMNode, mWeakShell, getter_AddRefs(tempAccessible)); - if (tempAccessible) - selectedAccessibles->AppendElement(tempAccessible, PR_FALSE); - } - } - - PRUint32 uLength = 0; - selectedAccessibles->GetLength(&uLength); - if (uLength != 0) { // length of nsIArray containing selected options - *_retval = selectedAccessibles; - NS_ADDREF(*_retval); - } - - return NS_OK; -} - -// return the nth selected child's nsIAccessible object -NS_IMETHODIMP nsXULSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccessible **_retval) -{ - *_retval = nsnull; - - nsCOMPtr accService(do_GetService("@mozilla.org/accessibilityService;1")); - if (!accService) - return NS_ERROR_FAILURE; - - nsCOMPtr tempDOMNode; - nsCOMPtr xulMultiSelect(do_QueryInterface(mDOMNode)); - if (xulMultiSelect) - xulMultiSelect->GetSelectedItem(aIndex, getter_AddRefs(tempDOMNode)); - - nsCOMPtr xulSelect(do_QueryInterface(mDOMNode)); - if (xulSelect && aIndex == 0) - xulSelect->GetSelectedItem(getter_AddRefs(tempDOMNode)); - - if (tempDOMNode) { - nsCOMPtr tempAccess; - accService->GetAccessibleInWeakShell(tempDOMNode, mWeakShell, getter_AddRefs(tempAccess)); - *_retval = tempAccess; - NS_IF_ADDREF(*_retval); - return *_retval ? NS_OK : NS_ERROR_FAILURE; - } - - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP nsXULSelectableAccessible::GetSelectionCount(PRInt32 *aSelectionCount) -{ - *aSelectionCount = 0; - - // For XUL multi-select control - nsCOMPtr xulMultiSelect(do_QueryInterface(mDOMNode)); - if (xulMultiSelect) - return xulMultiSelect->GetSelectedCount(aSelectionCount); - - // For XUL single-select control/menulist - nsCOMPtr xulSelect(do_QueryInterface(mDOMNode)); - if (xulSelect) { - PRInt32 index; - xulSelect->GetSelectedIndex(&index); - if (index >= 0) - *aSelectionCount = 1; - return NS_OK; - } - - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP nsXULSelectableAccessible::AddChildToSelection(PRInt32 aIndex) -{ - PRBool isSelected; - return ChangeSelection(aIndex, eSelection_Add, &isSelected); -} - -NS_IMETHODIMP nsXULSelectableAccessible::RemoveChildFromSelection(PRInt32 aIndex) -{ - PRBool isSelected; - return ChangeSelection(aIndex, eSelection_Remove, &isSelected); -} - -NS_IMETHODIMP nsXULSelectableAccessible::IsChildSelected(PRInt32 aIndex, PRBool *_retval) -{ - *_retval = PR_FALSE; - return ChangeSelection(aIndex, eSelection_GetState, _retval); -} - -NS_IMETHODIMP nsXULSelectableAccessible::ClearSelection() -{ - nsCOMPtr xulMultiSelect(do_QueryInterface(mDOMNode)); - if (xulMultiSelect) - return xulMultiSelect->ClearSelection(); - - nsCOMPtr xulSelect(do_QueryInterface(mDOMNode)); - if (xulSelect) - return xulSelect->SetSelectedIndex(-1); - - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP nsXULSelectableAccessible::SelectAllSelection(PRBool *_retval) -{ - *_retval = PR_TRUE; - - nsCOMPtr xulMultiSelect(do_QueryInterface(mDOMNode)); - if (xulMultiSelect) - return xulMultiSelect->SelectAll(); - - // otherwise, don't support this method - *_retval = PR_FALSE; - return NS_OK; -} - /** ----- nsXULListboxAccessible ----- */ /** Constructor */ @@ -402,6 +212,7 @@ NS_IMETHODIMP nsXULListitemAccessible::GetActionName(PRUint8 index, nsAString& _ } return NS_ERROR_INVALID_ARG; } + /** ------------------------------------------------------ */ /** Finally, the Combobox widgets */ /** ------------------------------------------------------ */ @@ -410,10 +221,17 @@ NS_IMETHODIMP nsXULListitemAccessible::GetActionName(PRUint8 index, nsAString& _ /** Constructor */ nsXULComboboxAccessible::nsXULComboboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell): -nsXULSelectableAccessible(aDOMNode, aShell) +nsAccessibleWrap(aDOMNode, aShell) { } +NS_IMETHODIMP nsXULComboboxAccessible::Init() +{ + nsresult rv = nsAccessibleWrap::Init(); + nsXULMenupopupAccessible::GenerateMenu(mDOMNode); + return rv; +} + /** We are a combobox */ NS_IMETHODIMP nsXULComboboxAccessible::GetRole(PRUint32 *aRole) { @@ -499,55 +317,17 @@ NS_IMETHODIMP nsXULComboboxAccessible::GetDescription(nsAString& aDescription) return NS_OK; } -void nsXULComboboxAccessible::CacheChildren() -{ - if (!mWeakShell) { - // This node has been shut down - mAccChildCount = eChildCountUninitialized; - return; - } - - if (mAccChildCount != eChildCountUninitialized) { - return; - } - - // Set menugenerated="true" on the menupopup node to generate the - // sub-menu items if they have not been generated - PRUint32 childIndex, numChildren = 0; - nsCOMPtr childNode; - nsCOMPtr nodeList; - mDOMNode->GetChildNodes(getter_AddRefs(nodeList)); - if (nodeList && NS_OK == nodeList->GetLength(&numChildren)) { - for (childIndex = 0; childIndex < numChildren; childIndex++) { - nodeList->Item(childIndex, getter_AddRefs(childNode)); - nsCOMPtr content = do_QueryInterface(childNode); - if (content->NodeInfo()->Equals(nsAccessibilityAtoms::menupopup, kNameSpaceID_XUL)) { - break; - } - } - - if (childIndex < numChildren) { - nsCOMPtr element(do_QueryInterface(childNode)); - if (element) { - nsAutoString attr; - element->GetAttribute(NS_LITERAL_STRING("menugenerated"), attr); - if (!attr.Equals(NS_LITERAL_STRING("true"))) { - element->SetAttribute(NS_LITERAL_STRING("menugenerated"), NS_LITERAL_STRING("true")); - } - } - } - } - nsXULSelectableAccessible::CacheChildren(); -} - NS_IMETHODIMP nsXULComboboxAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren) { nsCOMPtr content = do_QueryInterface(mDOMNode); - if (content->NodeInfo()->Equals(nsAccessibilityAtoms::textbox, kNameSpaceID_XUL)) { - // autocomplete textbox also uses nsXULComboboxAccessible and we need walk - // anonymous children + if (content->NodeInfo()->Equals(nsAccessibilityAtoms::textbox, kNameSpaceID_XUL) || + content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::editable, + nsAccessibilityAtoms::_true, eIgnoreCase)) { + // Both the XUL and widgets + // use nsXULComboboxAccessible. We need to walk the anonymous children for these + // so that the entry field is a child *aAllowsAnonChildren = PR_TRUE; } else { // Argument of PR_FALSE indicates we don't walk anonymous children for diff --git a/accessible/src/xul/nsXULSelectAccessible.h b/accessible/src/xul/nsXULSelectAccessible.h index dc00ca159d9e..2feb45ff17b9 100644 --- a/accessible/src/xul/nsXULSelectAccessible.h +++ b/accessible/src/xul/nsXULSelectAccessible.h @@ -39,7 +39,6 @@ #define __nsXULSelectAccessible_h__ #include "nsCOMPtr.h" -#include "nsIAccessibleSelectable.h" #include "nsXULMenuAccessible.h" class nsIWeakReference; @@ -63,30 +62,6 @@ class nsIWeakReference; /** First, the common widgets */ /** ------------------------------------------------------ */ -/* - * The basic implemetation of nsIAccessibleSelectable. - */ -class nsXULSelectableAccessible : public nsAccessibleWrap -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIACCESSIBLESELECTABLE - - nsXULSelectableAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell); - virtual ~nsXULSelectableAccessible() {} - - NS_IMETHOD GetName(nsAString& _retval); - -protected: - NS_IMETHOD ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState); - nsresult AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString) - { return NS_ERROR_FAILURE; } // Overrides base impl in nsAccessible -}; - -/** ------------------------------------------------------ */ -/** Secondly, the Listbox widget */ -/** ------------------------------------------------------ */ - /* * A class the represents the XUL Listbox widget. */ @@ -121,8 +96,6 @@ public: NS_IMETHOD GetRole(PRUint32 *_retval); NS_IMETHOD GetState(PRUint32 *_retval); NS_IMETHOD GetActionName(PRUint8 index, nsAString& _retval); - // Don't use XUL menu's special child aggregator, this can be a rich list item - void CacheChildren() { nsAccessibleWrap::CacheChildren(); } // Don't use XUL menuitems's description attribute NS_IMETHOD GetDescription(nsAString& aDesc) { return nsAccessibleWrap::GetDescription(aDesc); } @@ -137,7 +110,7 @@ private: /* * A class the represents the XUL Combobox widget. */ -class nsXULComboboxAccessible : public nsXULSelectableAccessible +class nsXULComboboxAccessible : public nsAccessibleWrap { public: enum { eAction_Click = 0 }; @@ -145,8 +118,10 @@ public: nsXULComboboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell); virtual ~nsXULComboboxAccessible() {} + /* ----- nsPIAccessible ---- */ + NS_IMETHOD Init(); + /* ----- nsIAccessible ----- */ - void CacheChildren(); NS_IMETHOD GetRole(PRUint32 *_retval); NS_IMETHOD GetState(PRUint32 *_retval); NS_IMETHOD GetValue(nsAString& _retval); diff --git a/toolkit/content/widgets/menulist.xml b/toolkit/content/widgets/menulist.xml index 7a1fa166910e..b53fffaec70d 100644 --- a/toolkit/content/widgets/menulist.xml +++ b/toolkit/content/widgets/menulist.xml @@ -312,7 +312,10 @@ + return (this.getAttribute("droppable") == "false") ? + Components.interfaces.nsIAccessibleProvider.XULTextBox : + Components.interfaces.nsIAccessibleProvider.XULCombobox; ]]>