Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / ui / message_center / views / message_popup_bubble.cc
blobe5f6cdf63a909b287ba95e33cee3e3c5abd5e924
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/views/message_popup_bubble.h"
7 #include "base/bind.h"
8 #include "base/stl_util.h"
9 #include "ui/message_center/message_center_constants.h"
10 #include "ui/message_center/notification.h"
11 #include "ui/message_center/notification_change_observer.h"
12 #include "ui/message_center/notification_types.h"
13 #include "ui/message_center/views/message_view.h"
14 #include "ui/message_center/views/notification_view.h"
15 #include "ui/views/bubble/tray_bubble_view.h"
16 #include "ui/views/layout/box_layout.h"
17 #include "ui/views/view.h"
18 #include "ui/views/widget/widget.h"
20 namespace message_center {
22 // Popup notifications contents.
23 class PopupBubbleContentsView : public views::View {
24 public:
25 explicit PopupBubbleContentsView(NotificationChangeObserver* observer);
27 void Update(const NotificationList::PopupNotifications& popup_notifications);
29 size_t NumMessageViews() const {
30 return content_->child_count();
33 private:
34 NotificationChangeObserver* observer_; // Weak reference.
35 views::View* content_;
37 DISALLOW_COPY_AND_ASSIGN(PopupBubbleContentsView);
40 PopupBubbleContentsView::PopupBubbleContentsView(
41 NotificationChangeObserver* observer)
42 : observer_(observer) {
43 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
45 content_ = new views::View;
46 content_->SetLayoutManager(
47 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
48 AddChildView(content_);
50 if (get_use_acceleration_when_possible()) {
51 content_->SetPaintToLayer(true);
52 content_->SetFillsBoundsOpaquely(false);
53 content_->layer()->SetMasksToBounds(true);
57 void PopupBubbleContentsView::Update(
58 const NotificationList::PopupNotifications& popup_notifications) {
59 content_->RemoveAllChildViews(true);
60 for (NotificationList::PopupNotifications::const_iterator iter =
61 popup_notifications.begin();
62 iter != popup_notifications.end(); ++iter) {
63 // NotificationViews are expanded by default here because MessagePopupBubble
64 // hasn't been tested yet with changing subview sizes, and such changes
65 // could come if those subviews were initially collapsed and allowed to be
66 // expanded by users. TODO(dharcourt): Fix.
67 content_->AddChildView(NotificationView::Create(*(*iter), observer_, true));
69 content_->SizeToPreferredSize();
70 content_->InvalidateLayout();
71 Layout();
72 if (GetWidget())
73 GetWidget()->GetRootView()->SchedulePaint();
76 // The timer to call OnAutoClose for |notification|.
77 class MessagePopupBubble::AutocloseTimer {
78 public:
79 AutocloseTimer(Notification* notification, MessagePopupBubble* bubble);
81 void Start();
82 void Restart();
83 void Suspend();
85 private:
86 const std::string id_;
87 base::TimeDelta delay_;
88 base::Time start_time_;
89 MessagePopupBubble* bubble_;
90 base::OneShotTimer<MessagePopupBubble> timer_;
92 DISALLOW_COPY_AND_ASSIGN(AutocloseTimer);
95 MessagePopupBubble::AutocloseTimer::AutocloseTimer(
96 Notification* notification,
97 MessagePopupBubble* bubble)
98 : id_(notification->id()),
99 bubble_(bubble) {
100 int seconds = kAutocloseDefaultDelaySeconds;
101 if (notification->priority() > DEFAULT_PRIORITY)
102 seconds = kAutocloseHighPriorityDelaySeconds;
103 delay_ = base::TimeDelta::FromSeconds(seconds);
106 void MessagePopupBubble::AutocloseTimer::Start() {
107 start_time_ = base::Time::Now();
108 timer_.Start(FROM_HERE,
109 delay_,
110 base::Bind(&MessagePopupBubble::OnAutoClose,
111 base::Unretained(bubble_), id_));
114 void MessagePopupBubble::AutocloseTimer::Restart() {
115 delay_ -= base::Time::Now() - start_time_;
116 if (delay_ < base::TimeDelta())
117 bubble_->OnAutoClose(id_);
118 else
119 Start();
122 void MessagePopupBubble::AutocloseTimer::Suspend() {
123 timer_.Stop();
126 // MessagePopupBubble
127 MessagePopupBubble::MessagePopupBubble(MessageCenter* message_center)
128 : MessageBubbleBase(message_center),
129 contents_view_(NULL) {
132 MessagePopupBubble::~MessagePopupBubble() {
133 STLDeleteContainerPairSecondPointers(autoclose_timers_.begin(),
134 autoclose_timers_.end());
137 views::TrayBubbleView::InitParams MessagePopupBubble::GetInitParams(
138 views::TrayBubbleView::AnchorAlignment anchor_alignment) {
139 views::TrayBubbleView::InitParams init_params =
140 GetDefaultInitParams(anchor_alignment);
141 init_params.arrow_color = kBackgroundColor;
142 init_params.close_on_deactivate = false;
143 return init_params;
146 void MessagePopupBubble::InitializeContents(
147 views::TrayBubbleView* new_bubble_view) {
148 set_bubble_view(new_bubble_view);
149 contents_view_ = new PopupBubbleContentsView(message_center());
150 bubble_view()->AddChildView(contents_view_);
151 bubble_view()->set_notify_enter_exit_on_child(true);
152 UpdateBubbleView();
155 void MessagePopupBubble::OnBubbleViewDestroyed() {
156 contents_view_ = NULL;
159 void MessagePopupBubble::UpdateBubbleView() {
160 NotificationList::PopupNotifications popups =
161 message_center()->notification_list()->GetPopupNotifications();
163 if (popups.size() == 0) {
164 if (bubble_view())
165 bubble_view()->delegate()->HideBubble(bubble_view()); // deletes |this|
166 return;
169 contents_view_->Update(popups);
170 bubble_view()->GetWidget()->Show();
171 bubble_view()->UpdateBubble();
173 std::set<std::string> old_popup_ids;
174 old_popup_ids.swap(popup_ids_);
176 // Start autoclose timers.
177 for (NotificationList::PopupNotifications::const_iterator iter =
178 popups.begin();
179 iter != popups.end(); ++iter) {
180 std::string id = (*iter)->id();
181 std::map<std::string, AutocloseTimer*>::const_iterator timer_iter =
182 autoclose_timers_.find(id);
183 if (timer_iter == autoclose_timers_.end()) {
184 AutocloseTimer *timer = new AutocloseTimer(*iter, this);
185 autoclose_timers_[id] = timer;
186 timer->Start();
188 popup_ids_.insert(id);
189 old_popup_ids.erase(id);
192 // Stops timers whose notifications are gone.
193 for (std::set<std::string>::const_iterator iter = old_popup_ids.begin();
194 iter != old_popup_ids.end(); ++iter) {
195 DeleteTimer(*iter);
199 void MessagePopupBubble::OnMouseEnteredView() {
200 for (std::map<std::string, AutocloseTimer*>::iterator iter =
201 autoclose_timers_.begin(); iter != autoclose_timers_.end(); ++iter) {
202 iter->second->Suspend();
206 void MessagePopupBubble::OnMouseExitedView() {
207 for (std::map<std::string, AutocloseTimer*>::iterator iter =
208 autoclose_timers_.begin(); iter != autoclose_timers_.end();) {
209 // |iter| can be deleted if timer is already over.
210 AutocloseTimer* timer = iter->second;
211 ++iter;
212 timer->Restart();
216 void MessagePopupBubble::OnAutoClose(const std::string& id) {
217 message_center()->notification_list()->MarkSinglePopupAsShown(id, false);
218 DeleteTimer(id);
219 UpdateBubbleView();
222 void MessagePopupBubble::DeleteTimer(const std::string& id) {
223 std::map<std::string, AutocloseTimer*>::iterator iter =
224 autoclose_timers_.find(id);
225 if (iter != autoclose_timers_.end()) {
226 scoped_ptr<AutocloseTimer> release_timer(iter->second);
227 autoclose_timers_.erase(iter);
231 size_t MessagePopupBubble::NumMessageViewsForTest() const {
232 return contents_view_->NumMessageViews();
235 } // namespace message_center