blob: 4a38203cbba7d5918d044a7d1e9634014080bdd5 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "chrome/browser/ui/views/passwords/manage_password_item_view.h"
#include "chrome/browser/ui/views/passwords/manage_passwords_icon_view.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents_view.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/views/controls/button/blue_button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_constants.h"
// Helpers --------------------------------------------------------------------
namespace {
// Updates either the biggest possible width for the username field in the
// manage passwords bubble or the biggest possible width for the password field.
void UpdateBiggestWidth(const autofill::PasswordForm& password_form,
bool username,
int* biggest_width) {
ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
gfx::FontList font_list(rb->GetFontList(ui::ResourceBundle::BaseFont));
base::string16 display_string(username ?
password_form.username_value :
ManagePasswordItemView::GetPasswordDisplayString(
password_form.password_value));
*biggest_width = std::max(
gfx::Canvas::GetStringWidth(display_string, font_list), *biggest_width);
}
} // namespace
// ManagePasswordsBubbleView --------------------------------------------------
// static
ManagePasswordsBubbleView* ManagePasswordsBubbleView::manage_passwords_bubble_ =
NULL;
// static
void ManagePasswordsBubbleView::ShowBubble(content::WebContents* web_contents,
ManagePasswordsIconView* icon_view) {
Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
DCHECK(browser);
DCHECK(browser->window());
DCHECK(browser->fullscreen_controller());
DCHECK(!IsShowing());
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
bool is_fullscreen = browser_view->IsFullscreen();
views::View* anchor_view = is_fullscreen ?
NULL : browser_view->GetLocationBarView()->manage_passwords_icon_view();
manage_passwords_bubble_ =
new ManagePasswordsBubbleView(web_contents, anchor_view, icon_view);
if (is_fullscreen) {
manage_passwords_bubble_->set_parent_window(
web_contents->GetView()->GetTopLevelNativeWindow());
}
views::BubbleDelegateView::CreateBubble(manage_passwords_bubble_);
// Adjust for fullscreen after creation as it relies on the content size.
if (is_fullscreen) {
manage_passwords_bubble_->AdjustForFullscreen(
browser_view->GetBoundsInScreen());
}
manage_passwords_bubble_->GetWidget()->Show();
}
// static
void ManagePasswordsBubbleView::CloseBubble() {
if (manage_passwords_bubble_)
manage_passwords_bubble_->Close();
}
// static
bool ManagePasswordsBubbleView::IsShowing() {
// The bubble may be in the process of closing.
return (manage_passwords_bubble_ != NULL) &&
manage_passwords_bubble_->GetWidget()->IsVisible();
}
ManagePasswordsBubbleView::ManagePasswordsBubbleView(
content::WebContents* web_contents,
views::View* anchor_view,
ManagePasswordsIconView* icon_view)
: BubbleDelegateView(
anchor_view,
anchor_view ?
views::BubbleBorder::TOP_RIGHT : views::BubbleBorder::NONE),
manage_passwords_bubble_model_(
new ManagePasswordsBubbleModel(web_contents)),
icon_view_(icon_view) {
// Compensate for built-in vertical padding in the anchor view's image.
set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
set_notify_enter_exit_on_child(true);
}
ManagePasswordsBubbleView::~ManagePasswordsBubbleView() {}
int ManagePasswordsBubbleView::GetMaximumUsernameOrPasswordWidth(
bool username) {
int biggest_width = 0;
if (manage_passwords_bubble_model_->manage_passwords_bubble_state() !=
ManagePasswordsBubbleModel::PASSWORD_TO_BE_SAVED) {
// If we are in the PASSWORD_TO_BE_SAVED state we only display the
// password that was just submitted and should not take these into account.
for (autofill::PasswordFormMap::const_iterator i(
manage_passwords_bubble_model_->best_matches().begin());
i != manage_passwords_bubble_model_->best_matches().end(); ++i) {
UpdateBiggestWidth((*i->second), username, &biggest_width);
}
}
if (manage_passwords_bubble_model_->password_submitted()) {
UpdateBiggestWidth(manage_passwords_bubble_model_->pending_credentials(),
username, &biggest_width);
}
return biggest_width;
}
void ManagePasswordsBubbleView::AdjustForFullscreen(
const gfx::Rect& screen_bounds) {
if (GetAnchorView())
return;
// The bubble's padding from the screen edge, used in fullscreen.
const int kFullscreenPaddingEnd = 20;
const size_t bubble_half_width = width() / 2;
const int x_pos = base::i18n::IsRTL() ?
screen_bounds.x() + bubble_half_width + kFullscreenPaddingEnd :
screen_bounds.right() - bubble_half_width - kFullscreenPaddingEnd;
SetAnchorRect(gfx::Rect(x_pos, screen_bounds.y(), 0, 0));
}
void ManagePasswordsBubbleView::Close() {
GetWidget()->Close();
}
void ManagePasswordsBubbleView::Init() {
using views::GridLayout;
GridLayout* layout = new GridLayout(this);
SetLayoutManager(layout);
// This calculates the necessary widths for the list of credentials in the
// bubble. We do not need to clamp the password field width because
// ManagePasswordItemView::GetPasswordFisplayString() does this.
ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
const int predefined_username_field_max_width =
rb->GetFont(ui::ResourceBundle::BaseFont).GetAverageCharacterWidth() * 22;
const int max_username_or_password_width =
std::min(GetMaximumUsernameOrPasswordWidth(true),
predefined_username_field_max_width);
const int first_field_width = std::max(max_username_or_password_width,
views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED)).
GetPreferredSize().width());
const int second_field_width = std::max(
GetMaximumUsernameOrPasswordWidth(false),
views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO)).
GetPreferredSize().width());
const int kSingleColumnSetId = 0;
views::ColumnSet* column_set = layout->AddColumnSet(kSingleColumnSetId);
column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
GridLayout::USE_PREF, 0, 0);
column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
views::Label* title_label =
new views::Label(manage_passwords_bubble_model_->title());
title_label->SetMultiLine(true);
title_label->SetFontList(rb->GetFontList(ui::ResourceBundle::MediumFont));
layout->StartRowWithPadding(0, kSingleColumnSetId,
0, views::kRelatedControlSmallVerticalSpacing);
layout->AddView(title_label);
layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
if (manage_passwords_bubble_model_->manage_passwords_bubble_state() ==
ManagePasswordsBubbleModel::PASSWORD_TO_BE_SAVED) {
const int kSingleColumnCredentialsId = 1;
views::ColumnSet* single_column =
layout->AddColumnSet(kSingleColumnCredentialsId);
single_column->AddPaddingColumn(0, views::kPanelHorizMargin);
single_column->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
GridLayout::USE_PREF, 0, 0);
single_column->AddPaddingColumn(0, views::kPanelHorizMargin);
layout->StartRow(0, kSingleColumnCredentialsId);
ManagePasswordItemView* item = new ManagePasswordItemView(
manage_passwords_bubble_model_,
manage_passwords_bubble_model_->pending_credentials(),
first_field_width, second_field_width);
item->set_border(views::Border::CreateSolidSidedBorder(
1, 0, 1, 0, GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
layout->AddView(item);
const int kDoubleColumnSetId = 2;
views::ColumnSet* double_column_set =
layout->AddColumnSet(kDoubleColumnSetId);
double_column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
double_column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 1,
GridLayout::USE_PREF, 0, 0);
double_column_set->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
double_column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
GridLayout::USE_PREF, 0, 0);
double_column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
cancel_button_ = new views::LabelButton(
this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_CANCEL_BUTTON));
cancel_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
save_button_ = new views::BlueButton(
this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON));
layout->StartRowWithPadding(0, kDoubleColumnSetId,
0, views::kRelatedControlVerticalSpacing);
layout->AddView(save_button_);
layout->AddView(cancel_button_);
layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
} else {
const int kSingleButtonSetId = 3;
views::ColumnSet* single_column_set =
layout->AddColumnSet(kSingleButtonSetId);
single_column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
single_column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
GridLayout::USE_PREF, 0, 0);
single_column_set->AddPaddingColumn(0,
views::kUnrelatedControlHorizontalSpacing);
single_column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
GridLayout::USE_PREF, 0, 0);
single_column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
const int kSingleColumnCredentialsId = 1;
views::ColumnSet* single_column =
layout->AddColumnSet(kSingleColumnCredentialsId);
single_column->AddPaddingColumn(0, views::kPanelHorizMargin);
single_column->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
GridLayout::USE_PREF, 0, 0);
single_column->AddPaddingColumn(0, views::kPanelHorizMargin);
if (!manage_passwords_bubble_model_->best_matches().empty()) {
for (autofill::PasswordFormMap::const_iterator i(
manage_passwords_bubble_model_->best_matches().begin());
i != manage_passwords_bubble_model_->best_matches().end(); ++i) {
layout->StartRow(0, kSingleColumnCredentialsId);
ManagePasswordItemView* item = new ManagePasswordItemView(
manage_passwords_bubble_model_, *i->second, first_field_width,
second_field_width);
if (i == manage_passwords_bubble_model_->best_matches().begin()) {
item->set_border(views::Border::CreateSolidSidedBorder(
1, 0, 1, 0, GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
} else {
item->set_border(views::Border::CreateSolidSidedBorder(
0, 0, 1, 0, GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
}
layout->AddView(item);
}
} else if (!manage_passwords_bubble_model_->password_submitted()) {
views::Label* empty_label = new views::Label(
l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_NO_PASSWORDS));
empty_label->SetMultiLine(true);
layout->StartRow(0, kSingleColumnSetId);
layout->AddView(empty_label);
}
if (manage_passwords_bubble_model_->password_submitted()) {
layout->StartRow(0, kSingleColumnCredentialsId);
ManagePasswordItemView* item = new ManagePasswordItemView(
manage_passwords_bubble_model_,
manage_passwords_bubble_model_->pending_credentials(),
first_field_width, second_field_width);
if (manage_passwords_bubble_model_->best_matches().empty()) {
item->set_border(views::Border::CreateSolidSidedBorder(1, 0, 1, 0,
GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
} else {
item->set_border(views::Border::CreateSolidSidedBorder(0, 0, 1, 0,
GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
}
layout->AddView(item);
}
manage_link_ =
new views::Link(manage_passwords_bubble_model_->manage_link());
manage_link_->set_listener(this);
layout->StartRowWithPadding(0, kSingleButtonSetId,
0, views::kRelatedControlVerticalSpacing);
layout->AddView(manage_link_);
done_button_ =
new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
done_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
layout->AddView(done_button_);
}
}
void ManagePasswordsBubbleView::WindowClosing() {
// Close() closes the window asynchronously, so by the time we reach here,
// |manage_passwords_bubble_| may have already been reset.
if (manage_passwords_bubble_ == this)
manage_passwords_bubble_ = NULL;
}
void ManagePasswordsBubbleView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender == save_button_)
manage_passwords_bubble_model_->OnSaveClicked();
else if (sender == cancel_button_)
manage_passwords_bubble_model_->OnCancelClicked();
else
DCHECK_EQ(done_button_, sender);
icon_view_->SetTooltip(
manage_passwords_bubble_model_->manage_passwords_bubble_state() ==
ManagePasswordsBubbleModel::PASSWORD_TO_BE_SAVED);
Close();
}
void ManagePasswordsBubbleView::LinkClicked(views::Link* source,
int event_flags) {
DCHECK_EQ(source, manage_link_);
manage_passwords_bubble_model_->OnManageLinkClicked();
}