notification_ui_manager.cc revision 201ade2fbba22bfb27ae029f4d23fca6ded109a0
1// Copyright (c) 2010 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 "chrome/browser/notifications/notification_ui_manager.h"
6
7#include "base/logging.h"
8#include "base/scoped_ptr.h"
9#include "base/stl_util-inl.h"
10#include "chrome/browser/notifications/balloon_collection.h"
11#include "chrome/browser/notifications/notification.h"
12#include "chrome/browser/renderer_host/site_instance.h"
13#include "chrome/common/notification_service.h"
14#include "chrome/common/notification_type.h"
15
16// A class which represents a notification waiting to be shown.
17class QueuedNotification {
18 public:
19  QueuedNotification(const Notification& notification, Profile* profile)
20      : notification_(notification),
21        profile_(profile) {
22  }
23
24  const Notification& notification() const { return notification_; }
25  Profile* profile() const { return profile_; }
26
27  void Replace(const Notification& new_notification) {
28    notification_ = new_notification;
29  }
30
31 private:
32  // The notification to be shown.
33  Notification notification_;
34
35  // Non owned pointer to the user's profile.
36  Profile* profile_;
37
38  DISALLOW_COPY_AND_ASSIGN(QueuedNotification);
39};
40
41NotificationUIManager::NotificationUIManager()
42    : balloon_collection_(NULL) {
43  registrar_.Add(this, NotificationType::APP_TERMINATING,
44                 NotificationService::AllSources());
45}
46
47NotificationUIManager::~NotificationUIManager() {
48  STLDeleteElements(&show_queue_);
49}
50
51// static
52NotificationUIManager* NotificationUIManager::Create() {
53  BalloonCollection* balloons = BalloonCollection::Create();
54  NotificationUIManager* instance = new NotificationUIManager();
55  instance->Initialize(balloons);
56  balloons->set_space_change_listener(instance);
57  return instance;
58}
59
60void NotificationUIManager::Add(const Notification& notification,
61                                Profile* profile) {
62  if (TryReplacement(notification)) {
63    return;
64  }
65
66  VLOG(1) << "Added notification. URL: "
67          << notification.content_url().spec();
68  show_queue_.push_back(
69      new QueuedNotification(notification, profile));
70  CheckAndShowNotifications();
71}
72
73bool NotificationUIManager::CancelById(const std::string& id) {
74  // See if this ID hasn't been shown yet.
75  NotificationDeque::iterator iter;
76  for (iter = show_queue_.begin(); iter != show_queue_.end(); ++iter) {
77    if ((*iter)->notification().notification_id() == id) {
78      show_queue_.erase(iter);
79      return true;
80    }
81  }
82  // If it has been shown, remove it from the balloon collections.
83  return balloon_collection_->RemoveById(id);
84}
85
86bool NotificationUIManager::CancelAllBySourceOrigin(const GURL& source) {
87  // Same pattern as CancelById, but more complicated than the above
88  // because there may be multiple notifications from the same source.
89  bool removed = false;
90  NotificationDeque::iterator iter;
91  for (iter = show_queue_.begin(); iter != show_queue_.end();) {
92    if ((*iter)->notification().origin_url() == source) {
93      iter = show_queue_.erase(iter);
94      removed = true;
95    } else {
96      ++iter;
97    }
98  }
99
100  return balloon_collection_->RemoveBySourceOrigin(source) || removed;
101}
102
103void NotificationUIManager::CancelAll() {
104  STLDeleteElements(&show_queue_);
105  balloon_collection_->RemoveAll();
106}
107
108void NotificationUIManager::CheckAndShowNotifications() {
109  // TODO(johnnyg): http://crbug.com/25061 - Check for user idle/presentation.
110  ShowNotifications();
111}
112
113void NotificationUIManager::ShowNotifications() {
114  while (!show_queue_.empty() && balloon_collection_->HasSpace()) {
115    scoped_ptr<QueuedNotification> queued_notification(show_queue_.front());
116    show_queue_.pop_front();
117    balloon_collection_->Add(queued_notification->notification(),
118                             queued_notification->profile());
119  }
120}
121
122void NotificationUIManager::OnBalloonSpaceChanged() {
123  CheckAndShowNotifications();
124}
125
126bool NotificationUIManager::TryReplacement(const Notification& notification) {
127  const GURL& origin = notification.origin_url();
128  const string16& replace_id = notification.replace_id();
129
130  if (replace_id.empty())
131    return false;
132
133  // First check the queue of pending notifications for replacement.
134  // Then check the list of notifications already being shown.
135  NotificationDeque::iterator iter;
136  for (iter = show_queue_.begin(); iter != show_queue_.end(); ++iter) {
137    if (origin == (*iter)->notification().origin_url() &&
138        replace_id == (*iter)->notification().replace_id()) {
139      (*iter)->Replace(notification);
140      return true;
141    }
142  }
143
144  BalloonCollection::Balloons::iterator balloon_iter;
145  BalloonCollection::Balloons balloons =
146      balloon_collection_->GetActiveBalloons();
147  for (balloon_iter = balloons.begin();
148       balloon_iter != balloons.end();
149       ++balloon_iter) {
150    if (origin == (*balloon_iter)->notification().origin_url() &&
151        replace_id == (*balloon_iter)->notification().replace_id()) {
152      (*balloon_iter)->Update(notification);
153      return true;
154    }
155  }
156
157  return false;
158}
159
160void NotificationUIManager::Observe(NotificationType type,
161                                    const NotificationSource& source,
162                                    const NotificationDetails& details) {
163  if (type == NotificationType::APP_TERMINATING)
164    CancelAll();
165  else
166    NOTREACHED();
167}
168