• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "components/autofill/content/common/autofill_messages.h"
12 #include "components/autofill/core/browser/password_generator.h"
13 #include "components/autofill/core/common/password_generation_util.h"
14 #include "components/password_manager/core/browser/password_manager.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "grit/generated_resources.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 
TextfieldWrapper(views::Textfield * textfield,views::ImageButton * image_button)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 
~TextfieldWrapper()76 TextfieldWrapper::~TextfieldWrapper() {}
77 
Layout()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 
GetPreferredSize() const99 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 
GetImageSize() const109 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 
PasswordGenerationBubbleView(const autofill::PasswordForm & form,const gfx::Rect & anchor_rect,views::View * anchor_view,content::RenderViewHost * render_view_host,password_manager::PasswordManager * password_manager,autofill::PasswordGenerator * password_generator,ui::ThemeProvider * theme_provider)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 
~PasswordGenerationBubbleView()139 PasswordGenerationBubbleView::~PasswordGenerationBubbleView() {}
140 
Init()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 
Layout()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 
GetPreferredSize() const199 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 
GetAnchorRect() const209 gfx::Rect PasswordGenerationBubbleView::GetAnchorRect() const {
210   return anchor_rect_;
211 }
212 
ButtonPressed(views::Button * sender,const ui::Event & event)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 
ContentsChanged(views::Textfield * sender,const base::string16 & contents)229 void PasswordGenerationBubbleView::ContentsChanged(
230     views::Textfield* sender,
231     const base::string16& contents) {
232   actions_.password_edited = true;
233 }
234 
HandleKeyEvent(views::Textfield * sender,const ui::KeyEvent & key_event)235 bool PasswordGenerationBubbleView::HandleKeyEvent(
236     views::Textfield* sender,
237     const ui::KeyEvent& key_event) {
238   return false;
239 }
240 
GetInitiallyFocusedView()241 views::View* PasswordGenerationBubbleView::GetInitiallyFocusedView() {
242   return textfield_;
243 }
244 
WindowClosing()245 void PasswordGenerationBubbleView::WindowClosing() {
246   autofill::password_generation::LogUserActions(actions_);
247 }
248