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#include "chrome/browser/chromeos/notifications/balloon_collection_impl.h"
6
7#include <algorithm>
8
9#include "base/logging.h"
10#include "chrome/browser/chromeos/notifications/balloon_view.h"
11#include "chrome/browser/chromeos/notifications/notification_panel.h"
12#include "chrome/browser/notifications/balloon.h"
13#include "chrome/browser/notifications/notification.h"
14#include "chrome/browser/ui/browser_list.h"
15#include "chrome/browser/ui/window_sizer.h"
16#include "content/common/notification_service.h"
17#include "ui/gfx/rect.h"
18#include "ui/gfx/size.h"
19
20namespace {
21
22// Margin from the edge of the work area
23const int kVerticalEdgeMargin = 5;
24const int kHorizontalEdgeMargin = 5;
25
26}  // namespace
27
28namespace chromeos {
29
30BalloonCollectionImpl::BalloonCollectionImpl()
31    : notification_ui_(new NotificationPanel()) {
32  registrar_.Add(this, NotificationType::BROWSER_CLOSED,
33                 NotificationService::AllSources());
34}
35
36BalloonCollectionImpl::~BalloonCollectionImpl() {
37  Shutdown();
38}
39
40void BalloonCollectionImpl::Add(const Notification& notification,
41                                Profile* profile) {
42  Balloon* new_balloon = MakeBalloon(notification, profile);
43  base_.Add(new_balloon);
44  new_balloon->Show();
45  notification_ui_->Add(new_balloon);
46
47  // There may be no listener in a unit test.
48  if (space_change_listener_)
49    space_change_listener_->OnBalloonSpaceChanged();
50}
51
52bool BalloonCollectionImpl::AddWebUIMessageCallback(
53    const Notification& notification,
54    const std::string& message,
55    MessageCallback* callback) {
56  Balloon* balloon = FindBalloon(notification);
57  if (!balloon) {
58    delete callback;
59    return false;
60  }
61  BalloonViewHost* host =
62      static_cast<BalloonViewHost*>(balloon->view()->GetHost());
63  return host->AddWebUIMessageCallback(message, callback);
64}
65
66void BalloonCollectionImpl::AddSystemNotification(
67    const Notification& notification,
68    Profile* profile,
69    bool sticky,
70    bool control) {
71
72  Balloon* new_balloon = new Balloon(notification, profile, this);
73  new_balloon->set_view(
74      new chromeos::BalloonViewImpl(sticky, control, true));
75  base_.Add(new_balloon);
76  new_balloon->Show();
77  notification_ui_->Add(new_balloon);
78
79  // There may be no listener in a unit test.
80  if (space_change_listener_)
81    space_change_listener_->OnBalloonSpaceChanged();
82}
83
84bool BalloonCollectionImpl::UpdateNotification(
85    const Notification& notification) {
86  Balloon* balloon = FindBalloon(notification);
87  if (!balloon)
88    return false;
89  balloon->Update(notification);
90  notification_ui_->Update(balloon);
91  return true;
92}
93
94bool BalloonCollectionImpl::UpdateAndShowNotification(
95    const Notification& notification) {
96  Balloon* balloon = FindBalloon(notification);
97  if (!balloon)
98    return false;
99  balloon->Update(notification);
100  bool updated = notification_ui_->Update(balloon);
101  DCHECK(updated);
102  notification_ui_->Show(balloon);
103  return true;
104}
105
106bool BalloonCollectionImpl::RemoveById(const std::string& id) {
107  return base_.CloseById(id);
108}
109
110bool BalloonCollectionImpl::RemoveBySourceOrigin(const GURL& origin) {
111  return base_.CloseAllBySourceOrigin(origin);
112}
113
114void BalloonCollectionImpl::RemoveAll() {
115  base_.CloseAll();
116}
117
118bool BalloonCollectionImpl::HasSpace() const {
119  return true;
120}
121
122void BalloonCollectionImpl::ResizeBalloon(Balloon* balloon,
123                                          const gfx::Size& size) {
124  notification_ui_->ResizeNotification(balloon, size);
125}
126
127void BalloonCollectionImpl::OnBalloonClosed(Balloon* source) {
128  notification_ui_->Remove(source);
129  base_.Remove(source);
130
131  // There may be no listener in a unit test.
132  if (space_change_listener_)
133    space_change_listener_->OnBalloonSpaceChanged();
134}
135
136void BalloonCollectionImpl::Observe(NotificationType type,
137                                    const NotificationSource& source,
138                                    const NotificationDetails& details) {
139  DCHECK(type == NotificationType::BROWSER_CLOSED);
140  bool app_closing = *Details<bool>(details).ptr();
141  // When exiting, we need to shutdown all renderers in
142  // BalloonViewImpl before IO thread gets deleted in the
143  // BrowserProcessImpl's destructor.  See http://crbug.com/40810
144  // for details.
145  if (app_closing)
146    RemoveAll();
147}
148
149void BalloonCollectionImpl::Shutdown() {
150  // We need to remove the panel first because deleting
151  // views that are not owned by parent will not remove
152  // themselves from the parent.
153  DVLOG(1) << "Shutting down notification UI";
154  notification_ui_.reset();
155}
156
157Balloon* BalloonCollectionImpl::MakeBalloon(const Notification& notification,
158                                            Profile* profile) {
159  Balloon* new_balloon = new Balloon(notification, profile, this);
160  new_balloon->set_view(new chromeos::BalloonViewImpl(false, true, false));
161  return new_balloon;
162}
163
164}  // namespace chromeos
165
166// static
167BalloonCollection* BalloonCollection::Create() {
168  return new chromeos::BalloonCollectionImpl();
169}
170