Home | History | Annotate | Download | only in views
      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 
     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 
     80 MenuModel::~MenuModel() {
     81 }
     82 
     83 bool MenuModel::IsItemForCommandIdDynamic(int command_id) const {
     84   return false;
     85 }
     86 
     87 bool MenuModel::IsCommandIdChecked(int command_id) const {
     88   return false;
     89 }
     90 
     91 bool MenuModel::IsCommandIdEnabled(int command_id) const {
     92   return true;
     93 }
     94 
     95 bool MenuModel::GetAcceleratorForCommandId(int command_id,
     96                                            ui::Accelerator* accelerator) {
     97   return false;
     98 }
     99 
    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 
    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 
    144 MessageViewContextMenuController::~MessageViewContextMenuController() {
    145 }
    146 
    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 
    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 
    197 MessageView::~MessageView() {
    198 }
    199 
    200 // static
    201 gfx::Insets MessageView::GetShadowInsets() {
    202   return gfx::Insets(kShadowBlur / 2 - kShadowOffset,
    203                      kShadowBlur / 2,
    204                      kShadowBlur / 2 + kShadowOffset,
    205                      kShadowBlur / 2);
    206 }
    207 
    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 
    215 bool MessageView::IsCloseButtonFocused() {
    216   views::FocusManager* focus_manager = GetFocusManager();
    217   return focus_manager && focus_manager->GetFocusedView() == close_button();
    218 }
    219 
    220 void MessageView::RequestFocusOnCloseButton() {
    221   close_button_->RequestFocus();
    222 }
    223 
    224 void MessageView::GetAccessibleState(ui::AccessibleViewState* state) {
    225   state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
    226   state->name = accessible_name_;
    227 }
    228 
    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 
    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 
    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 
    263 void MessageView::OnPaint(gfx::Canvas* canvas) {
    264   SlideOutView::OnPaint(canvas);
    265   views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
    266 }
    267 
    268 void MessageView::OnFocus() {
    269   SlideOutView::OnFocus();
    270   // We paint a focus indicator.
    271   SchedulePaint();
    272 }
    273 
    274 void MessageView::OnBlur() {
    275   SlideOutView::OnBlur();
    276   // We paint a focus indicator.
    277   SchedulePaint();
    278 }
    279 
    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 
    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 
    307 void MessageView::OnSlideOut() {
    308   controller_->RemoveNotification(notification_id_, true);  // By user.
    309 }
    310 
    311 }  // namespace message_center
    312