1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/embedding/components/commandhandler/src/nsCommandManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,300 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsString.h" 1.10 + 1.11 +#include "nsIController.h" 1.12 +#include "nsIControllers.h" 1.13 +#include "nsIObserver.h" 1.14 + 1.15 +#include "nsIComponentManager.h" 1.16 + 1.17 +#include "nsServiceManagerUtils.h" 1.18 +#include "nsIScriptSecurityManager.h" 1.19 + 1.20 +#include "nsIDOMWindow.h" 1.21 +#include "nsPIDOMWindow.h" 1.22 +#include "nsPIWindowRoot.h" 1.23 +#include "nsIFocusManager.h" 1.24 + 1.25 +#include "nsCOMArray.h" 1.26 + 1.27 +#include "nsCommandManager.h" 1.28 + 1.29 + 1.30 +nsCommandManager::nsCommandManager() 1.31 +: mWindow(nullptr) 1.32 +{ 1.33 + /* member initializers and constructor code */ 1.34 +} 1.35 + 1.36 +nsCommandManager::~nsCommandManager() 1.37 +{ 1.38 + /* destructor code */ 1.39 +} 1.40 + 1.41 + 1.42 +static PLDHashOperator 1.43 +TraverseCommandObservers(const char* aKey, 1.44 + nsCommandManager::ObserverList* aObservers, 1.45 + void* aClosure) 1.46 +{ 1.47 + nsCycleCollectionTraversalCallback *cb = 1.48 + static_cast<nsCycleCollectionTraversalCallback*>(aClosure); 1.49 + 1.50 + int32_t i, numItems = aObservers->Length(); 1.51 + for (i = 0; i < numItems; ++i) { 1.52 + cb->NoteXPCOMChild(aObservers->ElementAt(i)); 1.53 + } 1.54 + 1.55 + return PL_DHASH_NEXT; 1.56 +} 1.57 + 1.58 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager) 1.59 + 1.60 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager) 1.61 + tmp->mObserversTable.Clear(); 1.62 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.63 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager) 1.64 + tmp->mObserversTable.EnumerateRead(TraverseCommandObservers, &cb); 1.65 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.66 + 1.67 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager) 1.68 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager) 1.69 + 1.70 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager) 1.71 + NS_INTERFACE_MAP_ENTRY(nsICommandManager) 1.72 + NS_INTERFACE_MAP_ENTRY(nsPICommandUpdater) 1.73 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.74 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandManager) 1.75 +NS_INTERFACE_MAP_END 1.76 + 1.77 +#if 0 1.78 +#pragma mark - 1.79 +#endif 1.80 + 1.81 +/* void init (in nsIDOMWindow aWindow); */ 1.82 +NS_IMETHODIMP 1.83 +nsCommandManager::Init(nsIDOMWindow *aWindow) 1.84 +{ 1.85 + NS_ENSURE_ARG_POINTER(aWindow); 1.86 + 1.87 + NS_ASSERTION(aWindow, "Need non-null window here"); 1.88 + mWindow = aWindow; // weak ptr 1.89 + return NS_OK; 1.90 +} 1.91 + 1.92 +/* void commandStatusChanged (in DOMString aCommandName, in long aChangeFlags); */ 1.93 +NS_IMETHODIMP 1.94 +nsCommandManager::CommandStatusChanged(const char * aCommandName) 1.95 +{ 1.96 + ObserverList* commandObservers; 1.97 + mObserversTable.Get(aCommandName, &commandObservers); 1.98 + 1.99 + if (commandObservers) 1.100 + { 1.101 + // XXX Should we worry about observers removing themselves from Observe()? 1.102 + int32_t i, numItems = commandObservers->Length(); 1.103 + for (i = 0; i < numItems; ++i) 1.104 + { 1.105 + nsCOMPtr<nsIObserver> observer = commandObservers->ElementAt(i); 1.106 + // should we get the command state to pass here? This might be expensive. 1.107 + observer->Observe(NS_ISUPPORTS_CAST(nsICommandManager*, this), 1.108 + aCommandName, 1.109 + MOZ_UTF16("command_status_changed")); 1.110 + } 1.111 + } 1.112 + 1.113 + return NS_OK; 1.114 +} 1.115 + 1.116 +#if 0 1.117 +#pragma mark - 1.118 +#endif 1.119 + 1.120 +/* void addCommandObserver (in nsIObserver aCommandObserver, in wstring aCommandToObserve); */ 1.121 +NS_IMETHODIMP 1.122 +nsCommandManager::AddCommandObserver(nsIObserver *aCommandObserver, const char *aCommandToObserve) 1.123 +{ 1.124 + NS_ENSURE_ARG(aCommandObserver); 1.125 + 1.126 + // XXX todo: handle special cases of aCommandToObserve being null, or empty 1.127 + 1.128 + // for each command in the table, we make a list of observers for that command 1.129 + ObserverList* commandObservers; 1.130 + if (!mObserversTable.Get(aCommandToObserve, &commandObservers)) 1.131 + { 1.132 + commandObservers = new ObserverList; 1.133 + mObserversTable.Put(aCommandToObserve, commandObservers); 1.134 + } 1.135 + 1.136 + // need to check that this command observer hasn't already been registered 1.137 + int32_t existingIndex = commandObservers->IndexOf(aCommandObserver); 1.138 + if (existingIndex == -1) 1.139 + commandObservers->AppendElement(aCommandObserver); 1.140 + else 1.141 + NS_WARNING("Registering command observer twice on the same command"); 1.142 + 1.143 + return NS_OK; 1.144 +} 1.145 + 1.146 +/* void removeCommandObserver (in nsIObserver aCommandObserver, in wstring aCommandObserved); */ 1.147 +NS_IMETHODIMP 1.148 +nsCommandManager::RemoveCommandObserver(nsIObserver *aCommandObserver, const char *aCommandObserved) 1.149 +{ 1.150 + NS_ENSURE_ARG(aCommandObserver); 1.151 + 1.152 + // XXX todo: handle special cases of aCommandToObserve being null, or empty 1.153 + 1.154 + ObserverList* commandObservers; 1.155 + if (!mObserversTable.Get(aCommandObserved, &commandObservers)) 1.156 + return NS_ERROR_UNEXPECTED; 1.157 + 1.158 + commandObservers->RemoveElement(aCommandObserver); 1.159 + 1.160 + return NS_OK; 1.161 +} 1.162 + 1.163 +/* boolean isCommandSupported(in string aCommandName, 1.164 + in nsIDOMWindow aTargetWindow); */ 1.165 +NS_IMETHODIMP 1.166 +nsCommandManager::IsCommandSupported(const char *aCommandName, 1.167 + nsIDOMWindow *aTargetWindow, 1.168 + bool *outCommandSupported) 1.169 +{ 1.170 + NS_ENSURE_ARG_POINTER(outCommandSupported); 1.171 + 1.172 + nsCOMPtr<nsIController> controller; 1.173 + GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller)); 1.174 + *outCommandSupported = (controller.get() != nullptr); 1.175 + return NS_OK; 1.176 +} 1.177 + 1.178 +/* boolean isCommandEnabled(in string aCommandName, 1.179 + in nsIDOMWindow aTargetWindow); */ 1.180 +NS_IMETHODIMP 1.181 +nsCommandManager::IsCommandEnabled(const char *aCommandName, 1.182 + nsIDOMWindow *aTargetWindow, 1.183 + bool *outCommandEnabled) 1.184 +{ 1.185 + NS_ENSURE_ARG_POINTER(outCommandEnabled); 1.186 + 1.187 + bool commandEnabled = false; 1.188 + 1.189 + nsCOMPtr<nsIController> controller; 1.190 + GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller)); 1.191 + if (controller) 1.192 + { 1.193 + controller->IsCommandEnabled(aCommandName, &commandEnabled); 1.194 + } 1.195 + *outCommandEnabled = commandEnabled; 1.196 + return NS_OK; 1.197 +} 1.198 + 1.199 +/* void getCommandState (in DOMString aCommandName, 1.200 + in nsIDOMWindow aTargetWindow, 1.201 + inout nsICommandParams aCommandParams); */ 1.202 +NS_IMETHODIMP 1.203 +nsCommandManager::GetCommandState(const char *aCommandName, 1.204 + nsIDOMWindow *aTargetWindow, 1.205 + nsICommandParams *aCommandParams) 1.206 +{ 1.207 + nsCOMPtr<nsIController> controller; 1.208 + nsAutoString tValue; 1.209 + nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller)); 1.210 + if (!controller) 1.211 + return NS_ERROR_FAILURE; 1.212 + 1.213 + nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller); 1.214 + if (commandController) 1.215 + rv = commandController->GetCommandStateWithParams(aCommandName, aCommandParams); 1.216 + else 1.217 + rv = NS_ERROR_NOT_IMPLEMENTED; 1.218 + return rv; 1.219 +} 1.220 + 1.221 +/* void doCommand(in string aCommandName, 1.222 + in nsICommandParams aCommandParams, 1.223 + in nsIDOMWindow aTargetWindow); */ 1.224 +NS_IMETHODIMP 1.225 +nsCommandManager::DoCommand(const char *aCommandName, 1.226 + nsICommandParams *aCommandParams, 1.227 + nsIDOMWindow *aTargetWindow) 1.228 +{ 1.229 + nsCOMPtr<nsIController> controller; 1.230 + nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow, getter_AddRefs(controller)); 1.231 + if (!controller) 1.232 + return NS_ERROR_FAILURE; 1.233 + 1.234 + nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller); 1.235 + if (commandController && aCommandParams) 1.236 + rv = commandController->DoCommandWithParams(aCommandName, aCommandParams); 1.237 + else 1.238 + rv = controller->DoCommand(aCommandName); 1.239 + return rv; 1.240 +} 1.241 + 1.242 +nsresult 1.243 +nsCommandManager::IsCallerChrome(bool *is_caller_chrome) 1.244 +{ 1.245 + *is_caller_chrome = false; 1.246 + nsresult rv = NS_OK; 1.247 + nsCOMPtr<nsIScriptSecurityManager> secMan = 1.248 + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); 1.249 + if (NS_FAILED(rv)) 1.250 + return rv; 1.251 + if (!secMan) 1.252 + return NS_ERROR_FAILURE; 1.253 + 1.254 + rv = secMan->SubjectPrincipalIsSystem(is_caller_chrome); 1.255 + return rv; 1.256 +} 1.257 + 1.258 +nsresult 1.259 +nsCommandManager::GetControllerForCommand(const char *aCommand, 1.260 + nsIDOMWindow *aTargetWindow, 1.261 + nsIController** outController) 1.262 +{ 1.263 + nsresult rv = NS_ERROR_FAILURE; 1.264 + *outController = nullptr; 1.265 + 1.266 + // check if we're in content or chrome 1.267 + // if we're not chrome we must have a target window or we bail 1.268 + bool isChrome = false; 1.269 + rv = IsCallerChrome(&isChrome); 1.270 + if (NS_FAILED(rv)) 1.271 + return rv; 1.272 + 1.273 + if (!isChrome) { 1.274 + if (!aTargetWindow) 1.275 + return rv; 1.276 + 1.277 + // if a target window is specified, it must be the window we expect 1.278 + if (aTargetWindow != mWindow) 1.279 + return NS_ERROR_FAILURE; 1.280 + } 1.281 + 1.282 + if (aTargetWindow) { 1.283 + // get the controller for this particular window 1.284 + nsCOMPtr<nsIControllers> controllers; 1.285 + rv = aTargetWindow->GetControllers(getter_AddRefs(controllers)); 1.286 + if (NS_FAILED(rv)) 1.287 + return rv; 1.288 + if (!controllers) 1.289 + return NS_ERROR_FAILURE; 1.290 + 1.291 + // dispatch the command 1.292 + return controllers->GetControllerForCommand(aCommand, outController); 1.293 + } 1.294 + 1.295 + nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mWindow)); 1.296 + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 1.297 + nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot(); 1.298 + NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); 1.299 + 1.300 + // no target window; send command to focus controller 1.301 + return root->GetControllerForCommand(aCommand, outController); 1.302 +} 1.303 +