Home | History | Annotate | Download | only in passwords
      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 "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"
     18 
     19 namespace {
     20 
     21 enum FieldType { USERNAME_FIELD, PASSWORD_FIELD };
     22 
     23 // Upper limit on the size of the username and password fields.
     24 const int kUsernameFieldSize = 30;
     25 const int kPasswordFieldSize = 22;
     26 
     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);
     33 }
     34 
     35 int FirstFieldWidth() {
     36   return std::max(
     37       GetFieldWidth(USERNAME_FIELD),
     38       views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED))
     39           .GetPreferredSize()
     40           .width());
     41 }
     42 
     43 int SecondFieldWidth() {
     44   return std::max(
     45       GetFieldWidth(PASSWORD_FIELD),
     46       views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO))
     47           .GetPreferredSize()
     48           .width());
     49 }
     50 
     51 enum ColumnSets { TWO_COLUMN_SET = 0, THREE_COLUMN_SET };
     52 
     53 void BuildColumnSet(views::GridLayout* layout, int column_set_id) {
     54   views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
     55 
     56   // The username/"Deleted!" field.
     57   column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
     58   column_set->AddColumn(views::GridLayout::FILL,
     59                         views::GridLayout::FILL,
     60                         0,
     61                         views::GridLayout::FIXED,
     62                         FirstFieldWidth(),
     63                         FirstFieldWidth());
     64 
     65   // The password/"Undo!" field.
     66   column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
     67   column_set->AddColumn(views::GridLayout::FILL,
     68                         views::GridLayout::FILL,
     69                         1,
     70                         views::GridLayout::USE_PREF,
     71                         SecondFieldWidth(),
     72                         SecondFieldWidth());
     73 
     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,
     79                           0,
     80                           views::GridLayout::USE_PREF,
     81                           0,
     82                           0);
     83   }
     84   column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
     85 }
     86 
     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);
     92   return label;
     93 }
     94 
     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);
    101   return label;
    102 }
    103 
    104 }  // namespace
    105 
    106 // Pending View
    107 ManagePasswordItemView::PendingView::PendingView(
    108     ManagePasswordItemView* parent) {
    109   views::GridLayout* layout = new views::GridLayout(this);
    110   SetLayoutManager(layout);
    111 
    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);
    118 }
    119 
    120 ManagePasswordItemView::PendingView::~PendingView() {
    121 }
    122 
    123 // Manage View
    124 ManagePasswordItemView::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 
    147 void ManagePasswordItemView::ManageView::ButtonPressed(views::Button* sender,
    148                                                        const ui::Event& event) {
    149   DCHECK_EQ(delete_button_, sender);
    150   parent_->NotifyClickedDelete();
    151 }
    152 
    153 ManagePasswordItemView::ManageView::~ManageView() {
    154 }
    155 
    156 // Undo View
    157 ManagePasswordItemView::UndoView::UndoView(ManagePasswordItemView* parent)
    158     : parent_(parent) {
    159   views::GridLayout* layout = new views::GridLayout(this);
    160   SetLayoutManager(layout);
    161 
    162   views::Label* text =
    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));
    167 
    168   undo_link_ =
    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));
    175 
    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);
    182 }
    183 
    184 void ManagePasswordItemView::UndoView::LinkClicked(views::Link* sender,
    185                                                    int event_flags) {
    186   DCHECK_EQ(undo_link_, sender);
    187   parent_->NotifyClickedUndo();
    188 }
    189 
    190 ManagePasswordItemView::UndoView::~UndoView() {
    191 }
    192 
    193 // ManagePasswordItemView
    194 ManagePasswordItemView::ManagePasswordItemView(
    195     ManagePasswordsBubbleModel* manage_passwords_bubble_model,
    196     autofill::PasswordForm password_form,
    197     Position position)
    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);
    203 
    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,
    209       0,
    210       1,
    211       0,
    212       GetNativeTheme()->GetSystemColor(
    213           ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
    214 
    215   if (password_manager::ui::IsPendingState(model_->state())) {
    216     AddChildView(new PendingView(this));
    217   } else {
    218     AddChildView(new ManageView(this));
    219   }
    220   GetLayoutManager()->Layout(this);
    221 }
    222 
    223 ManagePasswordItemView::~ManagePasswordItemView() {
    224 }
    225 
    226 void ManagePasswordItemView::Refresh() {
    227   DCHECK(!password_manager::ui::IsPendingState(model_->state()));
    228 
    229   RemoveAllChildViews(true);
    230   if (delete_password_)
    231     AddChildView(new UndoView(this));
    232   else
    233     AddChildView(new ManageView(this));
    234   GetLayoutManager()->Layout(this);
    235 
    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_,
    239                            delete_password_
    240                                ? ManagePasswordsBubbleModel::REMOVE_PASSWORD
    241                                : ManagePasswordsBubbleModel::ADD_PASSWORD);
    242 }
    243 
    244 void ManagePasswordItemView::NotifyClickedDelete() {
    245   delete_password_ = true;
    246   Refresh();
    247 }
    248 
    249 void ManagePasswordItemView::NotifyClickedUndo() {
    250   delete_password_ = false;
    251   Refresh();
    252 }
    253