ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / ui / webui / downloads_dom_handler.cc
blob1a1dbc90aafa9cb331b7f04107dcc4364e0b0920
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/ui/webui/downloads_dom_handler.h"
7 #include <algorithm>
8 #include <functional>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/i18n/rtl.h"
14 #include "base/i18n/time_formatting.h"
15 #include "base/memory/singleton.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/metrics/histogram.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_piece.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/supports_user_data.h"
23 #include "base/threading/thread.h"
24 #include "base/value_conversions.h"
25 #include "base/values.h"
26 #include "chrome/browser/browser_process.h"
27 #include "chrome/browser/download/download_crx_util.h"
28 #include "chrome/browser/download/download_danger_prompt.h"
29 #include "chrome/browser/download/download_history.h"
30 #include "chrome/browser/download/download_item_model.h"
31 #include "chrome/browser/download/download_prefs.h"
32 #include "chrome/browser/download/download_query.h"
33 #include "chrome/browser/download/download_service.h"
34 #include "chrome/browser/download/download_service_factory.h"
35 #include "chrome/browser/download/drag_download_item.h"
36 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
37 #include "chrome/browser/extensions/extension_service.h"
38 #include "chrome/browser/platform_util.h"
39 #include "chrome/browser/profiles/profile.h"
40 #include "chrome/browser/ui/webui/fileicon_source.h"
41 #include "chrome/common/pref_names.h"
42 #include "chrome/common/url_constants.h"
43 #include "content/public/browser/browser_thread.h"
44 #include "content/public/browser/download_item.h"
45 #include "content/public/browser/url_data_source.h"
46 #include "content/public/browser/user_metrics.h"
47 #include "content/public/browser/web_contents.h"
48 #include "content/public/browser/web_ui.h"
49 #include "extensions/browser/extension_system.h"
50 #include "net/base/filename_util.h"
51 #include "ui/base/l10n/time_format.h"
52 #include "ui/gfx/image/image.h"
54 using base::UserMetricsAction;
55 using content::BrowserContext;
56 using content::BrowserThread;
58 namespace {
60 // Maximum number of downloads to show. TODO(glen): Remove this and instead
61 // stuff the downloads down the pipe slowly.
62 static const size_t kMaxDownloads = 150;
64 enum DownloadsDOMEvent {
65 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0,
66 DOWNLOADS_DOM_EVENT_OPEN_FILE = 1,
67 DOWNLOADS_DOM_EVENT_DRAG = 2,
68 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3,
69 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4,
70 DOWNLOADS_DOM_EVENT_SHOW = 5,
71 DOWNLOADS_DOM_EVENT_PAUSE = 6,
72 DOWNLOADS_DOM_EVENT_REMOVE = 7,
73 DOWNLOADS_DOM_EVENT_CANCEL = 8,
74 DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9,
75 DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10,
76 DOWNLOADS_DOM_EVENT_RESUME = 11,
77 DOWNLOADS_DOM_EVENT_MAX
80 void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
81 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
82 event,
83 DOWNLOADS_DOM_EVENT_MAX);
86 // Returns a string constant to be used as the |danger_type| value in
87 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE,
88 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
89 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
90 const char* GetDangerTypeString(content::DownloadDangerType danger_type) {
91 switch (danger_type) {
92 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
93 return "DANGEROUS_FILE";
94 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
95 return "DANGEROUS_URL";
96 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
97 return "DANGEROUS_CONTENT";
98 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
99 return "UNCOMMON_CONTENT";
100 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
101 return "DANGEROUS_HOST";
102 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
103 return "POTENTIALLY_UNWANTED";
104 default:
105 // Don't return a danger type string if it is NOT_DANGEROUS or
106 // MAYBE_DANGEROUS_CONTENT.
107 NOTREACHED();
108 return "";
112 // Returns a JSON dictionary containing some of the attributes of |download|.
113 // The JSON dictionary will also have a field "id" set to |id|, and a field
114 // "otr" set to |incognito|.
115 base::DictionaryValue* CreateDownloadItemValue(
116 content::DownloadItem* download_item,
117 bool incognito) {
118 // TODO(asanka): Move towards using download_model here for getting status and
119 // progress. The difference currently only matters to Drive downloads and
120 // those don't show up on the downloads page, but should.
121 DownloadItemModel download_model(download_item);
123 // The items which are to be written into file_value are also described in
124 // chrome/browser/resources/downloads/downloads.js in @typedef for
125 // BackendDownloadObject. Please update it whenever you add or remove
126 // any keys in file_value.
127 base::DictionaryValue* file_value = new base::DictionaryValue();
129 file_value->SetInteger(
130 "started", static_cast<int>(download_item->GetStartTime().ToTimeT()));
131 file_value->SetString(
132 "since_string", ui::TimeFormat::RelativeDate(
133 download_item->GetStartTime(), NULL));
134 file_value->SetString(
135 "date_string", base::TimeFormatShortDate(download_item->GetStartTime()));
136 file_value->SetString("id", base::Uint64ToString(download_item->GetId()));
138 base::FilePath download_path(download_item->GetTargetFilePath());
139 file_value->Set("file_path", base::CreateFilePathValue(download_path));
140 file_value->SetString("file_url",
141 net::FilePathToFileURL(download_path).spec());
143 extensions::DownloadedByExtension* by_ext =
144 extensions::DownloadedByExtension::Get(download_item);
145 if (by_ext) {
146 file_value->SetString("by_ext_id", by_ext->id());
147 file_value->SetString("by_ext_name", by_ext->name());
148 // Lookup the extension's current name() in case the user changed their
149 // language. This won't work if the extension was uninstalled, so the name
150 // might be the wrong language.
151 bool include_disabled = true;
152 const extensions::Extension* extension = extensions::ExtensionSystem::Get(
153 Profile::FromBrowserContext(download_item->GetBrowserContext()))->
154 extension_service()->GetExtensionById(by_ext->id(), include_disabled);
155 if (extension)
156 file_value->SetString("by_ext_name", extension->name());
159 // Keep file names as LTR.
160 base::string16 file_name =
161 download_item->GetFileNameToReportUser().LossyDisplayName();
162 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name);
163 file_value->SetString("file_name", file_name);
164 file_value->SetString("url", download_item->GetURL().spec());
165 file_value->SetBoolean("otr", incognito);
166 file_value->SetInteger("total", static_cast<int>(
167 download_item->GetTotalBytes()));
168 file_value->SetBoolean("file_externally_removed",
169 download_item->GetFileExternallyRemoved());
170 file_value->SetBoolean("retry", false); // Overridden below if needed.
171 file_value->SetBoolean("resume", download_item->CanResume());
173 switch (download_item->GetState()) {
174 case content::DownloadItem::IN_PROGRESS:
175 if (download_item->IsDangerous()) {
176 file_value->SetString("state", "DANGEROUS");
177 // These are the only danger states that the UI is equipped to handle.
178 DCHECK(download_item->GetDangerType() ==
179 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
180 download_item->GetDangerType() ==
181 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
182 download_item->GetDangerType() ==
183 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
184 download_item->GetDangerType() ==
185 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
186 download_item->GetDangerType() ==
187 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
188 download_item->GetDangerType() ==
189 content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
190 const char* danger_type_value =
191 GetDangerTypeString(download_item->GetDangerType());
192 file_value->SetString("danger_type", danger_type_value);
193 } else if (download_item->IsPaused()) {
194 file_value->SetString("state", "PAUSED");
195 } else {
196 file_value->SetString("state", "IN_PROGRESS");
198 file_value->SetString("progress_status_text",
199 download_model.GetTabProgressStatusText());
201 file_value->SetInteger("percent",
202 static_cast<int>(download_item->PercentComplete()));
203 file_value->SetInteger("received",
204 static_cast<int>(download_item->GetReceivedBytes()));
205 break;
207 case content::DownloadItem::INTERRUPTED:
208 file_value->SetString("state", "INTERRUPTED");
210 file_value->SetString("progress_status_text",
211 download_model.GetTabProgressStatusText());
213 file_value->SetInteger("percent",
214 static_cast<int>(download_item->PercentComplete()));
215 file_value->SetInteger("received",
216 static_cast<int>(download_item->GetReceivedBytes()));
217 file_value->SetString("last_reason_text",
218 download_model.GetInterruptReasonText());
219 if (content::DOWNLOAD_INTERRUPT_REASON_CRASH ==
220 download_item->GetLastReason() && !download_item->CanResume())
221 file_value->SetBoolean("retry", true);
222 break;
224 case content::DownloadItem::CANCELLED:
225 file_value->SetString("state", "CANCELLED");
226 file_value->SetBoolean("retry", true);
227 break;
229 case content::DownloadItem::COMPLETE:
230 DCHECK(!download_item->IsDangerous());
231 file_value->SetString("state", "COMPLETE");
232 break;
234 case content::DownloadItem::MAX_DOWNLOAD_STATE:
235 NOTREACHED();
238 return file_value;
241 // Filters out extension downloads and downloads that don't have a filename yet.
242 bool IsDownloadDisplayable(const content::DownloadItem& item) {
243 return !download_crx_util::IsExtensionDownload(item) &&
244 !item.IsTemporary() &&
245 !item.GetFileNameToReportUser().empty() &&
246 !item.GetTargetFilePath().empty() &&
247 DownloadItemModel(
248 const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf();
251 } // namespace
253 DownloadsDOMHandler::DownloadsDOMHandler(content::DownloadManager* dlm)
254 : main_notifier_(dlm, this),
255 update_scheduled_(false),
256 weak_ptr_factory_(this) {
257 // Create our fileicon data source.
258 Profile* profile = Profile::FromBrowserContext(dlm->GetBrowserContext());
259 content::URLDataSource::Add(profile, new FileIconSource());
261 if (profile->IsOffTheRecord()) {
262 original_notifier_.reset(new AllDownloadItemNotifier(
263 BrowserContext::GetDownloadManager(profile->GetOriginalProfile()),
264 this));
268 DownloadsDOMHandler::~DownloadsDOMHandler() {
269 FinalizeRemovals();
272 // DownloadsDOMHandler, public: -----------------------------------------------
274 void DownloadsDOMHandler::OnPageLoaded(const base::ListValue* args) {
275 SendCurrentDownloads();
278 void DownloadsDOMHandler::RegisterMessages() {
279 web_ui()->RegisterMessageCallback("onPageLoaded",
280 base::Bind(&DownloadsDOMHandler::OnPageLoaded,
281 weak_ptr_factory_.GetWeakPtr()));
282 web_ui()->RegisterMessageCallback("getDownloads",
283 base::Bind(&DownloadsDOMHandler::HandleGetDownloads,
284 weak_ptr_factory_.GetWeakPtr()));
285 web_ui()->RegisterMessageCallback("openFile",
286 base::Bind(&DownloadsDOMHandler::HandleOpenFile,
287 weak_ptr_factory_.GetWeakPtr()));
288 web_ui()->RegisterMessageCallback("drag",
289 base::Bind(&DownloadsDOMHandler::HandleDrag,
290 weak_ptr_factory_.GetWeakPtr()));
291 web_ui()->RegisterMessageCallback("saveDangerous",
292 base::Bind(&DownloadsDOMHandler::HandleSaveDangerous,
293 weak_ptr_factory_.GetWeakPtr()));
294 web_ui()->RegisterMessageCallback("discardDangerous",
295 base::Bind(&DownloadsDOMHandler::HandleDiscardDangerous,
296 weak_ptr_factory_.GetWeakPtr()));
297 web_ui()->RegisterMessageCallback("show",
298 base::Bind(&DownloadsDOMHandler::HandleShow,
299 weak_ptr_factory_.GetWeakPtr()));
300 web_ui()->RegisterMessageCallback("pause",
301 base::Bind(&DownloadsDOMHandler::HandlePause,
302 weak_ptr_factory_.GetWeakPtr()));
303 web_ui()->RegisterMessageCallback("resume",
304 base::Bind(&DownloadsDOMHandler::HandleResume,
305 weak_ptr_factory_.GetWeakPtr()));
306 web_ui()->RegisterMessageCallback("remove",
307 base::Bind(&DownloadsDOMHandler::HandleRemove,
308 weak_ptr_factory_.GetWeakPtr()));
309 web_ui()->RegisterMessageCallback("undo",
310 base::Bind(&DownloadsDOMHandler::HandleUndo,
311 weak_ptr_factory_.GetWeakPtr()));
312 web_ui()->RegisterMessageCallback("cancel",
313 base::Bind(&DownloadsDOMHandler::HandleCancel,
314 weak_ptr_factory_.GetWeakPtr()));
315 web_ui()->RegisterMessageCallback("clearAll",
316 base::Bind(&DownloadsDOMHandler::HandleClearAll,
317 weak_ptr_factory_.GetWeakPtr()));
318 web_ui()->RegisterMessageCallback("openDownloadsFolder",
319 base::Bind(&DownloadsDOMHandler::HandleOpenDownloadsFolder,
320 weak_ptr_factory_.GetWeakPtr()));
323 void DownloadsDOMHandler::OnDownloadCreated(
324 content::DownloadManager* manager, content::DownloadItem* download_item) {
325 if (IsDownloadDisplayable(*download_item))
326 ScheduleSendCurrentDownloads();
329 void DownloadsDOMHandler::OnDownloadUpdated(
330 content::DownloadManager* manager,
331 content::DownloadItem* download_item) {
332 if (IsDownloadDisplayable(*download_item)) {
333 if (search_terms_ && !search_terms_->empty()) {
334 // Don't CallDownloadUpdated() if download_item doesn't match
335 // search_terms_.
336 // TODO(benjhayden): Consider splitting MatchesQuery() out to a function.
337 content::DownloadManager::DownloadVector all_items, filtered_items;
338 all_items.push_back(download_item);
339 DownloadQuery query;
340 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_.get());
341 query.Search(all_items.begin(), all_items.end(), &filtered_items);
342 if (filtered_items.empty())
343 return;
345 base::ListValue results_value;
346 results_value.Append(CreateDownloadItemValue(
347 download_item,
348 (original_notifier_.get() &&
349 (manager == main_notifier_.GetManager()))));
350 CallDownloadUpdated(results_value);
351 } else {
352 ScheduleSendCurrentDownloads();
356 void DownloadsDOMHandler::OnDownloadRemoved(
357 content::DownloadManager* manager,
358 content::DownloadItem* download_item) {
359 if (!DownloadItemModel(download_item).ShouldShowInShelf())
360 return;
362 // This relies on |download_item| being removed from DownloadManager in this
363 // MessageLoop iteration. |download_item| may not have been removed from
364 // DownloadManager when OnDownloadRemoved() is fired, so bounce off the
365 // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks
366 // at all downloads, and we do not tell it that |download_item| is being
367 // removed. If DownloadManager is ever changed to not immediately remove
368 // |download_item| from its map when OnDownloadRemoved is sent, then
369 // DownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell
370 // SendCurrentDownloads() that |download_item| was removed. A
371 // SupportsUserData::Data would be the correct way to do this.
372 ScheduleSendCurrentDownloads();
375 void DownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) {
376 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS);
377 search_terms_.reset((args && !args->empty()) ? args->DeepCopy() : NULL);
378 SendCurrentDownloads();
381 void DownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) {
382 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE);
383 content::DownloadItem* file = GetDownloadByValue(args);
384 if (file)
385 file->OpenDownload();
388 void DownloadsDOMHandler::HandleDrag(const base::ListValue* args) {
389 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG);
390 content::DownloadItem* file = GetDownloadByValue(args);
391 if (!file)
392 return;
394 content::WebContents* web_contents = GetWebUIWebContents();
395 // |web_contents| is only NULL in the test.
396 if (!web_contents)
397 return;
399 if (file->GetState() != content::DownloadItem::COMPLETE)
400 return;
402 gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath(
403 file->GetTargetFilePath(), IconLoader::NORMAL);
404 gfx::NativeView view = web_contents->GetNativeView();
406 // Enable nested tasks during DnD, while |DragDownload()| blocks.
407 base::MessageLoop::ScopedNestableTaskAllower allow(
408 base::MessageLoop::current());
409 DragDownloadItem(file, icon, view);
413 void DownloadsDOMHandler::HandleSaveDangerous(const base::ListValue* args) {
414 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
415 content::DownloadItem* file = GetDownloadByValue(args);
416 if (file)
417 ShowDangerPrompt(file);
420 void DownloadsDOMHandler::HandleDiscardDangerous(const base::ListValue* args) {
421 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS);
422 content::DownloadItem* file = GetDownloadByValue(args);
423 if (file)
424 file->Remove();
427 void DownloadsDOMHandler::HandleShow(const base::ListValue* args) {
428 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW);
429 content::DownloadItem* file = GetDownloadByValue(args);
430 if (file)
431 file->ShowDownloadInShell();
434 void DownloadsDOMHandler::HandlePause(const base::ListValue* args) {
435 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE);
436 content::DownloadItem* file = GetDownloadByValue(args);
437 if (file)
438 file->Pause();
441 void DownloadsDOMHandler::HandleResume(const base::ListValue* args) {
442 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_RESUME);
443 content::DownloadItem* file = GetDownloadByValue(args);
444 if (file)
445 file->Resume();
448 void DownloadsDOMHandler::HandleRemove(const base::ListValue* args) {
449 if (!IsDeletingHistoryAllowed())
450 return;
452 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE);
453 content::DownloadItem* file = GetDownloadByValue(args);
454 if (!file)
455 return;
457 std::vector<content::DownloadItem*> downloads;
458 downloads.push_back(file);
459 RemoveDownloads(downloads);
462 void DownloadsDOMHandler::HandleUndo(const base::ListValue* args) {
463 // TODO(dbeam): handle more than removed downloads someday?
464 if (removals_.empty())
465 return;
467 const std::set<uint32> last_removed_ids = removals_.back();
468 removals_.pop_back();
470 for (auto id : last_removed_ids) {
471 content::DownloadItem* download = GetDownloadById(id);
472 if (!download)
473 continue;
474 DownloadItemModel(download).SetShouldShowInShelf(true);
475 download->UpdateObservers();
479 void DownloadsDOMHandler::HandleCancel(const base::ListValue* args) {
480 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL);
481 content::DownloadItem* file = GetDownloadByValue(args);
482 if (file)
483 file->Cancel(true);
486 void DownloadsDOMHandler::HandleClearAll(const base::ListValue* args) {
487 if (!IsDeletingHistoryAllowed())
488 return;
490 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL);
492 std::vector<content::DownloadItem*> downloads;
493 if (GetMainNotifierManager())
494 GetMainNotifierManager()->GetAllDownloads(&downloads);
495 if (original_notifier_ && original_notifier_->GetManager())
496 original_notifier_->GetManager()->GetAllDownloads(&downloads);
497 RemoveDownloads(downloads);
500 void DownloadsDOMHandler::RemoveDownloads(
501 const std::vector<content::DownloadItem*>& to_remove) {
502 std::set<uint32> ids;
503 for (auto* download : to_remove) {
504 DownloadItemModel item_model(download);
505 if (!item_model.ShouldShowInShelf() ||
506 download->GetState() == content::DownloadItem::IN_PROGRESS) {
507 continue;
510 item_model.SetShouldShowInShelf(false);
511 ids.insert(download->GetId());
512 download->UpdateObservers();
514 if (!ids.empty())
515 removals_.push_back(ids);
518 void DownloadsDOMHandler::HandleOpenDownloadsFolder(
519 const base::ListValue* args) {
520 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER);
521 content::DownloadManager* manager = main_notifier_.GetManager();
522 if (manager) {
523 platform_util::OpenItem(
524 Profile::FromBrowserContext(manager->GetBrowserContext()),
525 DownloadPrefs::FromDownloadManager(manager)->DownloadPath());
529 // DownloadsDOMHandler, private: ----------------------------------------------
531 void DownloadsDOMHandler::ScheduleSendCurrentDownloads() {
532 // Don't call SendCurrentDownloads() every time anything changes. Batch them
533 // together instead. This may handle hundreds of OnDownloadDestroyed() calls
534 // in a single UI message loop iteration when the user Clears All downloads.
535 if (update_scheduled_)
536 return;
537 update_scheduled_ = true;
538 BrowserThread::PostTask(
539 BrowserThread::UI, FROM_HERE,
540 base::Bind(&DownloadsDOMHandler::SendCurrentDownloads,
541 weak_ptr_factory_.GetWeakPtr()));
544 content::DownloadManager* DownloadsDOMHandler::GetMainNotifierManager() {
545 return main_notifier_.GetManager();
548 void DownloadsDOMHandler::FinalizeRemovals() {
549 while (!removals_.empty()) {
550 const std::set<uint32> remove = removals_.back();
551 removals_.pop_back();
553 for (const auto id : remove) {
554 content::DownloadItem* download = GetDownloadById(id);
555 if (download)
556 download->Remove();
561 void DownloadsDOMHandler::SendCurrentDownloads() {
562 update_scheduled_ = false;
563 content::DownloadManager::DownloadVector all_items, filtered_items;
564 if (main_notifier_.GetManager()) {
565 main_notifier_.GetManager()->GetAllDownloads(&all_items);
566 main_notifier_.GetManager()->CheckForHistoryFilesRemoval();
568 if (original_notifier_.get() && original_notifier_->GetManager()) {
569 original_notifier_->GetManager()->GetAllDownloads(&all_items);
570 original_notifier_->GetManager()->CheckForHistoryFilesRemoval();
572 DownloadQuery query;
573 if (search_terms_ && !search_terms_->empty()) {
574 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_.get());
576 query.AddFilter(base::Bind(&IsDownloadDisplayable));
577 query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING);
578 query.Limit(kMaxDownloads);
579 query.Search(all_items.begin(), all_items.end(), &filtered_items);
580 base::ListValue results_value;
581 for (content::DownloadManager::DownloadVector::iterator
582 iter = filtered_items.begin(); iter != filtered_items.end(); ++iter) {
583 results_value.Append(CreateDownloadItemValue(
584 *iter,
585 (original_notifier_.get() &&
586 main_notifier_.GetManager() &&
587 (main_notifier_.GetManager()->GetDownload((*iter)->GetId()) ==
588 *iter))));
590 CallDownloadsList(results_value);
593 void DownloadsDOMHandler::ShowDangerPrompt(
594 content::DownloadItem* dangerous_item) {
595 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create(
596 dangerous_item,
597 GetWebUIWebContents(),
598 false,
599 base::Bind(&DownloadsDOMHandler::DangerPromptDone,
600 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId()));
601 // danger_prompt will delete itself.
602 DCHECK(danger_prompt);
605 void DownloadsDOMHandler::DangerPromptDone(
606 int download_id, DownloadDangerPrompt::Action action) {
607 if (action != DownloadDangerPrompt::ACCEPT)
608 return;
609 content::DownloadItem* item = NULL;
610 if (main_notifier_.GetManager())
611 item = main_notifier_.GetManager()->GetDownload(download_id);
612 if (!item && original_notifier_.get() && original_notifier_->GetManager())
613 item = original_notifier_->GetManager()->GetDownload(download_id);
614 if (!item || item->IsDone())
615 return;
616 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
617 item->ValidateDangerousDownload();
620 bool DownloadsDOMHandler::IsDeletingHistoryAllowed() {
621 content::DownloadManager* manager = main_notifier_.GetManager();
622 return (manager &&
623 Profile::FromBrowserContext(manager->GetBrowserContext())->
624 GetPrefs()->GetBoolean(prefs::kAllowDeletingBrowserHistory));
627 content::DownloadItem* DownloadsDOMHandler::GetDownloadByValue(
628 const base::ListValue* args) {
629 std::string download_id;
630 if (!args->GetString(0, &download_id)) {
631 NOTREACHED();
632 return nullptr;
635 uint64 id;
636 if (!base::StringToUint64(download_id, &id)) {
637 NOTREACHED();
638 return nullptr;
641 return GetDownloadById(static_cast<uint32>(id));
644 content::DownloadItem* DownloadsDOMHandler::GetDownloadById(uint32 id) {
645 content::DownloadItem* item = NULL;
646 if (GetMainNotifierManager())
647 item = GetMainNotifierManager()->GetDownload(id);
648 if (!item && original_notifier_.get() && original_notifier_->GetManager())
649 item = original_notifier_->GetManager()->GetDownload(id);
650 return item;
653 content::WebContents* DownloadsDOMHandler::GetWebUIWebContents() {
654 return web_ui()->GetWebContents();
657 void DownloadsDOMHandler::CallDownloadsList(const base::ListValue& downloads) {
658 web_ui()->CallJavascriptFunction("downloadsList", downloads);
661 void DownloadsDOMHandler::CallDownloadUpdated(
662 const base::ListValue& download_item) {
663 web_ui()->CallJavascriptFunction("downloadUpdated", download_item);