1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/common/extensions/api/commands/commands_handler.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/values.h"
10 #include "chrome/common/extensions/command.h"
11 #include "extensions/common/error_utils.h"
12 #include "extensions/common/manifest_constants.h"
14 namespace extensions
{
16 namespace keys
= manifest_keys
;
19 // The maximum number of commands (including page action/browser actions) with a
20 // keybinding an extension can have.
21 const int kMaxCommandsWithKeybindingPerExtension
= 4;
24 CommandsInfo::CommandsInfo() {
27 CommandsInfo::~CommandsInfo() {
31 const Command
* CommandsInfo::GetBrowserActionCommand(
32 const Extension
* extension
) {
33 CommandsInfo
* info
= static_cast<CommandsInfo
*>(
34 extension
->GetManifestData(keys::kCommands
));
35 return info
? info
->browser_action_command
.get() : NULL
;
39 const Command
* CommandsInfo::GetPageActionCommand(const Extension
* extension
) {
40 CommandsInfo
* info
= static_cast<CommandsInfo
*>(
41 extension
->GetManifestData(keys::kCommands
));
42 return info
? info
->page_action_command
.get() : NULL
;
46 const CommandMap
* CommandsInfo::GetNamedCommands(const Extension
* extension
) {
47 CommandsInfo
* info
= static_cast<CommandsInfo
*>(
48 extension
->GetManifestData(keys::kCommands
));
49 return info
? &info
->named_commands
: NULL
;
52 CommandsHandler::CommandsHandler() {
55 CommandsHandler::~CommandsHandler() {
58 bool CommandsHandler::Parse(Extension
* extension
, base::string16
* error
) {
59 if (!extension
->manifest()->HasKey(keys::kCommands
)) {
60 scoped_ptr
<CommandsInfo
> commands_info(new CommandsInfo
);
61 MaybeSetBrowserActionDefault(extension
, commands_info
.get());
62 extension
->SetManifestData(keys::kCommands
,
63 commands_info
.release());
67 const base::DictionaryValue
* dict
= NULL
;
68 if (!extension
->manifest()->GetDictionary(keys::kCommands
, &dict
)) {
69 *error
= base::ASCIIToUTF16(manifest_errors::kInvalidCommandsKey
);
73 scoped_ptr
<CommandsInfo
> commands_info(new CommandsInfo
);
75 int command_index
= 0;
76 int keybindings_found
= 0;
77 for (base::DictionaryValue::Iterator
iter(*dict
); !iter
.IsAtEnd();
81 const base::DictionaryValue
* command
= NULL
;
82 if (!iter
.value().GetAsDictionary(&command
)) {
83 *error
= ErrorUtils::FormatErrorMessageUTF16(
84 manifest_errors::kInvalidKeyBindingDictionary
,
85 base::IntToString(command_index
));
89 scoped_ptr
<extensions::Command
> binding(new Command());
90 if (!binding
->Parse(command
, iter
.key(), command_index
, error
))
91 return false; // |error| already set.
93 if (binding
->accelerator().key_code() != ui::VKEY_UNKNOWN
) {
94 // Only media keys are allowed to work without modifiers, and because
95 // media keys aren't registered exclusively they should not count towards
96 // the max of four shortcuts per extension.
97 if (!Command::IsMediaKey(binding
->accelerator()))
100 if (keybindings_found
> kMaxCommandsWithKeybindingPerExtension
) {
101 *error
= ErrorUtils::FormatErrorMessageUTF16(
102 manifest_errors::kInvalidKeyBindingTooMany
,
103 base::IntToString(kMaxCommandsWithKeybindingPerExtension
));
108 std::string command_name
= binding
->command_name();
109 if (command_name
== manifest_values::kBrowserActionCommandEvent
) {
110 commands_info
->browser_action_command
.reset(binding
.release());
111 } else if (command_name
==
112 manifest_values::kPageActionCommandEvent
) {
113 commands_info
->page_action_command
.reset(binding
.release());
115 if (command_name
[0] != '_') // All commands w/underscore are reserved.
116 commands_info
->named_commands
[command_name
] = *binding
.get();
120 MaybeSetBrowserActionDefault(extension
, commands_info
.get());
122 extension
->SetManifestData(keys::kCommands
,
123 commands_info
.release());
127 bool CommandsHandler::AlwaysParseForType(Manifest::Type type
) const {
128 return type
== Manifest::TYPE_EXTENSION
||
129 type
== Manifest::TYPE_LEGACY_PACKAGED_APP
||
130 type
== Manifest::TYPE_PLATFORM_APP
;
133 void CommandsHandler::MaybeSetBrowserActionDefault(const Extension
* extension
,
134 CommandsInfo
* info
) {
135 if (extension
->manifest()->HasKey(keys::kBrowserAction
) &&
136 !info
->browser_action_command
.get()) {
137 info
->browser_action_command
.reset(
138 new Command(manifest_values::kBrowserActionCommandEvent
,
145 const std::vector
<std::string
> CommandsHandler::Keys() const {
146 return SingleKey(keys::kCommands
);
149 } // namespace extensions