[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / ui / views / passwords / manage_passwords_bubble_view.cc
blob2a9414483df432b52acda0d426d19802c6f1f227
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.
5 #include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h"
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"
32 // Helpers --------------------------------------------------------------------
34 namespace {
36 const int kDesiredBubbleWidth = 370;
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,
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,
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,
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 switch (type) {
61 case SINGLE_VIEW_COLUMN_SET:
62 column_set->AddColumn(views::GridLayout::FILL,
63 views::GridLayout::FILL,
65 views::GridLayout::USE_PREF,
67 0);
68 break;
70 case DOUBLE_BUTTON_COLUMN_SET:
71 column_set->AddColumn(views::GridLayout::TRAILING,
72 views::GridLayout::CENTER,
74 views::GridLayout::USE_PREF,
76 0);
77 column_set->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
78 column_set->AddColumn(views::GridLayout::TRAILING,
79 views::GridLayout::CENTER,
81 views::GridLayout::USE_PREF,
83 0);
84 break;
85 case LINK_BUTTON_COLUMN_SET:
86 column_set->AddColumn(views::GridLayout::LEADING,
87 views::GridLayout::CENTER,
89 views::GridLayout::USE_PREF,
91 0);
92 column_set->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
93 column_set->AddColumn(views::GridLayout::TRAILING,
94 views::GridLayout::CENTER,
96 views::GridLayout::USE_PREF,
98 0);
99 break;
101 column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
104 // Given a layout and a model, add an appropriate title using a
105 // SINGLE_VIEW_COLUMN_SET, followed by a spacer row.
106 void AddTitleRow(views::GridLayout* layout, ManagePasswordsBubbleModel* model) {
107 views::Label* title_label = new views::Label(model->title());
108 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
109 title_label->SetMultiLine(true);
110 title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
111 ui::ResourceBundle::MediumFont));
113 // Add the title to the layout with appropriate padding.
114 layout->StartRowWithPadding(
115 0, SINGLE_VIEW_COLUMN_SET, 0, views::kRelatedControlSmallVerticalSpacing);
116 layout->AddView(title_label);
117 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
120 } // namespace
123 // Globals --------------------------------------------------------------------
125 namespace chrome {
127 void ShowManagePasswordsBubble(content::WebContents* web_contents) {
128 ManagePasswordsUIController* controller =
129 ManagePasswordsUIController::FromWebContents(web_contents);
130 ManagePasswordsBubbleView::ShowBubble(
131 web_contents,
132 controller->state() ==
133 password_manager::ui::PENDING_PASSWORD_AND_BUBBLE_STATE
134 ? ManagePasswordsBubbleView::AUTOMATIC
135 : ManagePasswordsBubbleView::USER_ACTION);
138 } // namespace chrome
141 // ManagePasswordsBubbleView::PendingView -------------------------------------
143 ManagePasswordsBubbleView::PendingView::PendingView(
144 ManagePasswordsBubbleView* parent)
145 : parent_(parent) {
146 views::GridLayout* layout = new views::GridLayout(this);
147 layout->set_minimum_size(gfx::Size(kDesiredBubbleWidth, 0));
148 SetLayoutManager(layout);
150 // Create the pending credential item, save button and refusal combobox.
151 ManagePasswordItemView* item =
152 new ManagePasswordItemView(parent->model(),
153 parent->model()->pending_credentials(),
154 ManagePasswordItemView::FIRST_ITEM);
155 save_button_ = new views::BlueButton(
156 this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON));
157 save_button_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
158 ui::ResourceBundle::SmallFont));
160 combobox_model_.reset(new SavePasswordRefusalComboboxModel());
161 refuse_combobox_.reset(new views::Combobox(combobox_model_.get()));
162 refuse_combobox_->set_listener(this);
163 refuse_combobox_->SetStyle(views::Combobox::STYLE_ACTION);
164 // TODO(mkwst): Need a mechanism to pipe a font list down into a combobox.
166 // Title row.
167 BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
168 AddTitleRow(layout, parent_->model());
170 // Credential row.
171 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
172 layout->AddView(item);
174 // Button row.
175 BuildColumnSet(layout, DOUBLE_BUTTON_COLUMN_SET);
176 layout->StartRowWithPadding(
177 0, DOUBLE_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
178 layout->AddView(save_button_);
179 layout->AddView(refuse_combobox_.get());
181 // Extra padding for visual awesomeness.
182 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
185 ManagePasswordsBubbleView::PendingView::~PendingView() {
188 void ManagePasswordsBubbleView::PendingView::ButtonPressed(
189 views::Button* sender,
190 const ui::Event& event) {
191 DCHECK(sender == save_button_);
192 parent_->model()->OnSaveClicked();
193 parent_->Close();
196 void ManagePasswordsBubbleView::PendingView::OnPerformAction(
197 views::Combobox* source) {
198 DCHECK_EQ(source, refuse_combobox_);
199 switch (refuse_combobox_->selected_index()) {
200 case SavePasswordRefusalComboboxModel::INDEX_NOPE:
201 parent_->model()->OnNopeClicked();
202 break;
203 case SavePasswordRefusalComboboxModel::INDEX_NEVER_FOR_THIS_SITE:
204 parent_->model()->OnNeverForThisSiteClicked();
205 break;
207 parent_->Close();
210 // ManagePasswordsBubbleView::ManageView --------------------------------------
212 ManagePasswordsBubbleView::ManageView::ManageView(
213 ManagePasswordsBubbleView* parent)
214 : parent_(parent) {
215 views::GridLayout* layout = new views::GridLayout(this);
216 layout->set_minimum_size(gfx::Size(kDesiredBubbleWidth, 0));
217 SetLayoutManager(layout);
219 // Add the title.
220 BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
221 AddTitleRow(layout, parent_->model());
223 // If we have a list of passwords to store for the current site, display
224 // them to the user for management. Otherwise, render a "No passwords for
225 // this site" message.
226 if (!parent_->model()->best_matches().empty()) {
227 for (autofill::PasswordFormMap::const_iterator i(
228 parent_->model()->best_matches().begin());
229 i != parent_->model()->best_matches().end();
230 ++i) {
231 ManagePasswordItemView* item = new ManagePasswordItemView(
232 parent_->model(),
233 *i->second,
234 i == parent_->model()->best_matches().begin()
235 ? ManagePasswordItemView::FIRST_ITEM
236 : ManagePasswordItemView::SUBSEQUENT_ITEM);
238 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
239 layout->AddView(item);
241 } else {
242 views::Label* empty_label = new views::Label(
243 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_NO_PASSWORDS));
244 empty_label->SetMultiLine(true);
245 empty_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
246 empty_label->SetFontList(
247 ui::ResourceBundle::GetSharedInstance().GetFontList(
248 ui::ResourceBundle::SmallFont));
250 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
251 layout->AddView(empty_label);
252 layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
255 // Then add the "manage passwords" link and "Done" button.
256 manage_link_ = new views::Link(parent_->model()->manage_link());
257 manage_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
258 manage_link_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
259 ui::ResourceBundle::SmallFont));
260 manage_link_->SetUnderline(false);
261 manage_link_->set_listener(this);
263 done_button_ =
264 new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
265 done_button_->SetStyle(views::Button::STYLE_BUTTON);
266 done_button_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
267 ui::ResourceBundle::SmallFont));
269 BuildColumnSet(layout, LINK_BUTTON_COLUMN_SET);
270 layout->StartRowWithPadding(
271 0, LINK_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
272 layout->AddView(manage_link_);
273 layout->AddView(done_button_);
275 // Extra padding for visual awesomeness.
276 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
279 ManagePasswordsBubbleView::ManageView::~ManageView() {
282 void ManagePasswordsBubbleView::ManageView::ButtonPressed(
283 views::Button* sender,
284 const ui::Event& event) {
285 DCHECK(sender == done_button_);
286 parent_->model()->OnDoneClicked();
287 parent_->Close();
290 void ManagePasswordsBubbleView::ManageView::LinkClicked(views::Link* source,
291 int event_flags) {
292 DCHECK_EQ(source, manage_link_);
293 parent_->model()->OnManageLinkClicked();
294 parent_->Close();
297 // ManagePasswordsBubbleView::BlacklistedView ---------------------------------
299 ManagePasswordsBubbleView::BlacklistedView::BlacklistedView(
300 ManagePasswordsBubbleView* parent)
301 : parent_(parent) {
302 views::GridLayout* layout = new views::GridLayout(this);
303 layout->set_minimum_size(gfx::Size(kDesiredBubbleWidth, 0));
304 SetLayoutManager(layout);
306 // Add the title.
307 BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
308 AddTitleRow(layout, parent_->model());
310 // Add the "Hey! You blacklisted this site!" text.
311 views::Label* blacklisted = new views::Label(
312 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_BLACKLISTED));
313 blacklisted->SetMultiLine(true);
314 blacklisted->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
315 ui::ResourceBundle::SmallFont));
316 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
317 layout->AddView(blacklisted);
318 layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
320 // Then add the "enable password manager" and "Done" buttons.
321 unblacklist_button_ = new views::BlueButton(
322 this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_UNBLACKLIST_BUTTON));
323 unblacklist_button_->SetFontList(
324 ui::ResourceBundle::GetSharedInstance().GetFontList(
325 ui::ResourceBundle::SmallFont));
326 done_button_ =
327 new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
328 done_button_->SetStyle(views::Button::STYLE_BUTTON);
329 done_button_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
330 ui::ResourceBundle::SmallFont));
332 BuildColumnSet(layout, DOUBLE_BUTTON_COLUMN_SET);
333 layout->StartRowWithPadding(
334 0, DOUBLE_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
335 layout->AddView(unblacklist_button_);
336 layout->AddView(done_button_);
338 // Extra padding for visual awesomeness.
339 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
342 ManagePasswordsBubbleView::BlacklistedView::~BlacklistedView() {
345 void ManagePasswordsBubbleView::BlacklistedView::ButtonPressed(
346 views::Button* sender,
347 const ui::Event& event) {
348 if (sender == done_button_)
349 parent_->model()->OnDoneClicked();
350 else if (sender == unblacklist_button_)
351 parent_->model()->OnUnblacklistClicked();
352 else
353 NOTREACHED();
354 parent_->Close();
357 // ManagePasswordsBubbleView --------------------------------------------------
359 // static
360 ManagePasswordsBubbleView* ManagePasswordsBubbleView::manage_passwords_bubble_ =
361 NULL;
363 // static
364 void ManagePasswordsBubbleView::ShowBubble(content::WebContents* web_contents,
365 DisplayReason reason) {
366 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
367 DCHECK(browser);
368 DCHECK(browser->window());
369 DCHECK(browser->fullscreen_controller());
371 if (IsShowing())
372 return;
374 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
375 bool is_fullscreen = browser_view->IsFullscreen();
376 views::View* anchor_view = is_fullscreen ?
377 NULL : browser_view->GetLocationBarView()->manage_passwords_icon_view();
378 manage_passwords_bubble_ = new ManagePasswordsBubbleView(
379 web_contents, anchor_view, reason);
381 if (is_fullscreen) {
382 manage_passwords_bubble_->set_parent_window(
383 web_contents->GetTopLevelNativeWindow());
386 views::BubbleDelegateView::CreateBubble(manage_passwords_bubble_);
388 // Adjust for fullscreen after creation as it relies on the content size.
389 if (is_fullscreen) {
390 manage_passwords_bubble_->AdjustForFullscreen(
391 browser_view->GetBoundsInScreen());
394 manage_passwords_bubble_->GetWidget()->Show();
397 // static
398 void ManagePasswordsBubbleView::CloseBubble() {
399 if (manage_passwords_bubble_)
400 manage_passwords_bubble_->Close();
403 // static
404 bool ManagePasswordsBubbleView::IsShowing() {
405 // The bubble may be in the process of closing.
406 return (manage_passwords_bubble_ != NULL) &&
407 manage_passwords_bubble_->GetWidget()->IsVisible();
410 ManagePasswordsBubbleView::ManagePasswordsBubbleView(
411 content::WebContents* web_contents,
412 views::View* anchor_view,
413 DisplayReason reason)
414 : ManagePasswordsBubble(web_contents, reason),
415 BubbleDelegateView(anchor_view,
416 anchor_view ? views::BubbleBorder::TOP_RIGHT
417 : views::BubbleBorder::NONE) {
418 // Compensate for built-in vertical padding in the anchor view's image.
419 set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
420 set_notify_enter_exit_on_child(true);
423 ManagePasswordsBubbleView::~ManagePasswordsBubbleView() {}
425 void ManagePasswordsBubbleView::AdjustForFullscreen(
426 const gfx::Rect& screen_bounds) {
427 if (GetAnchorView())
428 return;
430 // The bubble's padding from the screen edge, used in fullscreen.
431 const int kFullscreenPaddingEnd = 20;
432 const size_t bubble_half_width = width() / 2;
433 const int x_pos = base::i18n::IsRTL() ?
434 screen_bounds.x() + bubble_half_width + kFullscreenPaddingEnd :
435 screen_bounds.right() - bubble_half_width - kFullscreenPaddingEnd;
436 SetAnchorRect(gfx::Rect(x_pos, screen_bounds.y(), 0, 0));
439 void ManagePasswordsBubbleView::Close() {
440 GetWidget()->Close();
443 void ManagePasswordsBubbleView::Init() {
444 views::FillLayout* layout = new views::FillLayout();
445 SetLayoutManager(layout);
446 SetFocusable(true);
448 if (password_manager::ui::IsPendingState(model()->state()))
449 AddChildView(new PendingView(this));
450 else if (model()->state() == password_manager::ui::BLACKLIST_STATE)
451 AddChildView(new BlacklistedView(this));
452 else
453 AddChildView(new ManageView(this));
456 void ManagePasswordsBubbleView::WindowClosing() {
457 // Close() closes the window asynchronously, so by the time we reach here,
458 // |manage_passwords_bubble_| may have already been reset.
459 if (manage_passwords_bubble_ == this)
460 manage_passwords_bubble_ = NULL;