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_feedback_service.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 "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 "extensions/common/extension.h"
21 #include "grit/generated_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
24 using content::DownloadItem
;
25 using extensions::Extension
;
29 // Returns true if downloads resumption is enabled.
30 bool IsDownloadResumptionEnabled() {
31 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
32 return command_line
.HasSwitch(switches::kEnableDownloadResumption
);
37 DownloadShelfContextMenu::~DownloadShelfContextMenu() {
38 DetachFromDownloadItem();
41 DownloadShelfContextMenu::DownloadShelfContextMenu(
42 DownloadItem
* download_item
,
43 content::PageNavigator
* navigator
)
44 : download_item_(download_item
),
45 navigator_(navigator
) {
46 DCHECK(download_item_
);
47 download_item_
->AddObserver(this);
50 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetMenuModel() {
51 ui::SimpleMenuModel
* model
= NULL
;
56 DownloadItemModel
download_model(download_item_
);
57 // We shouldn't be opening a context menu for a dangerous download, unless it
58 // is a malicious download.
59 DCHECK(!download_model
.IsDangerous() || download_model
.MightBeMalicious());
61 if (download_model
.IsMalicious())
62 model
= GetMaliciousMenuModel();
63 else if (download_model
.MightBeMalicious())
64 model
= GetMaybeMaliciousMenuModel();
65 else if (download_item_
->GetState() == DownloadItem::COMPLETE
)
66 model
= GetFinishedMenuModel();
67 else if (download_item_
->GetState() == DownloadItem::INTERRUPTED
)
68 model
= GetInterruptedMenuModel();
70 model
= GetInProgressMenuModel();
74 bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id
) const {
78 switch (static_cast<ContextMenuCommands
>(command_id
)) {
80 return download_item_
->CanShowInFolder();
81 case OPEN_WHEN_COMPLETE
:
83 return download_item_
->CanOpenDownload() &&
84 !download_crx_util::IsExtensionDownload(*download_item_
);
85 case ALWAYS_OPEN_TYPE
:
86 // For temporary downloads, the target filename might be a temporary
87 // filename. Don't base an "Always open" decision based on it. Also
88 // exclude extensions.
89 return download_item_
->CanOpenDownload() &&
90 !download_crx_util::IsExtensionDownload(*download_item_
);
92 return !download_item_
->IsDone();
94 return !download_item_
->IsDone();
98 case LEARN_MORE_SCANNING
:
99 case LEARN_MORE_INTERRUPTED
:
105 bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id
) const {
109 switch (command_id
) {
110 case OPEN_WHEN_COMPLETE
:
111 return download_item_
->GetOpenWhenComplete() ||
112 download_crx_util::IsExtensionDownload(*download_item_
);
113 case ALWAYS_OPEN_TYPE
:
114 return download_item_
->ShouldOpenFileBasedOnExtension();
116 return download_item_
->IsPaused();
121 void DownloadShelfContextMenu::ExecuteCommand(int command_id
, int event_flags
) {
125 switch (static_cast<ContextMenuCommands
>(command_id
)) {
127 download_item_
->ShowDownloadInShell();
129 case OPEN_WHEN_COMPLETE
:
130 download_item_
->OpenDownload();
132 case ALWAYS_OPEN_TYPE
: {
133 DownloadPrefs
* prefs
= DownloadPrefs::FromBrowserContext(
134 download_item_
->GetBrowserContext());
135 base::FilePath path
= download_item_
->GetTargetFilePath();
136 if (!IsCommandIdChecked(ALWAYS_OPEN_TYPE
))
137 prefs
->EnableAutoOpenBasedOnExtension(path
);
139 prefs
->DisableAutoOpenBasedOnExtension(path
);
143 DownloadItemModel(download_item_
).OpenUsingPlatformHandler();
146 download_item_
->Cancel(true /* Cancelled by user */);
149 if (download_item_
->GetState() == DownloadItem::IN_PROGRESS
&&
150 !download_item_
->IsPaused()) {
151 download_item_
->Pause();
153 download_item_
->Resume();
157 download_item_
->Remove();
160 download_item_
->ValidateDangerousDownload();
163 #if defined(FULL_SAFE_BROWSING)
164 using safe_browsing::DownloadProtectionService
;
165 DownloadItemModel
download_model(download_item_
);
166 if (!download_model
.ShouldAllowDownloadFeedback())
168 SafeBrowsingService
* sb_service
=
169 g_browser_process
->safe_browsing_service();
170 DownloadProtectionService
* protection_service
=
171 (sb_service
? sb_service
->download_protection_service() : NULL
);
172 if (protection_service
) {
173 protection_service
->feedback_service()->BeginFeedbackForDownload(
177 // Should only be getting invoked if we are using safe browsing.
182 case LEARN_MORE_SCANNING
: {
183 #if defined(FULL_SAFE_BROWSING)
184 using safe_browsing::DownloadProtectionService
;
185 SafeBrowsingService
* sb_service
=
186 g_browser_process
->safe_browsing_service();
187 DownloadProtectionService
* protection_service
=
188 (sb_service
? sb_service
->download_protection_service() : NULL
);
189 if (protection_service
) {
190 protection_service
->ShowDetailsForDownload(*download_item_
, navigator_
);
193 // Should only be getting invoked if we are using safe browsing.
198 case LEARN_MORE_INTERRUPTED
:
200 content::OpenURLParams(GURL(chrome::kDownloadInterruptedLearnMoreURL
),
203 content::PAGE_TRANSITION_LINK
,
209 bool DownloadShelfContextMenu::GetAcceleratorForCommandId(
210 int command_id
, ui::Accelerator
* accelerator
) {
214 bool DownloadShelfContextMenu::IsItemForCommandIdDynamic(int command_id
) const {
215 return command_id
== TOGGLE_PAUSE
;
218 base::string16
DownloadShelfContextMenu::GetLabelForCommandId(
219 int command_id
) const {
220 switch (static_cast<ContextMenuCommands
>(command_id
)) {
222 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_SHOW
);
223 case OPEN_WHEN_COMPLETE
:
224 if (download_item_
&& !download_item_
->IsDone())
225 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE
);
226 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_OPEN
);
227 case ALWAYS_OPEN_TYPE
:
228 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE
);
230 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PLATFORM_OPEN
);
232 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_CANCEL
);
234 if (download_item_
&&
235 download_item_
->GetState() == DownloadItem::IN_PROGRESS
&&
236 !download_item_
->IsPaused())
237 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PAUSE_ITEM
);
238 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_RESUME_ITEM
);
240 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_DISCARD
);
242 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_REPORT
);
244 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_KEEP
);
245 case LEARN_MORE_SCANNING
:
246 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING
);
247 case LEARN_MORE_INTERRUPTED
:
248 return l10n_util::GetStringUTF16(
249 IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED
);
252 return base::string16();
255 void DownloadShelfContextMenu::DetachFromDownloadItem() {
259 download_item_
->RemoveObserver(this);
260 download_item_
= NULL
;
263 void DownloadShelfContextMenu::OnDownloadDestroyed(DownloadItem
* download
) {
264 DCHECK(download_item_
== download
);
265 DetachFromDownloadItem();
268 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetInProgressMenuModel() {
269 if (in_progress_download_menu_model_
)
270 return in_progress_download_menu_model_
.get();
272 in_progress_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
274 in_progress_download_menu_model_
->AddCheckItemWithStringId(
275 OPEN_WHEN_COMPLETE
, IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE
);
276 in_progress_download_menu_model_
->AddCheckItemWithStringId(
277 ALWAYS_OPEN_TYPE
, IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE
);
278 in_progress_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
279 in_progress_download_menu_model_
->AddItemWithStringId(
280 TOGGLE_PAUSE
, IDS_DOWNLOAD_MENU_PAUSE_ITEM
);
281 in_progress_download_menu_model_
->AddItemWithStringId(
282 SHOW_IN_FOLDER
, IDS_DOWNLOAD_MENU_SHOW
);
283 in_progress_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
284 in_progress_download_menu_model_
->AddItemWithStringId(
285 CANCEL
, IDS_DOWNLOAD_MENU_CANCEL
);
287 return in_progress_download_menu_model_
.get();
290 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetFinishedMenuModel() {
291 if (finished_download_menu_model_
)
292 return finished_download_menu_model_
.get();
294 finished_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
296 finished_download_menu_model_
->AddItemWithStringId(
297 OPEN_WHEN_COMPLETE
, IDS_DOWNLOAD_MENU_OPEN
);
298 finished_download_menu_model_
->AddCheckItemWithStringId(
299 ALWAYS_OPEN_TYPE
, IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE
);
300 if (DownloadItemModel(download_item_
).ShouldPreferOpeningInBrowser())
301 finished_download_menu_model_
->AddItemWithStringId(
302 PLATFORM_OPEN
, IDS_DOWNLOAD_MENU_PLATFORM_OPEN
);
303 finished_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
304 finished_download_menu_model_
->AddItemWithStringId(
305 SHOW_IN_FOLDER
, IDS_DOWNLOAD_MENU_SHOW
);
306 finished_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
307 finished_download_menu_model_
->AddItemWithStringId(
308 CANCEL
, IDS_DOWNLOAD_MENU_CANCEL
);
310 return finished_download_menu_model_
.get();
313 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetInterruptedMenuModel() {
315 // If resumption isn't enabled and we aren't on Windows, then none of the
316 // options here are applicable.
317 if (!IsDownloadResumptionEnabled())
318 return GetInProgressMenuModel();
321 if (interrupted_download_menu_model_
)
322 return interrupted_download_menu_model_
.get();
324 interrupted_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
326 if (IsDownloadResumptionEnabled()) {
327 interrupted_download_menu_model_
->AddItemWithStringId(
328 TOGGLE_PAUSE
, IDS_DOWNLOAD_MENU_RESUME_ITEM
);
331 // The Help Center article is currently Windows specific.
332 // TODO(asanka): Enable this for other platforms when the article is expanded
333 // for other platforms.
334 interrupted_download_menu_model_
->AddItemWithStringId(
335 LEARN_MORE_INTERRUPTED
, IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED
);
337 if (IsDownloadResumptionEnabled()) {
338 interrupted_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
339 interrupted_download_menu_model_
->AddItemWithStringId(
340 CANCEL
, IDS_DOWNLOAD_MENU_CANCEL
);
343 return interrupted_download_menu_model_
.get();
346 ui::SimpleMenuModel
* DownloadShelfContextMenu::GetMaybeMaliciousMenuModel() {
347 if (maybe_malicious_download_menu_model_
)
348 return maybe_malicious_download_menu_model_
.get();
350 maybe_malicious_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
352 maybe_malicious_download_menu_model_
->AddItemWithStringId(
353 KEEP
, IDS_DOWNLOAD_MENU_KEEP
);
354 maybe_malicious_download_menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
355 maybe_malicious_download_menu_model_
->AddItemWithStringId(
356 LEARN_MORE_SCANNING
, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING
);
357 return maybe_malicious_download_menu_model_
.get();
361 DownloadShelfContextMenu::GetMaliciousMenuModel() {
362 if (malicious_download_menu_model_
)
363 return malicious_download_menu_model_
.get();
365 malicious_download_menu_model_
.reset(new ui::SimpleMenuModel(this));
367 DownloadItemModel
download_model(download_item_
);
368 if (download_model
.ShouldAllowDownloadFeedback()) {
369 malicious_download_menu_model_
->AddItemWithStringId(
370 REPORT
, IDS_DOWNLOAD_MENU_REPORT
);
372 malicious_download_menu_model_
->AddItemWithStringId(
373 LEARN_MORE_SCANNING
, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING
);
375 return malicious_download_menu_model_
.get();