Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(301)

Side by Side Diff: chrome/browser/ui/webui/downloads_dom_handler.cc

Issue 1710083005: Remove old downloads UI; Material Design version is now the default. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: remove testing/ Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/ui/webui/downloads_dom_handler.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <functional>
11
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/i18n/rtl.h"
15 #include "base/i18n/time_formatting.h"
16 #include "base/logging.h"
17 #include "base/memory/singleton.h"
18 #include "base/metrics/field_trial.h"
19 #include "base/metrics/histogram.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_piece.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/supports_user_data.h"
24 #include "base/threading/thread.h"
25 #include "base/value_conversions.h"
26 #include "base/values.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/download/download_crx_util.h"
29 #include "chrome/browser/download/download_danger_prompt.h"
30 #include "chrome/browser/download/download_history.h"
31 #include "chrome/browser/download/download_item_model.h"
32 #include "chrome/browser/download/download_prefs.h"
33 #include "chrome/browser/download/download_query.h"
34 #include "chrome/browser/download/download_service.h"
35 #include "chrome/browser/download/download_service_factory.h"
36 #include "chrome/browser/download/drag_download_item.h"
37 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
38 #include "chrome/browser/extensions/extension_service.h"
39 #include "chrome/browser/platform_util.h"
40 #include "chrome/browser/profiles/profile.h"
41 #include "chrome/browser/ui/webui/fileicon_source.h"
42 #include "chrome/common/chrome_switches.h"
43 #include "chrome/common/pref_names.h"
44 #include "chrome/common/url_constants.h"
45 #include "components/prefs/pref_service.h"
46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/download_item.h"
48 #include "content/public/browser/url_data_source.h"
49 #include "content/public/browser/user_metrics.h"
50 #include "content/public/browser/web_contents.h"
51 #include "content/public/browser/web_ui.h"
52 #include "extensions/browser/extension_system.h"
53 #include "net/base/filename_util.h"
54 #include "third_party/icu/source/i18n/unicode/datefmt.h"
55 #include "ui/base/l10n/time_format.h"
56 #include "ui/gfx/image/image.h"
57
58 using base::UserMetricsAction;
59 using content::BrowserContext;
60 using content::BrowserThread;
61
62 namespace {
63
64 // Maximum number of downloads to show. TODO(glen): Remove this and instead
65 // stuff the downloads down the pipe slowly.
66 size_t kMaxNumberOfDownloads = 150;
67
68 enum DownloadsDOMEvent {
69 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0,
70 DOWNLOADS_DOM_EVENT_OPEN_FILE = 1,
71 DOWNLOADS_DOM_EVENT_DRAG = 2,
72 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3,
73 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4,
74 DOWNLOADS_DOM_EVENT_SHOW = 5,
75 DOWNLOADS_DOM_EVENT_PAUSE = 6,
76 DOWNLOADS_DOM_EVENT_REMOVE = 7,
77 DOWNLOADS_DOM_EVENT_CANCEL = 8,
78 DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9,
79 DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10,
80 DOWNLOADS_DOM_EVENT_RESUME = 11,
81 DOWNLOADS_DOM_EVENT_MAX
82 };
83
84 void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
85 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
86 event,
87 DOWNLOADS_DOM_EVENT_MAX);
88 }
89
90 // Returns a string constant to be used as the |danger_type| value in
91 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE,
92 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
93 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
94 const char* GetDangerTypeString(content::DownloadDangerType danger_type) {
95 switch (danger_type) {
96 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
97 return "DANGEROUS_FILE";
98 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
99 return "DANGEROUS_URL";
100 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
101 return "DANGEROUS_CONTENT";
102 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
103 return "UNCOMMON_CONTENT";
104 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
105 return "DANGEROUS_HOST";
106 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
107 return "POTENTIALLY_UNWANTED";
108 default:
109 // Don't return a danger type string if it is NOT_DANGEROUS or
110 // MAYBE_DANGEROUS_CONTENT.
111 NOTREACHED();
112 return "";
113 }
114 }
115
116 // Returns a JSON dictionary containing some of the attributes of |download|.
117 // The JSON dictionary will also have a field "id" set to |id|, and a field
118 // "otr" set to |incognito|.
119 base::DictionaryValue* CreateDownloadItemValue(
120 content::DownloadItem* download_item,
121 bool incognito) {
122 // TODO(asanka): Move towards using download_model here for getting status and
123 // progress. The difference currently only matters to Drive downloads and
124 // those don't show up on the downloads page, but should.
125 DownloadItemModel download_model(download_item);
126
127 // The items which are to be written into file_value are also described in
128 // chrome/browser/resources/downloads/downloads.js in @typedef for
129 // BackendDownloadObject. Please update it whenever you add or remove
130 // any keys in file_value.
131 base::DictionaryValue* file_value = new base::DictionaryValue();
132
133 file_value->SetInteger(
134 "started", static_cast<int>(download_item->GetStartTime().ToTimeT()));
135 file_value->SetString(
136 "since_string", ui::TimeFormat::RelativeDate(
137 download_item->GetStartTime(), NULL));
138
139 base::Time start_time = download_item->GetStartTime();
140 base::string16 date_string = base::TimeFormatShortDate(start_time);
141 file_value->SetString("date_string", date_string);
142
143 file_value->SetString("id", base::Uint64ToString(download_item->GetId()));
144
145 base::FilePath download_path(download_item->GetTargetFilePath());
146 file_value->Set("file_path", base::CreateFilePathValue(download_path));
147 file_value->SetString("file_url",
148 net::FilePathToFileURL(download_path).spec());
149
150 extensions::DownloadedByExtension* by_ext =
151 extensions::DownloadedByExtension::Get(download_item);
152 std::string by_ext_id;
153 std::string by_ext_name;
154 if (by_ext) {
155 by_ext_id = by_ext->id();
156 // TODO(dbeam): why doesn't DownloadsByExtension::name() return a string16?
157 by_ext_name = by_ext->name();
158
159 // Lookup the extension's current name() in case the user changed their
160 // language. This won't work if the extension was uninstalled, so the name
161 // might be the wrong language.
162 bool include_disabled = true;
163 const extensions::Extension* extension = extensions::ExtensionSystem::Get(
164 Profile::FromBrowserContext(download_item->GetBrowserContext()))->
165 extension_service()->GetExtensionById(by_ext->id(), include_disabled);
166 if (extension)
167 file_value->SetString("by_ext_name", extension->name());
168 }
169 file_value->SetString("by_ext_id", by_ext_id);
170 file_value->SetString("by_ext_name", by_ext_name);
171
172 // Keep file names as LTR.
173 base::string16 file_name =
174 download_item->GetFileNameToReportUser().LossyDisplayName();
175 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name);
176 file_value->SetString("file_name", file_name);
177 file_value->SetString("url", download_item->GetURL().spec());
178 file_value->SetBoolean("otr", incognito);
179 file_value->SetInteger("total", static_cast<int>(
180 download_item->GetTotalBytes()));
181 file_value->SetBoolean("file_externally_removed",
182 download_item->GetFileExternallyRemoved());
183 file_value->SetBoolean("resume", download_item->CanResume());
184
185 const char* danger_type = "";
186 base::string16 last_reason_text;
187 // -2 is invalid, -1 means indeterminate, and 0-100 are in-progress.
188 int percent = -2;
189 base::string16 progress_status_text;
190 bool retry = false;
191 const char* state = nullptr;
192
193 switch (download_item->GetState()) {
194 case content::DownloadItem::IN_PROGRESS: {
195 if (download_item->IsDangerous()) {
196 state = "DANGEROUS";
197 // These are the only danger states that the UI is equipped to handle.
198 DCHECK(download_item->GetDangerType() ==
199 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
200 download_item->GetDangerType() ==
201 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
202 download_item->GetDangerType() ==
203 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
204 download_item->GetDangerType() ==
205 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
206 download_item->GetDangerType() ==
207 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
208 download_item->GetDangerType() ==
209 content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
210 danger_type = GetDangerTypeString(download_item->GetDangerType());
211 } else if (download_item->IsPaused()) {
212 state = "PAUSED";
213 } else {
214 state = "IN_PROGRESS";
215 }
216 progress_status_text = download_model.GetTabProgressStatusText();
217 percent = std::max(0, download_item->PercentComplete());
218 break;
219 }
220
221 case content::DownloadItem::INTERRUPTED:
222 state = "INTERRUPTED";
223 progress_status_text = download_model.GetTabProgressStatusText();
224
225 if (download_item->CanResume())
226 percent = download_item->PercentComplete();
227
228 last_reason_text = download_model.GetInterruptReasonText();
229 if (content::DOWNLOAD_INTERRUPT_REASON_CRASH ==
230 download_item->GetLastReason() && !download_item->CanResume()) {
231 retry = true;
232 }
233 break;
234
235 case content::DownloadItem::CANCELLED:
236 state = "CANCELLED";
237 retry = true;
238 break;
239
240 case content::DownloadItem::COMPLETE:
241 DCHECK(!download_item->IsDangerous());
242 state = "COMPLETE";
243 break;
244
245 case content::DownloadItem::MAX_DOWNLOAD_STATE:
246 NOTREACHED();
247 }
248
249 DCHECK(state);
250
251 file_value->SetString("danger_type", danger_type);
252 file_value->SetString("last_reason_text", last_reason_text);
253 file_value->SetInteger("percent", percent);
254 file_value->SetString("progress_status_text", progress_status_text);
255 file_value->SetBoolean("retry", retry);
256 file_value->SetString("state", state);
257
258 return file_value;
259 }
260
261 // Filters out extension downloads and downloads that don't have a filename yet.
262 bool IsDownloadDisplayable(const content::DownloadItem& item) {
263 return !download_crx_util::IsExtensionDownload(item) &&
264 !item.IsTemporary() &&
265 !item.GetFileNameToReportUser().empty() &&
266 !item.GetTargetFilePath().empty() &&
267 DownloadItemModel(
268 const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf();
269 }
270
271 } // namespace
272
273 DownloadsDOMHandler::DownloadsDOMHandler(
274 content::DownloadManager* download_manager)
275 : download_manager_(download_manager),
276 update_scheduled_(false),
277 weak_ptr_factory_(this) {
278 // Create our fileicon data source.
279 Profile* profile = Profile::FromBrowserContext(
280 download_manager->GetBrowserContext());
281 content::URLDataSource::Add(profile, new FileIconSource());
282 }
283
284 DownloadsDOMHandler::~DownloadsDOMHandler() {
285 FinalizeRemovals();
286 }
287
288 // DownloadsDOMHandler, public: -----------------------------------------------
289
290 void DownloadsDOMHandler::RegisterMessages() {
291 web_ui()->RegisterMessageCallback("getDownloads",
292 base::Bind(&DownloadsDOMHandler::HandleGetDownloads,
293 weak_ptr_factory_.GetWeakPtr()));
294 web_ui()->RegisterMessageCallback("openFile",
295 base::Bind(&DownloadsDOMHandler::HandleOpenFile,
296 weak_ptr_factory_.GetWeakPtr()));
297 web_ui()->RegisterMessageCallback("drag",
298 base::Bind(&DownloadsDOMHandler::HandleDrag,
299 weak_ptr_factory_.GetWeakPtr()));
300 web_ui()->RegisterMessageCallback("saveDangerous",
301 base::Bind(&DownloadsDOMHandler::HandleSaveDangerous,
302 weak_ptr_factory_.GetWeakPtr()));
303 web_ui()->RegisterMessageCallback("discardDangerous",
304 base::Bind(&DownloadsDOMHandler::HandleDiscardDangerous,
305 weak_ptr_factory_.GetWeakPtr()));
306 web_ui()->RegisterMessageCallback("show",
307 base::Bind(&DownloadsDOMHandler::HandleShow,
308 weak_ptr_factory_.GetWeakPtr()));
309 web_ui()->RegisterMessageCallback("pause",
310 base::Bind(&DownloadsDOMHandler::HandlePause,
311 weak_ptr_factory_.GetWeakPtr()));
312 web_ui()->RegisterMessageCallback("resume",
313 base::Bind(&DownloadsDOMHandler::HandleResume,
314 weak_ptr_factory_.GetWeakPtr()));
315 web_ui()->RegisterMessageCallback("remove",
316 base::Bind(&DownloadsDOMHandler::HandleRemove,
317 weak_ptr_factory_.GetWeakPtr()));
318 web_ui()->RegisterMessageCallback("undo",
319 base::Bind(&DownloadsDOMHandler::HandleUndo,
320 weak_ptr_factory_.GetWeakPtr()));
321 web_ui()->RegisterMessageCallback("cancel",
322 base::Bind(&DownloadsDOMHandler::HandleCancel,
323 weak_ptr_factory_.GetWeakPtr()));
324 web_ui()->RegisterMessageCallback("clearAll",
325 base::Bind(&DownloadsDOMHandler::HandleClearAll,
326 weak_ptr_factory_.GetWeakPtr()));
327 web_ui()->RegisterMessageCallback("openDownloadsFolder",
328 base::Bind(&DownloadsDOMHandler::HandleOpenDownloadsFolder,
329 weak_ptr_factory_.GetWeakPtr()));
330 }
331
332 void DownloadsDOMHandler::OnDownloadCreated(
333 content::DownloadManager* manager, content::DownloadItem* download_item) {
334 if (IsDownloadDisplayable(*download_item))
335 ScheduleSendCurrentDownloads();
336 else
337 new_downloads_.insert(download_item->GetId());
338 }
339
340 void DownloadsDOMHandler::OnDownloadUpdated(
341 content::DownloadManager* manager,
342 content::DownloadItem* download_item) {
343 if (update_scheduled_)
344 return;
345
346 bool showing_new_item = false;
347
348 if (new_downloads_.count(download_item->GetId())) {
349 // A new download (that the page doesn't know about yet) has been updated.
350 if (!IsDownloadDisplayable(*download_item)) {
351 // Item isn't ready to be displayed yet. Wait until it is.
352 return;
353 }
354
355 new_downloads_.erase(download_item->GetId());
356 showing_new_item = true;
357 }
358
359 if (showing_new_item || DownloadItemModel(download_item).IsBeingRevived() ||
360 !IsDownloadDisplayable(*download_item)) {
361 // A download will be shown or hidden by this update. Resend the list.
362 ScheduleSendCurrentDownloads();
363 return;
364 }
365
366 if (search_terms_ && !search_terms_->empty()) {
367 // Don't CallUpdateItem() if download_item doesn't match
368 // search_terms_.
369 // TODO(benjhayden): Consider splitting MatchesQuery() out to a function.
370 content::DownloadManager::DownloadVector all_items, filtered_items;
371 all_items.push_back(download_item);
372 DownloadQuery query;
373 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_);
374 query.Search(all_items.begin(), all_items.end(), &filtered_items);
375 if (filtered_items.empty())
376 return;
377 }
378
379 DCHECK(manager);
380 scoped_ptr<base::DictionaryValue> item(CreateDownloadItemValue(
381 download_item,
382 original_notifier_ && manager == GetMainNotifierManager()));
383 CallUpdateItem(*item);
384 }
385
386 void DownloadsDOMHandler::OnDownloadRemoved(
387 content::DownloadManager* manager,
388 content::DownloadItem* download_item) {
389 if (!DownloadItemModel(download_item).ShouldShowInShelf())
390 return;
391
392 // This relies on |download_item| being removed from DownloadManager in this
393 // MessageLoop iteration. |download_item| may not have been removed from
394 // DownloadManager when OnDownloadRemoved() is fired, so bounce off the
395 // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks
396 // at all downloads, and we do not tell it that |download_item| is being
397 // removed. If DownloadManager is ever changed to not immediately remove
398 // |download_item| from its map when OnDownloadRemoved is sent, then
399 // DownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell
400 // SendCurrentDownloads() that |download_item| was removed. A
401 // SupportsUserData::Data would be the correct way to do this.
402 ScheduleSendCurrentDownloads();
403 }
404
405 void DownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) {
406 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS);
407 search_terms_.reset(args && !args->empty() ? args->DeepCopy() : NULL);
408 ScheduleSendCurrentDownloads();
409
410 if (!main_notifier_) {
411 main_notifier_.reset(new AllDownloadItemNotifier(download_manager_, this));
412
413 Profile* profile = Profile::FromBrowserContext(
414 download_manager_->GetBrowserContext());
415 if (profile->IsOffTheRecord()) {
416 original_notifier_.reset(new AllDownloadItemNotifier(
417 BrowserContext::GetDownloadManager(profile->GetOriginalProfile()),
418 this));
419 }
420 }
421 }
422
423 void DownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) {
424 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE);
425 content::DownloadItem* file = GetDownloadByValue(args);
426 if (file)
427 file->OpenDownload();
428 }
429
430 void DownloadsDOMHandler::HandleDrag(const base::ListValue* args) {
431 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG);
432 content::DownloadItem* file = GetDownloadByValue(args);
433 if (!file)
434 return;
435
436 content::WebContents* web_contents = GetWebUIWebContents();
437 // |web_contents| is only NULL in the test.
438 if (!web_contents)
439 return;
440
441 if (file->GetState() != content::DownloadItem::COMPLETE)
442 return;
443
444 gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath(
445 file->GetTargetFilePath(), IconLoader::NORMAL);
446 gfx::NativeView view = web_contents->GetNativeView();
447 {
448 // Enable nested tasks during DnD, while |DragDownload()| blocks.
449 base::MessageLoop::ScopedNestableTaskAllower allow(
450 base::MessageLoop::current());
451 DragDownloadItem(file, icon, view);
452 }
453 }
454
455 void DownloadsDOMHandler::HandleSaveDangerous(const base::ListValue* args) {
456 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
457 content::DownloadItem* file = GetDownloadByValue(args);
458 if (file)
459 ShowDangerPrompt(file);
460 }
461
462 void DownloadsDOMHandler::HandleDiscardDangerous(const base::ListValue* args) {
463 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS);
464 content::DownloadItem* file = GetDownloadByValue(args);
465 if (file)
466 file->Remove();
467 }
468
469 void DownloadsDOMHandler::HandleShow(const base::ListValue* args) {
470 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW);
471 content::DownloadItem* file = GetDownloadByValue(args);
472 if (file)
473 file->ShowDownloadInShell();
474 }
475
476 void DownloadsDOMHandler::HandlePause(const base::ListValue* args) {
477 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE);
478 content::DownloadItem* file = GetDownloadByValue(args);
479 if (file)
480 file->Pause();
481 }
482
483 void DownloadsDOMHandler::HandleResume(const base::ListValue* args) {
484 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_RESUME);
485 content::DownloadItem* file = GetDownloadByValue(args);
486 if (file)
487 file->Resume();
488 }
489
490 void DownloadsDOMHandler::HandleRemove(const base::ListValue* args) {
491 if (!IsDeletingHistoryAllowed())
492 return;
493
494 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE);
495 content::DownloadItem* file = GetDownloadByValue(args);
496 if (!file)
497 return;
498
499 std::vector<content::DownloadItem*> downloads;
500 downloads.push_back(file);
501 RemoveDownloads(downloads);
502 }
503
504 void DownloadsDOMHandler::HandleUndo(const base::ListValue* args) {
505 // TODO(dbeam): handle more than removed downloads someday?
506 if (removals_.empty())
507 return;
508
509 const std::set<uint32_t> last_removed_ids = removals_.back();
510 removals_.pop_back();
511
512 for (auto id : last_removed_ids) {
513 content::DownloadItem* download = GetDownloadById(id);
514 if (!download)
515 continue;
516
517 DownloadItemModel model(download);
518 model.SetShouldShowInShelf(true);
519 model.SetIsBeingRevived(true);
520
521 download->UpdateObservers();
522
523 model.SetIsBeingRevived(false);
524 }
525 }
526
527 void DownloadsDOMHandler::HandleCancel(const base::ListValue* args) {
528 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL);
529 content::DownloadItem* file = GetDownloadByValue(args);
530 if (file)
531 file->Cancel(true);
532 }
533
534 void DownloadsDOMHandler::HandleClearAll(const base::ListValue* args) {
535 if (!IsDeletingHistoryAllowed()) {
536 // This should only be reached during tests.
537 return;
538 }
539
540 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL);
541
542 std::vector<content::DownloadItem*> downloads;
543 if (GetMainNotifierManager())
544 GetMainNotifierManager()->GetAllDownloads(&downloads);
545 if (GetOriginalNotifierManager())
546 GetOriginalNotifierManager()->GetAllDownloads(&downloads);
547 RemoveDownloads(downloads);
548 }
549
550 void DownloadsDOMHandler::RemoveDownloads(
551 const std::vector<content::DownloadItem*>& to_remove) {
552 std::set<uint32_t> ids;
553
554 for (auto* download : to_remove) {
555 DownloadItemModel item_model(download);
556 if (!item_model.ShouldShowInShelf() ||
557 download->GetState() == content::DownloadItem::IN_PROGRESS) {
558 continue;
559 }
560
561 item_model.SetShouldShowInShelf(false);
562 ids.insert(download->GetId());
563 download->UpdateObservers();
564 }
565
566 if (!ids.empty())
567 removals_.push_back(ids);
568 }
569
570 void DownloadsDOMHandler::HandleOpenDownloadsFolder(
571 const base::ListValue* args) {
572 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER);
573 content::DownloadManager* manager = GetMainNotifierManager();
574 if (manager) {
575 platform_util::OpenItem(
576 Profile::FromBrowserContext(manager->GetBrowserContext()),
577 DownloadPrefs::FromDownloadManager(manager)->DownloadPath(),
578 platform_util::OPEN_FOLDER, platform_util::OpenOperationCallback());
579 }
580 }
581
582 // DownloadsDOMHandler, private: ----------------------------------------------
583
584 void DownloadsDOMHandler::ScheduleSendCurrentDownloads() {
585 // Don't call SendCurrentDownloads() every time anything changes. Batch them
586 // together instead. This may handle hundreds of OnDownloadDestroyed() calls
587 // in a single UI message loop iteration when the user Clears All downloads.
588 if (update_scheduled_)
589 return;
590
591 update_scheduled_ = true;
592
593 BrowserThread::PostTask(
594 BrowserThread::UI, FROM_HERE,
595 base::Bind(&DownloadsDOMHandler::SendCurrentDownloads,
596 weak_ptr_factory_.GetWeakPtr()));
597 }
598
599 content::DownloadManager* DownloadsDOMHandler::GetMainNotifierManager() const {
600 return main_notifier_ ? main_notifier_->GetManager() : nullptr;
601 }
602
603 content::DownloadManager* DownloadsDOMHandler::GetOriginalNotifierManager()
604 const {
605 return original_notifier_ ? original_notifier_->GetManager() : nullptr;
606 }
607
608 void DownloadsDOMHandler::FinalizeRemovals() {
609 while (!removals_.empty()) {
610 const std::set<uint32_t> remove = removals_.back();
611 removals_.pop_back();
612
613 for (const auto id : remove) {
614 content::DownloadItem* download = GetDownloadById(id);
615 if (download)
616 download->Remove();
617 }
618 }
619 }
620
621 void DownloadsDOMHandler::SendCurrentDownloads() {
622 update_scheduled_ = false;
623
624 content::DownloadManager::DownloadVector all_items, filtered_items;
625 if (GetMainNotifierManager()) {
626 GetMainNotifierManager()->GetAllDownloads(&all_items);
627 GetMainNotifierManager()->CheckForHistoryFilesRemoval();
628 }
629 if (GetOriginalNotifierManager()) {
630 GetOriginalNotifierManager()->GetAllDownloads(&all_items);
631 GetOriginalNotifierManager()->CheckForHistoryFilesRemoval();
632 }
633
634 DownloadQuery query;
635 if (search_terms_ && !search_terms_->empty())
636 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_);
637 query.AddFilter(base::Bind(&IsDownloadDisplayable));
638 query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING);
639 query.Limit(kMaxNumberOfDownloads);
640 query.Search(all_items.begin(), all_items.end(), &filtered_items);
641
642 base::ListValue results_value;
643 for (auto* item : filtered_items) {
644 results_value.Append(CreateDownloadItemValue(
645 item,
646 original_notifier_ && GetMainNotifierManager() &&
647 GetMainNotifierManager()->GetDownload(item->GetId()) == item));
648 }
649 CallUpdateAll(results_value);
650 }
651
652 void DownloadsDOMHandler::ShowDangerPrompt(
653 content::DownloadItem* dangerous_item) {
654 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create(
655 dangerous_item,
656 GetWebUIWebContents(),
657 false,
658 base::Bind(&DownloadsDOMHandler::DangerPromptDone,
659 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId()));
660 // danger_prompt will delete itself.
661 DCHECK(danger_prompt);
662 }
663
664 void DownloadsDOMHandler::DangerPromptDone(
665 int download_id, DownloadDangerPrompt::Action action) {
666 if (action != DownloadDangerPrompt::ACCEPT)
667 return;
668 content::DownloadItem* item = NULL;
669 if (GetMainNotifierManager())
670 item = GetMainNotifierManager()->GetDownload(download_id);
671 if (!item && GetOriginalNotifierManager())
672 item = GetOriginalNotifierManager()->GetDownload(download_id);
673 if (!item || item->IsDone())
674 return;
675 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
676 item->ValidateDangerousDownload();
677 }
678
679 bool DownloadsDOMHandler::IsDeletingHistoryAllowed() {
680 content::DownloadManager* manager = GetMainNotifierManager();
681 return manager &&
682 Profile::FromBrowserContext(manager->GetBrowserContext())->
683 GetPrefs()->GetBoolean(prefs::kAllowDeletingBrowserHistory);
684 }
685
686 content::DownloadItem* DownloadsDOMHandler::GetDownloadByValue(
687 const base::ListValue* args) {
688 std::string download_id;
689 if (!args->GetString(0, &download_id)) {
690 NOTREACHED();
691 return nullptr;
692 }
693
694 uint64_t id;
695 if (!base::StringToUint64(download_id, &id)) {
696 NOTREACHED();
697 return nullptr;
698 }
699
700 return GetDownloadById(static_cast<uint32_t>(id));
701 }
702
703 content::DownloadItem* DownloadsDOMHandler::GetDownloadById(uint32_t id) {
704 content::DownloadItem* item = NULL;
705 if (GetMainNotifierManager())
706 item = GetMainNotifierManager()->GetDownload(id);
707 if (!item && GetOriginalNotifierManager())
708 item = GetOriginalNotifierManager()->GetDownload(id);
709 return item;
710 }
711
712 content::WebContents* DownloadsDOMHandler::GetWebUIWebContents() {
713 return web_ui()->GetWebContents();
714 }
715
716 void DownloadsDOMHandler::CallUpdateAll(const base::ListValue& list) {
717 web_ui()->CallJavascriptFunction("downloads.Manager.updateAll", list);
718 }
719
720 void DownloadsDOMHandler::CallUpdateItem(const base::DictionaryValue& item) {
721 web_ui()->CallJavascriptFunction("downloads.Manager.updateItem", item);
722 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/webui/downloads_dom_handler.h ('k') | chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698