1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Aaron Leventhal (aaronl@netscape.com)
24 : * Kyle Yuan (kyle.yuan@sun.com)
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsXULFormControlAccessible.h"
41 :
42 : #include "nsAccUtils.h"
43 : #include "nsAccTreeWalker.h"
44 : #include "nsCoreUtils.h"
45 : #include "nsDocAccessible.h"
46 : #include "Relation.h"
47 : #include "Role.h"
48 : #include "States.h"
49 :
50 : // NOTE: alphabetically ordered
51 : #include "nsHTMLFormControlAccessible.h"
52 : #include "nsXULMenuAccessible.h"
53 : #include "nsIAccessibleRelation.h"
54 : #include "nsIDOMHTMLInputElement.h"
55 : #include "nsIDOMNSEditableElement.h"
56 : #include "nsIDOMXULButtonElement.h"
57 : #include "nsIDOMXULCheckboxElement.h"
58 : #include "nsIDOMXULMenuListElement.h"
59 : #include "nsIDOMXULSelectCntrlItemEl.h"
60 : #include "nsIDOMXULTextboxElement.h"
61 : #include "nsIEditor.h"
62 : #include "nsIFrame.h"
63 : #include "nsINameSpaceManager.h"
64 : #include "nsITextControlFrame.h"
65 : #include "nsMenuPopupFrame.h"
66 :
67 : using namespace mozilla::a11y;
68 :
69 : ////////////////////////////////////////////////////////////////////////////////
70 : // nsXULButtonAccessible
71 : ////////////////////////////////////////////////////////////////////////////////
72 :
73 0 : nsXULButtonAccessible::
74 : nsXULButtonAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
75 0 : nsAccessibleWrap(aContent, aDoc)
76 : {
77 0 : if (ContainsMenu())
78 0 : mFlags |= eMenuButtonAccessible;
79 0 : }
80 :
81 : ////////////////////////////////////////////////////////////////////////////////
82 : // nsXULButtonAccessible: nsISupports
83 :
84 0 : NS_IMPL_ISUPPORTS_INHERITED0(nsXULButtonAccessible, nsAccessible)
85 :
86 : ////////////////////////////////////////////////////////////////////////////////
87 : // nsXULButtonAccessible: nsIAccessible
88 :
89 : PRUint8
90 0 : nsXULButtonAccessible::ActionCount()
91 : {
92 0 : return 1;
93 : }
94 :
95 : NS_IMETHODIMP
96 0 : nsXULButtonAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
97 : {
98 0 : if (aIndex == eAction_Click) {
99 0 : aName.AssignLiteral("press");
100 0 : return NS_OK;
101 : }
102 0 : return NS_ERROR_INVALID_ARG;
103 : }
104 :
105 : NS_IMETHODIMP
106 0 : nsXULButtonAccessible::DoAction(PRUint8 aIndex)
107 : {
108 0 : if (aIndex != 0)
109 0 : return NS_ERROR_INVALID_ARG;
110 :
111 0 : DoCommand();
112 0 : return NS_OK;
113 : }
114 :
115 : ////////////////////////////////////////////////////////////////////////////////
116 : // nsXULButtonAccessible: nsAccessible
117 :
118 : role
119 0 : nsXULButtonAccessible::NativeRole()
120 : {
121 0 : return roles::PUSHBUTTON;
122 : }
123 :
124 : PRUint64
125 0 : nsXULButtonAccessible::NativeState()
126 : {
127 : // Possible states: focused, focusable, unavailable(disabled).
128 :
129 : // get focus and disable status from base class
130 0 : PRUint64 state = nsAccessible::NativeState();
131 :
132 0 : bool disabled = false;
133 0 : nsCOMPtr<nsIDOMXULControlElement> xulFormElement(do_QueryInterface(mContent));
134 0 : if (xulFormElement) {
135 0 : xulFormElement->GetDisabled(&disabled);
136 0 : if (disabled)
137 0 : state |= states::UNAVAILABLE;
138 : else
139 0 : state |= states::FOCUSABLE;
140 : }
141 :
142 : // Buttons can be checked -- they simply appear pressed in rather than checked
143 0 : nsCOMPtr<nsIDOMXULButtonElement> xulButtonElement(do_QueryInterface(mContent));
144 0 : if (xulButtonElement) {
145 0 : nsAutoString type;
146 0 : xulButtonElement->GetType(type);
147 0 : if (type.EqualsLiteral("checkbox") || type.EqualsLiteral("radio")) {
148 0 : state |= states::CHECKABLE;
149 0 : bool checked = false;
150 0 : PRInt32 checkState = 0;
151 0 : xulButtonElement->GetChecked(&checked);
152 0 : if (checked) {
153 0 : state |= states::PRESSED;
154 0 : xulButtonElement->GetCheckState(&checkState);
155 0 : if (checkState == nsIDOMXULButtonElement::CHECKSTATE_MIXED) {
156 0 : state |= states::MIXED;
157 : }
158 : }
159 : }
160 : }
161 :
162 0 : if (ContainsMenu())
163 0 : state |= states::HASPOPUP;
164 :
165 0 : if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::_default))
166 0 : state |= states::DEFAULT;
167 :
168 0 : return state;
169 : }
170 :
171 : ////////////////////////////////////////////////////////////////////////////////
172 : // nsXULButtonAccessible: Widgets
173 :
174 : bool
175 0 : nsXULButtonAccessible::IsWidget() const
176 : {
177 0 : return true;
178 : }
179 :
180 : bool
181 0 : nsXULButtonAccessible::IsActiveWidget() const
182 : {
183 0 : return FocusMgr()->HasDOMFocus(mContent);
184 : }
185 :
186 : bool
187 0 : nsXULButtonAccessible::AreItemsOperable() const
188 : {
189 0 : if (IsMenuButton()) {
190 0 : nsAccessible* menuPopup = mChildren.SafeElementAt(0, nsnull);
191 0 : if (menuPopup) {
192 0 : nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(menuPopup->GetFrame());
193 0 : return menuPopupFrame->IsOpen();
194 : }
195 : }
196 0 : return false; // no items
197 : }
198 :
199 : nsAccessible*
200 0 : nsXULButtonAccessible::ContainerWidget() const
201 : {
202 0 : if (IsMenuButton() && mParent && mParent->IsAutoComplete())
203 0 : return mParent;
204 0 : return nsnull;
205 : }
206 :
207 : ////////////////////////////////////////////////////////////////////////////////
208 : // nsXULButtonAccessible: nsAccessible protected
209 :
210 : void
211 0 : nsXULButtonAccessible::CacheChildren()
212 : {
213 : // In general XUL button has not accessible children. Nevertheless menu
214 : // buttons can have button (@type="menu-button") and popup accessibles
215 : // (@type="menu-button" or @type="menu").
216 :
217 : // XXX: no children until the button is menu button. Probably it's not
218 : // totally correct but in general AT wants to have leaf buttons.
219 0 : bool isMenu = mContent->AttrValueIs(kNameSpaceID_None,
220 : nsGkAtoms::type,
221 : nsGkAtoms::menu,
222 0 : eCaseMatters);
223 :
224 : bool isMenuButton = isMenu ?
225 : false :
226 0 : mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
227 0 : nsGkAtoms::menuButton, eCaseMatters);
228 :
229 0 : NS_ENSURE_TRUE(mDoc,);
230 0 : if (!isMenu && !isMenuButton)
231 0 : return;
232 :
233 0 : nsAccessible* menupopup = nsnull;
234 0 : nsAccessible* button = nsnull;
235 :
236 0 : nsAccTreeWalker walker(mDoc, mContent, true);
237 :
238 0 : nsAccessible* child = nsnull;
239 0 : while ((child = walker.NextChild())) {
240 0 : roles::Role role = child->Role();
241 :
242 0 : if (role == roles::MENUPOPUP) {
243 : // Get an accessible for menupopup or panel elements.
244 0 : menupopup = child;
245 :
246 0 : } else if (isMenuButton && role == roles::PUSHBUTTON) {
247 : // Button type="menu-button" contains a real button. Get an accessible
248 : // for it. Ignore dropmarker button which is placed as a last child.
249 0 : button = child;
250 0 : break;
251 :
252 : } else {
253 : // Unbind rejected accessible from document.
254 0 : Document()->UnbindFromDocument(child);
255 : }
256 : }
257 :
258 0 : if (!menupopup)
259 : return;
260 :
261 0 : AppendChild(menupopup);
262 0 : if (button)
263 0 : AppendChild(button);
264 : }
265 :
266 : ////////////////////////////////////////////////////////////////////////////////
267 : // nsXULButtonAccessible protected
268 :
269 : bool
270 0 : nsXULButtonAccessible::ContainsMenu()
271 : {
272 : static nsIContent::AttrValuesArray strings[] =
273 : {&nsGkAtoms::menu, &nsGkAtoms::menuButton, nsnull};
274 :
275 0 : return mContent->FindAttrValueIn(kNameSpaceID_None,
276 : nsGkAtoms::type,
277 0 : strings, eCaseMatters) >= 0;
278 : }
279 :
280 : ////////////////////////////////////////////////////////////////////////////////
281 : // nsXULDropmarkerAccessible
282 : ////////////////////////////////////////////////////////////////////////////////
283 :
284 0 : nsXULDropmarkerAccessible::
285 : nsXULDropmarkerAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
286 0 : nsFormControlAccessible(aContent, aDoc)
287 : {
288 0 : }
289 :
290 : PRUint8
291 0 : nsXULDropmarkerAccessible::ActionCount()
292 : {
293 0 : return 1;
294 : }
295 :
296 0 : bool nsXULDropmarkerAccessible::DropmarkerOpen(bool aToggleOpen)
297 : {
298 0 : bool isOpen = false;
299 :
300 : nsCOMPtr<nsIDOMXULButtonElement> parentButtonElement =
301 0 : do_QueryInterface(mContent->GetParent());
302 :
303 0 : if (parentButtonElement) {
304 0 : parentButtonElement->GetOpen(&isOpen);
305 0 : if (aToggleOpen)
306 0 : parentButtonElement->SetOpen(!isOpen);
307 : }
308 : else {
309 : nsCOMPtr<nsIDOMXULMenuListElement> parentMenuListElement =
310 0 : do_QueryInterface(parentButtonElement);
311 0 : if (parentMenuListElement) {
312 0 : parentMenuListElement->GetOpen(&isOpen);
313 0 : if (aToggleOpen)
314 0 : parentMenuListElement->SetOpen(!isOpen);
315 : }
316 : }
317 :
318 0 : return isOpen;
319 : }
320 :
321 : /**
322 : * Return the name of our only action
323 : */
324 0 : NS_IMETHODIMP nsXULDropmarkerAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
325 : {
326 0 : if (aIndex == eAction_Click) {
327 0 : if (DropmarkerOpen(false))
328 0 : aName.AssignLiteral("close");
329 : else
330 0 : aName.AssignLiteral("open");
331 0 : return NS_OK;
332 : }
333 :
334 0 : return NS_ERROR_INVALID_ARG;
335 : }
336 :
337 : /**
338 : * Tell the Dropmarker to do its action
339 : */
340 0 : NS_IMETHODIMP nsXULDropmarkerAccessible::DoAction(PRUint8 index)
341 : {
342 0 : if (index == eAction_Click) {
343 0 : DropmarkerOpen(true); // Reverse the open attribute
344 0 : return NS_OK;
345 : }
346 0 : return NS_ERROR_INVALID_ARG;
347 : }
348 :
349 : role
350 0 : nsXULDropmarkerAccessible::NativeRole()
351 : {
352 0 : return roles::PUSHBUTTON;
353 : }
354 :
355 : PRUint64
356 0 : nsXULDropmarkerAccessible::NativeState()
357 : {
358 0 : return DropmarkerOpen(false) ? states::PRESSED : 0;
359 : }
360 :
361 : ////////////////////////////////////////////////////////////////////////////////
362 : // nsXULCheckboxAccessible
363 : ////////////////////////////////////////////////////////////////////////////////
364 :
365 0 : nsXULCheckboxAccessible::
366 : nsXULCheckboxAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
367 0 : nsFormControlAccessible(aContent, aDoc)
368 : {
369 0 : }
370 :
371 : role
372 0 : nsXULCheckboxAccessible::NativeRole()
373 : {
374 0 : return roles::CHECKBUTTON;
375 : }
376 :
377 : PRUint8
378 0 : nsXULCheckboxAccessible::ActionCount()
379 : {
380 0 : return 1;
381 : }
382 :
383 : /**
384 : * Return the name of our only action
385 : */
386 0 : NS_IMETHODIMP nsXULCheckboxAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
387 : {
388 0 : if (aIndex == eAction_Click) {
389 : // check or uncheck
390 :
391 0 : if (NativeState() & states::CHECKED)
392 0 : aName.AssignLiteral("uncheck");
393 : else
394 0 : aName.AssignLiteral("check");
395 :
396 0 : return NS_OK;
397 : }
398 0 : return NS_ERROR_INVALID_ARG;
399 : }
400 :
401 : /**
402 : * Tell the checkbox to do its only action -- check( or uncheck) itself
403 : */
404 : NS_IMETHODIMP
405 0 : nsXULCheckboxAccessible::DoAction(PRUint8 aIndex)
406 : {
407 0 : if (aIndex != eAction_Click)
408 0 : return NS_ERROR_INVALID_ARG;
409 :
410 0 : DoCommand();
411 0 : return NS_OK;
412 : }
413 :
414 : PRUint64
415 0 : nsXULCheckboxAccessible::NativeState()
416 : {
417 : // Possible states: focused, focusable, unavailable(disabled), checked
418 : // Get focus and disable status from base class
419 0 : PRUint64 state = nsFormControlAccessible::NativeState();
420 :
421 0 : state |= states::CHECKABLE;
422 :
423 : // Determine Checked state
424 : nsCOMPtr<nsIDOMXULCheckboxElement> xulCheckboxElement =
425 0 : do_QueryInterface(mContent);
426 0 : if (xulCheckboxElement) {
427 0 : bool checked = false;
428 0 : xulCheckboxElement->GetChecked(&checked);
429 0 : if (checked) {
430 0 : state |= states::CHECKED;
431 0 : PRInt32 checkState = 0;
432 0 : xulCheckboxElement->GetCheckState(&checkState);
433 0 : if (checkState == nsIDOMXULCheckboxElement::CHECKSTATE_MIXED)
434 0 : state |= states::MIXED;
435 : }
436 : }
437 :
438 0 : return state;
439 : }
440 :
441 : ////////////////////////////////////////////////////////////////////////////////
442 : // nsXULGroupboxAccessible
443 : ////////////////////////////////////////////////////////////////////////////////
444 :
445 0 : nsXULGroupboxAccessible::
446 : nsXULGroupboxAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
447 0 : nsAccessibleWrap(aContent, aDoc)
448 : {
449 0 : }
450 :
451 : role
452 0 : nsXULGroupboxAccessible::NativeRole()
453 : {
454 0 : return roles::GROUPING;
455 : }
456 :
457 : nsresult
458 0 : nsXULGroupboxAccessible::GetNameInternal(nsAString& aName)
459 : {
460 : // XXX: we use the first related accessible only.
461 : nsAccessible* label =
462 0 : RelationByType(nsIAccessibleRelation::RELATION_LABELLED_BY).Next();
463 0 : if (label)
464 0 : return label->GetName(aName);
465 :
466 0 : return NS_OK;
467 : }
468 :
469 : Relation
470 0 : nsXULGroupboxAccessible::RelationByType(PRUint32 aType)
471 : {
472 0 : Relation rel = nsAccessibleWrap::RelationByType(aType);
473 0 : if (aType != nsIAccessibleRelation::RELATION_LABELLED_BY)
474 0 : return rel;
475 :
476 : // The label for xul:groupbox is generated from xul:label that is
477 : // inside the anonymous content of the xul:caption.
478 : // The xul:label has an accessible object but the xul:caption does not
479 0 : PRInt32 childCount = GetChildCount();
480 0 : for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
481 0 : nsAccessible *childAcc = GetChildAt(childIdx);
482 0 : if (childAcc->Role() == roles::LABEL) {
483 : // Ensure that it's our label
484 : Relation reverseRel =
485 0 : childAcc->RelationByType(nsIAccessibleRelation::RELATION_LABEL_FOR);
486 0 : nsAccessible* testGroupbox = nsnull;
487 0 : while ((testGroupbox = reverseRel.Next()))
488 0 : if (testGroupbox == this) {
489 : // The <label> points back to this groupbox
490 0 : rel.AppendTarget(childAcc);
491 : }
492 : }
493 : }
494 :
495 0 : return rel;
496 : }
497 :
498 : ////////////////////////////////////////////////////////////////////////////////
499 : // nsXULRadioButtonAccessible
500 : ////////////////////////////////////////////////////////////////////////////////
501 :
502 0 : nsXULRadioButtonAccessible::
503 : nsXULRadioButtonAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
504 0 : nsRadioButtonAccessible(aContent, aDoc)
505 : {
506 0 : }
507 :
508 : PRUint64
509 0 : nsXULRadioButtonAccessible::NativeState()
510 : {
511 0 : PRUint64 state = nsFormControlAccessible::NativeState();
512 0 : state |= states::CHECKABLE;
513 :
514 0 : if (!(state & states::UNAVAILABLE))
515 0 : state |= states::FOCUSABLE;
516 :
517 : nsCOMPtr<nsIDOMXULSelectControlItemElement> radioButton =
518 0 : do_QueryInterface(mContent);
519 0 : if (radioButton) {
520 0 : bool selected = false; // Radio buttons can be selected
521 0 : radioButton->GetSelected(&selected);
522 0 : if (selected) {
523 0 : state |= states::CHECKED;
524 : }
525 : }
526 :
527 0 : return state;
528 : }
529 :
530 : void
531 0 : nsXULRadioButtonAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
532 : PRInt32 *aSetSize)
533 : {
534 : nsAccUtils::GetPositionAndSizeForXULSelectControlItem(mContent, aPosInSet,
535 0 : aSetSize);
536 0 : }
537 :
538 : ////////////////////////////////////////////////////////////////////////////////
539 : // nsXULRadioButtonAccessible: Widgets
540 :
541 : nsAccessible*
542 0 : nsXULRadioButtonAccessible::ContainerWidget() const
543 : {
544 0 : return mParent;
545 : }
546 :
547 :
548 : ////////////////////////////////////////////////////////////////////////////////
549 : // nsXULRadioGroupAccessible
550 : ////////////////////////////////////////////////////////////////////////////////
551 :
552 : /**
553 : * XUL Radio Group
554 : * The Radio Group proxies for the Radio Buttons themselves. The Group gets
555 : * focus whereas the Buttons do not. So we only have an accessible object for
556 : * this for the purpose of getting the proper RadioButton. Need this here to
557 : * avoid circular reference problems when navigating the accessible tree and
558 : * for getting to the radiobuttons.
559 : */
560 :
561 0 : nsXULRadioGroupAccessible::
562 : nsXULRadioGroupAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
563 0 : XULSelectControlAccessible(aContent, aDoc)
564 : {
565 0 : }
566 :
567 : role
568 0 : nsXULRadioGroupAccessible::NativeRole()
569 : {
570 0 : return roles::GROUPING;
571 : }
572 :
573 : PRUint64
574 0 : nsXULRadioGroupAccessible::NativeState()
575 : {
576 : // The radio group is not focusable. Sometimes the focus controller will
577 : // report that it is focused. That means that the actual selected radio button
578 : // should be considered focused.
579 0 : return nsAccessible::NativeState() & ~(states::FOCUSABLE | states::FOCUSED);
580 : }
581 :
582 : ////////////////////////////////////////////////////////////////////////////////
583 : // nsXULRadioGroupAccessible: Widgets
584 :
585 : bool
586 0 : nsXULRadioGroupAccessible::IsWidget() const
587 : {
588 0 : return true;
589 : }
590 :
591 : bool
592 0 : nsXULRadioGroupAccessible::IsActiveWidget() const
593 : {
594 0 : return FocusMgr()->HasDOMFocus(mContent);
595 : }
596 :
597 : bool
598 0 : nsXULRadioGroupAccessible::AreItemsOperable() const
599 : {
600 0 : return true;
601 : }
602 :
603 :
604 : ////////////////////////////////////////////////////////////////////////////////
605 : // nsXULStatusBarAccessible
606 : ////////////////////////////////////////////////////////////////////////////////
607 :
608 0 : nsXULStatusBarAccessible::
609 : nsXULStatusBarAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
610 0 : nsAccessibleWrap(aContent, aDoc)
611 : {
612 0 : }
613 :
614 : role
615 0 : nsXULStatusBarAccessible::NativeRole()
616 : {
617 0 : return roles::STATUSBAR;
618 : }
619 :
620 :
621 : ////////////////////////////////////////////////////////////////////////////////
622 : // nsXULToolbarButtonAccessible
623 : ////////////////////////////////////////////////////////////////////////////////
624 :
625 0 : nsXULToolbarButtonAccessible::
626 : nsXULToolbarButtonAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
627 0 : nsXULButtonAccessible(aContent, aDoc)
628 : {
629 0 : }
630 :
631 : void
632 0 : nsXULToolbarButtonAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
633 : PRInt32 *aSetSize)
634 : {
635 0 : PRInt32 setSize = 0;
636 0 : PRInt32 posInSet = 0;
637 :
638 0 : nsAccessible* parent = Parent();
639 0 : if (!parent)
640 0 : return;
641 :
642 0 : PRInt32 childCount = parent->GetChildCount();
643 0 : for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
644 0 : nsAccessible* child = parent->GetChildAt(childIdx);
645 0 : if (IsSeparator(child)) { // end of a group of buttons
646 0 : if (posInSet)
647 0 : break; // we've found our group, so we're done
648 :
649 0 : setSize = 0; // not our group, so start a new group
650 :
651 : } else {
652 0 : setSize++; // another button in the group
653 :
654 0 : if (child == this)
655 0 : posInSet = setSize; // we've found our button
656 : }
657 : }
658 :
659 0 : *aPosInSet = posInSet;
660 0 : *aSetSize = setSize;
661 : }
662 :
663 : bool
664 0 : nsXULToolbarButtonAccessible::IsSeparator(nsAccessible *aAccessible)
665 : {
666 0 : nsIContent* content = aAccessible->GetContent();
667 0 : return content && ((content->Tag() == nsGkAtoms::toolbarseparator) ||
668 0 : (content->Tag() == nsGkAtoms::toolbarspacer) ||
669 0 : (content->Tag() == nsGkAtoms::toolbarspring)); }
670 :
671 :
672 : ////////////////////////////////////////////////////////////////////////////////
673 : // nsXULToolbarAccessible
674 : ////////////////////////////////////////////////////////////////////////////////
675 :
676 0 : nsXULToolbarAccessible::
677 : nsXULToolbarAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
678 0 : nsAccessibleWrap(aContent, aDoc)
679 : {
680 0 : }
681 :
682 : role
683 0 : nsXULToolbarAccessible::NativeRole()
684 : {
685 0 : return roles::TOOLBAR;
686 : }
687 :
688 : nsresult
689 0 : nsXULToolbarAccessible::GetNameInternal(nsAString& aName)
690 : {
691 0 : nsAutoString name;
692 0 : if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::toolbarname, name)) {
693 0 : name.CompressWhitespace();
694 0 : aName = name;
695 : }
696 :
697 0 : return NS_OK;
698 : }
699 :
700 :
701 : ////////////////////////////////////////////////////////////////////////////////
702 : // nsXULToolbarAccessible
703 : ////////////////////////////////////////////////////////////////////////////////
704 :
705 0 : nsXULToolbarSeparatorAccessible::
706 : nsXULToolbarSeparatorAccessible(nsIContent* aContent,
707 : nsDocAccessible* aDoc) :
708 0 : nsLeafAccessible(aContent, aDoc)
709 : {
710 0 : }
711 :
712 : role
713 0 : nsXULToolbarSeparatorAccessible::NativeRole()
714 : {
715 0 : return roles::SEPARATOR;
716 : }
717 :
718 : PRUint64
719 0 : nsXULToolbarSeparatorAccessible::NativeState()
720 : {
721 0 : return 0;
722 : }
723 :
724 : ////////////////////////////////////////////////////////////////////////////////
725 : // nsXULTextFieldAccessible
726 : ////////////////////////////////////////////////////////////////////////////////
727 :
728 0 : nsXULTextFieldAccessible::
729 : nsXULTextFieldAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
730 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
731 : {
732 0 : }
733 :
734 0 : NS_IMPL_ISUPPORTS_INHERITED3(nsXULTextFieldAccessible, nsAccessible, nsHyperTextAccessible, nsIAccessibleText, nsIAccessibleEditableText)
735 :
736 : ////////////////////////////////////////////////////////////////////////////////
737 : // nsXULTextFieldAccessible: nsIAccessible
738 :
739 0 : NS_IMETHODIMP nsXULTextFieldAccessible::GetValue(nsAString& aValue)
740 : {
741 0 : if (IsDefunct())
742 0 : return NS_ERROR_FAILURE;
743 :
744 0 : PRUint64 state = NativeState();
745 :
746 0 : if (state & states::PROTECTED) // Don't return password text!
747 0 : return NS_ERROR_FAILURE;
748 :
749 0 : nsCOMPtr<nsIDOMXULTextBoxElement> textBox(do_QueryInterface(mContent));
750 0 : if (textBox) {
751 0 : return textBox->GetValue(aValue);
752 : }
753 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
754 0 : if (menuList) {
755 0 : return menuList->GetLabel(aValue);
756 : }
757 0 : return NS_ERROR_FAILURE;
758 : }
759 :
760 : void
761 0 : nsXULTextFieldAccessible::ApplyARIAState(PRUint64* aState)
762 : {
763 0 : nsHyperTextAccessibleWrap::ApplyARIAState(aState);
764 :
765 0 : nsStateMapEntry::MapToStates(mContent, aState, eARIAAutoComplete);
766 :
767 0 : }
768 :
769 : PRUint64
770 0 : nsXULTextFieldAccessible::NativeState()
771 : {
772 0 : PRUint64 state = nsHyperTextAccessibleWrap::NativeState();
773 :
774 0 : nsCOMPtr<nsIContent> inputField(GetInputField());
775 0 : NS_ENSURE_TRUE(inputField, state);
776 :
777 : // Create a temporary accessible from the HTML text field to get
778 : // the accessible state from. Doesn't add to cache into document cache.
779 : nsRefPtr<nsHTMLTextFieldAccessible> tempAccessible =
780 0 : new nsHTMLTextFieldAccessible(inputField, mDoc);
781 0 : if (!tempAccessible)
782 0 : return state;
783 :
784 0 : state |= tempAccessible->NativeState();
785 :
786 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
787 0 : if (menuList) {
788 : // <xul:menulist droppable="false">
789 0 : if (!mContent->AttrValueIs(kNameSpaceID_None,
790 : nsGkAtoms::editable,
791 0 : nsGkAtoms::_true, eIgnoreCase)) {
792 0 : state |= states::READONLY;
793 : }
794 : }
795 :
796 0 : return state;
797 : }
798 :
799 : role
800 0 : nsXULTextFieldAccessible::NativeRole()
801 : {
802 0 : if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
803 0 : nsGkAtoms::password, eIgnoreCase))
804 0 : return roles::PASSWORD_TEXT;
805 :
806 0 : return roles::ENTRY;
807 : }
808 :
809 : /**
810 : * Only one actions available
811 : */
812 : PRUint8
813 0 : nsXULTextFieldAccessible::ActionCount()
814 : {
815 0 : return 1;
816 : }
817 :
818 : /**
819 : * Return the name of our only action
820 : */
821 0 : NS_IMETHODIMP nsXULTextFieldAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
822 : {
823 0 : if (aIndex == eAction_Click) {
824 0 : aName.AssignLiteral("activate");
825 0 : return NS_OK;
826 : }
827 0 : return NS_ERROR_INVALID_ARG;
828 : }
829 :
830 : /**
831 : * Tell the button to do its action
832 : */
833 0 : NS_IMETHODIMP nsXULTextFieldAccessible::DoAction(PRUint8 index)
834 : {
835 0 : if (index == 0) {
836 0 : nsCOMPtr<nsIDOMXULElement> element(do_QueryInterface(mContent));
837 0 : if (element)
838 : {
839 0 : element->Focus();
840 0 : return NS_OK;
841 : }
842 0 : return NS_ERROR_FAILURE;
843 : }
844 0 : return NS_ERROR_INVALID_ARG;
845 : }
846 :
847 : bool
848 0 : nsXULTextFieldAccessible::CanHaveAnonChildren()
849 : {
850 0 : return false;
851 : }
852 :
853 : already_AddRefed<nsIEditor>
854 0 : nsXULTextFieldAccessible::GetEditor() const
855 : {
856 0 : nsCOMPtr<nsIContent> inputField = GetInputField();
857 0 : nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(inputField));
858 0 : if (!editableElt)
859 0 : return nsnull;
860 :
861 0 : nsCOMPtr<nsIEditor> editor;
862 0 : editableElt->GetEditor(getter_AddRefs(editor));
863 0 : return editor.forget();
864 : }
865 :
866 : ////////////////////////////////////////////////////////////////////////////////
867 : // nsXULTextFieldAccessible: nsAccessible protected
868 :
869 : void
870 0 : nsXULTextFieldAccessible::CacheChildren()
871 : {
872 0 : NS_ENSURE_TRUE(mDoc,);
873 : // Create child accessibles for native anonymous content of underlying HTML
874 : // input element.
875 0 : nsCOMPtr<nsIContent> inputContent(GetInputField());
876 0 : if (!inputContent)
877 : return;
878 :
879 0 : nsAccTreeWalker walker(mDoc, inputContent, false);
880 :
881 0 : nsAccessible* child = nsnull;
882 0 : while ((child = walker.NextChild()) && AppendChild(child));
883 : }
884 :
885 : ////////////////////////////////////////////////////////////////////////////////
886 : // nsXULTextFieldAccessible: nsHyperTextAccessible protected
887 :
888 : already_AddRefed<nsFrameSelection>
889 0 : nsXULTextFieldAccessible::FrameSelection()
890 : {
891 0 : nsCOMPtr<nsIContent> inputContent(GetInputField());
892 0 : nsIFrame* frame = inputContent->GetPrimaryFrame();
893 0 : return frame ? frame->GetFrameSelection() : nsnull;
894 : }
895 :
896 : ////////////////////////////////////////////////////////////////////////////////
897 : // nsXULTextFieldAccessible protected
898 :
899 : already_AddRefed<nsIContent>
900 0 : nsXULTextFieldAccessible::GetInputField() const
901 : {
902 0 : nsCOMPtr<nsIDOMNode> inputFieldDOMNode;
903 0 : nsCOMPtr<nsIDOMXULTextBoxElement> textBox = do_QueryInterface(mContent);
904 0 : if (textBox) {
905 0 : textBox->GetInputField(getter_AddRefs(inputFieldDOMNode));
906 :
907 : } else {
908 : // <xul:menulist droppable="false">
909 0 : nsCOMPtr<nsIDOMXULMenuListElement> menuList = do_QueryInterface(mContent);
910 0 : if (menuList)
911 0 : menuList->GetInputField(getter_AddRefs(inputFieldDOMNode));
912 : }
913 :
914 0 : NS_ASSERTION(inputFieldDOMNode, "No input field for nsXULTextFieldAccessible");
915 :
916 0 : nsIContent* inputField = nsnull;
917 0 : if (inputFieldDOMNode)
918 0 : CallQueryInterface(inputFieldDOMNode, &inputField);
919 :
920 0 : return inputField;
921 : }
|