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..5924f52a7ee36529df65852ac25900e481ddefc8 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 const DownloadsDOMHandlerData* Get(const content::DownloadItem* item) { |
+ 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()); |
+ const 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)) |
- return NULL; |
+ std::string download_id; |
+ if (!args->GetString(0, &download_id)) { |
+ NOTREACHED(); |
+ return nullptr; |
+ } |
+ |
+ uint64 id; |
+ if (!base::StringToUint64(download_id, &id)) { |
+ NOTREACHED(); |
+ return nullptr; |
+ } |
+ |
+ 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; |
} |