Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 } | |
| OLD | NEW |