• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "ui/message_center/views/message_view.h"
6 
7 #include "grit/ui_resources.h"
8 #include "grit/ui_strings.h"
9 #include "ui/accessibility/ax_view_state.h"
10 #include "ui/base/l10n/l10n_util.h"
11 #include "ui/base/models/simple_menu_model.h"
12 #include "ui/base/resource/resource_bundle.h"
13 #include "ui/compositor/scoped_layer_animation_settings.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/message_center/message_center.h"
16 #include "ui/message_center/message_center_style.h"
17 #include "ui/message_center/views/padded_button.h"
18 #include "ui/views/background.h"
19 #include "ui/views/controls/button/image_button.h"
20 #include "ui/views/controls/image_view.h"
21 #include "ui/views/controls/scroll_view.h"
22 #include "ui/views/focus/focus_manager.h"
23 #include "ui/views/painter.h"
24 #include "ui/views/shadow_border.h"
25 
26 namespace {
27 
28 const int kCloseIconTopPadding = 5;
29 const int kCloseIconRightPadding = 5;
30 
31 const int kShadowOffset = 1;
32 const int kShadowBlur = 4;
33 
34 }  // namespace
35 
36 namespace message_center {
37 
MessageView(MessageViewController * controller,const std::string & notification_id,const NotifierId & notifier_id,const gfx::ImageSkia & small_image,const base::string16 & display_source)38 MessageView::MessageView(MessageViewController* controller,
39                          const std::string& notification_id,
40                          const NotifierId& notifier_id,
41                          const gfx::ImageSkia& small_image,
42                          const base::string16& display_source)
43     : controller_(controller),
44       notification_id_(notification_id),
45       notifier_id_(notifier_id),
46       background_view_(NULL),
47       scroller_(NULL),
48       display_source_(display_source) {
49   SetFocusable(true);
50 
51   // Create the opaque background that's above the view's shadow.
52   background_view_ = new views::View();
53   background_view_->set_background(
54       views::Background::CreateSolidBackground(kNotificationBackgroundColor));
55   AddChildView(background_view_);
56 
57   views::ImageView* small_image_view = new views::ImageView();
58   small_image_view->SetImage(small_image);
59   small_image_view->SetImageSize(gfx::Size(kSmallImageSize, kSmallImageSize));
60   // The small image view should be added to view hierarchy by the derived
61   // class. This ensures that it is on top of other views.
62   small_image_view->set_owned_by_client();
63   small_image_view_.reset(small_image_view);
64 
65   PaddedButton *close = new PaddedButton(this);
66   close->SetPadding(-kCloseIconRightPadding, kCloseIconTopPadding);
67   close->SetNormalImage(IDR_NOTIFICATION_CLOSE);
68   close->SetHoveredImage(IDR_NOTIFICATION_CLOSE_HOVER);
69   close->SetPressedImage(IDR_NOTIFICATION_CLOSE_PRESSED);
70   close->set_animate_on_state_change(false);
71   close->SetAccessibleName(l10n_util::GetStringUTF16(
72       IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME));
73   // The close button should be added to view hierarchy by the derived class.
74   // This ensures that it is on top of other views.
75   close->set_owned_by_client();
76   close_button_.reset(close);
77 
78   focus_painter_ = views::Painter::CreateSolidFocusPainter(
79       kFocusBorderColor,
80       gfx::Insets(0, 1, 3, 2)).Pass();
81 }
82 
~MessageView()83 MessageView::~MessageView() {
84 }
85 
UpdateWithNotification(const Notification & notification)86 void MessageView::UpdateWithNotification(const Notification& notification) {
87   small_image_view_->SetImage(notification.small_image().AsImageSkia());
88   display_source_ = notification.display_source();
89 }
90 
91 // static
GetShadowInsets()92 gfx::Insets MessageView::GetShadowInsets() {
93   return gfx::Insets(kShadowBlur / 2 - kShadowOffset,
94                      kShadowBlur / 2,
95                      kShadowBlur / 2 + kShadowOffset,
96                      kShadowBlur / 2);
97 }
98 
CreateShadowBorder()99 void MessageView::CreateShadowBorder() {
100   SetBorder(scoped_ptr<views::Border>(
101       new views::ShadowBorder(kShadowBlur,
102                               message_center::kShadowColor,
103                               kShadowOffset,  // Vertical offset.
104                               0)));           // Horizontal offset.
105 }
106 
IsCloseButtonFocused()107 bool MessageView::IsCloseButtonFocused() {
108   views::FocusManager* focus_manager = GetFocusManager();
109   return focus_manager && focus_manager->GetFocusedView() == close_button();
110 }
111 
RequestFocusOnCloseButton()112 void MessageView::RequestFocusOnCloseButton() {
113   close_button_->RequestFocus();
114 }
115 
GetAccessibleState(ui::AXViewState * state)116 void MessageView::GetAccessibleState(ui::AXViewState* state) {
117   state->role = ui::AX_ROLE_BUTTON;
118   state->name = accessible_name_;
119 }
120 
OnMousePressed(const ui::MouseEvent & event)121 bool MessageView::OnMousePressed(const ui::MouseEvent& event) {
122   if (!event.IsOnlyLeftMouseButton())
123     return false;
124 
125   controller_->ClickOnNotification(notification_id_);
126   return true;
127 }
128 
OnKeyPressed(const ui::KeyEvent & event)129 bool MessageView::OnKeyPressed(const ui::KeyEvent& event) {
130   if (event.flags() != ui::EF_NONE)
131     return false;
132 
133   if (event.key_code() == ui::VKEY_RETURN) {
134     controller_->ClickOnNotification(notification_id_);
135     return true;
136   } else if ((event.key_code() == ui::VKEY_DELETE ||
137               event.key_code() == ui::VKEY_BACK)) {
138     controller_->RemoveNotification(notification_id_, true);  // By user.
139     return true;
140   }
141 
142   return false;
143 }
144 
OnKeyReleased(const ui::KeyEvent & event)145 bool MessageView::OnKeyReleased(const ui::KeyEvent& event) {
146   // Space key handling is triggerred at key-release timing. See
147   // ui/views/controls/buttons/custom_button.cc for why.
148   if (event.flags() != ui::EF_NONE || event.flags() != ui::VKEY_SPACE)
149     return false;
150 
151   controller_->ClickOnNotification(notification_id_);
152   return true;
153 }
154 
OnPaint(gfx::Canvas * canvas)155 void MessageView::OnPaint(gfx::Canvas* canvas) {
156   DCHECK_EQ(this, close_button_->parent());
157   DCHECK_EQ(this, small_image_view_->parent());
158   SlideOutView::OnPaint(canvas);
159   views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
160 }
161 
OnFocus()162 void MessageView::OnFocus() {
163   SlideOutView::OnFocus();
164   // We paint a focus indicator.
165   SchedulePaint();
166 }
167 
OnBlur()168 void MessageView::OnBlur() {
169   SlideOutView::OnBlur();
170   // We paint a focus indicator.
171   SchedulePaint();
172 }
173 
Layout()174 void MessageView::Layout() {
175   gfx::Rect content_bounds = GetContentsBounds();
176 
177   // Background.
178   background_view_->SetBoundsRect(content_bounds);
179 
180   // Close button.
181   gfx::Size close_size(close_button_->GetPreferredSize());
182   gfx::Rect close_rect(content_bounds.right() - close_size.width(),
183                        content_bounds.y(),
184                        close_size.width(),
185                        close_size.height());
186   close_button_->SetBoundsRect(close_rect);
187 
188   gfx::Size small_image_size(small_image_view_->GetPreferredSize());
189   gfx::Rect small_image_rect(small_image_size);
190   small_image_rect.set_origin(gfx::Point(
191       content_bounds.right() - small_image_size.width() - kSmallImagePadding,
192       content_bounds.bottom() - small_image_size.height() -
193           kSmallImagePadding));
194   small_image_view_->SetBoundsRect(small_image_rect);
195 }
196 
OnGestureEvent(ui::GestureEvent * event)197 void MessageView::OnGestureEvent(ui::GestureEvent* event) {
198   if (event->type() == ui::ET_GESTURE_TAP) {
199     controller_->ClickOnNotification(notification_id_);
200     event->SetHandled();
201     return;
202   }
203 
204   SlideOutView::OnGestureEvent(event);
205   // Do not return here by checking handled(). SlideOutView calls SetHandled()
206   // even though the scroll gesture doesn't make no (or little) effects on the
207   // slide-out behavior. See http://crbug.com/172991
208 
209   if (!event->IsScrollGestureEvent() && !event->IsFlingScrollEvent())
210     return;
211 
212   if (scroller_)
213     scroller_->OnGestureEvent(event);
214   event->SetHandled();
215 }
216 
ButtonPressed(views::Button * sender,const ui::Event & event)217 void MessageView::ButtonPressed(views::Button* sender,
218                                 const ui::Event& event) {
219   if (sender == close_button()) {
220     controller_->RemoveNotification(notification_id_, true);  // By user.
221   }
222 }
223 
OnSlideOut()224 void MessageView::OnSlideOut() {
225   controller_->RemoveNotification(notification_id_, true);  // By user.
226 }
227 
228 }  // namespace message_center
229