diff --git a/rdf/content/src/nsDlgDefaultKeys.cpp b/rdf/content/src/nsDlgDefaultKeys.cpp new file mode 100644 index 000000000000..c65fdf0cdf89 --- /dev/null +++ b/rdf/content/src/nsDlgDefaultKeys.cpp @@ -0,0 +1,389 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsCOMPtr.h" +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIDOMElement.h" +#include "nsIDOMFocusListener.h" +#include "nsIDOMKeyListener.h" +#include "nsIDOMMouseListener.h" +#include "nsIDOMUIEvent.h" +#include "nsIDOMWindow.h" +#include "nsIDOMXULDocument.h" +#include "nsINSEvent.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIScriptContextOwner.h" +#include "nsIScriptGlobalObject.h" +#include "nsIDlgDefaultKeys.h" +#include "nsRDFCID.h" + +//////////////////////////////////////////////////////////////////////// + +static NS_DEFINE_IID(kDlgDefaultKeysCID, NS_DLGDEFAULTKEYS_CID); +static NS_DEFINE_IID(kIDlgDefaultKeysIID, NS_IDLGDEFAULTKEYS_IID); +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + +static NS_DEFINE_IID(kIDomNodeIID, NS_IDOMNODE_IID); +static NS_DEFINE_IID(kIDomElementIID, NS_IDOMELEMENT_IID); +static NS_DEFINE_IID(kIDomEventListenerIID, NS_IDOMEVENTLISTENER_IID); +static NS_DEFINE_IID(kIDomUIEventIID, NS_IDOMUIEVENT_IID); + +enum eEventType { + eKeyPress, + eKeyDown, + eKeyUp +}; + +// DialogDefaultKeysImpl +// +// This is the key listener implementation for default keys in dialogs +// +class nsDlgDefaultKeysImpl : public nsIDlgDefaultKeys, + public nsIDOMKeyListener +{ +public: + nsDlgDefaultKeysImpl(void); + virtual ~nsDlgDefaultKeysImpl(void); + +public: + // nsISupports + NS_DECL_ISUPPORTS + + // nsIDlgDefaultKeys + NS_IMETHOD Init( + nsIDOMElement * aElement, + nsIDOMDocument * aDocument); + + // The KeyDown event is what handles the + virtual nsresult KeyDown(nsIDOMEvent* aKeyEvent); + + // We don't really care about these events but since we look like a listener we handle 'em + virtual nsresult KeyUp(nsIDOMEvent* aKeyEvent); + virtual nsresult KeyPress(nsIDOMEvent* aKeyEvent); + + // nsIDOMEventListener + virtual nsresult HandleEvent(nsIDOMEvent* anEvent) { return NS_OK; }; + +protected: + +private: + nsresult DoKey(nsIDOMEvent* aKeyEvent, eEventType aEventType); + + nsIDOMElement* element; // Weak reference. The element will go away first. + nsIDOMDocument* mDOMDocument; // Weak reference. +}; + +//////////////////////////////////////////////////////////////////////// + +nsDlgDefaultKeysImpl::nsDlgDefaultKeysImpl(void) +{ + NS_INIT_REFCNT(); + +} + +nsDlgDefaultKeysImpl::~nsDlgDefaultKeysImpl(void) +{ +} + +NS_IMPL_ADDREF(nsDlgDefaultKeysImpl) +NS_IMPL_RELEASE(nsDlgDefaultKeysImpl) + +NS_IMETHODIMP +nsDlgDefaultKeysImpl::QueryInterface(REFNSIID iid, void** result) +{ + if (! result) + return NS_ERROR_NULL_POINTER; + + *result = nsnull; + if (iid.Equals(nsIDlgDefaultKeys::GetIID()) || + iid.Equals(kISupportsIID)) { + *result = NS_STATIC_CAST(nsIDlgDefaultKeys*, this); + NS_ADDREF_THIS(); + return NS_OK; + } + else if (iid.Equals(nsIDOMKeyListener::GetIID())) { + *result = NS_STATIC_CAST(nsIDOMKeyListener*, this); + NS_ADDREF_THIS(); + return NS_OK; + } + else if (iid.Equals(kIDomEventListenerIID)) { + *result = (nsIDOMEventListener*)(nsIDOMMouseListener*)this; + NS_ADDREF_THIS(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + +NS_IMETHODIMP +nsDlgDefaultKeysImpl::Init( + nsIDOMElement * aElement, + nsIDOMDocument * aDocument) +{ + element = aElement; // Weak reference. Don't addref it. + mDOMDocument = aDocument; // Weak reference. + return NS_OK; +} + +//////////////////////////////////////////////////////////////// +// nsIDOMKeyListener + +/** + * Processes a key down event to see if it is a default key for ok + * or cancel for the dialog + * @param aKeyEvent @see nsIDOMEvent.h + * @returns whether the event was consumed or ignored. @see nsresult + */ +nsresult nsDlgDefaultKeysImpl::KeyDown(nsIDOMEvent* aKeyEvent) +{ + return DoKey(aKeyEvent, eKeyDown); +} + +//////////////////////////////////////////////////////////////// +/** + * Stub for a key release event + */ +nsresult nsDlgDefaultKeysImpl::KeyUp(nsIDOMEvent* aKeyEvent) +{ + return NS_OK; +} + +//////////////////////////////////////////////////////////////// +/** + * Stub for a key typed event + */ +nsresult nsDlgDefaultKeysImpl::KeyPress(nsIDOMEvent* aKeyEvent) +{ + return NS_OK; +} + +//////////////////////////////////////////////////////////////// +/** + * Here's where the actual work happens + */ +nsresult nsDlgDefaultKeysImpl::DoKey(nsIDOMEvent* aKeyEvent, eEventType aEventType) +{ + static PRBool inDlgDefaultKey = PR_FALSE; + + if(inDlgDefaultKey) + return NS_OK; + else + inDlgDefaultKey = PR_TRUE; + + if(aKeyEvent && mDOMDocument) + { + // Get DOMEvent target + nsIDOMNode* target = nsnull; + aKeyEvent->GetTarget(&target); + + nsIDOMUIEvent * theEvent; + aKeyEvent->QueryInterface(kIDomUIEventIID, (void**)&theEvent); + + // locate the window element which holds the top level key bindings + nsCOMPtr rootElement; + mDOMDocument->GetDocumentElement(getter_AddRefs(rootElement)); + if (!rootElement) { + inDlgDefaultKey = PR_FALSE; + return !NS_OK; + } + nsString rootName; + rootElement->GetNodeName(rootName); + + nsCOMPtr rootNode(do_QueryInterface(rootElement)); + + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr keysetNode; + rootNode->GetFirstChild(getter_AddRefs(keysetNode)); + while (keysetNode) + { + nsString keysetNodeType; + nsCOMPtr keysetElement(do_QueryInterface(keysetNode)); + if(!keysetElement) + { + inDlgDefaultKey = PR_FALSE; + return rv; + } + + keysetElement->GetNodeName(keysetNodeType); + if (keysetNodeType.Equals("keyset")) + { + // Given the DOM node and Key Event + // Walk the node's children looking for 'key' types + + // If the node isn't tagged disabled + // Compares the received key code to found 'key' types + // Executes command if found + // Marks event as consumed + nsCOMPtr keyNode; + keysetNode->GetFirstChild(getter_AddRefs(keyNode)); + while (keyNode) + { + nsCOMPtr keyElement(do_QueryInterface(keyNode)); + if (keyElement) + { + nsString keyNodeType; + nsString keyName; + nsString disabled; + nsString cmdToExecute; + keyElement->GetNodeName(keyNodeType); + + if (keyNodeType.Equals("key")) + { + keyElement->GetAttribute(nsAutoString("key"), keyName); + + keyElement->GetAttribute(nsAutoString("disabled"), disabled); + if (disabled == "false") + { + PRUint32 theChar; + + switch(aEventType) + { + case eKeyPress: + theEvent->GetCharCode(&theChar); + break; + case eKeyUp: + case eKeyDown: + theEvent->GetKeyCode(&theChar); + break; + } + + char tempChar[2]; + tempChar[0] = theChar; + tempChar[1] = 0; + nsString tempChar2 = tempChar; + //printf("compare key [%s] \n", tempChar2.ToNewCString()); // this leaks + // NOTE - convert theChar and keyName to upper + keyName.ToUpperCase(); + tempChar2.ToUpperCase(); + if (tempChar2 == keyName) + { + switch(aEventType) + { + case eKeyPress: + keyElement->GetAttribute(nsAutoString("oncommand"), cmdToExecute); + break; + case eKeyDown: + keyElement->GetAttribute(nsAutoString("onkeydown"), cmdToExecute); + break; + case eKeyUp: + keyElement->GetAttribute(nsAutoString("onkeyup"), cmdToExecute); + break; + } + + + //printf("onkeypress [%s] \n", cmdToExecute.ToNewCString()); // this leaks + do + { + + // Modifier tests passed so execute onclick command + + + // This code executes in every presentation context in which this + // document is appearing. + nsCOMPtr content; + content = do_QueryInterface(keyElement); + if (!content) + { + inDlgDefaultKey = PR_FALSE; + return NS_OK; + } + + nsCOMPtr document; + content->GetDocument(*getter_AddRefs(document)); + + if (!document) + { + inDlgDefaultKey = PR_FALSE; + return NS_OK; + } + + PRInt32 count = document->GetNumberOfShells(); + for (PRInt32 i = 0; i < count; i++) + { + nsIPresShell* shell = document->GetShellAt(i); + if (nsnull == shell) + continue; + + // Retrieve the context in which our DOM event will fire. + nsCOMPtr aPresContext; + shell->GetPresContext(getter_AddRefs(aPresContext)); + + NS_RELEASE(shell); + + // Handle the DOM event + nsEventStatus status = nsEventStatus_eIgnore; + nsKeyEvent event; + event.eventStructType = NS_KEY_EVENT; + switch (aEventType) + { + case eKeyPress: event.message = NS_KEY_PRESS; break; + case eKeyDown: event.message = NS_KEY_DOWN; break; + default: event.message = NS_KEY_UP; break; + } + aKeyEvent->PreventBubble(); + aKeyEvent->PreventCapture(); + content->HandleDOMEvent(*aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); + + if (aEventType == eKeyPress) + { + // Also execute the oncommand handler on a key press. + // Execute the oncommand event handler. + nsEventStatus stat = nsEventStatus_eIgnore; + nsMouseEvent evt; + evt.eventStructType = NS_EVENT; + evt.message = NS_MENU_ACTION; + content->HandleDOMEvent(*aPresContext, &evt, nsnull, NS_EVENT_FLAG_INIT, stat); + } + } + } while (PR_FALSE); + } // end if (theChar == keyName) + } // end if (disabled == "false") + } // end if (keyNodeType.Equals("key")) + } // end if(keyelement) + + nsCOMPtr oldkeyNode(keyNode); + oldkeyNode->GetNextSibling(getter_AddRefs(keyNode)); + + } // end while(keynode) + } // end if (keysetNodeType.Equals("keyset")) { + + nsCOMPtr oldkeysetNode(keysetNode); + oldkeysetNode->GetNextSibling(getter_AddRefs(keysetNode)); + + } // end while(keysetNode) + } // end if(aKeyEvent && mDOMDocument) + + inDlgDefaultKey = PR_FALSE; + return NS_ERROR_BASE; +} + +//////////////////////////////////////////////////////////////// +nsresult +NS_NewDlgDefaultKeys(nsIDlgDefaultKeys** aHandler) +{ + nsDlgDefaultKeysImpl * handler = new nsDlgDefaultKeysImpl(); + if (!handler) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(handler); + *aHandler = handler; + return NS_OK; +} diff --git a/rdf/content/src/nsDlgDefaultKeys.h b/rdf/content/src/nsDlgDefaultKeys.h new file mode 100644 index 000000000000..22cd69678b7e --- /dev/null +++ b/rdf/content/src/nsDlgDefaultKeys.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsIDlgDefaultKeys_h__ +#define nsIDlgDefaultKeys_h__ + +// {daedcb42-1dd1-11b2-b1d2-caf06cb40387} +#define NS_IDLGDEFAULTKEYS_IID \ +{ 0xdaedcb42, 0x1dd1, 0x11b2, { 0xb1, 0xd2, 0xca, 0xf0, 0x6c, 0xb4, 0x3, 0x87 } } + +class nsIDOMElement; + +class nsIDlgDefaultKeys: public nsISupports { +public: + static const nsIID& GetIID() { static nsIID iid = NS_IDLGDEFAULTKEYS_IID; return iid; } + + NS_IMETHOD Init(nsIDOMElement* anElement, nsIDOMDocument* aDocument) = 0; +}; + +extern nsresult +NS_NewDlgDefaultKeys(nsIDlgDefaultKeys** result); + +#endif // nsIDlgDefaultKeys_h__