Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / views / profile_chooser_view.cc
blob02ecb52ad66526421e6d25316c6075cec5cbd632
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/profile_chooser_view.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/profiles/profile_info_util.h"
10 #include "chrome/browser/profiles/profile_manager.h"
11 #include "chrome/browser/profiles/profile_window.h"
12 #include "chrome/browser/profiles/profiles_state.h"
13 #include "chrome/browser/signin/mutable_profile_oauth2_token_service.h"
14 #include "chrome/browser/signin/profile_oauth2_token_service.h"
15 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
16 #include "chrome/browser/signin/signin_manager.h"
17 #include "chrome/browser/signin/signin_manager_factory.h"
18 #include "chrome/browser/signin/signin_promo.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_dialogs.h"
21 #include "chrome/browser/ui/singleton_tabs.h"
22 #include "chrome/browser/ui/views/user_manager_view.h"
23 #include "chrome/common/url_constants.h"
24 #include "grit/chromium_strings.h"
25 #include "grit/generated_resources.h"
26 #include "grit/theme_resources.h"
27 #include "third_party/skia/include/core/SkColor.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/resource/resource_bundle.h"
30 #include "ui/gfx/image/image.h"
31 #include "ui/gfx/image/image_skia.h"
32 #include "ui/gfx/text_elider.h"
33 #include "ui/views/controls/button/blue_button.h"
34 #include "ui/views/controls/button/menu_button.h"
35 #include "ui/views/controls/label.h"
36 #include "ui/views/controls/link.h"
37 #include "ui/views/controls/separator.h"
38 #include "ui/views/controls/textfield/textfield.h"
39 #include "ui/views/controls/webview/webview.h"
40 #include "ui/views/layout/grid_layout.h"
41 #include "ui/views/layout/layout_constants.h"
42 #include "ui/views/widget/widget.h"
44 #if defined(USE_AURA)
45 #include "ui/native_theme/native_theme_aura.h"
46 #endif
48 namespace {
50 // Helpers --------------------------------------------------------------------
52 const int kMinMenuWidth = 250;
53 const int kButtonHeight = 29;
55 // Creates a GridLayout with a single column. This ensures that all the child
56 // views added get auto-expanded to fill the full width of the bubble.
57 views::GridLayout* CreateSingleColumnLayout(views::View* view) {
58 views::GridLayout* layout = new views::GridLayout(view);
59 view->SetLayoutManager(layout);
61 views::ColumnSet* columns = layout->AddColumnSet(0);
62 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
63 views::GridLayout::USE_PREF, 0, 0);
64 return layout;
67 // Creates a GridLayout with two columns.
68 views::GridLayout* CreateDoubleColumnLayout(views::View* view) {
69 views::GridLayout* layout = new views::GridLayout(view);
70 view->SetLayoutManager(layout);
72 views::ColumnSet* columns = layout->AddColumnSet(0);
73 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
74 views::GridLayout::USE_PREF, 0, 0);
75 columns->AddPaddingColumn(0, views::kUnrelatedControlLargeHorizontalSpacing);
76 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
77 views::GridLayout::USE_PREF, 0, 0);
78 return layout;
81 views::Link* CreateLink(const base::string16& link_text,
82 views::LinkListener* listener) {
83 views::Link* link_button = new views::Link(link_text);
84 link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
85 link_button->SetUnderline(false);
86 link_button->set_listener(listener);
87 return link_button;
91 // BackgroundColorHoverButton -------------------------------------------------
93 // A custom button that allows for setting a background color when hovered over.
94 class BackgroundColorHoverButton : public views::TextButton {
95 public:
96 BackgroundColorHoverButton(views::ButtonListener* listener,
97 const base::string16& text,
98 const gfx::ImageSkia& normal_icon,
99 const gfx::ImageSkia& hover_icon);
100 virtual ~BackgroundColorHoverButton();
102 private:
103 // views::TextButton:
104 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
105 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
107 void OnHighlightStateChanged();
109 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
112 BackgroundColorHoverButton::BackgroundColorHoverButton(
113 views::ButtonListener* listener,
114 const base::string16& text,
115 const gfx::ImageSkia& normal_icon,
116 const gfx::ImageSkia& hover_icon)
117 : views::TextButton(listener, text) {
118 scoped_ptr<views::TextButtonBorder> text_button_border(
119 new views::TextButtonBorder());
120 text_button_border->SetInsets(gfx::Insets(0, views::kButtonHEdgeMarginNew,
121 0, views::kButtonHEdgeMarginNew));
122 set_border(text_button_border.release());
123 set_min_height(kButtonHeight);
124 set_icon_text_spacing(views::kItemLabelSpacing);
125 SetIcon(normal_icon);
126 SetHoverIcon(hover_icon);
127 SetPushedIcon(hover_icon);
128 SetHoverColor(GetNativeTheme()->GetSystemColor(
129 ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor));
130 OnHighlightStateChanged();
133 BackgroundColorHoverButton::~BackgroundColorHoverButton() {
136 void BackgroundColorHoverButton::OnMouseEntered(const ui::MouseEvent& event) {
137 views::TextButton::OnMouseEntered(event);
138 OnHighlightStateChanged();
141 void BackgroundColorHoverButton::OnMouseExited(const ui::MouseEvent& event) {
142 views::TextButton::OnMouseExited(event);
143 OnHighlightStateChanged();
146 void BackgroundColorHoverButton::OnHighlightStateChanged() {
147 bool is_highlighted = (state() == views::TextButton::STATE_PRESSED) ||
148 (state() == views::TextButton::STATE_HOVERED) || HasFocus();
149 set_background(views::Background::CreateSolidBackground(
150 GetNativeTheme()->GetSystemColor(is_highlighted ?
151 ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor :
152 ui::NativeTheme::kColorId_MenuBackgroundColor)));
153 SchedulePaint();
156 } // namespace
159 // EditableProfilePhoto -------------------------------------------------
161 // A custom Image control that shows a "change" button when moused over.
162 class EditableProfilePhoto : public views::ImageView {
163 public:
164 EditableProfilePhoto(views::ButtonListener* listener,
165 const gfx::Image& icon,
166 bool is_editing_allowed)
167 : views::ImageView(),
168 change_photo_button_(NULL) {
169 const int kLargeImageSide = 64;
170 const SkColor kBackgroundColor = SkColorSetARGB(125, 0, 0, 0);
171 const int kOverlayHeight = 20;
173 gfx::Image image = profiles::GetSizedAvatarIconWithBorder(
174 icon, true,
175 kLargeImageSide + profiles::kAvatarIconPadding,
176 kLargeImageSide + profiles::kAvatarIconPadding);
177 SetImage(image.ToImageSkia());
179 if (!is_editing_allowed)
180 return;
182 set_notify_enter_exit_on_child(true);
184 // Button overlay that appears when hovering over the image.
185 change_photo_button_ = new views::TextButton(listener,
186 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_CHANGE_PHOTO_BUTTON));
187 change_photo_button_->set_alignment(views::TextButton::ALIGN_CENTER);
188 change_photo_button_->set_border(NULL);
189 change_photo_button_->SetEnabledColor(SK_ColorWHITE);
190 change_photo_button_->SetHoverColor(SK_ColorWHITE);
192 change_photo_button_->set_background(
193 views::Background::CreateSolidBackground(kBackgroundColor));
194 // Need to take in account the border padding on the avatar.
195 change_photo_button_->SetBounds(
196 profiles::kAvatarIconPadding,
197 kLargeImageSide - kOverlayHeight,
198 kLargeImageSide - profiles::kAvatarIconPadding,
199 kOverlayHeight);
200 change_photo_button_->SetVisible(false);
201 AddChildView(change_photo_button_);
204 views::TextButton* change_photo_button() {
205 return change_photo_button_;
208 private:
209 // views::View:
210 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
211 if (change_photo_button_)
212 change_photo_button_->SetVisible(true);
215 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
216 if (change_photo_button_)
217 change_photo_button_->SetVisible(false);
220 // Button that is shown when hovering over the image view. Can be NULL if
221 // the photo isn't allowed to be edited (e.g. for guest profiles).
222 views::TextButton* change_photo_button_;
224 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
228 // EditableProfileName -------------------------------------------------
230 // A custom text control that turns into a textfield for editing when clicked.
231 class EditableProfileName : public views::TextButton,
232 public views::ButtonListener {
233 public:
234 EditableProfileName(views::TextfieldController* controller,
235 const base::string16& text,
236 bool is_editing_allowed)
237 : views::TextButton(this, text),
238 profile_name_textfield_(NULL) {
239 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
240 const gfx::FontList& medium_font_list =
241 rb->GetFontList(ui::ResourceBundle::MediumFont);
242 SetFontList(medium_font_list);
243 set_border(NULL);
245 if (!is_editing_allowed)
246 return;
248 SetIcon(*rb->GetImageSkiaNamed(IDR_INFOBAR_AUTOFILL));
249 set_icon_placement(views::TextButton::ICON_ON_RIGHT);
251 // Textfield that overlaps the button.
252 profile_name_textfield_ = new views::Textfield();
253 profile_name_textfield_->set_controller(controller);
254 profile_name_textfield_->SetFontList(medium_font_list);
255 profile_name_textfield_->SetVisible(false);
256 AddChildView(profile_name_textfield_);
259 views::Textfield* profile_name_textfield() {
260 return profile_name_textfield_;
263 // Hide the editable textfield and show the button displaying the profile
264 // name instead.
265 void ShowReadOnlyView() {
266 if (profile_name_textfield_)
267 profile_name_textfield_->SetVisible(false);
270 private:
271 // views::ButtonListener:
272 virtual void ButtonPressed(views::Button* sender,
273 const ui::Event& event) OVERRIDE {
274 if (profile_name_textfield_) {
275 profile_name_textfield_->SetVisible(true);
276 profile_name_textfield_->SetText(text());
277 profile_name_textfield_->SelectAll(false);
278 profile_name_textfield_->RequestFocus();
282 // views::CustomButton:
283 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE {
284 // Override CustomButton's implementation, which presses the button when
285 // you press space and clicks it when you release space, as the space can be
286 // part of the new profile name typed in the textfield.
287 return false;
290 // views::View:
291 virtual void Layout() OVERRIDE {
292 if (profile_name_textfield_)
293 profile_name_textfield_->SetBounds(0, 0, width(), height());
294 views::View::Layout();
297 // Button that is shown when hovering over the image view. Can be NULL if
298 // the profile name isn't allowed to be edited (e.g. for guest profiles).
299 views::Textfield* profile_name_textfield_;
301 DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
305 // ProfileChooserView ---------------------------------------------------------
307 // static
308 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
309 bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
311 // static
312 void ProfileChooserView::ShowBubble(
313 views::View* anchor_view,
314 views::BubbleBorder::Arrow arrow,
315 views::BubbleBorder::BubbleAlignment border_alignment,
316 const gfx::Rect& anchor_rect,
317 Browser* browser) {
318 if (IsShowing())
319 // TODO(bcwhite): handle case where we should show on different window
320 return;
322 profile_bubble_ = new ProfileChooserView(
323 anchor_view, arrow, anchor_rect, browser);
324 views::BubbleDelegateView::CreateBubble(profile_bubble_);
325 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
326 profile_bubble_->SetAlignment(border_alignment);
327 profile_bubble_->GetWidget()->Show();
328 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
331 // static
332 bool ProfileChooserView::IsShowing() {
333 return profile_bubble_ != NULL;
336 // static
337 void ProfileChooserView::Hide() {
338 if (IsShowing())
339 profile_bubble_->GetWidget()->Close();
342 ProfileChooserView::ProfileChooserView(views::View* anchor_view,
343 views::BubbleBorder::Arrow arrow,
344 const gfx::Rect& anchor_rect,
345 Browser* browser)
346 : BubbleDelegateView(anchor_view, arrow),
347 browser_(browser),
348 view_mode_(PROFILE_CHOOSER_VIEW) {
349 // Reset the default margins inherited from the BubbleDelegateView.
350 set_margins(gfx::Insets());
352 ResetView();
354 avatar_menu_.reset(new AvatarMenu(
355 &g_browser_process->profile_manager()->GetProfileInfoCache(),
356 this,
357 browser_));
358 avatar_menu_->RebuildMenu();
360 ProfileOAuth2TokenService* oauth2_token_service =
361 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
362 if (oauth2_token_service)
363 oauth2_token_service->AddObserver(this);
366 ProfileChooserView::~ProfileChooserView() {
367 ProfileOAuth2TokenService* oauth2_token_service =
368 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
369 if (oauth2_token_service)
370 oauth2_token_service->RemoveObserver(this);
373 void ProfileChooserView::ResetView() {
374 manage_accounts_link_ = NULL;
375 signout_current_profile_link_ = NULL;
376 signin_current_profile_link_ = NULL;
377 guest_button_ = NULL;
378 end_guest_button_ = NULL;
379 users_button_ = NULL;
380 add_user_button_ = NULL;
381 add_account_button_ = NULL;
382 current_profile_photo_ = NULL;
383 current_profile_name_ = NULL;
384 open_other_profile_indexes_map_.clear();
385 current_profile_accounts_map_.clear();
388 void ProfileChooserView::Init() {
389 ShowView(PROFILE_CHOOSER_VIEW, avatar_menu_.get());
392 void ProfileChooserView::OnAvatarMenuChanged(
393 AvatarMenu* avatar_menu) {
394 // Refresh the view with the new menu. We can't just update the local copy
395 // as this may have been triggered by a sign out action, in which case
396 // the view is being destroyed.
397 ShowView(PROFILE_CHOOSER_VIEW, avatar_menu);
400 void ProfileChooserView::OnRefreshTokenAvailable(
401 const std::string& account_id) {
402 // Refresh the account management view when a new account is added to the
403 // profile.
404 if (view_mode_ == ACCOUNT_MANAGEMENT_VIEW ||
405 view_mode_ == GAIA_SIGNIN_VIEW ||
406 view_mode_ == GAIA_ADD_ACCOUNT_VIEW) {
407 ShowView(ACCOUNT_MANAGEMENT_VIEW, avatar_menu_.get());
411 void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
412 // Refresh the account management view when an account is removed from the
413 // profile.
414 if (view_mode_ == ACCOUNT_MANAGEMENT_VIEW)
415 ShowView(ACCOUNT_MANAGEMENT_VIEW, avatar_menu_.get());
418 void ProfileChooserView::ShowView(BubbleViewMode view_to_display,
419 AvatarMenu* avatar_menu) {
420 // The account management view should only be displayed if the active profile
421 // is signed in.
422 if (view_to_display == ACCOUNT_MANAGEMENT_VIEW) {
423 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt(
424 avatar_menu->GetActiveProfileIndex());
425 DCHECK(active_item.signed_in);
428 ResetView();
429 RemoveAllChildViews(true);
430 view_mode_ = view_to_display;
432 views::GridLayout* layout = CreateSingleColumnLayout(this);
433 layout->set_minimum_size(gfx::Size(kMinMenuWidth, 0));
435 if (view_to_display == GAIA_SIGNIN_VIEW ||
436 view_to_display == GAIA_ADD_ACCOUNT_VIEW) {
437 // Minimum size for embedded sign in pages as defined in Gaia.
438 const int kMinGaiaViewWidth = 320;
439 const int kMinGaiaViewHeight = 440;
440 Profile* profile = browser_->profile();
441 views::WebView* web_view = new views::WebView(profile);
442 signin::Source source = (view_to_display == GAIA_SIGNIN_VIEW) ?
443 signin::SOURCE_AVATAR_BUBBLE_SIGN_IN :
444 signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT;
445 GURL url(signin::GetPromoURL(
446 source, false /* auto_close */, true /* is_constrained */));
447 web_view->LoadInitialURL(url);
448 layout->StartRow(1, 0);
449 layout->AddView(web_view);
450 layout->set_minimum_size(
451 gfx::Size(kMinGaiaViewWidth, kMinGaiaViewHeight));
452 Layout();
453 if (GetBubbleFrameView())
454 SizeToContents();
455 return;
458 // Separate items into active and alternatives.
459 Indexes other_profiles;
460 bool is_guest_view = true;
461 views::View* current_profile_view = NULL;
462 views::View* current_profile_accounts = NULL;
463 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
464 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
465 if (item.active) {
466 if (view_to_display == PROFILE_CHOOSER_VIEW) {
467 current_profile_view = CreateCurrentProfileView(item, false);
468 } else {
469 current_profile_view = CreateCurrentProfileEditableView(item);
470 current_profile_accounts = CreateCurrentProfileAccountsView(item);
472 is_guest_view = false;
473 } else {
474 other_profiles.push_back(i);
478 if (!current_profile_view) // Guest windows don't have an active profile.
479 current_profile_view = CreateGuestProfileView();
481 layout->StartRow(1, 0);
482 layout->AddView(current_profile_view);
484 if (view_to_display == PROFILE_CHOOSER_VIEW) {
485 layout->StartRow(1, 0);
486 layout->AddView(CreateOtherProfilesView(other_profiles));
487 } else {
488 DCHECK(current_profile_accounts);
489 layout->StartRow(0, 0);
490 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
491 layout->StartRow(1, 0);
492 layout->AddView(current_profile_accounts);
495 layout->StartRow(0, 0);
496 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
498 // Action buttons.
499 views::View* option_buttons_view = CreateOptionsView(is_guest_view);
500 layout->StartRow(0, 0);
501 layout->AddView(option_buttons_view);
503 Layout();
504 if (GetBubbleFrameView())
505 SizeToContents();
508 void ProfileChooserView::WindowClosing() {
509 DCHECK_EQ(profile_bubble_, this);
510 profile_bubble_ = NULL;
513 void ProfileChooserView::ButtonPressed(views::Button* sender,
514 const ui::Event& event) {
515 // Disable button after clicking so that it doesn't get clicked twice and
516 // start a second action... which can crash Chrome. But don't disable if it
517 // has no parent (like in tests) because that will also crash.
518 if (sender->parent())
519 sender->SetEnabled(false);
521 if (sender == guest_button_) {
522 profiles::SwitchToGuestProfile(browser_->host_desktop_type(),
523 profiles::ProfileSwitchingDoneCallback());
524 } else if (sender == end_guest_button_) {
525 profiles::CloseGuestProfileWindows();
526 } else if (sender == users_button_) {
527 // Only non-guest users appear in the User Manager.
528 base::FilePath profile_path;
529 if (!end_guest_button_) {
530 size_t active_index = avatar_menu_->GetActiveProfileIndex();
531 profile_path = avatar_menu_->GetItemAt(active_index).profile_path;
533 chrome::ShowUserManager(profile_path);
534 } else if (sender == add_user_button_) {
535 profiles::CreateAndSwitchToNewProfile(
536 browser_->host_desktop_type(),
537 profiles::ProfileSwitchingDoneCallback());
538 } else if (sender == add_account_button_) {
539 ShowView(GAIA_ADD_ACCOUNT_VIEW, avatar_menu_.get());
540 } else if (sender == current_profile_photo_->change_photo_button()) {
541 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
542 } else {
543 // One of the "other profiles" buttons was pressed.
544 ButtonIndexes::const_iterator match =
545 open_other_profile_indexes_map_.find(sender);
546 DCHECK(match != open_other_profile_indexes_map_.end());
547 avatar_menu_->SwitchToProfile(
548 match->second,
549 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW);
553 void ProfileChooserView::OnMenuButtonClicked(views::View* source,
554 const gfx::Point& point) {
555 AccountButtonIndexes::const_iterator match =
556 current_profile_accounts_map_.find(source);
557 DCHECK(match != current_profile_accounts_map_.end());
559 MutableProfileOAuth2TokenService* oauth2_token_service =
560 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
561 browser_->profile());
562 if (oauth2_token_service)
563 oauth2_token_service->RevokeCredentials(match->second);
566 void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
567 if (sender == manage_accounts_link_) {
568 // ShowView() will DCHECK if this view is displayed for non signed-in users.
569 ShowView(ACCOUNT_MANAGEMENT_VIEW, avatar_menu_.get());
570 } else if (sender == signout_current_profile_link_) {
571 profiles::LockProfile(browser_->profile());
572 } else {
573 DCHECK(sender == signin_current_profile_link_);
574 ShowView(GAIA_SIGNIN_VIEW, avatar_menu_.get());
578 bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
579 const ui::KeyEvent& key_event) {
580 views::Textfield* name_textfield =
581 current_profile_name_->profile_name_textfield();
582 DCHECK(sender == name_textfield);
584 if (key_event.key_code() == ui::VKEY_RETURN ||
585 key_event.key_code() == ui::VKEY_TAB) {
586 // Pressing Tab/Enter commits the new profile name, unless it's empty.
587 base::string16 new_profile_name = name_textfield->text();
588 if (new_profile_name.empty())
589 return true;
591 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
592 avatar_menu_->GetActiveProfileIndex());
593 Profile* profile = g_browser_process->profile_manager()->GetProfile(
594 active_item.profile_path);
595 DCHECK(profile);
597 if (profile->IsManaged())
598 return true;
600 profiles::UpdateProfileName(profile, new_profile_name);
601 current_profile_name_->ShowReadOnlyView();
602 return true;
604 return false;
607 views::View* ProfileChooserView::CreateCurrentProfileView(
608 const AvatarMenu::Item& avatar_item,
609 bool is_guest) {
610 views::View* view = new views::View();
611 views::GridLayout* layout = CreateDoubleColumnLayout(view);
612 layout->SetInsets(views::kButtonVEdgeMarginNew,
613 views::kButtonHEdgeMarginNew,
614 views::kButtonVEdgeMarginNew,
615 views::kButtonHEdgeMarginNew);
617 current_profile_photo_ =
618 new EditableProfilePhoto(this, avatar_item.icon, !is_guest);
619 view->SetBoundsRect(current_profile_photo_->bounds());
620 current_profile_name_ =
621 new EditableProfileName(this, avatar_item.name, !is_guest);
623 layout->StartRow(1, 0);
624 layout->AddView(current_profile_photo_, 1, 3);
625 layout->AddView(current_profile_name_);
627 if (is_guest) {
628 layout->StartRow(1, 0);
629 layout->SkipColumns(1);
630 layout->StartRow(1, 0);
631 layout->SkipColumns(1);
632 } else if (avatar_item.signed_in) {
633 manage_accounts_link_ = CreateLink(
634 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON),
635 this);
636 signout_current_profile_link_ = CreateLink(
637 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON), this);
638 layout->StartRow(1, 0);
639 layout->SkipColumns(1);
640 layout->AddView(signout_current_profile_link_);
641 layout->StartRow(1, 0);
642 layout->SkipColumns(1);
643 layout->AddView(manage_accounts_link_);
644 } else {
645 signin_current_profile_link_ = CreateLink(
646 l10n_util::GetStringFUTF16(
647 IDS_SYNC_START_SYNC_BUTTON_LABEL,
648 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)),
649 this);
650 layout->StartRow(1, 0);
651 layout->SkipColumns(1);
652 layout->AddView(signin_current_profile_link_);
653 layout->StartRow(1, 0);
654 layout->SkipColumns(1);
657 return view;
660 views::View* ProfileChooserView::CreateCurrentProfileEditableView(
661 const AvatarMenu::Item& avatar_item) {
662 DCHECK(avatar_item.signed_in);
663 views::View* view = new views::View();
664 views::GridLayout* layout = CreateDoubleColumnLayout(view);
665 layout->SetInsets(views::kButtonVEdgeMarginNew,
666 views::kButtonHEdgeMarginNew,
667 views::kButtonVEdgeMarginNew,
668 views::kButtonHEdgeMarginNew);
670 current_profile_photo_ =
671 new EditableProfilePhoto(this, avatar_item.icon, true);
672 view->SetBoundsRect(current_profile_photo_->bounds());
673 current_profile_name_ =
674 new EditableProfileName(this, avatar_item.name, true);
676 layout->StartRow(1, 0);
677 layout->AddView(current_profile_photo_, 1, 3);
678 layout->AddView(current_profile_name_);
680 layout->StartRow(1, 0);
681 layout->SkipColumns(1);
683 layout->StartRow(1, 0);
684 layout->SkipColumns(1);
685 return view;
688 views::View* ProfileChooserView::CreateGuestProfileView() {
689 gfx::Image guest_icon =
690 ui::ResourceBundle::GetSharedInstance().GetImageNamed(IDR_LOGIN_GUEST);
691 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
692 guest_avatar_item.active = true;
693 guest_avatar_item.name = l10n_util::GetStringUTF16(
694 IDS_PROFILES_GUEST_PROFILE_NAME);
695 guest_avatar_item.signed_in = false;
697 return CreateCurrentProfileView(guest_avatar_item, true);
700 views::View* ProfileChooserView::CreateOtherProfilesView(
701 const Indexes& avatars_to_show) {
702 views::View* view = new views::View();
703 views::GridLayout* layout = CreateSingleColumnLayout(view);
704 layout->SetInsets(0, views::kButtonHEdgeMarginNew,
705 views::kButtonVEdgeMarginNew, views::kButtonHEdgeMarginNew);
706 int num_avatars_to_show = avatars_to_show.size();
707 for (int i = 0; i < num_avatars_to_show; ++i) {
708 const size_t index = avatars_to_show[i];
709 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
710 const int kSmallImageSide = 32;
712 gfx::Image image = profiles::GetSizedAvatarIconWithBorder(
713 item.icon, true,
714 kSmallImageSide + profiles::kAvatarIconPadding,
715 kSmallImageSide + profiles::kAvatarIconPadding);
717 views::TextButton* button = new views::TextButton(this, item.name);
718 open_other_profile_indexes_map_[button] = index;
719 button->SetIcon(*image.ToImageSkia());
720 button->set_icon_text_spacing(views::kItemLabelSpacing);
721 button->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
722 ui::ResourceBundle::MediumFont));
723 button->set_border(NULL);
725 layout->StartRow(1, 0);
726 layout->AddView(button);
728 // The last avatar in the list does not need any bottom padding.
729 if (i < num_avatars_to_show - 1)
730 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
733 return view;
736 views::View* ProfileChooserView::CreateOptionsView(bool is_guest_view) {
737 views::View* view = new views::View();
738 views::GridLayout* layout = CreateSingleColumnLayout(view);
739 // The horizontal padding will be set by each button individually, so that
740 // in the hovered state the button spans the entire parent view.
741 layout->SetInsets(views::kRelatedControlVerticalSpacing, 0,
742 views::kRelatedControlVerticalSpacing, 0);
744 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
746 layout->StartRow(1, 0);
747 if (is_guest_view) {
748 end_guest_button_ = new BackgroundColorHoverButton(
749 this,
750 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST_BUTTON),
751 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_BROWSE_GUEST),
752 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_BROWSE_GUEST_WHITE));
753 layout->AddView(end_guest_button_);
754 } else {
755 guest_button_ = new BackgroundColorHoverButton(
756 this,
757 l10n_util::GetStringUTF16(IDS_PROFILES_GUEST_BUTTON),
758 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_BROWSE_GUEST),
759 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_BROWSE_GUEST_WHITE));
760 layout->AddView(guest_button_);
763 add_user_button_ = new BackgroundColorHoverButton(
764 this,
765 l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON),
766 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_ADD_USER),
767 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_ADD_USER_WHITE));
768 layout->StartRow(1, 0);
769 layout->AddView(add_user_button_);
771 users_button_ = new BackgroundColorHoverButton(
772 this,
773 l10n_util::GetStringUTF16(IDS_PROFILES_ALL_PEOPLE_BUTTON),
774 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_ADD_USER),
775 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_ADD_USER_WHITE));
776 layout->StartRow(1, 0);
777 layout->AddView(users_button_);
779 return view;
782 views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
783 const AvatarMenu::Item& avatar_item) {
784 DCHECK(avatar_item.signed_in);
785 views::View* view = new views::View();
786 views::GridLayout* layout = CreateSingleColumnLayout(view);
787 layout->SetInsets(views::kButtonVEdgeMarginNew,
788 views::kButtonHEdgeMarginNew,
789 views::kButtonVEdgeMarginNew,
790 views::kButtonHEdgeMarginNew);
792 Profile* profile = browser_->profile();
793 std::string primary_account =
794 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername();
795 DCHECK(!primary_account.empty());
796 std::vector<std::string>accounts =
797 profiles::GetSecondaryAccountsForProfile(profile, primary_account);
799 // The primary account should always be listed first.
800 // TODO(rogerta): we still need to further differentiate the primary account
801 // from the others in the UI, so more work is likely required here:
802 // crbug.com/311124.
803 CreateAccountButton(layout, primary_account, true);
804 for (size_t i = 0; i < accounts.size(); ++i)
805 CreateAccountButton(layout, accounts[i], false);
807 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
809 add_account_button_ = new views::BlueButton(
810 this,
811 l10n_util::GetStringFUTF16(IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON,
812 avatar_item.name));
813 layout->StartRow(1, 0);
814 layout->AddView(add_account_button_);
815 return view;
818 void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
819 const std::string& account,
820 bool is_primary_account) {
821 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
822 // Use a MenuButtonListener and not a regular ButtonListener to be
823 // able to distinguish between the unnamed "other profile" buttons and the
824 // unnamed "multiple accounts" buttons.
825 views::MenuButton* email_button = new views::MenuButton(
826 NULL,
827 gfx::ElideEmail(base::UTF8ToUTF16(account),
828 rb->GetFontList(ui::ResourceBundle::BaseFont),
829 width()),
830 is_primary_account ? NULL : this, // Cannot delete the primary account.
831 !is_primary_account);
832 email_button->set_border(views::Border::CreateEmptyBorder(0, 0, 0, 0));
833 if (!is_primary_account) {
834 email_button->set_menu_marker(
835 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia());
836 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
838 layout->StartRow(1, 0);
839 layout->AddView(email_button);
841 // Save the original email address, as the button text could be elided.
842 current_profile_accounts_map_[email_button] = account;