- add sources.
[platform/framework/web/crosswalk.git] / src / ui / message_center / notification_list.cc
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.
4
5 #include "ui/message_center/notification_list.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10 #include "base/time/time.h"
11 #include "base/values.h"
12 #include "ui/message_center/message_center_style.h"
13 #include "ui/message_center/notification.h"
14 #include "ui/message_center/notification_blocker.h"
15 #include "ui/message_center/notification_types.h"
16
17 namespace message_center {
18
19 namespace {
20
21 bool ShouldShowNotificationAsPopup(
22     const NotifierId& notifier_id,
23     const std::vector<NotificationBlocker*>& blockers) {
24   for (size_t i = 0; i < blockers.size(); ++i) {
25     if (!blockers[i]->ShouldShowNotificationAsPopup(notifier_id))
26       return false;
27   }
28   return true;
29 }
30
31 }  // namespace
32
33 bool ComparePriorityTimestampSerial::operator()(Notification* n1,
34                                                 Notification* n2) {
35   if (n1->priority() > n2->priority())  // Higher pri go first.
36     return true;
37   if (n1->priority() < n2->priority())
38     return false;
39   return CompareTimestampSerial()(n1, n2);
40 }
41
42 bool CompareTimestampSerial::operator()(Notification* n1, Notification* n2) {
43   if (n1->timestamp() > n2->timestamp())  // Newer come first.
44     return true;
45   if (n1->timestamp() < n2->timestamp())
46     return false;
47   if (n1->serial_number() > n2->serial_number())  // Newer come first.
48     return true;
49   if (n1->serial_number() < n2->serial_number())
50     return false;
51   return false;
52 }
53
54 NotificationList::NotificationList()
55     : message_center_visible_(false),
56       unread_count_(0),
57       quiet_mode_(false) {
58 }
59
60 NotificationList::~NotificationList() {
61   STLDeleteContainerPointers(notifications_.begin(), notifications_.end());
62 }
63
64 void NotificationList::SetMessageCenterVisible(
65     bool visible,
66     std::set<std::string>* updated_ids) {
67   if (message_center_visible_ == visible)
68     return;
69
70   message_center_visible_ = visible;
71
72   if (!visible)
73     return;
74
75   unread_count_ = 0;
76
77   for (Notifications::iterator iter = notifications_.begin();
78        iter != notifications_.end(); ++iter) {
79     Notification* notification = *iter;
80     if (notification->priority() < SYSTEM_PRIORITY)
81       notification->set_shown_as_popup(true);
82     notification->set_is_read(true);
83     if (updated_ids &&
84         !(notification->shown_as_popup() && notification->is_read())) {
85       updated_ids->insert(notification->id());
86     }
87   }
88 }
89
90 void NotificationList::AddNotification(scoped_ptr<Notification> notification) {
91   PushNotification(notification.Pass());
92 }
93
94 void NotificationList::UpdateNotificationMessage(
95     const std::string& old_id,
96     scoped_ptr<Notification> new_notification) {
97   Notifications::iterator iter = GetNotification(old_id);
98   if (iter == notifications_.end())
99     return;
100
101   new_notification->CopyState(*iter);
102
103   // Handles priority promotion. If the notification is already dismissed but
104   // the updated notification has higher priority, it should re-appear as a
105   // toast.
106   if ((*iter)->priority() < new_notification->priority()) {
107     new_notification->set_is_read(false);
108     new_notification->set_shown_as_popup(false);
109   }
110
111   // Do not use EraseNotification and PushNotification, since we don't want to
112   // change unread counts nor to update is_read/shown_as_popup states.
113   Notification* old = *iter;
114   notifications_.erase(iter);
115   delete old;
116
117   // We really don't want duplicate IDs.
118   DCHECK(GetNotification(new_notification->id()) == notifications_.end());
119   notifications_.insert(new_notification.release());
120 }
121
122 void NotificationList::RemoveNotification(const std::string& id) {
123   EraseNotification(GetNotification(id));
124 }
125
126 void NotificationList::RemoveAllNotifications() {
127   for (Notifications::iterator loopiter = notifications_.begin();
128        loopiter != notifications_.end(); ) {
129     Notifications::iterator curiter = loopiter++;
130     EraseNotification(curiter);
131   }
132   unread_count_ = 0;
133 }
134
135 NotificationList::Notifications NotificationList::GetNotificationsByNotifierId(
136         const NotifierId& notifier_id) {
137   Notifications notifications;
138   for (Notifications::iterator iter = notifications_.begin();
139        iter != notifications_.end(); ++iter) {
140     if ((*iter)->notifier_id() == notifier_id)
141       notifications.insert(*iter);
142   }
143   return notifications;
144 }
145
146 bool NotificationList::SetNotificationIcon(const std::string& notification_id,
147                                            const gfx::Image& image) {
148   Notifications::iterator iter = GetNotification(notification_id);
149   if (iter == notifications_.end())
150     return false;
151   (*iter)->set_icon(image);
152   return true;
153 }
154
155 bool NotificationList::SetNotificationImage(const std::string& notification_id,
156                                             const gfx::Image& image) {
157   Notifications::iterator iter = GetNotification(notification_id);
158   if (iter == notifications_.end())
159     return false;
160   (*iter)->set_image(image);
161   return true;
162 }
163
164 bool NotificationList::SetNotificationButtonIcon(
165     const std::string& notification_id, int button_index,
166     const gfx::Image& image) {
167   Notifications::iterator iter = GetNotification(notification_id);
168   if (iter == notifications_.end())
169     return false;
170   (*iter)->SetButtonIcon(button_index, image);
171   return true;
172 }
173
174 bool NotificationList::HasNotification(const std::string& id) {
175   return GetNotification(id) != notifications_.end();
176 }
177
178 bool NotificationList::HasNotificationOfType(const std::string& id,
179                                              const NotificationType type) {
180   Notifications::iterator iter = GetNotification(id);
181   if (iter == notifications_.end())
182     return false;
183
184   return (*iter)->type() == type;
185 }
186
187 bool NotificationList::HasPopupNotifications(
188     const std::vector<NotificationBlocker*>& blockers) {
189   for (Notifications::iterator iter = notifications_.begin();
190        iter != notifications_.end(); ++iter) {
191     if ((*iter)->priority() < DEFAULT_PRIORITY)
192       break;
193     if (!ShouldShowNotificationAsPopup((*iter)->notifier_id(), blockers))
194       continue;
195     if (!(*iter)->shown_as_popup())
196       return true;
197   }
198   return false;
199 }
200
201 NotificationList::PopupNotifications NotificationList::GetPopupNotifications(
202     const std::vector<NotificationBlocker*>& blockers,
203     std::list<std::string>* blocked_ids) {
204   PopupNotifications result;
205   size_t default_priority_popup_count = 0;
206
207   // Collect notifications that should be shown as popups. Start from oldest.
208   for (Notifications::const_reverse_iterator iter = notifications_.rbegin();
209        iter != notifications_.rend(); iter++) {
210     if ((*iter)->shown_as_popup())
211       continue;
212
213     // No popups for LOW/MIN priority.
214     if ((*iter)->priority() < DEFAULT_PRIORITY)
215       continue;
216
217     if (!ShouldShowNotificationAsPopup((*iter)->notifier_id(), blockers)) {
218       if (blocked_ids)
219         blocked_ids->push_back((*iter)->id());
220       continue;
221     }
222
223     // Checking limits. No limits for HIGH/MAX priority. DEFAULT priority
224     // will return at most kMaxVisiblePopupNotifications entries. If the
225     // popup entries are more, older entries are used. see crbug.com/165768
226     if ((*iter)->priority() == DEFAULT_PRIORITY &&
227         default_priority_popup_count++ >= kMaxVisiblePopupNotifications) {
228       continue;
229     }
230
231     result.insert(*iter);
232   }
233   return result;
234 }
235
236 void NotificationList::MarkSinglePopupAsShown(
237     const std::string& id, bool mark_notification_as_read) {
238   Notifications::iterator iter = GetNotification(id);
239   DCHECK(iter != notifications_.end());
240
241   if ((*iter)->shown_as_popup())
242     return;
243
244   // System notification is marked as shown only when marked as read.
245   if ((*iter)->priority() != SYSTEM_PRIORITY || mark_notification_as_read)
246     (*iter)->set_shown_as_popup(true);
247
248   // The popup notification is already marked as read when it's displayed.
249   // Set the is_read() back to false if necessary.
250   if (!mark_notification_as_read) {
251     (*iter)->set_is_read(false);
252     ++unread_count_;
253   }
254 }
255
256 void NotificationList::MarkSinglePopupAsDisplayed(const std::string& id) {
257   Notifications::iterator iter = GetNotification(id);
258   if (iter == notifications_.end())
259     return;
260
261   if ((*iter)->shown_as_popup())
262     return;
263
264   if (!(*iter)->is_read()) {
265     (*iter)->set_is_read(true);
266     --unread_count_;
267   }
268 }
269
270 void NotificationList::MarkNotificationAsExpanded(const std::string& id) {
271   Notifications::iterator iter = GetNotification(id);
272   if (iter != notifications_.end())
273     (*iter)->set_is_expanded(true);
274 }
275
276 NotificationDelegate* NotificationList::GetNotificationDelegate(
277     const std::string& id) {
278   Notifications::iterator iter = GetNotification(id);
279   if (iter == notifications_.end())
280     return NULL;
281   return (*iter)->delegate();
282 }
283
284 void NotificationList::SetQuietMode(bool quiet_mode) {
285   quiet_mode_ = quiet_mode;
286   if (quiet_mode_) {
287     for (Notifications::iterator iter = notifications_.begin();
288          iter != notifications_.end();
289          ++iter) {
290       (*iter)->set_shown_as_popup(true);
291     }
292   }
293 }
294
295 const NotificationList::Notifications& NotificationList::GetNotifications() {
296   return notifications_;
297 }
298
299 size_t NotificationList::NotificationCount() const {
300   return notifications_.size();
301 }
302
303 NotificationList::Notifications::iterator NotificationList::GetNotification(
304     const std::string& id) {
305   for (Notifications::iterator iter = notifications_.begin();
306        iter != notifications_.end(); ++iter) {
307     if ((*iter)->id() == id)
308       return iter;
309   }
310   return notifications_.end();
311 }
312
313 void NotificationList::EraseNotification(Notifications::iterator iter) {
314   if (!(*iter)->is_read() && (*iter)->priority() > MIN_PRIORITY)
315     --unread_count_;
316   delete *iter;
317   notifications_.erase(iter);
318 }
319
320 void NotificationList::PushNotification(scoped_ptr<Notification> notification) {
321   // Ensure that notification.id is unique by erasing any existing
322   // notification with the same id (shouldn't normally happen).
323   Notifications::iterator iter = GetNotification(notification->id());
324   bool state_inherited = false;
325   if (iter != notifications_.end()) {
326     notification->CopyState(*iter);
327     state_inherited = true;
328     EraseNotification(iter);
329     // if |iter| is unread, EraseNotification decrements |unread_count_| but
330     // actually the count is unchanged since |notification| will be added.
331     if (!notification->is_read())
332       ++unread_count_;
333   }
334   // Add the notification to the the list and mark it unread and unshown.
335   if (!state_inherited) {
336     // TODO(mukai): needs to distinguish if a notification is dismissed by
337     // the quiet mode or user operation.
338     notification->set_is_read(false);
339     notification->set_shown_as_popup(message_center_visible_
340                                      || quiet_mode_
341                                      || notification->shown_as_popup());
342     if (notification->priority() > MIN_PRIORITY)
343       ++unread_count_;
344   }
345   // Take ownership. The notification can only be removed from the list
346   // in EraseNotification(), which will delete it.
347   notifications_.insert(notification.release());
348 }
349
350 }  // namespace message_center