b1e9d9aba7e005b0287347741eeddbf92c02c897
[platform/framework/web/crosswalk.git] / src / chrome / browser / download / download_shelf_context_menu.cc
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/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"
23
24 #if defined(OS_WIN)
25 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
26 #endif
27
28 using content::DownloadItem;
29
30 namespace {
31
32 // Returns true if downloads resumption is enabled.
33 bool IsDownloadResumptionEnabled() {
34   return base::CommandLine::ForCurrentProcess()->HasSwitch(
35       switches::kEnableDownloadResumption);
36 }
37
38 }  // namespace
39
40 DownloadShelfContextMenu::~DownloadShelfContextMenu() {
41   DetachFromDownloadItem();
42 }
43
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);
51
52 #if defined(OS_WIN)
53   is_adobe_pdf_reader_up_to_date_ = false;
54   if (IsDownloadPdf() && IsAdobeReaderDefaultPDFViewer()) {
55     is_adobe_pdf_reader_up_to_date_ =
56         DownloadTargetDeterminer::IsAdobeReaderUpToDate();
57   }
58 #endif  // defined(OS_WIN)
59 }
60
61 ui::SimpleMenuModel* DownloadShelfContextMenu::GetMenuModel() {
62   ui::SimpleMenuModel* model = NULL;
63
64   if (!download_item_)
65     return NULL;
66
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());
71
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();
80   else
81     model = GetInProgressMenuModel();
82   return model;
83 }
84
85 bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const {
86   if (!download_item_)
87     return false;
88
89   switch (static_cast<ContextMenuCommands>(command_id)) {
90     case SHOW_IN_FOLDER:
91       return download_item_->CanShowInFolder();
92     case OPEN_WHEN_COMPLETE:
93     case PLATFORM_OPEN:
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_);
102     case CANCEL:
103       return !download_item_->IsDone();
104     case TOGGLE_PAUSE:
105       return !download_item_->IsDone();
106     case DISCARD:
107     case KEEP:
108     case LEARN_MORE_SCANNING:
109     case LEARN_MORE_INTERRUPTED:
110       return true;
111   }
112   NOTREACHED();
113   return false;
114 }
115
116 bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id) const {
117   if (!download_item_)
118     return false;
119
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();
131       }
132 #endif
133       return download_item_->ShouldOpenFileBasedOnExtension();
134     case TOGGLE_PAUSE:
135       return download_item_->IsPaused();
136   }
137   return false;
138 }
139
140 bool DownloadShelfContextMenu::IsCommandIdVisible(int command_id) const {
141   if (!download_item_)
142     return false;
143
144   if (command_id == PLATFORM_OPEN)
145     return (DownloadItemModel(download_item_).ShouldPreferOpeningInBrowser());
146
147   return true;
148 }
149
150 void DownloadShelfContextMenu::ExecuteCommand(int command_id, int event_flags) {
151   if (!download_item_)
152     return;
153
154   switch (static_cast<ContextMenuCommands>(command_id)) {
155     case SHOW_IN_FOLDER:
156       download_item_->ShowDownloadInShell();
157       break;
158     case OPEN_WHEN_COMPLETE:
159       download_item_->OpenDownload();
160       break;
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(
170             is_checked);
171         break;
172       }
173 #endif
174       base::FilePath path = download_item_->GetTargetFilePath();
175       if (is_checked)
176         prefs->DisableAutoOpenBasedOnExtension(path);
177       else
178         prefs->EnableAutoOpenBasedOnExtension(path);
179       break;
180     }
181     case PLATFORM_OPEN:
182       DownloadItemModel(download_item_).OpenUsingPlatformHandler();
183       break;
184     case CANCEL:
185       download_item_->Cancel(true /* Cancelled by user */);
186       break;
187     case TOGGLE_PAUSE:
188       if (download_item_->GetState() == DownloadItem::IN_PROGRESS &&
189           !download_item_->IsPaused()) {
190         download_item_->Pause();
191       } else {
192         download_item_->Resume();
193       }
194       break;
195     case DISCARD:
196       download_item_->Remove();
197       break;
198     case KEEP:
199       download_item_->ValidateDangerousDownload();
200       break;
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_);
210       }
211 #else
212       // Should only be getting invoked if we are using safe browsing.
213       NOTREACHED();
214 #endif
215       break;
216     }
217     case LEARN_MORE_INTERRUPTED:
218       navigator_->OpenURL(
219           content::OpenURLParams(GURL(chrome::kDownloadInterruptedLearnMoreURL),
220                                  content::Referrer(),
221                                  NEW_FOREGROUND_TAB,
222                                  ui::PAGE_TRANSITION_LINK,
223                                  false));
224       break;
225   }
226 }
227
228 bool DownloadShelfContextMenu::GetAcceleratorForCommandId(
229     int command_id, ui::Accelerator* accelerator) {
230   return false;
231 }
232
233 bool DownloadShelfContextMenu::IsItemForCommandIdDynamic(int command_id) const {
234   return command_id == TOGGLE_PAUSE;
235 }
236
237 base::string16 DownloadShelfContextMenu::GetLabelForCommandId(
238     int command_id) const {
239   switch (static_cast<ContextMenuCommands>(command_id)) {
240     case SHOW_IN_FOLDER:
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());
248     case PLATFORM_OPEN:
249       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PLATFORM_OPEN);
250     case CANCEL:
251       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_CANCEL);
252     case TOGGLE_PAUSE:
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);
258     case DISCARD:
259       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_DISCARD);
260     case KEEP:
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);
267   }
268   NOTREACHED();
269   return base::string16();
270 }
271
272 void DownloadShelfContextMenu::DetachFromDownloadItem() {
273   if (!download_item_)
274     return;
275
276   download_item_->RemoveObserver(this);
277   download_item_ = NULL;
278 }
279
280 void DownloadShelfContextMenu::OnDownloadDestroyed(DownloadItem* download) {
281   DCHECK(download_item_ == download);
282   DetachFromDownloadItem();
283 }
284
285 ui::SimpleMenuModel* DownloadShelfContextMenu::GetInProgressMenuModel() {
286   if (in_progress_download_menu_model_)
287     return in_progress_download_menu_model_.get();
288
289   in_progress_download_menu_model_.reset(new ui::SimpleMenuModel(this));
290
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);
303
304   return in_progress_download_menu_model_.get();
305 }
306
307 ui::SimpleMenuModel* DownloadShelfContextMenu::GetFinishedMenuModel() {
308   if (finished_download_menu_model_)
309     return finished_download_menu_model_.get();
310
311   finished_download_menu_model_.reset(new ui::SimpleMenuModel(this));
312
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);
325
326   return finished_download_menu_model_.get();
327 }
328
329 ui::SimpleMenuModel* DownloadShelfContextMenu::GetInterruptedMenuModel() {
330 #if !defined(OS_WIN)
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();
335 #endif
336
337   if (interrupted_download_menu_model_)
338     return interrupted_download_menu_model_.get();
339
340   interrupted_download_menu_model_.reset(new ui::SimpleMenuModel(this));
341
342   if (IsDownloadResumptionEnabled()) {
343     interrupted_download_menu_model_->AddItemWithStringId(
344         TOGGLE_PAUSE, IDS_DOWNLOAD_MENU_RESUME_ITEM);
345   }
346 #if defined(OS_WIN)
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);
352 #endif
353   if (IsDownloadResumptionEnabled()) {
354     interrupted_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
355     interrupted_download_menu_model_->AddItemWithStringId(
356         CANCEL, IDS_DOWNLOAD_MENU_CANCEL);
357   }
358
359   return interrupted_download_menu_model_.get();
360 }
361
362 ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaybeMaliciousMenuModel() {
363   if (maybe_malicious_download_menu_model_)
364     return maybe_malicious_download_menu_model_.get();
365
366   maybe_malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
367
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();
374 }
375
376 ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaliciousMenuModel() {
377   if (malicious_download_menu_model_)
378     return malicious_download_menu_model_.get();
379
380   malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
381
382   DownloadItemModel download_model(download_item_);
383   malicious_download_menu_model_->AddItemWithStringId(
384       LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
385
386   return malicious_download_menu_model_.get();
387 }
388
389 int DownloadShelfContextMenu::GetAlwaysOpenStringId() const {
390 #if defined(OS_WIN)
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;
396 #endif
397   return IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE;
398 }
399
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"));
404 }
405 #endif
406
407 bool DownloadShelfContextMenu::CanOpenPdfInSystemViewer() const {
408 #if defined(OS_WIN)
409   return IsDownloadPdf() &&
410          (IsAdobeReaderDefaultPDFViewer() ? is_adobe_pdf_reader_up_to_date_ :
411                                             true);
412 #elif defined(OS_MACOSX) || defined(OS_LINUX)
413   return IsDownloadPdf();
414 #endif
415 }