Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / autofill / password_generation_popup_view_views.cc
blob36802a8617b03b3aca79eeb48ac3353b933efa83
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.
5 #include "chrome/browser/ui/views/autofill/password_generation_popup_view_views.h"
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"
22 namespace autofill {
24 namespace {
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;
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 {}
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);
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);
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);
64 // views::View:
65 bool CanProcessEventsWithinSubtree() const override {
66 // Send events to the parent view for handling.
67 return false;
70 private:
71 DISALLOW_COPY_AND_ASSIGN(PasswordTextBox);
74 } // namespace
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 {}
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 gfx::FontList& font_list) {
89 views::BoxLayout* box_layout = new views::BoxLayout(
90 views::BoxLayout::kHorizontal,
91 PasswordGenerationPopupController::kHorizontalPadding,
93 15);
94 box_layout->set_main_axis_alignment(
95 views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
96 SetLayoutManager(box_layout);
98 views::ImageView* key_image = new views::ImageView();
99 key_image->SetImage(
100 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
101 IDR_GENERATE_PASSWORD_KEY).ToImageSkia());
102 AddChildView(key_image);
104 PasswordTextBox* password_text_box = new PasswordTextBox();
105 password_text_box->Init(suggestion, password, font_list);
106 AddChildView(password_text_box);
109 // views::View:
110 bool CanProcessEventsWithinSubtree() const override {
111 // Send events to the parent view for handling.
112 return false;
115 private:
117 DISALLOW_COPY_AND_ASSIGN(PasswordBox);
120 PasswordGenerationPopupViewViews::PasswordGenerationPopupViewViews(
121 PasswordGenerationPopupController* controller,
122 views::Widget* parent_widget)
123 : AutofillPopupBaseView(controller, parent_widget),
124 password_view_(NULL),
125 font_list_(ResourceBundle::GetSharedInstance().GetFontList(
126 ResourceBundle::SmallFont)),
127 controller_(controller) {
128 if (controller_->display_password())
129 CreatePasswordView();
131 help_label_ = new views::StyledLabel(controller_->HelpText(), this);
132 help_label_->SetBaseFontList(font_list_);
133 help_label_->SetLineHeight(20);
134 views::StyledLabel::RangeStyleInfo default_style;
135 default_style.color = kExplanatoryTextColor;
136 help_label_->SetDefaultStyle(default_style);
138 views::StyledLabel::RangeStyleInfo link_style =
139 views::StyledLabel::RangeStyleInfo::CreateForLink();
140 link_style.disable_line_wrapping = false;
141 help_label_->AddStyleRange(controller_->HelpTextLinkRange(), link_style);
143 help_label_->set_background(
144 views::Background::CreateSolidBackground(
145 kExplanatoryTextBackgroundColor));
146 help_label_->SetBorder(views::Border::CreateEmptyBorder(
147 PasswordGenerationPopupController::kHelpVerticalPadding -
148 kHelpVerticalOffset,
149 PasswordGenerationPopupController::kHorizontalPadding,
150 PasswordGenerationPopupController::kHelpVerticalPadding -
151 kHelpVerticalOffset,
152 PasswordGenerationPopupController::kHorizontalPadding));
153 AddChildView(help_label_);
155 set_background(views::Background::CreateSolidBackground(kPopupBackground));
158 PasswordGenerationPopupViewViews::~PasswordGenerationPopupViewViews() {}
160 void PasswordGenerationPopupViewViews::CreatePasswordView() {
161 if (password_view_)
162 return;
164 password_view_ = new PasswordBox();
165 password_view_->Init(controller_->password(),
166 controller_->SuggestedText(),
167 font_list_);
168 password_view_->SetPosition(gfx::Point(kPopupBorderThickness,
169 kPopupBorderThickness));
170 password_view_->SizeToPreferredSize();
171 AddChildView(password_view_);
174 gfx::Size PasswordGenerationPopupViewViews::GetPreferredSizeOfPasswordView() {
175 int height = kPopupBorderThickness;
176 if (controller_->display_password()) {
177 // Add divider height as well.
178 height +=
179 PasswordGenerationPopupController::kPopupPasswordSectionHeight + 1;
181 int width = controller_->GetMinimumWidth();
182 int popup_width = width - 2 * kPopupBorderThickness;
183 height += help_label_->GetHeightForWidth(popup_width);
184 return gfx::Size(width, height + kPopupBorderThickness);
187 void PasswordGenerationPopupViewViews::Show() {
188 DoShow();
191 void PasswordGenerationPopupViewViews::Hide() {
192 // The controller is no longer valid after it hides us.
193 controller_ = NULL;
195 DoHide();
198 void PasswordGenerationPopupViewViews::UpdateBoundsAndRedrawPopup() {
199 DoUpdateBoundsAndRedrawPopup();
202 void PasswordGenerationPopupViewViews::PasswordSelectionUpdated() {
203 if (!password_view_)
204 return;
206 if (controller_->password_selected())
207 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
209 password_view_->set_background(
210 views::Background::CreateSolidBackground(
211 controller_->password_selected() ?
212 kHoveredBackgroundColor :
213 kPopupBackground));
216 void PasswordGenerationPopupViewViews::Layout() {
217 // Need to leave room for the border.
218 int y = kPopupBorderThickness;
219 int popup_width = bounds().width() - 2 * kPopupBorderThickness;
220 if (controller_->display_password()) {
221 // Currently the UI can change from not offering a password to offering
222 // a password (e.g. the user is editing a generated password and deletes
223 // it), but it can't change the other way around.
224 CreatePasswordView();
225 password_view_->SetBounds(
226 kPopupBorderThickness,
228 popup_width,
229 PasswordGenerationPopupController::kPopupPasswordSectionHeight);
230 divider_bounds_ =
231 gfx::Rect(kPopupBorderThickness, password_view_->bounds().bottom(),
232 popup_width, 1);
233 y = divider_bounds_.bottom();
236 help_label_->SetBounds(kPopupBorderThickness, y, popup_width,
237 help_label_->GetHeightForWidth(popup_width));
240 void PasswordGenerationPopupViewViews::OnPaint(gfx::Canvas* canvas) {
241 if (!controller_)
242 return;
244 // Draw border and background.
245 views::View::OnPaint(canvas);
247 // Divider line needs to be drawn after OnPaint() otherwise the background
248 // will overwrite the divider.
249 if (password_view_)
250 canvas->FillRect(divider_bounds_, kDividerColor);
253 void PasswordGenerationPopupViewViews::StyledLabelLinkClicked(
254 const gfx::Range& range, int event_flags) {
255 controller_->OnSavedPasswordsLinkClicked();
258 bool PasswordGenerationPopupViewViews::IsPointInPasswordBounds(
259 const gfx::Point& point) {
260 if (password_view_)
261 return password_view_->bounds().Contains(point);
262 return false;
265 PasswordGenerationPopupView* PasswordGenerationPopupView::Create(
266 PasswordGenerationPopupController* controller) {
267 views::Widget* observing_widget =
268 views::Widget::GetTopLevelWidgetForNativeView(
269 controller->container_view());
271 // If the top level widget can't be found, cancel the popup since we can't
272 // fully set it up.
273 if (!observing_widget)
274 return NULL;
276 return new PasswordGenerationPopupViewViews(controller, observing_widget);
279 void PasswordGenerationPopupViewViews::GetAccessibleState(
280 ui::AXViewState* state) {
281 state->name = controller_->SuggestedText();
282 state->role = ui::AX_ROLE_MENU_ITEM;
285 } // namespace autofill