summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-06 00:30:05 +0000
committerjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-06 00:30:05 +0000
commitb0b2a3dd01962592fc8c1f981415ab2bdb8edefb (patch)
tree6cbda13db92837ae9aadd32a9c4aa6c87aaaf38a /chrome/browser
parente5ce23e294561b52d35b72eb30c8f5ae869e0fe2 (diff)
downloadchromium_src-b0b2a3dd01962592fc8c1f981415ab2bdb8edefb.zip
chromium_src-b0b2a3dd01962592fc8c1f981415ab2bdb8edefb.tar.gz
chromium_src-b0b2a3dd01962592fc8c1f981415ab2bdb8edefb.tar.bz2
Allow the user to choose which corner of the screen should get notifications.
BUG=none TEST=create notifications, use the options menu Review URL: http://codereview.chromium.org/6006007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70564 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/browser_process_impl.cc3
-rw-r--r--chrome/browser/chromeos/notifications/balloon_collection_impl.h1
-rw-r--r--chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc6
-rw-r--r--chrome/browser/notifications/balloon.h2
-rw-r--r--chrome/browser/notifications/balloon_collection.cc51
-rw-r--r--chrome/browser/notifications/balloon_collection.h15
-rw-r--r--chrome/browser/notifications/balloon_collection_impl.h19
-rw-r--r--chrome/browser/notifications/balloon_collection_linux.cc21
-rw-r--r--chrome/browser/notifications/balloon_collection_mac.mm21
-rw-r--r--chrome/browser/notifications/balloon_collection_win.cc21
-rw-r--r--chrome/browser/notifications/desktop_notifications_unittest.cc81
-rw-r--r--chrome/browser/notifications/notification_options_menu_model.cc92
-rw-r--r--chrome/browser/notifications/notification_options_menu_model.h24
-rw-r--r--chrome/browser/notifications/notification_ui_manager.cc52
-rw-r--r--chrome/browser/notifications/notification_ui_manager.h25
-rw-r--r--chrome/browser/prefs/browser_prefs.cc2
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm3
17 files changed, 397 insertions, 42 deletions
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 83fe028..222ee28 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -770,7 +770,8 @@ void BrowserProcessImpl::CreateIntranetRedirectDetector() {
void BrowserProcessImpl::CreateNotificationUIManager() {
DCHECK(notification_ui_manager_.get() == NULL);
- notification_ui_manager_.reset(NotificationUIManager::Create());
+ notification_ui_manager_.reset(NotificationUIManager::Create(local_state()));
+
created_notification_ui_manager_ = true;
}
diff --git a/chrome/browser/chromeos/notifications/balloon_collection_impl.h b/chrome/browser/chromeos/notifications/balloon_collection_impl.h
index 03496df..320bfd6 100644
--- a/chrome/browser/chromeos/notifications/balloon_collection_impl.h
+++ b/chrome/browser/chromeos/notifications/balloon_collection_impl.h
@@ -66,6 +66,7 @@ class BalloonCollectionImpl : public BalloonCollection,
virtual void RemoveAll();
virtual bool HasSpace() const;
virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size);
+ virtual void SetPositionPreference(PositionPreference position) {}
virtual void DisplayChanged() {}
virtual void OnBalloonClosed(Balloon* source);
virtual const Balloons& GetActiveBalloons() { return base_.balloons(); }
diff --git a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc
index 377828b..9a77680 100644
--- a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc
+++ b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc
@@ -7,6 +7,7 @@
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/render_messages_params.h"
+#include "chrome/test/testing_pref_service.h"
namespace chromeos {
@@ -77,7 +78,8 @@ DesktopNotificationsTest::~DesktopNotificationsTest() {
void DesktopNotificationsTest::SetUp() {
profile_.reset(new TestingProfile());
balloon_collection_ = new MockBalloonCollection();
- ui_manager_.reset(new NotificationUIManager());
+ ui_manager_.reset(
+ new NotificationUIManager(profile_->GetTestingPrefService()));
ui_manager_->Initialize(balloon_collection_);
balloon_collection_->set_space_change_listener(ui_manager_.get());
service_.reset(new DesktopNotificationService(profile(), ui_manager_.get()));
@@ -86,8 +88,8 @@ void DesktopNotificationsTest::SetUp() {
void DesktopNotificationsTest::TearDown() {
service_.reset(NULL);
- profile_.reset(NULL);
ui_manager_.reset(NULL);
+ profile_.reset(NULL);
}
ViewHostMsg_ShowNotification_Params
diff --git a/chrome/browser/notifications/balloon.h b/chrome/browser/notifications/balloon.h
index 3f4ba0b..5b86508 100644
--- a/chrome/browser/notifications/balloon.h
+++ b/chrome/browser/notifications/balloon.h
@@ -68,6 +68,8 @@ class Balloon {
const gfx::Size& content_size() const { return content_size_; }
void set_content_size(const gfx::Size& size) { content_size_ = size; }
+ const BalloonCollection* collection() const { return collection_; }
+
const gfx::Size& min_scrollbar_size() const { return min_scrollbar_size_; }
void set_min_scrollbar_size(const gfx::Size& size) {
min_scrollbar_size_ = size;
diff --git a/chrome/browser/notifications/balloon_collection.cc b/chrome/browser/notifications/balloon_collection.cc
index 218126b..60c9f2d 100644
--- a/chrome/browser/notifications/balloon_collection.cc
+++ b/chrome/browser/notifications/balloon_collection.cc
@@ -28,20 +28,14 @@ const int kRepositionDelay = 300;
} // namespace
-// static
-// Note that on MacOS, since the coordinate system is inverted vertically from
-// the others, this actually produces notifications coming from the TOP right,
-// which is what is desired.
-BalloonCollectionImpl::Layout::Placement
- BalloonCollectionImpl::Layout::placement_ =
- Layout::VERTICALLY_FROM_BOTTOM_RIGHT;
-
BalloonCollectionImpl::BalloonCollectionImpl()
#if USE_OFFSETS
: ALLOW_THIS_IN_INITIALIZER_LIST(reposition_factory_(this)),
added_as_message_loop_observer_(false)
#endif
{
+
+ SetPositionPreference(BalloonCollection::DEFAULT_POSITION);
}
BalloonCollectionImpl::~BalloonCollectionImpl() {
@@ -221,26 +215,27 @@ void BalloonCollectionImpl::Layout::GetMaxLinearSize(int* max_balloon_size,
int* total_size) const {
DCHECK(max_balloon_size && total_size);
- switch (placement_) {
- case VERTICALLY_FROM_TOP_RIGHT:
- case VERTICALLY_FROM_BOTTOM_RIGHT:
- *total_size = work_area_.height();
- *max_balloon_size = max_balloon_height();
- break;
- default:
- NOTREACHED();
- break;
- }
+ // All placement schemes are vertical, so we only care about height.
+ *total_size = work_area_.height();
+ *max_balloon_size = max_balloon_height();
}
gfx::Point BalloonCollectionImpl::Layout::GetLayoutOrigin() const {
int x = 0;
int y = 0;
switch (placement_) {
+ case VERTICALLY_FROM_TOP_LEFT:
+ x = work_area_.x() + HorizontalEdgeMargin();
+ y = work_area_.y() + VerticalEdgeMargin();
+ break;
case VERTICALLY_FROM_TOP_RIGHT:
x = work_area_.right() - HorizontalEdgeMargin();
y = work_area_.y() + VerticalEdgeMargin();
break;
+ case VERTICALLY_FROM_BOTTOM_LEFT:
+ x = work_area_.x() + HorizontalEdgeMargin();
+ y = work_area_.bottom() - VerticalEdgeMargin();
+ break;
case VERTICALLY_FROM_BOTTOM_RIGHT:
x = work_area_.right() - HorizontalEdgeMargin();
y = work_area_.bottom() - VerticalEdgeMargin();
@@ -260,12 +255,24 @@ gfx::Point BalloonCollectionImpl::Layout::NextPosition(
int x = 0;
int y = 0;
switch (placement_) {
+ case VERTICALLY_FROM_TOP_LEFT:
+ x = position_iterator->x();
+ y = position_iterator->y();
+ position_iterator->set_y(position_iterator->y() + balloon_size.height() +
+ InterBalloonMargin());
+ break;
case VERTICALLY_FROM_TOP_RIGHT:
x = position_iterator->x() - balloon_size.width();
y = position_iterator->y();
position_iterator->set_y(position_iterator->y() + balloon_size.height() +
InterBalloonMargin());
break;
+ case VERTICALLY_FROM_BOTTOM_LEFT:
+ position_iterator->set_y(position_iterator->y() - balloon_size.height() -
+ InterBalloonMargin());
+ x = position_iterator->x();
+ y = position_iterator->y();
+ break;
case VERTICALLY_FROM_BOTTOM_RIGHT:
position_iterator->set_y(position_iterator->y() - balloon_size.height() -
InterBalloonMargin());
@@ -283,10 +290,18 @@ gfx::Point BalloonCollectionImpl::Layout::OffScreenLocation() const {
int x = 0;
int y = 0;
switch (placement_) {
+ case VERTICALLY_FROM_TOP_LEFT:
+ x = work_area_.x() + HorizontalEdgeMargin();
+ y = work_area_.y() + kBalloonMaxHeight + VerticalEdgeMargin();
+ break;
case VERTICALLY_FROM_TOP_RIGHT:
x = work_area_.right() - kBalloonMaxWidth - HorizontalEdgeMargin();
y = work_area_.y() + kBalloonMaxHeight + VerticalEdgeMargin();
break;
+ case VERTICALLY_FROM_BOTTOM_LEFT:
+ x = work_area_.x() + HorizontalEdgeMargin();
+ y = work_area_.bottom() + kBalloonMaxHeight + VerticalEdgeMargin();
+ break;
case VERTICALLY_FROM_BOTTOM_RIGHT:
x = work_area_.right() - kBalloonMaxWidth - HorizontalEdgeMargin();
y = work_area_.bottom() + kBalloonMaxHeight + VerticalEdgeMargin();
diff --git a/chrome/browser/notifications/balloon_collection.h b/chrome/browser/notifications/balloon_collection.h
index 13875dc..6909759 100644
--- a/chrome/browser/notifications/balloon_collection.h
+++ b/chrome/browser/notifications/balloon_collection.h
@@ -34,6 +34,18 @@ class BalloonCollection {
virtual void OnBalloonSpaceChanged() = 0;
};
+ // Do not change existing values without migration path; these
+ // are stored as integers in user preferences.
+ enum PositionPreference {
+ UPPER_RIGHT = 0,
+ LOWER_RIGHT = 1,
+ UPPER_LEFT = 2,
+ LOWER_LEFT = 3,
+
+ // The default position is different on different platforms.
+ DEFAULT_POSITION = -1
+ };
+
static BalloonCollection* Create();
BalloonCollection()
@@ -63,6 +75,9 @@ class BalloonCollection {
// Request the resizing of a balloon.
virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size) = 0;
+ // Set the position preference for the collection.
+ virtual void SetPositionPreference(PositionPreference position) = 0;
+
// Update for new screen dimensions.
virtual void DisplayChanged() = 0;
diff --git a/chrome/browser/notifications/balloon_collection_impl.h b/chrome/browser/notifications/balloon_collection_impl.h
index 7fb1ea9a..d123717 100644
--- a/chrome/browser/notifications/balloon_collection_impl.h
+++ b/chrome/browser/notifications/balloon_collection_impl.h
@@ -47,6 +47,7 @@ class BalloonCollectionImpl : public BalloonCollection
virtual void RemoveAll();
virtual bool HasSpace() const;
virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size);
+ virtual void SetPositionPreference(PositionPreference position);
virtual void DisplayChanged();
virtual void OnBalloonClosed(Balloon* source);
virtual const Balloons& GetActiveBalloons() { return base_.balloons(); }
@@ -68,6 +69,15 @@ class BalloonCollectionImpl : public BalloonCollection
public:
Layout();
+ // These enumerations all are based on a screen orientation where
+ // the origin is the top-left.
+ enum Placement {
+ VERTICALLY_FROM_TOP_LEFT,
+ VERTICALLY_FROM_TOP_RIGHT,
+ VERTICALLY_FROM_BOTTOM_LEFT,
+ VERTICALLY_FROM_BOTTOM_RIGHT
+ };
+
// Refresh the work area and balloon placement.
void OnDisplaySettingsChanged();
@@ -80,6 +90,8 @@ class BalloonCollectionImpl : public BalloonCollection
// Utility function constrains the input rectangle to the min and max sizes.
static gfx::Size ConstrainToSizeLimits(const gfx::Size& rect);
+ void set_placement(Placement placement) { placement_ = placement; }
+
// Returns both the total space available and the maximum
// allowed per balloon.
//
@@ -109,11 +121,6 @@ class BalloonCollectionImpl : public BalloonCollection
gfx::Point OffScreenLocation() const;
private:
- enum Placement {
- VERTICALLY_FROM_TOP_RIGHT,
- VERTICALLY_FROM_BOTTOM_RIGHT
- };
-
// Layout parameters
int VerticalEdgeMargin() const;
int HorizontalEdgeMargin() const;
@@ -125,7 +132,7 @@ class BalloonCollectionImpl : public BalloonCollection
static const int kBalloonMinHeight = 24;
static const int kBalloonMaxHeight = 160;
- static Placement placement_;
+ Placement placement_;
gfx::Rect work_area_;
DISALLOW_COPY_AND_ASSIGN(Layout);
};
diff --git a/chrome/browser/notifications/balloon_collection_linux.cc b/chrome/browser/notifications/balloon_collection_linux.cc
index 08354a0..099193c 100644
--- a/chrome/browser/notifications/balloon_collection_linux.cc
+++ b/chrome/browser/notifications/balloon_collection_linux.cc
@@ -67,6 +67,27 @@ bool BalloonCollectionImpl::IsCursorInBalloonCollection() const {
return bounds.Contains(cursor);
}
+void BalloonCollectionImpl::SetPositionPreference(
+ PositionPreference position) {
+ if (position == DEFAULT_POSITION)
+ position = LOWER_RIGHT;
+
+ // All positioning schemes are vertical, and linux
+ // uses the normal screen orientation.
+ if (position == UPPER_RIGHT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_TOP_RIGHT);
+ else if (position == UPPER_LEFT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_TOP_LEFT);
+ else if (position == LOWER_LEFT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_BOTTOM_LEFT);
+ else if (position == LOWER_RIGHT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_BOTTOM_RIGHT);
+ else
+ NOTREACHED();
+
+ PositionBalloons(true);
+}
+
// static
BalloonCollection* BalloonCollection::Create() {
return new BalloonCollectionImpl();
diff --git a/chrome/browser/notifications/balloon_collection_mac.mm b/chrome/browser/notifications/balloon_collection_mac.mm
index 7615415..d31bc39 100644
--- a/chrome/browser/notifications/balloon_collection_mac.mm
+++ b/chrome/browser/notifications/balloon_collection_mac.mm
@@ -43,6 +43,27 @@ void BalloonCollectionImpl::PositionBalloons(bool reposition) {
[NSAnimationContext endGrouping];
}
+void BalloonCollectionImpl::SetPositionPreference(
+ PositionPreference position) {
+ if (position == DEFAULT_POSITION)
+ position = UPPER_RIGHT;
+
+ // All positioning schemes are vertical, but mac
+ // uses a vertically reversed screen orientation.
+ if (position == UPPER_RIGHT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_BOTTOM_RIGHT);
+ else if (position == UPPER_LEFT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_BOTTOM_LEFT);
+ else if (position == LOWER_LEFT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_TOP_LEFT);
+ else if (position == LOWER_RIGHT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_TOP_RIGHT);
+ else
+ NOTREACHED();
+
+ PositionBalloons(true);
+}
+
// static
BalloonCollection* BalloonCollection::Create() {
return new BalloonCollectionImpl();
diff --git a/chrome/browser/notifications/balloon_collection_win.cc b/chrome/browser/notifications/balloon_collection_win.cc
index 07bcd18..742872b 100644
--- a/chrome/browser/notifications/balloon_collection_win.cc
+++ b/chrome/browser/notifications/balloon_collection_win.cc
@@ -62,6 +62,27 @@ bool BalloonCollectionImpl::IsCursorInBalloonCollection() const {
return bounds.Contains(cursor);
}
+void BalloonCollectionImpl::SetPositionPreference(
+ PositionPreference position) {
+ if (position == DEFAULT_POSITION)
+ position = LOWER_RIGHT;
+
+ // All positioning schemes are vertical, and windows
+ // uses the normal screen orientation.
+ if (position == UPPER_RIGHT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_TOP_RIGHT);
+ else if (position == UPPER_LEFT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_TOP_LEFT);
+ else if (position == LOWER_LEFT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_BOTTOM_LEFT);
+ else if (position == LOWER_RIGHT)
+ layout_.set_placement(Layout::VERTICALLY_FROM_BOTTOM_RIGHT);
+ else
+ NOTREACHED();
+
+ PositionBalloons(true);
+}
+
// static
BalloonCollection* BalloonCollection::Create() {
return new BalloonCollectionImpl();
diff --git a/chrome/browser/notifications/desktop_notifications_unittest.cc b/chrome/browser/notifications/desktop_notifications_unittest.cc
index ebb6ab8..762990f 100644
--- a/chrome/browser/notifications/desktop_notifications_unittest.cc
+++ b/chrome/browser/notifications/desktop_notifications_unittest.cc
@@ -6,7 +6,9 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages_params.h"
+#include "chrome/test/testing_pref_service.h"
// static
const int MockBalloonCollection::kMockBalloonSpace = 5;
@@ -69,7 +71,8 @@ DesktopNotificationsTest::~DesktopNotificationsTest() {
void DesktopNotificationsTest::SetUp() {
profile_.reset(new TestingProfile());
balloon_collection_ = new MockBalloonCollection();
- ui_manager_.reset(new NotificationUIManager());
+ ui_manager_.reset(
+ new NotificationUIManager(profile_->GetTestingPrefService()));
ui_manager_->Initialize(balloon_collection_);
balloon_collection_->set_space_change_listener(ui_manager_.get());
service_.reset(new DesktopNotificationService(profile(), ui_manager_.get()));
@@ -78,8 +81,8 @@ void DesktopNotificationsTest::SetUp() {
void DesktopNotificationsTest::TearDown() {
service_.reset(NULL);
- profile_.reset(NULL);
ui_manager_.reset(NULL);
+ profile_.reset(NULL);
}
ViewHostMsg_ShowNotification_Params
@@ -320,3 +323,77 @@ TEST_F(DesktopNotificationsTest, TestUserInputEscaping) {
EXPECT_EQ(std::string::npos, data_url.spec().find("%3cscript%3e"));
EXPECT_EQ(std::string::npos, data_url.spec().find("%3ci%3e"));
}
+
+TEST_F(DesktopNotificationsTest, TestPositionPreference) {
+ // Set position preference to lower right.
+ profile_->GetPrefs()->SetInteger(prefs::kDesktopNotificationPosition,
+ BalloonCollection::LOWER_RIGHT);
+
+ // Create some notifications.
+ ViewHostMsg_ShowNotification_Params params = StandardTestNotification();
+ for (int id = 0; id <= 3; ++id) {
+ params.notification_id = id;
+ EXPECT_TRUE(service_->ShowDesktopNotification(
+ params, 0, 0, DesktopNotificationService::PageNotification));
+ }
+
+ std::deque<Balloon*>& balloons = balloon_collection_->balloons();
+ std::deque<Balloon*>::iterator iter;
+
+ // Check that they decrease in y-position (for MAC, with reversed
+ // coordinates, they should increase).
+ int last_y = -1;
+ int last_x = -1;
+
+ for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
+ int current_x = (*iter)->GetPosition().x();
+ int current_y = (*iter)->GetPosition().y();
+ if (last_x > 0)
+ EXPECT_EQ(last_x, current_x);
+
+ if (last_y > 0) {
+#if defined(OS_MACOSX)
+ EXPECT_GT(current_y, last_y);
+#else
+ EXPECT_LT(current_y, last_y);
+#endif
+ }
+
+ last_x = current_x;
+ last_y = current_y;
+ }
+
+ // Now change the position to upper right. This should cause an immediate
+ // repositioning, and we check for the reverse ordering.
+ profile_->GetPrefs()->SetInteger(prefs::kDesktopNotificationPosition,
+ BalloonCollection::UPPER_RIGHT);
+ last_x = -1;
+ last_y = -1;
+
+ for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
+ int current_x = (*iter)->GetPosition().x();
+ int current_y = (*iter)->GetPosition().y();
+
+ if (last_x > 0)
+ EXPECT_EQ(last_x, current_x);
+
+ if (last_y > 0) {
+#if defined(OS_MACOSX)
+ EXPECT_LT(current_y, last_y);
+#else
+ EXPECT_GT(current_y, last_y);
+#endif
+ }
+
+ last_x = current_x;
+ last_y = current_y;
+ }
+
+ // Now change the position to upper left. Confirm that the X value for the
+ // balloons gets smaller.
+ profile_->GetPrefs()->SetInteger(prefs::kDesktopNotificationPosition,
+ BalloonCollection::UPPER_LEFT);
+
+ int current_x = (*balloons.begin())->GetPosition().x();
+ EXPECT_LT(current_x, last_x);
+}
diff --git a/chrome/browser/notifications/notification_options_menu_model.cc b/chrome/browser/notifications/notification_options_menu_model.cc
index 45620c9..fb05bda 100644
--- a/chrome/browser/notifications/notification_options_menu_model.cc
+++ b/chrome/browser/notifications/notification_options_menu_model.cc
@@ -7,10 +7,14 @@
#include "app/l10n_util.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/notifications/balloon_collection.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
@@ -27,6 +31,89 @@
const int kTogglePermissionCommand = 0;
const int kToggleExtensionCommand = 1;
const int kOpenContentSettingsCommand = 2;
+const int kCornerSelectionSubMenu = 3;
+
+const int kCornerGroupId = 10;
+const int kCornerUpperLeft = 11;
+const int kCornerUpperRight = 12;
+const int kCornerLowerLeft = 13;
+const int kCornerLowerRight = 14;
+const int kCornerDefault = 20;
+
+CornerSelectionMenuModel::CornerSelectionMenuModel(Balloon* balloon)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
+ balloon_(balloon) {
+ AddRadioItem(kCornerDefault,
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_DEFAULT),
+ kCornerGroupId);
+ AddSeparator();
+ AddRadioItem(kCornerUpperLeft,
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_UPPER_LEFT),
+ kCornerGroupId);
+ AddRadioItem(kCornerUpperRight,
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_UPPER_RIGHT),
+ kCornerGroupId);
+ AddRadioItem(kCornerLowerLeft,
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_LOWER_LEFT),
+ kCornerGroupId);
+ AddRadioItem(kCornerLowerRight,
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_LOWER_RIGHT),
+ kCornerGroupId);
+}
+
+CornerSelectionMenuModel::~CornerSelectionMenuModel() {
+}
+
+bool CornerSelectionMenuModel::IsCommandIdChecked(int command_id) const {
+ NotificationUIManager* ui = g_browser_process->notification_ui_manager();
+ BalloonCollection::PositionPreference current = ui->GetPositionPreference();
+
+ LOG(INFO) << "Current position preference: " << current;
+
+ if (command_id == kCornerUpperLeft)
+ return (current == BalloonCollection::UPPER_LEFT);
+ else if (command_id == kCornerUpperRight)
+ return (current == BalloonCollection::UPPER_RIGHT);
+ else if (command_id == kCornerLowerLeft)
+ return (current == BalloonCollection::LOWER_LEFT);
+ else if (command_id == kCornerLowerRight)
+ return (current == BalloonCollection::LOWER_RIGHT);
+ else if (command_id == kCornerDefault)
+ return (current == BalloonCollection::DEFAULT_POSITION);
+
+ NOTREACHED();
+ return false;
+}
+
+bool CornerSelectionMenuModel::IsCommandIdEnabled(int command_id) const {
+ // All the menu options are always enabled.
+ return true;
+}
+
+bool CornerSelectionMenuModel::GetAcceleratorForCommandId(
+ int command_id, menus::Accelerator* accelerator) {
+ // Currently no accelerators.
+ return false;
+}
+
+void CornerSelectionMenuModel::ExecuteCommand(int command_id) {
+ NotificationUIManager* ui = g_browser_process->notification_ui_manager();
+
+ LOG(INFO) << "Executing command: " << command_id;
+
+ if (command_id == kCornerUpperLeft)
+ ui->SetPositionPreference(BalloonCollection::UPPER_LEFT);
+ else if (command_id == kCornerUpperRight)
+ ui->SetPositionPreference(BalloonCollection::UPPER_RIGHT);
+ else if (command_id == kCornerLowerLeft)
+ ui->SetPositionPreference(BalloonCollection::LOWER_LEFT);
+ else if (command_id == kCornerLowerRight)
+ ui->SetPositionPreference(BalloonCollection::LOWER_RIGHT);
+ else if (command_id == kCornerDefault)
+ ui->SetPositionPreference(BalloonCollection::DEFAULT_POSITION);
+ else
+ NOTREACHED();
+}
NotificationOptionsMenuModel::NotificationOptionsMenuModel(Balloon* balloon)
: ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
@@ -49,6 +136,11 @@ NotificationOptionsMenuModel::NotificationOptionsMenuModel(Balloon* balloon)
const string16 settings_label = l10n_util::GetStringUTF16(
IDS_NOTIFICATIONS_SETTINGS_BUTTON);
AddItem(kOpenContentSettingsCommand, settings_label);
+
+ corner_menu_model_.reset(new CornerSelectionMenuModel(balloon));
+ AddSubMenu(kCornerSelectionSubMenu,
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_CHOOSE_POSITION),
+ corner_menu_model_.get());
}
NotificationOptionsMenuModel::~NotificationOptionsMenuModel() {
diff --git a/chrome/browser/notifications/notification_options_menu_model.h b/chrome/browser/notifications/notification_options_menu_model.h
index f7f4c77..022b7e0 100644
--- a/chrome/browser/notifications/notification_options_menu_model.h
+++ b/chrome/browser/notifications/notification_options_menu_model.h
@@ -9,6 +9,28 @@
#include "app/menus/simple_menu_model.h"
#include "chrome/browser/notifications/balloon.h"
+// Model for the corner-selection submenu.
+class CornerSelectionMenuModel : public menus::SimpleMenuModel,
+ public menus::SimpleMenuModel::Delegate {
+ public:
+ explicit CornerSelectionMenuModel(Balloon* balloon);
+ virtual ~CornerSelectionMenuModel();
+
+ // Overridden from menus::SimpleMenuModel::Delegate:
+ virtual bool IsCommandIdChecked(int command_id) const;
+ virtual bool IsCommandIdEnabled(int command_id) const;
+ virtual bool GetAcceleratorForCommandId(int command_id,
+ menus::Accelerator* accelerator);
+ virtual void ExecuteCommand(int command_id);
+
+ private:
+ // Not owned.
+ Balloon* balloon_;
+
+ DISALLOW_COPY_AND_ASSIGN(CornerSelectionMenuModel);
+};
+
+// Model for the notification options menu itself.
class NotificationOptionsMenuModel : public menus::SimpleMenuModel,
public menus::SimpleMenuModel::Delegate {
public:
@@ -29,6 +51,8 @@ class NotificationOptionsMenuModel : public menus::SimpleMenuModel,
private:
Balloon* balloon_; // Not owned.
+ scoped_ptr<CornerSelectionMenuModel> corner_menu_model_;
+
DISALLOW_COPY_AND_ASSIGN(NotificationOptionsMenuModel);
};
diff --git a/chrome/browser/notifications/notification_ui_manager.cc b/chrome/browser/notifications/notification_ui_manager.cc
index 6e2ff02..950bd6c 100644
--- a/chrome/browser/notifications/notification_ui_manager.cc
+++ b/chrome/browser/notifications/notification_ui_manager.cc
@@ -7,11 +7,14 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/notifications/balloon_collection.h"
#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
// A class which represents a notification waiting to be shown.
class QueuedNotification {
@@ -38,10 +41,11 @@ class QueuedNotification {
DISALLOW_COPY_AND_ASSIGN(QueuedNotification);
};
-NotificationUIManager::NotificationUIManager()
+NotificationUIManager::NotificationUIManager(PrefService* local_state)
: balloon_collection_(NULL) {
registrar_.Add(this, NotificationType::APP_TERMINATING,
NotificationService::AllSources());
+ position_pref_.Init(prefs::kDesktopNotificationPosition, local_state, this);
}
NotificationUIManager::~NotificationUIManager() {
@@ -49,14 +53,30 @@ NotificationUIManager::~NotificationUIManager() {
}
// static
-NotificationUIManager* NotificationUIManager::Create() {
+NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) {
BalloonCollection* balloons = BalloonCollection::Create();
- NotificationUIManager* instance = new NotificationUIManager();
+ NotificationUIManager* instance = new NotificationUIManager(local_state);
instance->Initialize(balloons);
balloons->set_space_change_listener(instance);
return instance;
}
+// static
+void NotificationUIManager::RegisterPrefs(PrefService* prefs) {
+ prefs->RegisterIntegerPref(prefs::kDesktopNotificationPosition,
+ BalloonCollection::DEFAULT_POSITION);
+}
+
+void NotificationUIManager::Initialize(
+ BalloonCollection* balloon_collection) {
+ DCHECK(!balloon_collection_.get());
+ DCHECK(balloon_collection);
+ balloon_collection_.reset(balloon_collection);
+ balloon_collection_->SetPositionPreference(
+ static_cast<BalloonCollection::PositionPreference>(
+ position_pref_.GetValue()));
+}
+
void NotificationUIManager::Add(const Notification& notification,
Profile* profile) {
if (TryReplacement(notification)) {
@@ -157,11 +177,33 @@ bool NotificationUIManager::TryReplacement(const Notification& notification) {
return false;
}
+BalloonCollection::PositionPreference
+NotificationUIManager::GetPositionPreference() {
+ LOG(INFO) << "Current position preference: " << position_pref_.GetValue();
+
+ return static_cast<BalloonCollection::PositionPreference>(
+ position_pref_.GetValue());
+}
+
+void NotificationUIManager::SetPositionPreference(
+ BalloonCollection::PositionPreference preference) {
+ LOG(INFO) << "Setting position preference: " << preference;
+ position_pref_.SetValue(static_cast<int>(preference));
+ balloon_collection_->SetPositionPreference(preference);
+}
+
void NotificationUIManager::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type == NotificationType::APP_TERMINATING)
+ if (type == NotificationType::APP_TERMINATING) {
CancelAll();
- else
+ } else if (type == NotificationType::PREF_CHANGED) {
+ std::string* name = Details<std::string>(details).ptr();
+ if (*name == prefs::kDesktopNotificationPosition)
+ balloon_collection_->SetPositionPreference(
+ static_cast<BalloonCollection::PositionPreference>(
+ position_pref_.GetValue()));
+ } else {
NOTREACHED();
+ }
}
diff --git a/chrome/browser/notifications/notification_ui_manager.h b/chrome/browser/notifications/notification_ui_manager.h
index de429db..3a0125c 100644
--- a/chrome/browser/notifications/notification_ui_manager.h
+++ b/chrome/browser/notifications/notification_ui_manager.h
@@ -13,10 +13,12 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/balloon_collection.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class Notification;
+class PrefService;
class Profile;
class QueuedNotification;
class SiteInstance;
@@ -27,21 +29,20 @@ class NotificationUIManager
: public BalloonCollection::BalloonSpaceChangeListener,
public NotificationObserver {
public:
- NotificationUIManager();
+ explicit NotificationUIManager(PrefService* local_state);
virtual ~NotificationUIManager();
// Creates an initialized UI manager with a new balloon collection
// and the listener relationship setup.
// Except for unit tests, this is the way to construct the object.
- static NotificationUIManager* Create();
+ static NotificationUIManager* Create(PrefService* local_state);
+
+ // Registers preferences.
+ static void RegisterPrefs(PrefService* prefs);
// Initializes the UI manager with a balloon collection; this object
// takes ownership of the balloon collection.
- void Initialize(BalloonCollection* balloon_collection) {
- DCHECK(!balloon_collection_.get());
- DCHECK(balloon_collection);
- balloon_collection_.reset(balloon_collection);
- }
+ void Initialize(BalloonCollection* balloon_collection);
// Adds a notification to be displayed. Virtual for unit test override.
virtual void Add(const Notification& notification,
@@ -65,6 +66,13 @@ class NotificationUIManager
return balloon_collection_.get();
}
+ // Gets the preference indicating where notifications should be placed.
+ BalloonCollection::PositionPreference GetPositionPreference();
+
+ // Sets the preference that indicates where notifications should
+ // be placed on the screen.
+ void SetPositionPreference(BalloonCollection::PositionPreference preference);
+
// NotificationObserver interface (the event signaling kind of notifications)
virtual void Observe(NotificationType type,
const NotificationSource& source,
@@ -95,6 +103,9 @@ class NotificationUIManager
// Registrar for the other kind of notifications (event signaling).
NotificationRegistrar registrar_;
+ // Prefs listener for the position preference.
+ IntegerPrefMember position_pref_;
+
DISALLOW_COPY_AND_ASSIGN(NotificationUIManager);
};
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 1d21c1f..1aa3c9e 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -34,6 +34,7 @@
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
#include "chrome/browser/net/net_pref_observer.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/page_info_model.h"
#include "chrome/browser/password_manager/password_manager.h"
@@ -100,6 +101,7 @@ void RegisterLocalState(PrefService* local_state) {
geolocation::RegisterPrefs(local_state);
AutoFillManager::RegisterBrowserPrefs(local_state);
BackgroundPageTracker::RegisterPrefs(local_state);
+ NotificationUIManager::RegisterPrefs(local_state);
#if defined(OS_CHROMEOS)
chromeos::UserManager::RegisterPrefs(local_state);
chromeos::UserCrosSettingsProvider::RegisterPrefs(local_state);
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm b/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm
index a63a327..3b168ef 100644
--- a/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm
@@ -34,8 +34,9 @@ class MockBalloonCollection : public BalloonCollection {
virtual bool RemoveBySourceOrigin(const GURL& origin) { return false; }
virtual void RemoveAll() {}
virtual bool HasSpace() const { return true; }
- virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size) {};
+ virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size) {}
virtual void DisplayChanged() {}
+ virtual void SetPositionPreference(PositionPreference preference) {}
virtual void OnBalloonClosed(Balloon* source) {};
virtual const Balloons& GetActiveBalloons() {
NOTREACHED();