Back to index

lightning-sunbird  0.9+nobinonly
nsCommandManager.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Kathleen Brade <brade@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsString.h"
00040 
00041 #include "nsIController.h"
00042 #include "nsIControllers.h"
00043 #include "nsIObserver.h"
00044 
00045 #include "nsIComponentManager.h"
00046 
00047 #include "nsServiceManagerUtils.h"
00048 #include "nsIScriptSecurityManager.h"
00049 
00050 #include "nsIDOMDocument.h"
00051 #include "nsIDOMWindow.h"
00052 #include "nsPIDOMWindow.h"
00053 #include "nsIDOMWindowInternal.h"
00054 #include "nsIFocusController.h"
00055 
00056 #include "nsSupportsArray.h"
00057 
00058 #include "nsCommandManager.h"
00059 
00060 
00061 nsCommandManager::nsCommandManager()
00062 : mWindow(nsnull)
00063 {
00064   /* member initializers and constructor code */
00065 }
00066 
00067 nsCommandManager::~nsCommandManager()
00068 {
00069   /* destructor code */
00070 }
00071 
00072 
00073 NS_IMPL_ISUPPORTS3(nsCommandManager, nsICommandManager, nsPICommandUpdater, nsISupportsWeakReference)
00074 
00075 #if 0
00076 #pragma mark -
00077 #endif
00078 
00079 /* void init (in nsIDOMWindow aWindow); */
00080 NS_IMETHODIMP
00081 nsCommandManager::Init(nsIDOMWindow *aWindow)
00082 {
00083   NS_ENSURE_ARG_POINTER(aWindow);
00084   
00085   NS_ASSERTION(aWindow, "Need non-null window here");
00086   mWindow = aWindow;      // weak ptr
00087   return NS_OK;
00088 }
00089 
00090 /* void commandStatusChanged (in DOMString aCommandName, in long aChangeFlags); */
00091 NS_IMETHODIMP
00092 nsCommandManager::CommandStatusChanged(const char * aCommandName)
00093 {
00094        nsCStringKey hashKey(aCommandName);
00095 
00096   
00097   nsresult rv = NS_OK;
00098        nsCOMPtr<nsISupports>       commandSupports  = getter_AddRefs(mCommandObserversTable.Get(&hashKey));
00099        nsCOMPtr<nsISupportsArray>  commandObservers = do_QueryInterface(commandSupports);
00100        if (commandObservers)
00101        {
00102          PRUint32  numItems;
00103          rv = commandObservers->Count(&numItems);
00104          if (NS_FAILED(rv)) return rv;
00105          
00106          for (PRUint32 i = 0; i < numItems; i ++)
00107          {
00108            nsCOMPtr<nsISupports>   itemSupports;
00109            rv = commandObservers->GetElementAt(i, getter_AddRefs(itemSupports));
00110            if (NS_FAILED(rv)) break;
00111       nsCOMPtr<nsIObserver>   itemObserver = do_QueryInterface(itemSupports);
00112       if (itemObserver)
00113       {
00114        // should we get the command state to pass here? This might be expensive.
00115         itemObserver->Observe((nsICommandManager *)this, aCommandName,NS_LITERAL_STRING("command_status_changed").get());
00116       }
00117          }
00118        }
00119 
00120   return NS_OK;
00121 }
00122 
00123 #if 0
00124 #pragma mark -
00125 #endif
00126 
00127 /* void addCommandObserver (in nsIObserver aCommandObserver, in wstring aCommandToObserve); */
00128 NS_IMETHODIMP
00129 nsCommandManager::AddCommandObserver(nsIObserver *aCommandObserver, const char *aCommandToObserve)
00130 {
00131        NS_ENSURE_ARG(aCommandObserver);
00132        
00133        nsresult rv = NS_OK;
00134 
00135        // XXX todo: handle special cases of aCommandToObserve being null, or empty
00136        
00137        // for each command in the table, we make a list of observers for that command
00138   nsCStringKey hashKey(aCommandToObserve);
00139        
00140        nsCOMPtr<nsISupports>       commandSupports  = getter_AddRefs(mCommandObserversTable.Get(&hashKey));
00141        nsCOMPtr<nsISupportsArray>  commandObservers = do_QueryInterface(commandSupports);
00142        if (!commandObservers)
00143        {
00144          rv = NS_NewISupportsArray(getter_AddRefs(commandObservers));
00145        if (NS_FAILED(rv)) return rv;
00146        
00147        commandSupports = do_QueryInterface(commandObservers);
00148        rv = mCommandObserversTable.Put(&hashKey, commandSupports);
00149        if (NS_FAILED(rv)) return rv;
00150        }
00151        
00152        // need to check that this command observer hasn't already been registered
00153        nsCOMPtr<nsISupports> observerAsSupports = do_QueryInterface(aCommandObserver);
00154        PRInt32 existingIndex = commandObservers->IndexOf(observerAsSupports);
00155   if (existingIndex == -1)
00156     rv = commandObservers->AppendElement(observerAsSupports);
00157   else
00158     NS_WARNING("Registering command observer twice on the same command");
00159   
00160   return rv;
00161 }
00162 
00163 /* void removeCommandObserver (in nsIObserver aCommandObserver, in wstring aCommandObserved); */
00164 NS_IMETHODIMP
00165 nsCommandManager::RemoveCommandObserver(nsIObserver *aCommandObserver, const char *aCommandObserved)
00166 {
00167        NS_ENSURE_ARG(aCommandObserver);
00168 
00169        // XXX todo: handle special cases of aCommandToObserve being null, or empty
00170        nsCStringKey hashKey(aCommandObserved);
00171 
00172        nsCOMPtr<nsISupports>       commandSupports  = getter_AddRefs(mCommandObserversTable.Get(&hashKey));
00173        nsCOMPtr<nsISupportsArray>  commandObservers = do_QueryInterface(commandSupports);
00174        if (!commandObservers)
00175          return NS_ERROR_UNEXPECTED;
00176        
00177        nsresult removed = commandObservers->RemoveElement(aCommandObserver);
00178        return (removed) ? NS_OK : NS_ERROR_FAILURE;
00179 }
00180 
00181 /* boolean isCommandSupported(in string aCommandName,
00182                               in nsIDOMWindow aTargetWindow); */
00183 NS_IMETHODIMP
00184 nsCommandManager::IsCommandSupported(const char *aCommandName,
00185                                      nsIDOMWindow *aTargetWindow,
00186                                      PRBool *outCommandSupported)
00187 {
00188   NS_ENSURE_ARG_POINTER(outCommandSupported);
00189 
00190   nsCOMPtr<nsIController> controller;
00191   GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller)); 
00192   *outCommandSupported = (controller.get() != nsnull);
00193   return NS_OK;
00194 }
00195 
00196 /* boolean isCommandEnabled(in string aCommandName,
00197                             in nsIDOMWindow aTargetWindow); */
00198 NS_IMETHODIMP
00199 nsCommandManager::IsCommandEnabled(const char *aCommandName,
00200                                    nsIDOMWindow *aTargetWindow,
00201                                    PRBool *outCommandEnabled)
00202 {
00203   NS_ENSURE_ARG_POINTER(outCommandEnabled);
00204   
00205   PRBool  commandEnabled = PR_FALSE;
00206   
00207   nsCOMPtr<nsIController> controller;
00208   GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller)); 
00209   if (controller)
00210   {
00211     controller->IsCommandEnabled(aCommandName, &commandEnabled);
00212   }
00213   *outCommandEnabled = commandEnabled;
00214   return NS_OK;
00215 }
00216 
00217 /* void getCommandState (in DOMString aCommandName,
00218                          in nsIDOMWindow aTargetWindow,
00219                          inout nsICommandParams aCommandParams); */
00220 NS_IMETHODIMP
00221 nsCommandManager::GetCommandState(const char *aCommandName,
00222                                   nsIDOMWindow *aTargetWindow,
00223                                   nsICommandParams *aCommandParams)
00224 {
00225   nsCOMPtr<nsIController> controller;
00226   nsAutoString tValue;
00227   nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller)); 
00228   if (!controller)
00229     return NS_ERROR_FAILURE;
00230 
00231   nsCOMPtr<nsICommandController>  commandController = do_QueryInterface(controller);
00232   if (commandController)
00233     rv = commandController->GetCommandStateWithParams(aCommandName, aCommandParams);
00234   else
00235     rv = NS_ERROR_NOT_IMPLEMENTED;
00236   return rv;
00237 }
00238 
00239 /* void doCommand(in string aCommandName,
00240                   in nsICommandParams aCommandParams,
00241                   in nsIDOMWindow aTargetWindow); */
00242 NS_IMETHODIMP
00243 nsCommandManager::DoCommand(const char *aCommandName,
00244                             nsICommandParams *aCommandParams,
00245                             nsIDOMWindow *aTargetWindow)
00246 {
00247   nsCOMPtr<nsIController> controller;
00248   nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller)); 
00249   if (!controller)
00250          return NS_ERROR_FAILURE;
00251 
00252   nsCOMPtr<nsICommandController>  commandController = do_QueryInterface(controller);
00253   if (commandController && aCommandParams)
00254     rv = commandController->DoCommandWithParams(aCommandName, aCommandParams);
00255   else
00256     rv = controller->DoCommand(aCommandName);
00257   return rv;
00258 }
00259 
00260 #ifdef XP_MAC
00261 #pragma mark -
00262 #endif
00263 
00264 nsresult
00265 nsCommandManager::IsCallerChrome(PRBool *is_caller_chrome)
00266 {
00267   *is_caller_chrome = PR_FALSE;
00268   nsresult rv = NS_OK;
00269   nsCOMPtr<nsIScriptSecurityManager> secMan = 
00270       do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
00271   if (NS_FAILED(rv))
00272     return rv;
00273   if (!secMan)
00274     return NS_ERROR_FAILURE;
00275 
00276   rv = secMan->SubjectPrincipalIsSystem(is_caller_chrome);
00277   return rv;
00278 }
00279 
00280 nsresult
00281 nsCommandManager::GetControllerForCommand(const char *aCommand, 
00282                                           nsIDOMWindow *aTargetWindow,
00283                                           nsIController** outController)
00284 {
00285   nsresult rv = NS_ERROR_FAILURE;
00286   *outController = nsnull;
00287 
00288   // check if we're in content or chrome
00289   // if we're not chrome we must have a target window or we bail
00290   PRBool isChrome = PR_FALSE;
00291   rv = IsCallerChrome(&isChrome);
00292   if (NS_FAILED(rv))
00293     return rv;
00294 
00295   if (!isChrome) {
00296     if (!aTargetWindow)
00297       return rv;
00298 
00299     // if a target window is specified, it must be the window we expect
00300     if (aTargetWindow != mWindow)
00301         return NS_ERROR_FAILURE;
00302   }
00303 
00304   if (aTargetWindow)
00305   {
00306     // get the controller for this particular window
00307     nsCOMPtr<nsIDOMWindowInternal> domWindowInternal = do_QueryInterface(aTargetWindow);
00308     if (!domWindowInternal)
00309       return NS_ERROR_FAILURE;
00310 
00311     nsCOMPtr<nsIControllers> controllers;
00312     rv = domWindowInternal->GetControllers(getter_AddRefs(controllers));
00313     if (NS_FAILED(rv))
00314       return rv;
00315     if (!controllers)
00316       return NS_ERROR_FAILURE;
00317 
00318     // dispatch the command
00319     return controllers->GetControllerForCommand(aCommand, outController);
00320   }
00321 
00322 
00323   // else we're not targeted to a particular window so use focus
00324   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mWindow);
00325   if (!window)
00326     return NS_ERROR_FAILURE;
00327 
00328   nsIFocusController *focusController = window->GetRootFocusController();
00329   if (!focusController)
00330     return NS_ERROR_FAILURE;
00331 
00332   nsCOMPtr<nsIDOMWindowInternal> focusWindowInternal;
00333   rv = focusController->GetFocusedWindow(getter_AddRefs(focusWindowInternal));
00334   if (NS_FAILED(rv))
00335     return rv;
00336 
00337   // get the destination window so we can check if it's in content or chrome
00338   nsCOMPtr<nsIDOMWindow> destWindow = do_QueryInterface(focusWindowInternal);
00339   if (!destWindow)
00340     return NS_ERROR_FAILURE;
00341 
00342   // no target window; send command to focus controller
00343   return focusController->GetControllerForCommand(aCommand, outController);
00344 }
00345