// 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/captcha_view.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/chromeos/login/helper.h" #include "chrome/browser/chromeos/login/image_downloader.h" #include "chrome/browser/chromeos/login/rounded_rect_painter.h" #include "chrome/browser/chromeos/login/textfield_with_margin.h" #include "chrome/browser/chromeos/views/copy_background.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" #include "ui/base/l10n/l10n_util.h" #include "views/background.h" #include "views/controls/button/text_button.h" #include "views/controls/image_view.h" #include "views/controls/label.h" #include "views/controls/textfield/textfield.h" #include "views/layout/grid_layout.h" #include "views/layout/layout_constants.h" #include "views/widget/widget_gtk.h" #include "views/window/window.h" using views::Label; using views::Textfield; using views::WidgetGtk; namespace chromeos { namespace { // A Textfield for captcha input, which also sets focus to itself // when a mouse is clicked on it. This is necessary in screen locker mode // as mouse events are grabbed in the screen locker. class CaptchaField : public TextfieldWithMargin { public: CaptchaField() : TextfieldWithMargin() { } // views::View overrides. virtual bool OnMousePressed(const views::MouseEvent& e) { RequestFocus(); return false; } private: DISALLOW_COPY_AND_ASSIGN(CaptchaField); }; class WideTextButton : public views::TextButton { public: WideTextButton(views::ButtonListener* listener, const std::wstring& text) : TextButton(listener, text) { SetFont(font().DeriveFont(kFontSizeCorrectionDelta)); } virtual ~WideTextButton() {} private: virtual gfx::Size GetPreferredSize() { gfx::Size preferred_size = TextButton::GetPreferredSize(); // Set minimal width. if (preferred_size.width() < login::kButtonMinWidth) preferred_size.set_width(login::kButtonMinWidth); return preferred_size; } DISALLOW_COPY_AND_ASSIGN(WideTextButton); }; } // namespace CaptchaView::CaptchaView(const GURL& captcha_url, bool is_standalone) : delegate_(NULL), captcha_url_(captcha_url), captcha_image_(NULL), captcha_textfield_(NULL), is_standalone_(is_standalone), ok_button_(NULL) { } bool CaptchaView::Accept() { if (delegate_) delegate_->OnCaptchaEntered(UTF16ToUTF8(captcha_textfield_->text())); return true; } std::wstring CaptchaView::GetWindowTitle() const { return UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOGIN_CAPTCHA_DIALOG_TITLE)); } void CaptchaView::SetCaptchaURL(const GURL& captcha_url) { captcha_url_ = captcha_url; captcha_textfield_->SetText(string16()); // ImageDownloader will delete itself once URL is fetched. // TODO(nkostylev): Make sure that it works after view is deleted. new ImageDownloader(this, GURL(captcha_url_), std::string()); } gfx::Size CaptchaView::GetPreferredSize() { gfx::Size size = gfx::Size(views::Window::GetLocalizedContentsSize( IDS_CAPTCHA_INPUT_DIALOG_WIDTH_CHARS, IDS_CAPTCHA_INPUT_DIALOG_HEIGHT_LINES)); if (is_standalone_) size.set_height(size.height() + ok_button_->GetPreferredSize().height()); return size; } void CaptchaView::ViewHierarchyChanged(bool is_add, views::View* parent, views::View* child) { // Can't focus before we're inserted into a Container. if (is_add && child == this) captcha_textfield_->RequestFocus(); } bool CaptchaView::HandleKeyEvent(views::Textfield* sender, const views::KeyEvent& key_event) { if (sender == captcha_textfield_ && key_event.key_code() == ui::VKEY_RETURN) { if (is_standalone_) { Accept(); } else { GetDialogClientView()->AcceptWindow(); } } return false; } void CaptchaView::OnImageDecoded(const ImageDecoder*, const SkBitmap& decoded_image) { captcha_image_->SetImage(decoded_image); captcha_textfield_->RequestFocus(); Layout(); } void CaptchaView::ButtonPressed(views::Button* sender, const views::Event& event) { DCHECK(sender == ok_button_); Accept(); } void CaptchaView::Init() { if (is_standalone_) { // Use rounded rect background. set_border(CreateWizardBorder(&BorderDefinition::kUserBorder)); views::Painter* painter = CreateWizardPainter( &BorderDefinition::kUserBorder); set_background(views::Background::CreateBackgroundPainter(true, painter)); } views::GridLayout* layout = views::GridLayout::CreatePanel(this); SetLayoutManager(layout); int column_view_set_id = 0; views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id); column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, views::GridLayout::USE_PREF, 0, 0); layout->StartRow(0, column_view_set_id); Label* label = new views::Label( UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOGIN_CAPTCHA_INSTRUCTIONS))); label->SetMultiLine(true); layout->AddView(label); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(0, column_view_set_id); captcha_image_ = new views::ImageView(); layout->AddView(captcha_image_); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(0, column_view_set_id); captcha_textfield_ = new CaptchaField(); captcha_textfield_->SetController(this); if (is_standalone_) captcha_textfield_->set_background(new CopyBackground(this)); layout->AddView(captcha_textfield_); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(0, column_view_set_id); label = new views::Label(UTF16ToWide( l10n_util::GetStringUTF16(IDS_SYNC_GAIA_CAPTCHA_CASE_INSENSITIVE_TIP))); label->SetMultiLine(true); layout->AddView(label); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); if (is_standalone_) { layout->StartRow(0, column_view_set_id); ok_button_ = new WideTextButton( this, UTF16ToWide(l10n_util::GetStringUTF16(IDS_OK))); ok_button_->set_alignment(views::TextButton::ALIGN_CENTER); ok_button_->SetFocusable(true); ok_button_->SetNormalHasBorder(true); ok_button_->set_animate_on_state_change(false); ok_button_->SetEnabledColor(SK_ColorBLACK); ok_button_->SetHighlightColor(SK_ColorBLACK); ok_button_->SetHoverColor(SK_ColorBLACK); layout->AddView(ok_button_, 1, 1, views::GridLayout::CENTER, views::GridLayout::CENTER); } // ImageDownloader will delete itself once URL is fetched. // TODO(nkostylev): Make sure that it works after view is deleted. new ImageDownloader(this, GURL(captcha_url_), std::string()); } } // namespace chromeos