OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/message_center/message_popup_bubble.h" | 5 #include "ui/message_center/message_popup_bubble.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/stl_util.h" | |
8 #include "ui/message_center/message_view.h" | 9 #include "ui/message_center/message_view.h" |
9 #include "ui/message_center/notification_view.h" | 10 #include "ui/message_center/notification_view.h" |
10 #include "ui/notifications/notification_types.h" | 11 #include "ui/notifications/notification_types.h" |
11 #include "ui/views/bubble/tray_bubble_view.h" | 12 #include "ui/views/bubble/tray_bubble_view.h" |
12 #include "ui/views/layout/box_layout.h" | 13 #include "ui/views/layout/box_layout.h" |
13 #include "ui/views/view.h" | 14 #include "ui/views/view.h" |
14 #include "ui/views/widget/widget.h" | 15 #include "ui/views/widget/widget.h" |
15 | 16 |
16 namespace message_center { | 17 namespace message_center { |
17 namespace { | 18 namespace { |
18 | 19 |
19 const int kAutocloseHighPriorityDelaySeconds = 25; | 20 const int kAutocloseHighPriorityDelaySeconds = 25; |
20 const int kAutocloseDefaultDelaySeconds = 8; | 21 const int kAutocloseDefaultDelaySeconds = 8; |
21 | 22 |
22 std::vector<const NotificationList::Notification*> GetNewNotifications( | |
23 const NotificationList::Notifications& old_list, | |
24 const NotificationList::Notifications& new_list) { | |
25 std::set<std::string> existing_ids; | |
26 std::vector<const NotificationList::Notification*> result; | |
27 for (NotificationList::Notifications::const_iterator iter = old_list.begin(); | |
28 iter != old_list.end(); ++iter) { | |
29 existing_ids.insert(iter->id); | |
30 } | |
31 for (NotificationList::Notifications::const_iterator iter = new_list.begin(); | |
32 iter != new_list.end(); ++iter) { | |
33 if (existing_ids.find(iter->id) == existing_ids.end()) | |
34 result.push_back(&(*iter)); | |
35 } | |
36 return result; | |
37 } | |
38 | |
39 } // namespace | 23 } // namespace |
40 | 24 |
41 // Popup notifications contents. | 25 // Popup notifications contents. |
42 class PopupBubbleContentsView : public views::View { | 26 class PopupBubbleContentsView : public views::View { |
43 public: | 27 public: |
44 explicit PopupBubbleContentsView(NotificationList::Delegate* list_delegate) | 28 explicit PopupBubbleContentsView(NotificationList::Delegate* list_delegate) |
45 : list_delegate_(list_delegate) { | 29 : list_delegate_(list_delegate) { |
46 SetLayoutManager( | 30 SetLayoutManager( |
47 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); | 31 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); |
48 | 32 |
(...skipping 30 matching lines...) Expand all Loading... | |
79 return content_->child_count(); | 63 return content_->child_count(); |
80 } | 64 } |
81 | 65 |
82 private: | 66 private: |
83 NotificationList::Delegate* list_delegate_; | 67 NotificationList::Delegate* list_delegate_; |
84 views::View* content_; | 68 views::View* content_; |
85 | 69 |
86 DISALLOW_COPY_AND_ASSIGN(PopupBubbleContentsView); | 70 DISALLOW_COPY_AND_ASSIGN(PopupBubbleContentsView); |
87 }; | 71 }; |
88 | 72 |
73 // The timer to call OnAutoClose for |notification|. | |
74 class MessagePopupBubble::AutocloseTimer { | |
75 public: | |
76 AutocloseTimer(const NotificationList::Notification& notification, | |
77 MessagePopupBubble* bubble) | |
78 : id_(notification.id), | |
79 bubble_(bubble) { | |
80 int seconds = kAutocloseDefaultDelaySeconds; | |
81 if (notification.priority > ui::notifications::DEFAULT_PRIORITY) | |
82 seconds = kAutocloseHighPriorityDelaySeconds; | |
83 delay_ = base::TimeDelta::FromSeconds(seconds); | |
84 } | |
dharcourt
2013/01/30 23:24:47
I may be misapplying that to this, but it seems th
Jun Mukai
2013/01/31 18:59:09
Thanks. Moved out-of-line (and fixed PopupBubbleC
| |
85 | |
86 void Start() { | |
87 start_time_ = base::Time::Now(); | |
88 timer_.Start(FROM_HERE, | |
89 delay_, | |
90 base::Bind(&MessagePopupBubble::OnAutoClose, | |
91 base::Unretained(bubble_), id_)); | |
92 } | |
93 | |
94 void Suspend() { | |
95 base::TimeDelta passed = base::Time::Now() - start_time_; | |
96 delay_ = std::max(base::TimeDelta(), delay_ - passed); | |
97 timer_.Reset(); | |
98 } | |
99 | |
100 private: | |
101 const std::string id_; | |
102 base::TimeDelta delay_; | |
103 base::Time start_time_; | |
104 MessagePopupBubble* bubble_; | |
105 base::OneShotTimer<MessagePopupBubble> timer_; | |
106 | |
107 DISALLOW_COPY_AND_ASSIGN(AutocloseTimer); | |
108 }; | |
109 | |
89 // MessagePopupBubble | 110 // MessagePopupBubble |
90 MessagePopupBubble::MessagePopupBubble(NotificationList::Delegate* delegate) | 111 MessagePopupBubble::MessagePopupBubble(NotificationList::Delegate* delegate) |
91 : MessageBubbleBase(delegate), | 112 : MessageBubbleBase(delegate), |
92 contents_view_(NULL), | 113 contents_view_(NULL) { |
93 should_run_default_timer_(false), | |
94 should_run_high_timer_(false) { | |
95 } | 114 } |
96 | 115 |
97 MessagePopupBubble::~MessagePopupBubble() { | 116 MessagePopupBubble::~MessagePopupBubble() { |
117 STLDeleteContainerPairSecondPointers(autoclose_timers_.begin(), | |
118 autoclose_timers_.end()); | |
98 } | 119 } |
99 | 120 |
100 views::TrayBubbleView::InitParams MessagePopupBubble::GetInitParams( | 121 views::TrayBubbleView::InitParams MessagePopupBubble::GetInitParams( |
101 views::TrayBubbleView::AnchorAlignment anchor_alignment) { | 122 views::TrayBubbleView::AnchorAlignment anchor_alignment) { |
102 views::TrayBubbleView::InitParams init_params = | 123 views::TrayBubbleView::InitParams init_params = |
103 GetDefaultInitParams(anchor_alignment); | 124 GetDefaultInitParams(anchor_alignment); |
104 init_params.arrow_color = kBackgroundColor; | 125 init_params.arrow_color = kBackgroundColor; |
105 init_params.close_on_deactivate = false; | 126 init_params.close_on_deactivate = false; |
106 return init_params; | 127 return init_params; |
107 } | 128 } |
108 | 129 |
109 void MessagePopupBubble::InitializeContents( | 130 void MessagePopupBubble::InitializeContents( |
110 views::TrayBubbleView* new_bubble_view) { | 131 views::TrayBubbleView* new_bubble_view) { |
111 set_bubble_view(new_bubble_view); | 132 set_bubble_view(new_bubble_view); |
112 contents_view_ = new PopupBubbleContentsView(list_delegate()); | 133 contents_view_ = new PopupBubbleContentsView(list_delegate()); |
113 bubble_view()->AddChildView(contents_view_); | 134 bubble_view()->AddChildView(contents_view_); |
114 UpdateBubbleView(); | 135 UpdateBubbleView(); |
115 } | 136 } |
116 | 137 |
117 void MessagePopupBubble::OnBubbleViewDestroyed() { | 138 void MessagePopupBubble::OnBubbleViewDestroyed() { |
118 contents_view_ = NULL; | 139 contents_view_ = NULL; |
119 } | 140 } |
120 | 141 |
121 void MessagePopupBubble::UpdateBubbleView() { | 142 void MessagePopupBubble::UpdateBubbleView() { |
122 NotificationList::Notifications new_notifications; | 143 NotificationList::Notifications popups; |
123 list_delegate()->GetNotificationList()->GetPopupNotifications( | 144 list_delegate()->GetNotificationList()->GetPopupNotifications(&popups); |
124 &new_notifications); | 145 |
125 if (new_notifications.size() == 0) { | 146 if (popups.size() == 0) { |
126 if (bubble_view()) | 147 if (bubble_view()) |
127 bubble_view()->delegate()->HideBubble(bubble_view()); // deletes |this| | 148 bubble_view()->delegate()->HideBubble(bubble_view()); // deletes |this| |
128 return; | 149 return; |
129 } | 150 } |
130 // Only reset the timer when the number of visible notifications changes. | 151 |
131 std::vector<const NotificationList::Notification*> added = | 152 contents_view_->Update(popups); |
132 GetNewNotifications(popup_notifications_, new_notifications); | |
133 bool run_default = false; | |
134 bool run_high = false; | |
135 for (std::vector<const NotificationList::Notification*>::const_iterator iter = | |
136 added.begin(); iter != added.end(); ++iter) { | |
137 if ((*iter)->priority == ui::notifications::DEFAULT_PRIORITY) | |
138 run_default = true; | |
139 else if ((*iter)->priority >= ui::notifications::HIGH_PRIORITY) | |
140 run_high = true; | |
141 } | |
142 // Currently MAX priority is same as HIGH priority. | |
143 if (run_high) | |
144 StartAutoCloseTimer(ui::notifications::MAX_PRIORITY); | |
145 if (run_default) | |
146 StartAutoCloseTimer(ui::notifications::DEFAULT_PRIORITY); | |
147 should_run_high_timer_ = run_high; | |
148 should_run_default_timer_ = run_default; | |
149 contents_view_->Update(new_notifications); | |
150 popup_notifications_.swap(new_notifications); | |
151 bubble_view()->Show(); | 153 bubble_view()->Show(); |
152 bubble_view()->UpdateBubble(); | 154 bubble_view()->UpdateBubble(); |
155 | |
156 std::set<std::string> old_popup_ids; | |
157 old_popup_ids.swap(popup_ids_); | |
158 | |
159 // Start autoclose timers. | |
160 for (NotificationList::Notifications::const_iterator iter = popups.begin(); | |
161 iter != popups.end(); ++iter) { | |
162 std::map<std::string, AutocloseTimer*>::const_iterator timer_iter = | |
163 autoclose_timers_.find(iter->id); | |
164 if (timer_iter == autoclose_timers_.end()) { | |
165 AutocloseTimer *timer = new AutocloseTimer(*iter, this); | |
166 autoclose_timers_[iter->id] = timer; | |
167 timer->Start(); | |
168 } | |
169 popup_ids_.insert(iter->id); | |
170 old_popup_ids.erase(iter->id); | |
171 } | |
172 | |
173 // Stops timers whose notifications are gone. | |
174 for (std::set<std::string>::const_iterator iter = old_popup_ids.begin(); | |
175 iter != old_popup_ids.end(); ++iter) { | |
176 DeleteTimer(*iter); | |
177 } | |
153 } | 178 } |
154 | 179 |
155 void MessagePopupBubble::OnMouseEnteredView() { | 180 void MessagePopupBubble::OnMouseEnteredView() { |
156 StopAutoCloseTimer(); | 181 for (std::map<std::string, AutocloseTimer*>::iterator iter = |
182 autoclose_timers_.begin(); iter != autoclose_timers_.end(); ++iter) { | |
183 iter->second->Suspend(); | |
184 } | |
157 } | 185 } |
158 | 186 |
159 void MessagePopupBubble::OnMouseExitedView() { | 187 void MessagePopupBubble::OnMouseExitedView() { |
160 if (should_run_high_timer_) | 188 for (std::map<std::string, AutocloseTimer*>::iterator iter = |
161 StartAutoCloseTimer(ui::notifications::HIGH_PRIORITY); | 189 autoclose_timers_.begin(); iter != autoclose_timers_.end(); ++iter) { |
162 if (should_run_default_timer_) | 190 iter->second->Start(); |
163 StartAutoCloseTimer(ui::notifications::DEFAULT_PRIORITY); | 191 } |
164 } | 192 } |
165 | 193 |
166 void MessagePopupBubble::StartAutoCloseTimer(int priority) { | 194 void MessagePopupBubble::OnAutoClose(const std::string& id) { |
167 base::TimeDelta seconds; | 195 DeleteTimer(id); |
168 base::OneShotTimer<MessagePopupBubble>* timer = NULL; | 196 list_delegate()->GetNotificationList()->MarkSinglePopupAsShown(id, false); |
169 if (priority == ui::notifications::MAX_PRIORITY) { | |
170 seconds = base::TimeDelta::FromSeconds(kAutocloseHighPriorityDelaySeconds); | |
171 timer = &autoclose_high_; | |
172 } else { | |
173 seconds = base::TimeDelta::FromSeconds(kAutocloseDefaultDelaySeconds); | |
174 timer = &autoclose_default_; | |
175 } | |
176 | |
177 timer->Start(FROM_HERE, | |
178 seconds, | |
179 base::Bind(&MessagePopupBubble::OnAutoClose, | |
180 base::Unretained(this), priority)); | |
181 } | |
182 | |
183 void MessagePopupBubble::StopAutoCloseTimer() { | |
184 autoclose_high_.Stop(); | |
185 autoclose_default_.Stop(); | |
186 } | |
187 | |
188 void MessagePopupBubble::OnAutoClose(int priority) { | |
189 list_delegate()->GetNotificationList()->MarkPopupsAsShown(priority); | |
190 if (priority == ui::notifications::MAX_PRIORITY) | |
191 list_delegate()->GetNotificationList()->MarkPopupsAsShown( | |
192 ui::notifications::HIGH_PRIORITY); | |
193 | |
194 if (priority >= ui::notifications::MAX_PRIORITY) | |
195 should_run_high_timer_ = false; | |
196 else | |
197 should_run_default_timer_ = false; | |
198 UpdateBubbleView(); | 197 UpdateBubbleView(); |
199 } | 198 } |
200 | 199 |
200 void MessagePopupBubble::DeleteTimer(const std::string& id) { | |
201 std::map<std::string, AutocloseTimer*>::iterator iter = | |
202 autoclose_timers_.find(id); | |
203 if (iter != autoclose_timers_.end()) { | |
204 delete iter->second; | |
205 autoclose_timers_.erase(iter); | |
dharcourt
2013/01/30 23:24:47
Will this make autoclose_timers_ briefly contain a
Jun Mukai
2013/01/31 18:59:09
using scoped_ptr to ensure releasing the object af
| |
206 } | |
207 } | |
208 | |
201 size_t MessagePopupBubble::NumMessageViewsForTest() const { | 209 size_t MessagePopupBubble::NumMessageViewsForTest() const { |
202 return contents_view_->NumMessageViews(); | 210 return contents_view_->NumMessageViews(); |
203 } | 211 } |
204 | 212 |
205 } // namespace message_center | 213 } // namespace message_center |
OLD | NEW |