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

Side by Side Diff: chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc

Issue 1428833005: MD Downloads: track downloads in C++, dispatch discrete JS updates (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: moar testz Created 5 years, 1 month 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h" 5 #include "chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <functional> 8 #include <functional>
9 9
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/i18n/rtl.h" 13 #include "base/i18n/rtl.h"
14 #include "base/i18n/time_formatting.h"
15 #include "base/logging.h" 14 #include "base/logging.h"
16 #include "base/memory/singleton.h"
17 #include "base/metrics/field_trial.h"
18 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
19 #include "base/prefs/pref_service.h" 16 #include "base/prefs/pref_service.h"
20 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_piece.h" 18 #include "base/strings/string_piece.h"
22 #include "base/strings/utf_string_conversions.h" 19 #include "base/strings/utf_string_conversions.h"
23 #include "base/supports_user_data.h" 20 #include "base/supports_user_data.h"
24 #include "base/threading/thread.h" 21 #include "base/threading/thread.h"
25 #include "base/value_conversions.h"
26 #include "base/values.h" 22 #include "base/values.h"
27 #include "chrome/browser/browser_process.h" 23 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/download/download_crx_util.h"
29 #include "chrome/browser/download/download_danger_prompt.h" 24 #include "chrome/browser/download/download_danger_prompt.h"
30 #include "chrome/browser/download/download_history.h" 25 #include "chrome/browser/download/download_history.h"
31 #include "chrome/browser/download/download_item_model.h" 26 #include "chrome/browser/download/download_item_model.h"
32 #include "chrome/browser/download/download_prefs.h" 27 #include "chrome/browser/download/download_prefs.h"
33 #include "chrome/browser/download/download_query.h" 28 #include "chrome/browser/download/download_query.h"
34 #include "chrome/browser/download/download_service.h" 29 #include "chrome/browser/download/download_service.h"
35 #include "chrome/browser/download/download_service_factory.h" 30 #include "chrome/browser/download/download_service_factory.h"
36 #include "chrome/browser/download/drag_download_item.h" 31 #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" 32 #include "chrome/browser/platform_util.h"
40 #include "chrome/browser/profiles/profile.h" 33 #include "chrome/browser/profiles/profile.h"
41 #include "chrome/browser/ui/webui/fileicon_source.h" 34 #include "chrome/browser/ui/webui/fileicon_source.h"
42 #include "chrome/common/chrome_switches.h" 35 #include "chrome/common/chrome_switches.h"
43 #include "chrome/common/pref_names.h" 36 #include "chrome/common/pref_names.h"
44 #include "chrome/common/url_constants.h" 37 #include "chrome/common/url_constants.h"
45 #include "content/public/browser/browser_thread.h" 38 #include "content/public/browser/browser_thread.h"
46 #include "content/public/browser/download_item.h" 39 #include "content/public/browser/download_item.h"
40 #include "content/public/browser/download_manager.h"
47 #include "content/public/browser/url_data_source.h" 41 #include "content/public/browser/url_data_source.h"
48 #include "content/public/browser/user_metrics.h" 42 #include "content/public/browser/user_metrics.h"
49 #include "content/public/browser/web_contents.h" 43 #include "content/public/browser/web_contents.h"
50 #include "content/public/browser/web_ui.h" 44 #include "content/public/browser/web_ui.h"
51 #include "extensions/browser/extension_system.h"
52 #include "net/base/filename_util.h" 45 #include "net/base/filename_util.h"
53 #include "third_party/icu/source/i18n/unicode/datefmt.h"
54 #include "ui/base/l10n/time_format.h" 46 #include "ui/base/l10n/time_format.h"
55 #include "ui/gfx/image/image.h" 47 #include "ui/gfx/image/image.h"
56 48
57 using base::UserMetricsAction; 49 using base::UserMetricsAction;
58 using content::BrowserContext;
59 using content::BrowserThread; 50 using content::BrowserThread;
60 51
61 namespace { 52 namespace {
62 53
63 // Maximum number of downloads to show. TODO(glen): Remove this and instead
64 // stuff the downloads down the pipe slowly.
65 size_t kMaxNumberOfDownloads = 150;
66
67 enum DownloadsDOMEvent { 54 enum DownloadsDOMEvent {
68 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0, 55 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0,
69 DOWNLOADS_DOM_EVENT_OPEN_FILE = 1, 56 DOWNLOADS_DOM_EVENT_OPEN_FILE = 1,
70 DOWNLOADS_DOM_EVENT_DRAG = 2, 57 DOWNLOADS_DOM_EVENT_DRAG = 2,
71 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3, 58 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3,
72 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4, 59 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4,
73 DOWNLOADS_DOM_EVENT_SHOW = 5, 60 DOWNLOADS_DOM_EVENT_SHOW = 5,
74 DOWNLOADS_DOM_EVENT_PAUSE = 6, 61 DOWNLOADS_DOM_EVENT_PAUSE = 6,
75 DOWNLOADS_DOM_EVENT_REMOVE = 7, 62 DOWNLOADS_DOM_EVENT_REMOVE = 7,
76 DOWNLOADS_DOM_EVENT_CANCEL = 8, 63 DOWNLOADS_DOM_EVENT_CANCEL = 8,
77 DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9, 64 DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9,
78 DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10, 65 DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10,
79 DOWNLOADS_DOM_EVENT_RESUME = 11, 66 DOWNLOADS_DOM_EVENT_RESUME = 11,
80 DOWNLOADS_DOM_EVENT_MAX 67 DOWNLOADS_DOM_EVENT_MAX
81 }; 68 };
82 69
83 void CountDownloadsDOMEvents(DownloadsDOMEvent event) { 70 void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
84 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent", 71 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
85 event, 72 event,
86 DOWNLOADS_DOM_EVENT_MAX); 73 DOWNLOADS_DOM_EVENT_MAX);
87 } 74 }
88 75
89 // Returns a string constant to be used as the |danger_type| value in
90 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE,
91 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
92 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
93 const char* GetDangerTypeString(content::DownloadDangerType danger_type) {
94 switch (danger_type) {
95 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
96 return "DANGEROUS_FILE";
97 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
98 return "DANGEROUS_URL";
99 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
100 return "DANGEROUS_CONTENT";
101 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
102 return "UNCOMMON_CONTENT";
103 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
104 return "DANGEROUS_HOST";
105 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
106 return "POTENTIALLY_UNWANTED";
107 default:
108 // Don't return a danger type string if it is NOT_DANGEROUS or
109 // MAYBE_DANGEROUS_CONTENT.
110 NOTREACHED();
111 return "";
112 }
113 }
114
115 // TODO(dbeam): if useful elsewhere, move to base/i18n/time_formatting.h?
116 base::string16 TimeFormatLongDate(const base::Time& time) {
117 scoped_ptr<icu::DateFormat> formatter(
118 icu::DateFormat::createDateInstance(icu::DateFormat::kLong));
119 icu::UnicodeString date_string;
120 formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
121 return base::string16(date_string.getBuffer(),
122 static_cast<size_t>(date_string.length()));
123 }
124
125 // Returns a JSON dictionary containing some of the attributes of |download|.
126 // The JSON dictionary will also have a field "id" set to |id|, and a field
127 // "otr" set to |incognito|.
128 base::DictionaryValue* CreateDownloadItemValue(
129 content::DownloadItem* download_item,
130 bool incognito) {
131 // TODO(asanka): Move towards using download_model here for getting status and
132 // progress. The difference currently only matters to Drive downloads and
133 // those don't show up on the downloads page, but should.
134 DownloadItemModel download_model(download_item);
135
136 // The items which are to be written into file_value are also described in
137 // chrome/browser/resources/downloads/downloads.js in @typedef for
138 // BackendDownloadObject. Please update it whenever you add or remove
139 // any keys in file_value.
140 base::DictionaryValue* file_value = new base::DictionaryValue();
141
142 file_value->SetInteger(
143 "started", static_cast<int>(download_item->GetStartTime().ToTimeT()));
144 file_value->SetString(
145 "since_string", ui::TimeFormat::RelativeDate(
146 download_item->GetStartTime(), NULL));
147
148 base::Time start_time = download_item->GetStartTime();
149 base::string16 date_string = TimeFormatLongDate(start_time);
150 file_value->SetString("date_string", date_string);
151
152 file_value->SetString("id", base::Uint64ToString(download_item->GetId()));
153
154 base::FilePath download_path(download_item->GetTargetFilePath());
155 file_value->Set("file_path", base::CreateFilePathValue(download_path));
156 file_value->SetString("file_url",
157 net::FilePathToFileURL(download_path).spec());
158
159 extensions::DownloadedByExtension* by_ext =
160 extensions::DownloadedByExtension::Get(download_item);
161 std::string by_ext_id;
162 std::string by_ext_name;
163 if (by_ext) {
164 by_ext_id = by_ext->id();
165 // TODO(dbeam): why doesn't DownloadsByExtension::name() return a string16?
166 by_ext_name = by_ext->name();
167
168 // Lookup the extension's current name() in case the user changed their
169 // language. This won't work if the extension was uninstalled, so the name
170 // might be the wrong language.
171 bool include_disabled = true;
172 const extensions::Extension* extension = extensions::ExtensionSystem::Get(
173 Profile::FromBrowserContext(download_item->GetBrowserContext()))->
174 extension_service()->GetExtensionById(by_ext->id(), include_disabled);
175 if (extension)
176 file_value->SetString("by_ext_name", extension->name());
177 }
178 file_value->SetString("by_ext_id", by_ext_id);
179 file_value->SetString("by_ext_name", by_ext_name);
180
181 // Keep file names as LTR.
182 base::string16 file_name =
183 download_item->GetFileNameToReportUser().LossyDisplayName();
184 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name);
185 file_value->SetString("file_name", file_name);
186 file_value->SetString("url", download_item->GetURL().spec());
187 file_value->SetBoolean("otr", incognito);
188 file_value->SetInteger("total", static_cast<int>(
189 download_item->GetTotalBytes()));
190 file_value->SetBoolean("file_externally_removed",
191 download_item->GetFileExternallyRemoved());
192 file_value->SetBoolean("resume", download_item->CanResume());
193
194 const char* danger_type = "";
195 base::string16 last_reason_text;
196 // -2 is invalid, -1 means indeterminate, and 0-100 are in-progress.
197 int percent = -2;
198 base::string16 progress_status_text;
199 bool retry = false;
200 const char* state = nullptr;
201
202 switch (download_item->GetState()) {
203 case content::DownloadItem::IN_PROGRESS: {
204 if (download_item->IsDangerous()) {
205 state = "DANGEROUS";
206 // These are the only danger states that the UI is equipped to handle.
207 DCHECK(download_item->GetDangerType() ==
208 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
209 download_item->GetDangerType() ==
210 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
211 download_item->GetDangerType() ==
212 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
213 download_item->GetDangerType() ==
214 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
215 download_item->GetDangerType() ==
216 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
217 download_item->GetDangerType() ==
218 content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
219 danger_type = GetDangerTypeString(download_item->GetDangerType());
220 } else if (download_item->IsPaused()) {
221 state = "PAUSED";
222 } else {
223 state = "IN_PROGRESS";
224 }
225 progress_status_text = download_model.GetTabProgressStatusText();
226 percent = download_item->PercentComplete();
227 break;
228 }
229
230 case content::DownloadItem::INTERRUPTED:
231 state = "INTERRUPTED";
232 progress_status_text = download_model.GetTabProgressStatusText();
233
234 if (download_item->CanResume())
235 percent = download_item->PercentComplete();
236
237 last_reason_text = download_model.GetInterruptReasonText();
238 if (content::DOWNLOAD_INTERRUPT_REASON_CRASH ==
239 download_item->GetLastReason() && !download_item->CanResume()) {
240 retry = true;
241 }
242 break;
243
244 case content::DownloadItem::CANCELLED:
245 state = "CANCELLED";
246 retry = true;
247 break;
248
249 case content::DownloadItem::COMPLETE:
250 DCHECK(!download_item->IsDangerous());
251 state = "COMPLETE";
252 break;
253
254 case content::DownloadItem::MAX_DOWNLOAD_STATE:
255 NOTREACHED();
256 }
257
258 DCHECK(state);
259
260 file_value->SetString("danger_type", danger_type);
261 file_value->SetString("last_reason_text", last_reason_text);
262 file_value->SetInteger("percent", percent);
263 file_value->SetString("progress_status_text", progress_status_text);
264 file_value->SetBoolean("retry", retry);
265 file_value->SetString("state", state);
266
267 return file_value;
268 }
269
270 // Filters out extension downloads and downloads that don't have a filename yet.
271 bool IsDownloadDisplayable(const content::DownloadItem& item) {
272 return !download_crx_util::IsExtensionDownload(item) &&
273 !item.IsTemporary() &&
274 !item.GetFileNameToReportUser().empty() &&
275 !item.GetTargetFilePath().empty() &&
276 DownloadItemModel(
277 const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf();
278 }
279
280 } // namespace 76 } // namespace
281 77
282 MdDownloadsDOMHandler::MdDownloadsDOMHandler( 78 MdDownloadsDOMHandler::MdDownloadsDOMHandler(
283 content::DownloadManager* download_manager) 79 content::DownloadManager* download_manager, content::WebUI* web_ui)
284 : download_manager_(download_manager), 80 : list_tracker_(download_manager, web_ui),
285 update_scheduled_(false),
286 weak_ptr_factory_(this) { 81 weak_ptr_factory_(this) {
287 // Create our fileicon data source. 82 // Create our fileicon data source.
288 Profile* profile = Profile::FromBrowserContext( 83 Profile* profile = Profile::FromBrowserContext(
289 download_manager->GetBrowserContext()); 84 download_manager->GetBrowserContext());
290 content::URLDataSource::Add(profile, new FileIconSource()); 85 content::URLDataSource::Add(profile, new FileIconSource());
291 } 86 }
292 87
293 MdDownloadsDOMHandler::~MdDownloadsDOMHandler() { 88 MdDownloadsDOMHandler::~MdDownloadsDOMHandler() {
294 FinalizeRemovals(); 89 FinalizeRemovals();
295 } 90 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 base::Bind(&MdDownloadsDOMHandler::HandleCancel, 126 base::Bind(&MdDownloadsDOMHandler::HandleCancel,
332 weak_ptr_factory_.GetWeakPtr())); 127 weak_ptr_factory_.GetWeakPtr()));
333 web_ui()->RegisterMessageCallback("clearAll", 128 web_ui()->RegisterMessageCallback("clearAll",
334 base::Bind(&MdDownloadsDOMHandler::HandleClearAll, 129 base::Bind(&MdDownloadsDOMHandler::HandleClearAll,
335 weak_ptr_factory_.GetWeakPtr())); 130 weak_ptr_factory_.GetWeakPtr()));
336 web_ui()->RegisterMessageCallback("openDownloadsFolder", 131 web_ui()->RegisterMessageCallback("openDownloadsFolder",
337 base::Bind(&MdDownloadsDOMHandler::HandleOpenDownloadsFolder, 132 base::Bind(&MdDownloadsDOMHandler::HandleOpenDownloadsFolder,
338 weak_ptr_factory_.GetWeakPtr())); 133 weak_ptr_factory_.GetWeakPtr()));
339 } 134 }
340 135
341 void MdDownloadsDOMHandler::OnDownloadCreated( 136 void MdDownloadsDOMHandler::RenderViewReused(
342 content::DownloadManager* manager, content::DownloadItem* download_item) { 137 content::RenderViewHost* render_view_host) {
343 if (IsDownloadDisplayable(*download_item)) 138 list_tracker_.Stop();
344 ScheduleSendCurrentDownloads();
345 else
346 new_downloads_.insert(download_item->GetId());
347 }
348
349 void MdDownloadsDOMHandler::OnDownloadUpdated(
350 content::DownloadManager* manager,
351 content::DownloadItem* download_item) {
352 if (update_scheduled_)
353 return;
354
355 bool showing_new_item = false;
356
357 if (new_downloads_.count(download_item->GetId())) {
358 // A new download (that the page doesn't know about yet) has been updated.
359 if (!IsDownloadDisplayable(*download_item)) {
360 // Item isn't ready to be displayed yet. Wait until it is.
361 return;
362 }
363
364 new_downloads_.erase(download_item->GetId());
365 showing_new_item = true;
366 }
367
368 if (showing_new_item || DownloadItemModel(download_item).IsBeingRevived() ||
369 !IsDownloadDisplayable(*download_item)) {
370 // A download will be shown or hidden by this update. Resend the list.
371 ScheduleSendCurrentDownloads();
372 return;
373 }
374
375 if (search_terms_ && !search_terms_->empty()) {
376 // Don't CallUpdateItem() if download_item doesn't match
377 // search_terms_.
378 // TODO(benjhayden): Consider splitting MatchesQuery() out to a function.
379 content::DownloadManager::DownloadVector all_items, filtered_items;
380 all_items.push_back(download_item);
381 DownloadQuery query;
382 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_);
383 query.Search(all_items.begin(), all_items.end(), &filtered_items);
384 if (filtered_items.empty())
385 return;
386 }
387
388 DCHECK(manager);
389 scoped_ptr<base::DictionaryValue> item(CreateDownloadItemValue(
390 download_item,
391 original_notifier_ && manager == GetMainNotifierManager()));
392 CallUpdateItem(*item);
393 }
394
395 void MdDownloadsDOMHandler::OnDownloadRemoved(
396 content::DownloadManager* manager,
397 content::DownloadItem* download_item) {
398 if (!DownloadItemModel(download_item).ShouldShowInShelf())
399 return;
400
401 // This relies on |download_item| being removed from DownloadManager in this
402 // MessageLoop iteration. |download_item| may not have been removed from
403 // DownloadManager when OnDownloadRemoved() is fired, so bounce off the
404 // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks
405 // at all downloads, and we do not tell it that |download_item| is being
406 // removed. If DownloadManager is ever changed to not immediately remove
407 // |download_item| from its map when OnDownloadRemoved is sent, then
408 // MdDownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell
409 // SendCurrentDownloads() that |download_item| was removed. A
410 // SupportsUserData::Data would be the correct way to do this.
411 ScheduleSendCurrentDownloads();
412 } 139 }
413 140
414 void MdDownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) { 141 void MdDownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) {
415 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS); 142 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS);
416 search_terms_.reset(args && !args->empty() ? args->DeepCopy() : NULL);
417 ScheduleSendCurrentDownloads();
418 143
419 if (!main_notifier_) { 144 bool terms_changed = list_tracker_.SetSearchTerms(*args);
420 main_notifier_.reset(new AllDownloadItemNotifier(download_manager_, this)); 145 if (terms_changed)
146 list_tracker_.CallClearAll();
421 147
422 Profile* profile = Profile::FromBrowserContext( 148 list_tracker_.Start();
423 download_manager_->GetBrowserContext());
424 if (profile->IsOffTheRecord()) {
425 original_notifier_.reset(new AllDownloadItemNotifier(
426 BrowserContext::GetDownloadManager(profile->GetOriginalProfile()),
427 this));
428 }
429 }
430 } 149 }
431 150
432 void MdDownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) { 151 void MdDownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) {
433 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE); 152 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE);
434 content::DownloadItem* file = GetDownloadByValue(args); 153 content::DownloadItem* file = GetDownloadByValue(args);
435 if (file) 154 if (file)
436 file->OpenDownload(); 155 file->OpenDownload();
437 } 156 }
438 157
439 void MdDownloadsDOMHandler::HandleDrag(const base::ListValue* args) { 158 void MdDownloadsDOMHandler::HandleDrag(const base::ListValue* args) {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 } 261 }
543 262
544 void MdDownloadsDOMHandler::HandleClearAll(const base::ListValue* args) { 263 void MdDownloadsDOMHandler::HandleClearAll(const base::ListValue* args) {
545 if (!IsDeletingHistoryAllowed()) { 264 if (!IsDeletingHistoryAllowed()) {
546 // This should only be reached during tests. 265 // This should only be reached during tests.
547 return; 266 return;
548 } 267 }
549 268
550 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL); 269 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL);
551 270
271 list_tracker_.CallClearAll();
272 list_tracker_.Stop();
273
552 DownloadVector downloads; 274 DownloadVector downloads;
553 if (GetMainNotifierManager()) 275 if (GetMainNotifierManager())
554 GetMainNotifierManager()->GetAllDownloads(&downloads); 276 GetMainNotifierManager()->GetAllDownloads(&downloads);
555 if (GetOriginalNotifierManager()) 277 if (GetOriginalNotifierManager())
556 GetOriginalNotifierManager()->GetAllDownloads(&downloads); 278 GetOriginalNotifierManager()->GetAllDownloads(&downloads);
557 RemoveDownloads(downloads); 279 RemoveDownloads(downloads);
280
281 list_tracker_.Start();
558 } 282 }
559 283
560 void MdDownloadsDOMHandler::RemoveDownloads(const DownloadVector& to_remove) { 284 void MdDownloadsDOMHandler::RemoveDownloads(const DownloadVector& to_remove) {
561 IdSet ids; 285 IdSet ids;
562 286
563 for (auto* download : to_remove) { 287 for (auto* download : to_remove) {
564 DownloadItemModel item_model(download); 288 DownloadItemModel item_model(download);
565 if (!item_model.ShouldShowInShelf() || 289 if (!item_model.ShouldShowInShelf() ||
566 download->GetState() == content::DownloadItem::IN_PROGRESS) { 290 download->GetState() == content::DownloadItem::IN_PROGRESS) {
567 continue; 291 continue;
(...skipping 15 matching lines...) Expand all
583 if (manager) { 307 if (manager) {
584 platform_util::OpenItem( 308 platform_util::OpenItem(
585 Profile::FromBrowserContext(manager->GetBrowserContext()), 309 Profile::FromBrowserContext(manager->GetBrowserContext()),
586 DownloadPrefs::FromDownloadManager(manager)->DownloadPath(), 310 DownloadPrefs::FromDownloadManager(manager)->DownloadPath(),
587 platform_util::OPEN_FOLDER, platform_util::OpenOperationCallback()); 311 platform_util::OPEN_FOLDER, platform_util::OpenOperationCallback());
588 } 312 }
589 } 313 }
590 314
591 // MdDownloadsDOMHandler, private: -------------------------------------------- 315 // MdDownloadsDOMHandler, private: --------------------------------------------
592 316
593 void MdDownloadsDOMHandler::ScheduleSendCurrentDownloads() {
594 // Don't call SendCurrentDownloads() every time anything changes. Batch them
595 // together instead. This may handle hundreds of OnDownloadDestroyed() calls
596 // in a single UI message loop iteration when the user Clears All downloads.
597 if (update_scheduled_)
598 return;
599
600 update_scheduled_ = true;
601
602 BrowserThread::PostTask(
603 BrowserThread::UI, FROM_HERE,
604 base::Bind(&MdDownloadsDOMHandler::SendCurrentDownloads,
605 weak_ptr_factory_.GetWeakPtr()));
606 }
607
608 content::DownloadManager* MdDownloadsDOMHandler::GetMainNotifierManager() 317 content::DownloadManager* MdDownloadsDOMHandler::GetMainNotifierManager()
609 const { 318 const {
610 return main_notifier_ ? main_notifier_->GetManager() : nullptr; 319 return list_tracker_.GetMainNotifierManager();
611 } 320 }
612 321
613 content::DownloadManager* MdDownloadsDOMHandler::GetOriginalNotifierManager() 322 content::DownloadManager* MdDownloadsDOMHandler::GetOriginalNotifierManager()
614 const { 323 const {
615 return original_notifier_ ? original_notifier_->GetManager() : nullptr; 324 return list_tracker_.GetOriginalNotifierManager();
616 } 325 }
617 326
618 void MdDownloadsDOMHandler::FinalizeRemovals() { 327 void MdDownloadsDOMHandler::FinalizeRemovals() {
619 while (!removals_.empty()) { 328 while (!removals_.empty()) {
620 const IdSet remove = removals_.back(); 329 const IdSet remove = removals_.back();
621 removals_.pop_back(); 330 removals_.pop_back();
622 331
623 for (const auto id : remove) { 332 for (const auto id : remove) {
624 content::DownloadItem* download = GetDownloadById(id); 333 content::DownloadItem* download = GetDownloadById(id);
625 if (download) 334 if (download)
626 download->Remove(); 335 download->Remove();
627 } 336 }
628 } 337 }
629 } 338 }
630 339
631 void MdDownloadsDOMHandler::SendCurrentDownloads() {
632 update_scheduled_ = false;
633
634 content::DownloadManager::DownloadVector all_items, filtered_items;
635 if (GetMainNotifierManager()) {
636 GetMainNotifierManager()->GetAllDownloads(&all_items);
637 GetMainNotifierManager()->CheckForHistoryFilesRemoval();
638 }
639 if (GetOriginalNotifierManager()) {
640 GetOriginalNotifierManager()->GetAllDownloads(&all_items);
641 GetOriginalNotifierManager()->CheckForHistoryFilesRemoval();
642 }
643
644 DownloadQuery query;
645 if (search_terms_ && !search_terms_->empty())
646 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_);
647 query.AddFilter(base::Bind(&IsDownloadDisplayable));
648 query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING);
649 query.Limit(kMaxNumberOfDownloads);
650 query.Search(all_items.begin(), all_items.end(), &filtered_items);
651
652 base::ListValue results_value;
653 for (auto* item : filtered_items) {
654 results_value.Append(CreateDownloadItemValue(
655 item,
656 original_notifier_ && GetMainNotifierManager() &&
657 GetMainNotifierManager()->GetDownload(item->GetId()) == item));
658 }
659 CallUpdateAll(results_value);
660 }
661
662 void MdDownloadsDOMHandler::ShowDangerPrompt( 340 void MdDownloadsDOMHandler::ShowDangerPrompt(
663 content::DownloadItem* dangerous_item) { 341 content::DownloadItem* dangerous_item) {
664 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create( 342 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create(
665 dangerous_item, 343 dangerous_item,
666 GetWebUIWebContents(), 344 GetWebUIWebContents(),
667 false, 345 false,
668 base::Bind(&MdDownloadsDOMHandler::DangerPromptDone, 346 base::Bind(&MdDownloadsDOMHandler::DangerPromptDone,
669 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId())); 347 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId()));
670 // danger_prompt will delete itself. 348 // danger_prompt will delete itself.
671 DCHECK(danger_prompt); 349 DCHECK(danger_prompt);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 if (GetMainNotifierManager()) 393 if (GetMainNotifierManager())
716 item = GetMainNotifierManager()->GetDownload(id); 394 item = GetMainNotifierManager()->GetDownload(id);
717 if (!item && GetOriginalNotifierManager()) 395 if (!item && GetOriginalNotifierManager())
718 item = GetOriginalNotifierManager()->GetDownload(id); 396 item = GetOriginalNotifierManager()->GetDownload(id);
719 return item; 397 return item;
720 } 398 }
721 399
722 content::WebContents* MdDownloadsDOMHandler::GetWebUIWebContents() { 400 content::WebContents* MdDownloadsDOMHandler::GetWebUIWebContents() {
723 return web_ui()->GetWebContents(); 401 return web_ui()->GetWebContents();
724 } 402 }
725
726 void MdDownloadsDOMHandler::CallUpdateAll(const base::ListValue& list) {
727 web_ui()->CallJavascriptFunction("downloads.Manager.updateAll", list);
728 }
729
730 void MdDownloadsDOMHandler::CallUpdateItem(const base::DictionaryValue& item) {
731 web_ui()->CallJavascriptFunction("downloads.Manager.updateItem", item);
732 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698