| Index: ui/message_center/notification_list.cc
|
| diff --git a/ui/message_center/notification_list.cc b/ui/message_center/notification_list.cc
|
| index 677c24d5aa69dddd898a85eec6ffc61effdbe9cd..9fb848517b13b7b13f1ffef270a30bb3e79e62a6 100644
|
| --- a/ui/message_center/notification_list.cc
|
| +++ b/ui/message_center/notification_list.cc
|
| @@ -6,12 +6,35 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| +#include "base/stl_util.h"
|
| #include "base/time.h"
|
| #include "base/values.h"
|
| #include "ui/message_center/notification.h"
|
| +#include "ui/message_center/notification_types.h"
|
|
|
| namespace message_center {
|
|
|
| +bool ComparePriorityTimestampSerial::operator()(Notification* n1,
|
| + Notification* n2) {
|
| + if (n1->priority() > n2->priority()) // Higher pri go first.
|
| + return true;
|
| + if (n1->priority() < n2->priority())
|
| + return false;
|
| + return CompareTimestampSerial()(n1, n2);
|
| +}
|
| +
|
| +bool CompareTimestampSerial::operator()(Notification* n1, Notification* n2) {
|
| + if (n1->timestamp() > n2->timestamp()) // Newer come first.
|
| + return true;
|
| + if (n1->timestamp() < n2->timestamp())
|
| + return false;
|
| + if (n1->serial_number() > n2->serial_number()) // Newer come first.
|
| + return true;
|
| + if (n1->serial_number() < n2->serial_number())
|
| + return false;
|
| + return false;
|
| +}
|
| +
|
| const size_t NotificationList::kMaxVisibleMessageCenterNotifications = 100;
|
| const size_t NotificationList::kMaxVisiblePopupNotifications = 2;
|
|
|
| @@ -23,6 +46,7 @@ NotificationList::NotificationList(Delegate* delegate)
|
| }
|
|
|
| NotificationList::~NotificationList() {
|
| + STLDeleteContainerPointers(notifications_.begin(), notifications_.end());
|
| }
|
|
|
| void NotificationList::SetMessageCenterVisible(bool visible) {
|
| @@ -35,83 +59,27 @@ void NotificationList::SetMessageCenterVisible(bool visible) {
|
| if (!visible)
|
| unread_count_ = 0;
|
|
|
| - for (NotificationMap::iterator mapiter = notifications_.begin();
|
| - mapiter != notifications_.end(); ++mapiter) {
|
| - for (Notifications::iterator iter = mapiter->second.begin();
|
| - iter != mapiter->second.end(); ++iter) {
|
| - if (visible)
|
| - iter->shown_as_popup = true;
|
| - else
|
| - iter->is_read = true;
|
| - }
|
| + for (Notifications::iterator iter = notifications_.begin();
|
| + iter != notifications_.end(); ++iter) {
|
| + if (visible)
|
| + (*iter)->set_shown_as_popup(true);
|
| + else
|
| + (*iter)->set_is_read(true);
|
| }
|
| }
|
|
|
| void NotificationList::AddNotification(
|
| - ui::notifications::NotificationType type,
|
| + NotificationType type,
|
| const std::string& id,
|
| const string16& title,
|
| const string16& message,
|
| const string16& display_source,
|
| const std::string& extension_id,
|
| const DictionaryValue* optional_fields) {
|
| - Notification notification;
|
| - notification.type = type;
|
| - notification.id = id;
|
| - notification.title = title;
|
| - notification.message = message;
|
| - notification.display_source = display_source;
|
| - notification.extension_id = extension_id;
|
| -
|
| - // Initialize primitive fields before unpacking optional fields.
|
| - notification.priority = ui::notifications::DEFAULT_PRIORITY;
|
| -
|
| - UnpackOptionalFields(optional_fields, ¬ification);
|
| -
|
| - PushNotification(notification);
|
| -}
|
| -
|
| -void NotificationList::UnpackOptionalFields(const DictionaryValue* fields,
|
| - Notification* notification) {
|
| - if (!fields)
|
| - return;
|
| -
|
| - fields->GetInteger(ui::notifications::kPriorityKey, ¬ification->priority);
|
| - if (fields->HasKey(ui::notifications::kTimestampKey)) {
|
| - double time_double;
|
| - fields->GetDouble(ui::notifications::kTimestampKey, &time_double);
|
| - notification->timestamp = base::Time::FromJsTime(time_double);
|
| - }
|
| - if (fields->HasKey(ui::notifications::kButtonOneTitleKey) ||
|
| - fields->HasKey(ui::notifications::kButtonOneIconUrlKey)) {
|
| - string16 title;
|
| - string16 icon;
|
| - if (fields->GetString(ui::notifications::kButtonOneTitleKey, &title) ||
|
| - fields->GetString(ui::notifications::kButtonOneIconUrlKey, &icon)) {
|
| - notification->button_titles.push_back(title);
|
| - notification->button_icons.push_back(gfx::ImageSkia());
|
| - if (fields->GetString(ui::notifications::kButtonTwoTitleKey, &title) ||
|
| - fields->GetString(ui::notifications::kButtonTwoIconUrlKey, &icon)) {
|
| - notification->button_titles.push_back(title);
|
| - notification->button_icons.push_back(gfx::ImageSkia());
|
| - }
|
| - }
|
| - }
|
| - fields->GetString(ui::notifications::kExpandedMessageKey,
|
| - ¬ification->expanded_message);
|
| - if (fields->HasKey(ui::notifications::kItemsKey)) {
|
| - const ListValue* items;
|
| - CHECK(fields->GetList(ui::notifications::kItemsKey, &items));
|
| - for (size_t i = 0; i < items->GetSize(); ++i) {
|
| - string16 title;
|
| - string16 message;
|
| - const base::DictionaryValue* item;
|
| - items->GetDictionary(i, &item);
|
| - item->GetString(ui::notifications::kItemTitleKey, &title);
|
| - item->GetString(ui::notifications::kItemMessageKey, &message);
|
| - notification->items.push_back(NotificationItem(title, message));
|
| - }
|
| - }
|
| + scoped_ptr<Notification> notification(
|
| + new Notification(type, id, title, message, display_source, extension_id,
|
| + optional_fields));
|
| + PushNotification(notification.Pass());
|
| }
|
|
|
| void NotificationList::UpdateNotificationMessage(
|
| @@ -120,176 +88,159 @@ void NotificationList::UpdateNotificationMessage(
|
| const string16& title,
|
| const string16& message,
|
| const base::DictionaryValue* optional_fields) {
|
| - Notifications::iterator iter;
|
| - if (!GetNotification(old_id, &iter))
|
| + Notifications::iterator iter = GetNotification(old_id);
|
| + if (iter == notifications_.end())
|
| return;
|
| - // Copy and update notification, then move it to the front of the list.
|
| - Notification notification(*iter);
|
| - notification.id = new_id;
|
| - notification.title = title;
|
| - notification.message = message;
|
| - UnpackOptionalFields(optional_fields, ¬ification);
|
| +
|
| + // Copy and update a notification. It has an effect of setting a new timestamp
|
| + // if not overridden by optional_fields
|
| + scoped_ptr<Notification> notification(
|
| + new Notification((*iter)->type(),
|
| + new_id,
|
| + title,
|
| + message,
|
| + (*iter)->display_source(),
|
| + (*iter)->extension_id(),
|
| + optional_fields));
|
| EraseNotification(iter);
|
| - PushNotification(notification);
|
| + PushNotification(notification.Pass());
|
| }
|
|
|
| -bool NotificationList::RemoveNotification(const std::string& id) {
|
| - Notifications::iterator iter;
|
| - if (!GetNotification(id, &iter))
|
| - return false;
|
| - EraseNotification(iter);
|
| - return true;
|
| +void NotificationList::RemoveNotification(const std::string& id) {
|
| + EraseNotification(GetNotification(id));
|
| }
|
|
|
| void NotificationList::RemoveAllNotifications() {
|
| - notifications_.clear();
|
| + for (Notifications::iterator loopiter = notifications_.begin();
|
| + loopiter != notifications_.end(); ) {
|
| + Notifications::iterator curiter = loopiter++;
|
| + EraseNotification(curiter);
|
| + }
|
| unread_count_ = 0;
|
| }
|
|
|
| void NotificationList::SendRemoveNotificationsBySource(
|
| const std::string& id) {
|
| - Notifications::iterator source_iter;
|
| - if (!GetNotification(id, &source_iter))
|
| + Notifications::iterator source_iter = GetNotification(id);
|
| + if (source_iter == notifications_.end())
|
| return;
|
| - string16 display_source = source_iter->display_source;
|
| - for (NotificationMap::iterator mapiter = notifications_.begin();
|
| - mapiter != notifications_.end(); ++mapiter) {
|
| - for (Notifications::iterator loopiter = mapiter->second.begin();
|
| - loopiter != mapiter->second.end(); ) {
|
| - Notifications::iterator curiter = loopiter++;
|
| - if (curiter->display_source == display_source)
|
| - delegate_->SendRemoveNotification(curiter->id);
|
| - }
|
| + string16 display_source = (*source_iter)->display_source();
|
| +
|
| + for (Notifications::iterator loopiter = notifications_.begin();
|
| + loopiter != notifications_.end(); ) {
|
| + Notifications::iterator curiter = loopiter++;
|
| + if ((*curiter)->display_source() == display_source)
|
| + delegate_->SendRemoveNotification((*curiter)->id());
|
| }
|
| }
|
|
|
| void NotificationList::SendRemoveNotificationsByExtension(
|
| const std::string& id) {
|
| - Notifications::iterator source_iter;
|
| - if (!GetNotification(id, &source_iter))
|
| + Notifications::iterator source_iter = GetNotification(id);
|
| + if (source_iter == notifications_.end())
|
| return;
|
| - std::string extension_id = source_iter->extension_id;
|
| - for (NotificationMap::iterator mapiter = notifications_.begin();
|
| - mapiter != notifications_.end(); ++mapiter) {
|
| - for (Notifications::iterator loopiter = mapiter->second.begin();
|
| - loopiter != mapiter->second.end(); ) {
|
| - Notifications::iterator curiter = loopiter++;
|
| - if (curiter->extension_id == extension_id)
|
| - delegate_->SendRemoveNotification(curiter->id);
|
| - }
|
| + std::string extension_id = (*source_iter)->extension_id();
|
| + for (Notifications::iterator loopiter = notifications_.begin();
|
| + loopiter != notifications_.end(); ) {
|
| + Notifications::iterator curiter = loopiter++;
|
| + if ((*curiter)->extension_id() == extension_id)
|
| + delegate_->SendRemoveNotification((*curiter)->id());
|
| }
|
| }
|
|
|
| bool NotificationList::SetNotificationIcon(const std::string& notification_id,
|
| const gfx::ImageSkia& image) {
|
| - Notifications::iterator iter;
|
| - if (!GetNotification(notification_id, &iter))
|
| + Notifications::iterator iter = GetNotification(notification_id);
|
| + if (iter == notifications_.end())
|
| return false;
|
| - iter->primary_icon = image;
|
| + (*iter)->set_primary_icon(image);
|
| return true;
|
| }
|
|
|
| bool NotificationList::SetNotificationImage(const std::string& notification_id,
|
| const gfx::ImageSkia& image) {
|
| - Notifications::iterator iter;
|
| - if (!GetNotification(notification_id, &iter))
|
| + Notifications::iterator iter = GetNotification(notification_id);
|
| + if (iter == notifications_.end())
|
| return false;
|
| - iter->image = image;
|
| + (*iter)->set_image(image);
|
| return true;
|
| }
|
|
|
| bool NotificationList::SetNotificationButtonIcon(
|
| const std::string& notification_id, int button_index,
|
| const gfx::ImageSkia& image) {
|
| - Notifications::iterator iter;
|
| - if (!GetNotification(notification_id, &iter) ||
|
| - static_cast<size_t>(button_index) >= iter->button_icons.size())
|
| + Notifications::iterator iter = GetNotification(notification_id);
|
| + if (iter == notifications_.end())
|
| return false;
|
| - iter->button_icons[button_index] = image;
|
| - return true;
|
| + return (*iter)->SetButtonIcon(button_index, image);
|
| }
|
|
|
| bool NotificationList::HasNotification(const std::string& id) {
|
| - Notifications::iterator dummy;
|
| - return GetNotification(id, &dummy);
|
| + return GetNotification(id) != notifications_.end();
|
| }
|
|
|
| bool NotificationList::HasPopupNotifications() {
|
| - for (int i = ui::notifications::DEFAULT_PRIORITY;
|
| - i <= ui::notifications::MAX_PRIORITY; ++i) {
|
| - Notifications notifications = notifications_[i];
|
| - if (!notifications.empty() && !notifications.front().shown_as_popup)
|
| + for (Notifications::iterator iter = notifications_.begin();
|
| + iter != notifications_.end(); ++iter) {
|
| + if ((*iter)->priority() < DEFAULT_PRIORITY)
|
| + break;
|
| + if (!(*iter)->shown_as_popup())
|
| return true;
|
| }
|
| return false;
|
| }
|
|
|
| -void NotificationList::GetPopupNotifications(
|
| - NotificationList::Notifications* notifications) {
|
| - typedef std::pair<Notifications::iterator, Notifications::iterator>
|
| - NotificationRange;
|
| - // In the popup, latest should come earlier.
|
| - std::list<NotificationRange> iters;
|
| - for (int i = ui::notifications::DEFAULT_PRIORITY;
|
| - i <= ui::notifications::MAX_PRIORITY; ++i) {
|
| - Notifications::iterator first, last;
|
| - GetPopupIterators(i, &first, &last);
|
| - if (first != last)
|
| - iters.push_back(make_pair(first, last));
|
| - }
|
| - notifications->clear();
|
| - while (!iters.empty()) {
|
| - std::list<NotificationRange>::iterator max_iter = iters.begin();
|
| - std::list<NotificationRange>::iterator iter = max_iter;
|
| - iter++;
|
| - for (; iter != iters.end(); ++iter) {
|
| - if (max_iter->first->timestamp < iter->first->timestamp)
|
| - max_iter = iter;
|
| +NotificationList::PopupNotifications NotificationList::GetPopupNotifications() {
|
| + PopupNotifications result;
|
| + size_t default_priority_popup_count = 0;
|
| +
|
| + // Collect notifications that should be shown as popups. Start from oldest.
|
| + for (Notifications::const_reverse_iterator iter = notifications_.rbegin();
|
| + iter != notifications_.rend(); iter++) {
|
| +
|
| + if ((*iter)->shown_as_popup())
|
| + continue;
|
| +
|
| + // No popups for LOW/MIN priority.
|
| + if ((*iter)->priority() < DEFAULT_PRIORITY)
|
| + break;
|
| +
|
| + // Checking limits. No limits for HIGH/MAX priority. DEFAULT priority
|
| + // will return at most kMaxVisiblePopupNotifications entries. If the
|
| + // popup entries are more, older entries are used. see crbug.com/165768
|
| + if ((*iter)->priority() == DEFAULT_PRIORITY &&
|
| + default_priority_popup_count++ >= kMaxVisiblePopupNotifications) {
|
| + continue;
|
| }
|
| - notifications->push_back(*(max_iter->first));
|
| - ++(max_iter->first);
|
| - if (max_iter->first == max_iter->second)
|
| - iters.erase(max_iter);
|
| +
|
| + result.insert(*iter);
|
| }
|
| + return result;
|
| }
|
|
|
| void NotificationList::MarkPopupsAsShown(int priority) {
|
| - Notifications::iterator first, last;
|
| - GetPopupIterators(priority, &first, &last);
|
| - for (Notifications::iterator iter = first; iter != last; ++iter)
|
| - iter->shown_as_popup = true;
|
| + PopupNotifications popups = GetPopupNotifications();
|
| + for (PopupNotifications::iterator iter = popups.begin();
|
| + iter != popups.end(); ++iter) {
|
| + if ((*iter)->priority() == priority)
|
| + (*iter)->set_shown_as_popup(true);
|
| + }
|
| }
|
|
|
| void NotificationList::MarkSinglePopupAsShown(
|
| const std::string& id, bool mark_notification_as_read) {
|
| - Notifications::iterator iter;
|
| - if (!GetNotification(id, &iter))
|
| - return;
|
| + Notifications::iterator iter = GetNotification(id);
|
| + DCHECK(iter != notifications_.end());
|
|
|
| - if (iter->shown_as_popup)
|
| + if ((*iter)->shown_as_popup())
|
| return;
|
|
|
| - // Moves the item to the beginning of the already-shown items.
|
| - Notification notification = *iter;
|
| - notification.shown_as_popup = true;
|
| + (*iter)->set_shown_as_popup(true);
|
| +
|
| if (mark_notification_as_read) {
|
| --unread_count_;
|
| - notification.is_read = true;
|
| - }
|
| -
|
| - notifications_[notification.priority].erase(iter);
|
| - for (Notifications::iterator iter2 =
|
| - notifications_[notification.priority].begin();
|
| - iter2 != notifications_[notification.priority].end(); iter2++) {
|
| - if (iter2->shown_as_popup) {
|
| - notifications_[notification.priority].insert(iter2, notification);
|
| - return;
|
| - }
|
| + (*iter)->set_is_read(true);
|
| }
|
| -
|
| - // No notifications are already shown as popup, so just re-adding at the end
|
| - // of the list.
|
| - notifications_[notification.priority].push_back(notification);
|
| }
|
|
|
| void NotificationList::SetQuietMode(bool quiet_mode) {
|
| @@ -311,121 +262,64 @@ void NotificationList::EnterQuietModeWithExpire(
|
| }
|
| }
|
|
|
| -void NotificationList::GetNotifications(
|
| - NotificationList::Notifications* notifications) const {
|
| - DCHECK(notifications);
|
| - // Higher priority should come earlier.
|
| - for (NotificationMap::const_reverse_iterator mapiter =
|
| - notifications_.rbegin();
|
| - mapiter != notifications_.rend(); ++mapiter) {
|
| - for (Notifications::const_iterator iter = mapiter->second.begin();
|
| - iter != mapiter->second.end(); ++iter) {
|
| - notifications->push_back(*iter);
|
| - }
|
| - }
|
| +const NotificationList::Notifications& NotificationList::GetNotifications() {
|
| + return notifications_;
|
| }
|
|
|
| size_t NotificationList::NotificationCount() const {
|
| - size_t result = 0;
|
| - for (NotificationMap::const_iterator mapiter = notifications_.begin();
|
| - mapiter != notifications_.end(); ++mapiter) {
|
| - result += mapiter->second.size();
|
| - }
|
| - return result;
|
| + return notifications_.size();
|
| }
|
|
|
| void NotificationList::SetQuietModeInternal(bool quiet_mode) {
|
| quiet_mode_ = quiet_mode;
|
| if (quiet_mode_) {
|
| - for (NotificationMap::iterator mapiter = notifications_.begin();
|
| - mapiter != notifications_.end(); ++mapiter) {
|
| - for (Notifications::iterator iter = mapiter->second.begin();
|
| - iter != mapiter->second.end(); ++iter) {
|
| - iter->is_read = true;
|
| - iter->shown_as_popup = true;
|
| - }
|
| + for (Notifications::iterator iter = notifications_.begin();
|
| + iter != notifications_.end(); ++iter) {
|
| + (*iter)->set_is_read(true);
|
| + (*iter)->set_shown_as_popup(true);
|
| }
|
| unread_count_ = 0;
|
| }
|
| delegate_->OnQuietModeChanged(quiet_mode);
|
| }
|
|
|
| -bool NotificationList::GetNotification(
|
| - const std::string& id, Notifications::iterator* iter) {
|
| - for (NotificationMap::iterator mapiter = notifications_.begin();
|
| - mapiter != notifications_.end(); ++mapiter) {
|
| - for (Notifications::iterator curiter = mapiter->second.begin();
|
| - curiter != mapiter->second.end(); ++curiter) {
|
| - if (curiter->id == id) {
|
| - *iter = curiter;
|
| - return true;
|
| - }
|
| - }
|
| +NotificationList::Notifications::iterator
|
| + NotificationList::GetNotification(const std::string& id) {
|
| + for (Notifications::iterator iter = notifications_.begin();
|
| + iter != notifications_.end(); ++iter) {
|
| + if ((*iter)->id() == id)
|
| + return iter;
|
| }
|
| - return false;
|
| + return notifications_.end();
|
| }
|
|
|
| void NotificationList::EraseNotification(Notifications::iterator iter) {
|
| - if (!message_center_visible_ && !iter->is_read &&
|
| - iter->priority > ui::notifications::MIN_PRIORITY) {
|
| + if (!message_center_visible_ && !(*iter)->is_read() &&
|
| + (*iter)->priority() > MIN_PRIORITY) {
|
| --unread_count_;
|
| }
|
| - notifications_[iter->priority].erase(iter);
|
| + delete *iter;
|
| + notifications_.erase(iter);
|
| }
|
|
|
| -void NotificationList::PushNotification(Notification& notification) {
|
| +void NotificationList::PushNotification(scoped_ptr<Notification> notification) {
|
| // Ensure that notification.id is unique by erasing any existing
|
| // notification with the same id (shouldn't normally happen).
|
| - Notifications::iterator iter;
|
| - if (GetNotification(notification.id, &iter))
|
| + Notifications::iterator iter = GetNotification(notification->id());
|
| + if (iter != notifications_.end())
|
| EraseNotification(iter);
|
| - // Add the notification to the front (top) of the list and mark it
|
| - // unread and unshown.
|
| + // Add the notification to the the list and mark it unread and unshown.
|
| if (!message_center_visible_) {
|
| - if (quiet_mode_) {
|
| - // TODO(mukai): needs to distinguish if a notification is dismissed by
|
| - // the quiet mode or user operation.
|
| - notification.is_read = true;
|
| - notification.shown_as_popup = true;
|
| - } else {
|
| - if (notification.priority > ui::notifications::MIN_PRIORITY)
|
| + // TODO(mukai): needs to distinguish if a notification is dismissed by
|
| + // the quiet mode or user operation.
|
| + notification->set_is_read(quiet_mode_);
|
| + notification->set_shown_as_popup(quiet_mode_);
|
| + if (!quiet_mode_ && notification->priority() > MIN_PRIORITY)
|
| ++unread_count_;
|
| - notification.is_read = false;
|
| - notification.shown_as_popup = false;
|
| - }
|
| - }
|
| - notifications_[notification.priority].push_front(notification);
|
| -}
|
| -
|
| -void NotificationList::GetPopupIterators(int priority,
|
| - Notifications::iterator* first,
|
| - Notifications::iterator* last) {
|
| - Notifications& notifications = notifications_[priority];
|
| - // No popups for LOW/MIN priority.
|
| - if (priority < ui::notifications::DEFAULT_PRIORITY) {
|
| - *first = notifications.end();
|
| - *last = notifications.end();
|
| - return;
|
| - }
|
| -
|
| - size_t popup_count = 0;
|
| - *first = notifications.begin();
|
| - *last = *first;
|
| - while (*last != notifications.end()) {
|
| - if ((*last)->shown_as_popup)
|
| - break;
|
| - ++(*last);
|
| -
|
| - // Checking limits. No limits for HIGH/MAX priority. DEFAULT priority
|
| - // will return at most kMaxVisiblePopupNotifications entries. If the
|
| - // popup entries are more, older entries are used. see crbug.com/165768
|
| - if (priority == ui::notifications::DEFAULT_PRIORITY &&
|
| - popup_count >= kMaxVisiblePopupNotifications) {
|
| - ++(*first);
|
| - } else {
|
| - ++popup_count;
|
| - }
|
| }
|
| + // Take ownership. The notification can only be removed from the list
|
| + // in EraseNotification(), which will delete it.
|
| + notifications_.insert(notification.release());
|
| }
|
|
|
| } // namespace message_center
|
|
|