diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-19 22:43:31 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-19 22:43:31 +0000 |
commit | 474d7f91ceddff4223df11e42e689934b3988d28 (patch) | |
tree | dd9fb9d1e374dabd3aae9375a2756ef8cd7b6040 /chrome/browser | |
parent | 29c1498d163ff9a4b476632ebbe5afa396424c21 (diff) | |
download | chromium_src-474d7f91ceddff4223df11e42e689934b3988d28.zip chromium_src-474d7f91ceddff4223df11e42e689934b3988d28.tar.gz chromium_src-474d7f91ceddff4223df11e42e689934b3988d28.tar.bz2 |
Don't change the panel state when deleting notifications (and mouse is on the panel)
so that a user can delete multiple notification by clicking mouse on the same position.
BUG=33306
TEST=none. I will add tests next week.
Review URL: http://codereview.chromium.org/1147003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42161 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
4 files changed, 101 insertions, 7 deletions
diff --git a/chrome/browser/chromeos/notifications/balloon_view.cc b/chrome/browser/chromeos/notifications/balloon_view.cc index 6b9c4f0..13af28b 100644 --- a/chrome/browser/chromeos/notifications/balloon_view.cc +++ b/chrome/browser/chromeos/notifications/balloon_view.cc @@ -45,7 +45,8 @@ BalloonViewImpl::BalloonViewImpl(bool sticky, bool controls) options_menu_button_(NULL), stale_(false), sticky_(sticky), - controls_(controls) { + controls_(controls), + closed_by_user_(false) { // This object is not to be deleted by the views hierarchy, // as it is owned by the balloon. set_parent_owned(false); @@ -114,6 +115,7 @@ void BalloonViewImpl::Update() { } void BalloonViewImpl::Close(bool by_user) { + closed_by_user_ = by_user; MessageLoop::current()->PostTask( FROM_HERE, method_factory_.NewRunnableMethod( diff --git a/chrome/browser/chromeos/notifications/balloon_view.h b/chrome/browser/chromeos/notifications/balloon_view.h index b350b76..61d9e16 100644 --- a/chrome/browser/chromeos/notifications/balloon_view.h +++ b/chrome/browser/chromeos/notifications/balloon_view.h @@ -65,6 +65,9 @@ class BalloonViewImpl : public BalloonView, // True if the notification is sticky. bool sticky() { return sticky_; } + // True if the notification is closed by the dismiss button. + bool closed_by_user() { return closed_by_user_; } + private: // views::View interface. virtual gfx::Size GetPreferredSize() { @@ -120,6 +123,8 @@ class BalloonViewImpl : public BalloonView, bool sticky_; // True if a notification should have info/option/dismiss label/buttons. bool controls_; + // True if the notification is closed by the dismiss button. + bool closed_by_user_; DISALLOW_COPY_AND_ASSIGN(BalloonViewImpl); }; diff --git a/chrome/browser/chromeos/notifications/notification_panel.cc b/chrome/browser/chromeos/notifications/notification_panel.cc index 0e76591..a1b5035 100644 --- a/chrome/browser/chromeos/notifications/notification_panel.cc +++ b/chrome/browser/chromeos/notifications/notification_panel.cc @@ -32,6 +32,38 @@ const int kStaleTimeoutInSeconds = 10; using chromeos::BalloonViewImpl; +class PanelWidget : public views::WidgetGtk { + public: + explicit PanelWidget(chromeos::NotificationPanel* panel) + : WidgetGtk(views::WidgetGtk::TYPE_WINDOW), + panel_(panel) { + } + + // views::WidgetGtk overrides. + virtual gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) { + gboolean result = WidgetGtk::OnMotionNotify(widget, event); + panel_->DontUpdatePanelOnStale(); + return result; + } + + virtual gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) { + gboolean result = views::WidgetGtk::OnLeaveNotify(widget, event); + // Leave notify can happen if the mouse moves into the child gdk window. + // Make sure the mouse is outside of the panel. + gfx::Point p(event->x_root, event->y_root); + gfx::Rect bounds; + GetBounds(&bounds, true); + if (!bounds.Contains(p)) { + panel_->OnMouseLeave(); + } + return result; + } + + private: + chromeos::NotificationPanel* panel_; + DISALLOW_COPY_AND_ASSIGN(PanelWidget); +}; + class BalloonSubContainer : public views::View { public: explicit BalloonSubContainer(int margin) @@ -258,7 +290,10 @@ class BalloonContainer : public views::View { NotificationPanel::NotificationPanel() : balloon_container_(NULL), state_(CLOSED), - task_factory_(this) { + task_factory_(this), + update_panel_on_mouse_leave_(false), + latest_token_(0), + stale_token_(0) { Init(); } @@ -273,7 +308,7 @@ void NotificationPanel::Show() { if (!panel_widget_.get()) { // TODO(oshima): Using window because Popup widget behaves weird // when resizing. This needs to be investigated. - panel_widget_.reset(new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW)); + panel_widget_.reset(new PanelWidget(this)); gfx::Rect bounds = GetPreferredBounds(); if (bounds.width() < kBalloonMinWidth || bounds.height() < kBalloonMinHeight) { @@ -344,7 +379,13 @@ void NotificationPanel::Remove(Balloon* balloon) { // no change to the state if (balloon_container_->GetNotificationCount() == 0) state_ = CLOSED; - UpdatePanel(true); + if (static_cast<BalloonViewImpl*>(balloon->view())->closed_by_user()) { + DontUpdatePanelOnStale(); + balloon_container_->UpdateBounds(); + scroll_view_->Layout(); + } else { + UpdatePanel(true); + } } void NotificationPanel::ResizeNotification( @@ -396,6 +437,21 @@ void NotificationPanel::OnPanelStateChanged(PanelController::State state) { } } +void NotificationPanel::OnMouseLeave() { + if (update_panel_on_mouse_leave_) { + // TODO(oshima): We need "AS_IS" state, which simply + // keeps the current panel size unless it has less notifications + // than it can show. + if (balloon_container_->GetStickyNotificationCount() > 0 || + balloon_container_->GetNewNotificationCount() > 0) { + state_ = STICKY_AND_NEW; + } else { + state_ = MINIMIZED; + } + UpdatePanel(true); + } +} + //////////////////////////////////////////////////////////////////////////////// // NotificationPanel private. @@ -408,9 +464,12 @@ void NotificationPanel::Init() { scroll_view_.reset(new views::ScrollView()); scroll_view_->set_parent_owned(false); scroll_view_->SetContents(balloon_container_); + scroll_view_->set_background( + views::Background::CreateSolidBackground(SK_ColorWHITE)); } void NotificationPanel::UpdatePanel(bool contents_changed) { + update_panel_on_mouse_leave_ = false; if (contents_changed) { balloon_container_->UpdateBounds(); scroll_view_->Layout(); @@ -461,18 +520,29 @@ gfx::Rect NotificationPanel::GetStickyNewBounds() { return gfx::Rect(0, 0, new_width, new_height); } +void NotificationPanel::DontUpdatePanelOnStale() { + if (stale_token_ != latest_token_) { + stale_token_ = latest_token_; + } + update_panel_on_mouse_leave_ = true; +} + void NotificationPanel::StartStaleTimer(Balloon* balloon) { BalloonViewImpl* view = static_cast<BalloonViewImpl*>(balloon->view()); MessageLoop::current()->PostDelayedTask( FROM_HERE, task_factory_.NewRunnableMethod( - &NotificationPanel::OnStale, view), + &NotificationPanel::OnStale, view, latest_token_++), 1000 * kStaleTimeoutInSeconds); } -void NotificationPanel::OnStale(BalloonViewImpl* view) { +void NotificationPanel::OnStale(BalloonViewImpl* view, int token) { if (balloon_container_->HasBalloonView(view) && !view->stale()) { view->set_stale(); + // don't update panel on stale + if (token < stale_token_) { + return; + } if (balloon_container_->GetStickyNotificationCount() > 0) { state_ = STICKY_AND_NEW; } else { diff --git a/chrome/browser/chromeos/notifications/notification_panel.h b/chrome/browser/chromeos/notifications/notification_panel.h index bbf8740..dfbb47a 100644 --- a/chrome/browser/chromeos/notifications/notification_panel.h +++ b/chrome/browser/chromeos/notifications/notification_panel.h @@ -82,6 +82,13 @@ class NotificationPanel : public PanelController::Delegate, virtual void ClosePanel(); virtual void OnPanelStateChanged(PanelController::State state); + // Called when a mouse left the panel window. + void OnMouseLeave(); + + // Tells that the panel should not update the size or state + // when a notification becomes stale. + void DontUpdatePanelOnStale(); + // Returns number of of sticky notifications. int GetStickyNotificationCount() const; @@ -113,7 +120,9 @@ class NotificationPanel : public PanelController::Delegate, // A callback function that is called when the notification // (that the view is associated with) becomes stale after a timeout. - void OnStale(BalloonViewImpl* view); + // |token| is a unique id assigned to a callback task and is + // used to cancel the task. + void OnStale(BalloonViewImpl* view, int token); BalloonContainer* balloon_container_; scoped_ptr<views::Widget> panel_widget_; @@ -121,6 +130,14 @@ class NotificationPanel : public PanelController::Delegate, scoped_ptr<views::ScrollView> scroll_view_; State state_; ScopedRunnableMethodFactory<NotificationPanel> task_factory_; + bool update_panel_on_mouse_leave_; + + // Task token is an integer value assigned to each task, and + // used to cancel the tasks. + // The latest task token. + int latest_token_; + // A task whose token is smaller than this value is stale and skipped. + int stale_token_; DISALLOW_COPY_AND_ASSIGN(NotificationPanel); }; |