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