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:
PasswordField()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.
OnMousePressed(const views::MouseEvent & e)49 virtual bool OnMousePressed(const views::MouseEvent& e) {
50 RequestFocus();
51 return false;
52 }
53
ViewHierarchyChanged(bool is_add,views::View * parent,views::View * child)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
OnButtonPressEvent(GtkWidget * widget,GdkEventButton * event)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
ScreenLockView(ScreenLocker * screen_locker)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
~ScreenLockView()100 ScreenLockView::~ScreenLockView() {
101 }
102
GetPreferredSize()103 gfx::Size ScreenLockView::GetPreferredSize() {
104 return main_->GetPreferredSize();
105 }
106
Layout()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
Init()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
ClearAndSetFocusToPassword()186 void ScreenLockView::ClearAndSetFocusToPassword() {
187 password_field_->RequestFocus();
188 password_field_->SetText(string16());
189 }
190
SetSignoutEnabled(bool enabled)191 void ScreenLockView::SetSignoutEnabled(bool enabled) {
192 user_view_->SetSignoutEnabled(enabled);
193 }
194
GetPasswordBoundsRelativeTo(const views::View * view)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
SetEnabled(bool enabled)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
OnSignout()218 void ScreenLockView::OnSignout() {
219 screen_locker_->Signout();
220 }
221
ContentsChanged(views::Textfield * sender,const string16 & new_contents)222 void ScreenLockView::ContentsChanged(views::Textfield* sender,
223 const string16& new_contents) {
224 if (!new_contents.empty())
225 screen_locker_->ClearErrors();
226 }
227
HandleKeyEvent(views::Textfield * sender,const views::KeyEvent & key_event)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
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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