15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_context_menu_model.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action_manager.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_tab_util.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/management_policy.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/manifest_url_handler.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::OpenURLParams;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::Referrer;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExtensionContextMenuModel::ExtensionContextMenuModel(const Extension* extension,
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     Browser* browser,
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     PopupDelegate* delegate)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : SimpleMenuModel(this),
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_id_(extension->id()),
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_(browser),
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(browser->profile()),
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitMenu(extension);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode) &&
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddSeparator(ui::NORMAL_SEPARATOR);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddItemWithStringId(INSPECT_POPUP, IDS_EXTENSION_ACTION_INSPECT_POPUP);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExtensionContextMenuModel::ExtensionContextMenuModel(const Extension* extension,
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     Browser* browser)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : SimpleMenuModel(this),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_id_(extension->id()),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_(browser),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(browser->profile()),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(NULL) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitMenu(extension);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionContextMenuModel::IsCommandIdChecked(int command_id) const {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionContextMenuModel::IsCommandIdEnabled(int command_id) const {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = this->GetExtension();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_id == CONFIGURE) {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::ManifestURL::GetOptionsPage(extension).spec().length() > 0;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command_id == NAME) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The NAME links to the Homepage URL. If the extension doesn't have a
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // homepage, we just disable this menu item.
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return extensions::ManifestURL::GetHomepageURL(extension).is_valid();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command_id == INSPECT_POPUP) {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WebContents* web_contents =
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        browser_->tab_strip_model()->GetActiveWebContents();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!web_contents)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return extension_action_ &&
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extension_action_->HasPopup(SessionID::IdForTab(web_contents));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command_id == UNINSTALL) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Some extension types can not be uninstalled.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return extensions::ExtensionSystem::Get(
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        profile_)->management_policy()->UserMayModifySettings(extension, NULL);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionContextMenuModel::GetAcceleratorForCommandId(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int command_id, ui::Accelerator* accelerator) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionContextMenuModel::ExecuteCommand(int command_id,
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               int event_flags) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = GetExtension();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (command_id) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case NAME: {
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      OpenURLParams params(extensions::ManifestURL::GetHomepageURL(extension),
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           Referrer(), NEW_FOREGROUND_TAB,
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           content::PAGE_TRANSITION_LINK, false);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_->OpenURL(params);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONFIGURE:
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK(!extensions::ManifestURL::GetOptionsPage(extension).is_empty());
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ExtensionTabUtil::OpenOptionsPage(extension, browser_);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HIDE: {
118b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      extensions::ExtensionActionAPI::SetBrowserActionVisibility(
119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          extensions::ExtensionSystem::Get(profile_)->
120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)              extension_service()->extension_prefs(),
121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          extension->id(),
122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          false);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case UNINSTALL: {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddRef();  // Balanced in Accepted() and Canceled()
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_uninstall_dialog_.reset(
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          ExtensionUninstallDialog::Create(profile_, browser_, this));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_uninstall_dialog_->ConfirmUninstall(extension);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case MANAGE: {
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chrome::ShowExtensions(browser_, extension->id());
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case INSPECT_POPUP: {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->InspectPopup(extension_action_);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     NOTREACHED() << "Unknown option";
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     break;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionContextMenuModel::ExtensionUninstallAccepted() {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (GetExtension()) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extensions::ExtensionSystem::Get(profile_)->extension_service()->
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        UninstallExtension(extension_id_, false, NULL);
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionContextMenuModel::ExtensionUninstallCanceled() {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionContextMenuModel::~ExtensionContextMenuModel() {}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionContextMenuModel::InitMenu(const Extension* extension) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(extension);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions::ExtensionActionManager* extension_action_manager =
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extensions::ExtensionActionManager::Get(profile_);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_action_ = extension_action_manager->GetBrowserAction(*extension);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension_action_)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extension_action_ = extension_action_manager->GetPageAction(*extension);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string extension_name = extension->name();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ampersands need to be escaped to avoid being treated like
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mnemonics in the menu.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReplaceChars(extension_name, "&", "&&", &extension_name);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddItem(NAME, UTF8ToUTF16(extension_name));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddSeparator(ui::NORMAL_SEPARATOR);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddItemWithStringId(CONFIGURE, IDS_EXTENSIONS_OPTIONS_MENU_ITEM);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddItem(UNINSTALL, l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (extension_action_manager->GetBrowserAction(*extension))
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddItemWithStringId(HIDE, IDS_EXTENSIONS_HIDE_BUTTON);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddSeparator(ui::NORMAL_SEPARATOR);
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddItemWithStringId(MANAGE, IDS_MANAGE_EXTENSION);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const Extension* ExtensionContextMenuModel::GetExtension() const {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* extension_service =
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->extension_service();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extension_service->GetExtensionById(extension_id_, false);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
188