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