Home | History | Annotate | Download | only in download
      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/download/download_shelf_context_menu.h"
      6 
      7 #include "base/command_line.h"
      8 #include "chrome/browser/browser_process.h"
      9 #include "chrome/browser/download/download_crx_util.h"
     10 #include "chrome/browser/download/download_item_model.h"
     11 #include "chrome/browser/download/download_prefs.h"
     12 #include "chrome/browser/safe_browsing/download_protection_service.h"
     13 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
     14 #include "chrome/common/extensions/extension.h"
     15 #include "chrome/common/url_constants.h"
     16 #include "content/public/browser/download_item.h"
     17 #include "content/public/browser/download_manager.h"
     18 #include "content/public/browser/page_navigator.h"
     19 #include "content/public/common/content_switches.h"
     20 #include "grit/generated_resources.h"
     21 #include "ui/base/l10n/l10n_util.h"
     22 
     23 using content::DownloadItem;
     24 using extensions::Extension;
     25 
     26 namespace {
     27 
     28 // Returns true if downloads resumption is enabled.
     29 bool IsDownloadResumptionEnabled() {
     30   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
     31   return command_line.HasSwitch(switches::kEnableDownloadResumption);
     32 }
     33 
     34 }  // namespace
     35 
     36 DownloadShelfContextMenu::~DownloadShelfContextMenu() {
     37   DetachFromDownloadItem();
     38 }
     39 
     40 DownloadShelfContextMenu::DownloadShelfContextMenu(
     41     DownloadItem* download_item,
     42     content::PageNavigator* navigator)
     43     : download_item_(download_item),
     44       navigator_(navigator) {
     45   DCHECK(download_item_);
     46   download_item_->AddObserver(this);
     47 }
     48 
     49 ui::SimpleMenuModel* DownloadShelfContextMenu::GetMenuModel() {
     50   ui::SimpleMenuModel* model = NULL;
     51 
     52   if (!download_item_)
     53     return NULL;
     54 
     55   DownloadItemModel download_model(download_item_);
     56   // We shouldn't be opening a context menu for a dangerous download, unless it
     57   // is a malicious download.
     58   DCHECK(!download_model.IsDangerous() || download_model.IsMalicious());
     59 
     60   if (download_model.IsMalicious())
     61     model = GetMaliciousMenuModel();
     62   else if (download_item_->GetState() == DownloadItem::COMPLETE)
     63     model = GetFinishedMenuModel();
     64   else if (download_item_->GetState() == DownloadItem::INTERRUPTED)
     65     model = GetInterruptedMenuModel();
     66   else
     67     model = GetInProgressMenuModel();
     68   return model;
     69 }
     70 
     71 bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const {
     72   if (!download_item_)
     73     return false;
     74 
     75   switch (static_cast<ContextMenuCommands>(command_id)) {
     76     case SHOW_IN_FOLDER:
     77       return download_item_->CanShowInFolder();
     78     case OPEN_WHEN_COMPLETE:
     79       return download_item_->CanOpenDownload() &&
     80           !download_crx_util::IsExtensionDownload(*download_item_);
     81     case ALWAYS_OPEN_TYPE:
     82       // For temporary downloads, the target filename might be a temporary
     83       // filename. Don't base an "Always open" decision based on it. Also
     84       // exclude extensions.
     85       return download_item_->CanOpenDownload() &&
     86           !download_crx_util::IsExtensionDownload(*download_item_);
     87     case CANCEL:
     88       return !download_item_->IsDone();
     89     case TOGGLE_PAUSE:
     90       return !download_item_->IsDone();
     91     case DISCARD:
     92     case KEEP:
     93     case LEARN_MORE_SCANNING:
     94     case LEARN_MORE_INTERRUPTED:
     95       return true;
     96   }
     97   return false;
     98 }
     99 
    100 bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id) const {
    101   if (!download_item_)
    102     return false;
    103 
    104   switch (command_id) {
    105     case OPEN_WHEN_COMPLETE:
    106       return download_item_->GetOpenWhenComplete() ||
    107           download_crx_util::IsExtensionDownload(*download_item_);
    108     case ALWAYS_OPEN_TYPE:
    109       return download_item_->ShouldOpenFileBasedOnExtension();
    110     case TOGGLE_PAUSE:
    111       return download_item_->IsPaused();
    112   }
    113   return false;
    114 }
    115 
    116 void DownloadShelfContextMenu::ExecuteCommand(int command_id, int event_flags) {
    117   if (!download_item_)
    118     return;
    119 
    120   switch (static_cast<ContextMenuCommands>(command_id)) {
    121     case SHOW_IN_FOLDER:
    122       download_item_->ShowDownloadInShell();
    123       break;
    124     case OPEN_WHEN_COMPLETE:
    125       download_item_->OpenDownload();
    126       break;
    127     case ALWAYS_OPEN_TYPE: {
    128       DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(
    129           download_item_->GetBrowserContext());
    130       base::FilePath path = download_item_->GetTargetFilePath();
    131       if (!IsCommandIdChecked(ALWAYS_OPEN_TYPE))
    132         prefs->EnableAutoOpenBasedOnExtension(path);
    133       else
    134         prefs->DisableAutoOpenBasedOnExtension(path);
    135       break;
    136     }
    137     case CANCEL:
    138       download_item_->Cancel(true /* Cancelled by user */);
    139       break;
    140     case TOGGLE_PAUSE:
    141       if (download_item_->GetState() == DownloadItem::IN_PROGRESS &&
    142           !download_item_->IsPaused()) {
    143         download_item_->Pause();
    144       } else {
    145         download_item_->Resume();
    146       }
    147       break;
    148     case DISCARD:
    149       download_item_->Remove();
    150       break;
    151     case KEEP:
    152       download_item_->ValidateDangerousDownload();
    153       break;
    154     case LEARN_MORE_SCANNING: {
    155 #if defined(FULL_SAFE_BROWSING)
    156       using safe_browsing::DownloadProtectionService;
    157       SafeBrowsingService* sb_service =
    158           g_browser_process->safe_browsing_service();
    159       DownloadProtectionService* protection_service =
    160           (sb_service ? sb_service->download_protection_service() : NULL);
    161       if (protection_service) {
    162         protection_service->ShowDetailsForDownload(*download_item_, navigator_);
    163       }
    164 #else
    165       // Should only be getting invoked if we are using safe browsing.
    166       NOTREACHED();
    167 #endif
    168       break;
    169     }
    170     case LEARN_MORE_INTERRUPTED:
    171       navigator_->OpenURL(
    172           content::OpenURLParams(GURL(chrome::kDownloadInterruptedLearnMoreURL),
    173                                  content::Referrer(),
    174                                  NEW_FOREGROUND_TAB,
    175                                  content::PAGE_TRANSITION_LINK,
    176                                  false));
    177       break;
    178   }
    179 }
    180 
    181 bool DownloadShelfContextMenu::GetAcceleratorForCommandId(
    182     int command_id, ui::Accelerator* accelerator) {
    183   return false;
    184 }
    185 
    186 bool DownloadShelfContextMenu::IsItemForCommandIdDynamic(int command_id) const {
    187   return command_id == TOGGLE_PAUSE;
    188 }
    189 
    190 string16 DownloadShelfContextMenu::GetLabelForCommandId(int command_id) const {
    191   switch (static_cast<ContextMenuCommands>(command_id)) {
    192     case SHOW_IN_FOLDER:
    193       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_SHOW);
    194     case OPEN_WHEN_COMPLETE:
    195       if (download_item_ && !download_item_->IsDone())
    196         return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
    197       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN);
    198     case ALWAYS_OPEN_TYPE:
    199       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
    200     case CANCEL:
    201       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_CANCEL);
    202     case TOGGLE_PAUSE:
    203       if (download_item_ &&
    204           download_item_->GetState() == DownloadItem::IN_PROGRESS &&
    205           !download_item_->IsPaused())
    206         return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PAUSE_ITEM);
    207       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_RESUME_ITEM);
    208     case DISCARD:
    209       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_DISCARD);
    210     case KEEP:
    211       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_KEEP);
    212     case LEARN_MORE_SCANNING:
    213       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
    214     case LEARN_MORE_INTERRUPTED:
    215       return l10n_util::GetStringUTF16(
    216           IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED);
    217   }
    218   NOTREACHED();
    219   return string16();
    220 }
    221 
    222 void DownloadShelfContextMenu::DetachFromDownloadItem() {
    223   if (!download_item_)
    224     return;
    225 
    226   download_item_->RemoveObserver(this);
    227   download_item_ = NULL;
    228 }
    229 
    230 void DownloadShelfContextMenu::OnDownloadDestroyed(DownloadItem* download) {
    231   DCHECK(download_item_ == download);
    232   DetachFromDownloadItem();
    233 }
    234 
    235 ui::SimpleMenuModel* DownloadShelfContextMenu::GetInProgressMenuModel() {
    236   if (in_progress_download_menu_model_)
    237     return in_progress_download_menu_model_.get();
    238 
    239   in_progress_download_menu_model_.reset(new ui::SimpleMenuModel(this));
    240 
    241   in_progress_download_menu_model_->AddCheckItemWithStringId(
    242       OPEN_WHEN_COMPLETE, IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
    243   in_progress_download_menu_model_->AddCheckItemWithStringId(
    244       ALWAYS_OPEN_TYPE, IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
    245   in_progress_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
    246   in_progress_download_menu_model_->AddItemWithStringId(
    247       TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_PAUSE_ITEM);
    248   in_progress_download_menu_model_->AddItemWithStringId(
    249       SHOW_IN_FOLDER, IDS_DOWNLOAD_MENU_SHOW);
    250   in_progress_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
    251   in_progress_download_menu_model_->AddItemWithStringId(
    252       CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
    253 
    254   return in_progress_download_menu_model_.get();
    255 }
    256 
    257 ui::SimpleMenuModel* DownloadShelfContextMenu::GetFinishedMenuModel() {
    258   if (finished_download_menu_model_)
    259     return finished_download_menu_model_.get();
    260 
    261   finished_download_menu_model_.reset(new ui::SimpleMenuModel(this));
    262 
    263   finished_download_menu_model_->AddItemWithStringId(
    264       OPEN_WHEN_COMPLETE, IDS_DOWNLOAD_MENU_OPEN);
    265   finished_download_menu_model_->AddCheckItemWithStringId(
    266       ALWAYS_OPEN_TYPE, IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
    267   finished_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
    268   finished_download_menu_model_->AddItemWithStringId(
    269       SHOW_IN_FOLDER, IDS_DOWNLOAD_MENU_SHOW);
    270   finished_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
    271   finished_download_menu_model_->AddItemWithStringId(
    272       CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
    273 
    274   return finished_download_menu_model_.get();
    275 }
    276 
    277 ui::SimpleMenuModel* DownloadShelfContextMenu::GetInterruptedMenuModel() {
    278 #if !defined(OS_WIN)
    279   // If resumption isn't enabled and we aren't on Windows, then none of the
    280   // options here are applicable.
    281   if (!IsDownloadResumptionEnabled())
    282     return GetInProgressMenuModel();
    283 #endif
    284 
    285   if (interrupted_download_menu_model_)
    286     return interrupted_download_menu_model_.get();
    287 
    288   interrupted_download_menu_model_.reset(new ui::SimpleMenuModel(this));
    289 
    290   if (IsDownloadResumptionEnabled()) {
    291     interrupted_download_menu_model_->AddItemWithStringId(
    292         TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_RESUME_ITEM);
    293   }
    294 #if defined(OS_WIN)
    295   // The Help Center article is currently Windows specific.
    296   // TODO(asanka): Enable this for other platforms when the article is expanded
    297   // for other platforms.
    298   interrupted_download_menu_model_->AddItemWithStringId(
    299       LEARN_MORE_INTERRUPTED, IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED);
    300 #endif
    301   if (IsDownloadResumptionEnabled()) {
    302     interrupted_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
    303     interrupted_download_menu_model_->AddItemWithStringId(
    304         CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
    305   }
    306 
    307   return interrupted_download_menu_model_.get();
    308 }
    309 
    310 ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaliciousMenuModel() {
    311   if (malicious_download_menu_model_)
    312     return malicious_download_menu_model_.get();
    313 
    314   malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
    315 
    316   malicious_download_menu_model_->AddItemWithStringId(
    317       DISCARD, IDS_DOWNLOAD_MENU_DISCARD);
    318   malicious_download_menu_model_->AddItemWithStringId(
    319       KEEP, IDS_DOWNLOAD_MENU_KEEP);
    320   malicious_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
    321   malicious_download_menu_model_->AddItemWithStringId(
    322       LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
    323 
    324   return malicious_download_menu_model_.get();
    325 }
    326