Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_context_menu_model.cc
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.
4
5 #include "chrome/browser/extensions/extension_context_menu_model.h"
6
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/ui/browser.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/chrome_pages.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
23 #include "chrome/common/extensions/extension_constants.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 "content/public/browser/web_contents.h"
28 #include "content/public/common/context_menu_params.h"
29 #include "extensions/browser/extension_prefs.h"
30 #include "extensions/browser/extension_registry.h"
31 #include "extensions/browser/extension_system.h"
32 #include "extensions/browser/management_policy.h"
33 #include "extensions/browser/uninstall_reason.h"
34 #include "extensions/common/extension.h"
35 #include "grit/chromium_strings.h"
36 #include "grit/generated_resources.h"
37 #include "ui/base/l10n/l10n_util.h"
38
39 using content::OpenURLParams;
40 using content::Referrer;
41 using content::WebContents;
42 using extensions::Extension;
43 using extensions::MenuItem;
44 using extensions::MenuManager;
45
46 namespace {
47
48 // Returns true if the given |item| is of the given |type|.
49 bool MenuItemMatchesAction(ExtensionContextMenuModel::ActionType type,
50                            const MenuItem* item) {
51   if (type == ExtensionContextMenuModel::NO_ACTION)
52     return false;
53
54   const MenuItem::ContextList& contexts = item->contexts();
55
56   if (contexts.Contains(MenuItem::ALL))
57     return true;
58   if (contexts.Contains(MenuItem::PAGE_ACTION) &&
59       (type == ExtensionContextMenuModel::PAGE_ACTION))
60     return true;
61   if (contexts.Contains(MenuItem::BROWSER_ACTION) &&
62       (type == ExtensionContextMenuModel::BROWSER_ACTION))
63     return true;
64
65   return false;
66 }
67
68 }  // namespace
69
70 ExtensionContextMenuModel::ExtensionContextMenuModel(const Extension* extension,
71                                                      Browser* browser,
72                                                      PopupDelegate* delegate)
73     : SimpleMenuModel(this),
74       extension_id_(extension->id()),
75       browser_(browser),
76       profile_(browser->profile()),
77       delegate_(delegate),
78       action_type_(NO_ACTION),
79       extension_items_count_(0) {
80   InitMenu(extension);
81
82   if (profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode) &&
83       delegate_) {
84     AddSeparator(ui::NORMAL_SEPARATOR);
85     AddItemWithStringId(INSPECT_POPUP, IDS_EXTENSION_ACTION_INSPECT_POPUP);
86   }
87 }
88
89 ExtensionContextMenuModel::ExtensionContextMenuModel(const Extension* extension,
90                                                      Browser* browser)
91     : SimpleMenuModel(this),
92       extension_id_(extension->id()),
93       browser_(browser),
94       profile_(browser->profile()),
95       delegate_(NULL),
96       action_type_(NO_ACTION),
97       extension_items_count_(0) {
98   InitMenu(extension);
99 }
100
101 bool ExtensionContextMenuModel::IsCommandIdChecked(int command_id) const {
102   if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
103       command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST)
104     return extension_items_->IsCommandIdChecked(command_id);
105   return false;
106 }
107
108 bool ExtensionContextMenuModel::IsCommandIdEnabled(int command_id) const {
109   const Extension* extension = GetExtension();
110   if (!extension)
111     return false;
112
113   if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
114       command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
115     return extension_items_->IsCommandIdEnabled(command_id);
116   } else if (command_id == CONFIGURE) {
117     return
118         extensions::ManifestURL::GetOptionsPage(extension).spec().length() > 0;
119   } else if (command_id == NAME) {
120     // The NAME links to the Homepage URL. If the extension doesn't have a
121     // homepage, we just disable this menu item.
122     return extensions::ManifestURL::GetHomepageURL(extension).is_valid();
123   } else if (command_id == INSPECT_POPUP) {
124     WebContents* web_contents = GetActiveWebContents();
125     if (!web_contents)
126       return false;
127
128     return extension_action_ &&
129         extension_action_->HasPopup(SessionID::IdForTab(web_contents));
130   } else if (command_id == UNINSTALL) {
131     // Some extension types can not be uninstalled.
132     return extensions::ExtensionSystem::Get(
133         profile_)->management_policy()->UserMayModifySettings(extension, NULL);
134   }
135   return true;
136 }
137
138 bool ExtensionContextMenuModel::GetAcceleratorForCommandId(
139     int command_id, ui::Accelerator* accelerator) {
140   return false;
141 }
142
143 void ExtensionContextMenuModel::ExecuteCommand(int command_id,
144                                                int event_flags) {
145   const Extension* extension = GetExtension();
146   if (!extension)
147     return;
148
149   if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
150       command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
151     WebContents* web_contents =
152         browser_->tab_strip_model()->GetActiveWebContents();
153     DCHECK(extension_items_);
154     extension_items_->ExecuteCommand(
155         command_id, web_contents, content::ContextMenuParams());
156     return;
157   }
158
159   switch (command_id) {
160     case NAME: {
161       OpenURLParams params(extensions::ManifestURL::GetHomepageURL(extension),
162                            Referrer(), NEW_FOREGROUND_TAB,
163                            content::PAGE_TRANSITION_LINK, false);
164       browser_->OpenURL(params);
165       break;
166     }
167     case ALWAYS_RUN: {
168       WebContents* web_contents = GetActiveWebContents();
169       if (web_contents) {
170         extensions::ActiveScriptController::GetForWebContents(web_contents)
171             ->AlwaysRunOnVisibleOrigin(extension);
172       }
173       break;
174     }
175     case CONFIGURE:
176       DCHECK(!extensions::ManifestURL::GetOptionsPage(extension).is_empty());
177       extensions::ExtensionTabUtil::OpenOptionsPage(extension, browser_);
178       break;
179     case HIDE: {
180       extensions::ExtensionActionAPI::SetBrowserActionVisibility(
181           extensions::ExtensionPrefs::Get(profile_), extension->id(), false);
182       break;
183     }
184     case UNINSTALL: {
185       AddRef();  // Balanced in Accepted() and Canceled()
186       extension_uninstall_dialog_.reset(
187           extensions::ExtensionUninstallDialog::Create(
188               profile_, browser_->window()->GetNativeWindow(), this));
189       extension_uninstall_dialog_->ConfirmUninstall(extension);
190       break;
191     }
192     case MANAGE: {
193       chrome::ShowExtensions(browser_, extension->id());
194       break;
195     }
196     case INSPECT_POPUP: {
197       delegate_->InspectPopup();
198       break;
199     }
200     default:
201      NOTREACHED() << "Unknown option";
202      break;
203   }
204 }
205
206 void ExtensionContextMenuModel::ExtensionUninstallAccepted() {
207   if (GetExtension()) {
208     extensions::ExtensionSystem::Get(profile_)
209         ->extension_service()
210         ->UninstallExtension(extension_id_,
211                              extensions::UNINSTALL_REASON_USER_INITIATED,
212                              base::Bind(&base::DoNothing),
213                              NULL);
214   }
215   Release();
216 }
217
218 void ExtensionContextMenuModel::ExtensionUninstallCanceled() {
219   Release();
220 }
221
222 ExtensionContextMenuModel::~ExtensionContextMenuModel() {}
223
224 void ExtensionContextMenuModel::InitMenu(const Extension* extension) {
225   DCHECK(extension);
226
227   extensions::ExtensionActionManager* extension_action_manager =
228       extensions::ExtensionActionManager::Get(profile_);
229   extension_action_ = extension_action_manager->GetBrowserAction(*extension);
230   if (!extension_action_) {
231     extension_action_ = extension_action_manager->GetPageAction(*extension);
232     if (extension_action_)
233       action_type_ = PAGE_ACTION;
234   } else {
235     action_type_ = BROWSER_ACTION;
236   }
237
238   extension_items_.reset(new extensions::ContextMenuMatcher(
239       profile_, this, this, base::Bind(MenuItemMatchesAction, action_type_)));
240
241   std::string extension_name = extension->name();
242   // Ampersands need to be escaped to avoid being treated like
243   // mnemonics in the menu.
244   base::ReplaceChars(extension_name, "&", "&&", &extension_name);
245   AddItem(NAME, base::UTF8ToUTF16(extension_name));
246   AppendExtensionItems();
247   AddSeparator(ui::NORMAL_SEPARATOR);
248
249   // Add the "Always Allow" item for adding persisted permissions for script
250   // injections if there is an active action for this extension. Note that this
251   // will add it to *all* extension action context menus, not just the one
252   // attached to the script injection request icon, but that's okay.
253   WebContents* web_contents = GetActiveWebContents();
254   if (web_contents &&
255       extensions::ActiveScriptController::GetForWebContents(web_contents)
256           ->HasActiveScriptAction(extension)) {
257     AddItemWithStringId(ALWAYS_RUN, IDS_EXTENSIONS_ALWAYS_RUN);
258   }
259
260   AddItemWithStringId(CONFIGURE, IDS_EXTENSIONS_OPTIONS_MENU_ITEM);
261   AddItem(UNINSTALL, l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
262   if (extension_action_manager->GetBrowserAction(*extension))
263     AddItemWithStringId(HIDE, IDS_EXTENSIONS_HIDE_BUTTON);
264   AddSeparator(ui::NORMAL_SEPARATOR);
265   AddItemWithStringId(MANAGE, IDS_MANAGE_EXTENSION);
266 }
267
268 const Extension* ExtensionContextMenuModel::GetExtension() const {
269   return extensions::ExtensionRegistry::Get(profile_)
270       ->enabled_extensions()
271       .GetByID(extension_id_);
272 }
273
274 void ExtensionContextMenuModel::AppendExtensionItems() {
275   extension_items_->Clear();
276
277   MenuManager* menu_manager = MenuManager::Get(profile_);
278   if (!menu_manager ||
279       !menu_manager->MenuItems(MenuItem::ExtensionKey(extension_id_)))
280     return;
281
282   AddSeparator(ui::NORMAL_SEPARATOR);
283
284   extension_items_count_ = 0;
285   extension_items_->AppendExtensionItems(MenuItem::ExtensionKey(extension_id_),
286                                          base::string16(),
287                                          &extension_items_count_,
288                                          true);  // is_action_menu
289 }
290
291 content::WebContents* ExtensionContextMenuModel::GetActiveWebContents() const {
292   return browser_->tab_strip_model()->GetActiveWebContents();
293 }