| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/message_center/message_center_bubble.h" |
| |
| #include "grit/ui_strings.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/gfx/size.h" |
| #include "ui/message_center/message_view.h" |
| #include "ui/message_center/message_view_factory.h" |
| #include "ui/views/controls/button/text_button.h" |
| #include "ui/views/controls/label.h" |
| #include "ui/views/controls/scroll_view.h" |
| #include "ui/views/layout/box_layout.h" |
| #include "ui/views/layout/grid_layout.h" |
| #include "ui/views/painter.h" |
| #include "ui/views/view.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace message_center { |
| |
| namespace { |
| |
| const int kMessageBubbleBaseMinHeight = 80; |
| const int kMessageBubbleBaseMaxHeight = 400; |
| const SkColor kBorderDarkColor = SkColorSetRGB(0xaa, 0xaa, 0xaa); |
| |
| // The view for the buttons at the bottom of the web notification tray. |
| class WebNotificationButtonView : public views::View, |
| public views::ButtonListener { |
| public: |
| explicit WebNotificationButtonView(NotificationList::Delegate* list_delegate) |
| : list_delegate_(list_delegate), |
| close_all_button_(NULL) { |
| set_background(views::Background::CreateBackgroundPainter( |
| true, |
| views::Painter::CreateVerticalGradient( |
| MessageBubbleBase::kHeaderBackgroundColorLight, |
| MessageBubbleBase::kHeaderBackgroundColorDark))); |
| set_border(views::Border::CreateSolidSidedBorder( |
| 2, 0, 0, 0, kBorderDarkColor)); |
| |
| views::GridLayout* layout = new views::GridLayout(this); |
| SetLayoutManager(layout); |
| views::ColumnSet* columns = layout->AddColumnSet(0); |
| columns->AddPaddingColumn(100, 0); |
| columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, |
| 0, /* resize percent */ |
| views::GridLayout::USE_PREF, 0, 0); |
| columns->AddPaddingColumn(0, 4); |
| |
| ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| close_all_button_ = new views::TextButton( |
| this, rb.GetLocalizedString(IDS_MESSAGE_CENTER_CLEAR_ALL)); |
| close_all_button_->set_alignment(views::TextButton::ALIGN_CENTER); |
| close_all_button_->set_focusable(true); |
| close_all_button_->set_request_focus_on_press(false); |
| |
| layout->AddPaddingRow(0, 4); |
| layout->StartRow(0, 0); |
| layout->AddView(close_all_button_); |
| } |
| |
| virtual ~WebNotificationButtonView() {} |
| |
| void SetCloseAllVisible(bool visible) { |
| close_all_button_->SetVisible(visible); |
| } |
| |
| // Overridden from ButtonListener. |
| virtual void ButtonPressed(views::Button* sender, |
| const ui::Event& event) OVERRIDE { |
| if (sender == close_all_button_) |
| list_delegate_->SendRemoveAllNotifications(); |
| } |
| |
| private: |
| NotificationList::Delegate* list_delegate_; |
| views::TextButton* close_all_button_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView); |
| }; |
| |
| // A custom scroll-view that has a specified size. |
| class FixedSizedScrollView : public views::ScrollView { |
| public: |
| FixedSizedScrollView() { |
| set_focusable(true); |
| set_notify_enter_exit_on_child(true); |
| } |
| |
| virtual ~FixedSizedScrollView() {} |
| |
| void SetFixedSize(const gfx::Size& size) { |
| if (fixed_size_ == size) |
| return; |
| fixed_size_ = size; |
| PreferredSizeChanged(); |
| } |
| |
| // views::View overrides. |
| virtual gfx::Size GetPreferredSize() OVERRIDE { |
| gfx::Size size = fixed_size_.IsEmpty() ? |
| contents()->GetPreferredSize() : fixed_size_; |
| 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); |
| |
| views::ScrollView::Layout(); |
| if (!vertical_scroll_bar()->visible()) { |
| gfx::Rect bounds = contents()->bounds(); |
| bounds.set_width(bounds.width() + GetScrollBarWidth()); |
| contents()->SetBoundsRect(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); |
| } |
| |
| private: |
| gfx::Size fixed_size_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FixedSizedScrollView); |
| }; |
| |
| // Container for the messages. |
| class ScrollContentView : public views::View { |
| public: |
| ScrollContentView() { |
| views::BoxLayout* layout = |
| new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1); |
| layout->set_spread_blank_space(true); |
| SetLayoutManager(layout); |
| } |
| |
| virtual ~ScrollContentView() { |
| } |
| |
| virtual gfx::Size GetPreferredSize() OVERRIDE { |
| if (!preferred_size_.IsEmpty()) |
| return preferred_size_; |
| return views::View::GetPreferredSize(); |
| } |
| |
| void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; } |
| |
| private: |
| gfx::Size preferred_size_; |
| DISALLOW_COPY_AND_ASSIGN(ScrollContentView); |
| }; |
| |
| } // namespace |
| |
| // Message Center contents. |
| class MessageCenterContentsView : public views::View { |
| public: |
| explicit MessageCenterContentsView(NotificationList::Delegate* list_delegate) |
| : list_delegate_(list_delegate) { |
| SetLayoutManager( |
| new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); |
| |
| scroll_content_ = new ScrollContentView; |
| scroller_ = new FixedSizedScrollView; |
| scroller_->SetContents(scroll_content_); |
| AddChildView(scroller_); |
| |
| scroller_->SetPaintToLayer(true); |
| scroller_->SetFillsBoundsOpaquely(false); |
| scroller_->layer()->SetMasksToBounds(true); |
| |
| button_view_ = new WebNotificationButtonView(list_delegate); |
| AddChildView(button_view_); |
| } |
| |
| void FocusContents() { |
| scroller_->RequestFocus(); |
| } |
| |
| void Update(const NotificationList::Notifications& notifications) { |
| scroll_content_->RemoveAllChildViews(true); |
| scroll_content_->set_preferred_size(gfx::Size()); |
| size_t num_children = 0; |
| for (NotificationList::Notifications::const_iterator iter = |
| notifications.begin(); iter != notifications.end(); ++iter) { |
| MessageView* view = |
| MessageViewFactory::ViewForNotification(*iter, list_delegate_); |
| view->set_scroller(scroller_); |
| view->SetUpView(); |
| scroll_content_->AddChildView(view); |
| if (++num_children >= |
| NotificationList::kMaxVisibleMessageCenterNotifications) { |
| break; |
| } |
| } |
| if (num_children == 0) { |
| views::Label* label = new views::Label(l10n_util::GetStringUTF16( |
| IDS_MESSAGE_CENTER_NO_MESSAGES)); |
| label->SetFont(label->font().DeriveFont(1)); |
| label->SetEnabledColor(SK_ColorGRAY); |
| scroll_content_->AddChildView(label); |
| button_view_->SetCloseAllVisible(false); |
| } else { |
| button_view_->SetCloseAllVisible(true); |
| } |
| SizeScrollContent(); |
| Layout(); |
| if (GetWidget()) |
| GetWidget()->GetRootView()->SchedulePaint(); |
| } |
| |
| size_t NumMessageViews() const { |
| return scroll_content_->child_count(); |
| } |
| |
| 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 = kMessageBubbleBaseMaxHeight - 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(); |
| } |
| |
| NotificationList::Delegate* list_delegate_; |
| FixedSizedScrollView* scroller_; |
| ScrollContentView* scroll_content_; |
| WebNotificationButtonView* button_view_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MessageCenterContentsView); |
| }; |
| |
| // Message Center Bubble. |
| MessageCenterBubble::MessageCenterBubble(NotificationList::Delegate* delegate) |
| : MessageBubbleBase(delegate), |
| contents_view_(NULL) { |
| } |
| |
| MessageCenterBubble::~MessageCenterBubble() {} |
| |
| views::TrayBubbleView::InitParams MessageCenterBubble::GetInitParams( |
| views::TrayBubbleView::AnchorAlignment anchor_alignment) { |
| views::TrayBubbleView::InitParams init_params = |
| GetDefaultInitParams(anchor_alignment); |
| init_params.max_height = kMessageBubbleBaseMaxHeight; |
| init_params.can_activate = true; |
| return init_params; |
| } |
| |
| void MessageCenterBubble::InitializeContents( |
| views::TrayBubbleView* new_bubble_view) { |
| set_bubble_view(new_bubble_view); |
| contents_view_ = new MessageCenterContentsView(list_delegate()); |
| bubble_view()->AddChildView(contents_view_); |
| UpdateBubbleView(); |
| contents_view_->FocusContents(); |
| } |
| |
| void MessageCenterBubble::OnBubbleViewDestroyed() { |
| contents_view_ = NULL; |
| } |
| |
| void MessageCenterBubble::UpdateBubbleView() { |
| if (!bubble_view()) |
| return; // Could get called after view is closed |
| NotificationList::Notifications notifications; |
| list_delegate()->GetNotificationList()->GetNotifications(¬ifications); |
| contents_view_->Update(notifications); |
| bubble_view()->Show(); |
| bubble_view()->UpdateBubble(); |
| } |
| |
| void MessageCenterBubble::OnMouseEnteredView() { |
| } |
| |
| void MessageCenterBubble::OnMouseExitedView() { |
| } |
| |
| size_t MessageCenterBubble::NumMessageViewsForTest() const { |
| return contents_view_->NumMessageViews(); |
| } |
| |
| } // namespace message_center |