diff options
24 files changed, 887 insertions, 365 deletions
diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc index b249f49..5661734 100644 --- a/chrome/browser/notifications/message_center_notification_manager.cc +++ b/chrome/browser/notifications/message_center_notification_manager.cc @@ -36,21 +36,22 @@ const int kFirstRunIdleDelaySeconds = 1; MessageCenterNotificationManager::MessageCenterNotificationManager( message_center::MessageCenter* message_center, - PrefService* local_state) + PrefService* local_state, + scoped_ptr<message_center::NotifierSettingsProvider> settings_provider) : message_center_(message_center), #if defined(OS_WIN) first_run_idle_timeout_( base::TimeDelta::FromSeconds(kFirstRunIdleDelaySeconds)), weak_factory_(this), #endif - settings_controller_(new MessageCenterSettingsController) { + settings_provider_(settings_provider.Pass()) { #if defined(OS_WIN) first_run_pref_.Init(prefs::kMessageCenterShowedFirstRunBalloon, local_state); #endif message_center_->SetDelegate(this); message_center_->AddObserver(this); - message_center_->SetNotifierSettingsProvider(settings_controller_.get()); + message_center_->SetNotifierSettingsProvider(settings_provider_.get()); #if defined(OS_WIN) || defined(OS_MACOSX) \ || (defined(USE_AURA) && !defined(USE_ASH)) diff --git a/chrome/browser/notifications/message_center_notification_manager.h b/chrome/browser/notifications/message_center_notification_manager.h index 91701d2..be2621e 100644 --- a/chrome/browser/notifications/message_center_notification_manager.h +++ b/chrome/browser/notifications/message_center_notification_manager.h @@ -34,9 +34,10 @@ class MessageCenterNotificationManager public message_center::MessageCenter::Delegate, public message_center::MessageCenterObserver { public: - explicit MessageCenterNotificationManager( + MessageCenterNotificationManager( message_center::MessageCenter* message_center, - PrefService* local_state); + PrefService* local_state, + scoped_ptr<message_center::NotifierSettingsProvider> settings_provider); virtual ~MessageCenterNotificationManager(); // NotificationUIManager @@ -220,7 +221,7 @@ class MessageCenterNotificationManager base::WeakPtrFactory<MessageCenterNotificationManager> weak_factory_; #endif - scoped_ptr<MessageCenterSettingsController> settings_controller_; + scoped_ptr<message_center::NotifierSettingsProvider> settings_provider_; // Registrar for the other kind of notifications (event signaling). content::NotificationRegistrar registrar_; diff --git a/chrome/browser/notifications/message_center_notifications_unittest_win.cc b/chrome/browser/notifications/message_center_notifications_unittest_win.cc index fd674e63..01c8534 100644 --- a/chrome/browser/notifications/message_center_notifications_unittest_win.cc +++ b/chrome/browser/notifications/message_center_notifications_unittest_win.cc @@ -17,9 +17,11 @@ #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/message_center/fake_notifier_settings_provider.h" #include "ui/message_center/message_center_impl.h" #include "ui/message_center/message_center_tray.h" #include "ui/message_center/message_center_tray_delegate.h" +#include "ui/message_center/notifier_settings.h" namespace message_center { class FakeMessageCenterTrayDelegate : public MessageCenterTrayDelegate { @@ -72,8 +74,10 @@ class MessageCenterNotificationManagerTest : public testing::Test { // Initialize message center infrastructure with mock tray delegate. MessageCenter::Initialize(); message_center_ = MessageCenter::Get(); - notification_manager_.reset( - new MessageCenterNotificationManager(message_center_, &local_state_)); + scoped_ptr<NotifierSettingsProvider> settings_provider( + new FakeNotifierSettingsProvider(notifiers_)); + notification_manager_.reset(new MessageCenterNotificationManager( + message_center_, &local_state_, settings_provider.Pass())); delegate_ = new FakeMessageCenterTrayDelegate(message_center_, run_loop_->QuitClosure()); notification_manager_->SetMessageCenterTrayDelegateForTest(delegate_); @@ -111,6 +115,7 @@ class MessageCenterNotificationManagerTest : public testing::Test { scoped_ptr<base::RunLoop> run_loop_; TestingPrefServiceSimple local_state_; MessageCenter* message_center_; + std::vector<Notifier*> notifiers_; scoped_ptr<MessageCenterNotificationManager> notification_manager_; FakeMessageCenterTrayDelegate* delegate_; content::TestBrowserThreadBundle thread_bundle_; diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc index 5e9a588..ef91c33 100644 --- a/chrome/browser/notifications/message_center_settings_controller.cc +++ b/chrome/browser/notifications/message_center_settings_controller.cc @@ -9,6 +9,7 @@ #include "base/command_line.h" #include "base/i18n/string_compare.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/app_icon_loader_impl.h" #include "chrome/browser/extensions/extension_service.h" @@ -19,6 +20,8 @@ #include "chrome/browser/notifications/desktop_notification_service_factory.h" #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h" #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/cancelable_task_tracker.h" #include "chrome/common/extensions/extension_constants.h" @@ -32,16 +35,39 @@ #include "ui/gfx/image/image.h" #include "ui/message_center/message_center_style.h" -#if defined(USE_ASH) -#include "ash/shell.h" -#include "ash/system/web_notification/web_notification_tray.h" -#endif - using message_center::Notifier; using message_center::NotifierId; -namespace { +namespace message_center { +class ProfileNotifierGroup : public message_center::NotifierGroup { + public: + ProfileNotifierGroup(const gfx::Image& icon, + const string16& display_name, + const string16& login_info, + size_t index, + const base::FilePath& profile_path); + virtual ~ProfileNotifierGroup() {} + + Profile* profile() const { return profile_; } + + private: + Profile* profile_; +}; + +ProfileNotifierGroup::ProfileNotifierGroup(const gfx::Image& icon, + const string16& display_name, + const string16& login_info, + size_t index, + const base::FilePath& profile_path) + : message_center::NotifierGroup(icon, display_name, login_info, index), + profile_(NULL) { + // Try to get the profile + profile_ = + g_browser_process->profile_manager()->GetProfileByPath(profile_path); +} +} // namespace message_center +namespace { class NotifierComparator { public: explicit NotifierComparator(icu::Collator* collator) : collator_(collator) {} @@ -61,13 +87,26 @@ bool SimpleCompareNotifiers(Notifier* n1, Notifier* n2) { } // namespace -MessageCenterSettingsController::MessageCenterSettingsController() - : profile_(NULL) { - // We set the profile associated with the settings at the beginning and fail - // silently if this profile is destroyed later. This is a temporary fix for - // http://crbug.com/263193 - registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, - content::NotificationService::AllSources()); +MessageCenterSettingsController::MessageCenterSettingsController( + ProfileInfoCache* profile_info_cache) + : current_notifier_group_(0), profile_info_cache_(profile_info_cache) { + DCHECK(profile_info_cache_); + // The following events all represent changes that may need to be reflected in + // the profile selector context menu, so listen for them all. We'll just + // rebuild the list when we get any of them. + registrar_.Add(this, + chrome::NOTIFICATION_PROFILE_CREATED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, + chrome::NOTIFICATION_PROFILE_ADDED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, + chrome::NOTIFICATION_PROFILE_DESTROYED, + content::NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, + chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, + content::NotificationService::AllBrowserContextsAndSources()); + RebuildNotifierGroups(); } MessageCenterSettingsController::~MessageCenterSettingsController() { @@ -83,15 +122,47 @@ void MessageCenterSettingsController::RemoveObserver( observers_.RemoveObserver(observer); } +size_t MessageCenterSettingsController::GetNotifierGroupCount() const { + return notifier_groups_.size(); +} + +const message_center::NotifierGroup& +MessageCenterSettingsController::GetNotifierGroupAt(size_t index) const { + DCHECK_LT(index, notifier_groups_.size()); + return *(notifier_groups_[index]); +} + +const message_center::NotifierGroup& +MessageCenterSettingsController::GetActiveNotifierGroup() const { + DCHECK_LT(current_notifier_group_, notifier_groups_.size()); + return *(notifier_groups_[current_notifier_group_]); +} + +void MessageCenterSettingsController::SwitchToNotifierGroup(size_t index) { + DCHECK_LT(index, notifier_groups_.size()); + if (current_notifier_group_ == index) + return; + + current_notifier_group_ = index; + FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver, + observers_, + NotifierGroupChanged()); +} + void MessageCenterSettingsController::GetNotifierList( std::vector<Notifier*>* notifiers) { DCHECK(notifiers); // TODO(mukai): Fix this for multi-profile. // Temporarily use the last used profile to prevent chrome from crashing when // the default profile is not loaded. - profile_ = ProfileManager::GetLastUsedProfileAllowedByPolicy(); + message_center::ProfileNotifierGroup* group = + notifier_groups_[current_notifier_group_]; + Profile* profile = group->profile(); + if (!profile) + return; + DesktopNotificationService* notification_service = - DesktopNotificationServiceFactory::GetForProfile(profile_); + DesktopNotificationServiceFactory::GetForProfile(profile); UErrorCode error; scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error)); @@ -99,7 +170,7 @@ void MessageCenterSettingsController::GetNotifierList( if (!U_FAILURE(error)) comparator.reset(new NotifierComparator(collator.get())); - ExtensionService* extension_service = profile_->GetExtensionService(); + ExtensionService* extension_service = profile->GetExtensionService(); const ExtensionSet* extension_set = extension_service->extensions(); // The extension icon size has to be 32x32 at least to load bigger icons if // the icon doesn't exist for the specified size, and in that case it falls @@ -107,9 +178,10 @@ void MessageCenterSettingsController::GetNotifierList( // dialog. See chrome/browser/extensions/extension_icon_image.cc and // crbug.com/222931 app_icon_loader_.reset(new extensions::AppIconLoaderImpl( - profile_, extension_misc::EXTENSION_ICON_SMALL, this)); + profile, extension_misc::EXTENSION_ICON_SMALL, this)); for (ExtensionSet::const_iterator iter = extension_set->begin(); - iter != extension_set->end(); ++iter) { + iter != extension_set->end(); + ++iter) { const extensions::Extension* extension = iter->get(); if (!extension->HasAPIPermission( extensions::APIPermission::kNotification)) { @@ -128,7 +200,7 @@ void MessageCenterSettingsController::GetNotifierList( CommandLine::ForCurrentProcess())) { notifier::ChromeNotifierService* sync_notifier_service = notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile( - profile_, Profile::EXPLICIT_ACCESS); + profile, Profile::EXPLICIT_ACCESS); sync_notifier_service->GetSyncedNotificationServices(notifiers); if (comparator) @@ -141,8 +213,8 @@ void MessageCenterSettingsController::GetNotifierList( ContentSettingsForOneType settings; notification_service->GetNotificationsSettings(&settings); - FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( - profile_, Profile::EXPLICIT_ACCESS); + FaviconService* favicon_service = + FaviconServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS); favicon_tracker_.reset(new CancelableTaskTracker()); patterns_.clear(); for (ContentSettingsForOneType::const_iterator iter = settings.begin(); @@ -163,7 +235,9 @@ void MessageCenterSettingsController::GetNotifierList( notification_service->IsNotifierEnabled(notifier_id))); patterns_[name] = iter->primary_pattern; FaviconService::FaviconForURLParams favicon_params( - profile_, url, chrome::FAVICON | chrome::TOUCH_ICON, + profile, + url, + chrome::FAVICON | chrome::TOUCH_ICON, message_center::kSettingsIconSize); // Note that favicon service obtains the favicon from history. This means // that it will fail to obtain the image if there are no history data for @@ -201,12 +275,11 @@ void MessageCenterSettingsController::GetNotifierList( void MessageCenterSettingsController::SetNotifierEnabled( const Notifier& notifier, bool enabled) { - // TODO(mukai): Fix this for multi-profile. - // If the profile has been destroyed, fail silently. - if (!profile_) - return; + Profile* profile = notifier_groups_[current_notifier_group_]->profile(); + DCHECK(profile); + DesktopNotificationService* notification_service = - DesktopNotificationServiceFactory::GetForProfile(profile_); + DesktopNotificationServiceFactory::GetForProfile(profile); if (notifier.notifier_id.type == NotifierId::WEB_PAGE) { // WEB_PAGE notifier cannot handle in DesktopNotificationService @@ -243,7 +316,7 @@ void MessageCenterSettingsController::SetNotifierEnabled( if (notifier.notifier_id.type == NotifierId::SYNCED_NOTIFICATION_SERVICE) { notifier::ChromeNotifierService* notifier_service = notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile( - profile_, Profile::EXPLICIT_ACCESS); + profile, Profile::EXPLICIT_ACCESS); notifier_service->OnSyncedNotificationServiceEnabled( notifier.notifier_id.id, enabled); } @@ -256,17 +329,6 @@ void MessageCenterSettingsController::OnNotifierSettingsClosing() { patterns_.clear(); } -void MessageCenterSettingsController::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - if (type == chrome::NOTIFICATION_PROFILE_DESTROYED && - content::Source<Profile>(source).ptr() == profile_) { - // Our profile just got destroyed, so we delete our pointer to it. - profile_ = NULL; - } -} - void MessageCenterSettingsController::OnFaviconLoaded( const GURL& url, const chrome::FaviconImageResult& favicon_result) { @@ -283,3 +345,32 @@ void MessageCenterSettingsController::SetAppImage(const std::string& id, UpdateIconImage(NotifierId(NotifierId::APPLICATION, id), gfx::Image(image))); } + +void MessageCenterSettingsController::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + RebuildNotifierGroups(); + FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver, + observers_, + NotifierGroupChanged()); +} + +void MessageCenterSettingsController::RebuildNotifierGroups() { + notifier_groups_.clear(); + current_notifier_group_ = 0; + + const size_t count = profile_info_cache_->GetNumberOfProfiles(); + for (size_t i = 0; i < count; ++i) { + message_center::ProfileNotifierGroup* group = + new message_center::ProfileNotifierGroup( + profile_info_cache_->GetAvatarIconOfProfileAtIndex(i), + profile_info_cache_->GetNameOfProfileAtIndex(i), + profile_info_cache_->GetUserNameOfProfileAtIndex(i), + i, + profile_info_cache_->GetPathOfProfileAtIndex(i)); + if (group->profile() != NULL) { + notifier_groups_.push_back(group); + } + } +} diff --git a/chrome/browser/notifications/message_center_settings_controller.h b/chrome/browser/notifications/message_center_settings_controller.h index 1a66099..4adc136 100644 --- a/chrome/browser/notifications/message_center_settings_controller.h +++ b/chrome/browser/notifications/message_center_settings_controller.h @@ -10,28 +10,36 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/observer_list.h" #include "chrome/browser/extensions/app_icon_loader.h" -#include "chrome/browser/profiles/profile.h" #include "chrome/common/content_settings.h" +#include "content/public/browser/notification_details.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_source.h" #include "ui/message_center/notifier_settings.h" class CancelableTaskTracker; +class ProfileInfoCache; namespace chrome { struct FaviconImageResult; } +namespace message_center { +class ProfileNotifierGroup; +} + // The class to bridge between the settings UI of notifiers and the preference // storage. class MessageCenterSettingsController : public message_center::NotifierSettingsProvider, - public extensions::AppIconLoader::Delegate, - public content::NotificationObserver { + public content::NotificationObserver, + public extensions::AppIconLoader::Delegate { public: - MessageCenterSettingsController(); + explicit MessageCenterSettingsController( + ProfileInfoCache* profile_info_cache); virtual ~MessageCenterSettingsController(); // Overridden from message_center::NotifierSettingsProvider. @@ -39,12 +47,16 @@ class MessageCenterSettingsController message_center::NotifierSettingsObserver* observer) OVERRIDE; virtual void RemoveObserver( message_center::NotifierSettingsObserver* observer) OVERRIDE; - virtual void GetNotifierList( - std::vector<message_center::Notifier*>* notifiers) + virtual size_t GetNotifierGroupCount() const OVERRIDE; + virtual const message_center::NotifierGroup& GetNotifierGroupAt( + size_t index) const OVERRIDE; + virtual void SwitchToNotifierGroup(size_t index) OVERRIDE; + virtual const message_center::NotifierGroup& GetActiveNotifierGroup() const OVERRIDE; - virtual void SetNotifierEnabled( - const message_center::Notifier& notifier, - bool enabled) OVERRIDE; + virtual void GetNotifierList( + std::vector<message_center::Notifier*>* notifiers) OVERRIDE; + virtual void SetNotifierEnabled(const message_center::Notifier& notifier, + bool enabled) OVERRIDE; virtual void OnNotifierSettingsClosing() OVERRIDE; // Overridden from extensions::AppIconLoader::Delegate. @@ -60,6 +72,8 @@ class MessageCenterSettingsController void OnFaviconLoaded(const GURL& url, const chrome::FaviconImageResult& favicon_result); + void RebuildNotifierGroups(); + // The views displaying notifier settings. ObserverList<message_center::NotifierSettingsObserver> observers_; @@ -70,12 +84,14 @@ class MessageCenterSettingsController std::map<string16, ContentSettingsPattern> patterns_; - // The Registrar used to register for notifications. + // The list of all configurable notifier groups. This is each profile that is + // loaded (and in the ProfileInfoCache - so no incognito profiles go here). + ScopedVector<message_center::ProfileNotifierGroup> notifier_groups_; + size_t current_notifier_group_; + content::NotificationRegistrar registrar_; - // TODO(sidharthms): Fix this for multi-profile. - // The profile associated with message center settings. - Profile* profile_; + ProfileInfoCache* profile_info_cache_; DISALLOW_COPY_AND_ASSIGN(MessageCenterSettingsController); }; diff --git a/chrome/browser/notifications/message_center_settings_controller_unittest.cc b/chrome/browser/notifications/message_center_settings_controller_unittest.cc new file mode 100644 index 0000000..e46505c --- /dev/null +++ b/chrome/browser/notifications/message_center_settings_controller_unittest.cc @@ -0,0 +1,71 @@ +// Copyright 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. + +#include <string> + +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/notifications/message_center_settings_controller.h" +#include "chrome/browser/prefs/pref_service_syncable.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/message_center/notifier_settings.h" + +class MessageCenterSettingsControllerTest : public testing::Test { + protected: + MessageCenterSettingsControllerTest() + : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {}; + virtual ~MessageCenterSettingsControllerTest() {}; + + base::FilePath GetProfilePath(const std::string& base_name) { + return testing_profile_manager_.profile_manager()->user_data_dir() + .AppendASCII(base_name); + } + + virtual void SetUp() OVERRIDE { + ASSERT_TRUE(testing_profile_manager_.SetUp()); + } + + ProfileInfoCache* GetCache() { + return testing_profile_manager_.profile_info_cache(); + } + + void CreateProfile(const std::string& name) { + testing_profile_manager_.CreateTestingProfile(name); + } + + TestingProfileManager testing_profile_manager_; +}; + +TEST_F(MessageCenterSettingsControllerTest, NotifierGroups) { + CreateProfile("Profile-1"); + CreateProfile("Profile-2"); + + scoped_ptr<MessageCenterSettingsController> controller( + new MessageCenterSettingsController(GetCache())); + + EXPECT_EQ(controller->GetNotifierGroupCount(), 2u); + + EXPECT_EQ(controller->GetNotifierGroupAt(0).name, UTF8ToUTF16("Profile-1")); + EXPECT_EQ(controller->GetNotifierGroupAt(0).index, 0u); + + EXPECT_EQ(controller->GetNotifierGroupAt(1).name, UTF8ToUTF16("Profile-2")); + EXPECT_EQ(controller->GetNotifierGroupAt(1).index, 1u); + + EXPECT_EQ(controller->GetActiveNotifierGroup().name, + UTF8ToUTF16("Profile-1")); + EXPECT_EQ(controller->GetActiveNotifierGroup().index, 0u); + + controller->SwitchToNotifierGroup(1); + EXPECT_EQ(controller->GetActiveNotifierGroup().name, + UTF8ToUTF16("Profile-2")); + EXPECT_EQ(controller->GetActiveNotifierGroup().index, 1u); + + controller->SwitchToNotifierGroup(0); + EXPECT_EQ(controller->GetActiveNotifierGroup().name, + UTF8ToUTF16("Profile-1")); +} diff --git a/chrome/browser/notifications/notification_ui_manager.cc b/chrome/browser/notifications/notification_ui_manager.cc index 8bbafe7..19e6c24 100644 --- a/chrome/browser/notifications/notification_ui_manager.cc +++ b/chrome/browser/notifications/notification_ui_manager.cc @@ -4,10 +4,14 @@ #include "chrome/browser/notifications/notification_ui_manager.h" +#include "base/memory/scoped_ptr.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/notifications/balloon_notification_ui_manager.h" #include "chrome/browser/notifications/message_center_notification_manager.h" +#include "chrome/browser/notifications/message_center_settings_controller.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_manager.h" #include "ui/message_center/message_center_util.h" // static @@ -24,9 +28,16 @@ bool NotificationUIManager::DelegatesToMessageCenter() { #if !defined(OS_MACOSX) // static NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) { - if (DelegatesToMessageCenter()) + if (DelegatesToMessageCenter()) { + ProfileInfoCache* profile_info_cache = + &g_browser_process->profile_manager()->GetProfileInfoCache(); + scoped_ptr<message_center::NotifierSettingsProvider> settings_provider( + new MessageCenterSettingsController(profile_info_cache)); return new MessageCenterNotificationManager( - g_browser_process->message_center(), local_state); + g_browser_process->message_center(), + local_state, + settings_provider.Pass()); + } BalloonNotificationUIManager* balloon_manager = new BalloonNotificationUIManager(local_state); diff --git a/chrome/browser/notifications/notification_ui_manager_mac.mm b/chrome/browser/notifications/notification_ui_manager_mac.mm index 5222aa1..d0b783c 100644 --- a/chrome/browser/notifications/notification_ui_manager_mac.mm +++ b/chrome/browser/notifications/notification_ui_manager_mac.mm @@ -6,12 +6,16 @@ #include "base/mac/cocoa_protocols.h" #include "base/mac/mac_util.h" +#include "base/memory/scoped_ptr.h" #include "base/strings/sys_string_conversions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/notifications/notification.h" #include "chrome/browser/notifications/balloon_notification_ui_manager.h" #include "chrome/browser/notifications/message_center_notification_manager.h" +#include "chrome/browser/notifications/message_center_settings_controller.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_manager.h" #include "ui/message_center/message_center_util.h" @class NSUserNotificationCenter; @@ -101,8 +105,14 @@ NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) { // TODO(rsesek): Remove this function and merge it with the one in // notification_ui_manager.cc. if (DelegatesToMessageCenter()) { + ProfileInfoCache* profile_info_cache = + &g_browser_process->profile_manager()->GetProfileInfoCache(); + scoped_ptr<message_center::NotifierSettingsProvider> settings_provider( + new MessageCenterSettingsController(profile_info_cache)); return new MessageCenterNotificationManager( - g_browser_process->message_center(), local_state); + g_browser_process->message_center(), + local_state, + settings_provider.Pass()); } BalloonNotificationUIManager* balloon_manager = NULL; diff --git a/chrome/browser/ui/ash/screenshot_taker_unittest.cc b/chrome/browser/ui/ash/screenshot_taker_unittest.cc index 439a6a1..a35339a 100644 --- a/chrome/browser/ui/ash/screenshot_taker_unittest.cc +++ b/chrome/browser/ui/ash/screenshot_taker_unittest.cc @@ -14,9 +14,9 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/test_utils.h" #include "ui/aura/root_window.h" @@ -36,13 +36,10 @@ class ScreenshotTakerTest : public AshTestBase, virtual void SetUp() { AshTestBase::SetUp(); - local_state_.reset( - new ScopedTestingLocalState(TestingBrowserProcess::GetGlobal())); } virtual void TearDown() { RunAllPendingInMessageLoop(); - local_state_.reset(); AshTestBase::TearDown(); } @@ -87,7 +84,6 @@ class ScreenshotTakerTest : public AshTestBase, EXPECT_TRUE(screenshot_complete_); } - scoped_ptr<ScopedTestingLocalState> local_state_; bool running_; bool screenshot_complete_; ScreenshotTakerObserver::Result screenshot_result_; @@ -98,14 +94,18 @@ class ScreenshotTakerTest : public AshTestBase, }; TEST_F(ScreenshotTakerTest, TakeScreenshot) { - TestingProfile profile; + scoped_ptr<TestingProfileManager> profile_manager( + new TestingProfileManager(TestingBrowserProcess::GetGlobal())); + ASSERT_TRUE(profile_manager->SetUp()); + TestingProfile* profile = + profile_manager->CreateTestingProfile("test_profile"); ScreenshotTaker screenshot_taker; screenshot_taker.AddObserver(this); base::ScopedTempDir directory; ASSERT_TRUE(directory.CreateUniqueTempDir()); SetScreenshotDirectoryForTest(&screenshot_taker, directory.path()); SetScreenshotBasenameForTest(&screenshot_taker, "Screenshot"); - SetScreenshotProfileForTest(&screenshot_taker, &profile); + SetScreenshotProfileForTest(&screenshot_taker, profile); EXPECT_TRUE(screenshot_taker.CanTakeScreenshot()); diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index be7412b..d26af2f 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -30,6 +30,7 @@ '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', '../third_party/zlib/zlib.gyp:zlib', + '../ui/message_center/message_center.gyp:message_center_test_support', ], 'export_dependent_settings': [ 'app/policy/cloud_policy_codegen.gyp:policy_test_support', @@ -998,6 +999,7 @@ 'browser/net/url_info_unittest.cc', 'browser/notifications/desktop_notification_service_unittest.cc', 'browser/notifications/message_center_notifications_unittest_win.cc', + 'browser/notifications/message_center_settings_controller_unittest.cc', 'browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc', 'browser/notifications/sync_notifier/synced_notification_unittest.cc', 'browser/notifications/sync_notifier/sync_notifier_test_utils.cc', diff --git a/ui/base/strings/ui_strings.grd b/ui/base/strings/ui_strings.grd index 21d7001..94b99d2 100644 --- a/ui/base/strings/ui_strings.grd +++ b/ui/base/strings/ui_strings.grd @@ -464,9 +464,16 @@ need to be translated for each locale.--> <message name="IDS_MESSAGE_CENTER_SETTINGS_GO_BACK_BUTTON_TOOLTIP" desc="The tooltip on back button that returns from settings to the notification list."> Go back to notifications </message> - <message name="IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION" desc="The label to describe the settings dialog."> - Allow notifications from the following: - </message> + <if expr="is_macosx"> + <message name="IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION" desc="The label to describe the settings dialog."> + Allow notifications from the following: + </message> + </if> + <if expr="not is_macosx"> + <message name="IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION" desc="The label to describe the settings dialog."> + Manage notifications per profile: + </message> + </if> <message name="IDS_MESSAGE_CENTER_SETTINGS" desc="The menu entry or button for visiting the appropriate settings page."> Settings... </message> diff --git a/ui/message_center/cocoa/settings_controller.h b/ui/message_center/cocoa/settings_controller.h index d81b99b..380ae14 100644 --- a/ui/message_center/cocoa/settings_controller.h +++ b/ui/message_center/cocoa/settings_controller.h @@ -26,6 +26,7 @@ class NotifierSettingsObserverMac : public NotifierSettingsObserver { // Overridden from NotifierSettingsObserver: virtual void UpdateIconImage(const NotifierId& notifier_id, const gfx::Image& icon) OVERRIDE; + virtual void NotifierGroupChanged() OVERRIDE; private: MCSettingsController* settings_controller_; // weak, owns this diff --git a/ui/message_center/cocoa/settings_controller.mm b/ui/message_center/cocoa/settings_controller.mm index 45c66ea..f34f9f0 100644 --- a/ui/message_center/cocoa/settings_controller.mm +++ b/ui/message_center/cocoa/settings_controller.mm @@ -110,6 +110,8 @@ void NotifierSettingsObserverMac::UpdateIconImage(const NotifierId& notifier_id, [settings_controller_ setIcon:icon.AsNSImage() forNotifierId:notifier_id]; } +void NotifierSettingsObserverMac::NotifierGroupChanged() {} + } // namespace message_center @implementation MCSettingsController diff --git a/ui/message_center/fake_notifier_settings_provider.cc b/ui/message_center/fake_notifier_settings_provider.cc index 0695d08..66b193b 100644 --- a/ui/message_center/fake_notifier_settings_provider.cc +++ b/ui/message_center/fake_notifier_settings_provider.cc @@ -4,14 +4,36 @@ #include "ui/message_center/fake_notifier_settings_provider.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/gfx/image/image.h" + namespace message_center { FakeNotifierSettingsProvider::FakeNotifierSettingsProvider( const std::vector<Notifier*>& notifiers) - : notifiers_(notifiers), closed_called_count_(0) {} + : notifiers_(notifiers), + notifier_group_(gfx::Image(), + UTF8ToUTF16("Fake name"), + UTF8ToUTF16("fake@email.com"), + true), + closed_called_count_(0) {} FakeNotifierSettingsProvider::~FakeNotifierSettingsProvider() {} +size_t FakeNotifierSettingsProvider::GetNotifierGroupCount() const { return 1; } + +const message_center::NotifierGroup& +FakeNotifierSettingsProvider::GetNotifierGroupAt(size_t index) const { + return notifier_group_; +} + +void FakeNotifierSettingsProvider::SwitchToNotifierGroup(size_t index) {} + +const message_center::NotifierGroup& +FakeNotifierSettingsProvider::GetActiveNotifierGroup() const { + return notifier_group_; +} + void FakeNotifierSettingsProvider::GetNotifierList( std::vector<Notifier*>* notifiers) { notifiers->clear(); diff --git a/ui/message_center/fake_notifier_settings_provider.h b/ui/message_center/fake_notifier_settings_provider.h index 47a3549..f2c5cd7 100644 --- a/ui/message_center/fake_notifier_settings_provider.h +++ b/ui/message_center/fake_notifier_settings_provider.h @@ -14,7 +14,14 @@ namespace message_center { class FakeNotifierSettingsProvider : public NotifierSettingsProvider { public: FakeNotifierSettingsProvider(const std::vector<Notifier*>& notifiers); - ~FakeNotifierSettingsProvider(); + virtual ~FakeNotifierSettingsProvider(); + + virtual size_t GetNotifierGroupCount() const OVERRIDE; + virtual const message_center::NotifierGroup& GetNotifierGroupAt( + size_t index) const OVERRIDE; + virtual void SwitchToNotifierGroup(size_t index) OVERRIDE; + virtual const message_center::NotifierGroup& GetActiveNotifierGroup() const + OVERRIDE; virtual void GetNotifierList(std::vector<Notifier*>* notifiers) OVERRIDE; @@ -31,6 +38,7 @@ class FakeNotifierSettingsProvider : public NotifierSettingsProvider { private: std::vector<Notifier*> notifiers_; std::map<const Notifier*, bool> enabled_; + const NotifierGroup notifier_group_; int closed_called_count_; }; diff --git a/ui/message_center/message_center.gyp b/ui/message_center/message_center.gyp index eac6938..dc1f1ab 100644 --- a/ui/message_center/message_center.gyp +++ b/ui/message_center/message_center.gyp @@ -70,6 +70,8 @@ 'views/message_bubble_base.h', 'views/message_center_bubble.cc', 'views/message_center_bubble.h', + 'views/message_center_button_bar.cc', + 'views/message_center_button_bar.h', 'views/message_center_view.cc', 'views/message_center_view.h', 'views/message_popup_collection.cc', diff --git a/ui/message_center/notifier_settings.cc b/ui/message_center/notifier_settings.cc index 85c6097..4355b94 100644 --- a/ui/message_center/notifier_settings.cc +++ b/ui/message_center/notifier_settings.cc @@ -50,8 +50,15 @@ Notifier::Notifier(const NotifierId& notifier_id, Notifier::~Notifier() { } -std::string ToString( - NotifierId::SystemComponentNotifierType type) { +NotifierGroup::NotifierGroup(const gfx::Image& icon, + const string16& name, + const string16& login_info, + size_t index) + : icon(icon), name(name), login_info(login_info), index(index) {} + +NotifierGroup::~NotifierGroup() {} + +std::string ToString(NotifierId::SystemComponentNotifierType type) { switch (type) { case NotifierId::SCREENSHOT: return "screenshot"; diff --git a/ui/message_center/notifier_settings.h b/ui/message_center/notifier_settings.h index c494048..05fc7fe 100644 --- a/ui/message_center/notifier_settings.h +++ b/ui/message_center/notifier_settings.h @@ -84,6 +84,30 @@ struct MESSAGE_CENTER_EXPORT Notifier { DISALLOW_COPY_AND_ASSIGN(Notifier); }; +struct MESSAGE_CENTER_EXPORT NotifierGroup { + NotifierGroup(const gfx::Image& icon, + const string16& name, + const string16& login_info, + size_t index); + ~NotifierGroup(); + + // Icon of a notifier group. + const gfx::Image icon; + + // Display name of a notifier group. + const string16 name; + + // More display information about the notifier group. + string16 login_info; + + // Unique identifier for the notifier group so that they can be selected in + // the UI. + const size_t index; + + private: + DISALLOW_COPY_AND_ASSIGN(NotifierGroup); +}; + MESSAGE_CENTER_EXPORT std::string ToString( NotifierId::SystemComponentNotifierType type); MESSAGE_CENTER_EXPORT NotifierId::SystemComponentNotifierType @@ -96,16 +120,36 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsObserver { // Called when an icon in the controller has been updated. virtual void UpdateIconImage(const NotifierId& notifier_id, const gfx::Image& icon) = 0; + + // Called when any change happens to the set of notifier groups. + virtual void NotifierGroupChanged() = 0; }; // A class used by NotifierSettingsView to integrate with a setting system // for the clients of this module. class MESSAGE_CENTER_EXPORT NotifierSettingsProvider { public: + virtual ~NotifierSettingsProvider() {}; + // Sets the delegate. virtual void AddObserver(NotifierSettingsObserver* observer) = 0; virtual void RemoveObserver(NotifierSettingsObserver* observer) = 0; + // Returns the number of notifier groups available. + virtual size_t GetNotifierGroupCount() const = 0; + + // Requests the model for a particular notifier group. + virtual const message_center::NotifierGroup& GetNotifierGroupAt( + size_t index) const = 0; + + // Informs the settings provider that further requests to GetNotifierList + // should return notifiers for the specified notifier group. + virtual void SwitchToNotifierGroup(size_t index) = 0; + + // Requests the currently active notifier group. + virtual const message_center::NotifierGroup& GetActiveNotifierGroup() + const = 0; + // Collects the current notifier list and fills to |notifiers|. Caller takes // the ownership of the elements of |notifiers|. virtual void GetNotifierList(std::vector<Notifier*>* notifiers) = 0; diff --git a/ui/message_center/views/message_center_button_bar.cc b/ui/message_center/views/message_center_button_bar.cc new file mode 100644 index 0000000..b436bf3 --- /dev/null +++ b/ui/message_center/views/message_center_button_bar.cc @@ -0,0 +1,210 @@ +// Copyright 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. + +#include "ui/message_center/views/message_center_button_bar.h" + +#include "grit/ui_resources.h" +#include "grit/ui_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/simple_menu_model.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/text_constants.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/message_center_style.h" +#include "ui/message_center/notifier_settings.h" +#include "ui/message_center/views/message_center_view.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/button/menu_button.h" +#include "ui/views/controls/button/menu_button_listener.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/menu/menu_runner.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/grid_layout.h" + +namespace message_center { + +namespace { +const int kButtonSize = 40; +const int kChevronMargin = 4; +const int kFooterLeftMargin = 17; +const int kFooterRightMargin = 14; +} // namespace + +// NotificationCenterButton //////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +class NotificationCenterButton : public views::ToggleImageButton { + public: + NotificationCenterButton(views::ButtonListener* listener, + int normal_id, + int hover_id, + int pressed_id, + int text_id); + + protected: + // Overridden from views::View: + virtual gfx::Size GetPreferredSize() OVERRIDE; + virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(NotificationCenterButton); +}; + +NotificationCenterButton::NotificationCenterButton( + views::ButtonListener* listener, + int normal_id, + int hover_id, + int pressed_id, + int text_id) + : views::ToggleImageButton(listener) { + ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); + SetImage(STATE_NORMAL, resource_bundle.GetImageSkiaNamed(normal_id)); + SetImage(STATE_HOVERED, resource_bundle.GetImageSkiaNamed(hover_id)); + SetImage(STATE_PRESSED, resource_bundle.GetImageSkiaNamed(pressed_id)); + SetImageAlignment(views::ImageButton::ALIGN_CENTER, + views::ImageButton::ALIGN_MIDDLE); + SetTooltipText(resource_bundle.GetLocalizedString(text_id)); + set_focusable(true); + set_request_focus_on_press(false); +} + +gfx::Size NotificationCenterButton::GetPreferredSize() { + return gfx::Size(kButtonSize, kButtonSize); +} + +void NotificationCenterButton::OnPaintFocusBorder(gfx::Canvas* canvas) { + if (HasFocus() && (focusable() || IsAccessibilityFocusable())) { + canvas->DrawRect(gfx::Rect(2, 1, width() - 4, height() - 3), + kFocusBorderColor); + } +} + +// MessageCenterButtonBar ///////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +MessageCenterButtonBar::MessageCenterButtonBar( + MessageCenterView* message_center_view, + MessageCenter* message_center, + NotifierSettingsProvider* notifier_settings_provider, + bool settings_initially_visible) + : message_center_view_(message_center_view), + message_center_(message_center), + close_all_button_(NULL), + quiet_mode_button_(NULL) { + if (get_use_acceleration_when_possible()) + SetPaintToLayer(true); + set_background( + views::Background::CreateSolidBackground(kMessageCenterBackgroundColor)); + + views::Label* notification_label = new views::Label( + l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_FOOTER_TITLE)); + notification_label->SetAutoColorReadabilityEnabled(false); + notification_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + notification_label->SetEnabledColor(kRegularTextColor); + AddChildView(notification_label); + + views::View* button_container = new views::View; + button_container->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); + quiet_mode_button_ = new NotificationCenterButton( + this, + IDR_NOTIFICATION_DO_NOT_DISTURB, + IDR_NOTIFICATION_DO_NOT_DISTURB_HOVER, + IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED, + IDS_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP); + ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); + quiet_mode_button_->SetToggledImage( + views::Button::STATE_NORMAL, + resource_bundle.GetImageSkiaNamed( + IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED)); + quiet_mode_button_->SetToggledImage( + views::Button::STATE_HOVERED, + resource_bundle.GetImageSkiaNamed( + IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED)); + quiet_mode_button_->SetToggledImage( + views::Button::STATE_PRESSED, + resource_bundle.GetImageSkiaNamed( + IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED)); + quiet_mode_button_->SetToggled(message_center->IsQuietMode()); + button_container->AddChildView(quiet_mode_button_); + + close_all_button_ = + new NotificationCenterButton(this, + IDR_NOTIFICATION_CLEAR_ALL, + IDR_NOTIFICATION_CLEAR_ALL_HOVER, + IDR_NOTIFICATION_CLEAR_ALL_PRESSED, + IDS_MESSAGE_CENTER_CLEAR_ALL); + button_container->AddChildView(close_all_button_); + settings_button_ = + new NotificationCenterButton(this, + IDR_NOTIFICATION_SETTINGS, + IDR_NOTIFICATION_SETTINGS_HOVER, + IDR_NOTIFICATION_SETTINGS_PRESSED, + IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL); + button_container->AddChildView(settings_button_); + + gfx::ImageSkia* settings_image = + ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_NOTIFICATION_SETTINGS); + int image_margin = std::max(0, (kButtonSize - settings_image->width()) / 2); + views::GridLayout* layout = new views::GridLayout(this); + SetLayoutManager(layout); + layout->SetInsets( + 0, kFooterLeftMargin, 0, std::max(0, kFooterRightMargin - image_margin)); + views::ColumnSet* column = layout->AddColumnSet(0); + column->AddColumn(views::GridLayout::FILL, + views::GridLayout::FILL, + 1.0f, + views::GridLayout::USE_PREF, + 0, + 0); + column->AddColumn(views::GridLayout::LEADING, + views::GridLayout::FILL, + 0, + views::GridLayout::USE_PREF, + 0, + 0); + layout->StartRow(0, 0); + layout->AddView(notification_label); + layout->AddView(button_container); +} + +MessageCenterButtonBar::~MessageCenterButtonBar() {} + +void MessageCenterButtonBar::SetAllButtonsEnabled(bool enabled) { + if (close_all_button_) + close_all_button_->SetEnabled(enabled); + settings_button_->SetEnabled(enabled); + quiet_mode_button_->SetEnabled(enabled); +} + +void MessageCenterButtonBar::SetCloseAllButtonVisible(bool visible) { + if (close_all_button_) + close_all_button_->SetVisible(visible); +} + +void MessageCenterButtonBar::ChildVisibilityChanged(views::View* child) { + InvalidateLayout(); +} + +void MessageCenterButtonBar::ButtonPressed(views::Button* sender, + const ui::Event& event) { + if (sender == close_all_button_) { + message_center_view()->ClearAllNotifications(); + } else if (sender == settings_button_) { + MessageCenterView* center_view = message_center_view(); + center_view->SetSettingsVisible(!center_view->settings_visible()); + } else if (sender == quiet_mode_button_) { + if (message_center()->IsQuietMode()) + message_center()->SetQuietMode(false); + else + message_center()->EnterQuietModeWithExpire(base::TimeDelta::FromDays(1)); + quiet_mode_button_->SetToggled(message_center()->IsQuietMode()); + } else { + NOTREACHED(); + } +} + +} // namespace message_center diff --git a/ui/message_center/views/message_center_button_bar.h b/ui/message_center/views/message_center_button_bar.h new file mode 100644 index 0000000..72b30c9 --- /dev/null +++ b/ui/message_center/views/message_center_button_bar.h @@ -0,0 +1,68 @@ +// Copyright 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_VIEWS_MESSAGE_CENTER_BUTTON_BAR_H_ +#define UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_BUTTON_BAR_H_ + +#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" + +namespace views { +class Label; +} + +namespace message_center { + +class ButtonBarSettingsLabel; +class MessageCenter; +class MessageCenterTray; +class MessageCenterView; +class NotificationCenterButton; +class NotifierSettingsProvider; + +// MessageCenterButtonBar is the class that shows the content outside the main +// notification area - the label (or NotifierGroup switcher) and the buttons. +class MessageCenterButtonBar : public views::View, + public views::ButtonListener { + public: + MessageCenterButtonBar(MessageCenterView* message_center_view, + MessageCenter* message_center, + NotifierSettingsProvider* notifier_settings_provider, + bool settings_initially_visible); + virtual ~MessageCenterButtonBar(); + + // Enables or disables all of the buttons in the center. This is used to + // prevent user clicks during the close-all animation. + virtual void SetAllButtonsEnabled(bool enabled); + + // Sometimes we shouldn't see the close-all button. + void SetCloseAllButtonVisible(bool visible); + + private: + // Overridden from views::View: + virtual void ChildVisibilityChanged(views::View* child) OVERRIDE; + + // Overridden from views::ButtonListener: + virtual void ButtonPressed(views::Button* sender, + const ui::Event& event) OVERRIDE; + + MessageCenterView* message_center_view() const { + return message_center_view_; + } + MessageCenter* message_center() const { return message_center_; } + + MessageCenterView* message_center_view_; // Weak reference. + MessageCenter* message_center_; // Weak reference. + + // Sub-views of the button bar. + views::Button* close_all_button_; + NotificationCenterButton* settings_button_; + NotificationCenterButton* quiet_mode_button_; + + DISALLOW_COPY_AND_ASSIGN(MessageCenterButtonBar); +}; + +} // namespace message_center + +#endif // UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_BUTTON_BAR_H_ diff --git a/ui/message_center/views/message_center_view.cc b/ui/message_center/views/message_center_view.cc index ee7ac74..9f0d2fd 100644 --- a/ui/message_center/views/message_center_view.cc +++ b/ui/message_center/views/message_center_view.cc @@ -10,22 +10,17 @@ #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/stl_util.h" -#include "grit/ui_resources.h" #include "grit/ui_strings.h" #include "ui/base/animation/multi_animation.h" #include "ui/base/animation/slide_animation.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/insets.h" -#include "ui/gfx/point.h" #include "ui/gfx/rect.h" #include "ui/gfx/size.h" -#include "ui/gfx/text_constants.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_style.h" -#include "ui/message_center/message_center_tray.h" -#include "ui/message_center/message_center_util.h" +#include "ui/message_center/views/message_center_button_bar.h" #include "ui/message_center/views/message_view.h" #include "ui/message_center/views/notification_view.h" #include "ui/message_center/views/notifier_settings_view.h" @@ -34,238 +29,30 @@ #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/label.h" #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/scrollbar/overlay_scroll_bar.h" #include "ui/views/layout/box_layout.h" -#include "ui/views/layout/grid_layout.h" -#include "ui/views/painter.h" #include "ui/views/widget/widget.h" namespace message_center { namespace { -const int kMinScrollViewHeight = 100; -const int kFooterLeftMargin = 17; -const int kFooterRightMargin = 14; -const int kButtonSize = 40; -const SkColor kNoNotificationsTextColor = SkColorSetRGB(0xb4, 0xb4, 0xb4); const SkColor kBorderDarkColor = SkColorSetRGB(0xaa, 0xaa, 0xaa); -const SkColor kTransparentColor = SkColorSetARGB(0, 0, 0, 0); const SkColor kButtonTextHighlightColor = SkColorSetRGB(0x2a, 0x2a, 0x2a); const SkColor kButtonTextHoverColor = SkColorSetRGB(0x2a, 0x2a, 0x2a); +const SkColor kNoNotificationsTextColor = SkColorSetRGB(0xb4, 0xb4, 0xb4); +const SkColor kTransparentColor = SkColorSetARGB(0, 0, 0, 0); const int kAnimateClearingNextNotificationDelayMS = 40; +const int kButtonBarBorderThickness = 1; +const int kMinScrollViewHeight = 100; -static const int kDefaultFrameRateHz = 60; static const int kDefaultAnimationDurationMs = 120; +static const int kDefaultFrameRateHz = 60; } // namespace -// NotificationCenterButton //////////////////////////////////////////////////// - -class NotificationCenterButton : public views::ToggleImageButton { - public: - NotificationCenterButton(views::ButtonListener* listener, - int normal_id, - int hover_id, - int pressed_id, - int text_id); - - protected: - // Overridden from views::View: - virtual gfx::Size GetPreferredSize() OVERRIDE; - virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(NotificationCenterButton); -}; - -NotificationCenterButton::NotificationCenterButton( - views::ButtonListener* listener, - int normal_id, - int hover_id, - int pressed_id, - int text_id) - : views::ToggleImageButton(listener) { - ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); - SetImage(STATE_NORMAL, resource_bundle.GetImageSkiaNamed(normal_id)); - SetImage(STATE_HOVERED, resource_bundle.GetImageSkiaNamed(hover_id)); - SetImage(STATE_PRESSED, resource_bundle.GetImageSkiaNamed(pressed_id)); - SetImageAlignment(views::ImageButton::ALIGN_CENTER, - views::ImageButton::ALIGN_MIDDLE); - SetTooltipText(resource_bundle.GetLocalizedString(text_id)); - set_focusable(true); - set_request_focus_on_press(false); -} - -gfx::Size NotificationCenterButton::GetPreferredSize() { - return gfx::Size(kButtonSize, kButtonSize); -} - -void NotificationCenterButton::OnPaintFocusBorder(gfx::Canvas* canvas) { - if (HasFocus() && (focusable() || IsAccessibilityFocusable())) { - canvas->DrawRect(gfx::Rect(2, 1, width() - 4, height() - 3), - kFocusBorderColor); - } -} - -// MessageCenterButtonBar ////////////////////////////////////////////////// - -class MessageCenterButtonBar : public views::View, - public views::ButtonListener { - public: - MessageCenterButtonBar(MessageCenterView* message_center_view, - MessageCenter* message_center); - virtual ~MessageCenterButtonBar(); - - virtual void SetAllButtonsEnabled(bool enabled); - void SetCloseAllVisible(bool visible); - - private: - // Overridden from views::View: - virtual void ChildVisibilityChanged(views::View* child) OVERRIDE; - - // Overridden from views::ButtonListener: - virtual void ButtonPressed(views::Button* sender, const ui::Event& event) - OVERRIDE; - - MessageCenterView* message_center_view() const { - return message_center_view_; - } - MessageCenter* message_center() const { return message_center_; } - MessageCenterTray* tray() const { return tray_; } - views::Button* close_all_button() const { return close_all_button_; } - void set_close_all_button(views::Button* button) { - close_all_button_ = button; - } - - MessageCenterView* message_center_view_; // Weak reference. - MessageCenter* message_center_; // Weak reference. - MessageCenterTray* tray_; // Weak reference. - views::Button* close_all_button_; - NotificationCenterButton* settings_button_; - NotificationCenterButton* quiet_mode_button_; - - DISALLOW_COPY_AND_ASSIGN(MessageCenterButtonBar); -}; - -MessageCenterButtonBar::MessageCenterButtonBar( - MessageCenterView* message_center_view, - MessageCenter* message_center) - : message_center_view_(message_center_view), - message_center_(message_center), - close_all_button_(NULL) { - if (get_use_acceleration_when_possible()) - SetPaintToLayer(true); - set_background(views::Background::CreateSolidBackground( - kMessageCenterBackgroundColor)); - - views::Label* notification_label = new views::Label(l10n_util::GetStringUTF16( - IDS_MESSAGE_CENTER_FOOTER_TITLE)); - notification_label->SetAutoColorReadabilityEnabled(false); - notification_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - notification_label->SetEnabledColor(kRegularTextColor); - AddChildView(notification_label); - - views::View* button_container = new views::View; - button_container->SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); - quiet_mode_button_ = new NotificationCenterButton( - this, - IDR_NOTIFICATION_DO_NOT_DISTURB, - IDR_NOTIFICATION_DO_NOT_DISTURB_HOVER, - IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED, - IDS_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP); - ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); - quiet_mode_button_->SetToggledImage( - views::Button::STATE_NORMAL, - resource_bundle.GetImageSkiaNamed( - IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED)); - quiet_mode_button_->SetToggledImage( - views::Button::STATE_HOVERED, - resource_bundle.GetImageSkiaNamed( - IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED)); - quiet_mode_button_->SetToggledImage( - views::Button::STATE_PRESSED, - resource_bundle.GetImageSkiaNamed( - IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED)); - quiet_mode_button_->SetToggled(message_center->IsQuietMode()); - button_container->AddChildView(quiet_mode_button_); - - NotificationCenterButton* close_all_button = new NotificationCenterButton( - this, - IDR_NOTIFICATION_CLEAR_ALL, - IDR_NOTIFICATION_CLEAR_ALL_HOVER, - IDR_NOTIFICATION_CLEAR_ALL_PRESSED, - IDS_MESSAGE_CENTER_CLEAR_ALL); - button_container->AddChildView(close_all_button); - set_close_all_button(close_all_button); - settings_button_ = new NotificationCenterButton( - this, - IDR_NOTIFICATION_SETTINGS, - IDR_NOTIFICATION_SETTINGS_HOVER, - IDR_NOTIFICATION_SETTINGS_PRESSED, - IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL); - button_container->AddChildView(settings_button_); - - gfx::ImageSkia* settings_image = - ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - IDR_NOTIFICATION_SETTINGS); - int image_margin = std::max(0, (kButtonSize - settings_image->width()) / 2); - views::GridLayout* layout = new views::GridLayout(this); - SetLayoutManager(layout); - layout->SetInsets( - 0, kFooterLeftMargin, 0, std::max(0, kFooterRightMargin - image_margin)); - views::ColumnSet* column = layout->AddColumnSet(0); - column->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, - 1.0f, views::GridLayout::USE_PREF, 0, 0); - column->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, - 0, views::GridLayout::USE_PREF, 0, 0); - layout->StartRow(0, 0); - layout->AddView(notification_label); - layout->AddView(button_container); -} - -MessageCenterButtonBar::~MessageCenterButtonBar() {} - -void MessageCenterButtonBar::SetAllButtonsEnabled(bool enabled) { - if (close_all_button_) - close_all_button_->SetEnabled(enabled); - settings_button_->SetEnabled(enabled); - quiet_mode_button_->SetEnabled(enabled); -} - -void MessageCenterButtonBar::SetCloseAllVisible(bool visible) { - if (close_all_button_) - close_all_button_->SetVisible(visible); -} - -// Overridden from views::View: -void MessageCenterButtonBar::ChildVisibilityChanged(views::View* child) { - InvalidateLayout(); -} - -// Overridden from views::ButtonListener: -void MessageCenterButtonBar::ButtonPressed(views::Button* sender, - const ui::Event& event) { - if (sender == close_all_button()) { - message_center_view()->ClearAllNotifications(); - } else if (sender == settings_button_) { - MessageCenterView* center_view = static_cast<MessageCenterView*>(parent()); - center_view->SetSettingsVisible(!center_view->settings_visible()); - } else if (sender == quiet_mode_button_) { - if (message_center()->IsQuietMode()) - message_center()->SetQuietMode(false); - else - message_center()->EnterQuietModeWithExpire(base::TimeDelta::FromDays(1)); - quiet_mode_button_->SetToggled(message_center()->IsQuietMode()); - } else { - NOTREACHED(); - } -} - // BoundedScrollView /////////////////////////////////////////////////////////// // A custom scroll view whose height has a minimum and maximum value and whose @@ -806,17 +593,33 @@ MessageCenterView::MessageCenterView(MessageCenter* message_center, tray_(tray), top_down_(top_down), settings_visible_(initially_settings_visible), + source_view_(NULL), + source_height_(0), + target_view_(NULL), + target_height_(0), is_closing_(false) { message_center_->AddObserver(this); set_notify_enter_exit_on_child(true); set_background(views::Background::CreateSolidBackground( kMessageCenterBackgroundColor)); - button_bar_ = new MessageCenterButtonBar(this, message_center); + NotifierSettingsProvider* notifier_settings_provider = + message_center_->GetNotifierSettingsProvider(); + button_bar_ = new MessageCenterButtonBar(this, + message_center, + notifier_settings_provider, + initially_settings_visible); const int button_height = button_bar_->GetPreferredSize().height(); - scroller_ = new BoundedScrollView(kMinScrollViewHeight, - max_height - button_height); + button_bar_->set_border(views::Border::CreateSolidSidedBorder( + top_down_ ? 0 : kButtonBarBorderThickness, + 0, + top_down_ ? kButtonBarBorderThickness : 0, + 0, + kFooterDelimiterColor)); + + scroller_ = + new BoundedScrollView(kMinScrollViewHeight, max_height - button_height); if (get_use_acceleration_when_possible()) { scroller_->SetPaintToLayer(true); @@ -832,8 +635,7 @@ MessageCenterView::MessageCenterView(MessageCenter* message_center, message_list_view_->AddChildView(no_notifications_message_view_); scroller_->SetContents(message_list_view_); - settings_view_ = new NotifierSettingsView( - message_center_->GetNotifierSettingsProvider()); + settings_view_ = new NotifierSettingsView(notifier_settings_provider); if (initially_settings_visible) scroller_->SetVisible(false); @@ -915,13 +717,6 @@ void MessageCenterView::SetSettingsVisible(bool visible) { settings_transition_animation_->Start(); } -void MessageCenterView::SetIsClosing(bool is_closing) { - is_closing_ = is_closing; - if (is_closing) - message_center_->RemoveObserver(this); - else - message_center_->AddObserver(this); -} void MessageCenterView::ClearAllNotifications() { if (is_closing_) @@ -942,11 +737,26 @@ size_t MessageCenterView::NumMessageViewsForTest() const { return message_list_view_->child_count(); } +void MessageCenterView::OnSettingsChanged() { + scroller_->InvalidateLayout(); + PreferredSizeChanged(); + Layout(); +} + +void MessageCenterView::SetIsClosing(bool is_closing) { + is_closing_ = is_closing; + if (is_closing) + message_center_->RemoveObserver(this); + else + message_center_->AddObserver(this); +} + void MessageCenterView::Layout() { if (is_closing_) return; - int button_height = button_bar_->GetHeightForWidth(width()); + int button_height = button_bar_->GetHeightForWidth(width()) + + button_bar_->GetInsets().height(); // Skip unnecessary re-layout of contents during the resize animation. if (settings_transition_animation_ && settings_transition_animation_->is_animating() && @@ -966,27 +776,6 @@ void MessageCenterView::Layout() { width(), height() - button_height); - bool is_scrollable = false; - if (scroller_->visible()) - is_scrollable = scroller_->height() < message_list_view_->height(); - else - is_scrollable = settings_view_->IsScrollable(); - - if (is_scrollable && !button_bar_->border()) { - // Draw separator line on the top of the button bar if it is on the bottom - // or draw it at the bottom if the bar is on the top. - button_bar_->set_border(views::Border::CreateSolidSidedBorder( - top_down_ ? 0 : 1, - 0, - top_down_ ? 1 : 0, - 0, - kFooterDelimiterColor)); - button_bar_->SchedulePaint(); - } else if (!is_scrollable && button_bar_->border()) { - button_bar_->set_border(NULL); - button_bar_->SchedulePaint(); - } - button_bar_->SetBounds(0, top_down_ ? 0 : height() - button_height, width(), @@ -1030,7 +819,8 @@ int MessageCenterView::GetHeightForWidth(int width) { content_height += scroller_->GetHeightForWidth(width); else content_height += settings_view_->GetHeightForWidth(width); - return button_bar_->GetHeightForWidth(width) + content_height; + return button_bar_->GetHeightForWidth(width) + + button_bar_->GetInsets().height() + content_height; } bool MessageCenterView::OnMouseWheel(const ui::MouseWheelEvent& event) { @@ -1178,15 +968,12 @@ void MessageCenterView::AddNotificationAt(const Notification& notification, } void MessageCenterView::NotificationsChanged() { - if (!message_views_.empty()) { - no_notifications_message_view_->SetVisible(false); - button_bar_->SetCloseAllVisible(true); - scroller_->set_focusable(true); - } else { - no_notifications_message_view_->SetVisible(true); - button_bar_->SetCloseAllVisible(false); - scroller_->set_focusable(false); - } + bool no_message_views = message_views_.empty(); + + no_notifications_message_view_->SetVisible(no_message_views); + button_bar_->SetCloseAllButtonVisible(!no_message_views); + scroller_->set_focusable(!no_message_views); + scroller_->InvalidateLayout(); PreferredSizeChanged(); Layout(); diff --git a/ui/message_center/views/message_center_view.h b/ui/message_center/views/message_center_view.h index 506a3a4..d53910c 100644 --- a/ui/message_center/views/message_center_view.h +++ b/ui/message_center/views/message_center_view.h @@ -54,6 +54,7 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View, size_t NumMessageViewsForTest() const; void SetSettingsVisible(bool visible); + void OnSettingsChanged(); bool settings_visible() const { return settings_visible_; } void SetIsClosing(bool is_closing); @@ -86,7 +87,9 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View, MessageCenter* message_center_; // Weak reference. MessageCenterTray* tray_; // Weak reference. - std::vector<MessageView*> message_views_; + std::vector<MessageView*> message_views_; // Weak references. + + // Child views. views::ScrollView* scroller_; MessageListView* message_list_view_; NotifierSettingsView* settings_view_; @@ -96,11 +99,17 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View, // Data for transition animation between settings view and message list. bool settings_visible_; + + // Animation managing transition between message center and settings (and vice + // versa). + scoped_ptr<ui::MultiAnimation> settings_transition_animation_; + + // Helper data to keep track of the transition between settings and + // message center views. views::View* source_view_; - views::View* target_view_; int source_height_; + views::View* target_view_; int target_height_; - scoped_ptr<ui::MultiAnimation> settings_transition_animation_; // True when the widget is closing so that further operations should be // ignored. diff --git a/ui/message_center/views/notifier_settings_view.cc b/ui/message_center/views/notifier_settings_view.cc index 5673070..b97bc84 100644 --- a/ui/message_center/views/notifier_settings_view.cc +++ b/ui/message_center/views/notifier_settings_view.cc @@ -8,14 +8,18 @@ #include <string> #include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" #include "grit/ui_resources.h" #include "grit/ui_strings.h" +#include "skia/ext/image_operations.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/keycodes/keyboard_codes.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/simple_menu_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/size.h" #include "ui/message_center/message_center_style.h" #include "ui/message_center/views/message_center_view.h" @@ -23,8 +27,10 @@ #include "ui/views/border.h" #include "ui/views/controls/button/checkbox.h" #include "ui/views/controls/button/custom_button.h" +#include "ui/views/controls/button/menu_button.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" +#include "ui/views/controls/menu/menu_runner.h" #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/scrollbar/overlay_scroll_bar.h" #include "ui/views/layout/box_layout.h" @@ -114,6 +120,78 @@ bool EntryView::OnKeyReleased(const ui::KeyEvent& event) { } // namespace +// NotifierGroupMenuModel ////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +class NotifierGroupMenuModel : public ui::SimpleMenuModel, + public ui::SimpleMenuModel::Delegate { + public: + NotifierGroupMenuModel(NotifierSettingsProvider* notifier_settings_provider); + virtual ~NotifierGroupMenuModel(); + + // Overridden from ui::SimpleMenuModel::Delegate: + virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; + virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; + virtual bool GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) OVERRIDE; + virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; + + private: + NotifierSettingsProvider* notifier_settings_provider_; +}; + +NotifierGroupMenuModel::NotifierGroupMenuModel( + NotifierSettingsProvider* notifier_settings_provider) + : ui::SimpleMenuModel(this), + notifier_settings_provider_(notifier_settings_provider) { + if (!notifier_settings_provider_) + return; + + size_t num_menu_items = notifier_settings_provider_->GetNotifierGroupCount(); + for (size_t i = 0; i < num_menu_items; ++i) { + const NotifierGroup& group = + notifier_settings_provider_->GetNotifierGroupAt(i); + + AddItem(i, group.login_info.empty() ? group.name : group.login_info); + + gfx::ImageSkia resized_icon = gfx::ImageSkiaOperations::CreateResizedImage( + *group.icon.ToImageSkia(), + skia::ImageOperations::RESIZE_BETTER, + gfx::Size(kSettingsIconSize, kSettingsIconSize)); + + SetIcon(i, gfx::Image(resized_icon)); + } +} + +NotifierGroupMenuModel::~NotifierGroupMenuModel() {} + +bool NotifierGroupMenuModel::IsCommandIdChecked(int command_id) const { + return false; +} + +bool NotifierGroupMenuModel::IsCommandIdEnabled(int command_id) const { + return true; +} + +bool NotifierGroupMenuModel::GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) { + return false; +} + +void NotifierGroupMenuModel::ExecuteCommand(int command_id, int event_flags) { + if (!notifier_settings_provider_) + return; + + size_t notifier_group_index = static_cast<size_t>(command_id); + size_t num_notifier_groups = + notifier_settings_provider_->GetNotifierGroupCount(); + if (notifier_group_index >= num_notifier_groups) + return; + + notifier_settings_provider_->SwitchToNotifierGroup(notifier_group_index); +} + // We do not use views::Checkbox class directly because it doesn't support // showing 'icon'. class NotifierSettingsView::NotifierButton : public views::CustomButton, @@ -240,30 +318,11 @@ NotifierSettingsView::NotifierSettingsView(NotifierSettingsProvider* provider) scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false)); AddChildView(scroller_); - views::View* contents_view = new views::View(); - contents_view->SetLayoutManager(new views::BoxLayout( - views::BoxLayout::kVertical, 0, 0, 0)); - - views::Label* top_label = new views::Label(l10n_util::GetStringUTF16( - IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION)); - top_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - top_label->SetMultiLine(true); - top_label->SizeToFit(kMinimumWindowWidth - kMarginWidth * 2); - contents_view->AddChildView(new EntryView(top_label)); - std::vector<Notifier*> notifiers; if (provider_) provider_->GetNotifierList(¬ifiers); - for (size_t i = 0; i < notifiers.size(); ++i) { - NotifierButton* button = new NotifierButton(notifiers[i], this); - EntryView* entry = new EntryView(button); - entry->set_focusable(true); - contents_view->AddChildView(entry); - buttons_.insert(button); - } - scroller_->SetContents(contents_view); - contents_view->SetBoundsRect(gfx::Rect(contents_view->GetPreferredSize())); + UpdateContentsView(notifiers); } NotifierSettingsView::~NotifierSettingsView() { @@ -287,6 +346,57 @@ void NotifierSettingsView::UpdateIconImage(const NotifierId& notifier_id, } } +void NotifierSettingsView::NotifierGroupChanged() { + std::vector<Notifier*> notifiers; + if (provider_) + provider_->GetNotifierList(¬ifiers); + + UpdateContentsView(notifiers); +} + +void NotifierSettingsView::UpdateContentsView( + const std::vector<Notifier*>& notifiers) { + buttons_.clear(); + + views::View* contents_view = new views::View(); + contents_view->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); + + views::View* contents_title_view = new views::View(); + contents_title_view->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 5)); + views::Label* top_label = new views::Label(l10n_util::GetStringUTF16( + IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION)); + top_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + top_label->SetMultiLine(true); + contents_title_view->AddChildView(top_label); + + string16 notifier_group_text; + if (provider_) { + const NotifierGroup& active_group = provider_->GetActiveNotifierGroup(); + notifier_group_text = active_group.login_info.empty() + ? active_group.name + : active_group.login_info; + } + + views::View* notifier_group_selector = + new views::MenuButton(NULL, notifier_group_text, this, true); + contents_title_view->AddChildView(notifier_group_selector); + contents_view->AddChildView(new EntryView(contents_title_view)); + + for (size_t i = 0; i < notifiers.size(); ++i) { + NotifierButton* button = new NotifierButton(notifiers[i], this); + EntryView* entry = new EntryView(button); + entry->set_focusable(true); + contents_view->AddChildView(entry); + buttons_.insert(button); + } + scroller_->SetContents(contents_view); + + contents_view->SetBoundsRect(gfx::Rect(contents_view->GetPreferredSize())); + InvalidateLayout(); +} + void NotifierSettingsView::Layout() { int title_height = title_entry_->GetHeightForWidth(width()); title_entry_->SetBounds(0, 0, width(), title_height); @@ -343,11 +453,30 @@ void NotifierSettingsView::ButtonPressed(views::Button* sender, std::set<NotifierButton*>::iterator iter = buttons_.find( static_cast<NotifierButton*>(sender)); - DCHECK(iter != buttons_.end()); + + if (iter == buttons_.end()) + return; (*iter)->SetChecked(!(*iter)->checked()); if (provider_) provider_->SetNotifierEnabled((*iter)->notifier(), (*iter)->checked()); } +void NotifierSettingsView::OnMenuButtonClicked(views::View* source, + const gfx::Point& point) { + notifier_group_menu_model_.reset(new NotifierGroupMenuModel(provider_)); + notifier_group_menu_runner_.reset( + new views::MenuRunner(notifier_group_menu_model_.get())); + if (views::MenuRunner::MENU_DELETED == + notifier_group_menu_runner_->RunMenuAt(GetWidget(), + NULL, + source->GetBoundsInScreen(), + views::MenuItemView::BUBBLE_ABOVE, + ui::MENU_SOURCE_MOUSE, + views::MenuRunner::CONTEXT_MENU)) + return; + MessageCenterView* center_view = static_cast<MessageCenterView*>(parent()); + center_view->OnSettingsChanged(); +} + } // namespace message_center diff --git a/ui/message_center/views/notifier_settings_view.h b/ui/message_center/views/notifier_settings_view.h index 303eff4..6fc5b58 100644 --- a/ui/message_center/views/notifier_settings_view.h +++ b/ui/message_center/views/notifier_settings_view.h @@ -5,20 +5,30 @@ #ifndef UI_MESSAGE_CENTER_VIEWS_NOTIFIER_SETTINGS_VIEW_H_ #define UI_MESSAGE_CENTER_VIEWS_NOTIFIER_SETTINGS_VIEW_H_ +#include <set> + +#include "base/memory/scoped_ptr.h" #include "ui/message_center/message_center_export.h" #include "ui/message_center/notifier_settings.h" #include "ui/message_center/views/message_bubble_base.h" #include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/button/menu_button_listener.h" #include "ui/views/view.h" +namespace views { +class MenuRunner; +} + namespace message_center { +class NotifierGroupMenuModel; // A class to show the list of notifier extensions / URL patterns and allow // users to customize the settings. class MESSAGE_CENTER_EXPORT NotifierSettingsView : public NotifierSettingsObserver, public views::View, - public views::ButtonListener { + public views::ButtonListener, + public views::MenuButtonListener { public: explicit NotifierSettingsView(NotifierSettingsProvider* provider); virtual ~NotifierSettingsView(); @@ -28,6 +38,7 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsView // Overridden from NotifierSettingsDelegate: virtual void UpdateIconImage(const NotifierId& notifier_id, const gfx::Image& icon) OVERRIDE; + virtual void NotifierGroupChanged() OVERRIDE; void set_provider(NotifierSettingsProvider* new_provider) { provider_ = new_provider; @@ -36,6 +47,9 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsView private: class NotifierButton; + // Given a new list of notifiers, updates the view to reflect it. + void UpdateContentsView(const std::vector<Notifier*>& notifiers); + // Overridden from views::View: virtual void Layout() OVERRIDE; virtual gfx::Size GetMinimumSize() OVERRIDE; @@ -46,12 +60,16 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsView // Overridden from views::ButtonListener: virtual void ButtonPressed(views::Button* sender, const ui::Event& event) OVERRIDE; + virtual void OnMenuButtonClicked(views::View* source, + const gfx::Point& point) OVERRIDE; views::ImageButton* title_arrow_; views::View* title_entry_; views::ScrollView* scroller_; NotifierSettingsProvider* provider_; std::set<NotifierButton*> buttons_; + scoped_ptr<NotifierGroupMenuModel> notifier_group_menu_model_; + scoped_ptr<views::MenuRunner> notifier_group_menu_runner_; DISALLOW_COPY_AND_ASSIGN(NotifierSettingsView); }; |