Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(689)

Side by Side Diff: ui/message_center/message_popup_bubble.cc

Issue 12082081: Sets per-item timers rather than global timer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/message_center/message_popup_bubble.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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) {
46 SetLayoutManager(
47 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
48 29
49 content_ = new views::View; 30 void Update(const NotificationList::Notifications& popup_notifications);
50 content_->SetLayoutManager(
51 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
52 AddChildView(content_);
53
54 if (get_use_acceleration_when_possible()) {
55 content_->SetPaintToLayer(true);
56 content_->SetFillsBoundsOpaquely(false);
57 content_->layer()->SetMasksToBounds(true);
58 }
59 }
60
61 void Update(const NotificationList::Notifications& popup_notifications) {
62 content_->RemoveAllChildViews(true);
63 for (NotificationList::Notifications::const_iterator iter =
64 popup_notifications.begin();
65 iter != popup_notifications.end(); ++iter) {
66 MessageView* view =
67 NotificationView::ViewForNotification(*iter, list_delegate_);
68 view->SetUpView();
69 content_->AddChildView(view);
70 }
71 content_->SizeToPreferredSize();
72 content_->InvalidateLayout();
73 Layout();
74 if (GetWidget())
75 GetWidget()->GetRootView()->SchedulePaint();
76 }
77 31
78 size_t NumMessageViews() const { 32 size_t NumMessageViews() const {
79 return content_->child_count(); 33 return content_->child_count();
80 } 34 }
81 35
82 private: 36 private:
83 NotificationList::Delegate* list_delegate_; 37 NotificationList::Delegate* list_delegate_;
84 views::View* content_; 38 views::View* content_;
85 39
86 DISALLOW_COPY_AND_ASSIGN(PopupBubbleContentsView); 40 DISALLOW_COPY_AND_ASSIGN(PopupBubbleContentsView);
87 }; 41 };
88 42
43 PopupBubbleContentsView::PopupBubbleContentsView(
44 NotificationList::Delegate* list_delegate)
45 : list_delegate_(list_delegate) {
46 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
47
48 content_ = new views::View;
49 content_->SetLayoutManager(
50 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
51 AddChildView(content_);
52
53 if (get_use_acceleration_when_possible()) {
54 content_->SetPaintToLayer(true);
55 content_->SetFillsBoundsOpaquely(false);
56 content_->layer()->SetMasksToBounds(true);
57 }
58 }
59
60 void PopupBubbleContentsView::Update(
61 const NotificationList::Notifications& popup_notifications) {
62 content_->RemoveAllChildViews(true);
63 for (NotificationList::Notifications::const_iterator iter =
64 popup_notifications.begin();
65 iter != popup_notifications.end(); ++iter) {
66 MessageView* view =
67 NotificationView::ViewForNotification(*iter, list_delegate_);
68 view->SetUpView();
69 content_->AddChildView(view);
70 }
71 content_->SizeToPreferredSize();
72 content_->InvalidateLayout();
73 Layout();
74 if (GetWidget())
75 GetWidget()->GetRootView()->SchedulePaint();
76 }
77
78 // The timer to call OnAutoClose for |notification|.
79 class MessagePopupBubble::AutocloseTimer {
80 public:
81 AutocloseTimer(const NotificationList::Notification& notification,
82 MessagePopupBubble* bubble);
83
84 void Start();
85
86 void Suspend();
87
88 private:
89 const std::string id_;
90 base::TimeDelta delay_;
91 base::Time start_time_;
92 MessagePopupBubble* bubble_;
93 base::OneShotTimer<MessagePopupBubble> timer_;
94
95 DISALLOW_COPY_AND_ASSIGN(AutocloseTimer);
96 };
97
98 MessagePopupBubble::AutocloseTimer::AutocloseTimer(
99 const NotificationList::Notification& notification,
100 MessagePopupBubble* bubble)
101 : id_(notification.id),
102 bubble_(bubble) {
103 int seconds = kAutocloseDefaultDelaySeconds;
104 if (notification.priority > ui::notifications::DEFAULT_PRIORITY)
105 seconds = kAutocloseHighPriorityDelaySeconds;
106 delay_ = base::TimeDelta::FromSeconds(seconds);
107 }
108
109 void MessagePopupBubble::AutocloseTimer::Start() {
110 start_time_ = base::Time::Now();
111 timer_.Start(FROM_HERE,
112 delay_,
113 base::Bind(&MessagePopupBubble::OnAutoClose,
114 base::Unretained(bubble_), id_));
115 }
116
117 void MessagePopupBubble::AutocloseTimer::Suspend() {
118 base::TimeDelta passed = base::Time::Now() - start_time_;
119 delay_ = std::max(base::TimeDelta(), delay_ - passed);
120 timer_.Reset();
121 }
122
89 // MessagePopupBubble 123 // MessagePopupBubble
90 MessagePopupBubble::MessagePopupBubble(NotificationList::Delegate* delegate) 124 MessagePopupBubble::MessagePopupBubble(NotificationList::Delegate* delegate)
91 : MessageBubbleBase(delegate), 125 : MessageBubbleBase(delegate),
92 contents_view_(NULL), 126 contents_view_(NULL) {
93 should_run_default_timer_(false),
94 should_run_high_timer_(false) {
95 } 127 }
96 128
97 MessagePopupBubble::~MessagePopupBubble() { 129 MessagePopupBubble::~MessagePopupBubble() {
130 STLDeleteContainerPairSecondPointers(autoclose_timers_.begin(),
131 autoclose_timers_.end());
98 } 132 }
99 133
100 views::TrayBubbleView::InitParams MessagePopupBubble::GetInitParams( 134 views::TrayBubbleView::InitParams MessagePopupBubble::GetInitParams(
101 views::TrayBubbleView::AnchorAlignment anchor_alignment) { 135 views::TrayBubbleView::AnchorAlignment anchor_alignment) {
102 views::TrayBubbleView::InitParams init_params = 136 views::TrayBubbleView::InitParams init_params =
103 GetDefaultInitParams(anchor_alignment); 137 GetDefaultInitParams(anchor_alignment);
104 init_params.arrow_color = kBackgroundColor; 138 init_params.arrow_color = kBackgroundColor;
105 init_params.close_on_deactivate = false; 139 init_params.close_on_deactivate = false;
106 return init_params; 140 return init_params;
107 } 141 }
108 142
109 void MessagePopupBubble::InitializeContents( 143 void MessagePopupBubble::InitializeContents(
110 views::TrayBubbleView* new_bubble_view) { 144 views::TrayBubbleView* new_bubble_view) {
111 set_bubble_view(new_bubble_view); 145 set_bubble_view(new_bubble_view);
112 contents_view_ = new PopupBubbleContentsView(list_delegate()); 146 contents_view_ = new PopupBubbleContentsView(list_delegate());
113 bubble_view()->AddChildView(contents_view_); 147 bubble_view()->AddChildView(contents_view_);
114 UpdateBubbleView(); 148 UpdateBubbleView();
115 } 149 }
116 150
117 void MessagePopupBubble::OnBubbleViewDestroyed() { 151 void MessagePopupBubble::OnBubbleViewDestroyed() {
118 contents_view_ = NULL; 152 contents_view_ = NULL;
119 } 153 }
120 154
121 void MessagePopupBubble::UpdateBubbleView() { 155 void MessagePopupBubble::UpdateBubbleView() {
122 NotificationList::Notifications new_notifications; 156 NotificationList::Notifications popups;
123 list_delegate()->GetNotificationList()->GetPopupNotifications( 157 list_delegate()->GetNotificationList()->GetPopupNotifications(&popups);
124 &new_notifications); 158
125 if (new_notifications.size() == 0) { 159 if (popups.size() == 0) {
126 if (bubble_view()) 160 if (bubble_view())
127 bubble_view()->delegate()->HideBubble(bubble_view()); // deletes |this| 161 bubble_view()->delegate()->HideBubble(bubble_view()); // deletes |this|
128 return; 162 return;
129 } 163 }
130 // Only reset the timer when the number of visible notifications changes. 164
131 std::vector<const NotificationList::Notification*> added = 165 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(); 166 bubble_view()->Show();
152 bubble_view()->UpdateBubble(); 167 bubble_view()->UpdateBubble();
168
169 std::set<std::string> old_popup_ids;
170 old_popup_ids.swap(popup_ids_);
171
172 // Start autoclose timers.
173 for (NotificationList::Notifications::const_iterator iter = popups.begin();
174 iter != popups.end(); ++iter) {
175 std::map<std::string, AutocloseTimer*>::const_iterator timer_iter =
176 autoclose_timers_.find(iter->id);
177 if (timer_iter == autoclose_timers_.end()) {
178 AutocloseTimer *timer = new AutocloseTimer(*iter, this);
179 autoclose_timers_[iter->id] = timer;
180 timer->Start();
181 }
182 popup_ids_.insert(iter->id);
183 old_popup_ids.erase(iter->id);
184 }
185
186 // Stops timers whose notifications are gone.
187 for (std::set<std::string>::const_iterator iter = old_popup_ids.begin();
188 iter != old_popup_ids.end(); ++iter) {
189 DeleteTimer(*iter);
190 }
153 } 191 }
154 192
155 void MessagePopupBubble::OnMouseEnteredView() { 193 void MessagePopupBubble::OnMouseEnteredView() {
156 StopAutoCloseTimer(); 194 for (std::map<std::string, AutocloseTimer*>::iterator iter =
195 autoclose_timers_.begin(); iter != autoclose_timers_.end(); ++iter) {
196 iter->second->Suspend();
197 }
157 } 198 }
158 199
159 void MessagePopupBubble::OnMouseExitedView() { 200 void MessagePopupBubble::OnMouseExitedView() {
160 if (should_run_high_timer_) 201 for (std::map<std::string, AutocloseTimer*>::iterator iter =
161 StartAutoCloseTimer(ui::notifications::HIGH_PRIORITY); 202 autoclose_timers_.begin(); iter != autoclose_timers_.end(); ++iter) {
162 if (should_run_default_timer_) 203 iter->second->Start();
163 StartAutoCloseTimer(ui::notifications::DEFAULT_PRIORITY); 204 }
164 } 205 }
165 206
166 void MessagePopupBubble::StartAutoCloseTimer(int priority) { 207 void MessagePopupBubble::OnAutoClose(const std::string& id) {
167 base::TimeDelta seconds; 208 DeleteTimer(id);
168 base::OneShotTimer<MessagePopupBubble>* timer = NULL; 209 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(); 210 UpdateBubbleView();
199 } 211 }
200 212
213 void MessagePopupBubble::DeleteTimer(const std::string& id) {
214 std::map<std::string, AutocloseTimer*>::iterator iter =
215 autoclose_timers_.find(id);
216 if (iter != autoclose_timers_.end()) {
217 scoped_ptr<AutocloseTimer> release_timer(iter->second);
218 autoclose_timers_.erase(iter);
219 }
220 }
221
201 size_t MessagePopupBubble::NumMessageViewsForTest() const { 222 size_t MessagePopupBubble::NumMessageViewsForTest() const {
202 return contents_view_->NumMessageViews(); 223 return contents_view_->NumMessageViews();
203 } 224 }
204 225
205 } // namespace message_center 226 } // namespace message_center
OLDNEW
« no previous file with comments | « ui/message_center/message_popup_bubble.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698