• 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/base/accessibility/accessible_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/message_center_util.h"
18 #include "ui/message_center/views/padded_button.h"
19 #include "ui/views/context_menu_controller.h"
20 #include "ui/views/controls/button/image_button.h"
21 #include "ui/views/controls/menu/menu_runner.h"
22 #include "ui/views/controls/scroll_view.h"
23 #include "ui/views/painter.h"
24 #include "ui/views/shadow_border.h"
25 #include "ui/views/widget/widget.h"
26 
27 namespace {
28 
29 const int kCloseIconTopPadding = 5;
30 const int kCloseIconRightPadding = 5;
31 
32 const int kShadowOffset = 1;
33 const int kShadowBlur = 4;
34 
35 // Menu constants
36 const int kTogglePermissionCommand = 0;
37 const int kShowSettingsCommand = 1;
38 
39 // A dropdown menu for notifications.
40 class MenuModel : public ui::SimpleMenuModel,
41                   public ui::SimpleMenuModel::Delegate {
42  public:
43   MenuModel(message_center::MessageViewController* controller,
44             message_center::NotifierId notifier_id,
45             const string16& display_source);
46   virtual ~MenuModel();
47 
48   // Overridden from ui::SimpleMenuModel::Delegate:
49   virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
50   virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
51   virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
52   virtual bool GetAcceleratorForCommandId(
53       int command_id,
54       ui::Accelerator* accelerator) OVERRIDE;
55   virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
56 
57  private:
58   message_center::MessageViewController* controller_;
59   message_center::NotifierId notifier_id_;
60   DISALLOW_COPY_AND_ASSIGN(MenuModel);
61 };
62 
MenuModel(message_center::MessageViewController * controller,message_center::NotifierId notifier_id,const string16 & display_source)63 MenuModel::MenuModel(message_center::MessageViewController* controller,
64                      message_center::NotifierId notifier_id,
65                      const string16& display_source)
66     : ui::SimpleMenuModel(this),
67       controller_(controller),
68       notifier_id_(notifier_id) {
69   // Add 'disable notifications' menu item.
70   if (!display_source.empty()) {
71     AddItem(kTogglePermissionCommand,
72             l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_NOTIFIER_DISABLE,
73                                        display_source));
74   }
75   // Add settings menu item.
76   AddItem(kShowSettingsCommand,
77           l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS));
78 }
79 
~MenuModel()80 MenuModel::~MenuModel() {
81 }
82 
IsItemForCommandIdDynamic(int command_id) const83 bool MenuModel::IsItemForCommandIdDynamic(int command_id) const {
84   return false;
85 }
86 
IsCommandIdChecked(int command_id) const87 bool MenuModel::IsCommandIdChecked(int command_id) const {
88   return false;
89 }
90 
IsCommandIdEnabled(int command_id) const91 bool MenuModel::IsCommandIdEnabled(int command_id) const {
92   return true;
93 }
94 
GetAcceleratorForCommandId(int command_id,ui::Accelerator * accelerator)95 bool MenuModel::GetAcceleratorForCommandId(int command_id,
96                                            ui::Accelerator* accelerator) {
97   return false;
98 }
99 
ExecuteCommand(int command_id,int event_flags)100 void MenuModel::ExecuteCommand(int command_id, int event_flags) {
101   switch (command_id) {
102     case kTogglePermissionCommand:
103       controller_->DisableNotificationsFromThisSource(notifier_id_);
104       break;
105     case kShowSettingsCommand:
106         controller_->ShowNotifierSettingsBubble();
107       break;
108     default:
109       NOTREACHED();
110   }
111 }
112 
113 }  // namespace
114 
115 namespace message_center {
116 
117 class MessageViewContextMenuController : public views::ContextMenuController {
118  public:
119   MessageViewContextMenuController(MessageViewController* controller,
120                                    const NotifierId& notifier_id,
121                                    const string16& display_source);
122   virtual ~MessageViewContextMenuController();
123 
124  protected:
125   // Overridden from views::ContextMenuController:
126   virtual void ShowContextMenuForView(views::View* source,
127                                       const gfx::Point& point,
128                                       ui::MenuSourceType source_type) OVERRIDE;
129 
130   MessageViewController* controller_;  // Weak, owns us.
131   NotifierId notifier_id_;
132   string16 display_source_;
133 };
134 
MessageViewContextMenuController(MessageViewController * controller,const NotifierId & notifier_id,const string16 & display_source)135 MessageViewContextMenuController::MessageViewContextMenuController(
136     MessageViewController* controller,
137     const NotifierId& notifier_id,
138     const string16& display_source)
139     : controller_(controller),
140       notifier_id_(notifier_id),
141       display_source_(display_source) {
142 }
143 
~MessageViewContextMenuController()144 MessageViewContextMenuController::~MessageViewContextMenuController() {
145 }
146 
ShowContextMenuForView(views::View * source,const gfx::Point & point,ui::MenuSourceType source_type)147 void MessageViewContextMenuController::ShowContextMenuForView(
148     views::View* source,
149     const gfx::Point& point,
150     ui::MenuSourceType source_type) {
151   MenuModel menu_model(controller_, notifier_id_, display_source_);
152   if (menu_model.GetItemCount() == 0)
153     return;
154 
155   views::MenuRunner menu_runner(&menu_model);
156 
157   ignore_result(menu_runner.RunMenuAt(
158       source->GetWidget()->GetTopLevelWidget(),
159       NULL,
160       gfx::Rect(point, gfx::Size()),
161       views::MenuItemView::TOPRIGHT,
162       source_type,
163       views::MenuRunner::HAS_MNEMONICS));
164 }
165 
MessageView(MessageViewController * controller,const std::string & notification_id,const NotifierId & notifier_id,const string16 & display_source)166 MessageView::MessageView(MessageViewController* controller,
167                          const std::string& notification_id,
168                          const NotifierId& notifier_id,
169                          const string16& display_source)
170     : controller_(controller),
171       notification_id_(notification_id),
172       notifier_id_(notifier_id),
173       context_menu_controller_(
174         new MessageViewContextMenuController(controller,
175                                              notifier_id,
176                                              display_source)),
177       scroller_(NULL) {
178   SetFocusable(true);
179   set_context_menu_controller(context_menu_controller_.get());
180 
181   PaddedButton *close = new PaddedButton(this);
182   close->SetPadding(-kCloseIconRightPadding, kCloseIconTopPadding);
183   close->SetNormalImage(IDR_NOTIFICATION_CLOSE);
184   close->SetHoveredImage(IDR_NOTIFICATION_CLOSE_HOVER);
185   close->SetPressedImage(IDR_NOTIFICATION_CLOSE_PRESSED);
186   close->set_owned_by_client();
187   close->set_animate_on_state_change(false);
188   close->SetAccessibleName(l10n_util::GetStringUTF16(
189       IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME));
190   close_button_.reset(close);
191 
192   focus_painter_ = views::Painter::CreateSolidFocusPainter(
193       kFocusBorderColor,
194       gfx::Insets(0, 1, 3, 2)).Pass();
195 }
196 
~MessageView()197 MessageView::~MessageView() {
198 }
199 
200 // static
GetShadowInsets()201 gfx::Insets MessageView::GetShadowInsets() {
202   return gfx::Insets(kShadowBlur / 2 - kShadowOffset,
203                      kShadowBlur / 2,
204                      kShadowBlur / 2 + kShadowOffset,
205                      kShadowBlur / 2);
206 }
207 
CreateShadowBorder()208 void MessageView::CreateShadowBorder() {
209   set_border(new views::ShadowBorder(kShadowBlur,
210                                      message_center::kShadowColor,
211                                      kShadowOffset,  // Vertical offset.
212                                      0));            // Horizontal offset.
213 }
214 
IsCloseButtonFocused()215 bool MessageView::IsCloseButtonFocused() {
216   views::FocusManager* focus_manager = GetFocusManager();
217   return focus_manager && focus_manager->GetFocusedView() == close_button();
218 }
219 
RequestFocusOnCloseButton()220 void MessageView::RequestFocusOnCloseButton() {
221   close_button_->RequestFocus();
222 }
223 
GetAccessibleState(ui::AccessibleViewState * state)224 void MessageView::GetAccessibleState(ui::AccessibleViewState* state) {
225   state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
226   state->name = accessible_name_;
227 }
228 
OnMousePressed(const ui::MouseEvent & event)229 bool MessageView::OnMousePressed(const ui::MouseEvent& event) {
230   if (!event.IsOnlyLeftMouseButton())
231     return false;
232 
233   controller_->ClickOnNotification(notification_id_);
234   return true;
235 }
236 
OnKeyPressed(const ui::KeyEvent & event)237 bool MessageView::OnKeyPressed(const ui::KeyEvent& event) {
238   if (event.flags() != ui::EF_NONE)
239     return false;
240 
241   if (event.key_code() == ui::VKEY_RETURN) {
242     controller_->ClickOnNotification(notification_id_);
243     return true;
244   } else if ((event.key_code() == ui::VKEY_DELETE ||
245               event.key_code() == ui::VKEY_BACK)) {
246     controller_->RemoveNotification(notification_id_, true);  // By user.
247     return true;
248   }
249 
250   return false;
251 }
252 
OnKeyReleased(const ui::KeyEvent & event)253 bool MessageView::OnKeyReleased(const ui::KeyEvent& event) {
254   // Space key handling is triggerred at key-release timing. See
255   // ui/views/controls/buttons/custom_button.cc for why.
256   if (event.flags() != ui::EF_NONE || event.flags() != ui::VKEY_SPACE)
257     return false;
258 
259   controller_->ClickOnNotification(notification_id_);
260   return true;
261 }
262 
OnPaint(gfx::Canvas * canvas)263 void MessageView::OnPaint(gfx::Canvas* canvas) {
264   SlideOutView::OnPaint(canvas);
265   views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
266 }
267 
OnFocus()268 void MessageView::OnFocus() {
269   SlideOutView::OnFocus();
270   // We paint a focus indicator.
271   SchedulePaint();
272 }
273 
OnBlur()274 void MessageView::OnBlur() {
275   SlideOutView::OnBlur();
276   // We paint a focus indicator.
277   SchedulePaint();
278 }
279 
OnGestureEvent(ui::GestureEvent * event)280 void MessageView::OnGestureEvent(ui::GestureEvent* event) {
281   if (event->type() == ui::ET_GESTURE_TAP) {
282     controller_->ClickOnNotification(notification_id_);
283     event->SetHandled();
284     return;
285   }
286 
287   SlideOutView::OnGestureEvent(event);
288   // Do not return here by checking handled(). SlideOutView calls SetHandled()
289   // even though the scroll gesture doesn't make no (or little) effects on the
290   // slide-out behavior. See http://crbug.com/172991
291 
292   if (!event->IsScrollGestureEvent() && !event->IsFlingScrollEvent())
293     return;
294 
295   if (scroller_)
296     scroller_->OnGestureEvent(event);
297   event->SetHandled();
298 }
299 
ButtonPressed(views::Button * sender,const ui::Event & event)300 void MessageView::ButtonPressed(views::Button* sender,
301                                 const ui::Event& event) {
302   if (sender == close_button()) {
303     controller_->RemoveNotification(notification_id_, true);  // By user.
304   }
305 }
306 
OnSlideOut()307 void MessageView::OnSlideOut() {
308   controller_->RemoveNotification(notification_id_, true);  // By user.
309 }
310 
311 }  // namespace message_center
312