| 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 |