Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/extension_keybinding_registry.h" | 5 #include "chrome/browser/extensions/extension_keybinding_registry.h" |
| 6 | 6 |
| 7 #include "base/utf_string_conversions.h" | |
| 8 #include "chrome/browser/prefs/pref_service.h" | |
| 9 #include "chrome/browser/prefs/scoped_user_pref_update.h" | |
| 7 #include "chrome/browser/profiles/profile.h" | 10 #include "chrome/browser/profiles/profile.h" |
| 8 #include "chrome/common/chrome_notification_types.h" | 11 #include "chrome/common/chrome_notification_types.h" |
| 9 #include "chrome/common/extensions/extension_manifest_constants.h" | 12 #include "chrome/common/extensions/extension_manifest_constants.h" |
| 10 #include "chrome/common/extensions/extension_set.h" | 13 #include "chrome/common/extensions/extension_set.h" |
| 14 #include "chrome/common/pref_names.h" | |
| 11 #include "chrome/browser/extensions/extension_service.h" | 15 #include "chrome/browser/extensions/extension_service.h" |
| 12 | 16 |
| 17 namespace { | |
| 18 | |
| 19 const char kExtension[] = "extension"; | |
| 20 const char kCommandName[] = "command_name"; | |
| 21 | |
| 22 } // namespace | |
| 23 | |
| 13 ExtensionKeybindingRegistry::ExtensionKeybindingRegistry(Profile* profile) | 24 ExtensionKeybindingRegistry::ExtensionKeybindingRegistry(Profile* profile) |
| 14 : profile_(profile) { | 25 : profile_(profile) { |
| 15 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | 26 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
| 16 content::Source<Profile>(profile->GetOriginalProfile())); | 27 content::Source<Profile>(profile->GetOriginalProfile())); |
| 17 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 28 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 18 content::Source<Profile>(profile->GetOriginalProfile())); | 29 content::Source<Profile>(profile->GetOriginalProfile())); |
| 19 } | 30 } |
| 20 | 31 |
| 21 ExtensionKeybindingRegistry::~ExtensionKeybindingRegistry() { | 32 ExtensionKeybindingRegistry::~ExtensionKeybindingRegistry() { |
| 22 } | 33 } |
| 23 | 34 |
| 24 void ExtensionKeybindingRegistry::Init() { | 35 void ExtensionKeybindingRegistry::Init() { |
| 25 ExtensionService* service = profile_->GetExtensionService(); | 36 ExtensionService* service = profile_->GetExtensionService(); |
| 26 if (!service) | 37 if (!service) |
| 27 return; // ExtensionService can be null during testing. | 38 return; // ExtensionService can be null during testing. |
| 28 | 39 |
| 29 const ExtensionSet* extensions = service->extensions(); | 40 const ExtensionSet* extensions = service->extensions(); |
| 30 ExtensionSet::const_iterator iter = extensions->begin(); | 41 ExtensionSet::const_iterator iter = extensions->begin(); |
| 31 for (; iter != extensions->end(); ++iter) | 42 for (; iter != extensions->end(); ++iter) |
| 32 AddExtensionKeybinding(*iter); | 43 AddExtensionKeybinding(*iter); |
| 33 } | 44 } |
| 34 | 45 |
| 35 bool ExtensionKeybindingRegistry::ShouldIgnoreCommand( | 46 bool ExtensionKeybindingRegistry::ShouldIgnoreCommand( |
| 36 const std::string& command) const { | 47 const std::string& command) const { |
| 37 return command == extension_manifest_values::kPageActionKeybindingEvent || | 48 return command == extension_manifest_values::kPageActionKeybindingEvent || |
| 38 command == extension_manifest_values::kBrowserActionKeybindingEvent; | 49 command == extension_manifest_values::kBrowserActionKeybindingEvent; |
| 39 } | 50 } |
| 40 | 51 |
| 52 // static | |
| 53 void ExtensionKeybindingRegistry::RegisterUserPrefs( | |
| 54 PrefService* user_prefs) { | |
| 55 user_prefs->RegisterDictionaryPref(prefs::kExtensionKeybindings, | |
| 56 PrefService::UNSYNCABLE_PREF); | |
|
Aaron Boodman
2012/04/25 19:14:38
This seems like something we'd want to sync.
Finnur
2012/04/26 13:12:35
Yes. I've now changed this to SYNCABLE_PREF. I was
| |
| 57 } | |
| 58 | |
| 59 // static | |
| 60 const Extension::ExtensionKeybinding* | |
| 61 ExtensionKeybindingRegistry::GetActiveBrowserActionCommand( | |
| 62 Profile* profile, | |
| 63 const std::string& extension_id) { | |
| 64 const Extension::ExtensionKeybinding* command = | |
|
Aaron Boodman
2012/04/25 19:14:38
In a separate change, uou should move ExtensionKey
Finnur
2012/04/26 13:12:35
Yup. Sounds good.
On 2012/04/25 19:14:38, Aaron B
| |
| 65 profile->GetExtensionService()->GetExtensionById( | |
|
Aaron Boodman
2012/04/25 19:14:38
If there is no such extension_id, we crash. Is tha
Finnur
2012/04/26 13:12:35
Callers are always holding what I assume to be val
| |
| 66 extension_id, false)->browser_action_command(); | |
| 67 if (!command) | |
| 68 return NULL; | |
| 69 return ExtensionKeybindingRegistry::KeybindingActive( | |
|
Aaron Boodman
2012/04/25 19:14:38
Nit: Since this function call is so long, I would
Aaron Boodman
2012/04/25 19:14:38
Do not need the "ExtensionKeybindingRegistry::" qu
Finnur
2012/04/26 13:12:35
Both done.
On 2012/04/25 19:14:38, Aaron Boodman
| |
| 70 profile->GetPrefs(), | |
| 71 command->accelerator(), | |
| 72 extension_id, | |
| 73 command->command_name()) ? command : NULL; | |
| 74 } | |
| 75 | |
| 76 // static | |
| 77 const Extension::ExtensionKeybinding* | |
| 78 ExtensionKeybindingRegistry::GetActivePageActionCommand( | |
| 79 Profile* profile, | |
| 80 const std::string& extension_id) { | |
| 81 const Extension::ExtensionKeybinding* command = | |
| 82 profile->GetExtensionService()->GetExtensionById( | |
| 83 extension_id, false)->page_action_command(); | |
| 84 if (!command) | |
| 85 return NULL; | |
| 86 return ExtensionKeybindingRegistry::KeybindingActive( | |
| 87 profile->GetPrefs(), | |
| 88 command->accelerator(), | |
| 89 extension_id, | |
| 90 command->command_name()) ? command : NULL; | |
| 91 } | |
| 92 | |
| 93 // static | |
| 94 Extension::CommandMap ExtensionKeybindingRegistry::GetActiveNamedCommands( | |
| 95 Profile* profile, | |
| 96 const std::string& extension_id) { | |
| 97 Extension::CommandMap result; | |
| 98 const Extension::CommandMap& commands = | |
| 99 profile->GetExtensionService()->GetExtensionById( | |
| 100 extension_id, false)->named_commands(); | |
| 101 if (commands.empty()) | |
| 102 return result; | |
| 103 | |
| 104 Extension::CommandMap::const_iterator iter = commands.begin(); | |
| 105 for (; iter != commands.end(); ++iter) { | |
| 106 if (!ExtensionKeybindingRegistry::KeybindingActive( | |
| 107 profile->GetPrefs(), | |
| 108 iter->second.accelerator(), | |
| 109 extension_id, | |
| 110 iter->second.command_name())) { | |
| 111 continue; | |
| 112 } | |
| 113 | |
| 114 result[iter->second.command_name()] = iter->second; | |
| 115 } | |
| 116 | |
| 117 return result; | |
| 118 } | |
| 119 | |
| 120 // static | |
| 121 void ExtensionKeybindingRegistry::ResolveKeyBindings( | |
| 122 PrefService* user_prefs, | |
| 123 const Extension* extension) { | |
| 124 const Extension::CommandMap& commands = extension->named_commands(); | |
| 125 Extension::CommandMap::const_iterator iter = commands.begin(); | |
| 126 for (; iter != commands.end(); ++iter) { | |
| 127 AddKeybindingPref(user_prefs, | |
| 128 iter->second.accelerator(), | |
| 129 extension->id(), | |
| 130 iter->second.command_name(), | |
| 131 false); // Overwriting not allowed. | |
| 132 } | |
| 133 | |
| 134 const Extension::ExtensionKeybinding* browser_action_command = | |
| 135 extension->browser_action_command(); | |
| 136 if (browser_action_command) { | |
| 137 AddKeybindingPref(user_prefs, | |
| 138 browser_action_command->accelerator(), | |
| 139 extension->id(), | |
| 140 browser_action_command->command_name(), | |
| 141 false); // Overwriting not allowed. | |
| 142 } | |
| 143 | |
| 144 const Extension::ExtensionKeybinding* page_action_command = | |
| 145 extension->page_action_command(); | |
| 146 if (page_action_command) { | |
| 147 AddKeybindingPref(user_prefs, | |
| 148 page_action_command->accelerator(), | |
| 149 extension->id(), | |
| 150 page_action_command->command_name(), | |
| 151 false); // Overwriting not allowed. | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 // static | |
| 156 bool ExtensionKeybindingRegistry::KeybindingActive( | |
| 157 PrefService* user_prefs, | |
| 158 const ui::Accelerator& accelerator, | |
| 159 std::string extension_id, | |
| 160 std::string command_name) { | |
| 161 DCHECK(!extension_id.empty()); | |
|
Aaron Boodman
2012/04/25 19:14:38
I prefer CHECK to DCHECK
| |
| 162 DCHECK(!command_name.empty()); | |
| 163 | |
| 164 std::string key = UTF16ToUTF8(accelerator.GetShortcutText()); | |
| 165 const DictionaryValue* bindings = | |
| 166 user_prefs->GetDictionary(prefs::kExtensionKeybindings); | |
| 167 if (!bindings->HasKey(key)) | |
| 168 return false; | |
| 169 | |
| 170 DictionaryValue* value; | |
|
Aaron Boodman
2012/04/25 19:14:38
= NULL
| |
| 171 if (!bindings->GetDictionary(key, &value) || !value) | |
| 172 return false; | |
| 173 | |
| 174 std::string id; | |
| 175 if (!value->GetString(kExtension, &id) || id != extension_id) | |
| 176 return false; // Already taken by another extension. | |
| 177 | |
| 178 std::string command; | |
| 179 if (!value->GetString(kCommandName, &command) || command != command_name) | |
| 180 return false; // Already taken by another command. | |
| 181 | |
| 182 return true; // We found a match, this one is active. | |
| 183 } | |
| 184 | |
| 185 // static | |
| 186 bool ExtensionKeybindingRegistry::AddKeybindingPref( | |
| 187 PrefService* user_prefs, | |
| 188 const ui::Accelerator& accelerator, | |
| 189 std::string extension_id, | |
| 190 std::string command_name, | |
| 191 bool allow_overrides) { | |
| 192 DictionaryPrefUpdate updater(user_prefs, prefs::kExtensionKeybindings); | |
| 193 DictionaryValue* bindings = updater.Get(); | |
| 194 | |
| 195 if (bindings->HasKey(UTF16ToUTF8(accelerator.GetShortcutText())) && | |
| 196 !allow_overrides) | |
| 197 return false; // Already taken. | |
| 198 | |
| 199 DictionaryValue* keybinding = new DictionaryValue(); | |
| 200 keybinding->SetString(kExtension, extension_id); | |
| 201 keybinding->SetString(kCommandName, command_name); | |
| 202 | |
| 203 bindings->Set(UTF16ToUTF8(accelerator.GetShortcutText()), keybinding); | |
| 204 return true; | |
| 205 } | |
| 206 | |
| 207 // static | |
| 208 void ExtensionKeybindingRegistry::RemoveKeybindingPref( | |
|
Aaron Boodman
2012/04/25 19:14:38
RemoveKeybindingPrefs (plural) since this can remo
| |
| 209 PrefService* user_prefs, | |
| 210 std::string extension_id) { | |
| 211 DictionaryPrefUpdate updater(user_prefs, prefs::kExtensionKeybindings); | |
| 212 DictionaryValue* bindings = updater.Get(); | |
| 213 | |
| 214 typedef std::vector<std::string> KeysToRemove; | |
| 215 KeysToRemove keys_to_remove; | |
| 216 for (DictionaryValue::key_iterator it = bindings->begin_keys(); | |
| 217 it != bindings->end_keys(); ++it) { | |
| 218 std::string key = *it; | |
| 219 DictionaryValue* item = NULL; | |
| 220 bindings->GetDictionary(key, &item); | |
| 221 | |
| 222 std::string extension; | |
| 223 item->GetString(kExtension, &extension); | |
| 224 if (extension == extension_id) | |
| 225 keys_to_remove.push_back(key); | |
| 226 } | |
| 227 | |
| 228 for (KeysToRemove::const_iterator it = keys_to_remove.begin(); | |
| 229 it != keys_to_remove.end(); ++it) { | |
| 230 bindings->Remove(*it, NULL); | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 | |
| 41 void ExtensionKeybindingRegistry::Observe( | 235 void ExtensionKeybindingRegistry::Observe( |
| 42 int type, | 236 int type, |
| 43 const content::NotificationSource& source, | 237 const content::NotificationSource& source, |
| 44 const content::NotificationDetails& details) { | 238 const content::NotificationDetails& details) { |
| 45 switch (type) { | 239 switch (type) { |
| 46 case chrome::NOTIFICATION_EXTENSION_LOADED: | 240 case chrome::NOTIFICATION_EXTENSION_LOADED: |
| 47 AddExtensionKeybinding( | 241 AddExtensionKeybinding( |
| 48 content::Details<const Extension>(details).ptr()); | 242 content::Details<const Extension>(details).ptr()); |
| 49 break; | 243 break; |
| 50 case chrome::NOTIFICATION_EXTENSION_UNLOADED: | 244 case chrome::NOTIFICATION_EXTENSION_UNLOADED: |
| 51 RemoveExtensionKeybinding( | 245 RemoveExtensionKeybinding( |
| 52 content::Details<UnloadedExtensionInfo>(details)->extension); | 246 content::Details<UnloadedExtensionInfo>(details)->extension); |
| 53 break; | 247 break; |
| 54 default: | 248 default: |
| 55 NOTREACHED(); | 249 NOTREACHED(); |
| 56 break; | 250 break; |
| 57 } | 251 } |
| 58 } | 252 } |
| OLD | NEW |