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

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

Issue 10854127: Rewrite DownloadsDOMHandler (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 4 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 | Annotate | Revision Log
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/downloads_dom_handler.h" 5 #include "chrome/browser/ui/webui/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"
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 #endif 52 #endif
53 53
54 using content::BrowserContext; 54 using content::BrowserContext;
55 using content::BrowserThread; 55 using content::BrowserThread;
56 using content::UserMetricsAction; 56 using content::UserMetricsAction;
57 57
58 namespace { 58 namespace {
59 59
60 // Maximum number of downloads to show. TODO(glen): Remove this and instead 60 // Maximum number of downloads to show. TODO(glen): Remove this and instead
61 // stuff the downloads down the pipe slowly. 61 // stuff the downloads down the pipe slowly.
62 static const int kMaxDownloads = 150; 62 static const size_t kMaxDownloads = 150;
63 63
64 // Sort DownloadItems into descending order by their start time. 64 // Sort DownloadItems into descending order by their start time.
65 class DownloadItemSorter : public std::binary_function<content::DownloadItem*, 65 class DownloadItemSorter : public std::binary_function<content::DownloadItem*,
66 content::DownloadItem*, 66 content::DownloadItem*,
67 bool> { 67 bool> {
68 public: 68 public:
69 bool operator()(const content::DownloadItem* lhs, 69 bool operator()(const content::DownloadItem* lhs,
70 const content::DownloadItem* rhs) { 70 const content::DownloadItem* rhs) {
71 return lhs->GetStartTime() > rhs->GetStartTime(); 71 return lhs->GetStartTime() > rhs->GetStartTime();
72 } 72 }
(...skipping 14 matching lines...) Expand all
87 DOWNLOADS_DOM_EVENT_MAX 87 DOWNLOADS_DOM_EVENT_MAX
88 }; 88 };
89 89
90 void CountDownloadsDOMEvents(DownloadsDOMEvent event) { 90 void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
91 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent", 91 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
92 event, 92 event,
93 DOWNLOADS_DOM_EVENT_MAX); 93 DOWNLOADS_DOM_EVENT_MAX);
94 } 94 }
95 95
96 // Returns a string constant to be used as the |danger_type| value in 96 // Returns a string constant to be used as the |danger_type| value in
97 // CreateDownloadItemValue(). We only return strings for DANGEROUS_FILE, 97 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE,
98 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the 98 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
99 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|. 99 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
100 const char* GetDangerTypeString(content::DownloadDangerType danger_type) { 100 const char* GetDangerTypeString(content::DownloadDangerType danger_type) {
101 switch (danger_type) { 101 switch (danger_type) {
102 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: 102 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
103 return "DANGEROUS_FILE"; 103 return "DANGEROUS_FILE";
104 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 104 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
105 return "DANGEROUS_URL"; 105 return "DANGEROUS_URL";
106 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 106 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
107 return "DANGEROUS_CONTENT"; 107 return "DANGEROUS_CONTENT";
108 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: 108 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
109 return "UNCOMMON_CONTENT"; 109 return "UNCOMMON_CONTENT";
110 default: 110 default:
111 // We shouldn't be returning a danger type string if it is 111 // Don't return a danger type string if it is NOT_DANGEROUS or
112 // NOT_DANGEROUS or MAYBE_DANGEROUS_CONTENT. 112 // MAYBE_DANGEROUS_CONTENT.
113 NOTREACHED(); 113 NOTREACHED();
114 return ""; 114 return "";
115 } 115 }
116 } 116 }
117 117
118 // Return a JSON dictionary containing some of the attributes of |download|. 118 // Return a JSON dictionary containing some of the attributes of |download|.
119 // The JSON dictionary will also have a field "id" set to |id|, and a field 119 // The JSON dictionary will also have a field "id" set to |id|, and a field
120 // "otr" set to |incognito|. 120 // "otr" set to |incognito|.
121 DictionaryValue* CreateDownloadItemValue( 121 DictionaryValue* CreateDownloadItemValue(
122 content::DownloadItem* download, 122 content::DownloadItem* download_item,
123 int id,
124 bool incognito) { 123 bool incognito) {
125 DictionaryValue* file_value = new DictionaryValue(); 124 DictionaryValue* file_value = new DictionaryValue();
126 125
127 file_value->SetInteger( 126 file_value->SetInteger(
128 "started", static_cast<int>(download->GetStartTime().ToTimeT())); 127 "started", static_cast<int>(download_item->GetStartTime().ToTimeT()));
129 file_value->SetString( 128 file_value->SetString(
130 "since_string", TimeFormat::RelativeDate(download->GetStartTime(), NULL)); 129 "since_string", TimeFormat::RelativeDate(
130 download_item->GetStartTime(), NULL));
131 file_value->SetString( 131 file_value->SetString(
132 "date_string", base::TimeFormatShortDate(download->GetStartTime())); 132 "date_string", base::TimeFormatShortDate(download_item->GetStartTime()));
133 file_value->SetInteger("id", id); 133 file_value->SetInteger("id", download_item->GetId());
134 134
135 FilePath download_path(download->GetTargetFilePath()); 135 FilePath download_path(download_item->GetTargetFilePath());
136 file_value->Set("file_path", base::CreateFilePathValue(download_path)); 136 file_value->Set("file_path", base::CreateFilePathValue(download_path));
137 file_value->SetString("file_url", 137 file_value->SetString("file_url",
138 net::FilePathToFileURL(download_path).spec()); 138 net::FilePathToFileURL(download_path).spec());
139 139
140 // Keep file names as LTR. 140 // Keep file names as LTR.
141 string16 file_name = download->GetFileNameToReportUser().LossyDisplayName(); 141 string16 file_name =
142 download_item->GetFileNameToReportUser().LossyDisplayName();
142 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name); 143 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name);
143 file_value->SetString("file_name", file_name); 144 file_value->SetString("file_name", file_name);
144 file_value->SetString("url", download->GetURL().spec()); 145 file_value->SetString("url", download_item->GetURL().spec());
145 file_value->SetBoolean("otr", incognito); 146 file_value->SetBoolean("otr", incognito);
146 file_value->SetInteger("total", static_cast<int>(download->GetTotalBytes())); 147 file_value->SetInteger("total", static_cast<int>(
148 download_item->GetTotalBytes()));
147 file_value->SetBoolean("file_externally_removed", 149 file_value->SetBoolean("file_externally_removed",
148 download->GetFileExternallyRemoved()); 150 download_item->GetFileExternallyRemoved());
149 151
150 if (download->IsInProgress()) { 152 if (download_item->IsInProgress()) {
151 if (download->GetSafetyState() == content::DownloadItem::DANGEROUS) { 153 if (download_item->GetSafetyState() == content::DownloadItem::DANGEROUS) {
152 file_value->SetString("state", "DANGEROUS"); 154 file_value->SetString("state", "DANGEROUS");
153 // These are the only danger states we expect to see (and the UI is 155 // These are the only danger states that the UI is equipped to handle.
154 // equipped to handle): 156 DCHECK(download_item->GetDangerType() ==
155 DCHECK(download->GetDangerType() ==
156 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE || 157 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
157 download->GetDangerType() == 158 download_item->GetDangerType() ==
158 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL || 159 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
159 download->GetDangerType() == 160 download_item->GetDangerType() ==
160 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT || 161 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
161 download->GetDangerType() == 162 download_item->GetDangerType() ==
162 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT); 163 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT);
163 const char* danger_type_value = 164 const char* danger_type_value =
164 GetDangerTypeString(download->GetDangerType()); 165 GetDangerTypeString(download_item->GetDangerType());
165 file_value->SetString("danger_type", danger_type_value); 166 file_value->SetString("danger_type", danger_type_value);
166 } else if (download->IsPaused()) { 167 } else if (download_item->IsPaused()) {
167 file_value->SetString("state", "PAUSED"); 168 file_value->SetString("state", "PAUSED");
168 } else { 169 } else {
169 file_value->SetString("state", "IN_PROGRESS"); 170 file_value->SetString("state", "IN_PROGRESS");
170 } 171 }
171 172
172 file_value->SetString("progress_status_text", 173 file_value->SetString("progress_status_text",
173 download_util::GetProgressStatusText(download)); 174 download_util::GetProgressStatusText(download_item));
174 175
175 file_value->SetInteger("percent", 176 file_value->SetInteger("percent",
176 static_cast<int>(download->PercentComplete())); 177 static_cast<int>(download_item->PercentComplete()));
177 file_value->SetInteger("received", 178 file_value->SetInteger("received",
178 static_cast<int>(download->GetReceivedBytes())); 179 static_cast<int>(download_item->GetReceivedBytes()));
179 } else if (download->IsInterrupted()) { 180 } else if (download_item->IsInterrupted()) {
180 file_value->SetString("state", "INTERRUPTED"); 181 file_value->SetString("state", "INTERRUPTED");
181 182
182 file_value->SetString("progress_status_text", 183 file_value->SetString("progress_status_text",
183 download_util::GetProgressStatusText(download)); 184 download_util::GetProgressStatusText(download_item));
184 185
185 file_value->SetInteger("percent", 186 file_value->SetInteger("percent",
186 static_cast<int>(download->PercentComplete())); 187 static_cast<int>(download_item->PercentComplete()));
187 file_value->SetInteger("received", 188 file_value->SetInteger("received",
188 static_cast<int>(download->GetReceivedBytes())); 189 static_cast<int>(download_item->GetReceivedBytes()));
189 file_value->SetString("last_reason_text", 190 file_value->SetString("last_reason_text",
190 BaseDownloadItemModel::InterruptReasonMessage( 191 BaseDownloadItemModel::InterruptReasonMessage(
191 download->GetLastReason())); 192 download_item->GetLastReason()));
192 } else if (download->IsCancelled()) { 193 } else if (download_item->IsCancelled()) {
193 file_value->SetString("state", "CANCELLED"); 194 file_value->SetString("state", "CANCELLED");
194 } else if (download->IsComplete()) { 195 } else if (download_item->IsComplete()) {
195 if (download->GetSafetyState() == content::DownloadItem::DANGEROUS) 196 if (download_item->GetSafetyState() == content::DownloadItem::DANGEROUS)
196 file_value->SetString("state", "DANGEROUS"); 197 file_value->SetString("state", "DANGEROUS");
197 else 198 else
198 file_value->SetString("state", "COMPLETE"); 199 file_value->SetString("state", "COMPLETE");
199 } else { 200 } else {
200 NOTREACHED() << "state undefined"; 201 NOTREACHED() << "state undefined";
201 } 202 }
202 203
203 return file_value; 204 return file_value;
204 } 205 }
205 206
206 // Return true if |download_id| refers to a download that belongs to the 207 // Return true if |download_id| refers to a download that belongs to the
207 // incognito download manager, if one exists. 208 // incognito download manager, if one exists.
208 bool IsItemIncognito( 209 bool IsItemIncognito(
209 int32 download_id, 210 int32 download_id,
210 content::DownloadManager* manager, 211 content::DownloadManager* manager,
211 content::DownloadManager* original_manager) { 212 content::DownloadManager* original_manager) {
212 // |original_manager| is only non-NULL if |manager| is incognito. 213 // |original_manager| is only non-NULL if |manager| is incognito.
213 return (original_manager && 214 return (original_manager &&
214 (manager->GetDownload(download_id) != NULL)); 215 (manager->GetDownload(download_id) != NULL));
215 } 216 }
216 217
218 // Filter out extension downloads and downloads that don't have a filename yet.
James Hawkins 2012/08/22 17:39:01 nit: Filters
benjhayden 2012/08/22 20:19:22 Done.
219 bool IsDownloadDisplayable(const content::DownloadItem& item) {
220 return (!download_crx_util::IsExtensionDownload(item) &&
221 !item.IsTemporary() &&
222 !item.GetFileNameToReportUser().empty() &&
223 !item.GetTargetFilePath().empty());
224 }
225
217 } // namespace 226 } // namespace
218 227
219 DownloadsDOMHandler::DownloadsDOMHandler(content::DownloadManager* dlm) 228 DownloadsDOMHandler::DownloadsDOMHandler(content::DownloadManager* dlm)
220 : search_text_(), 229 : search_text_(),
221 download_manager_(dlm), 230 download_manager_(dlm),
222 original_profile_download_manager_(NULL), 231 original_profile_download_manager_(NULL),
223 initialized_(false), 232 update_scheduled_(false),
224 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { 233 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
225 // Create our fileicon data source. 234 // Create our fileicon data source.
226 Profile* profile = Profile::FromBrowserContext(dlm->GetBrowserContext()); 235 Profile* profile = Profile::FromBrowserContext(dlm->GetBrowserContext());
227 ChromeURLDataManager::AddDataSource(profile, new FileIconSource()); 236 ChromeURLDataManager::AddDataSource(profile, new FileIconSource());
228 237
229 // Figure out our parent DownloadManager, if any. 238 // Observe the DownloadManagers.
230 Profile* original_profile = profile->GetOriginalProfile(); 239 download_manager_->AddObserver(this);
231 if (original_profile != profile) { 240 if (profile->IsOffTheRecord()) {
232 original_profile_download_manager_ = 241 original_profile_download_manager_ =
233 BrowserContext::GetDownloadManager(original_profile); 242 BrowserContext::GetDownloadManager(profile->GetOriginalProfile());
243 original_profile_download_manager_->AddObserver(this);
244 }
245
246 // Observe all the DownloadItems.
247 content::DownloadManager::DownloadVector downloads;
248 SearchDownloads(&downloads);
249 for (content::DownloadManager::DownloadVector::const_iterator
250 iter = downloads.begin();
251 iter != downloads.end(); ++iter) {
252 (*iter)->AddObserver(this);
253 observing_items_.insert(*iter);
234 } 254 }
235 } 255 }
236 256
237 DownloadsDOMHandler::~DownloadsDOMHandler() { 257 DownloadsDOMHandler::~DownloadsDOMHandler() {
238 ClearDownloadItems(); 258 for (DownloadSet::const_iterator it = observing_items_.begin();
259 it != observing_items_.end(); ++it) {
260 (*it)->RemoveObserver(this);
261 }
262 observing_items_.clear();
239 download_manager_->RemoveObserver(this); 263 download_manager_->RemoveObserver(this);
240 if (original_profile_download_manager_) 264 if (original_profile_download_manager_)
241 original_profile_download_manager_->RemoveObserver(this); 265 original_profile_download_manager_->RemoveObserver(this);
242 } 266 }
243 267
244 // DownloadsDOMHandler, public: ----------------------------------------------- 268 // DownloadsDOMHandler, public: -----------------------------------------------
245 269
246 void DownloadsDOMHandler::OnPageLoaded(const base::ListValue* args) { 270 void DownloadsDOMHandler::OnPageLoaded(const base::ListValue* args) {
247 if (initialized_) 271 SendCurrentDownloads();
248 return;
249 initialized_ = true;
250
251 download_manager_->AddObserver(this);
252 if (original_profile_download_manager_)
253 original_profile_download_manager_->AddObserver(this);
254 } 272 }
255 273
256 void DownloadsDOMHandler::RegisterMessages() { 274 void DownloadsDOMHandler::RegisterMessages() {
257 web_ui()->RegisterMessageCallback("onPageLoaded", 275 web_ui()->RegisterMessageCallback("onPageLoaded",
258 base::Bind(&DownloadsDOMHandler::OnPageLoaded, 276 base::Bind(&DownloadsDOMHandler::OnPageLoaded,
259 base::Unretained(this))); 277 weak_ptr_factory_.GetWeakPtr()));
260 web_ui()->RegisterMessageCallback("getDownloads", 278 web_ui()->RegisterMessageCallback("getDownloads",
261 base::Bind(&DownloadsDOMHandler::HandleGetDownloads, 279 base::Bind(&DownloadsDOMHandler::HandleGetDownloads,
262 base::Unretained(this))); 280 weak_ptr_factory_.GetWeakPtr()));
263 web_ui()->RegisterMessageCallback("openFile", 281 web_ui()->RegisterMessageCallback("openFile",
264 base::Bind(&DownloadsDOMHandler::HandleOpenFile, 282 base::Bind(&DownloadsDOMHandler::HandleOpenFile,
265 base::Unretained(this))); 283 weak_ptr_factory_.GetWeakPtr()));
266 web_ui()->RegisterMessageCallback("drag", 284 web_ui()->RegisterMessageCallback("drag",
267 base::Bind(&DownloadsDOMHandler::HandleDrag, 285 base::Bind(&DownloadsDOMHandler::HandleDrag,
268 base::Unretained(this))); 286 weak_ptr_factory_.GetWeakPtr()));
269 web_ui()->RegisterMessageCallback("saveDangerous", 287 web_ui()->RegisterMessageCallback("saveDangerous",
270 base::Bind(&DownloadsDOMHandler::HandleSaveDangerous, 288 base::Bind(&DownloadsDOMHandler::HandleSaveDangerous,
271 base::Unretained(this))); 289 weak_ptr_factory_.GetWeakPtr()));
272 web_ui()->RegisterMessageCallback("discardDangerous", 290 web_ui()->RegisterMessageCallback("discardDangerous",
273 base::Bind(&DownloadsDOMHandler::HandleDiscardDangerous, 291 base::Bind(&DownloadsDOMHandler::HandleDiscardDangerous,
274 base::Unretained(this))); 292 weak_ptr_factory_.GetWeakPtr()));
275 web_ui()->RegisterMessageCallback("show", 293 web_ui()->RegisterMessageCallback("show",
276 base::Bind(&DownloadsDOMHandler::HandleShow, 294 base::Bind(&DownloadsDOMHandler::HandleShow,
277 base::Unretained(this))); 295 weak_ptr_factory_.GetWeakPtr()));
278 web_ui()->RegisterMessageCallback("togglepause", 296 web_ui()->RegisterMessageCallback("togglepause",
279 base::Bind(&DownloadsDOMHandler::HandlePause, 297 base::Bind(&DownloadsDOMHandler::HandlePause,
280 base::Unretained(this))); 298 weak_ptr_factory_.GetWeakPtr()));
281 web_ui()->RegisterMessageCallback("resume", 299 web_ui()->RegisterMessageCallback("resume",
282 base::Bind(&DownloadsDOMHandler::HandlePause, 300 base::Bind(&DownloadsDOMHandler::HandlePause,
283 base::Unretained(this))); 301 weak_ptr_factory_.GetWeakPtr()));
284 web_ui()->RegisterMessageCallback("remove", 302 web_ui()->RegisterMessageCallback("remove",
285 base::Bind(&DownloadsDOMHandler::HandleRemove, 303 base::Bind(&DownloadsDOMHandler::HandleRemove,
286 base::Unretained(this))); 304 weak_ptr_factory_.GetWeakPtr()));
287 web_ui()->RegisterMessageCallback("cancel", 305 web_ui()->RegisterMessageCallback("cancel",
288 base::Bind(&DownloadsDOMHandler::HandleCancel, 306 base::Bind(&DownloadsDOMHandler::HandleCancel,
289 base::Unretained(this))); 307 weak_ptr_factory_.GetWeakPtr()));
290 web_ui()->RegisterMessageCallback("clearAll", 308 web_ui()->RegisterMessageCallback("clearAll",
291 base::Bind(&DownloadsDOMHandler::HandleClearAll, 309 base::Bind(&DownloadsDOMHandler::HandleClearAll,
292 base::Unretained(this))); 310 weak_ptr_factory_.GetWeakPtr()));
293 web_ui()->RegisterMessageCallback("openDownloadsFolder", 311 web_ui()->RegisterMessageCallback("openDownloadsFolder",
294 base::Bind(&DownloadsDOMHandler::HandleOpenDownloadsFolder, 312 base::Bind(&DownloadsDOMHandler::HandleOpenDownloadsFolder,
295 base::Unretained(this))); 313 weak_ptr_factory_.GetWeakPtr()));
296 } 314 }
297 315
298 void DownloadsDOMHandler::OnDownloadUpdated(content::DownloadItem* download) { 316 void DownloadsDOMHandler::OnDownloadCreated(
299 // Get the id for the download. Our downloads are sorted latest to first, 317 content::DownloadManager* manager, content::DownloadItem* download_item) {
300 // and the id is the index into that list. We should be careful of sync 318 // DownloadsDOMHandler observes all items and only chooses which downloads to
301 // errors between the UI and the download_items_ list (we may wish to use 319 // display in SendCurrentDownloads() and OnDownloadUpdated() using
302 // something other than 'id'). 320 // IsDownloadDisplayable().
303 OrderedDownloads::iterator it = std::find(download_items_.begin(), 321 download_item->AddObserver(this);
304 download_items_.end(), 322 observing_items_.insert(download_item);
305 download); 323 if (IsDownloadDisplayable(*download_item))
306 if (it == download_items_.end()) 324 ScheduleSendCurrentDownloads();
307 return; 325 }
308 326
309 const int id = static_cast<int>(it - download_items_.begin()); 327 void DownloadsDOMHandler::OnDownloadUpdated(
310 328 content::DownloadItem* download_item) {
311 ListValue results_value; 329 if (IsDownloadDisplayable(*download_item)) {
312 results_value.Append(CreateDownloadItemValue(download, id, IsItemIncognito( 330 base::ListValue results_value;
313 download->GetId(), 331 results_value.Append(CreateDownloadItemValue(download_item, IsItemIncognito(
314 download_manager_, 332 download_item->GetId(),
315 original_profile_download_manager_))); 333 download_manager_,
316 web_ui()->CallJavascriptFunction("downloadUpdated", results_value); 334 original_profile_download_manager_)));
335 CallDownloadUpdated(results_value);
336 }
317 } 337 }
318 338
319 void DownloadsDOMHandler::OnDownloadDestroyed( 339 void DownloadsDOMHandler::OnDownloadDestroyed(
320 content::DownloadItem* download) { 340 content::DownloadItem* download_item) {
321 download->RemoveObserver(this); 341 download_item->RemoveObserver(this);
322 OrderedDownloads::iterator it = std::find(download_items_.begin(), 342 observing_items_.erase(download_item);
323 download_items_.end(), 343 ScheduleSendCurrentDownloads();
324 download);
325 if (it != download_items_.end())
326 *it = NULL;
327 // A later ModelChanged() notification will change the WebUI's
328 // view of the downloads list.
329 }
330
331 // A download has started or been deleted. Query our DownloadManager for the
332 // current set of downloads.
333 void DownloadsDOMHandler::ModelChanged(content::DownloadManager* manager) {
334 DCHECK(manager == download_manager_ ||
335 manager == original_profile_download_manager_);
336
337 ClearDownloadItems();
338 download_manager_->SearchDownloads(WideToUTF16(search_text_),
339 &download_items_);
340 // If we have a parent DownloadManager, let it add its downloads to the
341 // results.
342 if (original_profile_download_manager_) {
343 original_profile_download_manager_->SearchDownloads(
344 WideToUTF16(search_text_), &download_items_);
345 }
346
347 sort(download_items_.begin(), download_items_.end(), DownloadItemSorter());
348
349 // Remove any extension downloads.
350 for (size_t i = 0; i < download_items_.size();) {
351 if (download_crx_util::IsExtensionDownload(*download_items_[i]))
352 download_items_.erase(download_items_.begin() + i);
353 else
354 i++;
355 }
356
357 // Add ourself to all download items as an observer.
358 for (OrderedDownloads::iterator it = download_items_.begin();
359 it != download_items_.end(); ++it) {
360 if (static_cast<int>(it - download_items_.begin()) > kMaxDownloads)
361 break;
362
363 // We should never see anything that isn't already in the history.
364 DCHECK(*it);
365 DCHECK((*it)->IsPersisted());
366
367 (*it)->AddObserver(this);
368 }
369
370 SendCurrentDownloads();
371 } 344 }
372 345
373 void DownloadsDOMHandler::ManagerGoingDown(content::DownloadManager* manager) { 346 void DownloadsDOMHandler::ManagerGoingDown(content::DownloadManager* manager) {
374 // This should never happen. The lifetime of the DownloadsDOMHandler 347 // This should never happen. The lifetime of the DownloadsDOMHandler
375 // is tied to the tab in which downloads.html is displayed, which cannot 348 // is tied to the tab in which downloads.html is displayed, which cannot
376 // outlive the Browser that contains it, which cannot outlive the Profile 349 // outlive the Browser that contains it, which cannot outlive the Profile
377 // it is associated with. If that profile is an incognito profile, 350 // it is associated with. If that profile is an incognito profile,
378 // it cannot outlive its original profile. Thus this class should be 351 // it cannot outlive its original profile. Thus this class should be
379 // destroyed before a ManagerGoingDown() notification occurs. 352 // destroyed before a ManagerGoingDown() notification occurs.
380 NOTREACHED(); 353 NOTREACHED();
381 } 354 }
382 355
383 void DownloadsDOMHandler::HandleGetDownloads(const ListValue* args) { 356 void DownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) {
384 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS); 357 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS);
385 std::wstring new_search = UTF16ToWideHack(ExtractStringValue(args)); 358 search_text_ = ExtractStringValue(args);
386 if (search_text_.compare(new_search) != 0) { 359 SendCurrentDownloads();
387 search_text_ = new_search;
388 ModelChanged(download_manager_);
389 } else {
390 SendCurrentDownloads();
391 }
392
393 download_manager_->CheckForHistoryFilesRemoval(); 360 download_manager_->CheckForHistoryFilesRemoval();
394 } 361 }
395 362
396 void DownloadsDOMHandler::HandleOpenFile(const ListValue* args) { 363 void DownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) {
397 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE); 364 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE);
398 content::DownloadItem* file = GetDownloadByValue(args); 365 content::DownloadItem* file = GetDownloadByValue(args);
399 if (file) 366 if (file)
400 file->OpenDownload(); 367 file->OpenDownload();
401 } 368 }
402 369
403 void DownloadsDOMHandler::HandleDrag(const ListValue* args) { 370 void DownloadsDOMHandler::HandleDrag(const base::ListValue* args) {
404 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG); 371 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG);
405 content::DownloadItem* file = GetDownloadByValue(args); 372 content::DownloadItem* file = GetDownloadByValue(args);
406 if (file) { 373 content::WebContents* web_contents = GetWebUIWebContents();
407 IconManager* im = g_browser_process->icon_manager(); 374 if (!file || !web_contents)
James Hawkins 2012/08/22 17:39:01 Under what circumstances is |web_contents| NULL?
benjhayden 2012/08/22 20:19:22 Only the test. GetWebUIWebContents(), CallDownload
James Hawkins 2012/08/22 20:24:20 Please document this case (that |web_contents| is
benjhayden 2012/08/23 16:48:57 Done.
408 gfx::Image* icon = im->LookupIcon(file->GetUserVerifiedFilePath(), 375 return;
409 IconLoader::NORMAL); 376 gfx::Image* icon = g_browser_process->icon_manager()->LookupIcon(
410 gfx::NativeView view = web_ui()->GetWebContents()->GetNativeView(); 377 file->GetUserVerifiedFilePath(), IconLoader::NORMAL);
411 { 378 gfx::NativeView view = web_contents->GetNativeView();
412 // Enable nested tasks during DnD, while |DragDownload()| blocks. 379 {
413 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); 380 // Enable nested tasks during DnD, while |DragDownload()| blocks.
414 download_util::DragDownload(file, icon, view); 381 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
415 } 382 download_util::DragDownload(file, icon, view);
416 } 383 }
417 } 384 }
418 385
419 void DownloadsDOMHandler::HandleSaveDangerous(const ListValue* args) { 386 void DownloadsDOMHandler::HandleSaveDangerous(const base::ListValue* args) {
420 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS); 387 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
421 content::DownloadItem* file = GetDownloadByValue(args); 388 content::DownloadItem* file = GetDownloadByValue(args);
422 if (file) 389 if (file)
423 ShowDangerPrompt(file); 390 ShowDangerPrompt(file);
424 // TODO(benjhayden): else ModelChanged()? Downloads might be able to disappear
425 // out from under us, so update our idea of the downloads as soon as possible.
426 } 391 }
427 392
428 void DownloadsDOMHandler::HandleDiscardDangerous(const ListValue* args) { 393 void DownloadsDOMHandler::HandleDiscardDangerous(const base::ListValue* args) {
429 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS); 394 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS);
430 content::DownloadItem* file = GetDownloadByValue(args); 395 content::DownloadItem* file = GetDownloadByValue(args);
431 if (file) 396 if (file)
432 file->Delete(content::DownloadItem::DELETE_DUE_TO_USER_DISCARD); 397 file->Delete(content::DownloadItem::DELETE_DUE_TO_USER_DISCARD);
433 } 398 }
434 399
435 void DownloadsDOMHandler::HandleShow(const ListValue* args) { 400 void DownloadsDOMHandler::HandleShow(const base::ListValue* args) {
436 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW); 401 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW);
437 content::DownloadItem* file = GetDownloadByValue(args); 402 content::DownloadItem* file = GetDownloadByValue(args);
438 if (file) 403 if (file)
439 file->ShowDownloadInShell(); 404 file->ShowDownloadInShell();
440 } 405 }
441 406
442 void DownloadsDOMHandler::HandlePause(const ListValue* args) { 407 void DownloadsDOMHandler::HandlePause(const base::ListValue* args) {
443 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE); 408 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE);
444 content::DownloadItem* file = GetDownloadByValue(args); 409 content::DownloadItem* file = GetDownloadByValue(args);
445 if (file) 410 if (file)
446 file->TogglePause(); 411 file->TogglePause();
447 } 412 }
448 413
449 void DownloadsDOMHandler::HandleRemove(const ListValue* args) { 414 void DownloadsDOMHandler::HandleRemove(const base::ListValue* args) {
450 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE); 415 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE);
451 content::DownloadItem* file = GetDownloadByValue(args); 416 content::DownloadItem* file = GetDownloadByValue(args);
452 if (file) { 417 if (file) {
453 DCHECK(file->IsPersisted()); 418 DCHECK(file->IsPersisted());
454 file->Remove(); 419 file->Remove();
455 } 420 }
456 } 421 }
457 422
458 void DownloadsDOMHandler::HandleCancel(const ListValue* args) { 423 void DownloadsDOMHandler::HandleCancel(const base::ListValue* args) {
459 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL); 424 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL);
460 content::DownloadItem* file = GetDownloadByValue(args); 425 content::DownloadItem* file = GetDownloadByValue(args);
461 if (file) 426 if (file)
462 file->Cancel(true); 427 file->Cancel(true);
463 } 428 }
464 429
465 void DownloadsDOMHandler::HandleClearAll(const ListValue* args) { 430 void DownloadsDOMHandler::HandleClearAll(const base::ListValue* args) {
466 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL); 431 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL);
467 download_manager_->RemoveAllDownloads(); 432 download_manager_->RemoveAllDownloads();
468 433
469 // If this is an incognito downloader, clear All should clear main download 434 // If this is an incognito downloader, clear All should clear main download
470 // manager as well. 435 // manager as well.
471 if (original_profile_download_manager_) 436 if (original_profile_download_manager_)
472 original_profile_download_manager_->RemoveAllDownloads(); 437 original_profile_download_manager_->RemoveAllDownloads();
473 } 438 }
474 439
475 void DownloadsDOMHandler::HandleOpenDownloadsFolder(const ListValue* args) { 440 void DownloadsDOMHandler::HandleOpenDownloadsFolder(
441 const base::ListValue* args) {
476 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER); 442 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER);
477 platform_util::OpenItem( 443 platform_util::OpenItem(
478 DownloadPrefs::FromDownloadManager(download_manager_)->DownloadPath()); 444 DownloadPrefs::FromDownloadManager(download_manager_)->DownloadPath());
479 } 445 }
480 446
481 // DownloadsDOMHandler, private: ---------------------------------------------- 447 // DownloadsDOMHandler, private: ----------------------------------------------
482 448
449 void DownloadsDOMHandler::ScheduleSendCurrentDownloads() {
450 // Don't call SendCurrentDownloads() every time anything changes. Batch them
451 // together instead. This may handle hundreds of OnDownloadDestroyed() calls
452 // in a single UI message loop iteration when the user Clears All downloads.
453 if (update_scheduled_)
454 return;
455 update_scheduled_ = true;
456 BrowserThread::PostTask(
457 BrowserThread::UI, FROM_HERE,
458 base::Bind(&DownloadsDOMHandler::SendCurrentDownloads,
459 weak_ptr_factory_.GetWeakPtr()));
460 }
461
483 void DownloadsDOMHandler::SendCurrentDownloads() { 462 void DownloadsDOMHandler::SendCurrentDownloads() {
484 ListValue results_value; 463 update_scheduled_ = false;
485 for (OrderedDownloads::iterator it = download_items_.begin(); 464 content::DownloadManager::DownloadVector downloads;
486 it != download_items_.end(); ++it) { 465 SearchDownloads(&downloads);
487 if (!*it) 466 sort(downloads.begin(), downloads.end(), DownloadItemSorter());
488 continue; 467 base::ListValue results_value;
489 int index = static_cast<int>(it - download_items_.begin()); 468 for (content::DownloadManager::DownloadVector::const_iterator
490 if (index <= kMaxDownloads) 469 iter = downloads.begin();
491 results_value.Append(CreateDownloadItemValue(*it, index, IsItemIncognito( 470 iter != downloads.end(); ++iter) {
492 (*it)->GetId(), 471 if (IsDownloadDisplayable(**iter))
493 download_manager_, 472 results_value.Append(CreateDownloadItemValue(*iter, IsItemIncognito(
494 original_profile_download_manager_))); 473 (*iter)->GetId(), download_manager_,
474 original_profile_download_manager_)));
475 if (results_value.GetSize() == kMaxDownloads)
476 break;
495 } 477 }
478 CallDownloadsList(results_value);
479 }
496 480
497 web_ui()->CallJavascriptFunction("downloadsList", results_value); 481 void DownloadsDOMHandler::SearchDownloads(
482 content::DownloadManager::DownloadVector* downloads) {
483 download_manager_->SearchDownloads(search_text_, downloads);
484 if (original_profile_download_manager_)
485 original_profile_download_manager_->SearchDownloads(
486 search_text_, downloads);
498 } 487 }
499 488
500 void DownloadsDOMHandler::ShowDangerPrompt( 489 void DownloadsDOMHandler::ShowDangerPrompt(
501 content::DownloadItem* dangerous_item) { 490 content::DownloadItem* dangerous_item) {
502 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create( 491 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create(
503 dangerous_item, 492 dangerous_item,
504 TabContents::FromWebContents(web_ui()->GetWebContents()), 493 TabContents::FromWebContents(GetWebUIWebContents()),
505 base::Bind(&DownloadsDOMHandler::DangerPromptAccepted, 494 base::Bind(&DownloadsDOMHandler::DangerPromptAccepted,
506 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId()), 495 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId()),
507 base::Closure()); 496 base::Closure());
508 // danger_prompt will delete itself. 497 // danger_prompt will delete itself.
509 DCHECK(danger_prompt); 498 DCHECK(danger_prompt);
510 } 499 }
511 500
512 void DownloadsDOMHandler::DangerPromptAccepted(int download_id) { 501 void DownloadsDOMHandler::DangerPromptAccepted(int download_id) {
513 content::DownloadItem* item = download_manager_->GetActiveDownloadItem( 502 content::DownloadItem* item = download_manager_->GetActiveDownloadItem(
514 download_id); 503 download_id);
515 if (!item) 504 if (!item)
516 return; 505 return;
517 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS); 506 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
518 item->DangerousDownloadValidated(); 507 item->DangerousDownloadValidated();
519 } 508 }
520 509
521 void DownloadsDOMHandler::ClearDownloadItems() { 510 content::DownloadItem* DownloadsDOMHandler::GetDownloadByValue(
522 // Clear out old state and remove self as observer for each download. 511 const base::ListValue* args) {
523 for (OrderedDownloads::iterator it = download_items_.begin(); 512 int id = -1;
524 it != download_items_.end(); ++it) { 513 if (!ExtractIntegerValue(args, &id))
525 if (!*it) 514 return NULL;
526 continue; 515 content::DownloadItem* download_item = download_manager_->GetDownload(id);
527 (*it)->RemoveObserver(this); 516 if (download_item == NULL)
528 } 517 download_item = original_profile_download_manager_->GetDownload(id);
529 download_items_.clear(); 518 return download_item;
530 } 519 }
531 520
532 content::DownloadItem* DownloadsDOMHandler::GetDownloadById(int id) { 521 content::WebContents* DownloadsDOMHandler::GetWebUIWebContents() {
533 for (OrderedDownloads::iterator it = download_items_.begin(); 522 return web_ui()->GetWebContents();
534 it != download_items_.end(); ++it) {
535 if (static_cast<int>(it - download_items_.begin() == id)) {
536 return (*it);
537 }
538 }
539
540 return NULL;
541 } 523 }
542 524
543 content::DownloadItem* DownloadsDOMHandler::GetDownloadByValue( 525 void DownloadsDOMHandler::CallDownloadsList(const base::ListValue& downloads) {
James Hawkins 2012/08/22 17:39:01 Remove these wrapper method and make the calls dir
benjhayden 2012/08/22 20:19:22 These wrapper methods facilitate the test. I'm hap
James Hawkins 2012/08/22 20:24:20 Ah, right. I forgot.
544 const ListValue* args) { 526 web_ui()->CallJavascriptFunction("downloadsList", downloads);
545 int id;
546 if (ExtractIntegerValue(args, &id)) {
547 return GetDownloadById(id);
548 }
549 return NULL;
550 } 527 }
528
529 void DownloadsDOMHandler::CallDownloadUpdated(
530 const base::ListValue& download_item) {
531 web_ui()->CallJavascriptFunction("downloadUpdated", download_item);
532 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698