Chromium Code Reviews| 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 cee9a906e683bdd2d2ea93b551bb565b29e7ab4b..35784d1c0f44d31e156e843e68614a236d6aca5b 100644 |
| --- a/chrome/browser/download/download_extension_api.cc |
| +++ b/chrome/browser/download/download_extension_api.cc |
| @@ -864,7 +864,9 @@ void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { |
| 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 |
| @@ -880,57 +882,116 @@ 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() { |
| + if (total > 0) |
| + UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", (fires * 100 / total)); |
| +} |
| + |
| +void ExtensionDownloadsEventRouter::OnDownloadUpdated(DownloadItem* item) { |
| + int download_id = item->GetId(); |
| + if (item->GetState() == DownloadItem::REMOVING) { |
|
Randy Smith (Not in Mondays)
2012/02/02 18:10:07
The code would be enhanced by a few comments indic
benjhayden
2012/02/02 20:40:38
Done.
|
| + downloads_.erase(download_id); |
| + item->RemoveObserver(this); |
| + DispatchEvent(extension_event_names::kOnDownloadErased, |
| + base::Value::CreateIntegerValue(download_id)); |
| + delete item_jsons_[download_id]; |
| + item_jsons_.erase(download_id); |
| + delete on_changed_stats_[download_id]; |
| + on_changed_stats_.erase(download_id); |
| + return; |
| + } |
| + |
| + base::DictionaryValue* old_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::Iterator iter(*new_json.get()); |
| + iter.HasNext(); iter.Advance()) { |
| + if (iter.key() != kBytesReceivedKey) { |
|
Randy Smith (Not in Mondays)
2012/02/02 18:10:07
My inclination would be to have changes in BytesRe
benjhayden
2012/02/02 20:40:38
API purity.
If I write an onChanged listener witho
|
| + base::Value* old_value = NULL; |
| + if (!old_json->HasKey(iter.key()) || |
| + (old_json->Get(iter.key(), &old_value) && |
| + !iter.value().Equals(old_value))) { |
|
Randy Smith (Not in Mondays)
2012/02/02 18:10:07
This looks like it'll leave out cases in which we'
benjhayden
2012/02/02 20:40:38
Good catch!
|
| + delta->Set(iter.key() + ".new", iter.value().DeepCopy()); |
| + if (old_value) |
| + delta->Set(iter.key() + ".old", old_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); |
| + } |
| + item_jsons_[download_id]->Swap(new_json.get()); |
| +} |
| + |
| +void ExtensionDownloadsEventRouter::OnDownloadOpened(DownloadItem* item) { |
| } |
| void ExtensionDownloadsEventRouter::ModelChanged() { |
|
Randy Smith (Not in Mondays)
2012/02/02 18:10:07
Again, I think just one or two comments would help
benjhayden
2012/02/02 20:40:38
Done.
|
| + typedef std::set<int> DownloadIdSet; |
| + |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (manager_ == NULL) |
| 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(); |
| iter != current_vec.end(); ++iter) { |
| DownloadItem* item = *iter; |
| int item_id = item->GetId(); |
| - // TODO(benjhayden): Remove the following line when every item's id >= 0, |
| - // which will allow firing onErased events for items from the history. |
| - if (item_id < 0) continue; |
| + CHECK(item_id >= 0); |
| DCHECK(current_map.find(item_id) == current_map.end()); |
| current_set.insert(item_id); |
| current_map[item_id] = item; |
| } |
| - DownloadIdSet new_set; // current_set - downloads_; |
| - DownloadIdSet erased_set; // downloads_ - current_set; |
| - std::insert_iterator<DownloadIdSet> new_insertor(new_set, new_set.begin()); |
| - std::insert_iterator<DownloadIdSet> erased_insertor( |
| - erased_set, erased_set.begin()); |
| + DownloadIdSet new_set; // current_set - prev_set; |
| std::set_difference(current_set.begin(), current_set.end(), |
| - downloads_.begin(), downloads_.end(), |
| - new_insertor); |
| - std::set_difference(downloads_.begin(), downloads_.end(), |
| - current_set.begin(), current_set.end(), |
| - erased_insertor); |
| + prev_set.begin(), prev_set.end(), |
| + std::insert_iterator<DownloadIdSet>( |
| + new_set, new_set.begin())); |
| for (DownloadIdSet::const_iterator iter = new_set.begin(); |
| iter != new_set.end(); ++iter) { |
| scoped_ptr<base::DictionaryValue> item( |
| DownloadItemToJSON(current_map[*iter])); |
| - DispatchEvent(extension_event_names::kOnDownloadCreated, item.release()); |
| - } |
| - for (DownloadIdSet::const_iterator iter = erased_set.begin(); |
| - iter != erased_set.end(); ++iter) { |
| - DispatchEvent(extension_event_names::kOnDownloadErased, |
| - base::Value::CreateIntegerValue(*iter)); |
| + DispatchEvent(extension_event_names::kOnDownloadCreated, item->DeepCopy()); |
|
Randy Smith (Not in Mondays)
2012/02/02 18:10:07
I think it's worthwhile having a comment in this r
benjhayden
2012/02/02 20:40:38
Done.
|
| + DCHECK(item_jsons_.find(*iter) == item_jsons_.end()); |
| + on_changed_stats_[*iter] = new OnChangedStat(); |
| + current_map[*iter]->AddObserver(this); |
| + item_jsons_[*iter] = item.release(); |
| } |
| - downloads_.swap(current_set); |
| + downloads_.swap(current_map); |
| } |
| void ExtensionDownloadsEventRouter::ManagerGoingDown() { |