Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc

Issue 255903006: Password bubble: Create subviews for ManagePasswordsBubbleView. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h" 5 #include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h"
6 6
7 #include "base/metrics/histogram.h" 7 #include "base/metrics/histogram.h"
8 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/ui/browser.h" 9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/browser_finder.h" 10 #include "chrome/browser/ui/browser_finder.h"
11 #include "chrome/browser/ui/browser_window.h" 11 #include "chrome/browser/ui/browser_window.h"
12 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h" 12 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
13 #include "chrome/browser/ui/passwords/manage_passwords_bubble_ui_controller.h" 13 #include "chrome/browser/ui/passwords/manage_passwords_bubble_ui_controller.h"
14 #include "chrome/browser/ui/views/frame/browser_view.h" 14 #include "chrome/browser/ui/views/frame/browser_view.h"
15 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" 15 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
16 #include "chrome/browser/ui/views/passwords/manage_password_item_view.h" 16 #include "chrome/browser/ui/views/passwords/manage_password_item_view.h"
17 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_view.h" 17 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_view.h"
18 #include "content/public/browser/notification_source.h" 18 #include "content/public/browser/notification_source.h"
19 #include "content/public/browser/web_contents_view.h" 19 #include "content/public/browser/web_contents_view.h"
20 #include "grit/generated_resources.h" 20 #include "grit/generated_resources.h"
21 #include "ui/base/l10n/l10n_util.h" 21 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/models/combobox_model.h" 22 #include "ui/base/models/combobox_model.h"
23 #include "ui/base/resource/resource_bundle.h" 23 #include "ui/base/resource/resource_bundle.h"
24 #include "ui/gfx/text_utils.h" 24 #include "ui/gfx/text_utils.h"
25 #include "ui/views/controls/button/blue_button.h" 25 #include "ui/views/controls/button/blue_button.h"
26 #include "ui/views/controls/button/label_button.h" 26 #include "ui/views/controls/button/label_button.h"
27 #include "ui/views/controls/combobox/combobox.h" 27 #include "ui/views/controls/combobox/combobox.h"
28 #include "ui/views/layout/fill_layout.h"
28 #include "ui/views/layout/grid_layout.h" 29 #include "ui/views/layout/grid_layout.h"
29 #include "ui/views/layout/layout_constants.h" 30 #include "ui/views/layout/layout_constants.h"
30 31
31 32
32 // Helpers -------------------------------------------------------------------- 33 // Helpers --------------------------------------------------------------------
33 34
34 namespace { 35 namespace {
35 36
36 enum FieldType { USERNAME_FIELD, PASSWORD_FIELD };
37
38 // Upper limit on the size of the username and password fields.
39 const int kUsernameFieldSize = 30;
40 const int kPasswordFieldSize = 22;
41
42 // Returns the width of |type| field.
43 int GetFieldWidth(FieldType type) {
44 return ui::ResourceBundle::GetSharedInstance()
45 .GetFontList(ui::ResourceBundle::SmallFont)
46 .GetExpectedTextWidth(type == USERNAME_FIELD ? kUsernameFieldSize
47 : kPasswordFieldSize);
48 }
49
50 class SavePasswordRefusalComboboxModel : public ui::ComboboxModel { 37 class SavePasswordRefusalComboboxModel : public ui::ComboboxModel {
51 public: 38 public:
52 enum { INDEX_NOPE = 0, INDEX_NEVER_FOR_THIS_SITE = 1, }; 39 enum { INDEX_NOPE = 0, INDEX_NEVER_FOR_THIS_SITE = 1, };
53 40
54 SavePasswordRefusalComboboxModel() { 41 SavePasswordRefusalComboboxModel() {
55 items_.push_back( 42 items_.push_back(
56 l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_CANCEL_BUTTON)); 43 l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_CANCEL_BUTTON));
57 items_.push_back( 44 items_.push_back(
58 l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON)); 45 l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON));
59 } 46 }
(...skipping 25 matching lines...) Expand all
85 ManagePasswordsBubbleUIController::FromWebContents(web_contents); 72 ManagePasswordsBubbleUIController::FromWebContents(web_contents);
86 ManagePasswordsBubbleView::ShowBubble( 73 ManagePasswordsBubbleView::ShowBubble(
87 web_contents, 74 web_contents,
88 controller->manage_passwords_bubble_needs_showing() 75 controller->manage_passwords_bubble_needs_showing()
89 ? ManagePasswordsBubbleView::AUTOMATIC 76 ? ManagePasswordsBubbleView::AUTOMATIC
90 : ManagePasswordsBubbleView::USER_ACTION); 77 : ManagePasswordsBubbleView::USER_ACTION);
91 } 78 }
92 79
93 } // namespace chrome 80 } // namespace chrome
94 81
82 // ManagePasswordsBubbleView::PendingView -------------------------------------
83
84 ManagePasswordsBubbleView::PendingView::PendingView(
85 ManagePasswordsBubbleView* parent)
86 : parent_(parent) {
87 views::GridLayout* layout = new views::GridLayout(this);
88 SetLayoutManager(layout);
89
90 // Create the pending credential item, save button and refusal combobox.
91 ManagePasswordItemView* item =
92 new ManagePasswordItemView(parent->model(),
93 parent->model()->pending_credentials(),
94 ManagePasswordItemView::FIRST_ITEM);
95 save_button_ = new views::BlueButton(
96 this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON));
97 refuse_combobox_ =
98 new views::Combobox(new SavePasswordRefusalComboboxModel());
99 refuse_combobox_->set_listener(this);
100 refuse_combobox_->SetStyle(views::Combobox::STYLE_ACTION);
101
102 // Title row.
103 parent->BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
104 parent->AddTitleRow(layout);
105
106 // Credential row.
107 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
108 layout->AddView(item);
109
110 // Button row.
111 parent->BuildColumnSet(layout, DOUBLE_BUTTON_COLUMN_SET);
112 layout->StartRowWithPadding(
113 0, DOUBLE_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
114 layout->AddView(save_button_);
115 layout->AddView(refuse_combobox_);
116
117 // Extra padding for visual awesomeness.
118 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
119 }
120
121 ManagePasswordsBubbleView::PendingView::~PendingView() {
122 }
123
124 void ManagePasswordsBubbleView::PendingView::ButtonPressed(
125 views::Button* sender,
126 const ui::Event& event) {
127 DCHECK(sender == save_button_);
128 parent_->model()->OnSaveClicked();
129 parent_->Close();
130 }
131
132 void ManagePasswordsBubbleView::PendingView::OnPerformAction(
133 views::Combobox* source) {
134 DCHECK_EQ(source, refuse_combobox_);
135 switch (refuse_combobox_->selected_index()) {
136 case SavePasswordRefusalComboboxModel::INDEX_NOPE:
137 parent_->model()->OnNopeClicked();
138 break;
139 case SavePasswordRefusalComboboxModel::INDEX_NEVER_FOR_THIS_SITE:
140 parent_->model()->OnNeverForThisSiteClicked();
141 break;
142 }
143 parent_->Close();
144 }
145
146 // ManagePasswordsBubbleView::ManageView --------------------------------------
147
148 ManagePasswordsBubbleView::ManageView::ManageView(
149 ManagePasswordsBubbleView* parent)
150 : parent_(parent) {
151 views::GridLayout* layout = new views::GridLayout(this);
152 SetLayoutManager(layout);
153
154 // Add the title.
155 parent->BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET);
156 parent->AddTitleRow(layout);
157
158 // If we have a list of passwords to store for the current site, display
159 // them to the user for management. Otherwise, render a "No passwords for
160 // this site" message.
161 if (!parent_->model()->best_matches().empty()) {
162 for (autofill::PasswordFormMap::const_iterator i(
163 parent_->model()->best_matches().begin());
164 i != parent_->model()->best_matches().end();
165 ++i) {
166 ManagePasswordItemView* item = new ManagePasswordItemView(
167 parent_->model(),
168 *i->second,
169 i == parent_->model()->best_matches().begin()
170 ? ManagePasswordItemView::FIRST_ITEM
171 : ManagePasswordItemView::SUBSEQUENT_ITEM);
172
173 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
174 layout->AddView(item);
175 }
176 } else {
177 views::Label* empty_label = new views::Label(
178 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_NO_PASSWORDS));
179 empty_label->SetMultiLine(true);
180
181 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
182 layout->AddView(empty_label);
183 }
184
185 // Then add the "manage passwords" link and "Done" button.
186 manage_link_ = new views::Link(parent_->model()->manage_link());
187 manage_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
188 manage_link_->SetUnderline(false);
189 manage_link_->set_listener(this);
190
191 done_button_ =
192 new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
193 done_button_->SetStyle(views::Button::STYLE_BUTTON);
194
195 parent->BuildColumnSet(layout, LINK_BUTTON_COLUMN_SET);
196 layout->StartRowWithPadding(
197 0, LINK_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
198 layout->AddView(manage_link_);
199 layout->AddView(done_button_);
200
201 // Extra padding for visual awesomeness.
202 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
203 }
204
205 ManagePasswordsBubbleView::ManageView::~ManageView() {
206 }
207
208 void ManagePasswordsBubbleView::ManageView::ButtonPressed(
209 views::Button* sender,
210 const ui::Event& event) {
211 DCHECK(sender == done_button_);
212 parent_->model()->OnDoneClicked();
213 parent_->Close();
214 }
215
216 void ManagePasswordsBubbleView::ManageView::LinkClicked(views::Link* source,
217 int event_flags) {
218 DCHECK_EQ(source, manage_link_);
219 parent_->model()->OnManageLinkClicked();
220 parent_->Close();
221 }
222
95 // ManagePasswordsBubbleView -------------------------------------------------- 223 // ManagePasswordsBubbleView --------------------------------------------------
96 224
97 // static 225 // static
98 ManagePasswordsBubbleView* ManagePasswordsBubbleView::manage_passwords_bubble_ = 226 ManagePasswordsBubbleView* ManagePasswordsBubbleView::manage_passwords_bubble_ =
99 NULL; 227 NULL;
100 228
101 // static 229 // static
102 void ManagePasswordsBubbleView::ShowBubble(content::WebContents* web_contents, 230 void ManagePasswordsBubbleView::ShowBubble(content::WebContents* web_contents,
103 DisplayReason reason) { 231 DisplayReason reason) {
104 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); 232 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 views::GridLayout::CENTER, 329 views::GridLayout::CENTER,
202 0, 330 0,
203 views::GridLayout::USE_PREF, 331 views::GridLayout::USE_PREF,
204 0, 332 0,
205 0); 333 0);
206 break; 334 break;
207 } 335 }
208 column_set->AddPaddingColumn(0, views::kPanelHorizMargin); 336 column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
209 } 337 }
210 338
339 void ManagePasswordsBubbleView::AddTitleRow(views::GridLayout* layout) const {
340 // Build the title label, and populate it with whatever title our model feels
341 // is appropriate for the bubble's state.
342 views::Label* title_label = new views::Label(model()->title());
343 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
344 title_label->SetMultiLine(true);
345 title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
346 ui::ResourceBundle::MediumFont));
347
348 // Add the title to the layout with appropriate padding.
349 layout->StartRowWithPadding(
350 0, SINGLE_VIEW_COLUMN_SET, 0, views::kRelatedControlSmallVerticalSpacing);
351 layout->AddView(title_label);
352 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
353 }
354
211 void ManagePasswordsBubbleView::AdjustForFullscreen( 355 void ManagePasswordsBubbleView::AdjustForFullscreen(
212 const gfx::Rect& screen_bounds) { 356 const gfx::Rect& screen_bounds) {
213 if (GetAnchorView()) 357 if (GetAnchorView())
214 return; 358 return;
215 359
216 // The bubble's padding from the screen edge, used in fullscreen. 360 // The bubble's padding from the screen edge, used in fullscreen.
217 const int kFullscreenPaddingEnd = 20; 361 const int kFullscreenPaddingEnd = 20;
218 const size_t bubble_half_width = width() / 2; 362 const size_t bubble_half_width = width() / 2;
219 const int x_pos = base::i18n::IsRTL() ? 363 const int x_pos = base::i18n::IsRTL() ?
220 screen_bounds.x() + bubble_half_width + kFullscreenPaddingEnd : 364 screen_bounds.x() + bubble_half_width + kFullscreenPaddingEnd :
221 screen_bounds.right() - bubble_half_width - kFullscreenPaddingEnd; 365 screen_bounds.right() - bubble_half_width - kFullscreenPaddingEnd;
222 SetAnchorRect(gfx::Rect(x_pos, screen_bounds.y(), 0, 0)); 366 SetAnchorRect(gfx::Rect(x_pos, screen_bounds.y(), 0, 0));
223 } 367 }
224 368
225 void ManagePasswordsBubbleView::Close() { 369 void ManagePasswordsBubbleView::Close() {
226 GetWidget()->Close(); 370 GetWidget()->Close();
227 } 371 }
228 372
229 void ManagePasswordsBubbleView::CloseWithoutLogging() { 373 void ManagePasswordsBubbleView::CloseWithoutLogging() {
230 model()->OnCloseWithoutLogging(); 374 model()->OnCloseWithoutLogging();
231 GetWidget()->Close(); 375 GetWidget()->Close();
232 } 376 }
233 377
234 void ManagePasswordsBubbleView::Init() { 378 void ManagePasswordsBubbleView::Init() {
235 using views::GridLayout; 379 views::FillLayout* layout = new views::FillLayout();
380 SetLayoutManager(layout);
381 SetFocusable(true);
236 382
237 GridLayout* layout = new GridLayout(this); 383 if (model()->WaitingToSavePassword())
238 SetFocusable(true); 384 AddChildView(new PendingView(this));
239 SetLayoutManager(layout); 385 else
240 BuildColumnSet(layout, SINGLE_VIEW_COLUMN_SET); 386 AddChildView(new ManageView(this));
241 BuildColumnSet(layout, DOUBLE_BUTTON_COLUMN_SET);
242 BuildColumnSet(layout, LINK_BUTTON_COLUMN_SET);
243
244 // This calculates the necessary widths for credential columns in the bubble.
245 const int first_field_width = std::max(
246 GetFieldWidth(USERNAME_FIELD),
247 views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED))
248 .GetPreferredSize()
249 .width());
250
251 const int second_field_width = std::max(
252 GetFieldWidth(PASSWORD_FIELD),
253 views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO))
254 .GetPreferredSize()
255 .width());
256
257 // Build and populate the header.
258 views::Label* title_label = new views::Label(model()->title());
259 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
260 title_label->SetMultiLine(true);
261 title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
262 ui::ResourceBundle::MediumFont));
263
264 layout->StartRowWithPadding(
265 0, SINGLE_VIEW_COLUMN_SET, 0, views::kRelatedControlSmallVerticalSpacing);
266 layout->AddView(title_label);
267 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
268
269 if (model()->WaitingToSavePassword()) {
270 // If we've got a password that we're deciding whether or not to save,
271 // then we need to display a single-view columnset containing the
272 // ManagePasswordItemView, followed by double-view columnset containing
273 // a "Save" and "Reject" button.
274 ManagePasswordItemView* item =
275 new ManagePasswordItemView(model(),
276 model()->pending_credentials(),
277 first_field_width,
278 second_field_width,
279 ManagePasswordItemView::FIRST_ITEM);
280 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
281 layout->AddView(item);
282
283 refuse_combobox_ =
284 new views::Combobox(new SavePasswordRefusalComboboxModel());
285 refuse_combobox_->set_listener(this);
286 refuse_combobox_->SetStyle(views::Combobox::STYLE_ACTION);
287
288 save_button_ = new views::BlueButton(
289 this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON));
290
291 layout->StartRowWithPadding(
292 0, DOUBLE_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
293 layout->AddView(save_button_);
294 layout->AddView(refuse_combobox_);
295 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
296 } else {
297 // If we have a list of passwords to store for the current site, display
298 // them to the user for management. Otherwise, render a "No passwords for
299 // this site" message.
300 //
301 // TODO(mkwst): Do we really want the "No passwords" case? It would probably
302 // be better to only clear the pending password upon navigation, rather than
303 // as soon as the bubble closes.
304 if (!model()->best_matches().empty()) {
305 for (autofill::PasswordFormMap::const_iterator i(
306 model()->best_matches().begin());
307 i != model()->best_matches().end();
308 ++i) {
309 ManagePasswordItemView* item = new ManagePasswordItemView(
310 model(),
311 *i->second,
312 first_field_width,
313 second_field_width,
314 i == model()->best_matches().begin()
315 ? ManagePasswordItemView::FIRST_ITEM
316 : ManagePasswordItemView::SUBSEQUENT_ITEM);
317
318 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
319 layout->AddView(item);
320 }
321 } else {
322 views::Label* empty_label = new views::Label(
323 l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_NO_PASSWORDS));
324 empty_label->SetMultiLine(true);
325
326 layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
327 layout->AddView(empty_label);
328 }
329
330 // Build a "manage" link and "done" button, and throw them both into a new
331 // row
332 // containing a double-view columnset.
333 manage_link_ = new views::Link(model()->manage_link());
334 manage_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
335 manage_link_->SetUnderline(false);
336 manage_link_->set_listener(this);
337
338 done_button_ =
339 new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
340 done_button_->SetStyle(views::Button::STYLE_BUTTON);
341
342 layout->StartRowWithPadding(
343 0, LINK_BUTTON_COLUMN_SET, 0, views::kRelatedControlVerticalSpacing);
344 layout->AddView(manage_link_);
345 layout->AddView(done_button_);
346 }
347 } 387 }
348 388
349 void ManagePasswordsBubbleView::WindowClosing() { 389 void ManagePasswordsBubbleView::WindowClosing() {
350 // Close() closes the window asynchronously, so by the time we reach here, 390 // Close() closes the window asynchronously, so by the time we reach here,
351 // |manage_passwords_bubble_| may have already been reset. 391 // |manage_passwords_bubble_| may have already been reset.
352 if (manage_passwords_bubble_ == this) 392 if (manage_passwords_bubble_ == this)
353 manage_passwords_bubble_ = NULL; 393 manage_passwords_bubble_ = NULL;
354 } 394 }
355
356 void ManagePasswordsBubbleView::ButtonPressed(views::Button* sender,
357 const ui::Event& event) {
358 DCHECK(sender == save_button_ || sender == done_button_);
359
360 if (sender == save_button_)
361 model()->OnSaveClicked();
362 else
363 model()->OnDoneClicked();
364 Close();
365 }
366
367 void ManagePasswordsBubbleView::LinkClicked(views::Link* source,
368 int event_flags) {
369 DCHECK_EQ(source, manage_link_);
370 model()->OnManageLinkClicked();
371 Close();
372 }
373
374 void ManagePasswordsBubbleView::OnPerformAction(views::Combobox* source) {
375 DCHECK_EQ(source, refuse_combobox_);
376 switch (refuse_combobox_->selected_index()) {
377 case SavePasswordRefusalComboboxModel::INDEX_NOPE:
378 model()->OnNopeClicked();
379 break;
380 case SavePasswordRefusalComboboxModel::INDEX_NEVER_FOR_THIS_SITE:
381 model()->OnNeverForThisSiteClicked();
382 break;
383 default:
384 NOTREACHED();
385 break;
386 }
387 Close();
388 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698