Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: chrome/browser/extensions/extension_keybinding_registry.cc

Issue 10201016: Conflict detection for Extension Keybinding. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698