Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2011 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/chromeos/login/screen_lock_view.h"
      6 
      7 #include "base/utf_string_conversions.h"
      8 #include "chrome/browser/chromeos/login/rounded_rect_painter.h"
      9 #include "chrome/browser/chromeos/login/screen_locker.h"
     10 #include "chrome/browser/chromeos/login/textfield_with_margin.h"
     11 #include "chrome/browser/chromeos/login/user_manager.h"
     12 #include "chrome/browser/chromeos/login/user_view.h"
     13 #include "chrome/browser/chromeos/login/username_view.h"
     14 #include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
     15 #include "chrome/browser/chromeos/views/copy_background.h"
     16 #include "chrome/browser/profiles/profile_manager.h"
     17 #include "content/common/notification_service.h"
     18 #include "grit/generated_resources.h"
     19 #include "grit/theme_resources.h"
     20 #include "ui/base/l10n/l10n_util.h"
     21 #include "ui/base/resource/resource_bundle.h"
     22 #include "views/background.h"
     23 #include "views/border.h"
     24 #include "views/controls/image_view.h"
     25 #include "views/controls/label.h"
     26 #include "views/controls/textfield/native_textfield_wrapper.h"
     27 #include "views/controls/textfield/textfield.h"
     28 #include "views/layout/grid_layout.h"
     29 
     30 namespace chromeos {
     31 
     32 namespace {
     33 
     34 const int kCornerRadius = 5;
     35 
     36 // A Textfield for password, which also sets focus to itself
     37 // when a mouse is clicked on it. This is necessary in screen locker
     38 // as mouse events are grabbed in the screen locker.
     39 class PasswordField : public TextfieldWithMargin {
     40  public:
     41   PasswordField()
     42       : TextfieldWithMargin(views::Textfield::STYLE_PASSWORD),
     43         context_menu_disabled_(false) {
     44     set_text_to_display_when_empty(
     45         l10n_util::GetStringUTF16(IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT));
     46   }
     47 
     48   // views::View overrides.
     49   virtual bool OnMousePressed(const views::MouseEvent& e) {
     50     RequestFocus();
     51     return false;
     52   }
     53 
     54   virtual void ViewHierarchyChanged(bool is_add,
     55                                     views::View* parent,
     56                                     views::View* child) OVERRIDE {
     57     Textfield::ViewHierarchyChanged(is_add, parent, child);
     58     // Wiat until native widget is created.
     59     if (!context_menu_disabled_ && native_wrapper_) {
     60       gfx::NativeView widget = native_wrapper_->GetTestingHandle();
     61       if (widget) {
     62         context_menu_disabled_ = true;
     63         g_signal_connect(widget, "button-press-event",
     64                          G_CALLBACK(OnButtonPressEventThunk), this);
     65       }
     66     }
     67   }
     68 
     69   CHROMEGTK_CALLBACK_1(PasswordField, gboolean, OnButtonPressEvent,
     70                        GdkEventButton*);
     71 
     72  private:
     73   bool context_menu_disabled_;
     74 
     75   DISALLOW_COPY_AND_ASSIGN(PasswordField);
     76 };
     77 
     78 gboolean PasswordField::OnButtonPressEvent(GtkWidget* widget,
     79                                            GdkEventButton* event) {
     80   // Eat button 2/3 and alt + any button to disable context menu.
     81   return event->state & GDK_MOD1_MASK ||
     82       event->button == 2 ||
     83       event->button == 3;
     84 }
     85 
     86 }  // namespace
     87 
     88 using views::GridLayout;
     89 using login::kBorderSize;
     90 
     91 ScreenLockView::ScreenLockView(ScreenLocker* screen_locker)
     92     : user_view_(NULL),
     93       password_field_(NULL),
     94       screen_locker_(screen_locker),
     95       main_(NULL),
     96       username_(NULL) {
     97   DCHECK(screen_locker_);
     98 }
     99 
    100 ScreenLockView::~ScreenLockView() {
    101 }
    102 
    103 gfx::Size ScreenLockView::GetPreferredSize() {
    104   return main_->GetPreferredSize();
    105 }
    106 
    107 void ScreenLockView::Layout() {
    108   int username_height = login::kSelectedLabelHeight;
    109   main_->SetBounds(0, 0, width(), height());
    110   username_->SetBounds(
    111       kBorderSize,
    112       login::kUserImageSize - username_height + kBorderSize,
    113       login::kUserImageSize,
    114       username_height);
    115 }
    116 
    117 void ScreenLockView::Init() {
    118   registrar_.Add(this,
    119                  NotificationType::LOGIN_USER_IMAGE_CHANGED,
    120                  NotificationService::AllSources());
    121 
    122   user_view_ = new UserView(this,
    123                             false,  // is_login
    124                             true);  // need_background
    125   main_ = new views::View();
    126   // Use rounded rect background.
    127   views::Painter* painter =
    128       CreateWizardPainter(&BorderDefinition::kUserBorder);
    129 
    130   main_->set_background(
    131       views::Background::CreateBackgroundPainter(true, painter));
    132   main_->set_border(CreateWizardBorder(&BorderDefinition::kUserBorder));
    133 
    134   // Password field.
    135   password_field_ = new PasswordField();
    136 
    137   password_field_->SetController(this);
    138   password_field_->set_background(new CopyBackground(main_));
    139 
    140   // Setup ThrobberView's host view.
    141   set_host_view(password_field_);
    142 
    143   // User icon.
    144   UserManager::User user = screen_locker_->user();
    145   user_view_->SetImage(user.image(), user.image());
    146 
    147   // User name.
    148   std::wstring text = UTF8ToWide(user.GetDisplayName());
    149 
    150   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    151   const gfx::Font& font = rb.GetFont(ResourceBundle::MediumBoldFont).DeriveFont(
    152       kSelectedUsernameFontDelta);
    153 
    154   // Layouts image, textfield and button components.
    155   GridLayout* layout = new GridLayout(main_);
    156   main_->SetLayoutManager(layout);
    157   views::ColumnSet* column_set = layout->AddColumnSet(0);
    158   column_set->AddPaddingColumn(0, kBorderSize);
    159   column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
    160                         GridLayout::USE_PREF, 0, 0);
    161   column_set->AddPaddingColumn(0, kBorderSize);
    162 
    163   column_set = layout->AddColumnSet(1);
    164   column_set->AddPaddingColumn(0, kBorderSize);
    165   column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
    166                         GridLayout::USE_PREF, 0, 0);
    167   column_set->AddPaddingColumn(0, kBorderSize);
    168 
    169   layout->AddPaddingRow(0, kBorderSize);
    170   layout->StartRow(0, 0);
    171   layout->AddView(user_view_);
    172   layout->AddPaddingRow(0, kBorderSize);
    173   layout->StartRow(0, 1);
    174   layout->AddView(password_field_);
    175   layout->AddPaddingRow(0, kBorderSize);
    176 
    177   AddChildView(main_);
    178 
    179   UsernameView* username = UsernameView::CreateShapedUsernameView(text, false);
    180   username_ = username;
    181   username->SetColor(login::kTextColor);
    182   username->SetFont(font);
    183   AddChildView(username);
    184 }
    185 
    186 void ScreenLockView::ClearAndSetFocusToPassword() {
    187   password_field_->RequestFocus();
    188   password_field_->SetText(string16());
    189 }
    190 
    191 void ScreenLockView::SetSignoutEnabled(bool enabled) {
    192   user_view_->SetSignoutEnabled(enabled);
    193 }
    194 
    195 gfx::Rect ScreenLockView::GetPasswordBoundsRelativeTo(const views::View* view) {
    196   gfx::Point p;
    197   views::View::ConvertPointToView(password_field_, view, &p);
    198   return gfx::Rect(p, size());
    199 }
    200 
    201 
    202 void ScreenLockView::SetEnabled(bool enabled) {
    203   views::View::SetEnabled(enabled);
    204 
    205   if (!enabled) {
    206     // TODO(oshima): Re-enabling does not move the focus to the view
    207     // that had a focus (issue http://crbug.com/43131).
    208     // Clear focus on the textfield so that re-enabling can set focus
    209     // back to the text field.
    210     // FocusManager may be null if the view does not have
    211     // associated Widget yet.
    212     if (password_field_->GetFocusManager())
    213       password_field_->GetFocusManager()->ClearFocus();
    214   }
    215   password_field_->SetEnabled(enabled);
    216 }
    217 
    218 void ScreenLockView::OnSignout() {
    219   screen_locker_->Signout();
    220 }
    221 
    222 void ScreenLockView::ContentsChanged(views::Textfield* sender,
    223                                      const string16& new_contents) {
    224   if (!new_contents.empty())
    225     screen_locker_->ClearErrors();
    226 }
    227 
    228 bool ScreenLockView::HandleKeyEvent(
    229     views::Textfield* sender,
    230     const views::KeyEvent& key_event) {
    231   screen_locker_->ClearErrors();
    232   if (key_event.key_code() == ui::VKEY_RETURN) {
    233     screen_locker_->Authenticate(password_field_->text());
    234     return true;
    235   }
    236   return false;
    237 }
    238 
    239 void ScreenLockView::Observe(
    240     NotificationType type,
    241     const NotificationSource& source,
    242     const NotificationDetails& details) {
    243   if (type != NotificationType::LOGIN_USER_IMAGE_CHANGED || !user_view_)
    244     return;
    245 
    246   UserManager::User* user = Details<UserManager::User>(details).ptr();
    247   if (screen_locker_->user().email() != user->email())
    248     return;
    249   user_view_->SetImage(user->image(), user->image());
    250 }
    251 
    252 }  // namespace chromeos
    253