/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ // NOTE: alphabetically ordered #include "nsAccessibilityService.h" #include "nsAccessibleEventData.h" #include "nsCaretAccessible.h" #include "nsHTMLSelectAccessible.h" #include "nsIAccessibleCaret.h" #include "nsIChromeEventHandler.h" #include "nsIDOMElement.h" #include "nsIDOMEventListener.h" #include "nsIDOMEventTarget.h" #include "nsIDOMHTMLAnchorElement.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLSelectElement.h" #include "nsIDOMNSEvent.h" #include "nsIDOMWindow.h" #include "nsIDOMXULSelectCntrlEl.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsIDocument.h" #include "nsIFrame.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIScriptGlobalObject.h" #include "nsIScrollableView.h" #include "nsIServiceManager.h" #include "nsIViewManager.h" #include "nsLayoutAtoms.h" #include "nsPIDOMWindow.h" #include "nsReadableUtils.h" #include "nsRootAccessible.h" #ifdef MOZ_XUL #include "nsXULTreeAccessible.h" #include "nsITreeSelection.h" #include "nsIXULDocument.h" #endif #include "nsAccessibilityService.h" #include "nsISelectionPrivate.h" #include "nsICaret.h" #include "nsIDOMHTMLInputElement.h" #include "nsAccessibleEventData.h" #include "nsIDOMDocument.h" #ifdef MOZ_ACCESSIBILITY_ATK #include "nsIAccessibleHyperText.h" #endif NS_INTERFACE_MAP_BEGIN(nsRootAccessible) NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener) NS_INTERFACE_MAP_ENTRY(nsIDOMFormListener) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFormListener) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMFormListener) NS_INTERFACE_MAP_END_INHERITING(nsDocAccessible) NS_IMPL_ADDREF_INHERITED(nsRootAccessible, nsDocAccessible) NS_IMPL_RELEASE_INHERITED(nsRootAccessible, nsDocAccessible) //----------------------------------------------------- // construction //----------------------------------------------------- nsRootAccessible::nsRootAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell): nsDocAccessibleWrap(aDOMNode, aShell), mAccService(do_GetService("@mozilla.org/accessibilityService;1")) { } //----------------------------------------------------- // destruction //----------------------------------------------------- nsRootAccessible::~nsRootAccessible() { } // helpers /* readonly attribute nsIAccessible accParent; */ NS_IMETHODIMP nsRootAccessible::GetParent(nsIAccessible * *aParent) { *aParent = nsnull; return NS_OK; } /* readonly attribute unsigned long accRole; */ NS_IMETHODIMP nsRootAccessible::GetRole(PRUint32 *aRole) { if (!mDocument) { return NS_ERROR_FAILURE; } *aRole = ROLE_PANE; // If it's a , use ROLE_DIALOG instead nsIContent *rootContent = mDocument->GetRootContent(); if (rootContent) { nsCOMPtr rootElement(do_QueryInterface(rootContent)); if (rootElement) { nsAutoString name; rootElement->GetLocalName(name); if (name.Equals(NS_LITERAL_STRING("dialog"))) *aRole = ROLE_DIALOG; } } return NS_OK; } void nsRootAccessible::GetChromeEventHandler(nsIDOMEventTarget **aChromeTarget) { nsCOMPtr domWin; GetWindow(getter_AddRefs(domWin)); nsCOMPtr privateDOMWindow(do_QueryInterface(domWin)); nsCOMPtr chromeEventHandler; if (privateDOMWindow) { privateDOMWindow->GetChromeEventHandler(getter_AddRefs(chromeEventHandler)); } nsCOMPtr target(do_QueryInterface(chromeEventHandler)); *aChromeTarget = target; NS_IF_ADDREF(*aChromeTarget); } nsresult nsRootAccessible::AddEventListeners() { // use AddEventListener from the nsIDOMEventTarget interface nsCOMPtr target(do_QueryInterface(mDocument)); if (target) { // capture DOM focus events nsresult rv = target->AddEventListener(NS_LITERAL_STRING("focus"), NS_STATIC_CAST(nsIDOMFocusListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); // capture Form change events rv = target->AddEventListener(NS_LITERAL_STRING("select"), NS_STATIC_CAST(nsIDOMFormListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); // add ourself as a CheckboxStateChange listener (custom event fired in nsHTMLInputElement.cpp) rv = target->AddEventListener(NS_LITERAL_STRING("CheckboxStateChange"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); // add ourself as a RadioStateChange Listener ( custom event fired in in nsHTMLInputElement.cpp & radio.xml) rv = target->AddEventListener(NS_LITERAL_STRING("RadioStateChange"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); rv = target->AddEventListener(NS_LITERAL_STRING("popupshowing"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); rv = target->AddEventListener(NS_LITERAL_STRING("popuphiding"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); rv = target->AddEventListener(NS_LITERAL_STRING("DOMMenuItemActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); rv = target->AddEventListener(NS_LITERAL_STRING("DOMMenuBarActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); rv = target->AddEventListener(NS_LITERAL_STRING("DOMMenuBarInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener"); } GetChromeEventHandler(getter_AddRefs(target)); NS_ASSERTION(target, "No chrome event handler for document"); if (target) { // onunload doesn't fire unless we use chrome event handler for target target->AddEventListener(NS_LITERAL_STRING("unload"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); } if (!mCaretAccessible) mCaretAccessible = new nsCaretAccessible(mDOMNode, mWeakShell, this); return nsDocAccessible::AddEventListeners(); } nsresult nsRootAccessible::RemoveEventListeners() { nsCOMPtr target(do_QueryInterface(mDocument)); if (target) { target->RemoveEventListener(NS_LITERAL_STRING("focus"), NS_STATIC_CAST(nsIDOMFocusListener*, this), PR_TRUE); target->RemoveEventListener(NS_LITERAL_STRING("select"), NS_STATIC_CAST(nsIDOMFormListener*, this), PR_TRUE); target->RemoveEventListener(NS_LITERAL_STRING("CheckboxStateChange"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); target->RemoveEventListener(NS_LITERAL_STRING("RadioStateChange"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); target->RemoveEventListener(NS_LITERAL_STRING("popupshowing"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); target->RemoveEventListener(NS_LITERAL_STRING("popuphiding"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuItemActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuBarActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuBarInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); } GetChromeEventHandler(getter_AddRefs(target)); if (target) { target->RemoveEventListener(NS_LITERAL_STRING("unload"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE); } if (mCaretAccessible) { mCaretAccessible->RemoveSelectionListener(); mCaretAccessible = nsnull; } mAccService = nsnull; return nsDocAccessible::RemoveEventListeners(); } NS_IMETHODIMP nsRootAccessible::GetCaretAccessible(nsIAccessible **aCaretAccessible) { *aCaretAccessible = nsnull; if (mCaretAccessible) { CallQueryInterface(mCaretAccessible, aCaretAccessible); } return NS_OK; } void nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *focusAccessible, nsIDOMNode *focusNode) { if (focusAccessible && focusNode && gLastFocusedNode != focusNode) { nsCOMPtr privateFocusAcc(do_QueryInterface(focusAccessible)); privateFocusAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_FOCUS, focusAccessible, nsnull); NS_IF_RELEASE(gLastFocusedNode); PRUint32 role = ROLE_NOTHING; focusAccessible->GetRole(&role); if (role != ROLE_MENUITEM && role != ROLE_LISTITEM) { // It must report all focus events on menu and list items gLastFocusedNode = focusNode; NS_ADDREF(gLastFocusedNode); } if (mCaretAccessible) mCaretAccessible->AttachNewSelectionListener(focusNode); } } void nsRootAccessible::GetEventShell(nsIDOMNode *aNode, nsIPresShell **aEventShell) { // XXX aaronl - this is not ideal. // We could avoid this whole section and the fallible // doc->GetShellAt(0) by putting the event handler // on nsDocAccessible instead. // The disadvantage would be that we would be seeing some events // for inner documents that we don't care about. nsCOMPtr domDocument; aNode->GetOwnerDocument(getter_AddRefs(domDocument)); nsCOMPtr doc(do_QueryInterface(domDocument)); if (!doc) { // This is necessary when the node is the document node doc = do_QueryInterface(aNode); } if (doc) { *aEventShell = doc->GetShellAt(0); NS_IF_ADDREF(*aEventShell); } } // --------------- nsIDOMEventListener Methods (3) ------------------------ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent) { // optionTargetNode is set to current option for HTML selects nsCOMPtr targetNode, optionTargetNode; GetTargetNode(aEvent, getter_AddRefs(targetNode)); if (!targetNode) return NS_ERROR_FAILURE; // Check to see if it's a select element. If so, need the currently focused option nsCOMPtr selectElement(do_QueryInterface(targetNode)); if (selectElement) // ----- Target Node is an HTML