Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / message_center / message_center_widget_delegate.cc
1 // Copyright 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 #include "chrome/browser/ui/views/message_center/message_center_widget_delegate.h"
6
7 #include <complex>
8
9 #include "chrome/browser/ui/views/message_center/message_center_frame_view.h"
10 #include "chrome/browser/ui/views/message_center/web_notification_tray.h"
11 #include "content/public/browser/user_metrics.h"
12 #include "ui/accessibility/ax_view_state.h"
13 #include "ui/gfx/screen.h"
14 #include "ui/message_center/message_center_style.h"
15 #include "ui/message_center/views/message_center_view.h"
16 #include "ui/native_theme/native_theme.h"
17 #include "ui/views/border.h"
18 #include "ui/views/layout/box_layout.h"
19 #include "ui/views/widget/widget.h"
20
21 #if defined(OS_WIN)
22 #include "ui/views/win/hwnd_util.h"
23 #endif
24
25 #if defined(USE_ASH)
26 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
27 #endif
28
29 namespace message_center {
30
31 MessageCenterWidgetDelegate::MessageCenterWidgetDelegate(
32     WebNotificationTray* tray,
33     MessageCenterTray* mc_tray,
34     bool initially_settings_visible,
35     const PositionInfo& pos_info)
36     : MessageCenterView(tray->message_center(),
37                         mc_tray,
38                         pos_info.max_height,
39                         initially_settings_visible,
40                         pos_info.message_center_alignment &
41                             ALIGNMENT_TOP),  // Show buttons on top if message
42                                              // center is top aligned
43       pos_info_(pos_info),
44       tray_(tray) {
45   // A WidgetDelegate should be deleted on DeleteDelegate.
46   set_owned_by_client();
47
48   views::BoxLayout* layout =
49       new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
50   layout->set_spread_blank_space(true);
51   SetLayoutManager(layout);
52
53   AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
54
55   SetPaintToLayer(true);
56   SetFillsBoundsOpaquely(true);
57
58   InitWidget();
59 }
60
61 MessageCenterWidgetDelegate::~MessageCenterWidgetDelegate() {
62   views::Widget* widget = GetWidget();
63   if (widget) {
64     widget->RemoveObserver(this);
65   }
66 }
67
68 views::View* MessageCenterWidgetDelegate::GetContentsView() {
69   return this;
70 }
71
72 views::NonClientFrameView*
73 MessageCenterWidgetDelegate::CreateNonClientFrameView(views::Widget* widget) {
74   MessageCenterFrameView* frame_view = new MessageCenterFrameView();
75   border_insets_ = frame_view->GetInsets();
76   return frame_view;
77 }
78
79 void MessageCenterWidgetDelegate::DeleteDelegate() {
80   delete this;
81 }
82
83 views::Widget* MessageCenterWidgetDelegate::GetWidget() {
84   return View::GetWidget();
85 }
86
87 const views::Widget* MessageCenterWidgetDelegate::GetWidget() const {
88   return View::GetWidget();
89 }
90
91 void MessageCenterWidgetDelegate::OnWidgetActivationChanged(
92     views::Widget* widget,
93     bool active) {
94   // Some Linux users set 'focus-follows-mouse' where the activation is lost
95   // immediately after the mouse exists from the bubble, which is a really bad
96   // experience. Disable hiding until the bug around the focus is fixed.
97   // TODO(erg, pkotwicz): fix the activation issue and then remove this ifdef.
98 #if !defined(OS_LINUX)
99   if (!active) {
100     tray_->SendHideMessageCenter();
101   }
102 #endif
103 }
104
105 void MessageCenterWidgetDelegate::OnWidgetClosing(views::Widget* widget) {
106   SetIsClosing(true);
107   tray_->MarkMessageCenterHidden();
108 }
109
110 void MessageCenterWidgetDelegate::PreferredSizeChanged() {
111   GetWidget()->SetBounds(GetMessageCenterBounds());
112   views::View::PreferredSizeChanged();
113 }
114
115 gfx::Size MessageCenterWidgetDelegate::GetPreferredSize() {
116   int preferred_width = kNotificationWidth + 2 * kMarginBetweenItems;
117   return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
118 }
119
120 gfx::Size MessageCenterWidgetDelegate::GetMaximumSize() {
121   gfx::Size size = GetPreferredSize();
122   return size;
123 }
124
125 int MessageCenterWidgetDelegate::GetHeightForWidth(int width) {
126   int height = MessageCenterView::GetHeightForWidth(width);
127   return (pos_info_.max_height != 0) ?
128     std::min(height, pos_info_.max_height - border_insets_.height()) : height;
129 }
130
131 bool MessageCenterWidgetDelegate::AcceleratorPressed(
132     const ui::Accelerator& accelerator) {
133   if (accelerator.key_code() != ui::VKEY_ESCAPE)
134     return false;
135   tray_->SendHideMessageCenter();
136   return true;
137 }
138
139 void MessageCenterWidgetDelegate::InitWidget() {
140   views::Widget* widget = new views::Widget();
141   views::Widget::InitParams params(views::Widget::InitParams::TYPE_BUBBLE);
142   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
143   params.delegate = this;
144   params.keep_on_top = true;
145   params.top_level = true;
146 #if defined(USE_ASH)
147   // This class is not used in Ash; there is another container for the message
148   // center that's used there.  So, we must be in a Views + Ash environment.  We
149   // want the notification center to be available on both desktops.  Setting the
150   // |native_widget| variable here ensures that the widget is hosted on the
151   // native desktop.
152   params.native_widget = new views::DesktopNativeWidgetAura(widget);
153 #endif
154   widget->Init(params);
155
156   widget->AddObserver(this);
157   widget->StackAtTop();
158   widget->SetAlwaysOnTop(true);
159
160   const NotificationList::Notifications& notifications =
161       tray_->message_center()->GetVisibleNotifications();
162   SetNotifications(notifications);
163
164   widget->SetBounds(GetMessageCenterBounds());
165   widget->Show();
166   widget->Activate();
167 }
168
169 gfx::Point MessageCenterWidgetDelegate::GetCorrectedAnchor(
170     gfx::Size calculated_size) {
171   gfx::Point corrected_anchor = pos_info_.inital_anchor_point;
172
173   // Inset the width slightly so that the click point is not exactly on the edge
174   // of the message center but somewhere within the middle 60 %.
175   int insetted_width = (calculated_size.width() * 4) / 5;
176
177   if (pos_info_.taskbar_alignment == ALIGNMENT_TOP ||
178       pos_info_.taskbar_alignment == ALIGNMENT_BOTTOM) {
179     int click_point_x = tray_->mouse_click_point().x();
180
181     if (pos_info_.message_center_alignment & ALIGNMENT_RIGHT) {
182       int opposite_x_corner =
183           pos_info_.inital_anchor_point.x() - insetted_width;
184
185       // If the click point is outside the x axis length of the message center,
186       // push the message center towards the left to align with the click point.
187       if (opposite_x_corner > click_point_x)
188         corrected_anchor.set_x(pos_info_.inital_anchor_point.x() -
189                                (opposite_x_corner - click_point_x));
190     } else {
191       int opposite_x_corner =
192           pos_info_.inital_anchor_point.x() + insetted_width;
193
194       if (opposite_x_corner < click_point_x)
195         corrected_anchor.set_x(pos_info_.inital_anchor_point.x() +
196                                (click_point_x - opposite_x_corner));
197     }
198   } else if (pos_info_.taskbar_alignment == ALIGNMENT_LEFT ||
199              pos_info_.taskbar_alignment == ALIGNMENT_RIGHT) {
200     int click_point_y = tray_->mouse_click_point().y();
201
202     if (pos_info_.message_center_alignment & ALIGNMENT_BOTTOM) {
203       int opposite_y_corner =
204           pos_info_.inital_anchor_point.y() - insetted_width;
205
206       // If the click point is outside the y axis length of the message center,
207       // push the message center upwards to align with the click point.
208       if (opposite_y_corner > click_point_y)
209         corrected_anchor.set_y(pos_info_.inital_anchor_point.y() -
210                                (opposite_y_corner - click_point_y));
211     } else {
212       int opposite_y_corner =
213           pos_info_.inital_anchor_point.y() + insetted_width;
214
215       if (opposite_y_corner < click_point_y)
216         corrected_anchor.set_y(pos_info_.inital_anchor_point.y() +
217                                (click_point_y - opposite_y_corner));
218     }
219   }
220   return corrected_anchor;
221 }
222
223 gfx::Rect MessageCenterWidgetDelegate::GetMessageCenterBounds() {
224   gfx::Size size = GetPreferredSize();
225
226   // Make space for borders on sides.
227   size.Enlarge(border_insets_.width(), border_insets_.height());
228   gfx::Rect bounds(size);
229
230   gfx::Point corrected_anchor = GetCorrectedAnchor(size);
231
232   if (pos_info_.message_center_alignment & ALIGNMENT_TOP)
233     bounds.set_y(corrected_anchor.y());
234   if (pos_info_.message_center_alignment & ALIGNMENT_BOTTOM)
235     bounds.set_y(corrected_anchor.y() - size.height());
236   if (pos_info_.message_center_alignment & ALIGNMENT_LEFT)
237     bounds.set_x(corrected_anchor.x());
238   if (pos_info_.message_center_alignment & ALIGNMENT_RIGHT)
239     bounds.set_x(corrected_anchor.x() - size.width());
240
241   return bounds;
242 }
243
244 }  // namespace message_center