- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / password_generation_bubble_view.cc
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/password_manager/password_manager.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/browser_list.h"
11 #include "chrome/common/url_constants.h"
12 #include "components/autofill/core/browser/password_generator.h"
13 #include "components/autofill/core/common/autofill_messages.h"
14 #include "components/autofill/core/common/password_generation_util.h"
15 #include "content/public/browser/page_navigator.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "grit/generated_resources.h"
18 #include "grit/theme_resources.h"
19 #include "third_party/skia/include/core/SkPaint.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"
26 #include "ui/views/controls/button/label_button.h"
27 #include "ui/views/controls/label.h"
28 #include "ui/views/controls/link.h"
29 #include "ui/views/controls/textfield/textfield.h"
30 #include "ui/views/layout/layout_constants.h"
31 #include "url/gurl.h"
32
33 namespace {
34 // Constants for PasswordGenerationBubbleView.
35 const int kBubbleMargin = 9;
36 const int kButtonHorizontalSpacing = 4;
37 const int kButtonWidth = 65;
38 const int kDefaultTextFieldChars = 18;
39 const int kTitleLabelVerticalOffset = -1;
40 const int kVerticalPadding = 8;
41
42 // Constants for Text fieldWrapper.
43 const int kTextfieldHorizontalPadding = 2;
44 const int kTextfieldVerticalPadding = 3;
45 const int kWrapperBorderSize = 1;
46
47 // This class handles layout so that it looks like a Textfield and ImageButton
48 // are part of one logical textfield with the button on the right side of the
49 // field. It also assumes that the textfield is already sized appropriately
50 // and will alter the image size to fit.
51 class TextfieldWrapper : public views::View {
52  public:
53   TextfieldWrapper(views::Textfield* textfield,
54                    views::ImageButton* image_button);
55   virtual ~TextfieldWrapper();
56
57   virtual void Layout() OVERRIDE;
58   virtual gfx::Size GetPreferredSize() OVERRIDE;
59
60  private:
61   gfx::Size GetImageSize() const;
62
63   views::Textfield* textfield_;
64   views::ImageButton* image_button_;
65 };
66
67 TextfieldWrapper::TextfieldWrapper(views::Textfield* textfield,
68                                    views::ImageButton* image_button)
69     : textfield_(textfield),
70       image_button_(image_button) {
71   textfield_->RemoveBorder();
72   set_border(views::Border::CreateSolidBorder(kWrapperBorderSize,
73                                               SK_ColorGRAY));
74
75   AddChildView(textfield_);
76   AddChildView(image_button);
77 }
78
79 TextfieldWrapper::~TextfieldWrapper() {}
80
81 void TextfieldWrapper::Layout() {
82   // Add some spacing between the textfield and the border.
83   textfield_->SetPosition(gfx::Point(kTextfieldHorizontalPadding,
84                                      kTextfieldVerticalPadding));
85   textfield_->SizeToPreferredSize();
86
87   // Button should be offset one pixel from the end of the textfield so that
88   // there is no overlap. It is also displaced down by the size of the border
89   // so it doesn't overlap with it either.
90   int button_x = (textfield_->GetPreferredSize().width() +
91                   kTextfieldHorizontalPadding + 1);
92   image_button_->SetPosition(gfx::Point(button_x,
93                                         kWrapperBorderSize));
94
95   // Make sure that the image is centered after cropping.
96   image_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
97                                    views::ImageButton::ALIGN_MIDDLE);
98
99   image_button_->SetSize(GetImageSize());
100 }
101
102 gfx::Size TextfieldWrapper::GetPreferredSize() {
103   int width = (textfield_->GetPreferredSize().width() +
104                GetImageSize().width() +
105                kTextfieldHorizontalPadding * 3);
106   int height = (textfield_->GetPreferredSize().height() +
107                 kTextfieldVerticalPadding * 2);
108
109   return gfx::Size(width, height);
110 }
111
112 gfx::Size TextfieldWrapper::GetImageSize() const {
113   // The image is sized so that it fills the space between the borders
114   // completely.
115   int size = (textfield_->GetPreferredSize().height() +
116               (kTextfieldVerticalPadding - kWrapperBorderSize) * 2);
117   return gfx::Size(size, size);
118 }
119 }  // namespace
120
121 PasswordGenerationBubbleView::PasswordGenerationBubbleView(
122     const autofill::PasswordForm& form,
123     const gfx::Rect& anchor_rect,
124     views::View* anchor_view,
125     content::RenderViewHost* render_view_host,
126     PasswordManager* password_manager,
127     autofill::PasswordGenerator* password_generator,
128     content::PageNavigator* navigator,
129     ui::ThemeProvider* theme_provider)
130     : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT),
131       title_label_(NULL),
132       accept_button_(NULL),
133       textfield_(NULL),
134       regenerate_button_(NULL),
135       textfield_wrapper_(NULL),
136       form_(form),
137       anchor_rect_(anchor_rect),
138       render_view_host_(render_view_host),
139       password_manager_(password_manager),
140       password_generator_(password_generator),
141       navigator_(navigator),
142       theme_provider_(theme_provider) {}
143
144 PasswordGenerationBubbleView::~PasswordGenerationBubbleView() {}
145
146 void PasswordGenerationBubbleView::Init() {
147   set_margins(gfx::Insets(kBubbleMargin, kBubbleMargin,
148                           kBubbleMargin, kBubbleMargin));
149
150   // TODO(gcasto): Localize text after we have finalized the UI.
151   // crbug.com/118062.
152   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
153   title_label_ = new views::Label(
154       l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_BUBBLE_TITLE),
155       rb.GetFont(ui::ResourceBundle::MediumFont));
156   AddChildView(title_label_);
157
158   regenerate_button_ = new views::ImageButton(this);
159   regenerate_button_->SetImage(
160       views::CustomButton::STATE_NORMAL,
161       theme_provider_->GetImageSkiaNamed(IDR_RELOAD_DIMMED));
162   regenerate_button_->SetImage(
163       views::CustomButton::STATE_HOVERED,
164       theme_provider_->GetImageSkiaNamed(IDR_RELOAD));
165   regenerate_button_->SetImage(
166       views::CustomButton::STATE_PRESSED,
167       theme_provider_->GetImageSkiaNamed(IDR_RELOAD));
168
169   textfield_ = new views::Textfield();
170   textfield_->set_default_width_in_chars(kDefaultTextFieldChars);
171   textfield_->SetText(ASCIIToUTF16(password_generator_->Generate()));
172   textfield_->SetController(this);
173
174   textfield_wrapper_ = new TextfieldWrapper(textfield_,
175                                             regenerate_button_);
176   AddChildView(textfield_wrapper_);
177
178   accept_button_ = new views::LabelButton(
179       this,
180       l10n_util::GetStringUTF16(IDS_PASSWORD_GENERATION_BUTTON_TEXT));
181   accept_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
182   AddChildView(accept_button_);
183 }
184
185 void PasswordGenerationBubbleView::Layout() {
186   // We have the title label shifted up to make the borders look more uniform.
187   title_label_->SetPosition(gfx::Point(0, kTitleLabelVerticalOffset));
188   title_label_->SizeToPreferredSize();
189
190   int y = title_label_->GetPreferredSize().height() + kVerticalPadding;
191
192   textfield_wrapper_->SetPosition(gfx::Point(0, y));
193   textfield_wrapper_->SizeToPreferredSize();
194
195   int button_x = (textfield_wrapper_->GetPreferredSize().width() +
196                   kButtonHorizontalSpacing);
197   accept_button_->SetBounds(
198       button_x,
199       y - kWrapperBorderSize,
200       kButtonWidth,
201       textfield_wrapper_->GetPreferredSize().height() + kWrapperBorderSize * 2);
202 }
203
204 gfx::Size PasswordGenerationBubbleView::GetPreferredSize() {
205   int width = (textfield_wrapper_->GetPreferredSize().width() +
206                kButtonHorizontalSpacing +
207                kButtonWidth - 1);
208   int height = (title_label_->GetPreferredSize().height() +
209                 textfield_wrapper_->GetPreferredSize().height() +
210                 kVerticalPadding);
211   return gfx::Size(width, height);
212 }
213
214 gfx::Rect PasswordGenerationBubbleView::GetAnchorRect() {
215   return anchor_rect_;
216 }
217
218 void PasswordGenerationBubbleView::ButtonPressed(views::Button* sender,
219                                                  const ui::Event& event) {
220   if (sender == accept_button_) {
221     render_view_host_->Send(new AutofillMsg_GeneratedPasswordAccepted(
222         render_view_host_->GetRoutingID(), textfield_->text()));
223     password_manager_->SetFormHasGeneratedPassword(form_);
224     actions_.password_accepted = true;
225     StartFade(false);
226   }
227   if (sender == regenerate_button_) {
228     textfield_->SetText(
229         ASCIIToUTF16(password_generator_->Generate()));
230     actions_.password_regenerated = true;
231   }
232 }
233
234 void PasswordGenerationBubbleView::ContentsChanged(views::Textfield* sender,
235                                                    const string16& contents) {
236   actions_.password_edited = true;
237 }
238
239 bool PasswordGenerationBubbleView::HandleKeyEvent(
240     views::Textfield* sender,
241     const ui::KeyEvent& key_event) {
242   return false;
243 }
244
245 views::View* PasswordGenerationBubbleView::GetInitiallyFocusedView() {
246   return textfield_;
247 }
248
249 void PasswordGenerationBubbleView::WindowClosing() {
250   autofill::password_generation::LogUserActions(actions_);
251 }