Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / ui / views / passwords / manage_password_items_view.cc
blobfdafc261af8820699144c37ab0cd66495f2c6877
1 // Copyright 2013 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/passwords/manage_password_items_view.h"
7 #include <numeric>
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "grit/components_strings.h"
13 #include "ui/base/l10n/l10n_util.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/resources/grit/ui_resources.h"
16 #include "ui/views/controls/button/button.h"
17 #include "ui/views/controls/button/image_button.h"
18 #include "ui/views/controls/label.h"
19 #include "ui/views/controls/link.h"
20 #include "ui/views/controls/link_listener.h"
21 #include "ui/views/layout/fill_layout.h"
22 #include "ui/views/layout/grid_layout.h"
23 #include "ui/views/layout/layout_constants.h"
25 namespace {
27 enum ColumnSets {
28 ONE_COLUMN_SET,
29 TWO_COLUMN_SET,
30 THREE_COLUMN_SET
33 void BuildColumnSetIfNeeded(views::GridLayout* layout, int column_set_id) {
34 if (layout->GetColumnSet(column_set_id))
35 return;
36 views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
38 // The username/"Deleted!"/Border field.
39 column_set->AddColumn(views::GridLayout::FILL,
40 views::GridLayout::FILL,
42 views::GridLayout::USE_PREF,
44 0);
45 if (column_set_id >= TWO_COLUMN_SET) {
46 // The password/"Undo!" field.
47 column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
48 column_set->AddColumn(views::GridLayout::FILL,
49 views::GridLayout::FILL,
51 views::GridLayout::USE_PREF,
53 0);
55 // If we're in manage-mode, we need another column for the delete button.
56 if (column_set_id == THREE_COLUMN_SET) {
57 column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
58 column_set->AddColumn(views::GridLayout::TRAILING,
59 views::GridLayout::FILL,
61 views::GridLayout::USE_PREF,
63 0);
67 scoped_ptr<views::Label> GenerateUsernameLabel(
68 const autofill::PasswordForm& form) {
69 scoped_ptr<views::Label> label(new views::Label(
70 form.username_value.empty()
71 ? l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_EMPTY_LOGIN)
72 : form.username_value));
73 label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
74 ui::ResourceBundle::SmallFont));
75 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
76 return label.Pass();
79 scoped_ptr<views::Label> GeneratePasswordLabel(
80 const autofill::PasswordForm& form) {
81 base::string16 text = form.federation_url.is_empty()
82 ? form.password_value
83 : l10n_util::GetStringFUTF16(
84 IDS_PASSWORDS_VIA_FEDERATION,
85 base::UTF8ToUTF16(form.federation_url.host()));
86 scoped_ptr<views::Label> label(new views::Label(text));
87 label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
88 ui::ResourceBundle::SmallFont));
89 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
90 if (form.federation_url.is_empty())
91 label->SetObscured(true);
92 return label.Pass();
95 scoped_ptr<views::ImageButton> GenerateDeleteButton(
96 views::ButtonListener* listener) {
97 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
98 scoped_ptr<views::ImageButton> button(new views::ImageButton(listener));
99 button->SetImage(views::ImageButton::STATE_NORMAL,
100 rb->GetImageNamed(IDR_CLOSE_2).ToImageSkia());
101 button->SetImage(views::ImageButton::STATE_HOVERED,
102 rb->GetImageNamed(IDR_CLOSE_2_H).ToImageSkia());
103 button->SetImage(views::ImageButton::STATE_PRESSED,
104 rb->GetImageNamed(IDR_CLOSE_2_P).ToImageSkia());
105 return button.Pass();
108 scoped_ptr<views::Label> GenerateDeletedPasswordLabel() {
109 scoped_ptr<views::Label> text(new views::Label(
110 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED)));
111 text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
112 text->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
113 ui::ResourceBundle::SmallFont));
114 return text.Pass();
117 scoped_ptr<views::Link> GenerateUndoLink(views::LinkListener* listener) {
118 scoped_ptr<views::Link> undo_link(new views::Link(
119 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO)));
120 undo_link->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
121 undo_link->set_listener(listener);
122 undo_link->SetUnderline(false);
123 undo_link->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
124 ui::ResourceBundle::SmallFont));
125 return undo_link.Pass();
128 } // namespace
130 // Manage credentials: stores credentials state and adds proper row to layout
131 // based on credential state.
132 class ManagePasswordItemsView::PasswordFormRow : public views::ButtonListener,
133 public views::LinkListener {
134 public:
135 PasswordFormRow(ManagePasswordItemsView* host,
136 const autofill::PasswordForm* password_form,
137 int fixed_height);
138 ~PasswordFormRow() override = default;
140 void AddRow(views::GridLayout* layout);
142 // Returns the fixed height for a row excluding padding. 0 means no fixed
143 // height required.
144 // In MANAGE_STATE a row may represent a credential or a deleted credential.
145 // To avoid repositioning all the rows should have a fixed height.
146 static int GetFixedHeight(password_manager::ui::State state);
148 private:
149 void AddCredentialsRow(views::GridLayout* layout);
150 void AddUndoRow(views::GridLayout* layout);
152 // views::ButtonListener:
153 void ButtonPressed(views::Button* sender, const ui::Event& event) override;
154 // views::LinkListener:
155 void LinkClicked(views::Link* source, int event_flags) override;
157 void ResetControls();
159 ManagePasswordItemsView* host_;
160 const autofill::PasswordForm* password_form_;
161 // The UI elements pointers are weak and owned by their parent.
162 views::Link* undo_link_;
163 views::ImageButton* delete_button_;
164 const int fixed_height_;
165 bool deleted_;
167 DISALLOW_COPY_AND_ASSIGN(PasswordFormRow);
170 ManagePasswordItemsView::PasswordFormRow::PasswordFormRow(
171 ManagePasswordItemsView* host,
172 const autofill::PasswordForm* password_form,
173 int fixed_height)
174 : host_(host),
175 password_form_(password_form),
176 undo_link_(nullptr),
177 delete_button_(nullptr),
178 fixed_height_(fixed_height),
179 deleted_(false) {}
181 void ManagePasswordItemsView::PasswordFormRow::AddRow(
182 views::GridLayout* layout) {
183 if (deleted_) {
184 AddUndoRow(layout);
185 } else {
186 AddCredentialsRow(layout);
190 int ManagePasswordItemsView::PasswordFormRow::GetFixedHeight(
191 password_manager::ui::State state) {
192 if (state != password_manager::ui::MANAGE_STATE)
193 return 0;
194 scoped_ptr<views::ImageButton> delete_button(GenerateDeleteButton(nullptr));
195 scoped_ptr<views::Link> link(GenerateUndoLink(nullptr));
196 scoped_ptr<views::Label> label(GenerateDeletedPasswordLabel());
197 views::View* row_views[] = {delete_button.get(), link.get(), label.get()};
198 return std::accumulate(row_views, row_views + arraysize(row_views), 0,
199 [](int max_height, const views::View* view) {
200 return std::max(max_height, view->GetPreferredSize().height());
204 void ManagePasswordItemsView::PasswordFormRow::AddCredentialsRow(
205 views::GridLayout* layout) {
206 ResetControls();
207 int column_set_id =
208 host_->model_->state() == password_manager::ui::MANAGE_STATE
209 ? THREE_COLUMN_SET
210 : TWO_COLUMN_SET;
211 BuildColumnSetIfNeeded(layout, column_set_id);
212 layout->StartRow(0, column_set_id);
213 layout->AddView(GenerateUsernameLabel(*password_form_).release(), 1, 1,
214 views::GridLayout::FILL, views::GridLayout::FILL,
215 0, fixed_height_);
216 layout->AddView(GeneratePasswordLabel(*password_form_).release(), 1, 1,
217 views::GridLayout::FILL, views::GridLayout::FILL,
218 0, fixed_height_);
219 if (column_set_id == THREE_COLUMN_SET) {
220 delete_button_ = GenerateDeleteButton(this).release();
221 layout->AddView(delete_button_, 1, 1,
222 views::GridLayout::TRAILING, views::GridLayout::FILL,
223 0, fixed_height_);
227 void ManagePasswordItemsView::PasswordFormRow::AddUndoRow(
228 views::GridLayout* layout) {
229 ResetControls();
230 scoped_ptr<views::Label> text = GenerateDeletedPasswordLabel();
231 scoped_ptr<views::Link> undo_link = GenerateUndoLink(this);
232 undo_link_ = undo_link.get();
233 BuildColumnSetIfNeeded(layout, TWO_COLUMN_SET);
234 layout->StartRow(0, TWO_COLUMN_SET);
235 layout->AddView(text.release(), 1, 1,
236 views::GridLayout::FILL, views::GridLayout::FILL,
237 0, fixed_height_);
238 layout->AddView(undo_link.release(), 1, 1,
239 views::GridLayout::FILL, views::GridLayout::FILL,
240 0, fixed_height_);
243 void ManagePasswordItemsView::PasswordFormRow::ButtonPressed(
244 views::Button* sender, const ui::Event& event) {
245 DCHECK_EQ(delete_button_, sender);
246 deleted_ = true;
247 host_->NotifyPasswordFormStatusChanged(*password_form_, deleted_);
250 void ManagePasswordItemsView::PasswordFormRow::LinkClicked(views::Link* sender,
251 int event_flags) {
252 DCHECK_EQ(undo_link_, sender);
253 deleted_ = false;
254 host_->NotifyPasswordFormStatusChanged(*password_form_, deleted_);
257 void ManagePasswordItemsView::PasswordFormRow::ResetControls() {
258 delete_button_ = nullptr;
259 undo_link_ = nullptr;
262 // ManagePasswordItemsView
263 ManagePasswordItemsView::ManagePasswordItemsView(
264 ManagePasswordsBubbleModel* manage_passwords_bubble_model,
265 const std::vector<const autofill::PasswordForm*>& password_forms)
266 : model_(manage_passwords_bubble_model) {
267 int fixed_height = PasswordFormRow::GetFixedHeight(model_->state());
268 for (const autofill::PasswordForm* password_form : password_forms) {
269 password_forms_rows_.push_back(
270 new PasswordFormRow(this, password_form, fixed_height));
272 AddRows();
275 ManagePasswordItemsView::~ManagePasswordItemsView() = default;
277 void ManagePasswordItemsView::AddRows() {
278 views::GridLayout* layout = new views::GridLayout(this);
279 SetLayoutManager(layout);
280 for (auto* row : password_forms_rows_) {
281 if (row != password_forms_rows_[0])
282 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
283 row->AddRow(layout);
285 GetLayoutManager()->Layout(this);
288 void ManagePasswordItemsView::NotifyPasswordFormStatusChanged(
289 const autofill::PasswordForm& password_form, bool deleted) {
290 Refresh();
291 // After the view is consistent, notify the model that the password needs to
292 // be updated (either removed or put back into the store, as appropriate.
293 model_->OnPasswordAction(password_form,
294 deleted
295 ? ManagePasswordsBubbleModel::REMOVE_PASSWORD
296 : ManagePasswordsBubbleModel::ADD_PASSWORD);
299 void ManagePasswordItemsView::Refresh() {
300 DCHECK_NE(password_manager::ui::PENDING_PASSWORD_STATE, model_->state());
301 RemoveAllChildViews(true);
302 AddRows();