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();