Chromium Code Reviews| Index: chrome/browser/ui/webui/downloads_dom_handler.cc |
| diff --git a/chrome/browser/ui/webui/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads_dom_handler.cc |
| index f347ba33b455b8cfb0f31555b804c19ea5752ca5..d0a14ec2bc8cae11867c7ad649d45ea25b4ab1ad 100644 |
| --- a/chrome/browser/ui/webui/downloads_dom_handler.cc |
| +++ b/chrome/browser/ui/webui/downloads_dom_handler.cc |
| @@ -16,8 +16,10 @@ |
| #include "base/metrics/field_trial.h" |
| #include "base/metrics/histogram.h" |
| #include "base/prefs/pref_service.h" |
| +#include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/utf_string_conversions.h" |
| +#include "base/supports_user_data.h" |
| #include "base/threading/thread.h" |
| #include "base/value_conversions.h" |
| #include "base/values.h" |
| @@ -75,6 +77,35 @@ enum DownloadsDOMEvent { |
| DOWNLOADS_DOM_EVENT_MAX |
| }; |
| +static const char kKey[] = "DownloadsDOMHandlerData"; |
| + |
| +class DownloadsDOMHandlerData : public base::SupportsUserData::Data { |
| + public: |
| + static DownloadsDOMHandlerData* Get(content::DownloadItem* item) { |
| + return static_cast<DownloadsDOMHandlerData*>(item->GetUserData(kKey)); |
| + } |
| + |
| + static DownloadsDOMHandlerData* Get(const content::DownloadItem* item) { |
|
asanka
2014/12/02 23:59:34
nit: return 'const DownloadsDOMHandlerData*'
Dan Beam
2014/12/03 01:08:24
Done.
|
| + return static_cast<DownloadsDOMHandlerData*>(item->GetUserData(kKey)); |
| + } |
| + |
| + static void Set(content::DownloadItem* item, DownloadsDOMHandlerData* data) { |
| + item->SetUserData(kKey, data); |
| + } |
| + |
| + static DownloadsDOMHandlerData* Create(content::DownloadItem* item) { |
| + DownloadsDOMHandlerData* data = new DownloadsDOMHandlerData; |
| + item->SetUserData(kKey, data); |
| + return data; |
| + } |
| + |
| + void set_is_removed(bool is_removed) { is_removed_ = is_removed; } |
| + bool is_removed() const { return is_removed_; } |
| + |
| + private: |
| + bool is_removed_; |
| +}; |
| + |
| void CountDownloadsDOMEvents(DownloadsDOMEvent event) { |
| UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent", |
| event, |
| @@ -131,7 +162,7 @@ base::DictionaryValue* CreateDownloadItemValue( |
| download_item->GetStartTime(), NULL)); |
| file_value->SetString( |
| "date_string", base::TimeFormatShortDate(download_item->GetStartTime())); |
| - file_value->SetInteger("id", download_item->GetId()); |
| + file_value->SetString("id", base::Uint64ToString(download_item->GetId())); |
| base::FilePath download_path(download_item->GetTargetFilePath()); |
| file_value->Set("file_path", base::CreateFilePathValue(download_path)); |
| @@ -230,7 +261,7 @@ base::DictionaryValue* CreateDownloadItemValue( |
| break; |
| case content::DownloadItem::MAX_DOWNLOAD_STATE: |
| - NOTREACHED() << "state undefined"; |
| + NOTREACHED(); |
| } |
| return file_value; |
| @@ -238,10 +269,12 @@ base::DictionaryValue* CreateDownloadItemValue( |
| // Filters out extension downloads and downloads that don't have a filename yet. |
| bool IsDownloadDisplayable(const content::DownloadItem& item) { |
| - return (!download_crx_util::IsExtensionDownload(item) && |
| - !item.IsTemporary() && |
| - !item.GetFileNameToReportUser().empty() && |
| - !item.GetTargetFilePath().empty()); |
| + DownloadsDOMHandlerData* data = DownloadsDOMHandlerData::Get(&item); |
| + return !download_crx_util::IsExtensionDownload(item) && |
| + !item.IsTemporary() && |
| + !item.GetFileNameToReportUser().empty() && |
| + !item.GetTargetFilePath().empty() && |
| + (!data || !data->is_removed()); |
| } |
| } // namespace |
| @@ -262,6 +295,12 @@ DownloadsDOMHandler::DownloadsDOMHandler(content::DownloadManager* dlm) |
| } |
| DownloadsDOMHandler::~DownloadsDOMHandler() { |
| + while (!removed_ids_.empty()) { |
| + content::DownloadItem* download = GetDownloadById(removed_ids_.back()); |
| + removed_ids_.pop_back(); |
| + if (download) |
| + download->Remove(); |
| + } |
| } |
| // DownloadsDOMHandler, public: ----------------------------------------------- |
| @@ -301,6 +340,9 @@ void DownloadsDOMHandler::RegisterMessages() { |
| web_ui()->RegisterMessageCallback("remove", |
| base::Bind(&DownloadsDOMHandler::HandleRemove, |
| weak_ptr_factory_.GetWeakPtr())); |
| + web_ui()->RegisterMessageCallback("undo", |
| + base::Bind(&DownloadsDOMHandler::HandleUndo, |
| + weak_ptr_factory_.GetWeakPtr())); |
| web_ui()->RegisterMessageCallback("cancel", |
| base::Bind(&DownloadsDOMHandler::HandleCancel, |
| weak_ptr_factory_.GetWeakPtr())); |
| @@ -340,12 +382,18 @@ void DownloadsDOMHandler::OnDownloadUpdated( |
| (original_notifier_.get() && |
| (manager == main_notifier_.GetManager())))); |
| CallDownloadUpdated(results_value); |
| + } else { |
| + ScheduleSendCurrentDownloads(); |
| } |
| } |
| void DownloadsDOMHandler::OnDownloadRemoved( |
| content::DownloadManager* manager, |
| content::DownloadItem* download_item) { |
| + DownloadsDOMHandlerData* data = DownloadsDOMHandlerData::Get(download_item); |
| + if (data && data->is_removed()) |
| + return; |
| + |
| // This relies on |download_item| being removed from DownloadManager in this |
| // MessageLoop iteration. |download_item| may not have been removed from |
| // DownloadManager when OnDownloadRemoved() is fired, so bounce off the |
| @@ -438,8 +486,28 @@ void DownloadsDOMHandler::HandleRemove(const base::ListValue* args) { |
| CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE); |
| content::DownloadItem* file = GetDownloadByValue(args); |
| - if (file) |
| - file->Remove(); |
| + if (!file) |
| + return; |
| + |
| + removed_ids_.push_back(file->GetId()); |
| + DownloadsDOMHandlerData::Create(file)->set_is_removed(true); |
| + file->UpdateObservers(); |
| +} |
| + |
| +void DownloadsDOMHandler::HandleUndo(const base::ListValue* args) { |
| + // TODO(dbeam): handle more than removed downloads someday? |
| + if (removed_ids_.empty()) |
| + return; |
| + |
| + uint32 last_removed_id = removed_ids_.back(); |
| + removed_ids_.pop_back(); |
| + |
| + content::DownloadItem* download = GetDownloadById(last_removed_id); |
| + if (!download) |
| + return; |
| + |
| + DownloadsDOMHandlerData::Set(download, nullptr); |
| + download->UpdateObservers(); |
| } |
| void DownloadsDOMHandler::HandleCancel(const base::ListValue* args) { |
| @@ -515,7 +583,7 @@ void DownloadsDOMHandler::SendCurrentDownloads() { |
| query.Limit(kMaxDownloads); |
| query.Search(all_items.begin(), all_items.end(), &filtered_items); |
| base::ListValue results_value; |
| - for (content::DownloadManager::DownloadVector::const_iterator |
| + for (content::DownloadManager::DownloadVector::iterator |
| iter = filtered_items.begin(); iter != filtered_items.end(); ++iter) { |
| results_value.Append(CreateDownloadItemValue( |
| *iter, |
| @@ -563,14 +631,27 @@ bool DownloadsDOMHandler::IsDeletingHistoryAllowed() { |
| content::DownloadItem* DownloadsDOMHandler::GetDownloadByValue( |
| const base::ListValue* args) { |
| - int download_id = -1; |
| - if (!ExtractIntegerValue(args, &download_id)) |
| + std::string download_id; |
| + if (!args->GetString(0, &download_id)) { |
| + NOTREACHED(); |
| return NULL; |
| + } |
| + |
| + uint64 id; |
| + if (!base::StringToUint64(download_id, &id)) { |
| + NOTREACHED(); |
| + return NULL; |
|
asanka
2014/12/02 23:59:34
nit: nullptr here and above.
Dan Beam
2014/12/03 01:08:24
Done.
|
| + } |
| + |
| + return GetDownloadById(static_cast<uint32>(id)); |
| +} |
| + |
| +content::DownloadItem* DownloadsDOMHandler::GetDownloadById(uint32 id) { |
| content::DownloadItem* item = NULL; |
| if (main_notifier_.GetManager()) |
| - item = main_notifier_.GetManager()->GetDownload(download_id); |
| + item = main_notifier_.GetManager()->GetDownload(id); |
| if (!item && original_notifier_.get() && original_notifier_->GetManager()) |
| - item = original_notifier_->GetManager()->GetDownload(download_id); |
| + item = original_notifier_->GetManager()->GetDownload(id); |
| return item; |
| } |