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 : * Kathleen Brade <brade@netscape.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsString.h"
40 :
41 : #include "nsIController.h"
42 : #include "nsIControllers.h"
43 : #include "nsIObserver.h"
44 :
45 : #include "nsIComponentManager.h"
46 :
47 : #include "nsServiceManagerUtils.h"
48 : #include "nsIScriptSecurityManager.h"
49 :
50 : #include "nsIDOMDocument.h"
51 : #include "nsIDOMWindow.h"
52 : #include "nsPIDOMWindow.h"
53 : #include "nsPIWindowRoot.h"
54 : #include "nsIFocusManager.h"
55 : #include "nsIDOMEventTarget.h"
56 :
57 : #include "nsCOMArray.h"
58 :
59 : #include "nsCommandManager.h"
60 :
61 :
62 0 : nsCommandManager::nsCommandManager()
63 0 : : mWindow(nsnull)
64 : {
65 : /* member initializers and constructor code */
66 0 : }
67 :
68 0 : nsCommandManager::~nsCommandManager()
69 : {
70 : /* destructor code */
71 0 : }
72 :
73 :
74 : static PLDHashOperator
75 0 : TraverseCommandObservers(const char* aKey, nsCOMArray<nsIObserver>* aObservers,
76 : void* aClosure)
77 : {
78 : nsCycleCollectionTraversalCallback *cb =
79 0 : static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
80 :
81 0 : PRInt32 i, numItems = aObservers->Count();
82 0 : for (i = 0; i < numItems; ++i) {
83 0 : cb->NoteXPCOMChild(aObservers->ObjectAt(i));
84 : }
85 :
86 0 : return PL_DHASH_NEXT;
87 : }
88 :
89 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager)
90 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager)
91 0 : tmp->mObserversTable.Clear();
92 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
93 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager)
94 0 : tmp->mObserversTable.EnumerateRead(TraverseCommandObservers, &cb);
95 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
96 :
97 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager)
98 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager)
99 :
100 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager)
101 0 : NS_INTERFACE_MAP_ENTRY(nsICommandManager)
102 0 : NS_INTERFACE_MAP_ENTRY(nsPICommandUpdater)
103 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
104 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandManager)
105 0 : NS_INTERFACE_MAP_END
106 :
107 : #if 0
108 : #pragma mark -
109 : #endif
110 :
111 : /* void init (in nsIDOMWindow aWindow); */
112 : NS_IMETHODIMP
113 0 : nsCommandManager::Init(nsIDOMWindow *aWindow)
114 : {
115 0 : NS_ENSURE_ARG_POINTER(aWindow);
116 :
117 0 : NS_ASSERTION(aWindow, "Need non-null window here");
118 0 : mWindow = aWindow; // weak ptr
119 0 : NS_ENSURE_TRUE(mObserversTable.Init(), NS_ERROR_OUT_OF_MEMORY);
120 0 : return NS_OK;
121 : }
122 :
123 : /* void commandStatusChanged (in DOMString aCommandName, in long aChangeFlags); */
124 : NS_IMETHODIMP
125 0 : nsCommandManager::CommandStatusChanged(const char * aCommandName)
126 : {
127 : nsCOMArray<nsIObserver>* commandObservers;
128 0 : mObserversTable.Get(aCommandName, &commandObservers);
129 :
130 0 : if (commandObservers)
131 : {
132 : // XXX Should we worry about observers removing themselves from Observe()?
133 0 : PRInt32 i, numItems = commandObservers->Count();
134 0 : for (i = 0; i < numItems; ++i)
135 : {
136 0 : nsCOMPtr<nsIObserver> observer = commandObservers->ObjectAt(i);
137 : // should we get the command state to pass here? This might be expensive.
138 0 : observer->Observe(NS_ISUPPORTS_CAST(nsICommandManager*, this),
139 : aCommandName,
140 0 : NS_LITERAL_STRING("command_status_changed").get());
141 : }
142 : }
143 :
144 0 : return NS_OK;
145 : }
146 :
147 : #if 0
148 : #pragma mark -
149 : #endif
150 :
151 : /* void addCommandObserver (in nsIObserver aCommandObserver, in wstring aCommandToObserve); */
152 : NS_IMETHODIMP
153 0 : nsCommandManager::AddCommandObserver(nsIObserver *aCommandObserver, const char *aCommandToObserve)
154 : {
155 0 : NS_ENSURE_ARG(aCommandObserver);
156 :
157 0 : nsresult rv = NS_OK;
158 :
159 : // XXX todo: handle special cases of aCommandToObserve being null, or empty
160 :
161 : // for each command in the table, we make a list of observers for that command
162 : nsCOMArray<nsIObserver>* commandObservers;
163 0 : if (!mObserversTable.Get(aCommandToObserve, &commandObservers))
164 : {
165 0 : nsAutoPtr<nsCOMArray<nsIObserver> > array(new nsCOMArray<nsIObserver>);
166 0 : if (!array || !mObserversTable.Put(aCommandToObserve, array))
167 0 : return NS_ERROR_OUT_OF_MEMORY;
168 :
169 0 : commandObservers = array.forget();
170 : }
171 :
172 : // need to check that this command observer hasn't already been registered
173 0 : PRInt32 existingIndex = commandObservers->IndexOf(aCommandObserver);
174 0 : if (existingIndex == -1)
175 0 : rv = commandObservers->AppendObject(aCommandObserver);
176 : else
177 0 : NS_WARNING("Registering command observer twice on the same command");
178 :
179 0 : return rv;
180 : }
181 :
182 : /* void removeCommandObserver (in nsIObserver aCommandObserver, in wstring aCommandObserved); */
183 : NS_IMETHODIMP
184 0 : nsCommandManager::RemoveCommandObserver(nsIObserver *aCommandObserver, const char *aCommandObserved)
185 : {
186 0 : NS_ENSURE_ARG(aCommandObserver);
187 :
188 : // XXX todo: handle special cases of aCommandToObserve being null, or empty
189 :
190 : nsCOMArray<nsIObserver>* commandObservers;
191 0 : if (!mObserversTable.Get(aCommandObserved, &commandObservers))
192 0 : return NS_ERROR_UNEXPECTED;
193 :
194 0 : return commandObservers->RemoveObject(aCommandObserver) ? NS_OK :
195 0 : NS_ERROR_FAILURE;
196 : }
197 :
198 : /* boolean isCommandSupported(in string aCommandName,
199 : in nsIDOMWindow aTargetWindow); */
200 : NS_IMETHODIMP
201 0 : nsCommandManager::IsCommandSupported(const char *aCommandName,
202 : nsIDOMWindow *aTargetWindow,
203 : bool *outCommandSupported)
204 : {
205 0 : NS_ENSURE_ARG_POINTER(outCommandSupported);
206 :
207 0 : nsCOMPtr<nsIController> controller;
208 0 : GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller));
209 0 : *outCommandSupported = (controller.get() != nsnull);
210 0 : return NS_OK;
211 : }
212 :
213 : /* boolean isCommandEnabled(in string aCommandName,
214 : in nsIDOMWindow aTargetWindow); */
215 : NS_IMETHODIMP
216 0 : nsCommandManager::IsCommandEnabled(const char *aCommandName,
217 : nsIDOMWindow *aTargetWindow,
218 : bool *outCommandEnabled)
219 : {
220 0 : NS_ENSURE_ARG_POINTER(outCommandEnabled);
221 :
222 0 : bool commandEnabled = false;
223 :
224 0 : nsCOMPtr<nsIController> controller;
225 0 : GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller));
226 0 : if (controller)
227 : {
228 0 : controller->IsCommandEnabled(aCommandName, &commandEnabled);
229 : }
230 0 : *outCommandEnabled = commandEnabled;
231 0 : return NS_OK;
232 : }
233 :
234 : /* void getCommandState (in DOMString aCommandName,
235 : in nsIDOMWindow aTargetWindow,
236 : inout nsICommandParams aCommandParams); */
237 : NS_IMETHODIMP
238 0 : nsCommandManager::GetCommandState(const char *aCommandName,
239 : nsIDOMWindow *aTargetWindow,
240 : nsICommandParams *aCommandParams)
241 : {
242 0 : nsCOMPtr<nsIController> controller;
243 0 : nsAutoString tValue;
244 0 : nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller));
245 0 : if (!controller)
246 0 : return NS_ERROR_FAILURE;
247 :
248 0 : nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller);
249 0 : if (commandController)
250 0 : rv = commandController->GetCommandStateWithParams(aCommandName, aCommandParams);
251 : else
252 0 : rv = NS_ERROR_NOT_IMPLEMENTED;
253 0 : return rv;
254 : }
255 :
256 : /* void doCommand(in string aCommandName,
257 : in nsICommandParams aCommandParams,
258 : in nsIDOMWindow aTargetWindow); */
259 : NS_IMETHODIMP
260 0 : nsCommandManager::DoCommand(const char *aCommandName,
261 : nsICommandParams *aCommandParams,
262 : nsIDOMWindow *aTargetWindow)
263 : {
264 0 : nsCOMPtr<nsIController> controller;
265 0 : nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller));
266 0 : if (!controller)
267 0 : return NS_ERROR_FAILURE;
268 :
269 0 : nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller);
270 0 : if (commandController && aCommandParams)
271 0 : rv = commandController->DoCommandWithParams(aCommandName, aCommandParams);
272 : else
273 0 : rv = controller->DoCommand(aCommandName);
274 0 : return rv;
275 : }
276 :
277 : nsresult
278 0 : nsCommandManager::IsCallerChrome(bool *is_caller_chrome)
279 : {
280 0 : *is_caller_chrome = false;
281 0 : nsresult rv = NS_OK;
282 : nsCOMPtr<nsIScriptSecurityManager> secMan =
283 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
284 0 : if (NS_FAILED(rv))
285 0 : return rv;
286 0 : if (!secMan)
287 0 : return NS_ERROR_FAILURE;
288 :
289 0 : rv = secMan->SubjectPrincipalIsSystem(is_caller_chrome);
290 0 : return rv;
291 : }
292 :
293 : nsresult
294 0 : nsCommandManager::GetControllerForCommand(const char *aCommand,
295 : nsIDOMWindow *aTargetWindow,
296 : nsIController** outController)
297 : {
298 0 : nsresult rv = NS_ERROR_FAILURE;
299 0 : *outController = nsnull;
300 :
301 : // check if we're in content or chrome
302 : // if we're not chrome we must have a target window or we bail
303 0 : bool isChrome = false;
304 0 : rv = IsCallerChrome(&isChrome);
305 0 : if (NS_FAILED(rv))
306 0 : return rv;
307 :
308 0 : if (!isChrome) {
309 0 : if (!aTargetWindow)
310 0 : return rv;
311 :
312 : // if a target window is specified, it must be the window we expect
313 0 : if (aTargetWindow != mWindow)
314 0 : return NS_ERROR_FAILURE;
315 : }
316 :
317 0 : if (aTargetWindow) {
318 : // get the controller for this particular window
319 0 : nsCOMPtr<nsIControllers> controllers;
320 0 : rv = aTargetWindow->GetControllers(getter_AddRefs(controllers));
321 0 : if (NS_FAILED(rv))
322 0 : return rv;
323 0 : if (!controllers)
324 0 : return NS_ERROR_FAILURE;
325 :
326 : // dispatch the command
327 0 : return controllers->GetControllerForCommand(aCommand, outController);
328 : }
329 :
330 0 : nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mWindow));
331 0 : NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
332 0 : nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
333 0 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
334 :
335 : // no target window; send command to focus controller
336 0 : return root->GetControllerForCommand(aCommand, outController);
337 4392 : }
338 :
|