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.
5 #include "chrome/browser/download/download_shelf_context_menu.h"
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/download/download_target_determiner.h"
13 #include "chrome/browser/safe_browsing/download_protection_service.h"
14 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
15 #include "chrome/common/url_constants.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "content/public/browser/download_item.h"
18 #include "content/public/browser/download_manager.h"
19 #include "content/public/browser/page_navigator.h"
20 #include "content/public/common/content_switches.h"
21 #include "extensions/common/extension.h"
22 #include "ui/base/l10n/l10n_util.h"
25 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
28 using content::DownloadItem;
32 // Returns true if downloads resumption is enabled.
33 bool IsDownloadResumptionEnabled() {
34 return base::CommandLine::ForCurrentProcess()->HasSwitch(
35 switches::kEnableDownloadResumption);
40 DownloadShelfContextMenu::~DownloadShelfContextMenu() {
41 DetachFromDownloadItem();
44 DownloadShelfContextMenu::DownloadShelfContextMenu(
45 DownloadItem* download_item,
46 content::PageNavigator* navigator)
47 : download_item_(download_item),
48 navigator_(navigator) {
49 DCHECK(download_item_);
50 download_item_->AddObserver(this);
53 is_adobe_pdf_reader_up_to_date_ = false;
54 if (IsDownloadPdf() && IsAdobeReaderDefaultPDFViewer()) {
55 is_adobe_pdf_reader_up_to_date_ =
56 DownloadTargetDeterminer::IsAdobeReaderUpToDate();
58 #endif // defined(OS_WIN)
61 ui::SimpleMenuModel* DownloadShelfContextMenu::GetMenuModel() {
62 ui::SimpleMenuModel* model = NULL;
67 DownloadItemModel download_model(download_item_);
68 // We shouldn't be opening a context menu for a dangerous download, unless it
69 // is a malicious download.
70 DCHECK(!download_model.IsDangerous() || download_model.MightBeMalicious());
72 if (download_model.IsMalicious())
73 model = GetMaliciousMenuModel();
74 else if (download_model.MightBeMalicious())
75 model = GetMaybeMaliciousMenuModel();
76 else if (download_item_->GetState() == DownloadItem::COMPLETE)
77 model = GetFinishedMenuModel();
78 else if (download_item_->GetState() == DownloadItem::INTERRUPTED)
79 model = GetInterruptedMenuModel();
81 model = GetInProgressMenuModel();
85 bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const {
89 switch (static_cast<ContextMenuCommands>(command_id)) {
91 return download_item_->CanShowInFolder();
92 case OPEN_WHEN_COMPLETE:
94 return download_item_->CanOpenDownload() &&
95 !download_crx_util::IsExtensionDownload(*download_item_);
96 case ALWAYS_OPEN_TYPE:
97 // For temporary downloads, the target filename might be a temporary
98 // filename. Don't base an "Always open" decision based on it. Also
99 // exclude extensions.
100 return download_item_->CanOpenDownload() &&
101 !download_crx_util::IsExtensionDownload(*download_item_);
103 return !download_item_->IsDone();
105 return !download_item_->IsDone();
108 case LEARN_MORE_SCANNING:
109 case LEARN_MORE_INTERRUPTED:
116 bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id) const {
120 switch (command_id) {
121 case OPEN_WHEN_COMPLETE:
122 return download_item_->GetOpenWhenComplete() ||
123 download_crx_util::IsExtensionDownload(*download_item_);
124 case ALWAYS_OPEN_TYPE:
125 #if defined(OS_WIN) || defined(OS_LINUX) || \
126 (defined(OS_MACOSX) && !defined(OS_IOS))
127 if (CanOpenPdfInSystemViewer()) {
128 DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(
129 download_item_->GetBrowserContext());
130 return prefs->ShouldOpenPdfInSystemReader();
133 return download_item_->ShouldOpenFileBasedOnExtension();
135 return download_item_->IsPaused();
140 bool DownloadShelfContextMenu::IsCommandIdVisible(int command_id) const {
144 if (command_id == PLATFORM_OPEN)
145 return (DownloadItemModel(download_item_).ShouldPreferOpeningInBrowser());
150 void DownloadShelfContextMenu::ExecuteCommand(int command_id, int event_flags) {
154 switch (static_cast<ContextMenuCommands>(command_id)) {
156 download_item_->ShowDownloadInShell();
158 case OPEN_WHEN_COMPLETE:
159 download_item_->OpenDownload();
161 case ALWAYS_OPEN_TYPE: {
162 bool is_checked = IsCommandIdChecked(ALWAYS_OPEN_TYPE);
163 DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(
164 download_item_->GetBrowserContext());
165 #if defined(OS_WIN) || defined(OS_LINUX) || \
166 (defined(OS_MACOSX) && !defined(OS_IOS))
167 if (CanOpenPdfInSystemViewer()) {
168 prefs->SetShouldOpenPdfInSystemReader(!is_checked);
169 DownloadItemModel(download_item_).SetShouldPreferOpeningInBrowser(
174 base::FilePath path = download_item_->GetTargetFilePath();
176 prefs->DisableAutoOpenBasedOnExtension(path);
178 prefs->EnableAutoOpenBasedOnExtension(path);
182 DownloadItemModel(download_item_).OpenUsingPlatformHandler();
185 download_item_->Cancel(true /* Cancelled by user */);
188 if (download_item_->GetState() == DownloadItem::IN_PROGRESS &&
189 !download_item_->IsPaused()) {
190 download_item_->Pause();
192 download_item_->Resume();
196 download_item_->Remove();
199 download_item_->ValidateDangerousDownload();
201 case LEARN_MORE_SCANNING: {
202 #if defined(FULL_SAFE_BROWSING)
203 using safe_browsing::DownloadProtectionService;
204 SafeBrowsingService* sb_service =
205 g_browser_process->safe_browsing_service();
206 DownloadProtectionService* protection_service =
207 (sb_service ? sb_service->download_protection_service() : NULL);
208 if (protection_service) {
209 protection_service->ShowDetailsForDownload(*download_item_, navigator_);
212 // Should only be getting invoked if we are using safe browsing.
217 case LEARN_MORE_INTERRUPTED:
219 content::OpenURLParams(GURL(chrome::kDownloadInterruptedLearnMoreURL),
222 ui::PAGE_TRANSITION_LINK,
228 bool DownloadShelfContextMenu::GetAcceleratorForCommandId(
229 int command_id, ui::Accelerator* accelerator) {
233 bool DownloadShelfContextMenu::IsItemForCommandIdDynamic(int command_id) const {
234 return command_id == TOGGLE_PAUSE;
237 base::string16 DownloadShelfContextMenu::GetLabelForCommandId(
238 int command_id) const {
239 switch (static_cast<ContextMenuCommands>(command_id)) {
241 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_SHOW);
242 case OPEN_WHEN_COMPLETE:
243 if (download_item_ && !download_item_->IsDone())
244 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
245 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN);
246 case ALWAYS_OPEN_TYPE:
247 return l10n_util::GetStringUTF16(GetAlwaysOpenStringId());
249 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PLATFORM_OPEN);
251 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_CANCEL);
253 if (download_item_ &&
254 download_item_->GetState() == DownloadItem::IN_PROGRESS &&
255 !download_item_->IsPaused())
256 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PAUSE_ITEM);
257 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_RESUME_ITEM);
259 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_DISCARD);
261 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_KEEP);
262 case LEARN_MORE_SCANNING:
263 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
264 case LEARN_MORE_INTERRUPTED:
265 return l10n_util::GetStringUTF16(
266 IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED);
269 return base::string16();
272 void DownloadShelfContextMenu::DetachFromDownloadItem() {
276 download_item_->RemoveObserver(this);
277 download_item_ = NULL;
280 void DownloadShelfContextMenu::OnDownloadDestroyed(DownloadItem* download) {
281 DCHECK(download_item_ == download);
282 DetachFromDownloadItem();
285 ui::SimpleMenuModel* DownloadShelfContextMenu::GetInProgressMenuModel() {
286 if (in_progress_download_menu_model_)
287 return in_progress_download_menu_model_.get();
289 in_progress_download_menu_model_.reset(new ui::SimpleMenuModel(this));
291 in_progress_download_menu_model_->AddCheckItemWithStringId(
292 OPEN_WHEN_COMPLETE, IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
293 in_progress_download_menu_model_->AddCheckItemWithStringId(
294 ALWAYS_OPEN_TYPE, GetAlwaysOpenStringId());
295 in_progress_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
296 in_progress_download_menu_model_->AddItemWithStringId(
297 TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_PAUSE_ITEM);
298 in_progress_download_menu_model_->AddItemWithStringId(
299 SHOW_IN_FOLDER, IDS_DOWNLOAD_MENU_SHOW);
300 in_progress_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
301 in_progress_download_menu_model_->AddItemWithStringId(
302 CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
304 return in_progress_download_menu_model_.get();
307 ui::SimpleMenuModel* DownloadShelfContextMenu::GetFinishedMenuModel() {
308 if (finished_download_menu_model_)
309 return finished_download_menu_model_.get();
311 finished_download_menu_model_.reset(new ui::SimpleMenuModel(this));
313 finished_download_menu_model_->AddItemWithStringId(
314 OPEN_WHEN_COMPLETE, IDS_DOWNLOAD_MENU_OPEN);
315 finished_download_menu_model_->AddCheckItemWithStringId(
316 ALWAYS_OPEN_TYPE, GetAlwaysOpenStringId());
317 finished_download_menu_model_->AddItemWithStringId(
318 PLATFORM_OPEN, IDS_DOWNLOAD_MENU_PLATFORM_OPEN);
319 finished_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
320 finished_download_menu_model_->AddItemWithStringId(
321 SHOW_IN_FOLDER, IDS_DOWNLOAD_MENU_SHOW);
322 finished_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
323 finished_download_menu_model_->AddItemWithStringId(
324 CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
326 return finished_download_menu_model_.get();
329 ui::SimpleMenuModel* DownloadShelfContextMenu::GetInterruptedMenuModel() {
331 // If resumption isn't enabled and we aren't on Windows, then none of the
332 // options here are applicable.
333 if (!IsDownloadResumptionEnabled())
334 return GetInProgressMenuModel();
337 if (interrupted_download_menu_model_)
338 return interrupted_download_menu_model_.get();
340 interrupted_download_menu_model_.reset(new ui::SimpleMenuModel(this));
342 if (IsDownloadResumptionEnabled()) {
343 interrupted_download_menu_model_->AddItemWithStringId(
344 TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_RESUME_ITEM);
347 // The Help Center article is currently Windows specific.
348 // TODO(asanka): Enable this for other platforms when the article is expanded
349 // for other platforms.
350 interrupted_download_menu_model_->AddItemWithStringId(
351 LEARN_MORE_INTERRUPTED, IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED);
353 if (IsDownloadResumptionEnabled()) {
354 interrupted_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
355 interrupted_download_menu_model_->AddItemWithStringId(
356 CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
359 return interrupted_download_menu_model_.get();
362 ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaybeMaliciousMenuModel() {
363 if (maybe_malicious_download_menu_model_)
364 return maybe_malicious_download_menu_model_.get();
366 maybe_malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
368 maybe_malicious_download_menu_model_->AddItemWithStringId(
369 KEEP, IDS_DOWNLOAD_MENU_KEEP);
370 maybe_malicious_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
371 maybe_malicious_download_menu_model_->AddItemWithStringId(
372 LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
373 return maybe_malicious_download_menu_model_.get();
376 ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaliciousMenuModel() {
377 if (malicious_download_menu_model_)
378 return malicious_download_menu_model_.get();
380 malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
382 DownloadItemModel download_model(download_item_);
383 malicious_download_menu_model_->AddItemWithStringId(
384 LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
386 return malicious_download_menu_model_.get();
389 int DownloadShelfContextMenu::GetAlwaysOpenStringId() const {
391 if (CanOpenPdfInSystemViewer())
392 return IDS_DOWNLOAD_MENU_ALWAYS_OPEN_PDF_IN_READER;
393 #elif defined(OS_MACOSX) || defined(OS_LINUX)
394 if (CanOpenPdfInSystemViewer())
395 return IDS_DOWNLOAD_MENU_PLATFORM_OPEN_ALWAYS;
397 return IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE;
400 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
401 bool DownloadShelfContextMenu::IsDownloadPdf() const {
402 base::FilePath path = download_item_->GetTargetFilePath();
403 return path.MatchesExtension(FILE_PATH_LITERAL(".pdf"));
407 bool DownloadShelfContextMenu::CanOpenPdfInSystemViewer() const {
409 return IsDownloadPdf() &&
410 (IsAdobeReaderDefaultPDFViewer() ? is_adobe_pdf_reader_up_to_date_ :
412 #elif defined(OS_MACOSX) || defined(OS_LINUX)
413 return IsDownloadPdf();