Chromium Code Reviews| Index: ui/message_center/message_center_bubble.cc |
| diff --git a/ui/message_center/message_center_bubble.cc b/ui/message_center/message_center_bubble.cc |
| index 007edb0fea996e4b3cfd4680819ebd9d3600539f..d869bd22c564aa618ef49c6170e8105948a22823 100644 |
| --- a/ui/message_center/message_center_bubble.cc |
| +++ b/ui/message_center/message_center_bubble.cc |
| @@ -4,6 +4,8 @@ |
| #include "ui/message_center/message_center_bubble.h" |
| +#include <map> |
| + |
| #include "grit/ui_strings.h" |
| #include "third_party/skia/include/core/SkPaint.h" |
| #include "ui/base/l10n/l10n_util.h" |
| @@ -67,7 +69,7 @@ class WebNotificationButtonViewBase : public views::View { |
| views::Button* close_all_button() { return close_all_button_; } |
| private: |
| - NotificationList::Delegate* list_delegate_; |
| + NotificationList::Delegate* list_delegate_; // Weak reference. |
| views::Button* close_all_button_; |
| DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonViewBase); |
| @@ -111,7 +113,7 @@ class WebNotificationButtonView : public WebNotificationButtonViewBase, |
| virtual ~WebNotificationButtonView() {} |
| - // Overridden from ButtonListener. |
| + // Overridden from views::ButtonListener: |
| virtual void ButtonPressed(views::Button* sender, |
| const ui::Event& event) OVERRIDE { |
| if (sender == close_all_button()) |
| @@ -134,7 +136,7 @@ class WebNotificationButton : public views::TextButton { |
| } |
| protected: |
| - // views::View overrides: |
| + // Overridden from views::View: |
|
dharcourt
2013/03/01 10:17:31
I took this opportunity to make the override comme
|
| virtual gfx::Size GetPreferredSize() OVERRIDE { |
| // Returns an empty size when invisible, to trim its space in the parent's |
| // GridLayout. |
| @@ -206,7 +208,7 @@ class WebNotificationButtonView2 : public WebNotificationButtonViewBase, |
| } |
| private: |
| - // views::ButtonListener overrides: |
| + // Overridden from views::ButtonListener: |
| virtual void ButtonPressed(views::Button* sender, |
| const ui::Event& event) OVERRIDE { |
| if (sender == close_all_button()) |
| @@ -224,10 +226,13 @@ class WebNotificationButtonView2 : public WebNotificationButtonViewBase, |
| DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView2); |
| }; |
| -// A custom scroll-view that has a specified size. |
| -class FixedSizedScrollView : public views::ScrollView { |
| +// A custom scroll view whose height has a minimum and maximum value and whose |
| +// scroll bar disappears when not needed. |
| +class BoundedScrollView : public views::ScrollView { |
| public: |
| - FixedSizedScrollView() { |
| + BoundedScrollView(int min_height, int max_height) |
| + : min_height_(min_height), |
| + max_height_(max_height) { |
| set_focusable(true); |
| set_notify_enter_exit_on_child(true); |
| if (IsRichNotificationEnabled()) { |
| @@ -236,53 +241,51 @@ class FixedSizedScrollView : public views::ScrollView { |
| } |
| } |
| - virtual ~FixedSizedScrollView() {} |
| - |
| - void SetFixedSize(const gfx::Size& size) { |
| - if (fixed_size_ == size) |
| - return; |
| - fixed_size_ = size; |
| - PreferredSizeChanged(); |
| - } |
| + virtual ~BoundedScrollView() {} |
| - // views::View overrides. |
| + // Overridden from views::View: |
| virtual gfx::Size GetPreferredSize() OVERRIDE { |
| - gfx::Size size = fixed_size_.IsEmpty() ? |
| - contents()->GetPreferredSize() : fixed_size_; |
| + gfx::Size size = contents()->GetPreferredSize(); |
| + size.ClampToMin(gfx::Size(size.width(), min_height_)); |
| + size.ClampToMax(gfx::Size(size.width(), max_height_)); |
| gfx::Insets insets = GetInsets(); |
| size.Enlarge(insets.width(), insets.height()); |
| return size; |
| } |
| virtual void Layout() OVERRIDE { |
| - gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize()); |
| - bounds.set_width(std::max(0, width() - GetScrollBarWidth())); |
| - contents()->SetBoundsRect(bounds); |
| - |
| + // Lay out the view as if it will have a scroll bar. |
| + gfx::Rect content_bounds = gfx::Rect(contents()->GetPreferredSize()); |
| + content_bounds.set_width(std::max(0, width() - GetScrollBarWidth())); |
| + contents()->SetBoundsRect(content_bounds); |
| views::ScrollView::Layout(); |
| + |
| + // But use the scroll bar space if no scroll bar is needed. |
| if (!vertical_scroll_bar()->visible()) { |
| - gfx::Rect bounds = contents()->bounds(); |
| - bounds.set_width(bounds.width() + GetScrollBarWidth()); |
| - contents()->SetBoundsRect(bounds); |
| + content_bounds = contents()->bounds(); |
| + content_bounds.set_width(content_bounds.width() + GetScrollBarWidth()); |
| + contents()->SetBoundsRect(content_bounds); |
| } |
| } |
| virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE { |
| - gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize()); |
| - bounds.set_width(std::max(0, width() - GetScrollBarWidth())); |
| - contents()->SetBoundsRect(bounds); |
| + // Make sure any content resizing takes into account the scroll bar. |
| + gfx::Rect content_bounds = gfx::Rect(contents()->GetPreferredSize()); |
| + content_bounds.set_width(std::max(0, width() - GetScrollBarWidth())); |
| + contents()->SetBoundsRect(content_bounds); |
| } |
| private: |
| - gfx::Size fixed_size_; |
| + int min_height_; |
| + int max_height_; |
| - DISALLOW_COPY_AND_ASSIGN(FixedSizedScrollView); |
| + DISALLOW_COPY_AND_ASSIGN(BoundedScrollView); |
| }; |
| -// Container for the messages. |
| -class ScrollContentView : public views::View { |
| +// Displays a list of messages. |
| +class MessageListView : public views::View { |
| public: |
| - ScrollContentView() { |
| + MessageListView() { |
| if (IsRichNotificationEnabled()) { |
| // Set the margin to 0 for the layout. BoxLayout assumes the same margin |
| // for top and bottom, but the bottom margin here should be smaller |
| @@ -309,39 +312,33 @@ class ScrollContentView : public views::View { |
| } |
| } |
| - virtual ~ScrollContentView() { |
| - } |
| - |
| - virtual gfx::Size GetPreferredSize() OVERRIDE { |
| - if (!preferred_size_.IsEmpty()) |
| - return preferred_size_; |
| - return views::View::GetPreferredSize(); |
| + virtual ~MessageListView() { |
| } |
| - void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; } |
| - |
| private: |
| - gfx::Size preferred_size_; |
| - DISALLOW_COPY_AND_ASSIGN(ScrollContentView); |
| + DISALLOW_COPY_AND_ASSIGN(MessageListView); |
| }; |
| } // namespace |
| -// Message Center contents. |
| -class MessageCenterContentsView : public views::View { |
| +// View that displays the whole message center. |
| +class MessageCenterView : public views::View { |
| public: |
| - explicit MessageCenterContentsView(MessageCenterBubble* bubble, |
| - NotificationList::Delegate* list_delegate) |
| - : list_delegate_(list_delegate), |
| - bubble_(bubble) { |
| + MessageCenterView(MessageCenterBubble* bubble) : bubble_(bubble) { |
| int between_child = IsRichNotificationEnabled() ? 0 : 1; |
| SetLayoutManager( |
| new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, between_child)); |
| - scroll_content_ = new ScrollContentView; |
| - scroller_ = new FixedSizedScrollView; |
| - scroller_->SetContents(scroll_content_); |
| - AddChildView(scroller_); |
| + |
| + if (IsRichNotificationEnabled()) |
| + button_view_ = new WebNotificationButtonView2(bubble_); |
| + else |
| + button_view_ = new WebNotificationButtonView(bubble_); |
| + |
| + const int button_height = button_view_->GetPreferredSize().height(); |
| + const int min_height = kMessageBubbleBaseMinHeight - button_height; |
| + const int max_height = bubble_->max_height() - button_height; |
| + scroller_ = new BoundedScrollView(min_height, max_height); |
| if (get_use_acceleration_when_possible()) { |
| scroller_->SetPaintToLayer(true); |
| @@ -349,10 +346,10 @@ class MessageCenterContentsView : public views::View { |
| scroller_->layer()->SetMasksToBounds(true); |
| } |
| - if (IsRichNotificationEnabled()) |
| - button_view_ = new WebNotificationButtonView2(list_delegate); |
| - else |
| - button_view_ = new WebNotificationButtonView(list_delegate); |
| + message_list_view_ = new MessageListView(); |
| + scroller_->SetContents(message_list_view_); |
| + |
| + AddChildView(scroller_); |
| AddChildView(button_view_); |
| } |
| @@ -360,21 +357,18 @@ class MessageCenterContentsView : public views::View { |
| scroller_->RequestFocus(); |
| } |
| - void Update(const NotificationList::Notifications& notifications) { |
| - scroll_content_->RemoveAllChildViews(true); |
| - scroll_content_->set_preferred_size(gfx::Size()); |
| - size_t num_children = 0; |
| + void UpdateAllNotifications( |
| + const NotificationList::Notifications& notifications) { |
| + RemoveAllNotifications(); |
| for (NotificationList::Notifications::const_iterator iter = |
| notifications.begin(); iter != notifications.end(); ++iter) { |
| - MessageView* view = NotificationView::Create(*(*iter), list_delegate_); |
| - view->set_scroller(scroller_); |
| - scroll_content_->AddChildView(view); |
| - if (++num_children >= |
| + AddNotification(*(*iter)); |
| + if (message_views_.size() >= |
| NotificationList::kMaxVisibleMessageCenterNotifications) { |
| break; |
| } |
| } |
| - if (num_children == 0) { |
| + if (message_views_.empty()) { |
| views::Label* label = new views::Label(l10n_util::GetStringUTF16( |
| IDS_MESSAGE_CENTER_NO_MESSAGES)); |
| label->SetFont(label->font().DeriveFont(1)); |
| @@ -382,53 +376,70 @@ class MessageCenterContentsView : public views::View { |
| // Set transparent background to ensure that subpixel rendering |
| // is disabled. See crbug.com/169056 |
| label->SetBackgroundColor(kTransparentColor); |
| - scroll_content_->AddChildView(label); |
| + message_list_view_->AddChildView(label); |
| button_view_->SetCloseAllVisible(false); |
| scroller_->set_focusable(false); |
| } else { |
| button_view_->SetCloseAllVisible(true); |
| scroller_->set_focusable(true); |
| } |
| - SizeScrollContent(); |
| Layout(); |
| - if (GetWidget()) |
| - GetWidget()->GetRootView()->SchedulePaint(); |
| + } |
| + |
| + void UpdateOneNotification(const Notification& notification) { |
| + // Update the corresponding message view if there is one and explicitly |
| + // update this view's layout as this is not automatic in spite of the |
| + // updated view's likely size change because ScrollView's Viewport breaks |
| + // the ChildPreferredSizeChange() chain. |
| + MessageView* view = message_views_[notification.id()]; |
| + if (view) { |
| + view->Update(notification); |
| + Layout(); |
| + } |
| } |
| size_t NumMessageViews() const { |
| - return scroll_content_->child_count(); |
| + return message_list_view_->child_count(); |
| + } |
| + |
| + protected: |
| + // Overridden from views::View: |
| + virtual void Layout() OVERRIDE { |
| + scroller_->SizeToPreferredSize(); |
| + views::View::Layout(); |
| + if (GetWidget()) |
| + GetWidget()->GetRootView()->SchedulePaint(); |
| + bubble_->bubble_view()->UpdateBubble(); |
| } |
| private: |
| - void SizeScrollContent() { |
| - gfx::Size scroll_size = scroll_content_->GetPreferredSize(); |
| - const int button_height = button_view_->GetPreferredSize().height(); |
| - const int min_height = kMessageBubbleBaseMinHeight - button_height; |
| - const int max_height = bubble_->max_height() - button_height; |
| - int scroll_height = std::min(std::max( |
| - scroll_size.height(), min_height), max_height); |
| - scroll_size.set_height(scroll_height); |
| - if (scroll_height == min_height) |
| - scroll_content_->set_preferred_size(scroll_size); |
| - else |
| - scroll_content_->set_preferred_size(gfx::Size()); |
| - scroller_->SetFixedSize(scroll_size); |
| - scroller_->SizeToPreferredSize(); |
| - scroll_content_->InvalidateLayout(); |
| + |
| + void RemoveAllNotifications() { |
| + message_views_.clear(); |
| + message_list_view_->RemoveAllChildViews(true); |
| + } |
| + |
| + void AddNotification(const Notification& notification) { |
| + // Always expand the first (topmost) notification. |
| + bool expand = (notification.is_expanded() || message_views_.empty()); |
| + MessageView* view = NotificationView::Create(notification, bubble_, expand); |
| + view->set_scroller(scroller_); |
| + message_views_[notification.id()] = view; |
| + message_list_view_->AddChildView(view); |
| } |
| - NotificationList::Delegate* list_delegate_; |
| - FixedSizedScrollView* scroller_; |
| - ScrollContentView* scroll_content_; |
| + MessageCenterBubble* bubble_; // Weak reference. |
| + std::map<std::string,MessageView*> message_views_; |
| + BoundedScrollView* scroller_; |
| + MessageListView* message_list_view_; |
| WebNotificationButtonViewBase* button_view_; |
| - MessageCenterBubble* bubble_; |
| - DISALLOW_COPY_AND_ASSIGN(MessageCenterContentsView); |
| + DISALLOW_COPY_AND_ASSIGN(MessageCenterView); |
| }; |
| // Message Center Bubble. |
| -MessageCenterBubble::MessageCenterBubble(NotificationList::Delegate* delegate) |
| - : MessageBubbleBase(delegate), |
| +MessageCenterBubble::MessageCenterBubble(MessageCenter* message_center) |
| + : MessageBubbleBase(message_center), |
| contents_view_(NULL) { |
| } |
| @@ -450,7 +461,7 @@ views::TrayBubbleView::InitParams MessageCenterBubble::GetInitParams( |
| void MessageCenterBubble::InitializeContents( |
| views::TrayBubbleView* new_bubble_view) { |
| set_bubble_view(new_bubble_view); |
| - contents_view_ = new MessageCenterContentsView(this, list_delegate()); |
| + contents_view_ = new MessageCenterView(this); |
| bubble_view()->AddChildView(contents_view_); |
| // Resize the content of the bubble view to the given bubble size. This is |
| // necessary in case of the bubble border forcing a bigger size then the |
| @@ -468,8 +479,8 @@ void MessageCenterBubble::UpdateBubbleView() { |
| if (!bubble_view()) |
| return; // Could get called after view is closed |
| const NotificationList::Notifications& notifications = |
| - list_delegate()->GetNotificationList()->GetNotifications(); |
| - contents_view_->Update(notifications); |
| + message_center()->notification_list()->GetNotifications(); |
| + contents_view_->UpdateAllNotifications(notifications); |
| bubble_view()->Show(); |
| bubble_view()->UpdateBubble(); |
| } |
| @@ -480,6 +491,61 @@ void MessageCenterBubble::OnMouseEnteredView() { |
| void MessageCenterBubble::OnMouseExitedView() { |
| } |
| +void MessageCenterBubble::SendRemoveNotification(const std::string& id, |
| + bool by_user) { |
| + message_center()->SendRemoveNotification(id, by_user); |
| +} |
| + |
| +void MessageCenterBubble::SendRemoveAllNotifications(bool by_user) { |
| + message_center()->SendRemoveAllNotifications(by_user); |
| +} |
| + |
| +void MessageCenterBubble::DisableNotificationByExtension( |
| + const std::string& id) { |
| + message_center()->DisableNotificationByExtension(id); |
| +} |
| + |
| +void MessageCenterBubble::DisableNotificationByUrl(const std::string& id) { |
| + message_center()->DisableNotificationByUrl(id); |
| +} |
| + |
| +void MessageCenterBubble::ShowNotificationSettings(const std::string& id) { |
| + message_center()->ShowNotificationSettings(id); |
| +} |
| + |
| +void MessageCenterBubble::ShowNotificationSettingsDialog( |
| + gfx::NativeView context) { |
| + message_center()->ShowNotificationSettingsDialog(context); |
| +} |
| + |
| +void MessageCenterBubble::OnNotificationClicked(const std::string& id) { |
| + message_center()->OnNotificationClicked(id); |
| +} |
| + |
| +void MessageCenterBubble::OnButtonClicked(const std::string& id, |
| + int button_index) { |
| + message_center()->OnButtonClicked(id, button_index); |
| +} |
| + |
| +void MessageCenterBubble::OnExpand(const std::string& id) { |
| + message_center()->OnExpand(id); |
| + |
| + // Update the view corresponding to this notification. |
| + const NotificationList::Notifications& notifications = |
| + message_center()->notification_list()->GetNotifications(); |
| + for (NotificationList::Notifications::const_iterator iter = |
| + notifications.begin(); iter != notifications.end(); ++iter) { |
| + if ((*iter)->id() == id) { |
| + contents_view_->UpdateOneNotification(*(*iter)); |
| + break; |
| + } |
| + } |
| +} |
| + |
| +void MessageCenterBubble::OnQuietModeChanged(bool quiet_mode) { |
| + message_center()->OnQuietModeChanged(quiet_mode); |
| +} |
| + |
|
dharcourt
2013/03/02 02:08:02
This isn't now only in NotificationList::Delegate
|
| size_t MessageCenterBubble::NumMessageViewsForTest() const { |
| return contents_view_->NumMessageViews(); |
| } |