1 // Copyright 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 #import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_controller.h"
7 #include "base/strings/sys_string_conversions.h"
8 #include "chrome/browser/extensions/active_script_controller.h"
9 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
10 #include "chrome/browser/extensions/extension_action_manager.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/extension_tab_util.h"
13 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_window.h"
17 #include "chrome/browser/ui/chrome_pages.h"
18 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
19 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
20 #include "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
21 #include "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
22 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
23 #include "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
24 #include "chrome/common/extensions/manifest_url_handler.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 "extensions/browser/extension_prefs.h"
31 #include "extensions/browser/extension_system.h"
32 #include "extensions/browser/uninstall_reason.h"
33 #include "extensions/common/constants.h"
34 #include "extensions/common/extension.h"
35 #include "extensions/common/extension_urls.h"
36 #include "extensions/common/manifest_handlers/options_page_info.h"
37 #include "ui/base/l10n/l10n_util_mac.h"
39 using content::OpenURLParams;
40 using content::Referrer;
41 using content::WebContents;
42 using extensions::Extension;
44 // A class that shows a confirmation dialog to uninstall the given extension.
45 // Also acts as the extension's UI delegate in order to display the dialog.
46 class AsyncUninstaller : public extensions::ExtensionUninstallDialog::Delegate {
48 AsyncUninstaller(const Extension* extension, Browser* browser)
49 : extension_(extension),
50 profile_(browser->profile()) {
51 extension_uninstall_dialog_.reset(
52 extensions::ExtensionUninstallDialog::Create(
53 profile_, browser->window()->GetNativeWindow(), this));
54 extension_uninstall_dialog_->ConfirmUninstall(extension_);
57 virtual ~AsyncUninstaller() {}
59 // ExtensionUninstallDialog::Delegate:
60 virtual void ExtensionUninstallAccepted() OVERRIDE {
61 extensions::ExtensionSystem::Get(profile_)
63 ->UninstallExtension(extension_->id(),
64 extensions::UNINSTALL_REASON_USER_INITIATED,
65 base::Bind(&base::DoNothing),
68 virtual void ExtensionUninstallCanceled() OVERRIDE {}
71 // The extension that's being uninstalled.
72 const Extension* extension_;
74 // The current profile. Weak.
77 scoped_ptr<extensions::ExtensionUninstallDialog> extension_uninstall_dialog_;
79 DISALLOW_COPY_AND_ASSIGN(AsyncUninstaller);
82 @interface ExtensionActionContextMenuController ()
83 - (void)onExtensionName:(id)sender;
84 - (void)onAlwaysRun:(id)sender;
85 - (void)onOptions:(id)sender;
86 - (void)onUninstall:(id)sender;
87 - (void)onHide:(id)sender;
88 - (void)onManage:(id)sender;
89 - (void)onInspect:(id)sender;
92 @implementation ExtensionActionContextMenuController
94 - (id)initWithExtension:(const Extension*)extension
95 browser:(Browser*)browser
96 extensionAction:(ExtensionAction*)action{
97 if ((self = [super init])) {
99 extension_ = extension;
105 - (void)populateMenu:(NSMenu*)menu {
106 [menu setAutoenablesItems:NO];
110 [menu addItemWithTitle:base::SysUTF8ToNSString(extension_->name())
111 action:@selector(onExtensionName:)
113 [item setTarget:self];
114 [item setEnabled:extensions::ManifestURL::GetHomepageURL(
115 extension_).is_valid()];
118 [menu addItem:[NSMenuItem separatorItem]];
120 // Always Run. Only displayed if there is an active script injection action.
121 content::WebContents* activeTab =
122 browser_->tab_strip_model()->GetActiveWebContents();
124 extensions::ActiveScriptController::GetForWebContents(activeTab)
125 ->WantsToRun(extension_)) {
126 item = [menu addItemWithTitle:
127 l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_ALWAYS_RUN)
128 action:@selector(onAlwaysRun:)
130 [item setTarget:self];
134 item = [menu addItemWithTitle:
135 l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_OPTIONS_MENU_ITEM)
136 action:@selector(onOptions:)
138 [item setTarget:self];
139 [item setEnabled:extensions::OptionsPageInfo::GetOptionsPage(
140 extension_).spec().length() > 0];
144 item = [menu addItemWithTitle:
145 l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_UNINSTALL)
146 action:@selector(onUninstall:)
148 [item setTarget:self];
150 // Hide. Only used for browser actions.
151 if (extensions::ExtensionActionManager::Get(
152 browser_->profile())->GetBrowserAction(*extension_)) {
153 item = [menu addItemWithTitle:
154 l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_HIDE_BUTTON)
155 action:@selector(onHide:)
157 [item setTarget:self];
161 [menu addItem:[NSMenuItem separatorItem]];
164 item = [menu addItemWithTitle:
165 l10n_util::GetNSStringWithFixup(IDS_MANAGE_EXTENSION)
166 action:@selector(onManage:)
168 [item setTarget:self];
171 PrefService* service = browser_->profile()->GetPrefs();
172 bool devMode = service->GetBoolean(prefs::kExtensionsUIDeveloperMode);
174 item = [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(
175 IDS_EXTENSION_ACTION_INSPECT_POPUP)
176 action:@selector(onInspect:)
178 [item setTarget:self];
182 - (void)onExtensionName:(id)sender {
183 GURL url(extension_urls::GetWebstoreItemDetailURLPrefix() + extension_->id());
184 OpenURLParams params(url,
187 ui::PAGE_TRANSITION_LINK,
189 browser_->OpenURL(params);
192 - (void)onAlwaysRun:(id)sender {
193 content::WebContents* activeTab =
194 browser_->tab_strip_model()->GetActiveWebContents();
196 extensions::ActiveScriptController::GetForWebContents(activeTab)
197 ->AlwaysRunOnVisibleOrigin(extension_);
201 - (void)onOptions:(id)sender {
202 DCHECK(!extensions::OptionsPageInfo::GetOptionsPage(extension_).is_empty());
203 extensions::ExtensionTabUtil::OpenOptionsPage(extension_, browser_);
206 - (void)onUninstall:(id)sender {
207 uninstaller_.reset(new AsyncUninstaller(extension_, browser_));
210 - (void)onHide:(id)sender {
211 extensions::ExtensionActionAPI::SetBrowserActionVisibility(
212 extensions::ExtensionPrefs::Get(browser_->profile()),
217 - (void)onManage:(id)sender {
218 chrome::ShowExtensions(browser_, extension_->id());
221 - (void)onInspect:(id)sender {
222 BrowserWindowCocoa* window =
223 static_cast<BrowserWindowCocoa*>(browser_->window());
224 ToolbarController* toolbarController =
225 [window->cocoa_controller() toolbarController];
226 LocationBarViewMac* locationBarView = [toolbarController locationBarBridge];
228 extensions::ExtensionActionManager* actionManager =
229 extensions::ExtensionActionManager::Get(browser_->profile());
230 NSPoint popupPoint = NSZeroPoint;
231 if (actionManager->GetPageAction(*extension_) == action_) {
232 popupPoint = locationBarView->GetPageActionBubblePoint(action_);
233 } else if (actionManager->GetBrowserAction(*extension_) == action_) {
234 BrowserActionsController* controller =
235 [toolbarController browserActionsController];
236 popupPoint = [controller popupPointForBrowserAction:extension_];
238 NOTREACHED() << "action_ is not a page action or browser action?";
241 content::WebContents* activeTab =
242 browser_->tab_strip_model()->GetActiveWebContents();
246 int tabId = extensions::ExtensionTabUtil::GetTabId(activeTab);
248 GURL url = action_->GetPopupUrl(tabId);
252 [ExtensionPopupController showURL:url
254 anchoredAt:popupPoint
255 arrowLocation:info_bubble::kTopRight