f8f08d6fbd6dae7c821836692877af401d427336
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / passwords / manage_passwords_bubble_view.cc
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   manage_passwords_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
470 }
471
472 // static
473 void ManagePasswordsBubbleView::CloseBubble() {
474   if (manage_passwords_bubble_)
475     manage_passwords_bubble_->Close();
476 }
477
478 // static
479 bool ManagePasswordsBubbleView::IsShowing() {
480   // The bubble may be in the process of closing.
481   return (manage_passwords_bubble_ != NULL) &&
482       manage_passwords_bubble_->GetWidget()->IsVisible();
483 }
484
485 ManagePasswordsBubbleView::ManagePasswordsBubbleView(
486     content::WebContents* web_contents,
487     ManagePasswordsIconView* anchor_view,
488     DisplayReason reason)
489     : ManagePasswordsBubble(web_contents, reason),
490       BubbleDelegateView(anchor_view,
491                          anchor_view ? views::BubbleBorder::TOP_RIGHT
492                                      : views::BubbleBorder::NONE),
493       anchor_view_(anchor_view),
494       never_save_passwords_(false) {
495   // Compensate for built-in vertical padding in the anchor view's image.
496   set_anchor_view_insets(gfx::Insets(2, 0, 2, 0));
497   set_notify_enter_exit_on_child(true);
498   if (anchor_view)
499     anchor_view->SetActive(true);
500 }
501
502 ManagePasswordsBubbleView::~ManagePasswordsBubbleView() {
503   if (anchor_view_)
504     anchor_view_->SetActive(false);
505 }
506
507 void ManagePasswordsBubbleView::AdjustForFullscreen(
508     const gfx::Rect& screen_bounds) {
509   if (GetAnchorView())
510     return;
511
512   // The bubble's padding from the screen edge, used in fullscreen.
513   const int kFullscreenPaddingEnd = 20;
514   const size_t bubble_half_width = width() / 2;
515   const int x_pos = base::i18n::IsRTL() ?
516       screen_bounds.x() + bubble_half_width + kFullscreenPaddingEnd :
517       screen_bounds.right() - bubble_half_width - kFullscreenPaddingEnd;
518   SetAnchorRect(gfx::Rect(x_pos, screen_bounds.y(), 0, 0));
519 }
520
521 void ManagePasswordsBubbleView::Close() {
522   GetWidget()->Close();
523 }
524
525 void ManagePasswordsBubbleView::Init() {
526   views::FillLayout* layout = new views::FillLayout();
527   SetLayoutManager(layout);
528   SetFocusable(true);
529
530   Refresh();
531 }
532
533 void ManagePasswordsBubbleView::WindowClosing() {
534   // Close() closes the window asynchronously, so by the time we reach here,
535   // |manage_passwords_bubble_| may have already been reset.
536   if (manage_passwords_bubble_ == this)
537     manage_passwords_bubble_ = NULL;
538 }
539
540 void ManagePasswordsBubbleView::Refresh() {
541   RemoveAllChildViews(true);
542   if (password_manager::ui::IsPendingState(model()->state())) {
543     if (never_save_passwords_)
544       AddChildView(new ConfirmNeverView(this));
545     else
546       AddChildView(new PendingView(this));
547   } else if (model()->state() == password_manager::ui::BLACKLIST_STATE) {
548     AddChildView(new BlacklistedView(this));
549   } else {
550     AddChildView(new ManageView(this));
551   }
552   GetLayoutManager()->Layout(this);
553 }
554
555 void ManagePasswordsBubbleView::NotifyNeverForThisSiteClicked() {
556   if (model()->best_matches().empty()) {
557     // Skip confirmation if there are no existing passwords for this site.
558     NotifyConfirmedNeverForThisSite();
559   } else {
560     never_save_passwords_ = true;
561     Refresh();
562   }
563 }
564
565 void ManagePasswordsBubbleView::NotifyConfirmedNeverForThisSite() {
566   model()->OnNeverForThisSiteClicked();
567   Close();
568 }
569
570 void ManagePasswordsBubbleView::NotifyUndoNeverForThisSite() {
571   never_save_passwords_ = false;
572   Refresh();
573 }