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_item_view.h"
7 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
8 #include "components/password_manager/core/common/password_manager_ui.h"
9 #include "grit/generated_resources.h"
10 #include "grit/ui_resources.h"
11 #include "ui/base/l10n/l10n_util.h"
12 #include "ui/base/resource/resource_bundle.h"
13 #include "ui/views/controls/button/button.h"
14 #include "ui/views/controls/button/image_button.h"
15 #include "ui/views/layout/fill_layout.h"
16 #include "ui/views/layout/grid_layout.h"
17 #include "ui/views/layout/layout_constants.h"
21 enum FieldType
{ USERNAME_FIELD
, PASSWORD_FIELD
};
23 // Upper limit on the size of the username and password fields.
24 const int kUsernameFieldSize
= 30;
25 const int kPasswordFieldSize
= 22;
27 // Returns the width of |type| field.
28 int GetFieldWidth(FieldType type
) {
29 return ui::ResourceBundle::GetSharedInstance()
30 .GetFontList(ui::ResourceBundle::SmallFont
)
31 .GetExpectedTextWidth(type
== USERNAME_FIELD
? kUsernameFieldSize
32 : kPasswordFieldSize
);
35 int FirstFieldWidth() {
37 GetFieldWidth(USERNAME_FIELD
),
38 views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED
))
43 int SecondFieldWidth() {
45 GetFieldWidth(PASSWORD_FIELD
),
46 views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO
))
51 enum ColumnSets
{ TWO_COLUMN_SET
= 0, THREE_COLUMN_SET
};
53 void BuildColumnSet(views::GridLayout
* layout
, int column_set_id
) {
54 views::ColumnSet
* column_set
= layout
->AddColumnSet(column_set_id
);
56 // The username/"Deleted!" field.
57 column_set
->AddPaddingColumn(0, views::kItemLabelSpacing
);
58 column_set
->AddColumn(views::GridLayout::FILL
,
59 views::GridLayout::FILL
,
61 views::GridLayout::FIXED
,
65 // The password/"Undo!" field.
66 column_set
->AddPaddingColumn(0, views::kItemLabelSpacing
);
67 column_set
->AddColumn(views::GridLayout::FILL
,
68 views::GridLayout::FILL
,
70 views::GridLayout::USE_PREF
,
74 // If we're in manage-mode, we need another column for the delete button.
75 if (column_set_id
== THREE_COLUMN_SET
) {
76 column_set
->AddPaddingColumn(0, views::kItemLabelSpacing
);
77 column_set
->AddColumn(views::GridLayout::TRAILING
,
78 views::GridLayout::FILL
,
80 views::GridLayout::USE_PREF
,
84 column_set
->AddPaddingColumn(0, views::kItemLabelSpacing
);
87 views::Label
* GenerateUsernameLabel(const autofill::PasswordForm
& form
) {
88 views::Label
* label
= new views::Label(form
.username_value
);
89 label
->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
90 ui::ResourceBundle::SmallFont
));
91 label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
95 views::Label
* GeneratePasswordLabel(const autofill::PasswordForm
& form
) {
96 views::Label
* label
= new views::Label(form
.password_value
);
97 label
->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
98 ui::ResourceBundle::SmallFont
));
99 label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
100 label
->SetObscured(true);
107 ManagePasswordItemView::PendingView::PendingView(
108 ManagePasswordItemView
* parent
) {
109 views::GridLayout
* layout
= new views::GridLayout(this);
110 SetLayoutManager(layout
);
112 BuildColumnSet(layout
, TWO_COLUMN_SET
);
113 layout
->StartRowWithPadding(
114 0, TWO_COLUMN_SET
, 0, views::kRelatedControlVerticalSpacing
);
115 layout
->AddView(GenerateUsernameLabel(parent
->password_form_
));
116 layout
->AddView(GeneratePasswordLabel(parent
->password_form_
));
117 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
120 ManagePasswordItemView::PendingView::~PendingView() {
124 ManagePasswordItemView::ManageView::ManageView(ManagePasswordItemView
* parent
)
126 views::GridLayout
* layout
= new views::GridLayout(this);
127 SetLayoutManager(layout
);
129 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
130 delete_button_
= new views::ImageButton(this);
131 delete_button_
->SetImage(views::ImageButton::STATE_NORMAL
,
132 rb
->GetImageNamed(IDR_CLOSE_2
).ToImageSkia());
133 delete_button_
->SetImage(views::ImageButton::STATE_HOVERED
,
134 rb
->GetImageNamed(IDR_CLOSE_2_H
).ToImageSkia());
135 delete_button_
->SetImage(views::ImageButton::STATE_PRESSED
,
136 rb
->GetImageNamed(IDR_CLOSE_2_P
).ToImageSkia());
138 BuildColumnSet(layout
, THREE_COLUMN_SET
);
139 layout
->StartRowWithPadding(
140 0, THREE_COLUMN_SET
, 0, views::kRelatedControlVerticalSpacing
);
141 layout
->AddView(GenerateUsernameLabel(parent
->password_form_
));
142 layout
->AddView(GeneratePasswordLabel(parent
->password_form_
));
143 layout
->AddView(delete_button_
);
144 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
147 void ManagePasswordItemView::ManageView::ButtonPressed(views::Button
* sender
,
148 const ui::Event
& event
) {
149 DCHECK_EQ(delete_button_
, sender
);
150 parent_
->NotifyClickedDelete();
153 ManagePasswordItemView::ManageView::~ManageView() {
157 ManagePasswordItemView::UndoView::UndoView(ManagePasswordItemView
* parent
)
159 views::GridLayout
* layout
= new views::GridLayout(this);
160 SetLayoutManager(layout
);
163 new views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED
));
164 text
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
165 text
->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
166 ui::ResourceBundle::SmallFont
));
169 new views::Link(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO
));
170 undo_link_
->SetHorizontalAlignment(gfx::ALIGN_RIGHT
);
171 undo_link_
->set_listener(this);
172 undo_link_
->SetUnderline(false);
173 undo_link_
->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
174 ui::ResourceBundle::SmallFont
));
176 BuildColumnSet(layout
, TWO_COLUMN_SET
);
177 layout
->StartRowWithPadding(
178 0, TWO_COLUMN_SET
, 0, views::kRelatedControlVerticalSpacing
);
179 layout
->AddView(text
);
180 layout
->AddView(undo_link_
);
181 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
184 void ManagePasswordItemView::UndoView::LinkClicked(views::Link
* sender
,
186 DCHECK_EQ(undo_link_
, sender
);
187 parent_
->NotifyClickedUndo();
190 ManagePasswordItemView::UndoView::~UndoView() {
193 // ManagePasswordItemView
194 ManagePasswordItemView::ManagePasswordItemView(
195 ManagePasswordsBubbleModel
* manage_passwords_bubble_model
,
196 autofill::PasswordForm password_form
,
198 : model_(manage_passwords_bubble_model
),
199 password_form_(password_form
),
200 delete_password_(false) {
201 views::FillLayout
* layout
= new views::FillLayout();
202 SetLayoutManager(layout
);
204 // When a password is displayed as the first item in a list, it has borders
205 // on both the top and bottom. When it's in the middle of a list, or at the
206 // end, it has a border only on the bottom.
207 SetBorder(views::Border::CreateSolidSidedBorder(
208 position
== FIRST_ITEM
? 1 : 0,
212 GetNativeTheme()->GetSystemColor(
213 ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor
)));
215 if (password_manager::ui::IsPendingState(model_
->state())) {
216 AddChildView(new PendingView(this));
218 AddChildView(new ManageView(this));
220 GetLayoutManager()->Layout(this);
223 ManagePasswordItemView::~ManagePasswordItemView() {
226 void ManagePasswordItemView::Refresh() {
227 DCHECK(!password_manager::ui::IsPendingState(model_
->state()));
229 RemoveAllChildViews(true);
230 if (delete_password_
)
231 AddChildView(new UndoView(this));
233 AddChildView(new ManageView(this));
234 GetLayoutManager()->Layout(this);
236 // After the view is consistent, notify the model that the password needs to
237 // be updated (either removed or put back into the store, as appropriate.
238 model_
->OnPasswordAction(password_form_
,
240 ? ManagePasswordsBubbleModel::REMOVE_PASSWORD
241 : ManagePasswordsBubbleModel::ADD_PASSWORD
);
244 void ManagePasswordItemView::NotifyClickedDelete() {
245 delete_password_
= true;
249 void ManagePasswordItemView::NotifyClickedUndo() {
250 delete_password_
= false;