Upstream version 5.34.104.0
[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/views/frame/browser_view.h"
13 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
14 #include "chrome/browser/ui/views/passwords/manage_password_item_view.h"
15 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_view.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/web_contents_view.h"
18 #include "grit/generated_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/gfx/text_utils.h"
21 #include "ui/views/controls/button/blue_button.h"
22 #include "ui/views/controls/button/label_button.h"
23 #include "ui/views/layout/grid_layout.h"
24 #include "ui/views/layout/layout_constants.h"
25
26
27 // Helpers --------------------------------------------------------------------
28
29 namespace {
30
31 // Updates either the biggest possible width for the username field in the
32 // manage passwords bubble or the biggest possible width for the password field.
33 void UpdateBiggestWidth(const autofill::PasswordForm& password_form,
34                         bool username,
35                         int* biggest_width) {
36   const gfx::FontList font_list;
37   base::string16 display_string(username ?
38       password_form.username_value :
39       ManagePasswordItemView::GetPasswordDisplayString(
40           password_form.password_value));
41   *biggest_width = std::max(gfx::GetStringWidth(display_string, font_list),
42                             *biggest_width);
43 }
44
45 }  // namespace
46
47
48 // ManagePasswordsBubbleView --------------------------------------------------
49
50 // static
51 ManagePasswordsBubbleView* ManagePasswordsBubbleView::manage_passwords_bubble_ =
52     NULL;
53
54 // static
55 void ManagePasswordsBubbleView::ShowBubble(content::WebContents* web_contents,
56                                            ManagePasswordsIconView* icon_view) {
57   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
58   DCHECK(browser);
59   DCHECK(browser->window());
60   DCHECK(browser->fullscreen_controller());
61   DCHECK(!IsShowing());
62
63   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
64   bool is_fullscreen = browser_view->IsFullscreen();
65   views::View* anchor_view = is_fullscreen ?
66       NULL : browser_view->GetLocationBarView()->manage_passwords_icon_view();
67   manage_passwords_bubble_ =
68       new ManagePasswordsBubbleView(web_contents, anchor_view, icon_view);
69
70   if (is_fullscreen) {
71     manage_passwords_bubble_->set_parent_window(
72         web_contents->GetView()->GetTopLevelNativeWindow());
73   }
74
75   views::BubbleDelegateView::CreateBubble(manage_passwords_bubble_);
76
77   // Adjust for fullscreen after creation as it relies on the content size.
78   if (is_fullscreen) {
79     manage_passwords_bubble_->AdjustForFullscreen(
80         browser_view->GetBoundsInScreen());
81   }
82
83   manage_passwords_bubble_->GetWidget()->Show();
84 }
85
86 // static
87 void ManagePasswordsBubbleView::CloseBubble() {
88   if (manage_passwords_bubble_)
89    manage_passwords_bubble_->Close();
90 }
91
92 // static
93 bool ManagePasswordsBubbleView::IsShowing() {
94   // The bubble may be in the process of closing.
95   return (manage_passwords_bubble_ != NULL) &&
96       manage_passwords_bubble_->GetWidget()->IsVisible();
97 }
98
99 ManagePasswordsBubbleView::ManagePasswordsBubbleView(
100     content::WebContents* web_contents,
101     views::View* anchor_view,
102     ManagePasswordsIconView* icon_view)
103     : BubbleDelegateView(
104           anchor_view,
105           anchor_view ?
106               views::BubbleBorder::TOP_RIGHT : views::BubbleBorder::NONE),
107       manage_passwords_bubble_model_(
108           new ManagePasswordsBubbleModel(web_contents)),
109       icon_view_(icon_view) {
110   // Compensate for built-in vertical padding in the anchor view's image.
111   set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
112   set_notify_enter_exit_on_child(true);
113 }
114
115 ManagePasswordsBubbleView::~ManagePasswordsBubbleView() {}
116
117 int ManagePasswordsBubbleView::GetMaximumUsernameOrPasswordWidth(
118     bool username) {
119   int biggest_width = 0;
120   if (manage_passwords_bubble_model_->manage_passwords_bubble_state() !=
121       ManagePasswordsBubbleModel::PASSWORD_TO_BE_SAVED) {
122     // If we are in the PASSWORD_TO_BE_SAVED state we only display the
123     // password that was just submitted and should not take these into account.
124     for (autofill::PasswordFormMap::const_iterator i(
125              manage_passwords_bubble_model_->best_matches().begin());
126          i != manage_passwords_bubble_model_->best_matches().end(); ++i) {
127       UpdateBiggestWidth((*i->second), username, &biggest_width);
128     }
129   }
130   if (manage_passwords_bubble_model_->password_submitted()) {
131     UpdateBiggestWidth(manage_passwords_bubble_model_->pending_credentials(),
132                        username, &biggest_width);
133   }
134   return biggest_width;
135 }
136
137 void ManagePasswordsBubbleView::AdjustForFullscreen(
138     const gfx::Rect& screen_bounds) {
139   if (GetAnchorView())
140     return;
141
142   // The bubble's padding from the screen edge, used in fullscreen.
143   const int kFullscreenPaddingEnd = 20;
144   const size_t bubble_half_width = width() / 2;
145   const int x_pos = base::i18n::IsRTL() ?
146       screen_bounds.x() + bubble_half_width + kFullscreenPaddingEnd :
147       screen_bounds.right() - bubble_half_width - kFullscreenPaddingEnd;
148   SetAnchorRect(gfx::Rect(x_pos, screen_bounds.y(), 0, 0));
149 }
150
151 void ManagePasswordsBubbleView::Close() {
152   GetWidget()->Close();
153 }
154
155 void ManagePasswordsBubbleView::Init() {
156   using views::GridLayout;
157
158   GridLayout* layout = new GridLayout(this);
159   SetLayoutManager(layout);
160
161   // This calculates the necessary widths for the list of credentials in the
162   // bubble. We do not need to clamp the password field width because
163   // ManagePasswordItemView::GetPasswordFisplayString() does this.
164
165   const int predefined_username_field_max_width =
166       gfx::FontList().GetExpectedTextWidth(22);
167   const int max_username_or_password_width =
168       std::min(GetMaximumUsernameOrPasswordWidth(true),
169                predefined_username_field_max_width);
170   const int first_field_width = std::max(max_username_or_password_width,
171       views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED)).
172           GetPreferredSize().width());
173
174   const int second_field_width = std::max(
175       GetMaximumUsernameOrPasswordWidth(false),
176       views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO)).
177           GetPreferredSize().width());
178
179   const int kSingleColumnSetId = 0;
180   views::ColumnSet* column_set = layout->AddColumnSet(kSingleColumnSetId);
181   column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
182   column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
183                         GridLayout::USE_PREF, 0, 0);
184   column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
185
186   ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
187   views::Label* title_label =
188       new views::Label(manage_passwords_bubble_model_->title());
189   title_label->SetMultiLine(true);
190   title_label->SetFontList(rb->GetFontList(ui::ResourceBundle::MediumFont));
191
192   layout->StartRowWithPadding(0, kSingleColumnSetId,
193                               0, views::kRelatedControlSmallVerticalSpacing);
194   layout->AddView(title_label);
195   layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
196
197   if (manage_passwords_bubble_model_->manage_passwords_bubble_state() ==
198       ManagePasswordsBubbleModel::PASSWORD_TO_BE_SAVED) {
199     const int kSingleColumnCredentialsId = 1;
200     views::ColumnSet* single_column =
201         layout->AddColumnSet(kSingleColumnCredentialsId);
202     single_column->AddPaddingColumn(0, views::kPanelHorizMargin);
203     single_column->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
204                              GridLayout::USE_PREF, 0, 0);
205     single_column->AddPaddingColumn(0, views::kPanelHorizMargin);
206
207     layout->StartRow(0, kSingleColumnCredentialsId);
208     ManagePasswordItemView* item = new ManagePasswordItemView(
209         manage_passwords_bubble_model_,
210         manage_passwords_bubble_model_->pending_credentials(),
211         first_field_width, second_field_width);
212     item->SetBorder(views::Border::CreateSolidSidedBorder(
213         1,
214         0,
215         1,
216         0,
217         GetNativeTheme()->GetSystemColor(
218             ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
219     layout->AddView(item);
220
221     const int kDoubleColumnSetId = 2;
222     views::ColumnSet* double_column_set =
223         layout->AddColumnSet(kDoubleColumnSetId);
224     double_column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
225     double_column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 1,
226                                  GridLayout::USE_PREF, 0, 0);
227     double_column_set->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
228     double_column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
229                                  GridLayout::USE_PREF, 0, 0);
230     double_column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
231
232     cancel_button_ = new views::LabelButton(
233         this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_CANCEL_BUTTON));
234     cancel_button_->SetStyle(views::Button::STYLE_BUTTON);
235     save_button_ = new views::BlueButton(
236         this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON));
237
238     layout->StartRowWithPadding(0, kDoubleColumnSetId,
239                                 0, views::kRelatedControlVerticalSpacing);
240     layout->AddView(save_button_);
241     layout->AddView(cancel_button_);
242     layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
243   } else {
244     const int kSingleButtonSetId = 3;
245     views::ColumnSet* single_column_set =
246         layout->AddColumnSet(kSingleButtonSetId);
247     single_column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
248     single_column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
249                                  GridLayout::USE_PREF, 0, 0);
250     single_column_set->AddPaddingColumn(0,
251         views::kUnrelatedControlHorizontalSpacing);
252     single_column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
253                                  GridLayout::USE_PREF, 0, 0);
254     single_column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
255
256     const int kSingleColumnCredentialsId = 1;
257     views::ColumnSet* single_column =
258         layout->AddColumnSet(kSingleColumnCredentialsId);
259     single_column->AddPaddingColumn(0, views::kPanelHorizMargin);
260     single_column->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
261                              GridLayout::USE_PREF, 0, 0);
262     single_column->AddPaddingColumn(0, views::kPanelHorizMargin);
263
264     if (!manage_passwords_bubble_model_->best_matches().empty()) {
265       for (autofill::PasswordFormMap::const_iterator i(
266                manage_passwords_bubble_model_->best_matches().begin());
267            i != manage_passwords_bubble_model_->best_matches().end(); ++i) {
268         layout->StartRow(0, kSingleColumnCredentialsId);
269         ManagePasswordItemView* item = new ManagePasswordItemView(
270             manage_passwords_bubble_model_, *i->second, first_field_width,
271             second_field_width);
272         if (i == manage_passwords_bubble_model_->best_matches().begin()) {
273           item->SetBorder(views::Border::CreateSolidSidedBorder(
274               1,
275               0,
276               1,
277               0,
278               GetNativeTheme()->GetSystemColor(
279                   ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
280         } else {
281           item->SetBorder(views::Border::CreateSolidSidedBorder(
282               0,
283               0,
284               1,
285               0,
286               GetNativeTheme()->GetSystemColor(
287                   ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
288         }
289         layout->AddView(item);
290       }
291     } else if (!manage_passwords_bubble_model_->password_submitted()) {
292         views::Label* empty_label = new views::Label(
293             l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_NO_PASSWORDS));
294         empty_label->SetMultiLine(true);
295         layout->StartRow(0, kSingleColumnSetId);
296         layout->AddView(empty_label);
297     }
298
299     if (manage_passwords_bubble_model_->password_submitted()) {
300       layout->StartRow(0, kSingleColumnCredentialsId);
301       ManagePasswordItemView* item = new ManagePasswordItemView(
302           manage_passwords_bubble_model_,
303           manage_passwords_bubble_model_->pending_credentials(),
304           first_field_width, second_field_width);
305       if (manage_passwords_bubble_model_->best_matches().empty()) {
306         item->SetBorder(views::Border::CreateSolidSidedBorder(
307             1,
308             0,
309             1,
310             0,
311             GetNativeTheme()->GetSystemColor(
312                 ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
313       } else {
314         item->SetBorder(views::Border::CreateSolidSidedBorder(
315             0,
316             0,
317             1,
318             0,
319             GetNativeTheme()->GetSystemColor(
320                 ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor)));
321       }
322       layout->AddView(item);
323     }
324
325     manage_link_ =
326         new views::Link(manage_passwords_bubble_model_->manage_link());
327     manage_link_->set_listener(this);
328     layout->StartRowWithPadding(0, kSingleButtonSetId,
329                                 0, views::kRelatedControlVerticalSpacing);
330     layout->AddView(manage_link_);
331
332     done_button_ =
333         new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
334     done_button_->SetStyle(views::Button::STYLE_BUTTON);
335     layout->AddView(done_button_);
336   }
337 }
338
339 void ManagePasswordsBubbleView::WindowClosing() {
340   // Close() closes the window asynchronously, so by the time we reach here,
341   // |manage_passwords_bubble_| may have already been reset.
342   if (manage_passwords_bubble_ == this)
343     manage_passwords_bubble_ = NULL;
344 }
345
346 void ManagePasswordsBubbleView::ButtonPressed(views::Button* sender,
347                                               const ui::Event& event) {
348   if (sender == save_button_)
349     manage_passwords_bubble_model_->OnSaveClicked();
350   else if (sender == cancel_button_)
351     manage_passwords_bubble_model_->OnCancelClicked();
352   else
353     DCHECK_EQ(done_button_, sender);
354   icon_view_->SetTooltip(
355       manage_passwords_bubble_model_->manage_passwords_bubble_state() ==
356           ManagePasswordsBubbleModel::PASSWORD_TO_BE_SAVED);
357   Close();
358 }
359
360 void ManagePasswordsBubbleView::LinkClicked(views::Link* source,
361                                             int event_flags) {
362   DCHECK_EQ(source, manage_link_);
363   manage_passwords_bubble_model_->OnManageLinkClicked();
364 }