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 "extensions/common/error_utils.h"
11 #include "extensions/common/manifest_constants.h"
13 namespace extensions
{
15 namespace keys
= manifest_keys
;
18 // The maximum number of commands (including page action/browser actions) with a
19 // keybinding an extension can have.
20 const int kMaxCommandsWithKeybindingPerExtension
= 4;
23 CommandsInfo::CommandsInfo() {
26 CommandsInfo::~CommandsInfo() {
30 const Command
* CommandsInfo::GetBrowserActionCommand(
31 const Extension
* extension
) {
32 CommandsInfo
* info
= static_cast<CommandsInfo
*>(
33 extension
->GetManifestData(keys::kCommands
));
34 return info
? info
->browser_action_command
.get() : NULL
;
38 const Command
* CommandsInfo::GetPageActionCommand(const Extension
* extension
) {
39 CommandsInfo
* info
= static_cast<CommandsInfo
*>(
40 extension
->GetManifestData(keys::kCommands
));
41 return info
? info
->page_action_command
.get() : NULL
;
45 const Command
* CommandsInfo::GetScriptBadgeCommand(const Extension
* extension
) {
46 CommandsInfo
* info
= static_cast<CommandsInfo
*>(
47 extension
->GetManifestData(keys::kCommands
));
48 return info
? info
->script_badge_command
.get() : NULL
;
52 const CommandMap
* CommandsInfo::GetNamedCommands(const Extension
* extension
) {
53 CommandsInfo
* info
= static_cast<CommandsInfo
*>(
54 extension
->GetManifestData(keys::kCommands
));
55 return info
? &info
->named_commands
: NULL
;
58 CommandsHandler::CommandsHandler() {
61 CommandsHandler::~CommandsHandler() {
64 bool CommandsHandler::Parse(Extension
* extension
, base::string16
* error
) {
65 if (!extension
->manifest()->HasKey(keys::kCommands
)) {
66 scoped_ptr
<CommandsInfo
> commands_info(new CommandsInfo
);
67 MaybeSetBrowserActionDefault(extension
, commands_info
.get());
68 extension
->SetManifestData(keys::kCommands
,
69 commands_info
.release());
73 const base::DictionaryValue
* dict
= NULL
;
74 if (!extension
->manifest()->GetDictionary(keys::kCommands
, &dict
)) {
75 *error
= base::ASCIIToUTF16(manifest_errors::kInvalidCommandsKey
);
79 scoped_ptr
<CommandsInfo
> commands_info(new CommandsInfo
);
81 int command_index
= 0;
82 int keybindings_found
= 0;
83 for (base::DictionaryValue::Iterator
iter(*dict
); !iter
.IsAtEnd();
87 const base::DictionaryValue
* command
= NULL
;
88 if (!iter
.value().GetAsDictionary(&command
)) {
89 *error
= ErrorUtils::FormatErrorMessageUTF16(
90 manifest_errors::kInvalidKeyBindingDictionary
,
91 base::IntToString(command_index
));
95 scoped_ptr
<extensions::Command
> binding(new Command());
96 if (!binding
->Parse(command
, iter
.key(), command_index
, error
))
97 return false; // |error| already set.
99 if (binding
->accelerator().key_code() != ui::VKEY_UNKNOWN
) {
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());
114 } else if (command_name
==
115 manifest_values::kScriptBadgeCommandEvent
) {
116 commands_info
->script_badge_command
.reset(binding
.release());
118 if (command_name
[0] != '_') // All commands w/underscore are reserved.
119 commands_info
->named_commands
[command_name
] = *binding
.get();
123 MaybeSetBrowserActionDefault(extension
, commands_info
.get());
125 extension
->SetManifestData(keys::kCommands
,
126 commands_info
.release());
130 bool CommandsHandler::AlwaysParseForType(Manifest::Type type
) const {
131 return type
== Manifest::TYPE_EXTENSION
||
132 type
== Manifest::TYPE_LEGACY_PACKAGED_APP
||
133 type
== Manifest::TYPE_PLATFORM_APP
;
136 void CommandsHandler::MaybeSetBrowserActionDefault(const Extension
* extension
,
137 CommandsInfo
* info
) {
138 if (extension
->manifest()->HasKey(keys::kBrowserAction
) &&
139 !info
->browser_action_command
.get()) {
140 info
->browser_action_command
.reset(
141 new Command(manifest_values::kBrowserActionCommandEvent
,
148 const std::vector
<std::string
> CommandsHandler::Keys() const {
149 return SingleKey(keys::kCommands
);
152 } // namespace extensions