Chromium Code Reviews| 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 |