manage_password_item_view.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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 "grit/generated_resources.h"
8#include "grit/ui_resources.h"
9#include "ui/base/l10n/l10n_util.h"
10#include "ui/base/resource/resource_bundle.h"
11#include "ui/views/controls/button/button.h"
12#include "ui/views/controls/button/image_button.h"
13#include "ui/views/layout/grid_layout.h"
14#include "ui/views/layout/layout_constants.h"
15
16ManagePasswordItemView::ManagePasswordItemView(
17    ManagePasswordsBubbleModel* manage_passwords_bubble_model,
18    autofill::PasswordForm password_form,
19    int field_1_width,
20    int field_2_width)
21    : manage_passwords_bubble_model_(manage_passwords_bubble_model),
22      password_form_(password_form),
23      delete_password_(false),
24      field_1_width_(field_1_width),
25      field_2_width_(field_2_width) {
26  views::GridLayout* layout = new views::GridLayout(this);
27  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
28  SetLayoutManager(layout);
29
30  // Build the columnset we need for the current state of the model.
31  int column_set_to_build =
32      !manage_passwords_bubble_model_->WaitingToSavePassword()
33          ? COLUMN_SET_MANAGE
34          : COLUMN_SET_SAVE;
35  BuildColumnSet(layout, column_set_to_build);
36  layout->StartRowWithPadding(
37      0, column_set_to_build, 0, views::kRelatedControlVerticalSpacing);
38
39  // Add the username field: fills the first non-padding column of the layout.
40  label_1_ = new views::Label(password_form_.username_value);
41  label_1_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
42  layout->AddView(label_1_);
43
44  // Add the password field: fills the second non-padding column of the layout.
45  label_2_ =
46      new views::Link(GetPasswordDisplayString(password_form_.password_value));
47  label_2_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
48  label_2_->set_listener(this);
49  label_2_->SetFocusable(false);
50  label_2_->SetEnabled(false);
51  label_2_->SetUnderline(false);
52  layout->AddView(label_2_);
53
54  // If we're managing passwords (that is, we're not currently in the process
55  // of saving a password), construct and add the delete button: fills the
56  // third non-padding column of the layout.
57  if (!manage_passwords_bubble_model_->WaitingToSavePassword()) {
58    delete_button_ = new views::ImageButton(this);
59    delete_button_->SetImage(views::ImageButton::STATE_NORMAL,
60                             rb->GetImageNamed(IDR_CLOSE_2).ToImageSkia());
61    delete_button_->SetImage(views::ImageButton::STATE_HOVERED,
62                             rb->GetImageNamed(IDR_CLOSE_2_H).ToImageSkia());
63    delete_button_->SetImage(views::ImageButton::STATE_PRESSED,
64                             rb->GetImageNamed(IDR_CLOSE_2_P).ToImageSkia());
65    layout->AddView(delete_button_, 1, 1);
66  }
67
68  // Match the padding at the top of the row with padding at the bottom.
69  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
70}
71
72void ManagePasswordItemView::BuildColumnSet(views::GridLayout* layout,
73                                            int column_set_id) {
74  views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
75
76  // The username field.
77  column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
78  column_set->AddColumn(views::GridLayout::FILL,
79                        views::GridLayout::FILL,
80                        0,
81                        views::GridLayout::FIXED,
82                        field_1_width_,
83                        field_1_width_);
84
85  // The password field.
86  column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
87  column_set->AddColumn(views::GridLayout::FILL,
88                        views::GridLayout::FILL,
89                        1,
90                        views::GridLayout::USE_PREF,
91                        field_2_width_,
92                        field_2_width_);
93
94  // If we're in manage-mode, we need another column for the delete button.
95  if (column_set_id == COLUMN_SET_MANAGE) {
96    column_set->AddColumn(views::GridLayout::TRAILING,
97                          views::GridLayout::FILL,
98                          0,
99                          views::GridLayout::USE_PREF,
100                          0,
101                          0);
102  }
103  column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
104}
105
106// static
107base::string16 ManagePasswordItemView::GetPasswordDisplayString(
108    const base::string16& password) {
109  const wchar_t kPasswordBullet = 0x2022;
110  const size_t kMaxPasswordChar = 22;
111  return base::string16(std::min(password.length(), kMaxPasswordChar),
112                  kPasswordBullet);
113}
114
115ManagePasswordItemView::~ManagePasswordItemView() {
116  if (delete_password_)
117    manage_passwords_bubble_model_->DeleteFromBestMatches(password_form_);
118}
119
120void ManagePasswordItemView::Refresh() {
121  // TODO(mkwst): We're currently swaping out values in the same view. We need
122  // to swap out views in order to enable some future work (and to make the undo
123  // button's alignment work correctly).
124
125  if (delete_password_) {
126    // The user clicked the "delete password" button, so:
127    //
128    // Change the username string to "Deleted"
129    label_1_->SetText(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED));
130
131    // Change the password's text to "Undo", and enable the link.
132    label_2_->SetText(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO));
133    label_2_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
134    label_2_->SetEnabled(true);
135    label_2_->SetFocusable(true);
136
137    if (delete_button_)
138      delete_button_->SetVisible(false);
139  } else {
140    // The user clicked the "undo" button after deleting a password, so:
141
142    // Move focus to the parent in order to get the focus ring off the link
143    // that the user just clicked.
144    parent()->RequestFocus();
145
146    // Change the username string back to the username.
147    label_1_->SetText(password_form_.username_value);
148
149    // Set the password string to the appropriate number of bullets, and
150    // disable the link.
151    label_2_->SetText(GetPasswordDisplayString(password_form_.password_value));
152    label_2_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
153    label_2_->SetEnabled(false);
154    label_2_->SetFocusable(false);
155
156    if (delete_button_)
157      delete_button_->SetVisible(true);
158  }
159
160  // After the view is consistent, notify the model that the password needs to
161  // be updated (either removed or put back into the store, as appropriate.
162  manage_passwords_bubble_model_->OnPasswordAction(
163      password_form_,
164      delete_password_ ? ManagePasswordsBubbleModel::REMOVE_PASSWORD
165                       : ManagePasswordsBubbleModel::ADD_PASSWORD);
166}
167
168void ManagePasswordItemView::ButtonPressed(views::Button* sender,
169                                           const ui::Event& event) {
170  DCHECK_EQ(delete_button_, sender);
171  delete_password_ = true;
172  Refresh();
173}
174
175void ManagePasswordItemView::LinkClicked(views::Link* source,
176                                         int event_flags) {
177  DCHECK_EQ(source, label_2_);
178  delete_password_ = false;
179  Refresh();
180}
181