blob: bd98ff221d2904a94edc81b7d2ed6412d9328f61 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/download/download_shelf_context_menu.h"
#include "base/command_line.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_crx_util.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/safe_browsing/download_feedback_service.h"
#include "chrome/browser/safe_browsing/download_protection_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/common/content_switches.h"
#include "extensions/common/extension.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
using content::DownloadItem;
using extensions::Extension;
namespace {
// Returns true if downloads resumption is enabled.
bool IsDownloadResumptionEnabled() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
return command_line.HasSwitch(switches::kEnableDownloadResumption);
}
} // namespace
DownloadShelfContextMenu::~DownloadShelfContextMenu() {
DetachFromDownloadItem();
}
DownloadShelfContextMenu::DownloadShelfContextMenu(
DownloadItem* download_item,
content::PageNavigator* navigator)
: download_item_(download_item),
navigator_(navigator) {
DCHECK(download_item_);
download_item_->AddObserver(this);
}
ui::SimpleMenuModel* DownloadShelfContextMenu::GetMenuModel() {
ui::SimpleMenuModel* model = NULL;
if (!download_item_)
return NULL;
DownloadItemModel download_model(download_item_);
// We shouldn't be opening a context menu for a dangerous download, unless it
// is a malicious download.
DCHECK(!download_model.IsDangerous() || download_model.MightBeMalicious());
if (download_model.IsMalicious())
model = GetMaliciousMenuModel();
else if (download_model.MightBeMalicious())
model = GetMaybeMaliciousMenuModel();
else if (download_item_->GetState() == DownloadItem::COMPLETE)
model = GetFinishedMenuModel();
else if (download_item_->GetState() == DownloadItem::INTERRUPTED)
model = GetInterruptedMenuModel();
else
model = GetInProgressMenuModel();
return model;
}
bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const {
if (!download_item_)
return false;
switch (static_cast<ContextMenuCommands>(command_id)) {
case SHOW_IN_FOLDER:
return download_item_->CanShowInFolder();
case OPEN_WHEN_COMPLETE:
case PLATFORM_OPEN:
return download_item_->CanOpenDownload() &&
!download_crx_util::IsExtensionDownload(*download_item_);
case ALWAYS_OPEN_TYPE:
// For temporary downloads, the target filename might be a temporary
// filename. Don't base an "Always open" decision based on it. Also
// exclude extensions.
return download_item_->CanOpenDownload() &&
!download_crx_util::IsExtensionDownload(*download_item_);
case CANCEL:
return !download_item_->IsDone();
case TOGGLE_PAUSE:
return !download_item_->IsDone();
case DISCARD:
case KEEP:
case REPORT:
case LEARN_MORE_SCANNING:
case LEARN_MORE_INTERRUPTED:
return true;
}
return false;
}
bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id) const {
if (!download_item_)
return false;
switch (command_id) {
case OPEN_WHEN_COMPLETE:
return download_item_->GetOpenWhenComplete() ||
download_crx_util::IsExtensionDownload(*download_item_);
case ALWAYS_OPEN_TYPE:
return download_item_->ShouldOpenFileBasedOnExtension();
case TOGGLE_PAUSE:
return download_item_->IsPaused();
}
return false;
}
void DownloadShelfContextMenu::ExecuteCommand(int command_id, int event_flags) {
if (!download_item_)
return;
switch (static_cast<ContextMenuCommands>(command_id)) {
case SHOW_IN_FOLDER:
download_item_->ShowDownloadInShell();
break;
case OPEN_WHEN_COMPLETE:
download_item_->OpenDownload();
break;
case ALWAYS_OPEN_TYPE: {
DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(
download_item_->GetBrowserContext());
base::FilePath path = download_item_->GetTargetFilePath();
if (!IsCommandIdChecked(ALWAYS_OPEN_TYPE))
prefs->EnableAutoOpenBasedOnExtension(path);
else
prefs->DisableAutoOpenBasedOnExtension(path);
break;
}
case PLATFORM_OPEN:
DownloadItemModel(download_item_).OpenUsingPlatformHandler();
break;
case CANCEL:
download_item_->Cancel(true /* Cancelled by user */);
break;
case TOGGLE_PAUSE:
if (download_item_->GetState() == DownloadItem::IN_PROGRESS &&
!download_item_->IsPaused()) {
download_item_->Pause();
} else {
download_item_->Resume();
}
break;
case DISCARD:
download_item_->Remove();
break;
case KEEP:
download_item_->ValidateDangerousDownload();
break;
case REPORT: {
#if defined(FULL_SAFE_BROWSING)
using safe_browsing::DownloadProtectionService;
DownloadItemModel download_model(download_item_);
if (!download_model.ShouldAllowDownloadFeedback())
break;
SafeBrowsingService* sb_service =
g_browser_process->safe_browsing_service();
DownloadProtectionService* protection_service =
(sb_service ? sb_service->download_protection_service() : NULL);
if (protection_service) {
protection_service->feedback_service()->BeginFeedbackForDownload(
download_item_);
}
#else
// Should only be getting invoked if we are using safe browsing.
NOTREACHED();
#endif
break;
}
case LEARN_MORE_SCANNING: {
#if defined(FULL_SAFE_BROWSING)
using safe_browsing::DownloadProtectionService;
SafeBrowsingService* sb_service =
g_browser_process->safe_browsing_service();
DownloadProtectionService* protection_service =
(sb_service ? sb_service->download_protection_service() : NULL);
if (protection_service) {
protection_service->ShowDetailsForDownload(*download_item_, navigator_);
}
#else
// Should only be getting invoked if we are using safe browsing.
NOTREACHED();
#endif
break;
}
case LEARN_MORE_INTERRUPTED:
navigator_->OpenURL(
content::OpenURLParams(GURL(chrome::kDownloadInterruptedLearnMoreURL),
content::Referrer(),
NEW_FOREGROUND_TAB,
content::PAGE_TRANSITION_LINK,
false));
break;
}
}
bool DownloadShelfContextMenu::GetAcceleratorForCommandId(
int command_id, ui::Accelerator* accelerator) {
return false;
}
bool DownloadShelfContextMenu::IsItemForCommandIdDynamic(int command_id) const {
return command_id == TOGGLE_PAUSE;
}
base::string16 DownloadShelfContextMenu::GetLabelForCommandId(
int command_id) const {
switch (static_cast<ContextMenuCommands>(command_id)) {
case SHOW_IN_FOLDER:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_SHOW);
case OPEN_WHEN_COMPLETE:
if (download_item_ && !download_item_->IsDone())
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN);
case ALWAYS_OPEN_TYPE:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
case PLATFORM_OPEN:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PLATFORM_OPEN);
case CANCEL:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_CANCEL);
case TOGGLE_PAUSE:
if (download_item_ &&
download_item_->GetState() == DownloadItem::IN_PROGRESS &&
!download_item_->IsPaused())
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PAUSE_ITEM);
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_RESUME_ITEM);
case DISCARD:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_DISCARD);
case REPORT:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_REPORT);
case KEEP:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_KEEP);
case LEARN_MORE_SCANNING:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
case LEARN_MORE_INTERRUPTED:
return l10n_util::GetStringUTF16(
IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED);
}
NOTREACHED();
return base::string16();
}
void DownloadShelfContextMenu::DetachFromDownloadItem() {
if (!download_item_)
return;
download_item_->RemoveObserver(this);
download_item_ = NULL;
}
void DownloadShelfContextMenu::OnDownloadDestroyed(DownloadItem* download) {
DCHECK(download_item_ == download);
DetachFromDownloadItem();
}
ui::SimpleMenuModel* DownloadShelfContextMenu::GetInProgressMenuModel() {
if (in_progress_download_menu_model_)
return in_progress_download_menu_model_.get();
in_progress_download_menu_model_.reset(new ui::SimpleMenuModel(this));
in_progress_download_menu_model_->AddCheckItemWithStringId(
OPEN_WHEN_COMPLETE, IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
in_progress_download_menu_model_->AddCheckItemWithStringId(
ALWAYS_OPEN_TYPE, IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
in_progress_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
in_progress_download_menu_model_->AddItemWithStringId(
TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_PAUSE_ITEM);
in_progress_download_menu_model_->AddItemWithStringId(
SHOW_IN_FOLDER, IDS_DOWNLOAD_MENU_SHOW);
in_progress_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
in_progress_download_menu_model_->AddItemWithStringId(
CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
return in_progress_download_menu_model_.get();
}
ui::SimpleMenuModel* DownloadShelfContextMenu::GetFinishedMenuModel() {
if (finished_download_menu_model_)
return finished_download_menu_model_.get();
finished_download_menu_model_.reset(new ui::SimpleMenuModel(this));
finished_download_menu_model_->AddItemWithStringId(
OPEN_WHEN_COMPLETE, IDS_DOWNLOAD_MENU_OPEN);
finished_download_menu_model_->AddCheckItemWithStringId(
ALWAYS_OPEN_TYPE, IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
if (DownloadItemModel(download_item_).ShouldPreferOpeningInBrowser())
finished_download_menu_model_->AddItemWithStringId(
PLATFORM_OPEN, IDS_DOWNLOAD_MENU_PLATFORM_OPEN);
finished_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
finished_download_menu_model_->AddItemWithStringId(
SHOW_IN_FOLDER, IDS_DOWNLOAD_MENU_SHOW);
finished_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
finished_download_menu_model_->AddItemWithStringId(
CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
return finished_download_menu_model_.get();
}
ui::SimpleMenuModel* DownloadShelfContextMenu::GetInterruptedMenuModel() {
#if !defined(OS_WIN)
// If resumption isn't enabled and we aren't on Windows, then none of the
// options here are applicable.
if (!IsDownloadResumptionEnabled())
return GetInProgressMenuModel();
#endif
if (interrupted_download_menu_model_)
return interrupted_download_menu_model_.get();
interrupted_download_menu_model_.reset(new ui::SimpleMenuModel(this));
if (IsDownloadResumptionEnabled()) {
interrupted_download_menu_model_->AddItemWithStringId(
TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_RESUME_ITEM);
}
#if defined(OS_WIN)
// The Help Center article is currently Windows specific.
// TODO(asanka): Enable this for other platforms when the article is expanded
// for other platforms.
interrupted_download_menu_model_->AddItemWithStringId(
LEARN_MORE_INTERRUPTED, IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED);
#endif
if (IsDownloadResumptionEnabled()) {
interrupted_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
interrupted_download_menu_model_->AddItemWithStringId(
CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
}
return interrupted_download_menu_model_.get();
}
ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaybeMaliciousMenuModel() {
if (maybe_malicious_download_menu_model_)
return maybe_malicious_download_menu_model_.get();
maybe_malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
maybe_malicious_download_menu_model_->AddItemWithStringId(
DISCARD, IDS_DOWNLOAD_MENU_DISCARD);
maybe_malicious_download_menu_model_->AddItemWithStringId(
KEEP, IDS_DOWNLOAD_MENU_KEEP);
maybe_malicious_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
maybe_malicious_download_menu_model_->AddItemWithStringId(
LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
return maybe_malicious_download_menu_model_.get();
}
ui::SimpleMenuModel*
DownloadShelfContextMenu::GetMaliciousMenuModel() {
if (malicious_download_menu_model_)
return malicious_download_menu_model_.get();
malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
DownloadItemModel download_model(download_item_);
if (download_model.ShouldAllowDownloadFeedback()) {
malicious_download_menu_model_->AddItemWithStringId(
REPORT, IDS_DOWNLOAD_MENU_REPORT);
}
malicious_download_menu_model_->AddItemWithStringId(
LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
return malicious_download_menu_model_.get();
}