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/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 
     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 
     83 MessageView::~MessageView() {
     84 }
     85 
     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
     92 gfx::Insets MessageView::GetShadowInsets() {
     93   return gfx::Insets(kShadowBlur / 2 - kShadowOffset,
     94                      kShadowBlur / 2,
     95                      kShadowBlur / 2 + kShadowOffset,
     96                      kShadowBlur / 2);
     97 }
     98 
     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 
    107 bool MessageView::IsCloseButtonFocused() {
    108   views::FocusManager* focus_manager = GetFocusManager();
    109   return focus_manager && focus_manager->GetFocusedView() == close_button();
    110 }
    111 
    112 void MessageView::RequestFocusOnCloseButton() {
    113   close_button_->RequestFocus();
    114 }
    115 
    116 void MessageView::GetAccessibleState(ui::AXViewState* state) {
    117   state->role = ui::AX_ROLE_BUTTON;
    118   state->name = accessible_name_;
    119 }
    120 
    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 
    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 
    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 
    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 
    162 void MessageView::OnFocus() {
    163   SlideOutView::OnFocus();
    164   // We paint a focus indicator.
    165   SchedulePaint();
    166 }
    167 
    168 void MessageView::OnBlur() {
    169   SlideOutView::OnBlur();
    170   // We paint a focus indicator.
    171   SchedulePaint();
    172 }
    173 
    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 
    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 
    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 
    224 void MessageView::OnSlideOut() {
    225   controller_->RemoveNotification(notification_id_, true);  // By user.
    226 }
    227 
    228 }  // namespace message_center
    229