OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "ui/message_center/views/message_popup_bubble.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/stl_util.h" | |
9 #include "ui/message_center/message_center.h" | |
10 #include "ui/message_center/message_center_style.h" | |
11 #include "ui/message_center/notification.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" | |
19 | |
20 namespace message_center { | |
21 | |
22 // Popup notifications contents. | |
23 class PopupBubbleContentsView : public views::View { | |
24 public: | |
25 explicit PopupBubbleContentsView(MessageCenter* message_center); | |
26 | |
27 void Update(const NotificationList::PopupNotifications& popup_notifications); | |
28 | |
29 size_t NumMessageViews() const { | |
30 return content_->child_count(); | |
31 } | |
32 | |
33 private: | |
34 MessageCenter* message_center_; // Weak reference. | |
35 views::View* content_; | |
36 | |
37 DISALLOW_COPY_AND_ASSIGN(PopupBubbleContentsView); | |
38 }; | |
39 | |
40 PopupBubbleContentsView::PopupBubbleContentsView( | |
41 MessageCenter* message_center) | |
42 : message_center_(message_center) { | |
43 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); | |
44 | |
45 content_ = new views::View; | |
46 content_->SetLayoutManager( | |
47 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); | |
48 AddChildView(content_); | |
49 | |
50 if (get_use_acceleration_when_possible()) { | |
51 content_->SetPaintToLayer(true); | |
52 content_->SetFillsBoundsOpaquely(false); | |
53 content_->layer()->SetMasksToBounds(true); | |
54 } | |
55 } | |
56 | |
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( | |
68 NotificationView::Create(*(*iter), | |
69 message_center_, | |
70 NULL, | |
71 true, // Create expanded. | |
72 false)); // Not creating a top-level | |
73 // notification. | |
74 } | |
75 content_->SizeToPreferredSize(); | |
76 content_->InvalidateLayout(); | |
77 Layout(); | |
78 if (GetWidget()) | |
79 GetWidget()->GetRootView()->SchedulePaint(); | |
80 } | |
81 | |
82 // The timer to call OnAutoClose for |notification|. | |
83 class MessagePopupBubble::AutocloseTimer { | |
84 public: | |
85 AutocloseTimer(Notification* notification, MessagePopupBubble* bubble); | |
86 | |
87 void Start(); | |
88 void Restart(); | |
89 void Suspend(); | |
90 | |
91 private: | |
92 const std::string id_; | |
93 base::TimeDelta delay_; | |
94 base::Time start_time_; | |
95 MessagePopupBubble* bubble_; | |
96 base::OneShotTimer<MessagePopupBubble> timer_; | |
97 | |
98 DISALLOW_COPY_AND_ASSIGN(AutocloseTimer); | |
99 }; | |
100 | |
101 MessagePopupBubble::AutocloseTimer::AutocloseTimer( | |
102 Notification* notification, | |
103 MessagePopupBubble* bubble) | |
104 : id_(notification->id()), | |
105 bubble_(bubble) { | |
106 int seconds = kAutocloseDefaultDelaySeconds; | |
107 if (notification->priority() > DEFAULT_PRIORITY) | |
108 seconds = kAutocloseHighPriorityDelaySeconds; | |
109 delay_ = base::TimeDelta::FromSeconds(seconds); | |
110 } | |
111 | |
112 void MessagePopupBubble::AutocloseTimer::Start() { | |
113 start_time_ = base::Time::Now(); | |
114 timer_.Start(FROM_HERE, | |
115 delay_, | |
116 base::Bind(&MessagePopupBubble::OnAutoClose, | |
117 base::Unretained(bubble_), id_)); | |
118 } | |
119 | |
120 void MessagePopupBubble::AutocloseTimer::Restart() { | |
121 delay_ -= base::Time::Now() - start_time_; | |
122 if (delay_ < base::TimeDelta()) | |
123 bubble_->OnAutoClose(id_); | |
124 else | |
125 Start(); | |
126 } | |
127 | |
128 void MessagePopupBubble::AutocloseTimer::Suspend() { | |
129 timer_.Stop(); | |
130 } | |
131 | |
132 // MessagePopupBubble | |
133 MessagePopupBubble::MessagePopupBubble(MessageCenter* message_center) | |
134 : MessageBubbleBase(message_center, NULL), | |
135 contents_view_(NULL) { | |
136 } | |
137 | |
138 MessagePopupBubble::~MessagePopupBubble() { | |
139 STLDeleteContainerPairSecondPointers(autoclose_timers_.begin(), | |
140 autoclose_timers_.end()); | |
141 } | |
142 | |
143 views::TrayBubbleView::InitParams MessagePopupBubble::GetInitParams( | |
144 views::TrayBubbleView::AnchorAlignment anchor_alignment) { | |
145 views::TrayBubbleView::InitParams init_params = | |
146 GetDefaultInitParams(anchor_alignment); | |
147 init_params.arrow_color = kBackgroundColor; | |
148 init_params.close_on_deactivate = false; | |
149 return init_params; | |
150 } | |
151 | |
152 void MessagePopupBubble::InitializeContents( | |
153 views::TrayBubbleView* new_bubble_view) { | |
154 set_bubble_view(new_bubble_view); | |
155 contents_view_ = new PopupBubbleContentsView(message_center()); | |
156 bubble_view()->AddChildView(contents_view_); | |
157 bubble_view()->set_notify_enter_exit_on_child(true); | |
158 UpdateBubbleView(); | |
159 } | |
160 | |
161 void MessagePopupBubble::OnBubbleViewDestroyed() { | |
162 contents_view_ = NULL; | |
163 } | |
164 | |
165 void MessagePopupBubble::UpdateBubbleView() { | |
166 NotificationList::PopupNotifications popups = | |
167 message_center()->GetPopupNotifications(); | |
168 | |
169 if (popups.size() == 0) { | |
170 if (bubble_view()) | |
171 bubble_view()->delegate()->HideBubble(bubble_view()); // deletes |this| | |
172 return; | |
173 } | |
174 | |
175 contents_view_->Update(popups); | |
176 bubble_view()->GetWidget()->Show(); | |
177 bubble_view()->UpdateBubble(); | |
178 | |
179 std::set<std::string> old_popup_ids; | |
180 old_popup_ids.swap(popup_ids_); | |
181 | |
182 // Start autoclose timers. | |
183 for (NotificationList::PopupNotifications::const_iterator iter = | |
184 popups.begin(); | |
185 iter != popups.end(); ++iter) { | |
186 std::string id = (*iter)->id(); | |
187 std::map<std::string, AutocloseTimer*>::const_iterator timer_iter = | |
188 autoclose_timers_.find(id); | |
189 if (timer_iter == autoclose_timers_.end()) { | |
190 AutocloseTimer *timer = new AutocloseTimer(*iter, this); | |
191 autoclose_timers_[id] = timer; | |
192 timer->Start(); | |
193 } | |
194 popup_ids_.insert(id); | |
195 old_popup_ids.erase(id); | |
196 } | |
197 | |
198 // Stops timers whose notifications are gone. | |
199 for (std::set<std::string>::const_iterator iter = old_popup_ids.begin(); | |
200 iter != old_popup_ids.end(); ++iter) { | |
201 DeleteTimer(*iter); | |
202 } | |
203 } | |
204 | |
205 void MessagePopupBubble::OnMouseEnteredView() { | |
206 for (std::map<std::string, AutocloseTimer*>::iterator iter = | |
207 autoclose_timers_.begin(); iter != autoclose_timers_.end(); ++iter) { | |
208 iter->second->Suspend(); | |
209 } | |
210 } | |
211 | |
212 void MessagePopupBubble::OnMouseExitedView() { | |
213 for (std::map<std::string, AutocloseTimer*>::iterator iter = | |
214 autoclose_timers_.begin(); iter != autoclose_timers_.end();) { | |
215 // |iter| can be deleted if timer is already over. | |
216 AutocloseTimer* timer = iter->second; | |
217 ++iter; | |
218 timer->Restart(); | |
219 } | |
220 } | |
221 | |
222 void MessagePopupBubble::OnAutoClose(const std::string& id) { | |
223 if (!message_center()->HasNotification(id)) | |
224 return; | |
225 | |
226 message_center()->MarkSinglePopupAsShown(id, false); | |
227 } | |
228 | |
229 void MessagePopupBubble::DeleteTimer(const std::string& id) { | |
230 std::map<std::string, AutocloseTimer*>::iterator iter = | |
231 autoclose_timers_.find(id); | |
232 if (iter != autoclose_timers_.end()) { | |
233 scoped_ptr<AutocloseTimer> release_timer(iter->second); | |
234 autoclose_timers_.erase(iter); | |
235 } | |
236 } | |
237 | |
238 size_t MessagePopupBubble::NumMessageViewsForTest() const { | |
239 return contents_view_->NumMessageViews(); | |
240 } | |
241 | |
242 } // namespace message_center | |
OLD | NEW |