| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ui/views/password_generation_bubble_view.h" | |
| 6 | |
| 7 #include "base/strings/utf_string_conversions.h" | |
| 8 #include "chrome/browser/ui/browser.h" | |
| 9 #include "chrome/browser/ui/browser_list.h" | |
| 10 #include "chrome/common/url_constants.h" | |
| 11 #include "chrome/grit/generated_resources.h" | |
| 12 #include "components/autofill/content/common/autofill_messages.h" | |
| 13 #include "components/autofill/core/browser/password_generator.h" | |
| 14 #include "components/autofill/core/common/password_generation_util.h" | |
| 15 #include "components/password_manager/core/browser/password_manager.h" | |
| 16 #include "content/public/browser/render_view_host.h" | |
| 17 #include "grit/theme_resources.h" | |
| 18 #include "third_party/skia/include/core/SkPaint.h" | |
| 19 #include "ui/base/l10n/l10n_util.h" | |
| 20 #include "ui/base/resource/resource_bundle.h" | |
| 21 #include "ui/base/theme_provider.h" | |
| 22 #include "ui/gfx/canvas.h" | |
| 23 #include "ui/views/border.h" | |
| 24 #include "ui/views/controls/button/image_button.h" | |
| 25 #include "ui/views/controls/button/label_button.h" | |
| 26 #include "ui/views/controls/label.h" | |
| 27 #include "ui/views/controls/link.h" | |
| 28 #include "ui/views/controls/textfield/textfield.h" | |
| 29 #include "ui/views/layout/layout_constants.h" | |
| 30 #include "url/gurl.h" | |
| 31 | |
| 32 namespace { | |
| 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 = -1; | |
| 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() const 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 SetBorder(views::Border::CreateSolidBorder(kWrapperBorderSize, SK_ColorGRAY)); | |
| 71 | |
| 72 AddChildView(textfield_); | |
| 73 AddChildView(image_button); | |
| 74 } | |
| 75 | |
| 76 TextfieldWrapper::~TextfieldWrapper() {} | |
| 77 | |
| 78 void TextfieldWrapper::Layout() { | |
| 79 // Add some spacing between the textfield and the border. | |
| 80 textfield_->SetPosition(gfx::Point(kTextfieldHorizontalPadding, | |
| 81 kTextfieldVerticalPadding)); | |
| 82 textfield_->SizeToPreferredSize(); | |
| 83 | |
| 84 // Button should be offset one pixel from the end of the textfield so that | |
| 85 // there is no overlap. It is also displaced down by the size of the border | |
| 86 // so it doesn't overlap with it either. | |
| 87 int button_x = (textfield_->GetPreferredSize().width() + | |
| 88 kTextfieldHorizontalPadding + 1); | |
| 89 image_button_->SetPosition(gfx::Point(button_x, | |
| 90 kWrapperBorderSize)); | |
| 91 | |
| 92 // Make sure that the image is centered after cropping. | |
| 93 image_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, | |
| 94 views::ImageButton::ALIGN_MIDDLE); | |
| 95 | |
| 96 image_button_->SetSize(GetImageSize()); | |
| 97 } | |
| 98 | |
| 99 gfx::Size TextfieldWrapper::GetPreferredSize() const { | |
| 100 int width = (textfield_->GetPreferredSize().width() + | |
| 101 GetImageSize().width() + | |
| 102 kTextfieldHorizontalPadding * 3); | |
| 103 int height = (textfield_->GetPreferredSize().height() + | |
| 104 kTextfieldVerticalPadding * 2); | |
| 105 | |
| 106 return gfx::Size(width, height); | |
| 107 } | |
| 108 | |
| 109 gfx::Size TextfieldWrapper::GetImageSize() const { | |
| 110 // The image is sized so that it fills the space between the borders | |
| 111 // completely. | |
| 112 int size = (textfield_->GetPreferredSize().height() + | |
| 113 (kTextfieldVerticalPadding - kWrapperBorderSize) * 2); | |
| 114 return gfx::Size(size, size); | |
| 115 } | |
| 116 } // namespace | |
| 117 | |
| 118 PasswordGenerationBubbleView::PasswordGenerationBubbleView( | |
| 119 const autofill::PasswordForm& form, | |
| 120 const gfx::Rect& anchor_rect, | |
| 121 views::View* anchor_view, | |
| 122 content::RenderViewHost* render_view_host, | |
| 123 password_manager::PasswordManager* password_manager, | |
| 124 autofill::PasswordGenerator* password_generator, | |
| 125 ui::ThemeProvider* theme_provider) | |
| 126 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT), | |
| 127 title_label_(NULL), | |
| 128 accept_button_(NULL), | |
| 129 textfield_(NULL), | |
| 130 regenerate_button_(NULL), | |
| 131 textfield_wrapper_(NULL), | |
| 132 form_(form), | |
| 133 anchor_rect_(anchor_rect), | |
| 134 render_view_host_(render_view_host), | |
| 135 password_manager_(password_manager), | |
| 136 password_generator_(password_generator), | |
| 137 theme_provider_(theme_provider) {} | |
| 138 | |
| 139 PasswordGenerationBubbleView::~PasswordGenerationBubbleView() {} | |
| 140 | |
| 141 void PasswordGenerationBubbleView::Init() { | |
| 142 set_margins(gfx::Insets(kBubbleMargin, kBubbleMargin, | |
| 143 kBubbleMargin, kBubbleMargin)); | |
| 144 | |
| 145 // TODO(gcasto): Localize text after we have finalized the UI. | |
| 146 // crbug.com/118062. | |
| 147 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 148 title_label_ = new views::Label( | |
| 149 l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_BUBBLE_TITLE), | |
| 150 rb.GetFontList(ui::ResourceBundle::MediumFont)); | |
| 151 AddChildView(title_label_); | |
| 152 | |
| 153 regenerate_button_ = new views::ImageButton(this); | |
| 154 regenerate_button_->SetImage( | |
| 155 views::CustomButton::STATE_NORMAL, | |
| 156 theme_provider_->GetImageSkiaNamed(IDR_RELOAD_DIMMED)); | |
| 157 regenerate_button_->SetImage( | |
| 158 views::CustomButton::STATE_HOVERED, | |
| 159 theme_provider_->GetImageSkiaNamed(IDR_RELOAD)); | |
| 160 regenerate_button_->SetImage( | |
| 161 views::CustomButton::STATE_PRESSED, | |
| 162 theme_provider_->GetImageSkiaNamed(IDR_RELOAD)); | |
| 163 | |
| 164 textfield_ = new views::Textfield(); | |
| 165 textfield_->set_default_width_in_chars(kDefaultTextFieldChars); | |
| 166 textfield_->SetText(base::ASCIIToUTF16(password_generator_->Generate())); | |
| 167 textfield_->set_controller(this); | |
| 168 | |
| 169 textfield_wrapper_ = new TextfieldWrapper(textfield_, | |
| 170 regenerate_button_); | |
| 171 AddChildView(textfield_wrapper_); | |
| 172 | |
| 173 accept_button_ = new views::LabelButton( | |
| 174 this, | |
| 175 l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_BUTTON_TEXT)); | |
| 176 accept_button_->SetStyle(views::Button::STYLE_BUTTON); | |
| 177 AddChildView(accept_button_); | |
| 178 } | |
| 179 | |
| 180 void PasswordGenerationBubbleView::Layout() { | |
| 181 // We have the title label shifted up to make the borders look more uniform. | |
| 182 title_label_->SetPosition(gfx::Point(0, kTitleLabelVerticalOffset)); | |
| 183 title_label_->SizeToPreferredSize(); | |
| 184 | |
| 185 int y = title_label_->GetPreferredSize().height() + kVerticalPadding; | |
| 186 | |
| 187 textfield_wrapper_->SetPosition(gfx::Point(0, y)); | |
| 188 textfield_wrapper_->SizeToPreferredSize(); | |
| 189 | |
| 190 int button_x = (textfield_wrapper_->GetPreferredSize().width() + | |
| 191 kButtonHorizontalSpacing); | |
| 192 accept_button_->SetBounds( | |
| 193 button_x, | |
| 194 y - kWrapperBorderSize, | |
| 195 kButtonWidth, | |
| 196 textfield_wrapper_->GetPreferredSize().height() + kWrapperBorderSize * 2); | |
| 197 } | |
| 198 | |
| 199 gfx::Size PasswordGenerationBubbleView::GetPreferredSize() const { | |
| 200 int width = (textfield_wrapper_->GetPreferredSize().width() + | |
| 201 kButtonHorizontalSpacing + | |
| 202 kButtonWidth - 1); | |
| 203 int height = (title_label_->GetPreferredSize().height() + | |
| 204 textfield_wrapper_->GetPreferredSize().height() + | |
| 205 kVerticalPadding); | |
| 206 return gfx::Size(width, height); | |
| 207 } | |
| 208 | |
| 209 gfx::Rect PasswordGenerationBubbleView::GetAnchorRect() const { | |
| 210 return anchor_rect_; | |
| 211 } | |
| 212 | |
| 213 void PasswordGenerationBubbleView::ButtonPressed(views::Button* sender, | |
| 214 const ui::Event& event) { | |
| 215 if (sender == accept_button_) { | |
| 216 render_view_host_->Send(new AutofillMsg_GeneratedPasswordAccepted( | |
| 217 render_view_host_->GetRoutingID(), textfield_->text())); | |
| 218 password_manager_->SetFormHasGeneratedPassword(form_); | |
| 219 actions_.password_accepted = true; | |
| 220 GetWidget()->Close(); | |
| 221 } | |
| 222 if (sender == regenerate_button_) { | |
| 223 textfield_->SetText( | |
| 224 base::ASCIIToUTF16(password_generator_->Generate())); | |
| 225 actions_.password_regenerated = true; | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 void PasswordGenerationBubbleView::ContentsChanged( | |
| 230 views::Textfield* sender, | |
| 231 const base::string16& contents) { | |
| 232 actions_.password_edited = true; | |
| 233 } | |
| 234 | |
| 235 bool PasswordGenerationBubbleView::HandleKeyEvent( | |
| 236 views::Textfield* sender, | |
| 237 const ui::KeyEvent& key_event) { | |
| 238 return false; | |
| 239 } | |
| 240 | |
| 241 views::View* PasswordGenerationBubbleView::GetInitiallyFocusedView() { | |
| 242 return textfield_; | |
| 243 } | |
| 244 | |
| 245 void PasswordGenerationBubbleView::WindowClosing() { | |
| 246 autofill::password_generation::LogUserActions(actions_); | |
| 247 } | |
| OLD | NEW |