Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / autofill / password_generation_popup_view_views.cc
1 // Copyright 2014 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/autofill/password_generation_popup_view_views.h"
6
7 #include "base/strings/string16.h"
8 #include "chrome/browser/ui/autofill/password_generation_popup_controller.h"
9 #include "chrome/browser/ui/autofill/popup_constants.h"
10 #include "grit/theme_resources.h"
11 #include "ui/accessibility/ax_view_state.h"
12 #include "ui/base/resource/resource_bundle.h"
13 #include "ui/gfx/canvas.h"
14 #include "ui/views/background.h"
15 #include "ui/views/border.h"
16 #include "ui/views/controls/image_view.h"
17 #include "ui/views/controls/label.h"
18 #include "ui/views/controls/styled_label.h"
19 #include "ui/views/layout/box_layout.h"
20 #include "ui/views/widget/widget.h"
21
22 namespace autofill {
23
24 namespace {
25
26 // The amount of whitespace that is present when there is no padding. Used
27 // to get the proper spacing in the help section.
28 const int kHelpVerticalOffset = 5;
29
30 // Wrapper around just the text portions of the generation UI (password and
31 // prompting text).
32 class PasswordTextBox : public views::View {
33  public:
34   PasswordTextBox() {}
35   ~PasswordTextBox() override {}
36
37   // |suggestion_text| prompts the user to select the password,
38   // |generated_password| is the generated password, and |font_list| is the font
39   // used for all text in this class.
40   void Init(const base::string16& suggestion_text,
41             const base::string16& generated_password,
42             const gfx::FontList& font_list) {
43     views::BoxLayout* box_layout = new views::BoxLayout(
44         views::BoxLayout::kVertical, 0, 12, 5);
45     box_layout->set_main_axis_alignment(
46         views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
47     SetLayoutManager(box_layout);
48
49     views::Label* suggestion_label = new views::Label(
50         suggestion_text, font_list.DeriveWithStyle(gfx::Font::BOLD));
51     suggestion_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
52     suggestion_label->SetEnabledColor(
53         PasswordGenerationPopupView::kPasswordTextColor);
54     AddChildView(suggestion_label);
55
56     views::Label* password_label =
57         new views::Label(generated_password, font_list);
58     password_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
59     password_label->SetEnabledColor(
60         PasswordGenerationPopupView::kPasswordTextColor);
61     AddChildView(password_label);
62   }
63
64   // views::View:
65   bool CanProcessEventsWithinSubtree() const override {
66     // Send events to the parent view for handling.
67     return false;
68   }
69
70  private:
71   DISALLOW_COPY_AND_ASSIGN(PasswordTextBox);
72 };
73
74 }  // namespace
75
76 // Class that shows the generated password and associated UI (currently a key
77 // image and some explanatory text).
78 class PasswordGenerationPopupViewViews::PasswordBox : public views::View {
79  public:
80   PasswordBox() {}
81   ~PasswordBox() override {}
82
83   // |password| is the generated password, |suggestion| is the text prompting
84   // the user to select the password, and |font_list| is the font used for all
85   // the text.
86   void Init(const base::string16& password,
87             const base::string16& suggestion,
88             const base::string16& accessible_name,
89             const gfx::FontList& font_list) {
90     accessible_name_ = accessible_name;
91
92     views::BoxLayout* box_layout = new views::BoxLayout(
93         views::BoxLayout::kHorizontal,
94         PasswordGenerationPopupController::kHorizontalPadding,
95         0,
96         15);
97     box_layout->set_main_axis_alignment(
98         views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
99     SetLayoutManager(box_layout);
100
101     views::ImageView* key_image = new views::ImageView();
102     key_image->SetImage(
103         ui::ResourceBundle::GetSharedInstance().GetImageNamed(
104             IDR_GENERATE_PASSWORD_KEY).ToImageSkia());
105     AddChildView(key_image);
106
107     PasswordTextBox* password_text_box = new PasswordTextBox();
108     password_text_box->Init(suggestion, password, font_list);
109     AddChildView(password_text_box);
110
111     NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
112   }
113
114   // views::View:
115   bool CanProcessEventsWithinSubtree() const override {
116     // Send events to the parent view for handling.
117     return false;
118   }
119
120   void GetAccessibleState(ui::AXViewState* state) override {
121     state->role = ui::AX_ROLE_ALERT;
122     state->name = accessible_name_;
123   }
124
125  private:
126   base::string16 accessible_name_;
127
128   DISALLOW_COPY_AND_ASSIGN(PasswordBox);
129 };
130
131 PasswordGenerationPopupViewViews::PasswordGenerationPopupViewViews(
132     PasswordGenerationPopupController* controller,
133     views::Widget* observing_widget)
134     : AutofillPopupBaseView(controller, observing_widget),
135       password_view_(NULL),
136       font_list_(ResourceBundle::GetSharedInstance().GetFontList(
137           ResourceBundle::SmallFont)),
138       controller_(controller) {
139   if (controller_->display_password())
140     CreatePasswordView();
141
142   help_label_ = new views::StyledLabel(controller_->HelpText(), this);
143   help_label_->SetBaseFontList(font_list_);
144   help_label_->SetLineHeight(20);
145   views::StyledLabel::RangeStyleInfo default_style;
146   default_style.color = kExplanatoryTextColor;
147   help_label_->SetDefaultStyle(default_style);
148
149   views::StyledLabel::RangeStyleInfo link_style =
150       views::StyledLabel::RangeStyleInfo::CreateForLink();
151   link_style.disable_line_wrapping = false;
152   help_label_->AddStyleRange(controller_->HelpTextLinkRange(), link_style);
153
154   help_label_->set_background(
155       views::Background::CreateSolidBackground(
156           kExplanatoryTextBackgroundColor));
157   help_label_->SetBorder(views::Border::CreateEmptyBorder(
158       PasswordGenerationPopupController::kHelpVerticalPadding -
159       kHelpVerticalOffset,
160       PasswordGenerationPopupController::kHorizontalPadding,
161       PasswordGenerationPopupController::kHelpVerticalPadding -
162       kHelpVerticalOffset,
163       PasswordGenerationPopupController::kHorizontalPadding));
164   AddChildView(help_label_);
165
166   set_background(views::Background::CreateSolidBackground(kPopupBackground));
167 }
168
169 PasswordGenerationPopupViewViews::~PasswordGenerationPopupViewViews() {}
170
171 void PasswordGenerationPopupViewViews::CreatePasswordView() {
172   if (password_view_)
173     return;
174
175   password_view_ = new PasswordBox();
176   password_view_->Init(controller_->password(),
177                        controller_->SuggestedText(),
178                        controller_->AccessibleName(),
179                        font_list_);
180   password_view_->SetPosition(gfx::Point(kPopupBorderThickness,
181                                          kPopupBorderThickness));
182   password_view_->SizeToPreferredSize();
183   AddChildView(password_view_);
184 }
185
186 gfx::Size PasswordGenerationPopupViewViews::GetPreferredSizeOfPasswordView() {
187   int height = kPopupBorderThickness;
188   if (controller_->display_password()) {
189     // Add divider height as well.
190     height +=
191         PasswordGenerationPopupController::kPopupPasswordSectionHeight + 1;
192   }
193   int width = controller_->GetMinimumWidth();
194   int popup_width = width - 2 * kPopupBorderThickness;
195   height += help_label_->GetHeightForWidth(popup_width);
196   return gfx::Size(width, height + kPopupBorderThickness);
197 }
198
199 void PasswordGenerationPopupViewViews::Show() {
200   DoShow();
201 }
202
203 void PasswordGenerationPopupViewViews::Hide() {
204   // The controller is no longer valid after it hides us.
205   controller_ = NULL;
206
207   DoHide();
208 }
209
210 void PasswordGenerationPopupViewViews::UpdateBoundsAndRedrawPopup() {
211   DoUpdateBoundsAndRedrawPopup();
212 }
213
214 void PasswordGenerationPopupViewViews::PasswordSelectionUpdated() {
215   if (!password_view_)
216     return;
217
218   password_view_->set_background(
219       views::Background::CreateSolidBackground(
220           controller_->password_selected() ?
221           kHoveredBackgroundColor :
222           kPopupBackground));
223 }
224
225 void PasswordGenerationPopupViewViews::Layout() {
226   // Need to leave room for the border.
227   int y = kPopupBorderThickness;
228   int popup_width = bounds().width() - 2 * kPopupBorderThickness;
229   if (controller_->display_password()) {
230     // Currently the UI can change from not offering a password to offering
231     // a password (e.g. the user is editing a generated password and deletes
232     // it), but it can't change the other way around.
233     CreatePasswordView();
234     password_view_->SetBounds(
235         kPopupBorderThickness,
236         y,
237         popup_width,
238         PasswordGenerationPopupController::kPopupPasswordSectionHeight);
239     divider_bounds_ =
240         gfx::Rect(kPopupBorderThickness, password_view_->bounds().bottom(),
241                   popup_width, 1);
242     y = divider_bounds_.bottom();
243   }
244
245   help_label_->SetBounds(kPopupBorderThickness, y, popup_width,
246                          help_label_->GetHeightForWidth(popup_width));
247 }
248
249 void PasswordGenerationPopupViewViews::OnPaint(gfx::Canvas* canvas) {
250   if (!controller_)
251     return;
252
253   // Draw border and background.
254   views::View::OnPaint(canvas);
255
256   // Divider line needs to be drawn after OnPaint() otherwise the background
257   // will overwrite the divider.
258   if (password_view_)
259     canvas->FillRect(divider_bounds_, kDividerColor);
260 }
261
262 void PasswordGenerationPopupViewViews::StyledLabelLinkClicked(
263     const gfx::Range& range, int event_flags) {
264   controller_->OnSavedPasswordsLinkClicked();
265 }
266
267 bool PasswordGenerationPopupViewViews::IsPointInPasswordBounds(
268     const gfx::Point& point) {
269   if (password_view_)
270     return password_view_->bounds().Contains(point);
271   return false;
272 }
273
274 PasswordGenerationPopupView* PasswordGenerationPopupView::Create(
275     PasswordGenerationPopupController* controller) {
276   views::Widget* observing_widget =
277       views::Widget::GetTopLevelWidgetForNativeView(
278           controller->container_view());
279
280   // If the top level widget can't be found, cancel the popup since we can't
281   // fully set it up.
282   if (!observing_widget)
283     return NULL;
284
285   return new PasswordGenerationPopupViewViews(controller, observing_widget);
286 }
287
288 }  // namespace autofill