1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
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
15
* The Original Code is mozilla.org code.
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.
23
* Original Author: David W. Hyatt (hyatt@netscape.com)
26
* Alternatively, the contents of this file may be used under the terms of
27
* either the GNU General Public License Version 2 or later (the "GPL"), or
28
* 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 NPL, 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 NPL, the GPL or the LGPL.
38
* ***** END LICENSE BLOCK ***** */
42
This file provides the implementation for the XUL Command Dispatcher.
46
#include "nsIContent.h"
47
#include "nsIFocusController.h"
48
#include "nsIControllers.h"
49
#include "nsIDOMDocument.h"
50
#include "nsIDOMXULDocument.h"
51
#include "nsIDOMHTMLDocument.h"
52
#include "nsIDOMElement.h"
53
#include "nsIDOMNSHTMLInputElement.h"
54
#include "nsIDOMNSHTMLTextAreaElement.h"
55
#include "nsIDOMUIEvent.h"
56
#include "nsIDOMWindowInternal.h"
57
#include "nsIDOMXULElement.h"
58
#include "nsIDocument.h"
59
#include "nsIPresContext.h"
60
#include "nsIPresShell.h"
61
#include "nsIScriptGlobalObject.h"
62
#include "nsPIDOMWindow.h"
64
#include "nsXULCommandDispatcher.h"
66
#include "nsIDOMEventTarget.h"
67
#include "nsGUIEvent.h"
68
#include "nsContentUtils.h"
69
#include "nsReadableUtils.h"
71
#include "nsDOMError.h"
74
static PRLogModuleInfo* gLog;
77
////////////////////////////////////////////////////////////////////////
79
nsXULCommandDispatcher::nsXULCommandDispatcher(nsIDocument* aDocument)
80
: mFocusController(nsnull), mDocument(aDocument), mUpdaters(nsnull)
85
gLog = PR_NewLogModule("nsXULCommandDispatcher");
89
nsXULCommandDispatcher::~nsXULCommandDispatcher()
92
Updater* doomed = mUpdaters;
93
mUpdaters = mUpdaters->mNext;
98
// QueryInterface implementation for nsXULCommandDispatcher
99
NS_INTERFACE_MAP_BEGIN(nsXULCommandDispatcher)
100
NS_INTERFACE_MAP_ENTRY(nsIDOMXULCommandDispatcher)
101
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
102
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMXULCommandDispatcher)
103
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XULCommandDispatcher)
107
NS_IMPL_ADDREF(nsXULCommandDispatcher)
108
NS_IMPL_RELEASE(nsXULCommandDispatcher)
112
nsXULCommandDispatcher::Create(nsIDocument* aDoc, nsIDOMXULCommandDispatcher** aResult)
114
nsXULCommandDispatcher* dispatcher = new nsXULCommandDispatcher(aDoc);
116
return NS_ERROR_OUT_OF_MEMORY;
118
*aResult = dispatcher;
124
nsXULCommandDispatcher::EnsureFocusController()
126
if (!mFocusController) {
127
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mDocument->GetScriptGlobalObject()));
129
// An inelegant way to retrieve this to be sure, but we are
130
// guaranteed that the focus controller outlives us, so it
131
// is safe to hold on to it (since we can't die until it has
133
nsCOMPtr<nsIFocusController> focus;
134
win->GetRootFocusController(getter_AddRefs(focus));
135
mFocusController = focus; // Store as a weak ptr.
139
////////////////////////////////////////////////////////////////
140
// nsIDOMXULTracker Interface
143
nsXULCommandDispatcher::GetFocusedElement(nsIDOMElement** aElement)
145
EnsureFocusController();
146
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
148
return mFocusController->GetFocusedElement(aElement);
152
nsXULCommandDispatcher::GetFocusedWindow(nsIDOMWindow** aWindow)
154
EnsureFocusController();
155
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
157
nsCOMPtr<nsIDOMWindowInternal> window;
158
nsresult rv = mFocusController->GetFocusedWindow(getter_AddRefs(window));
159
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && window, rv);
161
return CallQueryInterface(window, aWindow);
165
nsXULCommandDispatcher::SetFocusedElement(nsIDOMElement* aElement)
167
EnsureFocusController();
168
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
170
return mFocusController->SetFocusedElement(aElement);
174
nsXULCommandDispatcher::SetFocusedWindow(nsIDOMWindow* aWindow)
176
EnsureFocusController();
177
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
179
nsCOMPtr<nsIDOMWindowInternal> window(do_QueryInterface(aWindow));
181
return mFocusController->SetFocusedWindow(window);
185
nsXULCommandDispatcher::AdvanceFocus()
187
EnsureFocusController();
188
if (mFocusController)
189
return mFocusController->MoveFocus(PR_TRUE, nsnull);
194
nsXULCommandDispatcher::RewindFocus()
196
EnsureFocusController();
197
if (mFocusController)
198
return mFocusController->MoveFocus(PR_FALSE, nsnull);
203
nsXULCommandDispatcher::AdvanceFocusIntoSubtree(nsIDOMElement* aElt)
205
EnsureFocusController();
206
if (mFocusController)
207
return mFocusController->MoveFocus(PR_TRUE, aElt);
212
nsXULCommandDispatcher::AddCommandUpdater(nsIDOMElement* aElement,
213
const nsAString& aEvents,
214
const nsAString& aTargets)
216
NS_PRECONDITION(aElement != nsnull, "null ptr");
218
return NS_ERROR_NULL_POINTER;
220
nsCOMPtr<nsIDOMNode> doc(do_QueryInterface(mDocument));
222
nsresult rv = nsContentUtils::CheckSameOrigin(doc, aElement);
228
Updater* updater = mUpdaters;
229
Updater** link = &mUpdaters;
232
if (updater->mElement == aElement) {
235
nsCAutoString eventsC, targetsC, aeventsC, atargetsC;
236
eventsC.AssignWithConversion(updater->mEvents);
237
targetsC.AssignWithConversion(updater->mTargets);
238
CopyUTF16toUTF8(aEvents, aeventsC);
239
CopyUTF16toUTF8(aTargets, atargetsC);
240
PR_LOG(gLog, PR_LOG_ALWAYS,
241
("xulcmd[%p] replace %p(events=%s targets=%s) with (events=%s targets=%s)",
249
// If the updater was already in the list, then replace
250
// (?) the 'events' and 'targets' filters with the new
252
updater->mEvents = aEvents;
253
updater->mTargets = aTargets;
257
link = &(updater->mNext);
258
updater = updater->mNext;
261
nsCAutoString aeventsC, atargetsC;
262
CopyUTF16toUTF8(aEvents, aeventsC);
263
CopyUTF16toUTF8(aTargets, atargetsC);
265
PR_LOG(gLog, PR_LOG_ALWAYS,
266
("xulcmd[%p] add %p(events=%s targets=%s)",
272
// If we get here, this is a new updater. Append it to the list.
273
updater = new Updater(aElement, aEvents, aTargets);
275
return NS_ERROR_OUT_OF_MEMORY;
282
nsXULCommandDispatcher::RemoveCommandUpdater(nsIDOMElement* aElement)
284
NS_PRECONDITION(aElement != nsnull, "null ptr");
286
return NS_ERROR_NULL_POINTER;
288
Updater* updater = mUpdaters;
289
Updater** link = &mUpdaters;
292
if (updater->mElement == aElement) {
294
nsCAutoString eventsC, targetsC;
295
eventsC.AssignWithConversion(updater->mEvents);
296
targetsC.AssignWithConversion(updater->mTargets);
297
PR_LOG(gLog, PR_LOG_ALWAYS,
298
("xulcmd[%p] remove %p(events=%s targets=%s)",
304
*link = updater->mNext;
309
link = &(updater->mNext);
310
updater = updater->mNext;
313
// Hmm. Not found. Oh well.
318
nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName)
322
EnsureFocusController();
323
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
326
nsCOMPtr<nsIDOMElement> element;
327
mFocusController->GetFocusedElement(getter_AddRefs(element));
329
rv = element->GetAttribute(NS_LITERAL_STRING("id"), id);
330
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get element's id");
331
if (NS_FAILED(rv)) return rv;
336
char* actionString = ToNewCString(aEventName);
337
printf("Doing UpdateCommands(\"%s\")\n", actionString);
342
for (Updater* updater = mUpdaters; updater != nsnull; updater = updater->mNext) {
343
// Skip any nodes that don't match our 'events' or 'targets'
345
if (! Matches(updater->mEvents, aEventName))
348
if (! Matches(updater->mTargets, id))
351
nsCOMPtr<nsIContent> content = do_QueryInterface(updater->mElement);
352
NS_ASSERTION(content != nsnull, "not an nsIContent");
354
return NS_ERROR_UNEXPECTED;
356
nsCOMPtr<nsIDocument> document = content->GetDocument();
358
NS_ASSERTION(document != nsnull, "element has no document");
363
nsCAutoString aeventnameC;
364
CopyUTF16toUTF8(aEventName, aeventnameC);
365
PR_LOG(gLog, PR_LOG_ALWAYS,
366
("xulcmd[%p] update %p event=%s",
367
this, updater->mElement,
371
PRUint32 count = document->GetNumberOfShells();
372
for (PRUint32 i = 0; i < count; i++) {
373
nsIPresShell *shell = document->GetShellAt(i);
375
// Retrieve the context in which our DOM event will fire.
376
nsCOMPtr<nsIPresContext> context;
377
rv = shell->GetPresContext(getter_AddRefs(context));
378
if (NS_FAILED(rv)) return rv;
380
// Handle the DOM event
381
nsEventStatus status = nsEventStatus_eIgnore;
382
nsEvent event(NS_XUL_COMMAND_UPDATE);
383
content->HandleDOMEvent(context, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
390
nsXULCommandDispatcher::Matches(const nsString& aList,
391
const nsAString& aElement)
393
if (aList.Equals(NS_LITERAL_STRING("*")))
394
return PR_TRUE; // match _everything_!
396
PRInt32 indx = aList.Find(PromiseFlatString(aElement));
398
return PR_FALSE; // not in the list at all
400
// okay, now make sure it's not a substring snafu; e.g., 'ur'
401
// found inside of 'blur'.
403
PRUnichar ch = aList[indx - 1];
404
if (! nsCRT::IsAsciiSpace(ch) && ch != PRUnichar(','))
408
if (indx + aElement.Length() < aList.Length()) {
409
PRUnichar ch = aList[indx + aElement.Length()];
410
if (! nsCRT::IsAsciiSpace(ch) && ch != PRUnichar(','))
418
nsXULCommandDispatcher::GetControllers(nsIControllers** aResult)
420
EnsureFocusController();
421
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
423
return mFocusController->GetControllers(aResult);
427
nsXULCommandDispatcher::GetControllerForCommand(const char *aCommand, nsIController** _retval)
429
EnsureFocusController();
430
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
432
return mFocusController->GetControllerForCommand(aCommand, _retval);
436
nsXULCommandDispatcher::GetSuppressFocusScroll(PRBool* aSuppressFocusScroll)
438
EnsureFocusController();
439
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
441
return mFocusController->GetSuppressFocusScroll(aSuppressFocusScroll);
445
nsXULCommandDispatcher::SetSuppressFocusScroll(PRBool aSuppressFocusScroll)
447
EnsureFocusController();
448
NS_ENSURE_TRUE(mFocusController, NS_ERROR_FAILURE);
450
return mFocusController->SetSuppressFocusScroll(aSuppressFocusScroll);