1// Copyright (c) 2011 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// Draws the view for the balloons.
6
7#ifndef CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_NOTIFICATION_PANEL_H_
8#define CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_NOTIFICATION_PANEL_H_
9#pragma once
10
11#include "base/memory/scoped_ptr.h"
12#include "base/task.h"
13#include "chrome/browser/chromeos/frame/panel_controller.h"
14#include "chrome/browser/chromeos/notifications/balloon_collection_impl.h"
15#include "content/common/notification_registrar.h"
16#include "ui/gfx/rect.h"
17
18class Balloon;
19class Notification;
20
21namespace views {
22class ScrollView;
23}  // namespace views
24
25namespace chromeos {
26
27class BalloonContainer;
28class BalloonViewImpl;
29class NotificationPanelTester;
30
31// NotificationPanel is a panel that displays notifications. It has
32// several states and displays the different portion of notifications
33// depending on in which state the panel is. The following shows
34// how the panel's state changes in response to various events.
35//
36// TODO(oshima): add remove event and fix state transition graph below.
37// Event List:
38//   close: a user pressed close button on the title bar,
39//          or the system closed the panel.
40//   new : a new notification is added.
41//   stale: one of new notifications became stale.
42//   expand: a user pressed minimized panel to expand.
43//   minimize: a user pressed the panel's title bar to minimize.
44//   user: the user's mouse moved over the panel, indicates
45//         that user is trying to interact with the panel.
46// For state, see State enum's description below.
47//
48//
49// [CLOSE]<-(event=close)-+     +--(event=stale, cond=has new|sticky)
50//   |                    |     |         (event=new)
51//   |                    |     V           |
52//   +--(event=new)-->[STICKY_AND_NEW]----- +--------(event=user)
53//   |                  ^           |                      |
54//   |                  |  (event=stale,                   V
55//   |                  |  cond=has new, no sticy)  +[ KEEP_SIZE ]<-+
56//   |          (event=new)   (event=minimize)      |      |        |
57//   |                  |           |               |      |        |
58//   |                  |           |  (event=minimize)(event=close)|
59//   |                  |           +---------------+      |        |
60//   |                  |           V                      V        |
61//   |                  [ MINIMIZED ]---(event=close)--> [CLOSE]    |
62//   |                     |     ^                                  |
63//   |                     |     |                                  |
64//   |          (event=expand)  (event=minmize)                 (event=user)
65//   |                     V     |                                  |
66//   +--(event=open)---->[  FULL  ]-------------+-------------------+
67//                         |     ^              |
68//              (event=close)    +-------(event=stale)(event=new)
69//                         |
70//          [CLOSE] <------+
71//
72class NotificationPanel : public PanelController::Delegate,
73                          public BalloonCollectionImpl::NotificationUI,
74                          public NotificationObserver {
75 public:
76  enum State {
77    FULL,  // Show all notifications
78    KEEP_SIZE,  // Don't change the size.
79    STICKY_AND_NEW,  // Show only new and sticky notifications.
80    MINIMIZED,  // The panel is minimized.
81    CLOSED,  // The panel is closed.
82  };
83
84  NotificationPanel();
85  virtual ~NotificationPanel();
86
87  // Shows/Hides the Panel.
88  void Show();
89  void Hide();
90
91  // BalloonCollectionImpl::NotificationUI overrides..
92  virtual void Add(Balloon* balloon);
93  virtual bool Update(Balloon* balloon);
94  virtual void Remove(Balloon* balloon);
95  virtual void Show(Balloon* balloon);
96  virtual void ResizeNotification(Balloon* balloon,
97                                  const gfx::Size& size);
98  virtual void SetActiveView(BalloonViewImpl* view);
99
100  // PanelController::Delegate overrides.
101  virtual string16 GetPanelTitle();
102  virtual SkBitmap GetPanelIcon();
103  virtual bool CanClosePanel();
104  virtual void ClosePanel();
105  virtual void ActivatePanel();
106
107  // NotificationObserver overrides:
108  virtual void Observe(NotificationType type,
109                       const NotificationSource& source,
110                       const NotificationDetails& details);
111
112  // Called when a mouse left the panel window.
113  void OnMouseLeave();
114  void OnMouseMotion(const gfx::Point& point);
115
116  NotificationPanelTester* GetTester();
117
118 private:
119  friend class NotificationPanelTester;
120
121  void Init();
122
123  // Unregister the panel's state change notification.
124  void UnregisterNotification();
125
126  // Update the Panel Size according to its state.
127  void UpdatePanel(bool update_panel_size);
128
129  // Scroll the panel so that the |balloon| is visible.
130  void ScrollBalloonToVisible(Balloon* balloon);
131
132  // Update the container's bounds so that it can show all notifications.
133  void UpdateContainerBounds();
134
135  // Update the notification's control view state.
136  void UpdateControl();
137
138  // Returns the panel's preferred bounds in the screen's coordinates.
139  // The position will be controlled by window manager so
140  // the origin is always (0, 0).
141  gfx::Rect GetPreferredBounds();
142
143  // Returns the bounds that covers sticky and new notifications.
144  gfx::Rect GetStickyNewBounds();
145
146  void StartStaleTimer(Balloon* balloon);
147
148  // A callback function that is called when the notification
149  // (that the view is associated with) becomes stale after a timeout.
150  void OnStale(BalloonViewImpl* view);
151
152  // Set the state. It can also print the
153  void SetState(State, const char* method_name);
154
155  // Mark the given notification as stale.
156  void MarkStale(const Notification& notification);
157
158  // Contains all notifications. This is owned by the panel so that we can
159  // re-attach to the widget when closing and opening the panel.
160  scoped_ptr<BalloonContainer> balloon_container_;
161
162  // The notification panel's widget.
163  views::Widget* panel_widget_;
164
165  // The notification panel's widget.
166  views::Widget* container_host_;
167
168  // Panel controller for the notification panel.
169  // This is owned by the panel to compute the panel size before
170  // actually opening the panel.
171  scoped_ptr<PanelController> panel_controller_;
172
173  // A scrollable parent of the BalloonContainer.
174  scoped_ptr<views::ScrollView> scroll_view_;
175
176  // Panel's state.
177  State state_;
178
179  ScopedRunnableMethodFactory<NotificationPanel> task_factory_;
180
181  // The minimum size of a notification.
182  gfx::Rect min_bounds_;
183
184  // Stale timeout.
185  int stale_timeout_;
186
187  // A registrar to subscribe PANEL_STATE_CHANGED event.
188  NotificationRegistrar registrar_;
189
190  // The notification a mouse pointer is currently on. NULL if the mouse
191  // is out of the panel.
192  BalloonViewImpl* active_;
193
194  // A balloon that should be visible when it gets some size.
195  Balloon* scroll_to_;
196
197  // An object that provides interfacce for tests.
198  scoped_ptr<NotificationPanelTester> tester_;
199
200  DISALLOW_COPY_AND_ASSIGN(NotificationPanel);
201};
202
203class NotificationPanelTester {
204 public:
205  explicit NotificationPanelTester(NotificationPanel* panel)
206      : panel_(panel) {
207  }
208
209  NotificationPanel::State state() {
210    return panel_->state_;
211  }
212
213  // Returns number of of sticky and new notifications.
214  int GetNotificationCount() const;
215
216  // Returns number of new notifications.
217  int GetNewNotificationCount() const;
218
219  // Returns number of of sticky notifications.
220  int GetStickyNotificationCount() const;
221
222  // Sets the timeout for a notification to become stale.
223  void SetStaleTimeout(int timeout);
224
225  // Mark the given notification as stale.
226  void MarkStale(const Notification& notification);
227
228  // Returns the notification panel's PanelController.
229  PanelController* GetPanelController() const;
230
231  // Returns the BalloonView object of the notification.
232  BalloonViewImpl* GetBalloonView(BalloonCollectionImpl* collection,
233                                  const Notification& notification);
234
235  // True if the view is in visible in the ScrollView.
236  bool IsVisible(const BalloonViewImpl* view) const;
237
238  // True if the view is currently active.
239  bool IsActive(const BalloonViewImpl* view) const;
240
241 private:
242  NotificationPanel* panel_;
243  DISALLOW_COPY_AND_ASSIGN(NotificationPanelTester);
244};
245
246}  // namespace chromeos
247
248#endif  // CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_NOTIFICATION_PANEL_H_
249