Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLFormControlAccessible.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Author: Eric Vaughan (evaughan@netscape.com)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 // NOTE: alphabetically ordered
00040 #include "nsAccessibleTreeWalker.h"
00041 #include "nsAccessibilityAtoms.h"
00042 #include "nsHTMLFormControlAccessible.h"
00043 #include "nsIDOMHTMLInputElement.h"
00044 #include "nsIDOMNSHTMLButtonElement.h"
00045 #include "nsIDOMHTMLLegendElement.h"
00046 #include "nsIDOMHTMLTextAreaElement.h"
00047 #include "nsIFrame.h"
00048 #include "nsINameSpaceManager.h"
00049 #include "nsISelectionController.h"
00050 #include "nsISupportsArray.h"
00051 
00052 // --- checkbox -----
00053 
00054 nsHTMLCheckboxAccessible::nsHTMLCheckboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
00055 nsFormControlAccessible(aNode, aShell)
00056 { 
00057 }
00058 
00059 NS_IMETHODIMP nsHTMLCheckboxAccessible::GetRole(PRUint32 *_retval)
00060 {
00061   *_retval = ROLE_CHECKBUTTON;
00062   return NS_OK;
00063 }
00064 
00065 NS_IMETHODIMP nsHTMLCheckboxAccessible::GetNumActions(PRUint8 *_retval)
00066 {
00067   *_retval = eSingle_Action;
00068   return NS_OK;
00069 }
00070 
00071 NS_IMETHODIMP nsHTMLCheckboxAccessible::GetActionName(PRUint8 index, nsAString& _retval)
00072 {
00073   if (index == eAction_Click) {    // 0 is the magic value for default action
00074     // check or uncheck
00075     PRUint32 state;
00076     GetState(&state);
00077 
00078     if (state & STATE_CHECKED)
00079       nsAccessible::GetTranslatedString(NS_LITERAL_STRING("uncheck"), _retval); 
00080     else
00081       nsAccessible::GetTranslatedString(NS_LITERAL_STRING("check"), _retval); 
00082 
00083     return NS_OK;
00084   }
00085   return NS_ERROR_INVALID_ARG;
00086 }
00087 
00088 NS_IMETHODIMP nsHTMLCheckboxAccessible::DoAction(PRUint8 index)
00089 {
00090   if (index == 0) {   // 0 is the magic value for default action
00091     return DoCommand();
00092   }
00093   return NS_ERROR_INVALID_ARG;
00094 }
00095 
00096 NS_IMETHODIMP nsHTMLCheckboxAccessible::GetState(PRUint32 *_retval)
00097 {
00098   nsFormControlAccessible::GetState(_retval);
00099   PRBool checked = PR_FALSE;   // Radio buttons and check boxes can be checked
00100 
00101   nsCOMPtr<nsIDOMHTMLInputElement> htmlCheckboxElement(do_QueryInterface(mDOMNode));
00102   if (htmlCheckboxElement) 
00103     htmlCheckboxElement->GetChecked(&checked);
00104 
00105   if (checked) 
00106     *_retval |= STATE_CHECKED;
00107   
00108   return NS_OK;
00109 }
00110 
00111 //------ Radio button -------
00112 
00113 nsHTMLRadioButtonAccessible::nsHTMLRadioButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
00114 nsRadioButtonAccessible(aNode, aShell)
00115 { 
00116 }
00117 
00118 NS_IMETHODIMP nsHTMLRadioButtonAccessible::DoAction(PRUint8 index)
00119 {
00120   if (index == eAction_Click) {
00121     return DoCommand();
00122   }
00123   return NS_ERROR_INVALID_ARG;
00124 }
00125 
00126 NS_IMETHODIMP nsHTMLRadioButtonAccessible::GetState(PRUint32 *_retval)
00127 {
00128   nsFormControlAccessible::GetState(_retval);
00129   PRBool checked = PR_FALSE;   // Radio buttons and check boxes can be checked
00130 
00131   nsCOMPtr<nsIDOMHTMLInputElement> htmlRadioElement(do_QueryInterface(mDOMNode));
00132   if (htmlRadioElement) 
00133     htmlRadioElement->GetChecked(&checked);
00134 
00135   if (checked) 
00136     *_retval |= STATE_CHECKED;
00137 
00138   return NS_OK;
00139 }
00140 
00141 // ----- Button -----
00142 
00143 nsHTMLButtonAccessible::nsHTMLButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
00144 nsFormControlAccessible(aNode, aShell)
00145 { 
00146 }
00147 
00148 NS_IMETHODIMP nsHTMLButtonAccessible::GetNumActions(PRUint8 *_retval)
00149 {
00150   *_retval = eSingle_Action;
00151   return NS_OK;
00152 }
00153 
00154 NS_IMETHODIMP nsHTMLButtonAccessible::GetActionName(PRUint8 index, nsAString& _retval)
00155 {
00156   if (index == eAction_Click) {
00157     nsAccessible::GetTranslatedString(NS_LITERAL_STRING("press"), _retval); 
00158     return NS_OK;
00159   }
00160   return NS_ERROR_INVALID_ARG;
00161 }
00162 
00163 NS_IMETHODIMP nsHTMLButtonAccessible::DoAction(PRUint8 index)
00164 {
00165   if (index == eAction_Click) {
00166     return DoCommand();
00167   }
00168   return NS_ERROR_INVALID_ARG;
00169 }
00170 
00171 NS_IMETHODIMP nsHTMLButtonAccessible::GetState(PRUint32 *_retval)
00172 {
00173   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
00174   if (!element) {
00175     return NS_ERROR_FAILURE;  // Button accessible shut down
00176   }
00177   nsFormControlAccessible::GetState(_retval);
00178   nsAutoString buttonType;
00179   element->GetAttribute(NS_LITERAL_STRING("type"), buttonType);
00180   if (buttonType.LowerCaseEqualsLiteral("submit"))
00181     *_retval |= STATE_DEFAULT;
00182 
00183   return NS_OK;
00184 }
00185 
00186 NS_IMETHODIMP nsHTMLButtonAccessible::GetRole(PRUint32 *_retval)
00187 {
00188   *_retval = ROLE_PUSHBUTTON;
00189   return NS_OK;
00190 }
00191 
00192 NS_IMETHODIMP nsHTMLButtonAccessible::GetName(nsAString& aName)
00193 {
00194   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
00195   if (!content) {
00196     return NS_ERROR_FAILURE; // Node shut down
00197   }
00198 
00199   nsAutoString name;
00200   if (NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
00201                                                     nsAccessibilityAtoms::value,
00202                                                     name) &&
00203       NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
00204                                                     nsAccessibilityAtoms::alt,
00205                                                     name)) {
00206     if (mRoleMapEntry) {
00207       // Use HTML label or DHTML accessibility's labelledby attribute for name
00208       GetHTMLName(name, PR_FALSE);
00209     }
00210     if (name.IsEmpty()) {
00211       // Use anonymous text child of button if nothing else works.
00212       // This is necessary for submit, reset and browse buttons.
00213       nsCOMPtr<nsIPresShell> shell(GetPresShell());
00214       NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
00215       nsCOMPtr<nsISupportsArray> anonymousElements;
00216       shell->GetAnonymousContentFor(content, getter_AddRefs(anonymousElements));
00217       nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(anonymousElements, 0));
00218       if (domNode) {
00219         domNode->GetNodeValue(name);
00220       }
00221     }
00222     if (name.IsEmpty() &&
00223         NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
00224                                                       nsAccessibilityAtoms::title,
00225                                                       name) &&
00226         NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
00227                                                       nsAccessibilityAtoms::src,
00228                                                       name)) {
00229       content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::data, name);
00230     }
00231   }
00232 
00233   name.CompressWhitespace();
00234   aName = name;
00235 
00236   return NS_OK;
00237 }
00238 
00239 
00240 // ----- HTML 4 Button: can contain arbitrary HTML content -----
00241 
00242 nsHTML4ButtonAccessible::nsHTML4ButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
00243 nsLeafAccessible(aNode, aShell)
00244 { 
00245 }
00246 
00247 NS_IMETHODIMP nsHTML4ButtonAccessible::GetNumActions(PRUint8 *_retval)
00248 {
00249   *_retval = eSingle_Action;
00250   return NS_OK;;
00251 }
00252 
00253 NS_IMETHODIMP nsHTML4ButtonAccessible::GetActionName(PRUint8 index, nsAString& _retval)
00254 {
00255   if (index == eAction_Click) {
00256     nsAccessible::GetTranslatedString(NS_LITERAL_STRING("press"), _retval); 
00257     return NS_OK;
00258   }
00259   return NS_ERROR_INVALID_ARG;
00260 }
00261 
00262 NS_IMETHODIMP nsHTML4ButtonAccessible::DoAction(PRUint8 index)
00263 {
00264   if (index == 0) {
00265     return DoCommand();
00266   }
00267   return NS_ERROR_INVALID_ARG;
00268 }
00269 
00270 NS_IMETHODIMP nsHTML4ButtonAccessible::GetRole(PRUint32 *_retval)
00271 {
00272   *_retval = ROLE_PUSHBUTTON;
00273   return NS_OK;
00274 }
00275 
00276 NS_IMETHODIMP nsHTML4ButtonAccessible::GetState(PRUint32 *_retval)
00277 {
00278   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
00279   if (!element) {
00280     return NS_ERROR_FAILURE;  // Button accessible shut down
00281   }
00282   nsAccessible::GetState(_retval);
00283   *_retval |= STATE_FOCUSABLE;
00284 
00285   nsAutoString buttonType;
00286   element->GetAttribute(NS_LITERAL_STRING("type"), buttonType);
00287   if (buttonType.LowerCaseEqualsLiteral("submit"))
00288     *_retval |= STATE_DEFAULT;
00289 
00290   return NS_OK;
00291 }
00292 
00293 // --- textfield -----
00294 
00295 nsHTMLTextFieldAccessible::nsHTMLTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
00296 nsFormControlAccessible(aNode, aShell)
00297 { 
00298 }
00299 
00300 NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLTextFieldAccessible, nsFormControlAccessible)
00301 
00302 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetRole(PRUint32 *_retval)
00303 {
00304   *_retval = ROLE_TEXT;
00305   return NS_OK;
00306 }
00307 
00308 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetValue(nsAString& _retval)
00309 {
00310   PRUint32 state;
00311   GetState(&state);
00312   if (state & STATE_PROTECTED)    // Don't return password text!
00313     return NS_ERROR_FAILURE;
00314 
00315   nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mDOMNode));
00316   if (textArea) {
00317     return textArea->GetValue(_retval);
00318   }
00319   
00320   nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(mDOMNode));
00321   if (inputElement) {
00322     return inputElement->GetValue(_retval);
00323   }
00324 
00325   return NS_ERROR_FAILURE;
00326 }
00327 
00328 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetState(PRUint32 *aState)
00329 {
00330   // can be focusable, focused, protected. readonly, unavailable, selected
00331   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
00332   if (!content) {
00333     return NS_ERROR_FAILURE;  // Node has been Shutdown()
00334   }
00335 
00336   nsFormControlAccessible::GetState(aState);
00337   nsAutoString typeString;
00338   content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::type, typeString);
00339   if (typeString.LowerCaseEqualsLiteral("password")) {
00340     *aState |= STATE_PROTECTED;
00341   }
00342   if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::readonly)) {
00343     *aState |= STATE_READONLY;
00344   }
00345 
00346   return NS_OK;
00347 }
00348 
00349 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetExtState(PRUint32 *aExtState)
00350 {
00351   nsresult rv = nsFormControlAccessible::GetExtState(aExtState);
00352   *aExtState |= EXT_STATE_SINGLE_LINE;
00353   return rv;
00354 }
00355 
00356 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetNumActions(PRUint8 *_retval)
00357 {
00358   *_retval = eSingle_Action;
00359   return NS_OK;;
00360 }
00361 
00362 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetActionName(PRUint8 index, nsAString& _retval)
00363 {
00364   if (index == eAction_Click) {
00365     nsAccessible::GetTranslatedString(NS_LITERAL_STRING("activate"), _retval);
00366     return NS_OK;
00367   }
00368   return NS_ERROR_INVALID_ARG;
00369 }
00370 
00371 NS_IMETHODIMP nsHTMLTextFieldAccessible::DoAction(PRUint8 index)
00372 {
00373   if (index == 0) {
00374     nsCOMPtr<nsIDOMHTMLInputElement> element(do_QueryInterface(mDOMNode));
00375     if ( element )
00376     {
00377       element->Focus();
00378       return NS_OK;
00379     }
00380     return NS_ERROR_FAILURE;
00381   }
00382   return NS_ERROR_INVALID_ARG;
00383 }
00384 
00385 // --- groupbox  -----
00386 
00387 /*
00388  * The HTML for this is <fieldset> <legend>box-title</legend> form elements </fieldset> 
00389  */
00390 
00391 nsHTMLGroupboxAccessible::nsHTMLGroupboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
00392 nsAccessibleWrap(aNode, aShell)
00393 { 
00394 }
00395 
00396 NS_IMETHODIMP nsHTMLGroupboxAccessible::GetRole(PRUint32 *_retval)
00397 {
00398   *_retval = ROLE_GROUPING;
00399   return NS_OK;
00400 }
00401 
00402 NS_IMETHODIMP nsHTMLGroupboxAccessible::GetState(PRUint32 *_retval)
00403 {
00404   // Groupbox doesn't support any states!
00405   *_retval = 0;
00406 
00407   return NS_OK;
00408 }
00409 
00410 NS_IMETHODIMP nsHTMLGroupboxAccessible::GetName(nsAString& aName)
00411 {
00412   if (mRoleMapEntry) {
00413     nsAccessible::GetName(aName);
00414     if (!aName.IsEmpty()) {
00415       return NS_OK;
00416     }
00417   }
00418 
00419   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
00420   if (element) {
00421     nsCOMPtr<nsIDOMNodeList> legends;
00422     nsAutoString nameSpaceURI;
00423     element->GetNamespaceURI(nameSpaceURI);
00424     element->GetElementsByTagNameNS(nameSpaceURI, NS_LITERAL_STRING("legend"),
00425                                   getter_AddRefs(legends));
00426     if (legends) {
00427       nsCOMPtr<nsIDOMNode> legendNode;
00428       legends->Item(0, getter_AddRefs(legendNode));
00429       nsCOMPtr<nsIContent> legendContent(do_QueryInterface(legendNode));
00430       if (legendContent) {
00431         aName.Truncate();  // Default name is blank 
00432         return AppendFlatStringFromSubtree(legendContent, &aName);
00433       }
00434     }
00435   }
00436   return NS_OK;
00437 }
00438 
00439 void nsHTMLGroupboxAccessible::CacheChildren(PRBool aWalkAnonContent)
00440 {
00441   if (!mWeakShell) {
00442     // This node has been shut down
00443     mAccChildCount = -1;
00444     return;
00445   }
00446 
00447   if (mAccChildCount == eChildCountUninitialized) {
00448     nsAccessibleTreeWalker walker(mWeakShell, mDOMNode, aWalkAnonContent);
00449     walker.mState.frame = GetFrame();
00450     mAccChildCount = 0;
00451     walker.GetFirstChild();
00452     // Check for <legend> and skip it if it's there
00453     if (walker.mState.accessible && walker.mState.domNode) {
00454       nsCOMPtr<nsIDOMNode> mightBeLegendNode;
00455       walker.mState.domNode->GetParentNode(getter_AddRefs(mightBeLegendNode));
00456       nsCOMPtr<nsIDOMHTMLLegendElement> legend(do_QueryInterface(mightBeLegendNode));
00457       if (legend) {
00458         walker.GetNextSibling();      // Skip the legend
00459       }
00460     }
00461     SetFirstChild(walker.mState.accessible);
00462     nsCOMPtr<nsPIAccessible> privatePrevAccessible;
00463     while (walker.mState.accessible) {
00464       ++mAccChildCount;
00465       privatePrevAccessible = do_QueryInterface(walker.mState.accessible);
00466       privatePrevAccessible->SetParent(this);
00467       walker.GetNextSibling();
00468       privatePrevAccessible->SetNextSibling(walker.mState.accessible);
00469     }
00470   }
00471 }