• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/captcha_view.h"
6 
7 #include "base/string_util.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/chromeos/login/helper.h"
10 #include "chrome/browser/chromeos/login/image_downloader.h"
11 #include "chrome/browser/chromeos/login/rounded_rect_painter.h"
12 #include "chrome/browser/chromeos/login/textfield_with_margin.h"
13 #include "chrome/browser/chromeos/views/copy_background.h"
14 #include "grit/chromium_strings.h"
15 #include "grit/generated_resources.h"
16 #include "grit/locale_settings.h"
17 #include "ui/base/l10n/l10n_util.h"
18 #include "views/background.h"
19 #include "views/controls/button/text_button.h"
20 #include "views/controls/image_view.h"
21 #include "views/controls/label.h"
22 #include "views/controls/textfield/textfield.h"
23 #include "views/layout/grid_layout.h"
24 #include "views/layout/layout_constants.h"
25 #include "views/widget/widget_gtk.h"
26 #include "views/window/window.h"
27 
28 using views::Label;
29 using views::Textfield;
30 using views::WidgetGtk;
31 
32 namespace chromeos {
33 
34 namespace {
35 
36 // A Textfield for captcha input, which also sets focus to itself
37 // when a mouse is clicked on it. This is necessary in screen locker mode
38 // as mouse events are grabbed in the screen locker.
39 class CaptchaField : public TextfieldWithMargin {
40  public:
CaptchaField()41   CaptchaField()
42       : TextfieldWithMargin() {
43   }
44 
45   // views::View overrides.
OnMousePressed(const views::MouseEvent & e)46   virtual bool OnMousePressed(const views::MouseEvent& e) {
47     RequestFocus();
48     return false;
49   }
50 
51  private:
52   DISALLOW_COPY_AND_ASSIGN(CaptchaField);
53 };
54 
55 class WideTextButton : public views::TextButton {
56  public:
WideTextButton(views::ButtonListener * listener,const std::wstring & text)57   WideTextButton(views::ButtonListener* listener, const std::wstring& text)
58       : TextButton(listener, text) {
59     SetFont(font().DeriveFont(kFontSizeCorrectionDelta));
60   }
61 
~WideTextButton()62   virtual ~WideTextButton() {}
63 
64  private:
GetPreferredSize()65   virtual gfx::Size GetPreferredSize() {
66     gfx::Size preferred_size = TextButton::GetPreferredSize();
67     // Set minimal width.
68     if (preferred_size.width() < login::kButtonMinWidth)
69       preferred_size.set_width(login::kButtonMinWidth);
70     return preferred_size;
71   }
72 
73   DISALLOW_COPY_AND_ASSIGN(WideTextButton);
74 };
75 
76 }  // namespace
77 
CaptchaView(const GURL & captcha_url,bool is_standalone)78 CaptchaView::CaptchaView(const GURL& captcha_url, bool is_standalone)
79     : delegate_(NULL),
80       captcha_url_(captcha_url),
81       captcha_image_(NULL),
82       captcha_textfield_(NULL),
83       is_standalone_(is_standalone),
84       ok_button_(NULL) {
85 }
86 
Accept()87 bool CaptchaView::Accept() {
88   if (delegate_)
89     delegate_->OnCaptchaEntered(UTF16ToUTF8(captcha_textfield_->text()));
90   return true;
91 }
92 
GetWindowTitle() const93 std::wstring CaptchaView::GetWindowTitle() const {
94   return UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOGIN_CAPTCHA_DIALOG_TITLE));
95 }
96 
SetCaptchaURL(const GURL & captcha_url)97 void CaptchaView::SetCaptchaURL(const GURL& captcha_url) {
98   captcha_url_ = captcha_url;
99   captcha_textfield_->SetText(string16());
100   // ImageDownloader will delete itself once URL is fetched.
101   // TODO(nkostylev): Make sure that it works after view is deleted.
102   new ImageDownloader(this, GURL(captcha_url_), std::string());
103 }
104 
GetPreferredSize()105 gfx::Size CaptchaView::GetPreferredSize() {
106   gfx::Size size = gfx::Size(views::Window::GetLocalizedContentsSize(
107       IDS_CAPTCHA_INPUT_DIALOG_WIDTH_CHARS,
108       IDS_CAPTCHA_INPUT_DIALOG_HEIGHT_LINES));
109   if (is_standalone_)
110     size.set_height(size.height() + ok_button_->GetPreferredSize().height());
111 
112   return size;
113 }
114 
ViewHierarchyChanged(bool is_add,views::View * parent,views::View * child)115 void CaptchaView::ViewHierarchyChanged(bool is_add,
116                                        views::View* parent,
117                                        views::View* child) {
118   // Can't focus before we're inserted into a Container.
119   if (is_add && child == this)
120     captcha_textfield_->RequestFocus();
121 }
122 
HandleKeyEvent(views::Textfield * sender,const views::KeyEvent & key_event)123 bool CaptchaView::HandleKeyEvent(views::Textfield* sender,
124                                  const views::KeyEvent& key_event) {
125   if (sender == captcha_textfield_ &&
126       key_event.key_code() == ui::VKEY_RETURN) {
127     if (is_standalone_) {
128       Accept();
129     } else {
130       GetDialogClientView()->AcceptWindow();
131     }
132   }
133   return false;
134 }
135 
OnImageDecoded(const ImageDecoder *,const SkBitmap & decoded_image)136 void CaptchaView::OnImageDecoded(const ImageDecoder*,
137                                  const SkBitmap& decoded_image) {
138   captcha_image_->SetImage(decoded_image);
139   captcha_textfield_->RequestFocus();
140   Layout();
141 }
142 
ButtonPressed(views::Button * sender,const views::Event & event)143 void CaptchaView::ButtonPressed(views::Button* sender,
144                                 const views::Event& event) {
145   DCHECK(sender == ok_button_);
146   Accept();
147 }
148 
Init()149 void CaptchaView::Init() {
150   if (is_standalone_) {
151     // Use rounded rect background.
152     set_border(CreateWizardBorder(&BorderDefinition::kUserBorder));
153     views::Painter* painter = CreateWizardPainter(
154         &BorderDefinition::kUserBorder);
155     set_background(views::Background::CreateBackgroundPainter(true, painter));
156   }
157 
158   views::GridLayout* layout = views::GridLayout::CreatePanel(this);
159   SetLayoutManager(layout);
160 
161   int column_view_set_id = 0;
162   views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id);
163   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
164                         views::GridLayout::USE_PREF, 0, 0);
165   layout->StartRow(0, column_view_set_id);
166   Label* label = new views::Label(
167       UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOGIN_CAPTCHA_INSTRUCTIONS)));
168   label->SetMultiLine(true);
169   layout->AddView(label);
170   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
171 
172   layout->StartRow(0, column_view_set_id);
173   captcha_image_ = new views::ImageView();
174   layout->AddView(captcha_image_);
175   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
176 
177   layout->StartRow(0, column_view_set_id);
178   captcha_textfield_ = new CaptchaField();
179   captcha_textfield_->SetController(this);
180   if (is_standalone_)
181     captcha_textfield_->set_background(new CopyBackground(this));
182   layout->AddView(captcha_textfield_);
183   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
184 
185   layout->StartRow(0, column_view_set_id);
186   label = new views::Label(UTF16ToWide(
187       l10n_util::GetStringUTF16(IDS_SYNC_GAIA_CAPTCHA_CASE_INSENSITIVE_TIP)));
188   label->SetMultiLine(true);
189   layout->AddView(label);
190   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
191 
192   if (is_standalone_) {
193     layout->StartRow(0, column_view_set_id);
194     ok_button_ = new WideTextButton(
195         this, UTF16ToWide(l10n_util::GetStringUTF16(IDS_OK)));
196     ok_button_->set_alignment(views::TextButton::ALIGN_CENTER);
197     ok_button_->SetFocusable(true);
198     ok_button_->SetNormalHasBorder(true);
199     ok_button_->set_animate_on_state_change(false);
200     ok_button_->SetEnabledColor(SK_ColorBLACK);
201     ok_button_->SetHighlightColor(SK_ColorBLACK);
202     ok_button_->SetHoverColor(SK_ColorBLACK);
203     layout->AddView(ok_button_, 1, 1,
204                     views::GridLayout::CENTER, views::GridLayout::CENTER);
205   }
206 
207   // ImageDownloader will delete itself once URL is fetched.
208   // TODO(nkostylev): Make sure that it works after view is deleted.
209   new ImageDownloader(this, GURL(captcha_url_), std::string());
210 }
211 
212 }  // namespace chromeos
213