| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/password_generation_bubble_view.h" | 5 #include "chrome/browser/ui/views/password_generation_bubble_view.h" |
| 6 | 6 |
| 7 #include "base/utf_string_conversions.h" | 7 #include "base/utf_string_conversions.h" |
| 8 #include "chrome/browser/autofill/password_generator.h" | 8 #include "chrome/browser/autofill/password_generator.h" |
| 9 #include "chrome/browser/password_manager/password_manager.h" | 9 #include "chrome/browser/password_manager/password_manager.h" |
| 10 #include "chrome/browser/ui/browser.h" | 10 #include "chrome/browser/ui/browser.h" |
| 11 #include "chrome/browser/ui/browser_list.h" | 11 #include "chrome/browser/ui/browser_list.h" |
| 12 #include "chrome/common/autofill_messages.h" | 12 #include "chrome/common/autofill_messages.h" |
| 13 #include "chrome/common/url_constants.h" | 13 #include "chrome/common/url_constants.h" |
| 14 #include "content/public/browser/page_navigator.h" | 14 #include "content/public/browser/page_navigator.h" |
| 15 #include "content/public/browser/render_view_host.h" | 15 #include "content/public/browser/render_view_host.h" |
| 16 #include "googleurl/src/gurl.h" | 16 #include "googleurl/src/gurl.h" |
| 17 #include "grit/generated_resources.h" | 17 #include "grit/generated_resources.h" |
| 18 #include "grit/theme_resources.h" |
| 19 #include "third_party/skia/include/core/SkPaint.h" |
| 18 #include "ui/base/l10n/l10n_util.h" | 20 #include "ui/base/l10n/l10n_util.h" |
| 21 #include "ui/base/resource/resource_bundle.h" |
| 22 #include "ui/base/theme_provider.h" |
| 23 #include "ui/gfx/canvas.h" |
| 24 #include "ui/views/border.h" |
| 25 #include "ui/views/controls/button/image_button.h" |
| 19 #include "ui/views/controls/button/text_button.h" | 26 #include "ui/views/controls/button/text_button.h" |
| 20 #include "ui/views/controls/label.h" | 27 #include "ui/views/controls/label.h" |
| 21 #include "ui/views/controls/link.h" | 28 #include "ui/views/controls/link.h" |
| 22 #include "ui/views/controls/textfield/textfield.h" | 29 #include "ui/views/controls/textfield/textfield.h" |
| 23 #include "ui/views/layout/grid_layout.h" | |
| 24 #include "ui/views/layout/layout_constants.h" | 30 #include "ui/views/layout/layout_constants.h" |
| 25 | 31 |
| 26 using views::ColumnSet; | 32 namespace { |
| 27 using views::GridLayout; | 33 // Constants for PasswordGenerationBubbleView. |
| 34 const int kBubbleMargin = 9; |
| 35 const int kButtonHorizontalSpacing = 4; |
| 36 const int kButtonWidth = 65; |
| 37 const int kDefaultTextFieldChars = 18; |
| 38 const int kTitleLabelVerticalOffset = -3; |
| 39 const int kVerticalPadding = 8; |
| 40 |
| 41 // Constants for Text fieldWrapper. |
| 42 const int kTextfieldHorizontalPadding = 2; |
| 43 const int kTextfieldVerticalPadding = 3; |
| 44 const int kWrapperBorderSize = 1; |
| 45 |
| 46 // This class handles layout so that it looks like a Textfield and ImageButton |
| 47 // are part of one logical textfield with the button on the right side of the |
| 48 // field. It also assumes that the textfield is already sized appropriately |
| 49 // and will alter the image size to fit. |
| 50 class TextfieldWrapper : public views::View { |
| 51 public: |
| 52 TextfieldWrapper(views::Textfield* textfield, |
| 53 views::ImageButton* image_button); |
| 54 virtual ~TextfieldWrapper(); |
| 55 |
| 56 virtual void Layout() OVERRIDE; |
| 57 virtual gfx::Size GetPreferredSize() OVERRIDE; |
| 58 |
| 59 private: |
| 60 gfx::Size GetImageSize() const; |
| 61 |
| 62 views::Textfield* textfield_; |
| 63 views::ImageButton* image_button_; |
| 64 }; |
| 65 |
| 66 TextfieldWrapper::TextfieldWrapper(views::Textfield* textfield, |
| 67 views::ImageButton* image_button) |
| 68 : textfield_(textfield), |
| 69 image_button_(image_button) { |
| 70 textfield_->RemoveBorder(); |
| 71 set_border(views::Border::CreateSolidBorder(kWrapperBorderSize, |
| 72 SK_ColorGRAY)); |
| 73 |
| 74 AddChildView(textfield_); |
| 75 AddChildView(image_button); |
| 76 } |
| 77 |
| 78 TextfieldWrapper::~TextfieldWrapper() {} |
| 79 |
| 80 void TextfieldWrapper::Layout() { |
| 81 // Add some spacing between the textfield and the border. |
| 82 textfield_->SetPosition(gfx::Point(kTextfieldHorizontalPadding, |
| 83 kTextfieldVerticalPadding)); |
| 84 textfield_->SizeToPreferredSize(); |
| 85 |
| 86 // Button should be offset one pixel from the end of the textfield so that |
| 87 // there is no overlap. It is also displaced down by the size of the border |
| 88 // so it doesn't overlap with it either. |
| 89 int button_x = (textfield_->GetPreferredSize().width() + |
| 90 kTextfieldHorizontalPadding + 1); |
| 91 image_button_->SetPosition(gfx::Point(button_x, |
| 92 kWrapperBorderSize)); |
| 93 |
| 94 // Make sure that the image is centered after cropping. |
| 95 image_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, |
| 96 views::ImageButton::ALIGN_MIDDLE); |
| 97 |
| 98 image_button_->SetSize(GetImageSize()); |
| 99 } |
| 100 |
| 101 gfx::Size TextfieldWrapper::GetPreferredSize() { |
| 102 int width = (textfield_->GetPreferredSize().width() + |
| 103 GetImageSize().width() + |
| 104 kTextfieldHorizontalPadding * 3); |
| 105 int height = (textfield_->GetPreferredSize().height() + |
| 106 kTextfieldVerticalPadding * 2); |
| 107 |
| 108 return gfx::Size(width, height); |
| 109 } |
| 110 |
| 111 gfx::Size TextfieldWrapper::GetImageSize() const { |
| 112 // The image is sized so that it fills the space between the borders |
| 113 // completely. |
| 114 int size = (textfield_->GetPreferredSize().height() + |
| 115 (kTextfieldVerticalPadding - kWrapperBorderSize) * 2); |
| 116 return gfx::Size(size, size); |
| 117 } |
| 118 } // namespace |
| 28 | 119 |
| 29 PasswordGenerationBubbleView::PasswordGenerationBubbleView( | 120 PasswordGenerationBubbleView::PasswordGenerationBubbleView( |
| 121 const webkit::forms::PasswordForm& form, |
| 30 const gfx::Rect& anchor_rect, | 122 const gfx::Rect& anchor_rect, |
| 31 const webkit::forms::PasswordForm& form, | |
| 32 views::View* anchor_view, | 123 views::View* anchor_view, |
| 33 content::RenderViewHost* render_view_host, | 124 content::RenderViewHost* render_view_host, |
| 125 PasswordManager* password_manager, |
| 34 autofill::PasswordGenerator* password_generator, | 126 autofill::PasswordGenerator* password_generator, |
| 35 content::PageNavigator* navigator, | 127 content::PageNavigator* navigator, |
| 36 PasswordManager* password_manager) | 128 ui::ThemeProvider* theme_provider) |
| 37 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT), | 129 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT), |
| 130 title_label_(NULL), |
| 38 accept_button_(NULL), | 131 accept_button_(NULL), |
| 39 text_field_(NULL), | 132 textfield_(NULL), |
| 133 form_(form), |
| 40 anchor_rect_(anchor_rect), | 134 anchor_rect_(anchor_rect), |
| 41 form_(form), | |
| 42 render_view_host_(render_view_host), | 135 render_view_host_(render_view_host), |
| 136 password_manager_(password_manager), |
| 43 password_generator_(password_generator), | 137 password_generator_(password_generator), |
| 44 navigator_(navigator), | 138 navigator_(navigator), |
| 45 password_manager_(password_manager) {} | 139 theme_provider_(theme_provider) {} |
| 46 | 140 |
| 47 PasswordGenerationBubbleView::~PasswordGenerationBubbleView() {} | 141 PasswordGenerationBubbleView::~PasswordGenerationBubbleView() {} |
| 48 | 142 |
| 49 void PasswordGenerationBubbleView::Init() { | 143 void PasswordGenerationBubbleView::Init() { |
| 144 set_margins(gfx::Insets(kBubbleMargin, kBubbleMargin, |
| 145 kBubbleMargin, kBubbleMargin)); |
| 146 |
| 50 // TODO(gcasto): Localize text after we have finalized the UI. | 147 // TODO(gcasto): Localize text after we have finalized the UI. |
| 51 // crbug.com/118062 | 148 // crbug.com/118062. |
| 149 gfx::Font label_font = |
| 150 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont); |
| 151 label_font = label_font.DeriveFont(2); |
| 152 title_label_ = new views::Label(ASCIIToUTF16("Password Suggestion"), |
| 153 label_font); |
| 154 AddChildView(title_label_); |
| 155 |
| 156 regenerate_button_ = new views::ImageButton(this); |
| 157 regenerate_button_->SetImage( |
| 158 views::CustomButton::BS_NORMAL, |
| 159 theme_provider_->GetImageSkiaNamed(IDR_RELOAD)); |
| 160 regenerate_button_->SetImage( |
| 161 views::CustomButton::BS_HOT, |
| 162 theme_provider_->GetImageSkiaNamed(IDR_RELOAD)); |
| 163 regenerate_button_->SetImage( |
| 164 views::CustomButton::BS_PUSHED, |
| 165 theme_provider_->GetImageSkiaNamed(IDR_RELOAD)); |
| 166 |
| 167 textfield_ = new views::Textfield(); |
| 168 gfx::Font textfield_font = |
| 169 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont); |
| 170 textfield_font = textfield_font.DeriveFont(2, gfx::Font::BOLD); |
| 171 textfield_->SetFont(textfield_font); |
| 172 textfield_->set_default_width_in_chars(kDefaultTextFieldChars); |
| 173 textfield_->SetText(ASCIIToUTF16(password_generator_->Generate())); |
| 174 |
| 175 textfield_wrapper_ = new TextfieldWrapper(textfield_, |
| 176 regenerate_button_); |
| 177 AddChildView(textfield_wrapper_); |
| 178 |
| 52 accept_button_ = new views::NativeTextButton(this, | 179 accept_button_ = new views::NativeTextButton(this, |
| 53 ASCIIToUTF16("Try It")); | 180 ASCIIToUTF16("Try it")); |
| 181 AddChildView(accept_button_); |
| 182 } |
| 54 | 183 |
| 55 text_field_ = new views::Textfield(); | 184 void PasswordGenerationBubbleView::Layout() { |
| 56 text_field_->SetText( | 185 // We have the title label shifted up to make the borders look more uniform. |
| 57 ASCIIToUTF16(password_generator_->Generate())); | 186 title_label_->SetPosition(gfx::Point(0, kTitleLabelVerticalOffset)); |
| 187 title_label_->SizeToPreferredSize(); |
| 58 | 188 |
| 59 views::Label* title_label = new views::Label( | 189 int y = title_label_->GetPreferredSize().height() + kVerticalPadding; |
| 60 ASCIIToUTF16("Password Suggestion")); | |
| 61 | 190 |
| 62 views::Link* learn_more_link = new views::Link( | 191 textfield_wrapper_->SetPosition(gfx::Point(0, y)); |
| 63 l10n_util::GetStringUTF16(IDS_LEARN_MORE)); | 192 textfield_wrapper_->SizeToPreferredSize(); |
| 64 learn_more_link->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 65 learn_more_link->set_listener(this); | |
| 66 | 193 |
| 67 GridLayout* layout = new GridLayout(this); | 194 int button_x = (textfield_wrapper_->GetPreferredSize().width() + |
| 68 SetLayoutManager(layout); | 195 kButtonHorizontalSpacing); |
| 196 accept_button_->SetBounds( |
| 197 button_x, |
| 198 y - kWrapperBorderSize, |
| 199 kButtonWidth, |
| 200 textfield_wrapper_->GetPreferredSize().height() + kWrapperBorderSize * 2); |
| 201 } |
| 69 | 202 |
| 70 // Title row. | 203 gfx::Size PasswordGenerationBubbleView::GetPreferredSize() { |
| 71 ColumnSet* cs = layout->AddColumnSet(0); | 204 int width = (textfield_wrapper_->GetPreferredSize().width() + |
| 72 cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, | 205 kButtonHorizontalSpacing + |
| 73 GridLayout::USE_PREF, 0, 100); | 206 kButtonWidth - 1); |
| 74 cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing); | 207 int height = (title_label_->GetPreferredSize().height() + |
| 75 cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0, | 208 textfield_wrapper_->GetPreferredSize().height() + |
| 76 GridLayout::USE_PREF, 0, 0); | 209 kVerticalPadding); |
| 77 | 210 return gfx::Size(width, height); |
| 78 // Input row | |
| 79 cs = layout->AddColumnSet(1); | |
| 80 cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, | |
| 81 GridLayout::USE_PREF, 0, 100); | |
| 82 cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing); | |
| 83 cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0, | |
| 84 GridLayout::USE_PREF, 0, 0); | |
| 85 | |
| 86 layout->StartRow(0, 0); | |
| 87 layout->AddView(title_label); | |
| 88 layout->AddView(learn_more_link); | |
| 89 | |
| 90 layout->StartRow(0, 1); | |
| 91 layout->AddView(text_field_); | |
| 92 layout->AddView(accept_button_); | |
| 93 } | 211 } |
| 94 | 212 |
| 95 gfx::Rect PasswordGenerationBubbleView::GetAnchorRect() { | 213 gfx::Rect PasswordGenerationBubbleView::GetAnchorRect() { |
| 96 return anchor_rect_; | 214 return anchor_rect_; |
| 97 } | 215 } |
| 98 | 216 |
| 99 void PasswordGenerationBubbleView::ButtonPressed(views::Button* sender, | 217 void PasswordGenerationBubbleView::ButtonPressed(views::Button* sender, |
| 100 const ui::Event& event) { | 218 const ui::Event& event) { |
| 101 if (sender == accept_button_) { | 219 if (sender == accept_button_) { |
| 102 render_view_host_->Send(new AutofillMsg_GeneratedPasswordAccepted( | 220 render_view_host_->Send(new AutofillMsg_GeneratedPasswordAccepted( |
| 103 render_view_host_->GetRoutingID(), text_field_->text())); | 221 render_view_host_->GetRoutingID(), textfield_->text())); |
| 104 password_manager_->SetFormHasGeneratedPassword(form_); | 222 password_manager_->SetFormHasGeneratedPassword(form_); |
| 105 StartFade(false); | 223 StartFade(false); |
| 106 } | 224 } |
| 107 } | 225 if (sender == regenerate_button_) { |
| 108 | 226 textfield_->SetText( |
| 109 void PasswordGenerationBubbleView::LinkClicked(views::Link* source, | 227 ASCIIToUTF16(password_generator_->Generate())); |
| 110 int event_flags) { | 228 } |
| 111 content::OpenURLParams params( | |
| 112 GURL(chrome::kAutoPasswordGenerationLearnMoreURL), content::Referrer(), | |
| 113 NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, false); | |
| 114 navigator_->OpenURL(params); | |
| 115 StartFade(false); | |
| 116 } | 229 } |
| 117 | 230 |
| 118 views::View* PasswordGenerationBubbleView::GetInitiallyFocusedView() { | 231 views::View* PasswordGenerationBubbleView::GetInitiallyFocusedView() { |
| 119 return text_field_; | 232 return textfield_; |
| 120 } | 233 } |
| OLD | NEW |