Mailbox support for texture layers.
[chromium-blink-merge.git] / ui / message_center / notification_list.cc
blobd92051a7ee1510a71dcd22d180636800d94637f7
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/message_center/notification_list.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/time.h"
10 #include "base/values.h"
12 namespace message_center {
14 const size_t NotificationList::kMaxVisibleMessageCenterNotifications = 100;
15 const size_t NotificationList::kMaxVisiblePopupNotifications = 2;
17 NotificationList::Notification::Notification() : is_read(false),
18 shown_as_popup(false) {
21 NotificationList::Notification::~Notification() {
24 NotificationList::NotificationList(Delegate* delegate)
25 : delegate_(delegate),
26 message_center_visible_(false),
27 unread_count_(0),
28 quiet_mode_(false) {
31 NotificationList::~NotificationList() {
34 void NotificationList::SetMessageCenterVisible(bool visible) {
35 if (message_center_visible_ == visible)
36 return;
37 message_center_visible_ = visible;
38 if (!visible) {
39 // When the list is hidden, clear the unread count, and mark all
40 // notifications as read and shown.
41 unread_count_ = 0;
42 for (NotificationMap::iterator mapiter = notifications_.begin();
43 mapiter != notifications_.end(); ++mapiter) {
44 for (Notifications::iterator iter = mapiter->second.begin();
45 iter != mapiter->second.end(); ++iter) {
46 iter->is_read = true;
47 iter->shown_as_popup = true;
53 void NotificationList::AddNotification(
54 ui::notifications::NotificationType type,
55 const std::string& id,
56 const string16& title,
57 const string16& message,
58 const string16& display_source,
59 const std::string& extension_id,
60 const DictionaryValue* optional_fields) {
61 Notification notification;
62 notification.type = type;
63 notification.id = id;
64 notification.title = title;
65 notification.message = message;
66 notification.display_source = display_source;
67 notification.extension_id = extension_id;
69 // Initialize primitive fields before unpacking optional fields.
70 // timestamp initializes to default NULL time.
71 notification.priority = ui::notifications::DEFAULT_PRIORITY;
72 notification.unread_count = 0;
74 UnpackOptionalFields(optional_fields, &notification);
76 PushNotification(notification);
79 void NotificationList::UnpackOptionalFields(
80 const DictionaryValue* optional_fields, Notification* notification) {
81 if (!optional_fields)
82 return;
84 if (optional_fields->HasKey(ui::notifications::kPriorityKey))
85 optional_fields->GetInteger(ui::notifications::kPriorityKey,
86 &notification->priority);
87 if (optional_fields->HasKey(ui::notifications::kTimestampKey)) {
88 std::string time_string;
89 optional_fields->GetString(ui::notifications::kTimestampKey, &time_string);
90 base::Time::FromString(time_string.c_str(), &notification->timestamp);
92 if (optional_fields->HasKey(ui::notifications::kUnreadCountKey))
93 optional_fields->GetInteger(ui::notifications::kUnreadCountKey,
94 &notification->unread_count);
95 if (optional_fields->HasKey(ui::notifications::kButtonOneTitleKey))
96 optional_fields->GetString(ui::notifications::kButtonOneTitleKey,
97 &notification->button_one_title);
98 if (optional_fields->HasKey(ui::notifications::kButtonTwoTitleKey))
99 optional_fields->GetString(ui::notifications::kButtonTwoTitleKey,
100 &notification->button_two_title);
101 if (optional_fields->HasKey(ui::notifications::kExpandedMessageKey))
102 optional_fields->GetString(ui::notifications::kExpandedMessageKey,
103 &notification->expanded_message);
104 if (optional_fields->HasKey(ui::notifications::kItemsKey)) {
105 const ListValue* items;
106 CHECK(optional_fields->GetList(ui::notifications::kItemsKey, &items));
107 for (size_t i = 0; i < items->GetSize(); ++i) {
108 string16 title;
109 string16 message;
110 const base::DictionaryValue* item;
111 items->GetDictionary(i, &item);
112 item->GetString(ui::notifications::kItemTitleKey, &title);
113 item->GetString(ui::notifications::kItemMessageKey, &message);
114 notification->items.push_back(NotificationItem(title, message));
119 void NotificationList::UpdateNotificationMessage(
120 const std::string& old_id,
121 const std::string& new_id,
122 const string16& title,
123 const string16& message,
124 const base::DictionaryValue* optional_fields) {
125 Notifications::iterator iter;
126 if (!GetNotification(old_id, &iter))
127 return;
128 // Copy and update notification, then move it to the front of the list.
129 Notification notification(*iter);
130 notification.id = new_id;
131 notification.title = title;
132 notification.message = message;
133 UnpackOptionalFields(optional_fields, &notification);
134 EraseNotification(iter);
135 PushNotification(notification);
138 bool NotificationList::RemoveNotification(const std::string& id) {
139 Notifications::iterator iter;
140 if (!GetNotification(id, &iter))
141 return false;
142 EraseNotification(iter);
143 return true;
146 void NotificationList::RemoveAllNotifications() {
147 notifications_.clear();
148 unread_count_ = 0;
151 void NotificationList::SendRemoveNotificationsBySource(
152 const std::string& id) {
153 Notifications::iterator source_iter;
154 if (!GetNotification(id, &source_iter))
155 return;
156 string16 display_source = source_iter->display_source;
157 for (NotificationMap::iterator mapiter = notifications_.begin();
158 mapiter != notifications_.end(); ++mapiter) {
159 for (Notifications::iterator loopiter = mapiter->second.begin();
160 loopiter != mapiter->second.end(); ) {
161 Notifications::iterator curiter = loopiter++;
162 if (curiter->display_source == display_source)
163 delegate_->SendRemoveNotification(curiter->id);
168 void NotificationList::SendRemoveNotificationsByExtension(
169 const std::string& id) {
170 Notifications::iterator source_iter;
171 if (!GetNotification(id, &source_iter))
172 return;
173 std::string extension_id = source_iter->extension_id;
174 for (NotificationMap::iterator mapiter = notifications_.begin();
175 mapiter != notifications_.end(); ++mapiter) {
176 for (Notifications::iterator loopiter = mapiter->second.begin();
177 loopiter != mapiter->second.end(); ) {
178 Notifications::iterator curiter = loopiter++;
179 if (curiter->extension_id == extension_id)
180 delegate_->SendRemoveNotification(curiter->id);
185 bool NotificationList::SetNotificationPrimaryIcon(const std::string& id,
186 const gfx::ImageSkia& image) {
187 Notifications::iterator iter;
188 if (!GetNotification(id, &iter))
189 return false;
190 iter->primary_icon = image;
191 return true;
194 bool NotificationList::SetNotificationSecondaryIcon(
195 const std::string& id,
196 const gfx::ImageSkia& image) {
197 Notifications::iterator iter;
198 if (!GetNotification(id, &iter))
199 return false;
200 iter->secondary_icon = image;
201 return true;
204 bool NotificationList::SetNotificationImage(const std::string& id,
205 const gfx::ImageSkia& image) {
206 Notifications::iterator iter;
207 if (!GetNotification(id, &iter))
208 return false;
209 iter->image = image;
210 return true;
213 bool NotificationList::HasNotification(const std::string& id) {
214 Notifications::iterator dummy;
215 return GetNotification(id, &dummy);
218 bool NotificationList::HasPopupNotifications() {
219 for (int i = ui::notifications::DEFAULT_PRIORITY;
220 i <= ui::notifications::MAX_PRIORITY; ++i) {
221 Notifications notifications = notifications_[i];
222 if (!notifications.empty() && !notifications.front().shown_as_popup)
223 return true;
225 return false;
228 void NotificationList::GetPopupNotifications(
229 NotificationList::Notifications* notifications) {
230 typedef std::pair<Notifications::iterator, Notifications::iterator>
231 NotificationRange;
232 // In the popup, latest should come earlier.
233 std::list<NotificationRange> iters;
234 for (int i = ui::notifications::DEFAULT_PRIORITY;
235 i <= ui::notifications::MAX_PRIORITY; ++i) {
236 Notifications::iterator first, last;
237 GetPopupIterators(i, first, last);
238 if (first != last)
239 iters.push_back(make_pair(first, last));
241 notifications->clear();
242 while (!iters.empty()) {
243 std::list<NotificationRange>::iterator max_iter = iters.begin();
244 std::list<NotificationRange>::iterator iter = max_iter;
245 iter++;
246 for (; iter != iters.end(); ++iter) {
247 if (max_iter->first->timestamp < iter->first->timestamp)
248 max_iter = iter;
250 notifications->push_back(*(max_iter->first));
251 ++(max_iter->first);
252 if (max_iter->first == max_iter->second)
253 iters.erase(max_iter);
257 void NotificationList::MarkPopupsAsShown(int priority) {
258 Notifications::iterator first, last;
259 GetPopupIterators(priority, first, last);
260 for (Notifications::iterator iter = first; iter != last; ++iter)
261 iter->shown_as_popup = true;
264 void NotificationList::SetQuietMode(bool quiet_mode) {
265 SetQuietModeInternal(quiet_mode);
266 quiet_mode_timer_.reset();
269 void NotificationList::EnterQuietModeWithExpire(
270 const base::TimeDelta& expires_in) {
271 if (quiet_mode_timer_.get()) {
272 // Note that the capital Reset() is the method to restart the timer, not
273 // scoped_ptr::reset().
274 quiet_mode_timer_->Reset();
275 } else {
276 SetQuietModeInternal(true);
277 quiet_mode_timer_.reset(new base::OneShotTimer<NotificationList>);
278 quiet_mode_timer_->Start(FROM_HERE, expires_in, base::Bind(
279 &NotificationList::SetQuietMode, base::Unretained(this), false));
283 void NotificationList::GetNotifications(
284 NotificationList::Notifications* notifications) const {
285 DCHECK(notifications);
286 // Higher priority should come earlier.
287 for (NotificationMap::const_reverse_iterator mapiter =
288 notifications_.rbegin();
289 mapiter != notifications_.rend(); ++mapiter) {
290 for (Notifications::const_iterator iter = mapiter->second.begin();
291 iter != mapiter->second.end(); ++iter) {
292 notifications->push_back(*iter);
297 size_t NotificationList::NotificationCount() const {
298 size_t result = 0;
299 for (NotificationMap::const_iterator mapiter = notifications_.begin();
300 mapiter != notifications_.end(); ++mapiter) {
301 result += mapiter->second.size();
303 return result;
306 void NotificationList::SetQuietModeInternal(bool quiet_mode) {
307 quiet_mode_ = quiet_mode;
308 if (quiet_mode_) {
309 for (NotificationMap::iterator mapiter = notifications_.begin();
310 mapiter != notifications_.end(); ++mapiter) {
311 for (Notifications::iterator iter = mapiter->second.begin();
312 iter != mapiter->second.end(); ++iter) {
313 iter->is_read = true;
314 iter->shown_as_popup = true;
317 unread_count_ = 0;
319 delegate_->OnQuietModeChanged(quiet_mode);
322 bool NotificationList::GetNotification(
323 const std::string& id, Notifications::iterator* iter) {
324 for (NotificationMap::iterator mapiter = notifications_.begin();
325 mapiter != notifications_.end(); ++mapiter) {
326 for (Notifications::iterator curiter = mapiter->second.begin();
327 curiter != mapiter->second.end(); ++curiter) {
328 if (curiter->id == id) {
329 *iter = curiter;
330 return true;
334 return false;
337 void NotificationList::EraseNotification(Notifications::iterator iter) {
338 if (!message_center_visible_ && !iter->is_read &&
339 iter->priority > ui::notifications::MIN_PRIORITY) {
340 --unread_count_;
342 notifications_[iter->priority].erase(iter);
345 void NotificationList::PushNotification(Notification& notification) {
346 // Ensure that notification.id is unique by erasing any existing
347 // notification with the same id (shouldn't normally happen).
348 Notifications::iterator iter;
349 if (GetNotification(notification.id, &iter))
350 EraseNotification(iter);
351 // Add the notification to the front (top) of the list and mark it
352 // unread and unshown.
353 if (!message_center_visible_) {
354 if (quiet_mode_) {
355 // TODO(mukai): needs to distinguish if a notification is dismissed by
356 // the quiet mode or user operation.
357 notification.is_read = true;
358 notification.shown_as_popup = true;
359 } else {
360 if (notification.priority > ui::notifications::MIN_PRIORITY)
361 ++unread_count_;
362 notification.is_read = false;
363 notification.shown_as_popup = false;
366 notifications_[notification.priority].push_front(notification);
369 void NotificationList::GetPopupIterators(int priority,
370 Notifications::iterator& first,
371 Notifications::iterator& last) {
372 Notifications& notifications = notifications_[priority];
373 // No popups for LOW/MIN priority.
374 if (priority < ui::notifications::DEFAULT_PRIORITY) {
375 first = notifications.end();
376 last = notifications.end();
377 return;
380 size_t popup_count = 0;
381 first = notifications.begin();
382 last = first;
383 while (last != notifications.end()) {
384 if (last->shown_as_popup)
385 break;
386 ++last;
387 popup_count++;
388 // No limits for HIGH/MAX priority.
389 if (priority == ui::notifications::DEFAULT_PRIORITY &&
390 popup_count >= kMaxVisiblePopupNotifications) {
391 break;
396 } // namespace message_center