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"
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
{
25 explicit PopupBubbleContentsView(NotificationChangeObserver
* observer
);
27 void Update(const NotificationList::PopupNotifications
& popup_notifications
);
29 size_t NumMessageViews() const {
30 return content_
->child_count();
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();
73 GetWidget()->GetRootView()->SchedulePaint();
76 // The timer to call OnAutoClose for |notification|.
77 class MessagePopupBubble::AutocloseTimer
{
79 AutocloseTimer(Notification
* notification
, MessagePopupBubble
* bubble
);
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()),
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
,
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_
);
122 void MessagePopupBubble::AutocloseTimer::Suspend() {
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;
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);
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) {
165 bubble_view()->delegate()->HideBubble(bubble_view()); // deletes |this|
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
=
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
;
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
) {
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
;
216 void MessagePopupBubble::OnAutoClose(const std::string
& id
) {
217 message_center()->notification_list()->MarkSinglePopupAsShown(id
, false);
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