Index: chrome/browser/download/download_extension_api.cc |
diff --git a/chrome/browser/download/download_extension_api.cc b/chrome/browser/download/download_extension_api.cc |
index 34055e06e2b5302cb7332feaaa0f3eb02c0f94d3..35748ff6af8e849c1fcdd36fdd2db7436c35d915 100644 |
--- a/chrome/browser/download/download_extension_api.cc |
+++ b/chrome/browser/download/download_extension_api.cc |
@@ -35,6 +35,7 @@ |
#include "chrome/browser/ui/webui/web_ui_util.h" |
#include "content/browser/download/download_id.h" |
#include "content/browser/download/download_state_info.h" |
+#include "content/browser/download/download_stats.h" |
#include "content/browser/download/download_types.h" |
#include "content/browser/download/interrupt_reasons.h" |
#include "content/browser/renderer_host/render_view_host.h" |
@@ -42,7 +43,6 @@ |
#include "content/public/browser/download_item.h" |
#include "content/public/browser/render_process_host.h" |
#include "net/http/http_util.h" |
-#include "net/url_request/url_request.h" |
using content::BrowserThread; |
using content::DownloadItem; |
@@ -665,11 +665,16 @@ base::DictionaryValue* DownloadItemToJSON(DownloadItem* item) { |
json->SetInteger(kFileSizeKey, item->GetTotalBytes()); |
return json; |
} |
+ |
+typedef std::set<int> DownloadIdSet; |
+ |
} // anonymous namespace |
ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(Profile* profile) |
: profile_(profile), |
- manager_(NULL) { |
+ manager_(NULL), |
+ delete_item_jsons_(&item_jsons_), |
+ delete_on_changed_stats_(&on_changed_stats_) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
DCHECK(profile_); |
// Register a callback with the DownloadService for this profile to be called |
@@ -685,12 +690,70 @@ ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(Profile* profile) |
void ExtensionDownloadsEventRouter::Init(DownloadManager* manager) { |
DCHECK(manager_ == NULL); |
manager_ = manager; |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
manager_->AddObserver(this); |
} |
ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { |
if (manager_ != NULL) |
manager_->RemoveObserver(this); |
+ for (ItemMap::const_iterator iter = downloads_.begin(); |
+ iter != downloads_.end(); ++iter) { |
+ if (iter->second != NULL) |
+ iter->second->RemoveObserver(this); |
+ } |
+} |
+ |
+ExtensionDownloadsEventRouter::OnChangedStat::OnChangedStat() |
+ : fires(0), total(0) { |
+} |
+ |
+ExtensionDownloadsEventRouter::OnChangedStat::~OnChangedStat() { |
+ download_stats::RecordOnChanged(fires * 100 / total); |
+} |
+ |
+void ExtensionDownloadsEventRouter::OnDownloadUpdated(DownloadItem* item) { |
+ int download_id = item->GetId(); |
+ if (item->GetState() == DownloadItem::REMOVING) { |
+ // Remove item from downloads_, but keep the id in downloads_ so that we |
+ // notice its absence in ModelChanged() and fire an onErased. |
Randy Smith (Not in Mondays)
2012/01/15 18:47:13
Idea (i.e. the notch below "suggestion"; just some
benjhayden
2012/02/01 21:42:40
Done.
|
+ ItemMap::const_iterator it = downloads_.find(download_id); |
+ DCHECK(it != downloads_.end()); |
+ DCHECK(it->second == item); |
+ downloads_[download_id] = NULL; |
+ item->RemoveObserver(this); |
+ return; |
+ } |
+ base::DictionaryValue* current_json = item_jsons_[download_id]; |
+ scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON(item)); |
+ scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); |
+ delta->SetInteger(kIdKey, download_id); |
+ bool changed = false; |
+ for (base::DictionaryValue::key_iterator key = new_json->begin_keys(); |
+ key != new_json->end_keys(); ++key) { |
+ if (*key != kBytesReceivedKey) { |
+ base::Value* new_value = NULL; |
+ base::Value* old_value = NULL; |
+ if (new_json->Get(*key, &new_value) && |
Randy Smith (Not in Mondays)
2012/01/15 18:47:13
So this isn't performance critical code, but (:-})
benjhayden
2012/02/01 21:42:40
Done.
|
+ (!current_json->HasKey(*key) || |
+ (current_json->Get(*key, &old_value) && |
+ !new_value->Equals(old_value)))) { |
+ delta->Set(*key + ".old", (old_value ? old_value->DeepCopy() |
+ : base::Value::CreateNullValue())); |
+ delta->Set(*key + ".new", new_value->DeepCopy()); |
+ changed = true; |
+ } |
+ } |
+ } |
+ ++(on_changed_stats_[download_id]->total); |
+ if (changed) { |
+ DispatchEvent(extension_event_names::kOnDownloadChanged, delta.release()); |
+ ++(on_changed_stats_[download_id]->fires); |
+ } |
+ current_json->Swap(new_json.get()); |
+} |
+ |
+void ExtensionDownloadsEventRouter::OnDownloadOpened(DownloadItem* item) { |
} |
void ExtensionDownloadsEventRouter::ModelChanged() { |
@@ -699,7 +762,11 @@ void ExtensionDownloadsEventRouter::ModelChanged() { |
return; |
DownloadManager::DownloadVector current_vec; |
manager_->SearchDownloads(string16(), ¤t_vec); |
- DownloadIdSet current_set; |
+ DownloadIdSet current_set, prev_set; |
+ for (ItemMap::const_iterator iter = downloads_.begin(); |
+ iter != downloads_.end(); ++iter) { |
+ prev_set.insert(iter->first); |
+ } |
ItemMap current_map; |
for (DownloadManager::DownloadVector::const_iterator iter = |
current_vec.begin(); |
@@ -713,28 +780,36 @@ void ExtensionDownloadsEventRouter::ModelChanged() { |
current_set.insert(item_id); |
current_map[item_id] = item; |
} |
- DownloadIdSet new_set; // current_set - downloads_; |
- DownloadIdSet erased_set; // downloads_ - current_set; |
+ DownloadIdSet new_set; // current_set - prev_set; |
Randy Smith (Not in Mondays)
2012/01/15 18:47:13
semi-nit: I think this section would be clearer if
benjhayden
2012/02/01 21:42:40
erased_set isn't necessary now that the onErased i
|
+ DownloadIdSet erased_set; // prev_set - current_set; |
std::insert_iterator<DownloadIdSet> new_insertor(new_set, new_set.begin()); |
std::insert_iterator<DownloadIdSet> erased_insertor( |
erased_set, erased_set.begin()); |
std::set_difference(current_set.begin(), current_set.end(), |
- downloads_.begin(), downloads_.end(), |
+ prev_set.begin(), prev_set.end(), |
new_insertor); |
- std::set_difference(downloads_.begin(), downloads_.end(), |
+ std::set_difference(prev_set.begin(), prev_set.end(), |
current_set.begin(), current_set.end(), |
erased_insertor); |
for (DownloadIdSet::const_iterator iter = new_set.begin(); |
iter != new_set.end(); ++iter) { |
DispatchEvent(extension_event_names::kOnDownloadCreated, |
DownloadItemToJSON(current_map[*iter])); |
+ DCHECK(item_jsons_.find(*iter) == item_jsons_.end()); |
+ on_changed_stats_[*iter] = new OnChangedStat(); |
+ item_jsons_[*iter] = DownloadItemToJSON(current_map[*iter]); |
+ current_map[*iter]->AddObserver(this); |
} |
for (DownloadIdSet::const_iterator iter = erased_set.begin(); |
iter != erased_set.end(); ++iter) { |
DispatchEvent(extension_event_names::kOnDownloadErased, |
base::Value::CreateIntegerValue(*iter)); |
+ delete item_jsons_[*iter]; |
+ item_jsons_.erase(*iter); |
+ delete on_changed_stats_[*iter]; |
+ on_changed_stats_.erase(*iter); |
} |
- downloads_.swap(current_set); |
+ downloads_.swap(current_map); |
} |
void ExtensionDownloadsEventRouter::ManagerGoingDown() { |