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_passwords_bubble_view.h"
      6 
      7 #include "chrome/browser/chrome_notification_types.h"
      8 #include "chrome/browser/ui/browser.h"
      9 #include "chrome/browser/ui/browser_finder.h"
     10 #include "chrome/browser/ui/browser_window.h"
     11 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
     12 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
     13 #include "chrome/browser/ui/views/frame/browser_view.h"
     14 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
     15 #include "chrome/browser/ui/views/passwords/manage_password_item_view.h"
     16 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_view.h"
     17 #include "components/password_manager/core/common/password_manager_ui.h"
     18 #include "content/public/browser/notification_source.h"
     19 #include "grit/generated_resources.h"
     20 #include "ui/base/l10n/l10n_util.h"
     21 #include "ui/base/models/combobox_model.h"
     22 #include "ui/base/resource/resource_bundle.h"
     23 #include "ui/gfx/text_utils.h"
     24 #include "ui/views/controls/button/blue_button.h"
     25 #include "ui/views/controls/button/label_button.h"
     26 #include "ui/views/controls/combobox/combobox.h"
     27 #include "ui/views/layout/fill_layout.h"
     28 #include "ui/views/layout/grid_layout.h"
     29 #include "ui/views/layout/layout_constants.h"
     30 
     31 
     32 // Helpers --------------------------------------------------------------------
     33 
     34 namespace {
     35 
     36 const int kDesiredBubbleWidth = 370;
     37 
     38 enum ColumnSetType {
     39   // | | (FILL, FILL) | |
     40   // Used for the bubble's header, the credentials list, and for simple
     41   // messages like "No passwords".
     42   SINGLE_VIEW_COLUMN_SET = 0,
     43 
     44   // | | (TRAILING, CENTER) | | (TRAILING, CENTER) | |
     45   // Used for buttons at the bottom of the bubble which should nest at the
     46   // bottom-right corner.
     47   DOUBLE_BUTTON_COLUMN_SET = 1,
     48 
     49   // | | (LEADING, CENTER) | | (TRAILING, CENTER) | |
     50   // Used for buttons at the bottom of the bubble which should occupy
     51   // the corners.
     52   LINK_BUTTON_COLUMN_SET = 2,
     53 };
     54 
     55 // Construct an appropriate ColumnSet for the given |type|, and add it
     56 // to |layout|.
     57 void BuildColumnSet(views::GridLayout* layout, ColumnSetType type) {
     58   views::ColumnSet* column_set = layout->AddColumnSet(type);
     59   column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
     60   int full_width = kDesiredBubbleWidth - (2 * views::kPanelHorizMargin);
     61   switch (type) {
     62     case SINGLE_VIEW_COLUMN_SET:
     63       column_set->AddColumn(views::GridLayout::FILL,
     64                             views::GridLayout::FILL,
     65                             0,
     66                             views::GridLayout::FIXED,
     67                             full_width,
     68                             0);
     69       break;
     70 
     71     case DOUBLE_BUTTON_COLUMN_SET:
     72       column_set->AddColumn(views::GridLayout::TRAILING,
     73                             views::GridLayout::CENTER,
     74                             1,
     75                             views::GridLayout::USE_PREF,
     76                             0,
     77                             0);
     78       column_set->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
     79       column_set->AddColumn(views::GridLayout::TRAILING,
     80                             views::GridLayout::CENTER,
     81                             0,
     82                             views::GridLayout::USE_PREF,
     83                             0,
     84                             0);
     85       break;
     86     case LINK_BUTTON_COLUMN_SET:
     87       column_set->AddColumn(views::GridLayout::LEADING,
     88                             views::GridLayout::CENTER,
     89                             1,
     90                             views::GridLayout::USE_PREF,
     91                             0,
     92                             0);
     93       column_set->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
     94       column_set->AddColumn(views::GridLayout::TRAILING,
     95                             views::GridLayout::CENTER,
     96                             0,
     97                             views::GridLayout::USE_PREF,
     98                             0,
     99                             0);
    100       break;
    101   }
    102   column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
    103 }
    104 
    105 // Given a layout and a model, add an appropriate title using a
    106 // SINGLE_VIEW_COLUMN_SET, followed by a spacer row.
    107 void AddTitleRow(views::GridLayout* layout, ManagePasswordsBubbleModel* model) {
    108   views::Label* title_label = new views::Label(model->title());
    109   title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    110   title_label->SetMultiLine(true);
    111   title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    112       ui::ResourceBundle::MediumFont));
    113 
    114   // Add the title to the layout with appropriate padding.
    115   layout->StartRowWithPadding(
    116       0, SINGLE_VIEW_COLUMN_SET, 0, views::kRelatedControlSmallVerticalSpacing);
    117   layout->AddView(title_label);
    118   layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
    119 }
    120 
    121 }  // namespace
    122 
    123 
    124 // Globals --------------------------------------------------------------------
    125 
    126 namespace chrome {
    127 
    128 void ShowManagePasswordsBubble(content::WebContents* web_contents) {
    129   ManagePasswordsUIController* controller =
    130       ManagePasswordsUIController::FromWebContents(web_contents);
    131   ManagePasswordsBubbleView::ShowBubble(
    132       web_contents,
    133       controller->state() ==
    134               password_manager::ui::PENDING_PASSWORD_AND_BUBBLE_STATE
    135           ? ManagePasswordsBubbleView::AUTOMATIC
    136           : ManagePasswordsBubbleView::USER_ACTION);
    137 }
    138 
    139 }  // namespace chrome
    140 
    141 
    142 // ManagePasswordsBubbleView::PendingView -------------------------------------
    143 
    144 ManagePasswordsBubbleView::PendingView::PendingView(
    145     ManagePasswordsBubbleView* parent)
    146     : parent_(parent) {
    147   views::GridLayout* layout = new views::GridLayout(this);
    148   layout->set_minimum_size(gfx::Size(kDesiredBubbleWidth, 0));
    149   SetLayoutManager(layout);
    150 
    151   // Create the pending credential item, save button and refusal combobox.
    152   ManagePasswordItemView* item =
    153       new ManagePasswordItemView(parent->model(),
    154                                  parent->model()->pending_credentials(),
    155                                  ManagePasswordItemView::FIRST_ITEM);
    156   save_button_ = new views::BlueButton(
    157       this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON));
    158   save_button_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    159       ui::ResourceBundle::SmallFont));
    160 
    161   combobox_model_.reset(new SavePasswordRefusalComboboxModel());
    162   refuse_combobox_.reset(new views::Combobox(combobox_model_.get()));
    163   refuse_combobox_->set_listener(this);
    164   refuse_combobox_->SetStyle(views::Combobox::STYLE_ACTION);
    165   // TODO(mkwst): Need a mechanism to pipe a font list down into a combobox.
    166 
    167   // Title row.
    168   BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
    169   AddTitleRow(layout, parent_->model());
    170 
    171   // Credential row.
    172   layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
    173   layout->AddView(item);
    174 
    175   // Button row.
    176   BuildColumnSet(layout, DOUBLE_BUTTON_COLUMN_SET);
    177   layout->StartRowWithPadding(
    178       0, DOUBLE_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
    179   layout->AddView(save_button_);
    180   layout->AddView(refuse_combobox_.get());
    181 
    182   // Extra padding for visual awesomeness.
    183   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    184 }
    185 
    186 ManagePasswordsBubbleView::PendingView::~PendingView() {
    187 }
    188 
    189 void ManagePasswordsBubbleView::PendingView::ButtonPressed(
    190     views::Button* sender,
    191     const ui::Event& event) {
    192   DCHECK(sender == save_button_);
    193   parent_->model()->OnSaveClicked();
    194   parent_->Close();
    195 }
    196 
    197 void ManagePasswordsBubbleView::PendingView::OnPerformAction(
    198     views::Combobox* source) {
    199   DCHECK_EQ(source, refuse_combobox_);
    200   switch (refuse_combobox_->selected_index()) {
    201     case SavePasswordRefusalComboboxModel::INDEX_NOPE:
    202       parent_->model()->OnNopeClicked();
    203       parent_->Close();
    204       break;
    205     case SavePasswordRefusalComboboxModel::INDEX_NEVER_FOR_THIS_SITE:
    206       parent_->NotifyNeverForThisSiteClicked();
    207       break;
    208   }
    209 }
    210 
    211 // ManagePasswordsBubbleView::ConfirmNeverView ---------------------------------
    212 
    213 ManagePasswordsBubbleView::ConfirmNeverView::ConfirmNeverView(
    214     ManagePasswordsBubbleView* parent)
    215     : parent_(parent) {
    216   views::GridLayout* layout = new views::GridLayout(this);
    217   layout->set_minimum_size(gfx::Size(kDesiredBubbleWidth, 0));
    218   SetLayoutManager(layout);
    219 
    220   // Title row.
    221   BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
    222   views::Label* title_label = new views::Label(l10n_util::GetStringUTF16(
    223       IDS_MANAGE_PASSWORDS_BLACKLIST_CONFIRMATION_TITLE));
    224   title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    225   title_label->SetMultiLine(true);
    226   title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    227       ui::ResourceBundle::MediumFont));
    228   layout->StartRowWithPadding(
    229       0, SINGLE_VIEW_COLUMN_SET, 0, views::kRelatedControlSmallVerticalSpacing);
    230   layout->AddView(title_label);
    231   layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
    232 
    233   // Confirmation text.
    234   views::Label* confirmation = new views::Label(l10n_util::GetStringUTF16(
    235       IDS_MANAGE_PASSWORDS_BLACKLIST_CONFIRMATION_TEXT));
    236   confirmation->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    237   confirmation->SetMultiLine(true);
    238   confirmation->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    239       ui::ResourceBundle::SmallFont));
    240   layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
    241   layout->AddView(confirmation);
    242   layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
    243 
    244   // Confirm and undo buttons.
    245   BuildColumnSet(layout, DOUBLE_BUTTON_COLUMN_SET);
    246   layout->StartRowWithPadding(
    247       0, DOUBLE_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
    248 
    249   confirm_button_ = new views::LabelButton(
    250       this,
    251       l10n_util::GetStringUTF16(
    252           IDS_MANAGE_PASSWORDS_BLACKLIST_CONFIRMATION_BUTTON));
    253   confirm_button_->SetStyle(views::Button::STYLE_BUTTON);
    254   confirm_button_->SetFontList(
    255       ui::ResourceBundle::GetSharedInstance().GetFontList(
    256           ui::ResourceBundle::SmallFont));
    257   layout->AddView(confirm_button_);
    258 
    259   undo_button_ =
    260       new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_CANCEL));
    261   undo_button_->SetStyle(views::Button::STYLE_BUTTON);
    262   undo_button_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    263       ui::ResourceBundle::SmallFont));
    264   layout->AddView(undo_button_);
    265 
    266   // Extra padding for visual awesomeness.
    267   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    268 }
    269 
    270 ManagePasswordsBubbleView::ConfirmNeverView::~ConfirmNeverView() {
    271 }
    272 
    273 void ManagePasswordsBubbleView::ConfirmNeverView::ButtonPressed(
    274     views::Button* sender,
    275     const ui::Event& event) {
    276   DCHECK(sender == confirm_button_ || sender == undo_button_);
    277   if (sender == confirm_button_)
    278     parent_->NotifyConfirmedNeverForThisSite();
    279   else
    280     parent_->NotifyUndoNeverForThisSite();
    281 }
    282 
    283 // ManagePasswordsBubbleView::ManageView --------------------------------------
    284 
    285 ManagePasswordsBubbleView::ManageView::ManageView(
    286     ManagePasswordsBubbleView* parent)
    287     : parent_(parent) {
    288   views::GridLayout* layout = new views::GridLayout(this);
    289   layout->set_minimum_size(gfx::Size(kDesiredBubbleWidth, 0));
    290   SetLayoutManager(layout);
    291 
    292   // Add the title.
    293   BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
    294   AddTitleRow(layout, parent_->model());
    295 
    296   // If we have a list of passwords to store for the current site, display
    297   // them to the user for management. Otherwise, render a "No passwords for
    298   // this site" message.
    299   if (!parent_->model()->best_matches().empty()) {
    300     for (autofill::PasswordFormMap::const_iterator i(
    301              parent_->model()->best_matches().begin());
    302          i != parent_->model()->best_matches().end();
    303          ++i) {
    304       ManagePasswordItemView* item = new ManagePasswordItemView(
    305           parent_->model(),
    306           *i->second,
    307           i == parent_->model()->best_matches().begin()
    308               ? ManagePasswordItemView::FIRST_ITEM
    309               : ManagePasswordItemView::SUBSEQUENT_ITEM);
    310 
    311       layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
    312       layout->AddView(item);
    313     }
    314   } else {
    315     views::Label* empty_label = new views::Label(
    316         l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_NO_PASSWORDS));
    317     empty_label->SetMultiLine(true);
    318     empty_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    319     empty_label->SetFontList(
    320         ui::ResourceBundle::GetSharedInstance().GetFontList(
    321             ui::ResourceBundle::SmallFont));
    322 
    323     layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
    324     layout->AddView(empty_label);
    325     layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
    326   }
    327 
    328   // Then add the "manage passwords" link and "Done" button.
    329   manage_link_ = new views::Link(parent_->model()->manage_link());
    330   manage_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    331   manage_link_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    332       ui::ResourceBundle::SmallFont));
    333   manage_link_->SetUnderline(false);
    334   manage_link_->set_listener(this);
    335 
    336   done_button_ =
    337       new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
    338   done_button_->SetStyle(views::Button::STYLE_BUTTON);
    339   done_button_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    340       ui::ResourceBundle::SmallFont));
    341 
    342   BuildColumnSet(layout, LINK_BUTTON_COLUMN_SET);
    343   layout->StartRowWithPadding(
    344       0, LINK_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
    345   layout->AddView(manage_link_);
    346   layout->AddView(done_button_);
    347 
    348   // Extra padding for visual awesomeness.
    349   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    350 }
    351 
    352 ManagePasswordsBubbleView::ManageView::~ManageView() {
    353 }
    354 
    355 void ManagePasswordsBubbleView::ManageView::ButtonPressed(
    356     views::Button* sender,
    357     const ui::Event& event) {
    358   DCHECK(sender == done_button_);
    359   parent_->model()->OnDoneClicked();
    360   parent_->Close();
    361 }
    362 
    363 void ManagePasswordsBubbleView::ManageView::LinkClicked(views::Link* source,
    364                                                         int event_flags) {
    365   DCHECK_EQ(source, manage_link_);
    366   parent_->model()->OnManageLinkClicked();
    367   parent_->Close();
    368 }
    369 
    370 // ManagePasswordsBubbleView::BlacklistedView ---------------------------------
    371 
    372 ManagePasswordsBubbleView::BlacklistedView::BlacklistedView(
    373     ManagePasswordsBubbleView* parent)
    374     : parent_(parent) {
    375   views::GridLayout* layout = new views::GridLayout(this);
    376   layout->set_minimum_size(gfx::Size(kDesiredBubbleWidth, 0));
    377   SetLayoutManager(layout);
    378 
    379   // Add the title.
    380   BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
    381   AddTitleRow(layout, parent_->model());
    382 
    383   // Add the "Hey! You blacklisted this site!" text.
    384   views::Label* blacklisted = new views::Label(
    385       l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_BLACKLISTED));
    386   blacklisted->SetMultiLine(true);
    387   blacklisted->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    388       ui::ResourceBundle::SmallFont));
    389   layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
    390   layout->AddView(blacklisted);
    391   layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
    392 
    393   // Then add the "enable password manager" and "Done" buttons.
    394   unblacklist_button_ = new views::BlueButton(
    395       this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_UNBLACKLIST_BUTTON));
    396   unblacklist_button_->SetFontList(
    397       ui::ResourceBundle::GetSharedInstance().GetFontList(
    398           ui::ResourceBundle::SmallFont));
    399   done_button_ =
    400       new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
    401   done_button_->SetStyle(views::Button::STYLE_BUTTON);
    402   done_button_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
    403       ui::ResourceBundle::SmallFont));
    404 
    405   BuildColumnSet(layout, DOUBLE_BUTTON_COLUMN_SET);
    406   layout->StartRowWithPadding(
    407       0, DOUBLE_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
    408   layout->AddView(unblacklist_button_);
    409   layout->AddView(done_button_);
    410 
    411   // Extra padding for visual awesomeness.
    412   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    413 }
    414 
    415 ManagePasswordsBubbleView::BlacklistedView::~BlacklistedView() {
    416 }
    417 
    418 void ManagePasswordsBubbleView::BlacklistedView::ButtonPressed(
    419     views::Button* sender,
    420     const ui::Event& event) {
    421   if (sender == done_button_)
    422     parent_->model()->OnDoneClicked();
    423   else if (sender == unblacklist_button_)
    424     parent_->model()->OnUnblacklistClicked();
    425   else
    426     NOTREACHED();
    427   parent_->Close();
    428 }
    429 
    430 // ManagePasswordsBubbleView --------------------------------------------------
    431 
    432 // static
    433 ManagePasswordsBubbleView* ManagePasswordsBubbleView::manage_passwords_bubble_ =
    434     NULL;
    435 
    436 // static
    437 void ManagePasswordsBubbleView::ShowBubble(content::WebContents* web_contents,
    438                                            DisplayReason reason) {
    439   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
    440   DCHECK(browser);
    441   DCHECK(browser->window());
    442   DCHECK(browser->fullscreen_controller());
    443 
    444   if (IsShowing())
    445     return;
    446 
    447   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
    448   bool is_fullscreen = browser_view->IsFullscreen();
    449   ManagePasswordsIconView* anchor_view =
    450       is_fullscreen
    451           ? NULL
    452           : browser_view->GetLocationBarView()->manage_passwords_icon_view();
    453   manage_passwords_bubble_ = new ManagePasswordsBubbleView(
    454       web_contents, anchor_view, reason);
    455 
    456   if (is_fullscreen) {
    457     manage_passwords_bubble_->set_parent_window(
    458         web_contents->GetTopLevelNativeWindow());
    459   }
    460 
    461   views::BubbleDelegateView::CreateBubble(manage_passwords_bubble_);
    462 
    463   // Adjust for fullscreen after creation as it relies on the content size.
    464   if (is_fullscreen) {
    465     manage_passwords_bubble_->AdjustForFullscreen(
    466         browser_view->GetBoundsInScreen());
    467   }
    468   manage_passwords_bubble_->GetWidget()->Show();
    469 }
    470 
    471 // static
    472 void ManagePasswordsBubbleView::CloseBubble() {
    473   if (manage_passwords_bubble_)
    474     manage_passwords_bubble_->Close();
    475 }
    476 
    477 // static
    478 bool ManagePasswordsBubbleView::IsShowing() {
    479   // The bubble may be in the process of closing.
    480   return (manage_passwords_bubble_ != NULL) &&
    481       manage_passwords_bubble_->GetWidget()->IsVisible();
    482 }
    483 
    484 ManagePasswordsBubbleView::ManagePasswordsBubbleView(
    485     content::WebContents* web_contents,
    486     ManagePasswordsIconView* anchor_view,
    487     DisplayReason reason)
    488     : ManagePasswordsBubble(web_contents, reason),
    489       BubbleDelegateView(anchor_view,
    490                          anchor_view ? views::BubbleBorder::TOP_RIGHT
    491                                      : views::BubbleBorder::NONE),
    492       anchor_view_(anchor_view),
    493       never_save_passwords_(false) {
    494   // Compensate for built-in vertical padding in the anchor view's image.
    495   set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
    496   set_notify_enter_exit_on_child(true);
    497   if (anchor_view)
    498     anchor_view->SetActive(true);
    499 }
    500 
    501 ManagePasswordsBubbleView::~ManagePasswordsBubbleView() {
    502   if (anchor_view_)
    503     anchor_view_->SetActive(false);
    504 }
    505 
    506 void ManagePasswordsBubbleView::AdjustForFullscreen(
    507     const gfx::Rect& screen_bounds) {
    508   if (GetAnchorView())
    509     return;
    510 
    511   // The bubble's padding from the screen edge, used in fullscreen.
    512   const int kFullscreenPaddingEnd = 20;
    513   const size_t bubble_half_width = width() / 2;
    514   const int x_pos = base::i18n::IsRTL() ?
    515       screen_bounds.x() + bubble_half_width + kFullscreenPaddingEnd :
    516       screen_bounds.right() - bubble_half_width - kFullscreenPaddingEnd;
    517   SetAnchorRect(gfx::Rect(x_pos, screen_bounds.y(), 0, 0));
    518 }
    519 
    520 void ManagePasswordsBubbleView::Close() {
    521   GetWidget()->Close();
    522 }
    523 
    524 void ManagePasswordsBubbleView::Init() {
    525   views::FillLayout* layout = new views::FillLayout();
    526   SetLayoutManager(layout);
    527   SetFocusable(true);
    528 
    529   Refresh();
    530 }
    531 
    532 void ManagePasswordsBubbleView::WindowClosing() {
    533   // Close() closes the window asynchronously, so by the time we reach here,
    534   // |manage_passwords_bubble_| may have already been reset.
    535   if (manage_passwords_bubble_ == this)
    536     manage_passwords_bubble_ = NULL;
    537 }
    538 
    539 void ManagePasswordsBubbleView::Refresh() {
    540   RemoveAllChildViews(true);
    541   if (password_manager::ui::IsPendingState(model()->state())) {
    542     if (never_save_passwords_)
    543       AddChildView(new ConfirmNeverView(this));
    544     else
    545       AddChildView(new PendingView(this));
    546   } else if (model()->state() == password_manager::ui::BLACKLIST_STATE) {
    547     AddChildView(new BlacklistedView(this));
    548   } else {
    549     AddChildView(new ManageView(this));
    550   }
    551   GetLayoutManager()->Layout(this);
    552 }
    553 
    554 void ManagePasswordsBubbleView::NotifyNeverForThisSiteClicked() {
    555   if (model()->best_matches().empty()) {
    556     // Skip confirmation if there are no existing passwords for this site.
    557     NotifyConfirmedNeverForThisSite();
    558   } else {
    559     never_save_passwords_ = true;
    560     Refresh();
    561   }
    562 }
    563 
    564 void ManagePasswordsBubbleView::NotifyConfirmedNeverForThisSite() {
    565   model()->OnNeverForThisSiteClicked();
    566   Close();
    567 }
    568 
    569 void ManagePasswordsBubbleView::NotifyUndoNeverForThisSite() {
    570   never_save_passwords_ = false;
    571   Refresh();
    572 }
    573