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/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:
     41   CaptchaField()
     42       : TextfieldWithMargin() {
     43   }
     44 
     45   // views::View overrides.
     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:
     57   WideTextButton(views::ButtonListener* listener, const std::wstring& text)
     58       : TextButton(listener, text) {
     59     SetFont(font().DeriveFont(kFontSizeCorrectionDelta));
     60   }
     61 
     62   virtual ~WideTextButton() {}
     63 
     64  private:
     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 
     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 
     87 bool CaptchaView::Accept() {
     88   if (delegate_)
     89     delegate_->OnCaptchaEntered(UTF16ToUTF8(captcha_textfield_->text()));
     90   return true;
     91 }
     92 
     93 std::wstring CaptchaView::GetWindowTitle() const {
     94   return UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOGIN_CAPTCHA_DIALOG_TITLE));
     95 }
     96 
     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 
    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 
    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 
    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 
    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 
    143 void CaptchaView::ButtonPressed(views::Button* sender,
    144                                 const views::Event& event) {
    145   DCHECK(sender == ok_button_);
    146   Accept();
    147 }
    148 
    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