diff options
31 files changed, 606 insertions, 404 deletions
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc index b58845c..7895d18 100644 --- a/ash/system/web_notification/web_notification_tray_unittest.cc +++ b/ash/system/web_notification/web_notification_tray_unittest.cc @@ -74,6 +74,10 @@ class TestDelegate : public message_center::MessageCenter::Delegate { virtual void OnClicked(const std::string& notifcation_id) OVERRIDE { } + virtual void OnButtonClicked(const std::string& id, + int button_index) OVERRIDE { + } + void AddNotification(WebNotificationTray* tray, const std::string& id) { notification_ids_.insert(id); get_message_center()->AddNotification( @@ -222,10 +226,8 @@ TEST_F(WebNotificationTrayTest, ManyPopupNotifications) { EXPECT_EQ(notifications_to_add, get_message_center()->NotificationCount()); if (message_center::IsRichNotificationEnabled()) { - NotificationList::Delegate* list_delegate = - tray->popup_collection_.get()->list_delegate_; NotificationList::PopupNotifications popups = - list_delegate->GetNotificationList()->GetPopupNotifications(); + get_message_center()->notification_list()->GetPopupNotifications(); EXPECT_EQ(NotificationList::kMaxVisiblePopupNotifications, popups.size()); } else { EXPECT_EQ(NotificationList::kMaxVisiblePopupNotifications, diff --git a/chrome/browser/extensions/api/notifications/notifications_apitest.cc b/chrome/browser/extensions/api/notifications/notifications_apitest.cc index 523643d..27bb6f3 100644 --- a/chrome/browser/extensions/api/notifications/notifications_apitest.cc +++ b/chrome/browser/extensions/api/notifications/notifications_apitest.cc @@ -283,18 +283,6 @@ IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestByUser) { true); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } - - { - ResultCatcher catcher; - g_browser_process->message_center()->SendRemoveAllNotifications(false); - EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); - } - - { - ResultCatcher catcher; - g_browser_process->message_center()->SendRemoveAllNotifications(true); - EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); - } } #endif diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc index 220885c..af461a7 100644 --- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc +++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc @@ -125,11 +125,11 @@ class MessageCenterExtensionCrashRecoveryTest message_center::MessageCenter::Get(); ASSERT_GT(message_center->NotificationCount(), index); message_center::NotificationList::Notifications::reverse_iterator it = - message_center->GetNotificationList()->GetNotifications().rbegin(); + message_center->notification_list()->GetNotifications().rbegin(); for (size_t i=0; i < index; ++i) it++; std::string id = (*it)->id(); - message_center->OnNotificationClicked(id); + message_center->OnClicked(id); WaitForExtensionLoad(); } @@ -138,7 +138,7 @@ class MessageCenterExtensionCrashRecoveryTest message_center::MessageCenter::Get(); ASSERT_GT(message_center->NotificationCount(), index); message_center::NotificationList::Notifications::reverse_iterator it = - message_center->GetNotificationList()->GetNotifications().rbegin(); + message_center->notification_list()->GetNotifications().rbegin(); for (size_t i=0; i < index; i++) { it++; } ASSERT_TRUE( g_browser_process->notification_ui_manager()->CancelById((*it)->id())); diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc index 347f26b..38d1995 100644 --- a/chrome/browser/notifications/message_center_notification_manager.cc +++ b/chrome/browser/notifications/message_center_notification_manager.cc @@ -141,7 +141,7 @@ bool MessageCenterNotificationManager::UpdateNotification( old_notification->profile()->IsSameProfile(profile)) { std::string old_id = old_notification->notification().notification_id(); - DCHECK(message_center_->GetNotificationList()->HasNotification(old_id)); + DCHECK(message_center_->notification_list()->HasNotification(old_id)); // Add/remove notification in the local list but just update the same // one in MessageCenter. diff --git a/chrome/browser/ui/views/message_center/web_notification_tray_win_browsertest.cc b/chrome/browser/ui/views/message_center/web_notification_tray_win_browsertest.cc index b7c9c39..efe5429 100644 --- a/chrome/browser/ui/views/message_center/web_notification_tray_win_browsertest.cc +++ b/chrome/browser/ui/views/message_center/web_notification_tray_win_browsertest.cc @@ -52,9 +52,10 @@ class TestDelegate : public message_center::MessageCenter::Delegate { virtual void DisableExtension(const std::string& notification_id) OVERRIDE { } virtual void ShowSettings(const std::string& notification_id) OVERRIDE { } - virtual void OnClicked(const std::string& notification_id) OVERRIDE { } virtual void ShowSettingsDialog(gfx::NativeView context) OVERRIDE { } - + virtual void OnClicked(const std::string& notification_id) OVERRIDE { } + virtual void OnButtonClicked(const std::string& id, + int button_index) OVERRIDE {} void AddNotification(const std::string& id) { notification_ids_.insert(id); diff --git a/ui/message_center/message_center.cc b/ui/message_center/message_center.cc index 29492a8..9f67ecd 100644 --- a/ui/message_center/message_center.cc +++ b/ui/message_center/message_center.cc @@ -36,6 +36,12 @@ void MessageCenter::Shutdown() { } //------------------------------------------------------------------------------ + +MessageCenter::Delegate::~Delegate() { +} + +//------------------------------------------------------------------------------ + MessageCenter::MessageCenter() : delegate_(NULL) { notification_list_.reset(new NotificationList(this)); @@ -126,15 +132,14 @@ void MessageCenter::SetNotificationButtonIcon( } //------------------------------------------------------------------------------ -// Overridden from NotificationList::Delegate. +// Overridden from NotificationChangeObserver: -void MessageCenter::SendRemoveNotification(const std::string& id, - bool by_user) { +void MessageCenter::OnRemoveNotification(const std::string& id, bool by_user) { if (delegate_) delegate_->NotificationRemoved(id, by_user); } -void MessageCenter::SendRemoveAllNotifications(bool by_user) { +void MessageCenter::OnRemoveAllNotifications(bool by_user) { if (delegate_) { const NotificationList::Notifications& notifications = notification_list_->GetNotifications(); @@ -149,7 +154,7 @@ void MessageCenter::SendRemoveAllNotifications(bool by_user) { } } -void MessageCenter::DisableNotificationByExtension( +void MessageCenter::OnDisableNotificationsByExtension( const std::string& id) { if (delegate_) delegate_->DisableExtension(id); @@ -158,23 +163,27 @@ void MessageCenter::DisableNotificationByExtension( notification_list_->SendRemoveNotificationsByExtension(id); } -void MessageCenter::DisableNotificationByUrl(const std::string& id) { +void MessageCenter::OnDisableNotificationsByUrl(const std::string& id) { if (delegate_) delegate_->DisableNotificationsFromSource(id); notification_list_->SendRemoveNotificationsBySource(id); } -void MessageCenter::ShowNotificationSettings(const std::string& id) { +void MessageCenter::OnShowNotificationSettings(const std::string& id) { if (delegate_) delegate_->ShowSettings(id); } -void MessageCenter::ShowNotificationSettingsDialog(gfx::NativeView context) { +void MessageCenter::OnShowNotificationSettingsDialog(gfx::NativeView context) { if (delegate_) delegate_->ShowSettingsDialog(context); } -void MessageCenter::OnNotificationClicked(const std::string& id) { +void MessageCenter::OnExpanded(const std::string& id) { + notification_list_->MarkNotificationAsExpanded(id); +} + +void MessageCenter::OnClicked(const std::string& id) { if (delegate_) delegate_->OnClicked(id); if (HasPopupNotifications()) { @@ -183,10 +192,6 @@ void MessageCenter::OnNotificationClicked(const std::string& id) { } } -void MessageCenter::OnQuietModeChanged(bool quiet_mode) { - NotifyMessageCenterChanged(true); -} - void MessageCenter::OnButtonClicked(const std::string& id, int button_index) { if (delegate_) delegate_->OnButtonClicked(id, button_index); @@ -196,12 +201,17 @@ void MessageCenter::OnButtonClicked(const std::string& id, int button_index) { } } -NotificationList* MessageCenter::GetNotificationList() { - return notification_list_.get(); +//------------------------------------------------------------------------------ +// Overridden from NotificationList::Delegate: + +void MessageCenter::SendRemoveNotification(const std::string& id, + bool by_user) { + if (delegate_) + delegate_->NotificationRemoved(id, by_user); } -void MessageCenter::Delegate::OnButtonClicked(const std::string& id, - int button_index) { +void MessageCenter::OnQuietModeChanged(bool quiet_mode) { + NotifyMessageCenterChanged(true); } //------------------------------------------------------------------------------ diff --git a/ui/message_center/message_center.gyp b/ui/message_center/message_center.gyp index 04847d1..46c8f8c 100644 --- a/ui/message_center/message_center.gyp +++ b/ui/message_center/message_center.gyp @@ -40,6 +40,7 @@ 'message_center_util.h', 'notification.cc', 'notification.h', + 'notification_change_observer.h', 'notification_list.cc', 'notification_list.h', 'notification_types.cc', diff --git a/ui/message_center/message_center.h b/ui/message_center/message_center.h index a0c6e94..58575bd 100644 --- a/ui/message_center/message_center.h +++ b/ui/message_center/message_center.h @@ -11,6 +11,7 @@ #include "base/observer_list.h" #include "ui/gfx/native_widget_types.h" #include "ui/message_center/message_center_export.h" +#include "ui/message_center/notification_change_observer.h" #include "ui/message_center/notification_list.h" #include "ui/message_center/notification_types.h" @@ -28,7 +29,8 @@ class DictionaryValue; namespace message_center { -class MESSAGE_CENTER_EXPORT MessageCenter : public NotificationList::Delegate { +class MESSAGE_CENTER_EXPORT MessageCenter : public NotificationChangeObserver, + public NotificationList::Delegate { public: // Creates the global message center object. static void Initialize(); @@ -51,6 +53,8 @@ class MESSAGE_CENTER_EXPORT MessageCenter : public NotificationList::Delegate { class MESSAGE_CENTER_EXPORT Delegate { public: + virtual ~Delegate(); + // Called when the notification associated with |notification_id| is // removed (i.e. closed by the user). virtual void NotificationRemoved(const std::string& notification_id, @@ -81,10 +85,7 @@ class MESSAGE_CENTER_EXPORT MessageCenter : public NotificationList::Delegate { // TODO(miket): consider providing default implementations for the pure // virtuals above, to avoid changing so many files in disparate parts of // the codebase each time we enhance this interface. - virtual void OnButtonClicked(const std::string& id, int button_index); - - protected: - virtual ~Delegate() {} + virtual void OnButtonClicked(const std::string& id, int button_index) = 0; }; // Called to set the delegate. Generally called only once, except in tests. @@ -145,19 +146,25 @@ class MESSAGE_CENTER_EXPORT MessageCenter : public NotificationList::Delegate { NotificationList* notification_list() { return notification_list_.get(); } bool quiet_mode() const { return notification_list_->quiet_mode(); } - // Overridden from NotificationList::Delegate. + // Overridden from NotificationChangeObserver: + virtual void OnRemoveNotification(const std::string& id, bool by_user) + OVERRIDE; + virtual void OnRemoveAllNotifications(bool by_user) OVERRIDE; + virtual void OnDisableNotificationsByExtension(const std::string& id) + OVERRIDE; + virtual void OnDisableNotificationsByUrl(const std::string& id) OVERRIDE; + virtual void OnShowNotificationSettings(const std::string& id) OVERRIDE; + virtual void OnShowNotificationSettingsDialog(gfx::NativeView context) + OVERRIDE; + virtual void OnExpanded(const std::string& id) OVERRIDE; + virtual void OnClicked(const std::string& id) OVERRIDE; + virtual void OnButtonClicked(const std::string& id, int button_index) + OVERRIDE; + + // Overridden from NotificationList::Delegate: virtual void SendRemoveNotification(const std::string& id, bool by_user) OVERRIDE; - virtual void SendRemoveAllNotifications(bool by_user) OVERRIDE; - virtual void DisableNotificationByExtension(const std::string& id) OVERRIDE; - virtual void DisableNotificationByUrl(const std::string& id) OVERRIDE; - virtual void ShowNotificationSettings(const std::string& id) OVERRIDE; - virtual void ShowNotificationSettingsDialog(gfx::NativeView context) OVERRIDE; - virtual void OnNotificationClicked(const std::string& id) OVERRIDE; virtual void OnQuietModeChanged(bool quiet_mode) OVERRIDE; - virtual void OnButtonClicked(const std::string& id, int button_index) - OVERRIDE; - virtual NotificationList* GetNotificationList() OVERRIDE; protected: MessageCenter(); diff --git a/ui/message_center/message_center_tray.h b/ui/message_center/message_center_tray.h index f40026f..9a3b33c0 100644 --- a/ui/message_center/message_center_tray.h +++ b/ui/message_center/message_center_tray.h @@ -60,7 +60,7 @@ class MESSAGE_CENTER_EXPORT MessageCenterTray } message_center::MessageCenter* message_center() { return message_center_; } - // Overridden from message_center::MessageCenter::Observer. + // Overridden from message_center::MessageCenter::Observer: virtual void OnMessageCenterChanged(bool new_notification) OVERRIDE; // Overridden from SimpleMenuModel::Delegate. diff --git a/ui/message_center/notification.cc b/ui/message_center/notification.cc index 4bd1911..284d278 100644 --- a/ui/message_center/notification.cc +++ b/ui/message_center/notification.cc @@ -39,8 +39,9 @@ Notification::Notification(NotificationType type, priority_(DEFAULT_PRIORITY), timestamp_(base::Time::Now()), serial_number_(g_next_serial_number_++), + shown_as_popup_(false), is_read_(false), - shown_as_popup_(false) { + is_expanded_(false) { // This can override some data members initialized to deafule values above. ApplyOptionalFields(optional_fields); } diff --git a/ui/message_center/notification.h b/ui/message_center/notification.h index 2aed7d5..ffb301b 100644 --- a/ui/message_center/notification.h +++ b/ui/message_center/notification.h @@ -57,8 +57,8 @@ class MESSAGE_CENTER_EXPORT Notification { // End unpacked values. // Images fetched asynchronously. - const gfx::Image& primary_icon() const { return primary_icon_; } - void set_primary_icon(const gfx::Image& icon) { primary_icon_ = icon; } + const gfx::Image& icon() const { return icon_; } + void set_icon(const gfx::Image& icon) { icon_ = icon; } const gfx::Image& image() const { return image_; } void set_image(const gfx::Image& image) { image_ = image; } @@ -67,15 +67,19 @@ class MESSAGE_CENTER_EXPORT Notification { const std::vector<ButtonInfo>& buttons() const { return buttons_; } bool SetButtonIcon(size_t index, const gfx::Image& icon); - // Status in MessageCenter. - bool is_read() const { return is_read_; } - void set_is_read(bool is_read) { is_read_ = is_read; } - bool shown_as_popup() const { return shown_as_popup_; } void set_shown_as_popup(bool shown_as_popup) { shown_as_popup_ = shown_as_popup; } + // Read status in the message center. + bool is_read() const { return is_read_; } + void set_is_read(bool read) { is_read_ = read; } + + // Expanded status in the message center (not the popups). + bool is_expanded() const { return is_expanded_; } + void set_is_expanded(bool expanded) { is_expanded_ = expanded; } + // Used to keep the order of notifications with the same timestamp. // The notification with lesser serial_number is considered 'older'. unsigned serial_number() { return serial_number_; } @@ -96,11 +100,12 @@ class MESSAGE_CENTER_EXPORT Notification { unsigned serial_number_; string16 expanded_message_; std::vector<NotificationItem> items_; - gfx::Image primary_icon_; + gfx::Image icon_; gfx::Image image_; std::vector<ButtonInfo> buttons_; + bool shown_as_popup_; // True if this has been shown as a popup. bool is_read_; // True if this has been seen in the message center. - bool shown_as_popup_; // True if this has been shown as a popup notification. + bool is_expanded_; // True if this has been expanded in the message center. DISALLOW_COPY_AND_ASSIGN(Notification); }; diff --git a/ui/message_center/notification_change_observer.h b/ui/message_center/notification_change_observer.h new file mode 100644 index 0000000..ff45685 --- /dev/null +++ b/ui/message_center/notification_change_observer.h @@ -0,0 +1,35 @@ +// Copyright (c) 2013 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. + +#ifndef UI_MESSAGE_CENTER_NOTIFICATION_CHANGE_OBSERVER_H_ +#define UI_MESSAGE_CENTER_NOTIFICATION_CHANGE_OBSERVER_H_ + +#include <string> + +#include "ui/gfx/native_widget_types.h" + +namespace message_center { + +// For classes that need to handle or propagate notification changes. +class MESSAGE_CENTER_EXPORT NotificationChangeObserver { + public: + virtual ~NotificationChangeObserver() {}; + + virtual void OnRemoveNotification(const std::string& id, bool by_user) {}; + virtual void OnRemoveAllNotifications(bool by_user) {}; + + virtual void OnDisableNotificationsByExtension(const std::string& id) {}; + virtual void OnDisableNotificationsByUrl(const std::string& id) {}; + + virtual void OnShowNotificationSettings(const std::string& id) {}; + virtual void OnShowNotificationSettingsDialog(gfx::NativeView context) {}; + + virtual void OnExpanded(const std::string& id) {}; + virtual void OnClicked(const std::string& id) {}; + virtual void OnButtonClicked(const std::string& id, int button_index) {}; +}; + +} // namespace message_center + +#endif // UI_MESSAGE_CENTER_NOTIFICATION_CHANGE_OBSERVER_H_ diff --git a/ui/message_center/notification_list.cc b/ui/message_center/notification_list.cc index 4f0c69a..2e108f9 100644 --- a/ui/message_center/notification_list.cc +++ b/ui/message_center/notification_list.cc @@ -38,6 +38,9 @@ bool CompareTimestampSerial::operator()(Notification* n1, Notification* n2) { const size_t NotificationList::kMaxVisibleMessageCenterNotifications = 100; const size_t NotificationList::kMaxVisiblePopupNotifications = 2; +NotificationList::Delegate::~Delegate() { +} + NotificationList::NotificationList(Delegate* delegate) : delegate_(delegate), message_center_visible_(false), @@ -157,7 +160,7 @@ bool NotificationList::SetNotificationIcon(const std::string& notification_id, Notifications::iterator iter = GetNotification(notification_id); if (iter == notifications_.end()) return false; - (*iter)->set_primary_icon(image); + (*iter)->set_icon(image); return true; } @@ -247,6 +250,12 @@ void NotificationList::MarkSinglePopupAsShown( } } +void NotificationList::MarkNotificationAsExpanded(const std::string& id) { + Notifications::iterator iter = GetNotification(id); + if (iter != notifications_.end()) + (*iter)->set_is_expanded(true); +} + void NotificationList::SetQuietMode(bool quiet_mode) { SetQuietModeInternal(quiet_mode); quiet_mode_timer_.reset(); diff --git a/ui/message_center/notification_list.h b/ui/message_center/notification_list.h index be8718c..9a4c957 100644 --- a/ui/message_center/notification_list.h +++ b/ui/message_center/notification_list.h @@ -45,37 +45,14 @@ class MESSAGE_CENTER_EXPORT NotificationList { class MESSAGE_CENTER_EXPORT Delegate { public: - Delegate() {} - virtual ~Delegate() {} + virtual ~Delegate(); // Removes notifications virtual void SendRemoveNotification(const std::string& id, bool by_user) = 0; - virtual void SendRemoveAllNotifications(bool by_user) = 0; - - // Disables notifications - virtual void DisableNotificationByExtension(const std::string& id) = 0; - virtual void DisableNotificationByUrl(const std::string& id) = 0; - - // Requests the Delegate to show the settings page. - virtual void ShowNotificationSettings(const std::string& id) = 0; - - // Requests the Delegate to show the settings dialog. - virtual void ShowNotificationSettingsDialog(gfx::NativeView context) = 0; - - // Called when a notification is clicked on. - virtual void OnNotificationClicked(const std::string& id) = 0; // Called when the quiet mode status has been changed. virtual void OnQuietModeChanged(bool quiet_mode) = 0; - - // Called when a button in a notification is clicked. |button_index| - // indicates which button was clicked, zero-indexed (button one is 0, - // button two is 1). - virtual void OnButtonClicked(const std::string& id, int button_index) = 0; - - // Returns the list of notifications to display. - virtual NotificationList* GetNotificationList() = 0; }; explicit NotificationList(Delegate* delegate); @@ -139,6 +116,9 @@ class MESSAGE_CENTER_EXPORT NotificationList { void MarkSinglePopupAsShown(const std::string& id, bool mark_notification_as_read); + // Marks the specified notification as expanded in the notification center. + void MarkNotificationAsExpanded(const std::string& id); + bool quiet_mode() const { return quiet_mode_; } // Sets the current quiet mode status to |quiet_mode|. The new status is not diff --git a/ui/message_center/notification_list_unittest.cc b/ui/message_center/notification_list_unittest.cc index 4cf791e..aa4ab66 100644 --- a/ui/message_center/notification_list_unittest.cc +++ b/ui/message_center/notification_list_unittest.cc @@ -27,42 +27,15 @@ class MockNotificationListDelegate : public NotificationList::Delegate { } private: - // NotificationList::Delegate overrides: + // Overridden from NotificationList::Delegate: virtual void SendRemoveNotification(const std::string& id, bool by_user) OVERRIDE { send_remove_count_++; } - virtual void SendRemoveAllNotifications(bool by_user) OVERRIDE { - } - - virtual void DisableNotificationByExtension(const std::string& id) OVERRIDE { - } - - virtual void DisableNotificationByUrl(const std::string& id) OVERRIDE { - } - - virtual void ShowNotificationSettings(const std::string& id) OVERRIDE { - } - - virtual void ShowNotificationSettingsDialog( - gfx::NativeView context) OVERRIDE { - } - - virtual void OnNotificationClicked(const std::string& id) OVERRIDE { - } - virtual void OnQuietModeChanged(bool quiet_mode) OVERRIDE { } - virtual void OnButtonClicked(const std::string& id, - int button_index) OVERRIDE { - } - - virtual NotificationList* GetNotificationList() OVERRIDE { - return NULL; - } - size_t send_remove_count_; DISALLOW_COPY_AND_ASSIGN(MockNotificationListDelegate); }; diff --git a/ui/message_center/views/message_bubble_base.cc b/ui/message_center/views/message_bubble_base.cc index d7fc5e7..7438496 100644 --- a/ui/message_center/views/message_bubble_base.cc +++ b/ui/message_center/views/message_bubble_base.cc @@ -26,8 +26,8 @@ const SkColor MessageBubbleBase::kHeaderBackgroundColorLight = const SkColor MessageBubbleBase::kHeaderBackgroundColorDark = SkColorSetRGB(0xe7, 0xe7, 0xe7); -MessageBubbleBase::MessageBubbleBase(NotificationList::Delegate* list_delegate) - : list_delegate_(list_delegate), +MessageBubbleBase::MessageBubbleBase(MessageCenter* message_center) + : message_center_(message_center), bubble_view_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), max_height_(kMessageBubbleBaseDefaultMaxHeight) { diff --git a/ui/message_center/views/message_bubble_base.h b/ui/message_center/views/message_bubble_base.h index f43c9b7..c7255f8 100644 --- a/ui/message_center/views/message_bubble_base.h +++ b/ui/message_center/views/message_bubble_base.h @@ -6,15 +6,15 @@ #define UI_MESSAGE_CENTER_VIEWS_MESSAGE_BUBBLE_BASE_H_ #include "base/memory/scoped_ptr.h" +#include "ui/message_center/message_center.h" #include "ui/message_center/message_center_export.h" -#include "ui/message_center/notification_list.h" #include "ui/views/bubble/tray_bubble_view.h" namespace message_center { class MESSAGE_CENTER_EXPORT MessageBubbleBase { public: - explicit MessageBubbleBase(NotificationList::Delegate* list_delegate); + explicit MessageBubbleBase(MessageCenter* message_center); virtual ~MessageBubbleBase(); @@ -61,13 +61,13 @@ class MESSAGE_CENTER_EXPORT MessageBubbleBase { protected: views::TrayBubbleView::InitParams GetDefaultInitParams( views::TrayBubbleView::AnchorAlignment anchor_alignment); - NotificationList::Delegate* list_delegate() { return list_delegate_; } + MessageCenter* message_center() { return message_center_; } void set_bubble_view(views::TrayBubbleView* bubble_view) { bubble_view_ = bubble_view; } private: - NotificationList::Delegate* list_delegate_; + MessageCenter* message_center_; views::TrayBubbleView* bubble_view_; base::WeakPtrFactory<MessageBubbleBase> weak_ptr_factory_; int max_height_; diff --git a/ui/message_center/views/message_center_bubble.cc b/ui/message_center/views/message_center_bubble.cc index a64c854..b91854e 100644 --- a/ui/message_center/views/message_center_bubble.cc +++ b/ui/message_center/views/message_center_bubble.cc @@ -4,6 +4,8 @@ #include "ui/message_center/views/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" @@ -49,8 +51,8 @@ const SkColor kFocusBorderColor = SkColorSetRGB(0x40, 0x80, 0xfa); class WebNotificationButtonViewBase : public views::View { public: - WebNotificationButtonViewBase(NotificationList::Delegate* list_delegate) - : list_delegate_(list_delegate), + WebNotificationButtonViewBase(NotificationChangeObserver* observer) + : observer_(observer), close_all_button_(NULL) {} void SetCloseAllVisible(bool visible) { @@ -63,11 +65,11 @@ class WebNotificationButtonViewBase : public views::View { } protected: - NotificationList::Delegate* list_delegate() { return list_delegate_; } + NotificationChangeObserver* observer() { return observer_; } views::Button* close_all_button() { return close_all_button_; } private: - NotificationList::Delegate* list_delegate_; + NotificationChangeObserver* observer_; // Weak reference. views::Button* close_all_button_; DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonViewBase); @@ -77,8 +79,8 @@ class WebNotificationButtonViewBase : public views::View { class WebNotificationButtonView : public WebNotificationButtonViewBase, public views::ButtonListener { public: - explicit WebNotificationButtonView(NotificationList::Delegate* list_delegate) - : WebNotificationButtonViewBase(list_delegate) { + explicit WebNotificationButtonView(NotificationChangeObserver* observer) + : WebNotificationButtonViewBase(observer) { set_background(views::Background::CreateBackgroundPainter( true, views::Painter::CreateVerticalGradient( @@ -111,11 +113,11 @@ 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()) - list_delegate()->SendRemoveAllNotifications(true); // Action by user. + observer()->OnRemoveAllNotifications(true); // Action by user. } private: @@ -134,7 +136,7 @@ class WebNotificationButton : public views::TextButton { } protected: - // views::View overrides: + // Overridden from views::View: virtual gfx::Size GetPreferredSize() OVERRIDE { // Returns an empty size when invisible, to trim its space in the parent's // GridLayout. @@ -164,8 +166,8 @@ class WebNotificationButton : public views::TextButton { class WebNotificationButtonView2 : public WebNotificationButtonViewBase, public views::ButtonListener { public: - explicit WebNotificationButtonView2(NotificationList::Delegate* list_delegate) - : WebNotificationButtonViewBase(list_delegate) { + explicit WebNotificationButtonView2(NotificationChangeObserver* observer) + : WebNotificationButtonViewBase(observer) { set_background(views::Background::CreateSolidBackground( kMessageCenterBackgroundColor)); set_border(views::Border::CreateSolidSidedBorder( @@ -206,13 +208,13 @@ 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()) - list_delegate()->SendRemoveAllNotifications(true); // Action by user. + observer()->OnRemoveAllNotifications(true); // Action by user. else if (sender == settings_button_) - list_delegate()->ShowNotificationSettingsDialog( + observer()->OnShowNotificationSettingsDialog( GetWidget()->GetNativeView()); else NOTREACHED(); @@ -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_notify_enter_exit_on_child(true); if (IsRichNotificationEnabled()) { set_background(views::Background::CreateSolidBackground( @@ -235,53 +240,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 @@ -308,39 +311,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); @@ -348,31 +345,28 @@ 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_); } void FocusContents() { } - 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)); @@ -380,53 +374,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) { } @@ -448,7 +459,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 @@ -466,8 +477,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(); } @@ -478,6 +489,57 @@ void MessageCenterBubble::OnMouseEnteredView() { void MessageCenterBubble::OnMouseExitedView() { } +void MessageCenterBubble::OnRemoveNotification(const std::string& id, + bool by_user) { + message_center()->OnRemoveNotification(id, by_user); +} + +void MessageCenterBubble::OnRemoveAllNotifications(bool by_user) { + message_center()->OnRemoveAllNotifications(by_user); +} + +void MessageCenterBubble::OnDisableNotificationsByExtension( + const std::string& id) { + message_center()->OnDisableNotificationsByExtension(id); +} + +void MessageCenterBubble::OnDisableNotificationsByUrl(const std::string& id) { + message_center()->OnDisableNotificationsByUrl(id); +} + +void MessageCenterBubble::OnShowNotificationSettings(const std::string& id) { + message_center()->OnShowNotificationSettings(id); +} + +void MessageCenterBubble::OnShowNotificationSettingsDialog( + gfx::NativeView context) { + message_center()->OnShowNotificationSettingsDialog(context); +} + +void MessageCenterBubble::OnClicked(const std::string& id) { + message_center()->OnClicked(id); +} + +void MessageCenterBubble::OnButtonClicked(const std::string& id, + int button_index) { + message_center()->OnButtonClicked(id, button_index); +} + +void MessageCenterBubble::OnExpanded(const std::string& id) { + message_center()->OnExpanded(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; + } + } +} + size_t MessageCenterBubble::NumMessageViewsForTest() const { return contents_view_->NumMessageViews(); } diff --git a/ui/message_center/views/message_center_bubble.h b/ui/message_center/views/message_center_bubble.h index 3b77571..bed2262 100644 --- a/ui/message_center/views/message_center_bubble.h +++ b/ui/message_center/views/message_center_bubble.h @@ -6,21 +6,23 @@ #define UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_BUBBLE_H_ #include "ui/message_center/message_center_export.h" -#include "ui/message_center/notification_list.h" +#include "ui/message_center/notification_change_observer.h" #include "ui/message_center/views/message_bubble_base.h" namespace message_center { -class MessageCenterContentsView; +class MessageCenterView; // Bubble for message center. -class MESSAGE_CENTER_EXPORT MessageCenterBubble : public MessageBubbleBase { +class MESSAGE_CENTER_EXPORT MessageCenterBubble + : public MessageBubbleBase, + public NotificationChangeObserver { public: - explicit MessageCenterBubble(NotificationList::Delegate* delegate); + explicit MessageCenterBubble(MessageCenter* message_center); virtual ~MessageCenterBubble(); - // Overridden from MessageBubbleBase. + // Overridden from MessageBubbleBase: virtual views::TrayBubbleView::InitParams GetInitParams( views::TrayBubbleView::AnchorAlignment anchor_alignment) OVERRIDE; virtual void InitializeContents(views::TrayBubbleView* bubble_view) OVERRIDE; @@ -29,10 +31,25 @@ class MESSAGE_CENTER_EXPORT MessageCenterBubble : public MessageBubbleBase { virtual void OnMouseEnteredView() OVERRIDE; virtual void OnMouseExitedView() OVERRIDE; + // Overridden from NotificationChangeObserver: + virtual void OnRemoveNotification(const std::string& id, bool by_user) + OVERRIDE; + virtual void OnRemoveAllNotifications(bool by_user) OVERRIDE; + virtual void OnDisableNotificationsByExtension(const std::string& id) + OVERRIDE; + virtual void OnDisableNotificationsByUrl(const std::string& id) OVERRIDE; + virtual void OnShowNotificationSettings(const std::string& id) OVERRIDE; + virtual void OnShowNotificationSettingsDialog(gfx::NativeView context) + OVERRIDE; + virtual void OnExpanded(const std::string& id) OVERRIDE; + virtual void OnClicked(const std::string& id) OVERRIDE; + virtual void OnButtonClicked(const std::string& id, + int button_index) OVERRIDE; + size_t NumMessageViewsForTest() const; private: - MessageCenterContentsView* contents_view_; + MessageCenterView* contents_view_; // The maximum height int max_height_; diff --git a/ui/message_center/views/message_popup_bubble.cc b/ui/message_center/views/message_popup_bubble.cc index 696b016..46238dd 100644 --- a/ui/message_center/views/message_popup_bubble.cc +++ b/ui/message_center/views/message_popup_bubble.cc @@ -8,6 +8,7 @@ #include "base/stl_util.h" #include "ui/message_center/message_center_constants.h" #include "ui/message_center/notification.h" +#include "ui/message_center/notification_change_observer.h" #include "ui/message_center/notification_types.h" #include "ui/message_center/views/message_view.h" #include "ui/message_center/views/notification_view.h" @@ -21,7 +22,7 @@ namespace message_center { // Popup notifications contents. class PopupBubbleContentsView : public views::View { public: - explicit PopupBubbleContentsView(NotificationList::Delegate* list_delegate); + explicit PopupBubbleContentsView(NotificationChangeObserver* observer); void Update(const NotificationList::PopupNotifications& popup_notifications); @@ -30,15 +31,15 @@ class PopupBubbleContentsView : public views::View { } private: - NotificationList::Delegate* list_delegate_; + NotificationChangeObserver* observer_; // Weak reference. views::View* content_; DISALLOW_COPY_AND_ASSIGN(PopupBubbleContentsView); }; PopupBubbleContentsView::PopupBubbleContentsView( - NotificationList::Delegate* list_delegate) - : list_delegate_(list_delegate) { + NotificationChangeObserver* observer) + : observer_(observer) { SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); content_ = new views::View; @@ -59,7 +60,11 @@ void PopupBubbleContentsView::Update( for (NotificationList::PopupNotifications::const_iterator iter = popup_notifications.begin(); iter != popup_notifications.end(); ++iter) { - content_->AddChildView(NotificationView::Create(*(*iter), list_delegate_)); + // NotificationViews are expanded by default here because MessagePopupBubble + // hasn't been tested yet with changing subview sizes, and such changes + // could come if those subviews were initially collapsed and allowed to be + // expanded by users. TODO(dharcourt): Fix. + content_->AddChildView(NotificationView::Create(*(*iter), observer_, true)); } content_->SizeToPreferredSize(); content_->InvalidateLayout(); @@ -113,8 +118,8 @@ void MessagePopupBubble::AutocloseTimer::Suspend() { } // MessagePopupBubble -MessagePopupBubble::MessagePopupBubble(NotificationList::Delegate* delegate) - : MessageBubbleBase(delegate), +MessagePopupBubble::MessagePopupBubble(MessageCenter* message_center) + : MessageBubbleBase(message_center), contents_view_(NULL) { } @@ -135,7 +140,7 @@ views::TrayBubbleView::InitParams MessagePopupBubble::GetInitParams( void MessagePopupBubble::InitializeContents( views::TrayBubbleView* new_bubble_view) { set_bubble_view(new_bubble_view); - contents_view_ = new PopupBubbleContentsView(list_delegate()); + contents_view_ = new PopupBubbleContentsView(message_center()); bubble_view()->AddChildView(contents_view_); UpdateBubbleView(); } @@ -146,7 +151,7 @@ void MessagePopupBubble::OnBubbleViewDestroyed() { void MessagePopupBubble::UpdateBubbleView() { NotificationList::PopupNotifications popups = - list_delegate()->GetNotificationList()->GetPopupNotifications(); + message_center()->notification_list()->GetPopupNotifications(); if (popups.size() == 0) { if (bubble_view()) @@ -200,7 +205,7 @@ void MessagePopupBubble::OnMouseExitedView() { void MessagePopupBubble::OnAutoClose(const std::string& id) { DeleteTimer(id); - list_delegate()->GetNotificationList()->MarkSinglePopupAsShown(id, false); + message_center()->notification_list()->MarkSinglePopupAsShown(id, false); UpdateBubbleView(); } diff --git a/ui/message_center/views/message_popup_bubble.h b/ui/message_center/views/message_popup_bubble.h index 060d22f..671c0b6 100644 --- a/ui/message_center/views/message_popup_bubble.h +++ b/ui/message_center/views/message_popup_bubble.h @@ -11,7 +11,6 @@ #include "base/timer.h" #include "ui/message_center/message_center_export.h" -#include "ui/message_center/notification_list.h" #include "ui/message_center/views/message_bubble_base.h" namespace message_center { @@ -21,11 +20,11 @@ class PopupBubbleContentsView; // Bubble for popup notifications. class MESSAGE_CENTER_EXPORT MessagePopupBubble : public MessageBubbleBase { public: - explicit MessagePopupBubble(NotificationList::Delegate* delegate); + explicit MessagePopupBubble(MessageCenter* message_center); virtual ~MessagePopupBubble(); - // Overridden from MessageBubbleBase. + // Overridden from MessageBubbleBase: virtual views::TrayBubbleView::InitParams GetInitParams( views::TrayBubbleView::AnchorAlignment anchor_alignment) OVERRIDE; virtual void InitializeContents(views::TrayBubbleView* bubble_view) OVERRIDE; diff --git a/ui/message_center/views/message_popup_collection.cc b/ui/message_center/views/message_popup_collection.cc index f00308d..fb81d69 100644 --- a/ui/message_center/views/message_popup_collection.cc +++ b/ui/message_center/views/message_popup_collection.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/timer.h" #include "ui/gfx/screen.h" +#include "ui/message_center/message_center.h" #include "ui/message_center/message_center_constants.h" #include "ui/message_center/notification.h" #include "ui/message_center/notification_list.h" @@ -18,6 +19,7 @@ #include "ui/views/layout/fill_layout.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" namespace message_center { @@ -85,7 +87,7 @@ class ToastContentsView : public views::WidgetDelegateView { base::Unretained(GetWidget()))); } - // views::WidgetDelegate overrides: + // Overridden from views::WidgetDelegate: virtual views::View* GetContentsView() OVERRIDE { return this; } @@ -99,7 +101,7 @@ class ToastContentsView : public views::WidgetDelegateView { return false; } - // views::View overrides: + // Overridden from views::View: virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE { collection_->OnMouseEntered(); } @@ -117,12 +119,11 @@ class ToastContentsView : public views::WidgetDelegateView { DISALLOW_COPY_AND_ASSIGN(ToastContentsView); }; -MessagePopupCollection::MessagePopupCollection( - gfx::NativeView context, - NotificationList::Delegate* list_delegate) +MessagePopupCollection::MessagePopupCollection(gfx::NativeView context, + MessageCenter* message_center) : context_(context), - list_delegate_(list_delegate) { - DCHECK(list_delegate_); + message_center_(message_center) { + DCHECK(message_center_); } MessagePopupCollection::~MessagePopupCollection() { @@ -131,7 +132,7 @@ MessagePopupCollection::~MessagePopupCollection() { void MessagePopupCollection::UpdatePopups() { NotificationList::PopupNotifications popups = - list_delegate_->GetNotificationList()->GetPopupNotifications(); + message_center_->notification_list()->GetPopupNotifications(); if (popups.empty()) { CloseAllWidgets(); @@ -153,7 +154,12 @@ void MessagePopupCollection::UpdatePopups() { popups.begin(); iter != popups.end(); ++iter) { ToastContainer::iterator toast_iter = toasts_.find((*iter)->id()); views::Widget* widget = NULL; - MessageView* view = NotificationView::Create(*(*iter), list_delegate_); + // NotificationViews are expanded by default here because + // MessagePopupCollection hasn't been tested yet with changing subview + // sizes, and such changes could come if those subviews were initially + // collapsed and allowed to be expanded by users. TODO(dharcourt): Fix. + MessageView* view = NotificationView::Create(*(*iter), message_center_, + true); if (toast_iter != toasts_.end()) { widget = toast_iter->second->GetWidget(); old_toast_ids.erase((*iter)->id()); @@ -240,7 +246,7 @@ void MessagePopupCollection::OnWidgetDestroying(views::Widget* widget) { for (ToastContainer::iterator iter = toasts_.begin(); iter != toasts_.end(); ++iter) { if (iter->second->GetWidget() == widget) { - list_delegate_->GetNotificationList()->MarkSinglePopupAsShown( + message_center_->notification_list()->MarkSinglePopupAsShown( iter->first, false); toasts_.erase(iter); break; diff --git a/ui/message_center/views/message_popup_collection.h b/ui/message_center/views/message_popup_collection.h index 0f71a2f..b85bcf0 100644 --- a/ui/message_center/views/message_popup_collection.h +++ b/ui/message_center/views/message_popup_collection.h @@ -8,11 +8,10 @@ #include <list> #include <map> +#include "base/compiler_specific.h" #include "base/gtest_prod_util.h" -#include "base/timer.h" +#include "ui/gfx/native_widget_types.h" #include "ui/message_center/message_center_export.h" -#include "ui/message_center/notification_list.h" -#include "ui/message_center/views/message_bubble_base.h" #include "ui/views/widget/widget_observer.h" namespace views { @@ -25,6 +24,7 @@ FORWARD_DECLARE_TEST(WebNotificationTrayTest, ManyPopupNotifications); namespace message_center { +class MessageCenter; class ToastContentsView; // Container for popup toasts. Because each toast is a frameless window rather @@ -38,7 +38,7 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection // |context| specifies the context to create toast windows. It can be NULL // for non-aura environment. See comments in ui/views/widget/widget.h. MessagePopupCollection(gfx::NativeView context, - NotificationList::Delegate* list_delegate); + MessageCenter* message_center); virtual ~MessagePopupCollection(); void UpdatePopups(); @@ -53,11 +53,11 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection void CloseAllWidgets(); - // views::WidgetObserver overrides: + // Overridden from views::WidgetObserver: virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE; gfx::NativeView context_; - NotificationList::Delegate* list_delegate_; + MessageCenter* message_center_; ToastContainer toasts_; DISALLOW_COPY_AND_ASSIGN(MessagePopupCollection); diff --git a/ui/message_center/views/message_simple_view.cc b/ui/message_center/views/message_simple_view.cc index 3fe905a..9402eee 100644 --- a/ui/message_center/views/message_simple_view.cc +++ b/ui/message_center/views/message_simple_view.cc @@ -7,7 +7,6 @@ #include "grit/ui_resources.h" #include "ui/base/resource/resource_bundle.h" #include "ui/message_center/notification.h" -#include "ui/message_center/notification_list.h" #include "ui/views/background.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/image_view.h" @@ -20,10 +19,9 @@ namespace message_center { const SkColor kNotificationColor = SkColorSetRGB(0xfe, 0xfe, 0xfe); const SkColor kNotificationReadColor = SkColorSetRGB(0xfa, 0xfa, 0xfa); -MessageSimpleView::MessageSimpleView( - NotificationList::Delegate* list_delegate, - const Notification& notification) - : MessageView(list_delegate, notification) { +MessageSimpleView::MessageSimpleView(const Notification& notification, + NotificationChangeObserver* observer) + : MessageView(notification, observer, false) { views::ImageButton* close = new views::ImageButton(this); close->SetImage( views::CustomButton::STATE_NORMAL, @@ -64,7 +62,7 @@ void MessageSimpleView::SetUpView(const Notification& notification) { views::ImageView* icon = new views::ImageView; icon->SetImageSize( gfx::Size(kWebNotificationIconSize, kWebNotificationIconSize)); - icon->SetImage(notification.primary_icon().AsImageSkia()); + icon->SetImage(notification.icon().AsImageSkia()); views::Label* title = new views::Label(notification.title()); title->SetHorizontalAlignment(gfx::ALIGN_LEFT); diff --git a/ui/message_center/views/message_simple_view.h b/ui/message_center/views/message_simple_view.h index 2a9e9b1..50cd5d3 100644 --- a/ui/message_center/views/message_simple_view.h +++ b/ui/message_center/views/message_simple_view.h @@ -5,18 +5,18 @@ #ifndef UI_MESSAGE_CENTER_VIEWS_MESSAGE_SIMPLE_VIEW_H_ #define UI_MESSAGE_CENTER_VIEWS_MESSAGE_SIMPLE_VIEW_H_ -#include "ui/message_center/notification_list.h" #include "ui/message_center/views/message_view.h" namespace message_center { class Notification; +class NotificationChangeObserver; // A simple view for a notification entry (icon + message + buttons). class MessageSimpleView : public MessageView { public: - MessageSimpleView(NotificationList::Delegate* list_delegate, - const Notification& notification); + MessageSimpleView(const Notification& notification, + NotificationChangeObserver* observer); virtual ~MessageSimpleView(); // Overridden from MessageView: diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc index 0ea4f91..a8c1a63 100644 --- a/ui/message_center/views/message_view.cc +++ b/ui/message_center/views/message_view.cc @@ -14,6 +14,7 @@ #include "ui/gfx/shadow_value.h" #include "ui/gfx/skia_util.h" #include "ui/message_center/message_center_util.h" +#include "ui/message_center/notification_change_observer.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/menu/menu_model_adapter.h" #include "ui/views/controls/menu/menu_runner.h" @@ -22,9 +23,12 @@ namespace { -const int kCloseButtonSize = 29; +const int kControlButtonSize = 29; const int kCloseIconTopPadding = 5; const int kCloseIconRightPadding = 5; +const int kExpandIconBottomPadding = 8; +const int kExpandIconRightPadding = 11; + const int kShadowOffset = 1; const int kShadowBlur = 4; @@ -104,7 +108,7 @@ void ControlButton::SetPressedImage(int resource_id) { } gfx::Size ControlButton::GetPreferredSize() { - return gfx::Size(kCloseButtonSize, kCloseButtonSize); + return gfx::Size(kControlButtonSize, kControlButtonSize); } void ControlButton::OnPaint(gfx::Canvas* canvas) { @@ -151,7 +155,7 @@ class ShadowBorder : public views::Border { virtual ~ShadowBorder() {} protected: - // views::Border overrides: + // Overridden from views::Border: virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE; virtual gfx::Insets GetInsets() const OVERRIDE; @@ -180,7 +184,7 @@ gfx::Insets ShadowBorder::GetInsets() const { class MenuModel : public ui::SimpleMenuModel, public ui::SimpleMenuModel::Delegate { public: - MenuModel(message_center::NotificationList::Delegate* list_delegate, + MenuModel(message_center::NotificationChangeObserver* observer, const std::string& notification_id, const string16& display_source, const std::string& extension_id); @@ -196,19 +200,18 @@ class MenuModel : public ui::SimpleMenuModel, virtual void ExecuteCommand(int command_id) OVERRIDE; private: - message_center::NotificationList::Delegate* list_delegate_; - // Weak, global MessageCenter + message_center::NotificationChangeObserver* observer_; // Weak reference. std::string notification_id_; DISALLOW_COPY_AND_ASSIGN(MenuModel); }; -MenuModel::MenuModel(message_center::NotificationList::Delegate* list_delegate, +MenuModel::MenuModel(message_center::NotificationChangeObserver* observer, const std::string& notification_id, const string16& display_source, const std::string& extension_id) : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)), - list_delegate_(list_delegate), + observer_(observer), notification_id_(notification_id) { // Add 'disable notifications' menu item. if (!extension_id.empty()) { @@ -249,13 +252,13 @@ bool MenuModel::GetAcceleratorForCommandId(int command_id, void MenuModel::ExecuteCommand(int command_id) { switch (command_id) { case kToggleExtensionCommand: - list_delegate_->DisableNotificationByExtension(notification_id_); + observer_->OnDisableNotificationsByExtension(notification_id_); break; case kTogglePermissionCommand: - list_delegate_->DisableNotificationByUrl(notification_id_); + observer_->OnDisableNotificationsByUrl(notification_id_); break; case kShowSettingsCommand: - list_delegate_->ShowNotificationSettings(notification_id_); + observer_->OnShowNotificationSettings(notification_id_); break; default: NOTREACHED(); @@ -266,19 +269,31 @@ void MenuModel::ExecuteCommand(int command_id) { namespace message_center { -MessageView::MessageView(NotificationList::Delegate* list_delegate, - const Notification& notification) - : list_delegate_(list_delegate), +MessageView::MessageView(const Notification& notification, + NotificationChangeObserver* observer, + bool expanded) + : observer_(observer), notification_id_(notification.id()), display_source_(notification.display_source()), extension_id_(notification.extension_id()), - scroller_(NULL) { + scroller_(NULL), + is_expanded_(expanded) { ControlButton *close = new ControlButton(this); close->SetPadding(-kCloseIconRightPadding, kCloseIconTopPadding); close->SetNormalImage(IDR_NOTIFICATION_CLOSE); close->SetHoveredImage(IDR_NOTIFICATION_CLOSE_HOVER); close->SetPressedImage(IDR_NOTIFICATION_CLOSE_PRESSED); + close->set_owned_by_client(); close_button_.reset(close); + + ControlButton *expand = new ControlButton(this); + expand->SetPadding(-kExpandIconRightPadding, -kExpandIconBottomPadding); + expand->SetNormalImage(IDR_NOTIFICATIONS_EXPAND); + expand->SetHoveredImage(IDR_NOTIFICATIONS_EXPAND_HOVER); + expand->SetPressedImage(IDR_NOTIFICATIONS_EXPAND_PRESSED); + expand->set_owned_by_client(); + expand_button_.reset(expand); + if (IsRichNotificationEnabled()) set_border(new ShadowBorder()); } @@ -297,18 +312,24 @@ gfx::Insets MessageView::GetShadowInsets() { kShadowBlur / 2); } +void MessageView::Update(const Notification& notification) { + notification_id_ = notification.id(); + display_source_ = notification.display_source(); + extension_id_ = notification.extension_id(); +} + bool MessageView::OnMousePressed(const ui::MouseEvent& event) { if (event.flags() & ui::EF_RIGHT_MOUSE_BUTTON) { ShowMenu(event.location()); return true; } - list_delegate_->OnNotificationClicked(notification_id_); + observer_->OnClicked(notification_id_); return true; } void MessageView::OnGestureEvent(ui::GestureEvent* event) { if (event->type() == ui::ET_GESTURE_TAP) { - list_delegate_->OnNotificationClicked(notification_id_); + observer_->OnClicked(notification_id_); event->SetHandled(); return; } @@ -334,12 +355,16 @@ void MessageView::OnGestureEvent(ui::GestureEvent* event) { void MessageView::ButtonPressed(views::Button* sender, const ui::Event& event) { - if (sender == close_button()) - list_delegate_->SendRemoveNotification(notification_id_, true); // By user. + if (sender == close_button()) { + observer_->OnRemoveNotification(notification_id_, true); // By user. + } else if (sender == expand_button()) { + is_expanded_ = true; + observer_->OnExpanded(notification_id_); + } } void MessageView::ShowMenu(gfx::Point screen_location) { - MenuModel menu_model(list_delegate_, notification_id_, + MenuModel menu_model(observer_, notification_id_, display_source_, extension_id_); if (menu_model.GetItemCount() == 0) return; @@ -357,7 +382,7 @@ void MessageView::ShowMenu(gfx::Point screen_location) { } void MessageView::OnSlideOut() { - list_delegate_->SendRemoveNotification(notification_id_, true); // By user. + observer_->OnRemoveNotification(notification_id_, true); // By user. } } // namespace message_center diff --git a/ui/message_center/views/message_view.h b/ui/message_center/views/message_view.h index 86920b9..37725db 100644 --- a/ui/message_center/views/message_view.h +++ b/ui/message_center/views/message_view.h @@ -7,18 +7,19 @@ #include "ui/gfx/insets.h" #include "ui/message_center/notification.h" -#include "ui/message_center/notification_list.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/slide_out_view.h" -#include "ui/views/view.h" namespace views { class ImageButton; +class ImageView; class ScrollView; } namespace message_center { +class NotificationChangeObserver; + // Individual notifications constants. const int kPaddingBetweenItems = 10; const int kPaddingHorizontal = 18; @@ -30,52 +31,59 @@ const int kWebNotificationWidth = 300; class MessageView : public views::SlideOutView, public views::ButtonListener { public: - MessageView(NotificationList::Delegate* list_delegate, - const Notification& notification); - + MessageView(const Notification& notification, + NotificationChangeObserver* observer, + bool expanded); virtual ~MessageView(); // Returns the insets for the shadow it will have for rich notification. static gfx::Insets GetShadowInsets(); - void set_scroller(views::ScrollView* scroller) { scroller_ = scroller; } + // Adjust to any change in notification data or expanded status. + virtual void Update(const Notification& notification); - // Overridden from views::View. + // Overridden from views::View: virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; - // Overridden from ui::EventHandler. + // Overridden from ui::EventHandler: virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; - // Overridden from ButtonListener. + // Overridden from ButtonListener: virtual void ButtonPressed(views::Button* sender, const ui::Event& event) OVERRIDE; + void set_scroller(views::ScrollView* scroller) { scroller_ = scroller; } + protected: MessageView(); // Shows the menu for the notification. void ShowMenu(gfx::Point screen_location); - // Overridden from views::SlideOutView. + // Overridden from views::SlideOutView: virtual void OnSlideOut() OVERRIDE; - NotificationList::Delegate* list_delegate() { return list_delegate_; } + NotificationChangeObserver* observer() { return observer_; } const std::string& notification_id() { return notification_id_; } const string16& display_source() const { return display_source_; } const std::string& extension_id() const { return extension_id_; } views::ImageButton* close_button() { return close_button_.get(); } + views::ImageButton* expand_button() { return expand_button_.get(); } views::ScrollView* scroller() { return scroller_; } + const bool is_expanded() { return is_expanded_; } private: - NotificationList::Delegate* list_delegate_; // Weak, global (MessageCenter). + NotificationChangeObserver* observer_; // Weak reference. std::string notification_id_; string16 display_source_; std::string extension_id_; scoped_ptr<views::ImageButton> close_button_; - + scoped_ptr<views::ImageButton> expand_button_; views::ScrollView* scroller_; + bool is_expanded_; + DISALLOW_COPY_AND_ASSIGN(MessageView); }; diff --git a/ui/message_center/views/notification_view.cc b/ui/message_center/views/notification_view.cc index e4b2cca..268bd35 100644 --- a/ui/message_center/views/notification_view.cc +++ b/ui/message_center/views/notification_view.cc @@ -10,11 +10,13 @@ #include "ui/base/accessibility/accessible_view_state.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/text/text_elider.h" +#include "ui/gfx/canvas.h" #include "ui/gfx/size.h" #include "ui/message_center/message_center_constants.h" #include "ui/message_center/message_center_switches.h" #include "ui/message_center/message_center_util.h" #include "ui/message_center/notification.h" +#include "ui/message_center/notification_change_observer.h" #include "ui/message_center/notification_types.h" #include "ui/message_center/views/message_simple_view.h" #include "ui/native_theme/native_theme.h" @@ -96,17 +98,22 @@ ItemView::ItemView(const message_center::NotificationItem& item) { ItemView::~ItemView() { } -// ProportionalImageViews match their heights to their widths to preserve the -// proportions of their images. +// ProportionalImageViews center their images to preserve their proportion. +// Note that for this subclass of views::ImageView GetImageBounds() will return +// potentially incorrect values (this can't be fixed because GetImageBounds() +// is not virtual) and horizontal and vertical alignments will be ignored. class ProportionalImageView : public views::ImageView { public: ProportionalImageView(); virtual ~ProportionalImageView(); - // Overridden from views::View. + // Overridden from views::View: virtual int GetHeightForWidth(int width) OVERRIDE; + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; private: + gfx::Size GetImageSizeForWidth(int width); + DISALLOW_COPY_AND_ASSIGN(ProportionalImageView); }; @@ -117,18 +124,42 @@ ProportionalImageView::~ProportionalImageView() { } int ProportionalImageView::GetHeightForWidth(int width) { - int height = 0; - gfx::ImageSkia image = GetImage(); - if (image.width() > 0 && image.height() > 0) { - double proportion = image.height() / (double) image.width(); - height = 0.5 + width * proportion; - if (height > message_center::kNotificationMaximumImageHeight) { - height = message_center::kNotificationMaximumImageHeight; - width = 0.5 + height / proportion; + return GetImageSizeForWidth(width).height(); +} + +void ProportionalImageView::OnPaint(gfx::Canvas* canvas) { + View::OnPaint(canvas); + + gfx::Size draw_size(GetImageSizeForWidth(width())); + if (!draw_size.IsEmpty()) { + int x = (width() - draw_size.width()) / 2; + int y = (height() - draw_size.height()) / 2; + + gfx::Size image_size(GetImage().size()); + if (image_size == draw_size) { + canvas->DrawImageInt(GetImage(), x, y); + } else { + // Resize case + SkPaint paint; + paint.setFilterBitmap(true); + canvas->DrawImageInt(GetImage(), 0, 0, + image_size.width(), image_size.height(), x, y, + draw_size.width(), draw_size.height(), true, paint); + } + } +} + +gfx::Size ProportionalImageView::GetImageSizeForWidth(int width) { + gfx::Size size(GetImage().size()); + if (width > 0 && !size.IsEmpty()) { + double proportion = size.height() / (double) size.width(); + size.SetSize(width, std::max(0.5 + width * proportion, 1.0)); + if (size.height() > message_center::kNotificationMaximumImageHeight) { + int height = message_center::kNotificationMaximumImageHeight; + size.SetSize(std::max(0.5 + height / proportion, 1.0), height); } - SetImageSize(gfx::Size(width, height)); } - return height; + return size; } // NotificationsButtons render the action buttons of notifications. @@ -196,9 +227,9 @@ void NotificationButton::SetTitle(const string16& title) { namespace message_center { // static -MessageView* NotificationView::Create( - const Notification& notification, - NotificationList::Delegate* list_delegate) { +MessageView* NotificationView::Create(const Notification& notification, + NotificationChangeObserver* observer, + bool expanded) { // For the time being, use MessageSimpleView for simple notifications unless // one of the use-the-new-style flags are set. This preserves the appearance // of notifications created by existing code that uses webkitNotifications. @@ -206,7 +237,7 @@ MessageView* NotificationView::Create( !IsRichNotificationEnabled() && !CommandLine::ForCurrentProcess()->HasSwitch( message_center::switches::kEnableNewSimpleNotifications)) { - return new MessageSimpleView(list_delegate, notification); + return new MessageSimpleView(notification, observer); } switch (notification.type()) { @@ -227,61 +258,89 @@ MessageView* NotificationView::Create( } // Currently all roads lead to the generic NotificationView. - return new NotificationView(list_delegate, notification); + return new NotificationView(notification, observer, expanded); } -NotificationView::NotificationView(NotificationList::Delegate* list_delegate, - const Notification& notification) - : MessageView(list_delegate, notification) { - // This view is composed of two layers: The first layer has the notification - // content (text, images, action buttons, ...). This is overlaid by a second - // layer that has the notification close button and will later also have the - // expand button. This allows the close and expand buttons to overlap the - // content as needed to provide a large enough click area - // (<http://crbug.com/168822> and touch area <http://crbug.com/168856>). - AddChildView(MakeContentView(notification)); - AddChildView(close_button()); +NotificationView::NotificationView(const Notification& notification, + NotificationChangeObserver* observer, + bool expanded) + : MessageView(notification, observer, expanded), + content_view_(NULL), + icon_view_(NULL) { + AddChildViews(notification); } NotificationView::~NotificationView() { } void NotificationView::Layout() { - if (content_view_) { - gfx::Rect contents_bounds = GetContentsBounds(); - content_view_->SetBoundsRect(contents_bounds); - if (close_button()) { - gfx::Size size(close_button()->GetPreferredSize()); - close_button()->SetBounds(contents_bounds.right() - size.width(), 0, - size.width(), size.height()); - } - } + gfx::Rect content_bounds(GetLocalBounds()); + content_bounds.Inset(GetInsets()); + content_view_->SetBoundsRect(content_bounds); + + gfx::Size close_size(close_button()->GetPreferredSize()); + close_button()->SetBounds(content_bounds.right() - close_size.width(), + content_bounds.y(), + close_size.width(), + close_size.height()); + + gfx::Rect icon_bounds(content_bounds.origin(), icon_view_->size()); + gfx::Size expand_size(expand_button()->GetPreferredSize()); + expand_button()->SetBounds(content_bounds.right() - expand_size.width(), + icon_bounds.bottom() - expand_size.height(), + expand_size.width(), + expand_size.height()); } gfx::Size NotificationView::GetPreferredSize() { - if (!content_view_) - return gfx::Size(); - gfx::Size size = content_view_->GetPreferredSize(); - if (border()) { - gfx::Insets border_insets = border()->GetInsets(); - size.Enlarge(border_insets.width(), border_insets.height()); + gfx::Size size; + if (content_view_) { + size = content_view_->GetPreferredSize(); + if (border()) { + gfx::Insets insets = border()->GetInsets(); + size.Enlarge(insets.width(), insets.height()); + } } return size; } +void NotificationView::Update(const Notification& notification) { + MessageView::Update(notification); + content_view_ = NULL; + icon_view_ = NULL; + action_buttons_.clear(); + RemoveAllChildViews(true); + AddChildViews(notification); + PreferredSizeChanged(); + SchedulePaint(); +} + void NotificationView::ButtonPressed(views::Button* sender, const ui::Event& event) { for (size_t i = 0; i < action_buttons_.size(); ++i) { - if (action_buttons_[i] == sender) { - list_delegate()->OnButtonClicked(notification_id(), i); + if (sender == action_buttons_[i]) { + observer()->OnButtonClicked(notification_id(), i); return; } } MessageView::ButtonPressed(sender, event); } -views::View* NotificationView::MakeContentView( - const Notification& notification) { +void NotificationView::AddChildViews(const Notification& notification) { + // Child views are in two layers: The first layer has the notification content + // (text, images, action buttons, ...). This is overlaid by a second layer + // that has the notification close and expand buttons. This allows the close + // and expand buttons to overlap the content as needed to provide large enough + // click and touch areas (<http://crbug.com/168822> and + // <http://crbug.com/168856>). + AddContentView(notification); + AddChildView(close_button()); + if (!is_expanded()) { + AddChildView(expand_button()); + } +} + +void NotificationView::AddContentView(const Notification& notification) { content_view_ = new views::View(); content_view_->set_background( views::Background::CreateSolidBackground(kBackgroundColor)); @@ -291,39 +350,44 @@ views::View* NotificationView::MakeContentView( // items), followed by a padding view. Laying out the icon view will require // information about the text views, so these are created first and collected // in this vector. - std::vector<views::View*> texts; + std::vector<views::View*> text_views; // Title if it exists. if (!notification.title().empty()) { views::Label* title = new views::Label(notification.title()); title->SetHorizontalAlignment(gfx::ALIGN_LEFT); - title->SetElideBehavior(views::Label::ELIDE_AT_END); + if (is_expanded()) + title->SetMultiLine(true); + else + title->SetElideBehavior(views::Label::ELIDE_AT_END); title->SetFont(title->font().DeriveFont(4)); title->SetEnabledColor(kTitleColor); title->SetBackgroundColor(kTitleBackgroundColor); title->set_border(MakePadding(kTextTopPadding, 0, 3, kTextRightPadding)); - texts.push_back(title); + text_views.push_back(title); + } + + // List notification items up to a maximum if appropriate. + size_t maximum = is_expanded() ? kNotificationMaximumItems : 0ul; + size_t items = std::min(notification.items().size(), maximum); + for (size_t i = 0; i < items; ++i) { + ItemView* item = new ItemView(notification.items()[i]); + item->set_border(MakePadding(0, 0, 4, kTextRightPadding)); + text_views.push_back(item); } // Message if appropriate. - if (notification.items().size() == 0 && - !notification.message().empty()) { + if (items == 0ul && !notification.message().empty()) { views::Label* message = new views::Label(notification.message()); message->SetHorizontalAlignment(gfx::ALIGN_LEFT); - message->SetMultiLine(true); + if (is_expanded()) + message->SetMultiLine(true); + else + message->SetElideBehavior(views::Label::ELIDE_AT_END); message->SetEnabledColor(kMessageColor); message->SetBackgroundColor(kMessageBackgroundColor); message->set_border(MakePadding(0, 0, 3, kTextRightPadding)); - texts.push_back(message); - } - - // List notification items up to a maximum. - int items = std::min(notification.items().size(), - kNotificationMaximumItems); - for (int i = 0; i < items; ++i) { - ItemView* item = new ItemView(notification.items()[i]); - item->set_border(MakePadding(0, 0, 4, kTextRightPadding)); - texts.push_back(item); + text_views.push_back(message); } // Set up the content view with a fixed-width icon column on the left and a @@ -345,28 +409,28 @@ views::View* NotificationView::MakeContentView( // Create the first row and its icon view, which spans all the text views // to its right as well as the padding view below them. layout->StartRow(0, 0); - views::ImageView* icon = new views::ImageView(); - icon->SetImageSize(gfx::Size(message_center::kNotificationIconSize, - message_center::kNotificationIconSize)); - icon->SetImage(notification.primary_icon().AsImageSkia()); - icon->SetHorizontalAlignment(views::ImageView::LEADING); - icon->SetVerticalAlignment(views::ImageView::LEADING); - icon->set_border(MakePadding(0, 0, 0, kIconToTextPadding)); - layout->AddView(icon, 1, texts.size() + 1); + icon_view_ = new views::ImageView(); + icon_view_->SetImageSize(gfx::Size(message_center::kNotificationIconSize, + message_center::kNotificationIconSize)); + icon_view_->SetImage(notification.icon().AsImageSkia()); + icon_view_->SetHorizontalAlignment(views::ImageView::LEADING); + icon_view_->SetVerticalAlignment(views::ImageView::LEADING); + icon_view_->set_border(MakePadding(0, 0, 0, kIconToTextPadding)); + layout->AddView(icon_view_, 1, text_views.size() + 1); // Add the text views, creating rows for them if necessary. - for (size_t i = 0; i < texts.size(); ++i) { + for (size_t i = 0; i < text_views.size(); ++i) { if (i > 0) { layout->StartRow(0, 0); layout->SkipColumns(1); } - layout->AddView(texts[i]); + layout->AddView(text_views[i]); } // Add a text padding row if necessary. This adds some space between the last // line of text and anything below it but it also ensures views above it are // top-justified by expanding vertically to take up any extra space. - if (texts.size() == 0) { + if (text_views.size() == 0) { layout->SkipColumns(1); } else { layout->StartRow(100, 0); @@ -377,14 +441,11 @@ views::View* NotificationView::MakeContentView( } // Add an image row if appropriate. - if (!notification.image().IsEmpty()) { + if (is_expanded() && !notification.image().IsEmpty()) { layout->StartRow(0, 0); - views::ImageView* image = new ProportionalImageView(); - image->SetImageSize(notification.image().ToImageSkia()->size()); - image->SetImage(notification.image().ToImageSkia()); - image->SetHorizontalAlignment(views::ImageView::CENTER); - image->SetVerticalAlignment(views::ImageView::LEADING); - layout->AddView(image, 2, 1); + ProportionalImageView* image_view = new ProportionalImageView(); + image_view->SetImage(notification.image().ToImageSkia()); + layout->AddView(image_view, 2, 1); } // Add action button rows. @@ -404,7 +465,7 @@ views::View* NotificationView::MakeContentView( views::GridLayout::FILL, views::GridLayout::FILL, 0, 40); } - return content_view_; + AddChildView(content_view_); } } // namespace message_center diff --git a/ui/message_center/views/notification_view.h b/ui/message_center/views/notification_view.h index dee7e98..a0b23e9 100644 --- a/ui/message_center/views/notification_view.h +++ b/ui/message_center/views/notification_view.h @@ -5,40 +5,49 @@ #ifndef UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_H_ #define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_H_ -#include "ui/message_center/notification_list.h" +#include <vector> + #include "ui/message_center/views/message_view.h" namespace message_center { +class NotificationChangeObserver; + // View that displays all current types of notification (web, basic, image, and // list). Future notification types may be handled by other classes, in which -// case instances of those classes would be returned by the -// ViewForNotification() factory method below. +// case instances of those classes would be returned by the Create() factory +// method below. class NotificationView : public MessageView { public: // Creates appropriate MessageViews for notifications. Those currently are - // always NotificationView instances but in the future may be instances of - // other classes, with the class depending on the notification type. + // always NotificationView or MessageSimpleView instances but in the future + // may be instances of other classes, with the class depending on the + // notification type. static MessageView* Create(const Notification& notification, - NotificationList::Delegate* list_delegate); + NotificationChangeObserver* observer, + bool expanded); virtual ~NotificationView(); - // Overridden from View. + // Overridden from views::View: virtual void Layout() OVERRIDE; virtual gfx::Size GetPreferredSize() OVERRIDE; - // Overridden from MessageView. + // Overridden from MessageView: + virtual void Update(const Notification& notification) OVERRIDE; virtual void ButtonPressed(views::Button* sender, const ui::Event& event) OVERRIDE; private: - NotificationView(NotificationList::Delegate* list_delegate, - const Notification& notification); + NotificationView(const Notification& notification, + NotificationChangeObserver* observer, + bool expanded); - views::View* MakeContentView(const Notification& notification); + void AddChildViews(const Notification& notification); + void AddContentView(const Notification& notification); views::View* content_view_; + views::ImageView* icon_view_; std::vector<views::Button*> action_buttons_; DISALLOW_COPY_AND_ASSIGN(NotificationView); diff --git a/ui/message_center/views/notifier_settings_view.cc b/ui/message_center/views/notifier_settings_view.cc index 3de1f0b..c65d4e0 100644 --- a/ui/message_center/views/notifier_settings_view.cc +++ b/ui/message_center/views/notifier_settings_view.cc @@ -83,7 +83,7 @@ class NotifierSettingsView::NotifierButton : public views::CustomButton, } private: - // views::ButtonListener overrides: + // Overridden from views::ButtonListener: virtual void ButtonPressed(views::Button* button, const ui::Event& event) OVERRIDE { DCHECK(button == checkbox_); diff --git a/ui/message_center/views/notifier_settings_view.h b/ui/message_center/views/notifier_settings_view.h index a296dd5..4aa7701 100644 --- a/ui/message_center/views/notifier_settings_view.h +++ b/ui/message_center/views/notifier_settings_view.h @@ -45,13 +45,13 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsView NotifierSettingsView(NotifierSettingsViewDelegate* delegate); virtual ~NotifierSettingsView(); - // views::WidgetDelegate overrides: + // Overridden from views::WidgetDelegate: virtual bool CanResize() const OVERRIDE; virtual string16 GetWindowTitle() const OVERRIDE; virtual void WindowClosing() OVERRIDE; virtual views::View* GetContentsView() OVERRIDE; - // views::ButtonListener overrides: + // Overridden from views::ButtonListener: virtual void ButtonPressed(views::Button* sender, const ui::Event& event) OVERRIDE; |