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/safe_browsing/download_protection_service.h"
13 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
14 #include "chrome/common/url_constants.h"
15 #include "content/public/browser/download_item.h"
16 #include "content/public/browser/download_manager.h"
17 #include "content/public/browser/page_navigator.h"
18 #include "content/public/common/content_switches.h"
19 #include "extensions/common/extension.h"
20 #include "grit/generated_resources.h"
21 #include "ui/base/l10n/l10n_util.h"
23 using content::DownloadItem
;
24 using extensions::Extension
;
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
);
36 DownloadShelfContextMenu::~DownloadShelfContextMenu() {
37 DetachFromDownloadItem();
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);
49 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetMenuModel() {
50 ui::SimpleMenuModel
* model
= NULL
;
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
.MightBeMalicious());
60 if (download_model
.IsMalicious())
61 model
= GetMaliciousMenuModel();
62 else if (download_model
.MightBeMalicious())
63 model
= GetMaybeMaliciousMenuModel();
64 else if (download_item_
->GetState() == DownloadItem::COMPLETE
)
65 model
= GetFinishedMenuModel();
66 else if (download_item_
->GetState() == DownloadItem::INTERRUPTED
)
67 model
= GetInterruptedMenuModel();
69 model
= GetInProgressMenuModel();
73 bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id
) const {
77 switch (static_cast<ContextMenuCommands
>(command_id
)) {
79 return download_item_
->CanShowInFolder();
80 case OPEN_WHEN_COMPLETE
:
82 return download_item_
->CanOpenDownload() &&
83 !download_crx_util::IsExtensionDownload(*download_item_
);
84 case ALWAYS_OPEN_TYPE
:
85 // For temporary downloads, the target filename might be a temporary
86 // filename. Don't base an "Always open" decision based on it. Also
87 // exclude extensions.
88 return download_item_
->CanOpenDownload() &&
89 !download_crx_util::IsExtensionDownload(*download_item_
);
91 return !download_item_
->IsDone();
93 return !download_item_
->IsDone();
96 case LEARN_MORE_SCANNING
:
97 case LEARN_MORE_INTERRUPTED
:
103 bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id
) const {
107 switch (command_id
) {
108 case OPEN_WHEN_COMPLETE
:
109 return download_item_
->GetOpenWhenComplete() ||
110 download_crx_util::IsExtensionDownload(*download_item_
);
111 case ALWAYS_OPEN_TYPE
:
112 return download_item_
->ShouldOpenFileBasedOnExtension();
114 return download_item_
->IsPaused();
119 void DownloadShelfContextMenu::ExecuteCommand(int command_id
, int event_flags
) {
123 switch (static_cast<ContextMenuCommands
>(command_id
)) {
125 download_item_
->ShowDownloadInShell();
127 case OPEN_WHEN_COMPLETE
:
128 download_item_
->OpenDownload();
130 case ALWAYS_OPEN_TYPE
: {
131 DownloadPrefs
* prefs
= DownloadPrefs::FromBrowserContext(
132 download_item_
->GetBrowserContext());
133 base::FilePath path
= download_item_
->GetTargetFilePath();
134 if (!IsCommandIdChecked(ALWAYS_OPEN_TYPE
))
135 prefs
->EnableAutoOpenBasedOnExtension(path
);
137 prefs
->DisableAutoOpenBasedOnExtension(path
);
141 DownloadItemModel(download_item_
).OpenUsingPlatformHandler();
144 download_item_
->Cancel(true /* Cancelled by user */);
147 if (download_item_
->GetState() == DownloadItem::IN_PROGRESS
&&
148 !download_item_
->IsPaused()) {
149 download_item_
->Pause();
151 download_item_
->Resume();
155 download_item_
->Remove();
158 download_item_
->ValidateDangerousDownload();
160 case LEARN_MORE_SCANNING
: {
161 #if defined(FULL_SAFE_BROWSING)
162 using safe_browsing::DownloadProtectionService
;
163 SafeBrowsingService
* sb_service
=
164 g_browser_process
->safe_browsing_service();
165 DownloadProtectionService
* protection_service
=
166 (sb_service
? sb_service
->download_protection_service() : NULL
);
167 if (protection_service
) {
168 protection_service
->ShowDetailsForDownload(*download_item_
, navigator_
);
171 // Should only be getting invoked if we are using safe browsing.
176 case LEARN_MORE_INTERRUPTED
:
178 content::OpenURLParams(GURL(chrome::kDownloadInterruptedLearnMoreURL
),
181 content::PAGE_TRANSITION_LINK
,
187 bool DownloadShelfContextMenu::GetAcceleratorForCommandId(
188 int command_id
, ui::Accelerator
* accelerator
) {
192 bool DownloadShelfContextMenu::IsItemForCommandIdDynamic(int command_id
) const {
193 return command_id
== TOGGLE_PAUSE
;
196 base::string16
DownloadShelfContextMenu::GetLabelForCommandId(
197 int command_id
) const {
198 switch (static_cast<ContextMenuCommands
>(command_id
)) {
200 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_SHOW
);
201 case OPEN_WHEN_COMPLETE
:
202 if (download_item_
&& !download_item_
->IsDone())
203 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE
);
204 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN
);
205 case ALWAYS_OPEN_TYPE
:
206 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE
);
208 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PLATFORM_OPEN
);
210 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_CANCEL
);
212 if (download_item_
&&
213 download_item_
->GetState() == DownloadItem::IN_PROGRESS
&&
214 !download_item_
->IsPaused())
215 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PAUSE_ITEM
);
216 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_RESUME_ITEM
);
218 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_DISCARD
);
220 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_KEEP
);
221 case LEARN_MORE_SCANNING
:
222 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING
);
223 case LEARN_MORE_INTERRUPTED
:
224 return l10n_util::GetStringUTF16(
225 IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED
);
228 return base::string16();
231 void DownloadShelfContextMenu::DetachFromDownloadItem() {
235 download_item_
->RemoveObserver(this);
236 download_item_
= NULL
;
239 void DownloadShelfContextMenu::OnDownloadDestroyed(DownloadItem
* download
) {
240 DCHECK(download_item_
== download
);
241 DetachFromDownloadItem();
244 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetInProgressMenuModel() {
245 if (in_progress_download_menu_model_
)
246 return in_progress_download_menu_model_
.get();
248 in_progress_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
250 in_progress_download_menu_model_
->AddCheckItemWithStringId(
251 OPEN_WHEN_COMPLETE
, IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE
);
252 in_progress_download_menu_model_
->AddCheckItemWithStringId(
253 ALWAYS_OPEN_TYPE
, IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE
);
254 in_progress_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
255 in_progress_download_menu_model_
->AddItemWithStringId(
256 TOGGLE_PAUSE
, IDS_DOWNLOAD_MENU_PAUSE_ITEM
);
257 in_progress_download_menu_model_
->AddItemWithStringId(
258 SHOW_IN_FOLDER
, IDS_DOWNLOAD_MENU_SHOW
);
259 in_progress_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
260 in_progress_download_menu_model_
->AddItemWithStringId(
261 CANCEL
, IDS_DOWNLOAD_MENU_CANCEL
);
263 return in_progress_download_menu_model_
.get();
266 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetFinishedMenuModel() {
267 if (finished_download_menu_model_
)
268 return finished_download_menu_model_
.get();
270 finished_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
272 finished_download_menu_model_
->AddItemWithStringId(
273 OPEN_WHEN_COMPLETE
, IDS_DOWNLOAD_MENU_OPEN
);
274 finished_download_menu_model_
->AddCheckItemWithStringId(
275 ALWAYS_OPEN_TYPE
, IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE
);
276 if (DownloadItemModel(download_item_
).ShouldPreferOpeningInBrowser())
277 finished_download_menu_model_
->AddItemWithStringId(
278 PLATFORM_OPEN
, IDS_DOWNLOAD_MENU_PLATFORM_OPEN
);
279 finished_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
280 finished_download_menu_model_
->AddItemWithStringId(
281 SHOW_IN_FOLDER
, IDS_DOWNLOAD_MENU_SHOW
);
282 finished_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
283 finished_download_menu_model_
->AddItemWithStringId(
284 CANCEL
, IDS_DOWNLOAD_MENU_CANCEL
);
286 return finished_download_menu_model_
.get();
289 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetInterruptedMenuModel() {
291 // If resumption isn't enabled and we aren't on Windows, then none of the
292 // options here are applicable.
293 if (!IsDownloadResumptionEnabled())
294 return GetInProgressMenuModel();
297 if (interrupted_download_menu_model_
)
298 return interrupted_download_menu_model_
.get();
300 interrupted_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
302 if (IsDownloadResumptionEnabled()) {
303 interrupted_download_menu_model_
->AddItemWithStringId(
304 TOGGLE_PAUSE
, IDS_DOWNLOAD_MENU_RESUME_ITEM
);
307 // The Help Center article is currently Windows specific.
308 // TODO(asanka): Enable this for other platforms when the article is expanded
309 // for other platforms.
310 interrupted_download_menu_model_
->AddItemWithStringId(
311 LEARN_MORE_INTERRUPTED
, IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED
);
313 if (IsDownloadResumptionEnabled()) {
314 interrupted_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
315 interrupted_download_menu_model_
->AddItemWithStringId(
316 CANCEL
, IDS_DOWNLOAD_MENU_CANCEL
);
319 return interrupted_download_menu_model_
.get();
322 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetMaybeMaliciousMenuModel() {
323 if (maybe_malicious_download_menu_model_
)
324 return maybe_malicious_download_menu_model_
.get();
326 maybe_malicious_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
328 maybe_malicious_download_menu_model_
->AddItemWithStringId(
329 KEEP
, IDS_DOWNLOAD_MENU_KEEP
);
330 maybe_malicious_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
331 maybe_malicious_download_menu_model_
->AddItemWithStringId(
332 LEARN_MORE_SCANNING
, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING
);
333 return maybe_malicious_download_menu_model_
.get();
337 DownloadShelfContextMenu::GetMaliciousMenuModel() {
338 if (malicious_download_menu_model_
)
339 return malicious_download_menu_model_
.get();
341 malicious_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
343 DownloadItemModel
download_model(download_item_
);
344 malicious_download_menu_model_
->AddItemWithStringId(
345 LEARN_MORE_SCANNING
, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING
);
347 return malicious_download_menu_model_
.get();