Home | History | Annotate | Download | only in views
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_
      6 #define UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_
      7 
      8 #include <list>
      9 #include <map>
     10 
     11 #include "base/compiler_specific.h"
     12 #include "base/gtest_prod_util.h"
     13 #include "base/memory/weak_ptr.h"
     14 #include "base/timer/timer.h"
     15 #include "ui/gfx/native_widget_types.h"
     16 #include "ui/gfx/rect.h"
     17 #include "ui/message_center/message_center_export.h"
     18 #include "ui/message_center/message_center_observer.h"
     19 #include "ui/message_center/views/message_center_controller.h"
     20 #include "ui/message_center/views/toast_contents_view.h"
     21 #include "ui/views/widget/widget_observer.h"
     22 
     23 namespace base {
     24 class RunLoop;
     25 }
     26 
     27 namespace views {
     28 class Widget;
     29 }
     30 
     31 namespace gfx {
     32 class Display;
     33 class Screen;
     34 }
     35 
     36 namespace message_center {
     37 namespace test {
     38 class MessagePopupCollectionTest;
     39 }
     40 
     41 class MessageCenter;
     42 class MessageCenterTray;
     43 class MessageViewContextMenuController;
     44 class PopupAlignmentDelegate;
     45 
     46 // Container for popup toasts. Because each toast is a frameless window rather
     47 // than a view in a bubble, now the container just manages all of those toasts.
     48 // This is similar to chrome/browser/notifications/balloon_collection, but the
     49 // contents of each toast are for the message center and layout strategy would
     50 // be slightly different.
     51 class MESSAGE_CENTER_EXPORT MessagePopupCollection
     52     : public MessageCenterController,
     53       public MessageCenterObserver {
     54  public:
     55   // |parent| specifies the parent widget of the toast windows. The default
     56   // parent will be used for NULL. Usually each icon is spacing against its
     57   // predecessor.
     58   MessagePopupCollection(gfx::NativeView parent,
     59                          MessageCenter* message_center,
     60                          MessageCenterTray* tray,
     61                          PopupAlignmentDelegate* alignment_delegate);
     62   virtual ~MessagePopupCollection();
     63 
     64   // Overridden from MessageCenterController:
     65   virtual void ClickOnNotification(const std::string& notification_id) OVERRIDE;
     66   virtual void RemoveNotification(const std::string& notification_id,
     67                                   bool by_user) OVERRIDE;
     68   virtual scoped_ptr<ui::MenuModel> CreateMenuModel(
     69       const NotifierId& notifier_id,
     70       const base::string16& display_source) OVERRIDE;
     71   virtual bool HasClickedListener(const std::string& notification_id) OVERRIDE;
     72   virtual void ClickOnNotificationButton(const std::string& notification_id,
     73                                          int button_index) OVERRIDE;
     74 
     75   void MarkAllPopupsShown();
     76 
     77   // Since these events are really coming from individual toast widgets,
     78   // it helps to be able to keep track of the sender.
     79   void OnMouseEntered(ToastContentsView* toast_entered);
     80   void OnMouseExited(ToastContentsView* toast_exited);
     81 
     82   // Invoked by toasts when they start/finish their animations.
     83   // While "defer counter" is greater then zero, the popup collection does
     84   // not perform updates. It is used to wait for various animations and user
     85   // actions like serial closing of the toasts, when the remaining toasts "flow
     86   // under the mouse".
     87   void IncrementDeferCounter();
     88   void DecrementDeferCounter();
     89 
     90   // Runs the next step in update/animate sequence, if the defer counter is not
     91   // zero. Otherwise, simply waits when it becomes zero.
     92   void DoUpdateIfPossible();
     93 
     94   // Removes the toast from our internal list of toasts; this is called when the
     95   // toast is irrevocably closed (such as within RemoveToast).
     96   void ForgetToast(ToastContentsView* toast);
     97 
     98   // Called when the display bounds has been changed. Used in Windows only.
     99   void OnDisplayMetricsChanged(const gfx::Display& display);
    100 
    101   // Used by ToastContentsView to locate itself.
    102   gfx::NativeView parent() const { return parent_; }
    103 
    104  private:
    105   friend class test::MessagePopupCollectionTest;
    106   typedef std::list<ToastContentsView*> Toasts;
    107 
    108   // Iterates toasts and starts closing them.
    109   std::set<std::string> CloseAllWidgets();
    110 
    111   // Called by ToastContentsView when its window is closed.
    112   void RemoveToast(ToastContentsView* toast, bool mark_as_shown);
    113 
    114   // Creates new widgets for new toast notifications, and updates |toasts_| and
    115   // |widgets_| correctly.
    116   void UpdateWidgets();
    117 
    118   // Repositions all of the widgets based on the current work area.
    119   void RepositionWidgets();
    120 
    121   // Repositions widgets to the top edge of the notification toast that was
    122   // just removed, so that the user can click close button without mouse moves.
    123   // See crbug.com/224089
    124   void RepositionWidgetsWithTarget();
    125 
    126   // The base line is an (imaginary) line that would touch the bottom of the
    127   // next created notification if bottom-aligned or its top if top-aligned.
    128   int GetBaseLine(ToastContentsView* last_toast) const;
    129 
    130   // Overridden from MessageCenterObserver:
    131   virtual void OnNotificationAdded(const std::string& notification_id) OVERRIDE;
    132   virtual void OnNotificationRemoved(const std::string& notification_id,
    133                                      bool by_user) OVERRIDE;
    134   virtual void OnNotificationUpdated(
    135       const std::string& notification_id) OVERRIDE;
    136 
    137   ToastContentsView* FindToast(const std::string& notification_id) const;
    138 
    139   // While the toasts are animated, avoid updating the collection, to reduce
    140   // user confusion. Instead, update the collection when all animations are
    141   // done. This method is run when defer counter is zero, may initiate next
    142   // update/animation step.
    143   void OnDeferTimerExpired();
    144 
    145   // "ForTest" methods.
    146   views::Widget* GetWidgetForTest(const std::string& id) const;
    147   void CreateRunLoopForTest();
    148   void WaitForTest();
    149   gfx::Rect GetToastRectAt(size_t index) const;
    150 
    151   gfx::NativeView parent_;
    152   MessageCenter* message_center_;
    153   MessageCenterTray* tray_;
    154   Toasts toasts_;
    155 
    156   PopupAlignmentDelegate* alignment_delegate_;
    157 
    158   int defer_counter_;
    159 
    160   // This is only used to compare with incoming events, do not assume that
    161   // the toast will be valid if this pointer is non-NULL.
    162   ToastContentsView* latest_toast_entered_;
    163 
    164   // Denotes a mode when user is clicking the Close button of toasts in a
    165   // sequence, w/o moving the mouse. We reposition the toasts so the next one
    166   // happens to be right under the mouse, and the user can just dispose of
    167   // multipel toasts by clicking. The mode ends when defer_timer_ expires.
    168   bool user_is_closing_toasts_by_clicking_;
    169   scoped_ptr<base::OneShotTimer<MessagePopupCollection> > defer_timer_;
    170   // The top edge to align the position of the next toast during 'close by
    171   // clicking" mode.
    172   // Only to be used when user_is_closing_toasts_by_clicking_ is true.
    173   int target_top_edge_;
    174 
    175   // Weak, only exists temporarily in tests.
    176   scoped_ptr<base::RunLoop> run_loop_for_test_;
    177 
    178   scoped_ptr<MessageViewContextMenuController> context_menu_controller_;
    179 
    180   // Gives out weak pointers to toast contents views which have an unrelated
    181   // lifetime.  Must remain the last member variable.
    182   base::WeakPtrFactory<MessagePopupCollection> weak_factory_;
    183 
    184   DISALLOW_COPY_AND_ASSIGN(MessagePopupCollection);
    185 };
    186 
    187 }  // namespace message_center
    188 
    189 #endif // UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_
    190