manage_password_item_view.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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.
4
5#include "chrome/browser/ui/views/passwords/manage_password_item_view.h"
6
7#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
8#include "chrome/grit/generated_resources.h"
9#include "ui/base/l10n/l10n_util.h"
10#include "ui/base/resource/resource_bundle.h"
11#include "ui/resources/grit/ui_resources.h"
12#include "ui/views/border.h"
13#include "ui/views/controls/button/button.h"
14#include "ui/views/controls/button/image_button.h"
15#include "ui/views/controls/label.h"
16#include "ui/views/controls/link.h"
17#include "ui/views/controls/link_listener.h"
18#include "ui/views/layout/fill_layout.h"
19#include "ui/views/layout/grid_layout.h"
20#include "ui/views/layout/layout_constants.h"
21
22namespace {
23
24enum ColumnSets {
25  TWO_COLUMN_SET,
26  THREE_COLUMN_SET
27};
28
29void BuildColumnSet(views::GridLayout* layout, int column_set_id) {
30  views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
31
32  // The username/"Deleted!" field.
33  column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
34  column_set->AddColumn(views::GridLayout::FILL,
35                        views::GridLayout::FILL,
36                        2,
37                        views::GridLayout::USE_PREF,
38                        0,
39                        0);
40
41  // The password/"Undo!" field.
42  column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
43  column_set->AddColumn(views::GridLayout::FILL,
44                        views::GridLayout::FILL,
45                        1,
46                        views::GridLayout::USE_PREF,
47                        0,
48                        0);
49
50  // If we're in manage-mode, we need another column for the delete button.
51  if (column_set_id == THREE_COLUMN_SET) {
52    column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
53    column_set->AddColumn(views::GridLayout::TRAILING,
54                          views::GridLayout::FILL,
55                          0,
56                          views::GridLayout::USE_PREF,
57                          0,
58                          0);
59  }
60  column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
61}
62
63views::Label* GenerateUsernameLabel(const autofill::PasswordForm& form) {
64  views::Label* label = new views::Label(form.username_value);
65  label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
66      ui::ResourceBundle::SmallFont));
67  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
68  return label;
69}
70
71views::Label* GeneratePasswordLabel(const autofill::PasswordForm& form) {
72  views::Label* label = new views::Label(form.password_value);
73  label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
74      ui::ResourceBundle::SmallFont));
75  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
76  label->SetObscured(true);
77  return label;
78}
79
80}  // namespace
81
82// Render credentials in two columns: username and password.
83class ManagePasswordItemView::PendingView : public views::View {
84 public:
85  explicit PendingView(ManagePasswordItemView* parent);
86
87 private:
88  virtual ~PendingView();
89};
90
91ManagePasswordItemView::PendingView::PendingView(
92    ManagePasswordItemView* parent) {
93  views::GridLayout* layout = new views::GridLayout(this);
94  SetLayoutManager(layout);
95
96  BuildColumnSet(layout, TWO_COLUMN_SET);
97  layout->StartRowWithPadding(
98      0, TWO_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
99  layout->AddView(GenerateUsernameLabel(parent->password_form_));
100  layout->AddView(GeneratePasswordLabel(parent->password_form_));
101  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
102}
103
104ManagePasswordItemView::PendingView::~PendingView() {
105}
106
107// Render credentials in three columns: username, password, and delete.
108class ManagePasswordItemView::ManageView : public views::View,
109                                           public views::ButtonListener {
110 public:
111  explicit ManageView(ManagePasswordItemView* parent);
112
113 private:
114  virtual ~ManageView();
115
116  // views::ButtonListener:
117  virtual void ButtonPressed(views::Button* sender,
118                             const ui::Event& event) OVERRIDE;
119
120  views::ImageButton* delete_button_;
121  ManagePasswordItemView* parent_;
122};
123
124ManagePasswordItemView::ManageView::ManageView(ManagePasswordItemView* parent)
125    : parent_(parent) {
126  views::GridLayout* layout = new views::GridLayout(this);
127  SetLayoutManager(layout);
128
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());
137
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);
145}
146
147ManagePasswordItemView::ManageView::~ManageView() {
148}
149
150void ManagePasswordItemView::ManageView::ButtonPressed(views::Button* sender,
151                                                       const ui::Event& event) {
152  DCHECK_EQ(delete_button_, sender);
153  parent_->NotifyClickedDelete();
154}
155
156// Render a notification to the user that a password has been removed, and
157// offer an undo link.
158class ManagePasswordItemView::UndoView : public views::View,
159                                         public views::LinkListener {
160 public:
161  explicit UndoView(ManagePasswordItemView* parent);
162
163 private:
164  virtual ~UndoView();
165
166  // views::LinkListener:
167  virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
168
169  views::Link* undo_link_;
170  ManagePasswordItemView* parent_;
171};
172
173ManagePasswordItemView::UndoView::UndoView(ManagePasswordItemView* parent)
174    : parent_(parent) {
175  views::GridLayout* layout = new views::GridLayout(this);
176  SetLayoutManager(layout);
177
178  views::Label* text =
179      new views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED));
180  text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
181  text->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
182      ui::ResourceBundle::SmallFont));
183
184  undo_link_ =
185      new views::Link(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO));
186  undo_link_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
187  undo_link_->set_listener(this);
188  undo_link_->SetUnderline(false);
189  undo_link_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
190      ui::ResourceBundle::SmallFont));
191
192  BuildColumnSet(layout, TWO_COLUMN_SET);
193  layout->StartRowWithPadding(
194      0, TWO_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
195  layout->AddView(text);
196  layout->AddView(undo_link_);
197  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
198}
199
200ManagePasswordItemView::UndoView::~UndoView() {
201}
202
203void ManagePasswordItemView::UndoView::LinkClicked(views::Link* sender,
204                                                   int event_flags) {
205  DCHECK_EQ(undo_link_, sender);
206  parent_->NotifyClickedUndo();
207}
208
209// ManagePasswordItemView
210ManagePasswordItemView::ManagePasswordItemView(
211    ManagePasswordsBubbleModel* manage_passwords_bubble_model,
212    const autofill::PasswordForm& password_form,
213    password_manager::ui::PasswordItemPosition position)
214    : model_(manage_passwords_bubble_model),
215      password_form_(password_form),
216      delete_password_(false) {
217  views::FillLayout* layout = new views::FillLayout();
218  SetLayoutManager(layout);
219
220  // When a password is displayed as the first item in a list, it has borders
221  // on both the top and bottom. When it's in the middle of a list, or at the
222  // end, it has a border only on the bottom.
223  SetBorder(views::Border::CreateSolidSidedBorder(
224      position == password_manager::ui::FIRST_ITEM ? 1 : 0,
225      0,
226      1,
227      0,
228      GetNativeTheme()->GetSystemColor(
229          ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
230
231  if (password_manager::ui::IsPendingState(model_->state())) {
232    AddChildView(new PendingView(this));
233  } else {
234    AddChildView(new ManageView(this));
235  }
236  GetLayoutManager()->Layout(this);
237}
238
239ManagePasswordItemView::~ManagePasswordItemView() {
240}
241
242void ManagePasswordItemView::NotifyClickedDelete() {
243  delete_password_ = true;
244  Refresh();
245}
246
247void ManagePasswordItemView::NotifyClickedUndo() {
248  delete_password_ = false;
249  Refresh();
250}
251
252void ManagePasswordItemView::Refresh() {
253  DCHECK(!password_manager::ui::IsPendingState(model_->state()));
254
255  RemoveAllChildViews(true);
256  if (delete_password_)
257    AddChildView(new UndoView(this));
258  else
259    AddChildView(new ManageView(this));
260  GetLayoutManager()->Layout(this);
261
262  // After the view is consistent, notify the model that the password needs to
263  // be updated (either removed or put back into the store, as appropriate.
264  model_->OnPasswordAction(password_form_,
265                           delete_password_
266                               ? ManagePasswordsBubbleModel::REMOVE_PASSWORD
267                               : ManagePasswordsBubbleModel::ADD_PASSWORD);
268}
269