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.
5 #ifndef UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_
6 #define UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_
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/geometry/rect.h"
16 #include "ui/gfx/native_widget_types.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"
36 namespace message_center
{
38 class MessagePopupCollectionTest
;
42 class MessageCenterTray
;
43 class MessageViewContextMenuController
;
44 class PopupAlignmentDelegate
;
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
{
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
58 MessagePopupCollection(gfx::NativeView parent
,
59 MessageCenter
* message_center
,
60 MessageCenterTray
* tray
,
61 PopupAlignmentDelegate
* alignment_delegate
);
62 ~MessagePopupCollection() override
;
64 // Overridden from MessageCenterController:
65 void ClickOnNotification(const std::string
& notification_id
) override
;
66 void RemoveNotification(const std::string
& notification_id
,
67 bool by_user
) override
;
68 scoped_ptr
<ui::MenuModel
> CreateMenuModel(
69 const NotifierId
& notifier_id
,
70 const base::string16
& display_source
) override
;
71 bool HasClickedListener(const std::string
& notification_id
) override
;
72 void ClickOnNotificationButton(const std::string
& notification_id
,
73 int button_index
) override
;
75 void MarkAllPopupsShown();
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
);
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
87 void IncrementDeferCounter();
88 void DecrementDeferCounter();
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();
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
);
98 // Called when the display bounds has been changed. Used in Windows only.
99 void OnDisplayMetricsChanged(const gfx::Display
& display
);
101 // Used by ToastContentsView to locate itself.
102 gfx::NativeView
parent() const { return parent_
; }
105 friend class test::MessagePopupCollectionTest
;
106 typedef std::list
<ToastContentsView
*> Toasts
;
108 // Iterates toasts and starts closing them.
109 std::set
<std::string
> CloseAllWidgets();
111 // Called by ToastContentsView when its window is closed.
112 void RemoveToast(ToastContentsView
* toast
, bool mark_as_shown
);
114 // Creates new widgets for new toast notifications, and updates |toasts_| and
115 // |widgets_| correctly.
116 void UpdateWidgets();
118 // Repositions all of the widgets based on the current work area.
119 void RepositionWidgets();
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();
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;
130 // Overridden from MessageCenterObserver:
131 void OnNotificationAdded(const std::string
& notification_id
) override
;
132 void OnNotificationRemoved(const std::string
& notification_id
,
133 bool by_user
) override
;
134 void OnNotificationUpdated(const std::string
& notification_id
) override
;
136 ToastContentsView
* FindToast(const std::string
& notification_id
) const;
138 // While the toasts are animated, avoid updating the collection, to reduce
139 // user confusion. Instead, update the collection when all animations are
140 // done. This method is run when defer counter is zero, may initiate next
141 // update/animation step.
142 void OnDeferTimerExpired();
144 // "ForTest" methods.
145 views::Widget
* GetWidgetForTest(const std::string
& id
) const;
146 void CreateRunLoopForTest();
148 gfx::Rect
GetToastRectAt(size_t index
) const;
150 gfx::NativeView parent_
;
151 MessageCenter
* message_center_
;
152 MessageCenterTray
* tray_
;
155 PopupAlignmentDelegate
* alignment_delegate_
;
159 // This is only used to compare with incoming events, do not assume that
160 // the toast will be valid if this pointer is non-NULL.
161 ToastContentsView
* latest_toast_entered_
;
163 // Denotes a mode when user is clicking the Close button of toasts in a
164 // sequence, w/o moving the mouse. We reposition the toasts so the next one
165 // happens to be right under the mouse, and the user can just dispose of
166 // multipel toasts by clicking. The mode ends when defer_timer_ expires.
167 bool user_is_closing_toasts_by_clicking_
;
168 scoped_ptr
<base::OneShotTimer
<MessagePopupCollection
> > defer_timer_
;
169 // The top edge to align the position of the next toast during 'close by
171 // Only to be used when user_is_closing_toasts_by_clicking_ is true.
172 int target_top_edge_
;
174 // Weak, only exists temporarily in tests.
175 scoped_ptr
<base::RunLoop
> run_loop_for_test_
;
177 scoped_ptr
<MessageViewContextMenuController
> context_menu_controller_
;
179 // Gives out weak pointers to toast contents views which have an unrelated
180 // lifetime. Must remain the last member variable.
181 base::WeakPtrFactory
<MessagePopupCollection
> weak_factory_
;
183 DISALLOW_COPY_AND_ASSIGN(MessagePopupCollection
);
186 } // namespace message_center
188 #endif // UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_