Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_context_menu_model.cc
bloba54ac2ceab3f0f04b9a406c2052edf6dc00df0bb
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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/extension_context_menu_model.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/app/chrome_command_ids.h"
10 #include "chrome/browser/extensions/active_script_controller.h"
11 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
12 #include "chrome/browser/extensions/context_menu_matcher.h"
13 #include "chrome/browser/extensions/extension_action.h"
14 #include "chrome/browser/extensions/extension_action_manager.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_tab_util.h"
17 #include "chrome/browser/extensions/menu_manager.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/sessions/session_tab_helper.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_window.h"
22 #include "chrome/browser/ui/chrome_pages.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/common/extensions/extension_constants.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/grit/chromium_strings.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/context_menu_params.h"
31 #include "extensions/browser/extension_prefs.h"
32 #include "extensions/browser/extension_registry.h"
33 #include "extensions/browser/extension_system.h"
34 #include "extensions/browser/management_policy.h"
35 #include "extensions/browser/uninstall_reason.h"
36 #include "extensions/common/extension.h"
37 #include "extensions/common/feature_switch.h"
38 #include "extensions/common/manifest_handlers/options_page_info.h"
39 #include "extensions/common/manifest_url_handlers.h"
40 #include "ui/base/l10n/l10n_util.h"
42 using content::OpenURLParams;
43 using content::Referrer;
44 using content::WebContents;
45 using extensions::Extension;
46 using extensions::ExtensionActionAPI;
47 using extensions::ExtensionPrefs;
48 using extensions::MenuItem;
49 using extensions::MenuManager;
51 namespace {
53 // Returns true if the given |item| is of the given |type|.
54 bool MenuItemMatchesAction(ExtensionContextMenuModel::ActionType type,
55 const MenuItem* item) {
56 if (type == ExtensionContextMenuModel::NO_ACTION)
57 return false;
59 const MenuItem::ContextList& contexts = item->contexts();
61 if (contexts.Contains(MenuItem::ALL))
62 return true;
63 if (contexts.Contains(MenuItem::PAGE_ACTION) &&
64 (type == ExtensionContextMenuModel::PAGE_ACTION))
65 return true;
66 if (contexts.Contains(MenuItem::BROWSER_ACTION) &&
67 (type == ExtensionContextMenuModel::BROWSER_ACTION))
68 return true;
70 return false;
73 // Returns the id for the visibility command for the given |extension|, or -1
74 // if none should be shown.
75 int GetVisibilityStringId(Profile* profile, const Extension* extension) {
76 DCHECK(profile);
77 int string_id = -1;
78 if (!extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) {
79 // Without the toolbar redesign, we only show the visibility toggle for
80 // browser actions, and only give the option to hide.
81 if (extensions::ExtensionActionManager::Get(profile)->GetBrowserAction(
82 *extension)) {
83 string_id = IDS_EXTENSIONS_HIDE_BUTTON;
85 } else {
86 // With the redesign, we display "show" or "hide" based on the icon's
87 // visibility.
88 bool visible = ExtensionActionAPI::GetBrowserActionVisibility(
89 ExtensionPrefs::Get(profile), extension->id());
90 string_id =
91 visible ? IDS_EXTENSIONS_HIDE_BUTTON : IDS_EXTENSIONS_SHOW_BUTTON;
93 return string_id;
96 } // namespace
98 ExtensionContextMenuModel::ExtensionContextMenuModel(const Extension* extension,
99 Browser* browser,
100 PopupDelegate* delegate)
101 : SimpleMenuModel(this),
102 extension_id_(extension->id()),
103 browser_(browser),
104 profile_(browser->profile()),
105 delegate_(delegate),
106 action_type_(NO_ACTION),
107 extension_items_count_(0) {
108 InitMenu(extension);
110 if (profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode) &&
111 delegate_) {
112 AddSeparator(ui::NORMAL_SEPARATOR);
113 AddItemWithStringId(INSPECT_POPUP, IDS_EXTENSION_ACTION_INSPECT_POPUP);
117 ExtensionContextMenuModel::ExtensionContextMenuModel(const Extension* extension,
118 Browser* browser)
119 : SimpleMenuModel(this),
120 extension_id_(extension->id()),
121 browser_(browser),
122 profile_(browser->profile()),
123 delegate_(NULL),
124 action_type_(NO_ACTION),
125 extension_items_count_(0) {
126 InitMenu(extension);
129 bool ExtensionContextMenuModel::IsCommandIdChecked(int command_id) const {
130 if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
131 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST)
132 return extension_items_->IsCommandIdChecked(command_id);
133 return false;
136 bool ExtensionContextMenuModel::IsCommandIdEnabled(int command_id) const {
137 const Extension* extension = GetExtension();
138 if (!extension)
139 return false;
141 if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
142 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
143 return extension_items_->IsCommandIdEnabled(command_id);
144 } else if (command_id == CONFIGURE) {
145 return extensions::OptionsPageInfo::HasOptionsPage(extension);
146 } else if (command_id == NAME) {
147 // The NAME links to the Homepage URL. If the extension doesn't have a
148 // homepage, we just disable this menu item.
149 return extensions::ManifestURL::GetHomepageURL(extension).is_valid();
150 } else if (command_id == INSPECT_POPUP) {
151 WebContents* web_contents = GetActiveWebContents();
152 if (!web_contents)
153 return false;
155 return extension_action_ &&
156 extension_action_->HasPopup(SessionTabHelper::IdForTab(web_contents));
157 } else if (command_id == UNINSTALL) {
158 // Some extension types can not be uninstalled.
159 extensions::ManagementPolicy* policy =
160 extensions::ExtensionSystem::Get(profile_)->management_policy();
161 return policy->UserMayModifySettings(extension, nullptr) &&
162 !policy->MustRemainInstalled(extension, nullptr);
164 return true;
167 bool ExtensionContextMenuModel::GetAcceleratorForCommandId(
168 int command_id, ui::Accelerator* accelerator) {
169 return false;
172 void ExtensionContextMenuModel::ExecuteCommand(int command_id,
173 int event_flags) {
174 const Extension* extension = GetExtension();
175 if (!extension)
176 return;
178 if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
179 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
180 WebContents* web_contents =
181 browser_->tab_strip_model()->GetActiveWebContents();
182 DCHECK(extension_items_);
183 extension_items_->ExecuteCommand(
184 command_id, web_contents, content::ContextMenuParams());
185 return;
188 switch (command_id) {
189 case NAME: {
190 OpenURLParams params(extensions::ManifestURL::GetHomepageURL(extension),
191 Referrer(), NEW_FOREGROUND_TAB,
192 ui::PAGE_TRANSITION_LINK, false);
193 browser_->OpenURL(params);
194 break;
196 case ALWAYS_RUN: {
197 WebContents* web_contents = GetActiveWebContents();
198 if (web_contents) {
199 extensions::ActiveScriptController::GetForWebContents(web_contents)
200 ->AlwaysRunOnVisibleOrigin(extension);
202 break;
204 case CONFIGURE:
205 DCHECK(extensions::OptionsPageInfo::HasOptionsPage(extension));
206 extensions::ExtensionTabUtil::OpenOptionsPage(extension, browser_);
207 break;
208 case TOGGLE_VISIBILITY: {
209 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
210 bool visible = ExtensionActionAPI::GetBrowserActionVisibility(
211 prefs, extension->id());
212 ExtensionActionAPI::SetBrowserActionVisibility(
213 prefs, extension->id(), !visible);
214 break;
216 case UNINSTALL: {
217 AddRef(); // Balanced in Accepted() and Canceled()
218 extension_uninstall_dialog_.reset(
219 extensions::ExtensionUninstallDialog::Create(
220 profile_, browser_->window()->GetNativeWindow(), this));
221 extension_uninstall_dialog_->ConfirmUninstall(extension);
222 break;
224 case MANAGE: {
225 chrome::ShowExtensions(browser_, extension->id());
226 break;
228 case INSPECT_POPUP: {
229 delegate_->InspectPopup();
230 break;
232 default:
233 NOTREACHED() << "Unknown option";
234 break;
238 void ExtensionContextMenuModel::ExtensionUninstallAccepted() {
239 if (GetExtension()) {
240 extensions::ExtensionSystem::Get(profile_)
241 ->extension_service()
242 ->UninstallExtension(extension_id_,
243 extensions::UNINSTALL_REASON_USER_INITIATED,
244 base::Bind(&base::DoNothing),
245 NULL);
247 Release();
250 void ExtensionContextMenuModel::ExtensionUninstallCanceled() {
251 Release();
254 ExtensionContextMenuModel::~ExtensionContextMenuModel() {}
256 void ExtensionContextMenuModel::InitMenu(const Extension* extension) {
257 DCHECK(extension);
259 extensions::ExtensionActionManager* extension_action_manager =
260 extensions::ExtensionActionManager::Get(profile_);
261 extension_action_ = extension_action_manager->GetBrowserAction(*extension);
262 if (!extension_action_) {
263 extension_action_ = extension_action_manager->GetPageAction(*extension);
264 if (extension_action_)
265 action_type_ = PAGE_ACTION;
266 } else {
267 action_type_ = BROWSER_ACTION;
270 extension_items_.reset(new extensions::ContextMenuMatcher(
271 profile_, this, this, base::Bind(MenuItemMatchesAction, action_type_)));
273 std::string extension_name = extension->name();
274 // Ampersands need to be escaped to avoid being treated like
275 // mnemonics in the menu.
276 base::ReplaceChars(extension_name, "&", "&&", &extension_name);
277 AddItem(NAME, base::UTF8ToUTF16(extension_name));
278 AppendExtensionItems();
279 AddSeparator(ui::NORMAL_SEPARATOR);
281 // Add the "Always Allow" item for adding persisted permissions for script
282 // injections if there is an active action for this extension. Note that this
283 // will add it to *all* extension action context menus, not just the one
284 // attached to the script injection request icon, but that's okay.
285 WebContents* web_contents = GetActiveWebContents();
286 if (web_contents &&
287 extensions::ActiveScriptController::GetForWebContents(web_contents)
288 ->WantsToRun(extension)) {
289 AddItemWithStringId(ALWAYS_RUN, IDS_EXTENSIONS_ALWAYS_RUN);
292 AddItemWithStringId(CONFIGURE, IDS_EXTENSIONS_OPTIONS_MENU_ITEM);
293 AddItem(UNINSTALL, l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
295 // Add a toggle visibility (show/hide) if the extension icon is shown on the
296 // toolbar.
297 int visibility_string_id = GetVisibilityStringId(profile_, extension);
298 if (visibility_string_id != -1)
299 AddItemWithStringId(TOGGLE_VISIBILITY, visibility_string_id);
301 AddSeparator(ui::NORMAL_SEPARATOR);
302 AddItemWithStringId(MANAGE, IDS_MANAGE_EXTENSION);
305 const Extension* ExtensionContextMenuModel::GetExtension() const {
306 return extensions::ExtensionRegistry::Get(profile_)
307 ->enabled_extensions()
308 .GetByID(extension_id_);
311 void ExtensionContextMenuModel::AppendExtensionItems() {
312 extension_items_->Clear();
314 MenuManager* menu_manager = MenuManager::Get(profile_);
315 if (!menu_manager ||
316 !menu_manager->MenuItems(MenuItem::ExtensionKey(extension_id_)))
317 return;
319 AddSeparator(ui::NORMAL_SEPARATOR);
321 extension_items_count_ = 0;
322 extension_items_->AppendExtensionItems(MenuItem::ExtensionKey(extension_id_),
323 base::string16(),
324 &extension_items_count_,
325 true); // is_action_menu
328 content::WebContents* ExtensionContextMenuModel::GetActiveWebContents() const {
329 return browser_->tab_strip_model()->GetActiveWebContents();