普通文本  |  253行  |  7.91 KB

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/screen_lock_view.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/textfield_with_margin.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/user_view.h"
#include "chrome/browser/chromeos/login/username_view.h"
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
#include "chrome/browser/chromeos/views/copy_background.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "content/common/notification_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "views/background.h"
#include "views/border.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/controls/textfield/native_textfield_wrapper.h"
#include "views/controls/textfield/textfield.h"
#include "views/layout/grid_layout.h"

namespace chromeos {

namespace {

const int kCornerRadius = 5;

// A Textfield for password, which also sets focus to itself
// when a mouse is clicked on it. This is necessary in screen locker
// as mouse events are grabbed in the screen locker.
class PasswordField : public TextfieldWithMargin {
 public:
  PasswordField()
      : TextfieldWithMargin(views::Textfield::STYLE_PASSWORD),
        context_menu_disabled_(false) {
    set_text_to_display_when_empty(
        l10n_util::GetStringUTF16(IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT));
  }

  // views::View overrides.
  virtual bool OnMousePressed(const views::MouseEvent& e) {
    RequestFocus();
    return false;
  }

  virtual void ViewHierarchyChanged(bool is_add,
                                    views::View* parent,
                                    views::View* child) OVERRIDE {
    Textfield::ViewHierarchyChanged(is_add, parent, child);
    // Wiat until native widget is created.
    if (!context_menu_disabled_ && native_wrapper_) {
      gfx::NativeView widget = native_wrapper_->GetTestingHandle();
      if (widget) {
        context_menu_disabled_ = true;
        g_signal_connect(widget, "button-press-event",
                         G_CALLBACK(OnButtonPressEventThunk), this);
      }
    }
  }

  CHROMEGTK_CALLBACK_1(PasswordField, gboolean, OnButtonPressEvent,
                       GdkEventButton*);

 private:
  bool context_menu_disabled_;

  DISALLOW_COPY_AND_ASSIGN(PasswordField);
};

gboolean PasswordField::OnButtonPressEvent(GtkWidget* widget,
                                           GdkEventButton* event) {
  // Eat button 2/3 and alt + any button to disable context menu.
  return event->state & GDK_MOD1_MASK ||
      event->button == 2 ||
      event->button == 3;
}

}  // namespace

using views::GridLayout;
using login::kBorderSize;

ScreenLockView::ScreenLockView(ScreenLocker* screen_locker)
    : user_view_(NULL),
      password_field_(NULL),
      screen_locker_(screen_locker),
      main_(NULL),
      username_(NULL) {
  DCHECK(screen_locker_);
}

ScreenLockView::~ScreenLockView() {
}

gfx::Size ScreenLockView::GetPreferredSize() {
  return main_->GetPreferredSize();
}

void ScreenLockView::Layout() {
  int username_height = login::kSelectedLabelHeight;
  main_->SetBounds(0, 0, width(), height());
  username_->SetBounds(
      kBorderSize,
      login::kUserImageSize - username_height + kBorderSize,
      login::kUserImageSize,
      username_height);
}

void ScreenLockView::Init() {
  registrar_.Add(this,
                 NotificationType::LOGIN_USER_IMAGE_CHANGED,
                 NotificationService::AllSources());

  user_view_ = new UserView(this,
                            false,  // is_login
                            true);  // need_background
  main_ = new views::View();
  // Use rounded rect background.
  views::Painter* painter =
      CreateWizardPainter(&BorderDefinition::kUserBorder);

  main_->set_background(
      views::Background::CreateBackgroundPainter(true, painter));
  main_->set_border(CreateWizardBorder(&BorderDefinition::kUserBorder));

  // Password field.
  password_field_ = new PasswordField();

  password_field_->SetController(this);
  password_field_->set_background(new CopyBackground(main_));

  // Setup ThrobberView's host view.
  set_host_view(password_field_);

  // User icon.
  UserManager::User user = screen_locker_->user();
  user_view_->SetImage(user.image(), user.image());

  // User name.
  std::wstring text = UTF8ToWide(user.GetDisplayName());

  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  const gfx::Font& font = rb.GetFont(ResourceBundle::MediumBoldFont).DeriveFont(
      kSelectedUsernameFontDelta);

  // Layouts image, textfield and button components.
  GridLayout* layout = new GridLayout(main_);
  main_->SetLayoutManager(layout);
  views::ColumnSet* column_set = layout->AddColumnSet(0);
  column_set->AddPaddingColumn(0, kBorderSize);
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kBorderSize);

  column_set = layout->AddColumnSet(1);
  column_set->AddPaddingColumn(0, kBorderSize);
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kBorderSize);

  layout->AddPaddingRow(0, kBorderSize);
  layout->StartRow(0, 0);
  layout->AddView(user_view_);
  layout->AddPaddingRow(0, kBorderSize);
  layout->StartRow(0, 1);
  layout->AddView(password_field_);
  layout->AddPaddingRow(0, kBorderSize);

  AddChildView(main_);

  UsernameView* username = UsernameView::CreateShapedUsernameView(text, false);
  username_ = username;
  username->SetColor(login::kTextColor);
  username->SetFont(font);
  AddChildView(username);
}

void ScreenLockView::ClearAndSetFocusToPassword() {
  password_field_->RequestFocus();
  password_field_->SetText(string16());
}

void ScreenLockView::SetSignoutEnabled(bool enabled) {
  user_view_->SetSignoutEnabled(enabled);
}

gfx::Rect ScreenLockView::GetPasswordBoundsRelativeTo(const views::View* view) {
  gfx::Point p;
  views::View::ConvertPointToView(password_field_, view, &p);
  return gfx::Rect(p, size());
}


void ScreenLockView::SetEnabled(bool enabled) {
  views::View::SetEnabled(enabled);

  if (!enabled) {
    // TODO(oshima): Re-enabling does not move the focus to the view
    // that had a focus (issue http://crbug.com/43131).
    // Clear focus on the textfield so that re-enabling can set focus
    // back to the text field.
    // FocusManager may be null if the view does not have
    // associated Widget yet.
    if (password_field_->GetFocusManager())
      password_field_->GetFocusManager()->ClearFocus();
  }
  password_field_->SetEnabled(enabled);
}

void ScreenLockView::OnSignout() {
  screen_locker_->Signout();
}

void ScreenLockView::ContentsChanged(views::Textfield* sender,
                                     const string16& new_contents) {
  if (!new_contents.empty())
    screen_locker_->ClearErrors();
}

bool ScreenLockView::HandleKeyEvent(
    views::Textfield* sender,
    const views::KeyEvent& key_event) {
  screen_locker_->ClearErrors();
  if (key_event.key_code() == ui::VKEY_RETURN) {
    screen_locker_->Authenticate(password_field_->text());
    return true;
  }
  return false;
}

void ScreenLockView::Observe(
    NotificationType type,
    const NotificationSource& source,
    const NotificationDetails& details) {
  if (type != NotificationType::LOGIN_USER_IMAGE_CHANGED || !user_view_)
    return;

  UserManager::User* user = Details<UserManager::User>(details).ptr();
  if (screen_locker_->user().email() != user->email())
    return;
  user_view_->SetImage(user->image(), user->image());
}

}  // namespace chromeos