profile_chooser_view.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
1// Copyright 2014 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/profiles/profile_chooser_view.h" 6 7#include "base/prefs/pref_service.h" 8#include "base/strings/utf_string_conversions.h" 9#include "chrome/browser/browser_process.h" 10#include "chrome/browser/lifetime/application_lifetime.h" 11#include "chrome/browser/profiles/profile_avatar_icon_util.h" 12#include "chrome/browser/profiles/profile_info_cache.h" 13#include "chrome/browser/profiles/profile_manager.h" 14#include "chrome/browser/profiles/profile_window.h" 15#include "chrome/browser/profiles/profiles_state.h" 16#include "chrome/browser/signin/profile_oauth2_token_service_factory.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_commands.h" 21#include "chrome/browser/ui/browser_dialogs.h" 22#include "chrome/browser/ui/chrome_pages.h" 23#include "chrome/browser/ui/singleton_tabs.h" 24#include "chrome/browser/ui/views/profiles/user_manager_view.h" 25#include "chrome/common/pref_names.h" 26#include "chrome/common/url_constants.h" 27#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h" 28#include "components/signin/core/browser/profile_oauth2_token_service.h" 29#include "components/signin/core/browser/signin_manager.h" 30#include "components/signin/core/common/profile_management_switches.h" 31#include "grit/chromium_strings.h" 32#include "grit/generated_resources.h" 33#include "grit/theme_resources.h" 34#include "third_party/skia/include/core/SkColor.h" 35#include "ui/base/l10n/l10n_util.h" 36#include "ui/base/resource/resource_bundle.h" 37#include "ui/gfx/canvas.h" 38#include "ui/gfx/image/image.h" 39#include "ui/gfx/image/image_skia.h" 40#include "ui/gfx/text_elider.h" 41#include "ui/native_theme/native_theme.h" 42#include "ui/views/controls/button/blue_button.h" 43#include "ui/views/controls/button/image_button.h" 44#include "ui/views/controls/button/label_button.h" 45#include "ui/views/controls/button/menu_button.h" 46#include "ui/views/controls/label.h" 47#include "ui/views/controls/link.h" 48#include "ui/views/controls/separator.h" 49#include "ui/views/controls/styled_label.h" 50#include "ui/views/controls/textfield/textfield.h" 51#include "ui/views/controls/webview/webview.h" 52#include "ui/views/layout/grid_layout.h" 53#include "ui/views/layout/layout_constants.h" 54#include "ui/views/widget/widget.h" 55 56namespace { 57 58// Helpers -------------------------------------------------------------------- 59 60const int kFixedMenuWidth = 250; 61const int kButtonHeight = 29; 62const int kProfileAvatarTutorialShowMax = 5; 63const int kFixedGaiaViewHeight = 400; 64const int kFixedGaiaViewWidth = 360; 65const int kFixedAccountRemovalViewWidth = 280; 66const int kFixedEndPreviewViewWidth = 280; 67const int kLargeImageSide = 88; 68 69// Creates a GridLayout with a single column. This ensures that all the child 70// views added get auto-expanded to fill the full width of the bubble. 71views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) { 72 views::GridLayout* layout = new views::GridLayout(view); 73 view->SetLayoutManager(layout); 74 75 views::ColumnSet* columns = layout->AddColumnSet(0); 76 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 77 views::GridLayout::FIXED, width, width); 78 return layout; 79} 80 81views::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; 88} 89 90gfx::ImageSkia CreateSquarePlaceholderImage(int size) { 91 SkBitmap bitmap; 92 bitmap.setConfig(SkBitmap::kA8_Config, size, size); 93 bitmap.allocPixels(); 94 bitmap.eraseARGB(0, 0, 0, 0); 95 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); 96} 97 98// BackgroundColorHoverButton ------------------------------------------------- 99 100// A custom button that allows for setting a background color when hovered over. 101class BackgroundColorHoverButton : public views::LabelButton { 102 public: 103 BackgroundColorHoverButton(views::ButtonListener* listener, 104 const base::string16& text, 105 const gfx::ImageSkia& normal_icon, 106 const gfx::ImageSkia& hover_icon); 107 virtual ~BackgroundColorHoverButton(); 108 109 private: 110 // views::LabelButton: 111 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 112 113 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton); 114}; 115 116BackgroundColorHoverButton::BackgroundColorHoverButton( 117 views::ButtonListener* listener, 118 const base::string16& text, 119 const gfx::ImageSkia& normal_icon, 120 const gfx::ImageSkia& hover_icon) 121 : views::LabelButton(listener, text) { 122 SetBorder(views::Border::CreateEmptyBorder(0, views::kButtonHEdgeMarginNew, 123 0, views::kButtonHEdgeMarginNew)); 124 set_min_size(gfx::Size(0, kButtonHeight)); 125 SetImage(STATE_NORMAL, normal_icon); 126 SetImage(STATE_HOVERED, hover_icon); 127 SetImage(STATE_PRESSED, hover_icon); 128} 129 130BackgroundColorHoverButton::~BackgroundColorHoverButton() {} 131 132void BackgroundColorHoverButton::OnPaint(gfx::Canvas* canvas) { 133 if ((state() == STATE_PRESSED) || (state() == STATE_HOVERED) || HasFocus()) { 134 canvas->DrawColor(GetNativeTheme()->GetSystemColor( 135 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor)); 136 } 137 LabelButton::OnPaint(canvas); 138} 139 140} // namespace 141 142 143// EditableProfilePhoto ------------------------------------------------- 144 145// A custom Image control that shows a "change" button when moused over. 146class EditableProfilePhoto : public views::ImageView { 147 public: 148 EditableProfilePhoto(views::ButtonListener* listener, 149 const gfx::Image& icon, 150 bool is_editing_allowed, 151 const gfx::Rect& bounds) 152 : views::ImageView(), 153 change_photo_button_(NULL) { 154 gfx::Image image = profiles::GetSizedAvatarIcon( 155 icon, true, 156 kLargeImageSide + profiles::kAvatarIconPadding, 157 kLargeImageSide + profiles::kAvatarIconPadding); 158 SetImage(image.ToImageSkia()); 159 SetBoundsRect(bounds); 160 161 if (!is_editing_allowed) 162 return; 163 164 set_notify_enter_exit_on_child(true); 165 166 // Button overlay that appears when hovering over the image. 167 change_photo_button_ = new views::LabelButton(listener, 168 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_CHANGE_PHOTO_BUTTON)); 169 change_photo_button_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 170 change_photo_button_->SetBorder(views::Border::NullBorder()); 171 const SkColor color = SK_ColorWHITE; 172 change_photo_button_->SetTextColor(views::Button::STATE_NORMAL, color); 173 change_photo_button_->SetTextColor(views::Button::STATE_HOVERED, color); 174 175 const SkColor kBackgroundColor = SkColorSetARGB(125, 0, 0, 0); 176 change_photo_button_->set_background( 177 views::Background::CreateSolidBackground(kBackgroundColor)); 178 // Need to take into account the border padding on the avatar. 179 const int kOverlayHeight = 20; 180 change_photo_button_->SetBounds( 181 bounds.origin().x(), 182 bounds.origin().y() + kLargeImageSide - kOverlayHeight, 183 kLargeImageSide, 184 kOverlayHeight); 185 change_photo_button_->SetVisible(false); 186 AddChildView(change_photo_button_); 187 } 188 189 views::LabelButton* change_photo_button() { return change_photo_button_; } 190 191 private: 192 // views::View: 193 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE { 194 if (change_photo_button_) 195 change_photo_button_->SetVisible(true); 196 } 197 198 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE { 199 if (change_photo_button_) 200 change_photo_button_->SetVisible(false); 201 } 202 203 // Button that is shown when hovering over the image view. Can be NULL if 204 // the photo isn't allowed to be edited (e.g. for guest profiles). 205 views::LabelButton* change_photo_button_; 206 207 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto); 208}; 209 210 211// EditableProfileName ------------------------------------------------- 212 213// A custom text control that turns into a textfield for editing when clicked. 214class EditableProfileName : public views::LabelButton, 215 public views::ButtonListener { 216 public: 217 EditableProfileName(views::TextfieldController* controller, 218 const base::string16& text, 219 bool is_editing_allowed) 220 : views::LabelButton(this, text), 221 profile_name_textfield_(NULL) { 222 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 223 const gfx::FontList& medium_font_list = 224 rb->GetFontList(ui::ResourceBundle::MediumFont); 225 SetFontList(medium_font_list); 226 SetHorizontalAlignment(gfx::ALIGN_CENTER); 227 228 if (!is_editing_allowed) 229 return; 230 231 // Show an "edit" pencil icon when hovering over. In the default state, 232 // we need to create an empty placeholder of the correct size, so that 233 // the text doesn't jump around when the hovered icon appears. 234 gfx::ImageSkia hover_image = 235 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER); 236 SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width())); 237 SetImage(STATE_HOVERED, hover_image); 238 SetImage(STATE_PRESSED, 239 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED)); 240 // To center the text, we need to offest it by the width of the icon we 241 // are adding. We need to also add a small top/bottom padding to account 242 // for the textfield's border. 243 SetBorder(views::Border::CreateEmptyBorder(2, hover_image.width(), 2, 0)); 244 245 // Textfield that overlaps the button. 246 profile_name_textfield_ = new views::Textfield(); 247 profile_name_textfield_->set_controller(controller); 248 profile_name_textfield_->SetFontList(medium_font_list); 249 profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 250 251 profile_name_textfield_->SetVisible(false); 252 AddChildView(profile_name_textfield_); 253 } 254 255 views::Textfield* profile_name_textfield() { 256 return profile_name_textfield_; 257 } 258 259 // Hide the editable textfield to show the profile name button instead. 260 void ShowReadOnlyView() { 261 if (profile_name_textfield_) 262 profile_name_textfield_->SetVisible(false); 263 } 264 265 private: 266 // views::ButtonListener: 267 virtual void ButtonPressed(views::Button* sender, 268 const ui::Event& event) OVERRIDE { 269 if (profile_name_textfield_) { 270 profile_name_textfield_->SetVisible(true); 271 profile_name_textfield_->SetText(GetText()); 272 profile_name_textfield_->SelectAll(false); 273 profile_name_textfield_->RequestFocus(); 274 } 275 } 276 277 // views::LabelButton: 278 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE { 279 // Override CustomButton's implementation, which presses the button when 280 // you press space and clicks it when you release space, as the space can be 281 // part of the new profile name typed in the textfield. 282 return false; 283 } 284 285 virtual void Layout() OVERRIDE { 286 if (profile_name_textfield_) 287 profile_name_textfield_->SetBounds(0, 0, width(), height()); 288 // This layout trick keeps the text left-aligned and the icon right-aligned. 289 SetHorizontalAlignment(gfx::ALIGN_RIGHT); 290 views::LabelButton::Layout(); 291 label()->SetHorizontalAlignment(gfx::ALIGN_CENTER); 292 } 293 294 // Textfield that is shown when editing the profile name. Can be NULL if 295 // the profile name isn't allowed to be edited (e.g. for guest profiles). 296 views::Textfield* profile_name_textfield_; 297 298 DISALLOW_COPY_AND_ASSIGN(EditableProfileName); 299}; 300 301// A title card with one back button right aligned and one label center aligned. 302class TitleCard : public views::View { 303 public: 304 TitleCard(int message_id, views::ButtonListener* listener, 305 views::ImageButton** back_button) { 306 back_button_ = new views::ImageButton(listener); 307 back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, 308 views::ImageButton::ALIGN_MIDDLE); 309 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 310 back_button_->SetImage(views::ImageButton::STATE_NORMAL, 311 rb->GetImageSkiaNamed(IDR_BACK)); 312 back_button_->SetImage(views::ImageButton::STATE_HOVERED, 313 rb->GetImageSkiaNamed(IDR_BACK_H)); 314 back_button_->SetImage(views::ImageButton::STATE_PRESSED, 315 rb->GetImageSkiaNamed(IDR_BACK_P)); 316 back_button_->SetImage(views::ImageButton::STATE_DISABLED, 317 rb->GetImageSkiaNamed(IDR_BACK_D)); 318 *back_button = back_button_; 319 320 title_label_ = new views::Label(l10n_util::GetStringUTF16(message_id)); 321 title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 322 const gfx::FontList& medium_font_list = 323 rb->GetFontList(ui::ResourceBundle::MediumFont); 324 title_label_->SetFontList(medium_font_list); 325 326 AddChildView(back_button_); 327 AddChildView(title_label_); 328 } 329 330 private: 331 virtual void Layout() OVERRIDE{ 332 back_button_->SetBounds( 333 0, 0, back_button_->GetPreferredSize().width(), height()); 334 title_label_->SetBoundsRect(GetContentsBounds()); 335 } 336 337 virtual gfx::Size GetPreferredSize() OVERRIDE{ 338 int height = profiles::kAvatarIconPadding * 2 + 339 std::max(title_label_->GetPreferredSize().height(), 340 back_button_->GetPreferredSize().height()); 341 return gfx::Size(width(), height); 342 } 343 344 views::ImageButton* back_button_; 345 views::Label* title_label_; 346 347 DISALLOW_COPY_AND_ASSIGN(TitleCard); 348}; 349 350// ProfileChooserView --------------------------------------------------------- 351 352// static 353ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL; 354bool ProfileChooserView::close_on_deactivate_for_testing_ = true; 355 356// static 357void ProfileChooserView::ShowBubble( 358 BubbleViewMode view_mode, 359 views::View* anchor_view, 360 views::BubbleBorder::Arrow arrow, 361 views::BubbleBorder::BubbleAlignment border_alignment, 362 const gfx::Rect& anchor_rect, 363 Browser* browser) { 364 profile_bubble_ = new ProfileChooserView(anchor_view, arrow, anchor_rect, 365 browser, view_mode); 366 views::BubbleDelegateView::CreateBubble(profile_bubble_); 367 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_); 368 profile_bubble_->SetAlignment(border_alignment); 369 profile_bubble_->GetWidget()->Show(); 370 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE); 371} 372 373// static 374bool ProfileChooserView::IsShowing() { 375 return profile_bubble_ != NULL; 376} 377 378// static 379void ProfileChooserView::Hide() { 380 if (IsShowing()) 381 profile_bubble_->GetWidget()->Close(); 382} 383 384ProfileChooserView::ProfileChooserView(views::View* anchor_view, 385 views::BubbleBorder::Arrow arrow, 386 const gfx::Rect& anchor_rect, 387 Browser* browser, 388 BubbleViewMode view_mode) 389 : BubbleDelegateView(anchor_view, arrow), 390 browser_(browser), 391 view_mode_(view_mode), 392 tutorial_mode_(TUTORIAL_MODE_NONE) { 393 // Reset the default margins inherited from the BubbleDelegateView. 394 set_margins(gfx::Insets()); 395 396 ResetView(); 397 398 set_background(views::Background::CreateSolidBackground( 399 GetNativeTheme()->GetSystemColor( 400 ui::NativeTheme::kColorId_DialogBackground))); 401 402 avatar_menu_.reset(new AvatarMenu( 403 &g_browser_process->profile_manager()->GetProfileInfoCache(), 404 this, 405 browser_)); 406 avatar_menu_->RebuildMenu(); 407 408 ProfileOAuth2TokenService* oauth2_token_service = 409 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile()); 410 if (oauth2_token_service) 411 oauth2_token_service->AddObserver(this); 412} 413 414ProfileChooserView::~ProfileChooserView() { 415 ProfileOAuth2TokenService* oauth2_token_service = 416 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile()); 417 if (oauth2_token_service) 418 oauth2_token_service->RemoveObserver(this); 419} 420 421void ProfileChooserView::ResetView() { 422 question_mark_button_ = NULL; 423 manage_accounts_link_ = NULL; 424 signin_current_profile_link_ = NULL; 425 users_button_ = NULL; 426 lock_button_ = NULL; 427 add_account_link_ = NULL; 428 current_profile_photo_ = NULL; 429 current_profile_name_ = NULL; 430 tutorial_ok_button_ = NULL; 431 tutorial_learn_more_link_ = NULL; 432 tutorial_enable_new_profile_management_button_ = NULL; 433 tutorial_end_preview_link_ = NULL; 434 tutorial_send_feedback_button_ = NULL; 435 end_preview_and_relaunch_button_ = NULL; 436 end_preview_cancel_button_ = NULL; 437 remove_account_and_relaunch_button_ = NULL; 438 account_removal_cancel_button_ = NULL; 439 gaia_signin_cancel_button_ = NULL; 440 open_other_profile_indexes_map_.clear(); 441 current_profile_accounts_map_.clear(); 442 tutorial_mode_ = TUTORIAL_MODE_NONE; 443} 444 445void ProfileChooserView::Init() { 446 ShowView(view_mode_, avatar_menu_.get()); 447} 448 449void ProfileChooserView::OnAvatarMenuChanged( 450 AvatarMenu* avatar_menu) { 451 // Refresh the view with the new menu. We can't just update the local copy 452 // as this may have been triggered by a sign out action, in which case 453 // the view is being destroyed. 454 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu); 455} 456 457void ProfileChooserView::OnRefreshTokenAvailable( 458 const std::string& account_id) { 459 // Refresh the account management view when a new account is added to the 460 // profile. 461 if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT || 462 view_mode_ == BUBBLE_VIEW_MODE_GAIA_SIGNIN || 463 view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT) { 464 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 465 } 466} 467 468void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) { 469 // Refresh the account management view when an account is removed from the 470 // profile. 471 if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) 472 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 473} 474 475void ProfileChooserView::ShowView(BubbleViewMode view_to_display, 476 AvatarMenu* avatar_menu) { 477 // The account management view should only be displayed if the active profile 478 // is signed in. 479 if (view_to_display == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) { 480 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt( 481 avatar_menu->GetActiveProfileIndex()); 482 DCHECK(active_item.signed_in); 483 } 484 485 // Records the last tutorial mode. 486 TutorialMode last_tutorial_mode = tutorial_mode_; 487 ResetView(); 488 RemoveAllChildViews(true); 489 view_mode_ = view_to_display; 490 491 views::GridLayout* layout; 492 views::View* sub_view; 493 switch (view_mode_) { 494 case BUBBLE_VIEW_MODE_GAIA_SIGNIN: 495 case BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT: 496 layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth); 497 sub_view = CreateGaiaSigninView( 498 view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT); 499 break; 500 case BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL: 501 layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth); 502 sub_view = CreateAccountRemovalView(); 503 break; 504 case BUBBLE_VIEW_MODE_END_PREVIEW: 505 layout = CreateSingleColumnLayout(this, kFixedEndPreviewViewWidth); 506 sub_view = CreateEndPreviewView(); 507 break; 508 default: 509 layout = CreateSingleColumnLayout(this, kFixedMenuWidth); 510 sub_view = CreateProfileChooserView(avatar_menu, last_tutorial_mode); 511 } 512 layout->StartRow(1, 0); 513 layout->AddView(sub_view); 514 Layout(); 515 if (GetBubbleFrameView()) 516 SizeToContents(); 517} 518 519void ProfileChooserView::WindowClosing() { 520 DCHECK_EQ(profile_bubble_, this); 521 profile_bubble_ = NULL; 522} 523 524void ProfileChooserView::ButtonPressed(views::Button* sender, 525 const ui::Event& event) { 526 // Disable button after clicking so that it doesn't get clicked twice and 527 // start a second action... which can crash Chrome. But don't disable if it 528 // has no parent (like in tests) because that will also crash. 529 if (sender->parent()) 530 sender->SetEnabled(false); 531 532 if (sender == users_button_) { 533 profiles::ShowUserManagerMaybeWithTutorial(browser_->profile()); 534 // If this is a guest session, also close all the guest browser windows. 535 if (browser_->profile()->IsGuestSession()) 536 profiles::CloseGuestProfileWindows(); 537 } else if (sender == lock_button_) { 538 profiles::LockProfile(browser_->profile()); 539 } else if (sender == tutorial_ok_button_) { 540 // If the user manually dismissed the tutorial, never show it again by 541 // setting the number of times shown to the maximum plus 1, so that later we 542 // could distinguish between the dismiss case and the case when the tutorial 543 // is indeed shown for the maximum number of times. 544 browser_->profile()->GetPrefs()->SetInteger( 545 prefs::kProfileAvatarTutorialShown, kProfileAvatarTutorialShowMax + 1); 546 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); 547 } else if (sender == tutorial_enable_new_profile_management_button_) { 548 profiles::EnableNewProfileManagementPreview(); 549 } else if (sender == remove_account_and_relaunch_button_) { 550 RemoveAccount(); 551 } else if (sender == account_removal_cancel_button_) { 552 account_id_to_remove_.clear(); 553 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 554 } else if (sender == gaia_signin_cancel_button_) { 555 std::string primary_account = 556 SigninManagerFactory::GetForProfile(browser_->profile())-> 557 GetAuthenticatedUsername(); 558 ShowView(primary_account.empty() ? BUBBLE_VIEW_MODE_PROFILE_CHOOSER : 559 BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, 560 avatar_menu_.get()); 561 } else if (sender == question_mark_button_) { 562 tutorial_mode_ = TUTORIAL_MODE_SEND_FEEDBACK; 563 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); 564 } else if (sender == tutorial_send_feedback_button_) { 565 chrome::OpenFeedbackDialog(browser_); 566 } else if (sender == end_preview_and_relaunch_button_) { 567 profiles::DisableNewProfileManagementPreview(); 568 } else if (sender == end_preview_cancel_button_) { 569 tutorial_mode_ = TUTORIAL_MODE_SEND_FEEDBACK; 570 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); 571 } else if (current_profile_photo_ && 572 sender == current_profile_photo_->change_photo_button()) { 573 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex()); 574 } else if (sender == signin_current_profile_link_) { 575 ShowView(BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get()); 576 } else { 577 // Either one of the "other profiles", or one of the profile accounts 578 // buttons was pressed. 579 ButtonIndexes::const_iterator profile_match = 580 open_other_profile_indexes_map_.find(sender); 581 if (profile_match != open_other_profile_indexes_map_.end()) { 582 avatar_menu_->SwitchToProfile( 583 profile_match->second, 584 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW, 585 ProfileMetrics::SWITCH_PROFILE_ICON); 586 } else { 587 // This was a profile accounts button. 588 AccountButtonIndexes::const_iterator account_match = 589 current_profile_accounts_map_.find(sender); 590 DCHECK(account_match != current_profile_accounts_map_.end()); 591 account_id_to_remove_ = account_match->second; 592 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL, avatar_menu_.get()); 593 } 594 } 595} 596 597void ProfileChooserView::RemoveAccount() { 598 DCHECK(!account_id_to_remove_.empty()); 599 MutableProfileOAuth2TokenService* oauth2_token_service = 600 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile( 601 browser_->profile()); 602 if (oauth2_token_service) 603 oauth2_token_service->RevokeCredentials(account_id_to_remove_); 604 account_id_to_remove_.clear(); 605 606 chrome::AttemptRestart(); 607} 608 609void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) { 610 if (sender == manage_accounts_link_) { 611 // This link can either mean show/hide the account management view, 612 // depending on which view it is displayed. ShowView() will DCHECK if 613 // the account management view is displayed for non signed-in users. 614 ShowView( 615 view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ? 616 BUBBLE_VIEW_MODE_PROFILE_CHOOSER : 617 BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, 618 avatar_menu_.get()); 619 } else if (sender == add_account_link_) { 620 ShowView(BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get()); 621 } else if (sender == tutorial_learn_more_link_) { 622 // TODO(guohui): update |learn_more_url| once it is decided. 623 const GURL lear_more_url("https://support.google.com/chrome/?hl=en#to"); 624 chrome::NavigateParams params( 625 browser_->profile(), 626 lear_more_url, 627 content::PAGE_TRANSITION_LINK); 628 params.disposition = NEW_FOREGROUND_TAB; 629 chrome::Navigate(¶ms); 630 } else { 631 DCHECK(sender == tutorial_end_preview_link_); 632 ShowView(BUBBLE_VIEW_MODE_END_PREVIEW, avatar_menu_.get()); 633 } 634} 635 636void ProfileChooserView::StyledLabelLinkClicked( 637 const gfx::Range& range, int event_flags) { 638 chrome::ShowSettings(browser_); 639} 640 641bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender, 642 const ui::KeyEvent& key_event) { 643 views::Textfield* name_textfield = 644 current_profile_name_->profile_name_textfield(); 645 DCHECK(sender == name_textfield); 646 647 if (key_event.key_code() == ui::VKEY_RETURN || 648 key_event.key_code() == ui::VKEY_TAB) { 649 // Pressing Tab/Enter commits the new profile name, unless it's empty. 650 base::string16 new_profile_name = name_textfield->text(); 651 if (new_profile_name.empty()) 652 return true; 653 654 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt( 655 avatar_menu_->GetActiveProfileIndex()); 656 Profile* profile = g_browser_process->profile_manager()->GetProfile( 657 active_item.profile_path); 658 DCHECK(profile); 659 660 if (profile->IsManaged()) 661 return true; 662 663 profiles::UpdateProfileName(profile, new_profile_name); 664 current_profile_name_->ShowReadOnlyView(); 665 return true; 666 } 667 return false; 668} 669 670views::View* ProfileChooserView::CreateProfileChooserView( 671 AvatarMenu* avatar_menu, TutorialMode last_tutorial_mode) { 672 // TODO(guohui, noms): the view should be customized based on whether new 673 // profile management preview is enabled or not. 674 675 views::View* view = new views::View(); 676 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 677 // Separate items into active and alternatives. 678 Indexes other_profiles; 679 views::View* tutorial_view = NULL; 680 views::View* current_profile_view = NULL; 681 views::View* current_profile_accounts = NULL; 682 views::View* option_buttons_view = NULL; 683 bool is_new_profile_management = switches::IsNewProfileManagement(); 684 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) { 685 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i); 686 if (item.active) { 687 option_buttons_view = CreateOptionsView(item.signed_in); 688 current_profile_view = CreateCurrentProfileView(item, false); 689 if (view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { 690 if (is_new_profile_management) { 691 tutorial_view = last_tutorial_mode == TUTORIAL_MODE_SEND_FEEDBACK ? 692 CreateSendPreviewFeedbackView() : 693 CreatePreviewEnabledTutorialView( 694 item, last_tutorial_mode == TUTORIAL_MODE_PREVIEW_ENABLED); 695 } else { 696 tutorial_view = CreateNewProfileManagementPreviewView(); 697 } 698 } else { 699 current_profile_accounts = CreateCurrentProfileAccountsView(item); 700 } 701 } else { 702 other_profiles.push_back(i); 703 } 704 } 705 706 if (tutorial_view) { 707 layout->StartRow(1, 0); 708 layout->AddView(tutorial_view); 709 } 710 711 if (!current_profile_view) { 712 // Guest windows don't have an active profile. 713 current_profile_view = CreateGuestProfileView(); 714 option_buttons_view = CreateOptionsView(false); 715 } 716 717 layout->StartRow(1, 0); 718 layout->AddView(current_profile_view); 719 720 if (view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { 721 layout->StartRow(1, 0); 722 if (switches::IsFastUserSwitching()) 723 layout->AddView(CreateOtherProfilesView(other_profiles)); 724 } else { 725 DCHECK(current_profile_accounts); 726 layout->StartRow(0, 0); 727 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 728 layout->StartRow(1, 0); 729 layout->AddView(current_profile_accounts); 730 } 731 732 layout->StartRow(0, 0); 733 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 734 735 // Option buttons. Only available with the new profile management flag. 736 if (switches::IsNewProfileManagement()) { 737 layout->StartRow(0, 0); 738 layout->AddView(option_buttons_view); 739 } 740 741 return view; 742} 743 744views::View* ProfileChooserView::CreatePreviewEnabledTutorialView( 745 const AvatarMenu::Item& current_avatar_item, 746 bool tutorial_shown) { 747 if (!switches::IsNewProfileManagementPreviewEnabled()) 748 return NULL; 749 750 Profile* profile = browser_->profile(); 751 const int show_count = profile->GetPrefs()->GetInteger( 752 prefs::kProfileAvatarTutorialShown); 753 // Do not show the tutorial if user has dismissed it. 754 if (show_count > kProfileAvatarTutorialShowMax) 755 return NULL; 756 757 if (!tutorial_shown) { 758 if (show_count == kProfileAvatarTutorialShowMax) 759 return NULL; 760 profile->GetPrefs()->SetInteger( 761 prefs::kProfileAvatarTutorialShown, show_count + 1); 762 } 763 764 return CreateTutorialView( 765 TUTORIAL_MODE_PREVIEW_ENABLED, 766 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_TITLE), 767 l10n_util::GetStringUTF16( 768 IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_CONTENT_TEXT), 769 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE), 770 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON), 771 &tutorial_learn_more_link_, 772 &tutorial_ok_button_); 773} 774 775views::View* ProfileChooserView::CreateSendPreviewFeedbackView() { 776 return CreateTutorialView( 777 TUTORIAL_MODE_SEND_FEEDBACK, 778 l10n_util::GetStringUTF16(IDS_PROFILES_FEEDBACK_TUTORIAL_TITLE), 779 l10n_util::GetStringUTF16( 780 IDS_PROFILES_FEEDBACK_TUTORIAL_CONTENT_TEXT), 781 l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW), 782 l10n_util::GetStringUTF16(IDS_PROFILES_SEND_FEEDBACK_BUTTON), 783 &tutorial_end_preview_link_, 784 &tutorial_send_feedback_button_); 785} 786 787views::View* ProfileChooserView::CreateTutorialView( 788 TutorialMode tutorial_mode, 789 const base::string16& title_text, 790 const base::string16& content_text, 791 const base::string16& link_text, 792 const base::string16& button_text, 793 views::Link** link, 794 views::LabelButton** button) { 795 tutorial_mode_ = tutorial_mode; 796 797 views::View* view = new views::View(); 798 view->set_background(views::Background::CreateSolidBackground( 799 profiles::kAvatarTutorialBackgroundColor)); 800 views::GridLayout* layout = CreateSingleColumnLayout(view, 801 kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew); 802 layout->SetInsets(views::kButtonVEdgeMarginNew, 803 views::kButtonHEdgeMarginNew, 804 views::kButtonVEdgeMarginNew, 805 views::kButtonHEdgeMarginNew); 806 807 // Adds title. 808 views::Label* title_label = new views::Label(title_text); 809 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 810 title_label->SetAutoColorReadabilityEnabled(false); 811 title_label->SetEnabledColor(SK_ColorWHITE); 812 title_label ->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( 813 ui::ResourceBundle::MediumFont)); 814 layout->StartRow(1, 0); 815 layout->AddView(title_label); 816 817 // Adds body content. 818 views::Label* content_label = new views::Label(content_text); 819 content_label->SetMultiLine(true); 820 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 821 content_label->SetAutoColorReadabilityEnabled(false); 822 content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor); 823 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing); 824 layout->AddView(content_label); 825 826 // Adds links and buttons. 827 views::View* button_row = new views::View(); 828 views::GridLayout* button_layout = new views::GridLayout(button_row); 829 views::ColumnSet* button_columns = button_layout->AddColumnSet(0); 830 button_columns->AddColumn(views::GridLayout::LEADING, 831 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 832 button_columns->AddPaddingColumn( 833 1, views::kUnrelatedControlHorizontalSpacing); 834 button_columns->AddColumn(views::GridLayout::TRAILING, 835 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 836 button_row->SetLayoutManager(button_layout); 837 838 *link = CreateLink(link_text, this); 839 (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT); 840 (*link)->SetAutoColorReadabilityEnabled(false); 841 (*link)->SetEnabledColor(SK_ColorWHITE); 842 button_layout->StartRow(1, 0); 843 button_layout->AddView(*link); 844 845 *button = new views::LabelButton(this, button_text); 846 (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER); 847 (*button)->SetStyle(views::Button::STYLE_BUTTON); 848 button_layout->AddView(*button); 849 850 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); 851 layout->AddView(button_row); 852 853 // Adds a padded caret image at the bottom. 854 views::View* padded_caret_view = new views::View(); 855 views::GridLayout* padded_caret_layout = 856 new views::GridLayout(padded_caret_view); 857 views::ColumnSet* padded_columns = padded_caret_layout->AddColumnSet(0); 858 padded_columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 859 padded_columns->AddColumn(views::GridLayout::LEADING, 860 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 861 padded_caret_view->SetLayoutManager(padded_caret_layout); 862 863 views::ImageView* caret_image_view = new views::ImageView(); 864 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 865 caret_image_view->SetImage( 866 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_CARET)); 867 868 padded_caret_layout->StartRow(1, 0); 869 padded_caret_layout->AddView(caret_image_view); 870 871 views::View* view_with_caret = new views::View(); 872 views::GridLayout* layout_with_caret = 873 CreateSingleColumnLayout(view_with_caret, kFixedMenuWidth); 874 layout_with_caret->StartRow(1, 0); 875 layout_with_caret->AddView(view); 876 layout_with_caret->StartRow(1, 0); 877 layout_with_caret->AddView(padded_caret_view); 878 return view_with_caret; 879} 880 881views::View* ProfileChooserView::CreateCurrentProfileView( 882 const AvatarMenu::Item& avatar_item, 883 bool is_guest) { 884 views::View* view = new views::View(); 885 int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew; 886 views::GridLayout* layout = CreateSingleColumnLayout(view, column_width); 887 layout->SetInsets(views::kButtonVEdgeMarginNew, 888 views::kButtonHEdgeMarginNew, 889 views::kRelatedControlVerticalSpacing, 890 views::kButtonHEdgeMarginNew); 891 892 // Profile icon, centered. 893 float x_offset = (column_width - kLargeImageSide) / 2; 894 current_profile_photo_ = new EditableProfilePhoto( 895 this, avatar_item.icon, !is_guest, 896 gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide)); 897 898 if (switches::IsNewProfileManagementPreviewEnabled()) { 899 question_mark_button_ = new views::ImageButton(this); 900 question_mark_button_->SetImageAlignment( 901 views::ImageButton::ALIGN_LEFT, views::ImageButton::ALIGN_MIDDLE); 902 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 903 question_mark_button_->SetImage(views::ImageButton::STATE_NORMAL, 904 rb->GetImageSkiaNamed(IDR_QUESTION_MARK)); 905 gfx::Size preferred_size = question_mark_button_->GetPreferredSize(); 906 question_mark_button_->SetBounds( 907 0, 0, preferred_size.width(), preferred_size.height()); 908 current_profile_photo_->AddChildView(question_mark_button_); 909 } 910 911 layout->StartRow(1, 0); 912 layout->AddView(current_profile_photo_); 913 914 // Profile name, centered. 915 current_profile_name_ = new EditableProfileName( 916 this, profiles::GetAvatarNameForProfile(browser_->profile()), !is_guest); 917 layout->StartRow(1, 0); 918 layout->AddView(current_profile_name_); 919 920 if (is_guest) 921 return view; 922 923 // The available links depend on the type of profile that is active. 924 layout->StartRow(1, 0); 925 if (avatar_item.signed_in) { 926 if (switches::IsNewProfileManagement()) { 927 base::string16 link_title = l10n_util::GetStringUTF16( 928 view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER ? 929 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON : 930 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON); 931 manage_accounts_link_ = CreateLink(link_title, this); 932 manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 933 layout->AddView(manage_accounts_link_); 934 } else { 935 views::Label* email_label = new views::Label(avatar_item.sync_state); 936 email_label->SetHorizontalAlignment(gfx::ALIGN_CENTER); 937 layout->AddView(email_label); 938 } 939 } else { 940 signin_current_profile_link_ = new views::BlueButton( 941 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL, 942 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME))); 943 layout->AddView(signin_current_profile_link_); 944 } 945 946 return view; 947} 948 949views::View* ProfileChooserView::CreateGuestProfileView() { 950 gfx::Image guest_icon = 951 ui::ResourceBundle::GetSharedInstance().GetImageNamed( 952 profiles::GetPlaceholderAvatarIconResourceID()); 953 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon); 954 guest_avatar_item.active = true; 955 guest_avatar_item.name = l10n_util::GetStringUTF16( 956 IDS_PROFILES_GUEST_PROFILE_NAME); 957 guest_avatar_item.signed_in = false; 958 959 return CreateCurrentProfileView(guest_avatar_item, true); 960} 961 962views::View* ProfileChooserView::CreateOtherProfilesView( 963 const Indexes& avatars_to_show) { 964 views::View* view = new views::View(); 965 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 966 967 int num_avatars_to_show = avatars_to_show.size(); 968 for (int i = 0; i < num_avatars_to_show; ++i) { 969 const size_t index = avatars_to_show[i]; 970 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index); 971 const int kSmallImageSide = 32; 972 973 gfx::Image image = profiles::GetSizedAvatarIcon( 974 item.icon, true, 975 kSmallImageSide + profiles::kAvatarIconPadding, 976 kSmallImageSide + profiles::kAvatarIconPadding); 977 978 views::LabelButton* button = new BackgroundColorHoverButton( 979 this, 980 item.name, 981 *image.ToImageSkia(), 982 *image.ToImageSkia()); 983 button->set_min_size(gfx::Size( 984 0, kButtonHeight + views::kRelatedControlVerticalSpacing)); 985 986 open_other_profile_indexes_map_[button] = index; 987 988 layout->StartRow(1, 0); 989 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 990 layout->StartRow(1, 0); 991 layout->AddView(button); 992 } 993 994 return view; 995} 996 997views::View* ProfileChooserView::CreateOptionsView(bool enable_lock) { 998 views::View* view = new views::View(); 999 views::GridLayout* layout; 1000 1001 // Only signed-in users have the ability to lock. 1002 if (enable_lock) { 1003 layout = new views::GridLayout(view); 1004 views::ColumnSet* columns = layout->AddColumnSet(0); 1005 int width_of_lock_button = 1006 2 * views::kUnrelatedControlLargeHorizontalSpacing + 12; 1007 int width_of_users_button = kFixedMenuWidth - width_of_lock_button; 1008 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 1009 views::GridLayout::FIXED, width_of_users_button, 1010 width_of_users_button); 1011 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 1012 views::GridLayout::FIXED, width_of_lock_button, 1013 width_of_lock_button); 1014 view->SetLayoutManager(layout); 1015 } else { 1016 layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 1017 } 1018 1019 base::string16 text = browser_->profile()->IsGuestSession() ? 1020 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) : 1021 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU_BUTTON, 1022 profiles::GetAvatarNameForProfile(browser_->profile())); 1023 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1024 users_button_ = new BackgroundColorHoverButton( 1025 this, 1026 text, 1027 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR), 1028 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR)); 1029 users_button_->set_min_size(gfx::Size( 1030 0, kButtonHeight + views::kRelatedControlVerticalSpacing)); 1031 1032 layout->StartRow(1, 0); 1033 layout->AddView(users_button_); 1034 1035 if (enable_lock) { 1036 lock_button_ = new BackgroundColorHoverButton( 1037 this, 1038 base::string16(), 1039 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK), 1040 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK)); 1041 lock_button_->set_min_size(gfx::Size( 1042 0, kButtonHeight + views::kRelatedControlVerticalSpacing)); 1043 layout->AddView(lock_button_); 1044 } 1045 return view; 1046} 1047 1048views::View* ProfileChooserView::CreateCurrentProfileAccountsView( 1049 const AvatarMenu::Item& avatar_item) { 1050 DCHECK(avatar_item.signed_in); 1051 views::View* view = new views::View(); 1052 view->set_background(views::Background::CreateSolidBackground( 1053 profiles::kAvatarBubbleAccountsBackgroundColor)); 1054 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 1055 1056 Profile* profile = browser_->profile(); 1057 std::string primary_account = 1058 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername(); 1059 DCHECK(!primary_account.empty()); 1060 std::vector<std::string>accounts = 1061 profiles::GetSecondaryAccountsForProfile(profile, primary_account); 1062 1063 // The primary account should always be listed first. 1064 // TODO(rogerta): we still need to further differentiate the primary account 1065 // from the others in the UI, so more work is likely required here: 1066 // crbug.com/311124. 1067 CreateAccountButton(layout, primary_account, true, kFixedMenuWidth); 1068 for (size_t i = 0; i < accounts.size(); ++i) 1069 CreateAccountButton(layout, accounts[i], false, kFixedMenuWidth); 1070 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 1071 1072 add_account_link_ = CreateLink(l10n_util::GetStringFUTF16( 1073 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this); 1074 add_account_link_->SetBorder(views::Border::CreateEmptyBorder( 1075 0, views::kButtonVEdgeMarginNew, 1076 views::kRelatedControlVerticalSpacing, 0)); 1077 layout->StartRow(1, 0); 1078 layout->AddView(add_account_link_); 1079 return view; 1080} 1081 1082void ProfileChooserView::CreateAccountButton(views::GridLayout* layout, 1083 const std::string& account, 1084 bool is_primary_account, 1085 int width) { 1086 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1087 const gfx::ImageSkia* menu_marker = 1088 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia(); 1089 1090 views::LabelButton* email_button = new BackgroundColorHoverButton( 1091 this, 1092 gfx::ElideEmail(base::UTF8ToUTF16(account), 1093 rb->GetFontList(ui::ResourceBundle::BaseFont), 1094 width - menu_marker->width()), 1095 gfx::ImageSkia(), 1096 gfx::ImageSkia()); 1097 layout->StartRow(1, 0); 1098 layout->AddView(email_button); 1099 1100 // Save the original email address, as the button text could be elided. 1101 current_profile_accounts_map_[email_button] = account; 1102} 1103 1104views::View* ProfileChooserView::CreateGaiaSigninView( 1105 bool add_secondary_account) { 1106 views::View* view = new views::View(); 1107 views::GridLayout* layout = 1108 CreateSingleColumnLayout(view, kFixedGaiaViewWidth); 1109 1110 // Adds title. 1111 views::View* padded_title = new views::View(); 1112 int available_width = kFixedGaiaViewWidth - 2 * views::kButtonHEdgeMarginNew; 1113 views::GridLayout* padded_layout = CreateSingleColumnLayout( 1114 padded_title, available_width); 1115 padded_layout->SetInsets(views::kButtonVEdgeMarginNew, 1116 views::kButtonHEdgeMarginNew, 1117 views::kButtonVEdgeMarginNew, 1118 views::kButtonHEdgeMarginNew); 1119 padded_layout->StartRow(1, 0); 1120 padded_layout->AddView(new TitleCard( 1121 add_secondary_account ? IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE : 1122 IDS_PROFILES_GAIA_SIGNIN_TITLE, 1123 this, &gaia_signin_cancel_button_)); 1124 1125 layout->StartRow(1, 0); 1126 layout->AddView(padded_title); 1127 layout->StartRow(1, 0); 1128 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1129 1130 // Adds Gaia signin webview 1131 Profile* profile = browser_->profile(); 1132 views::WebView* web_view = new views::WebView(profile); 1133 signin::Source source = add_secondary_account ? 1134 signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT : 1135 signin::SOURCE_AVATAR_BUBBLE_SIGN_IN; 1136 GURL url(signin::GetPromoURL( 1137 source, false /* auto_close */, true /* is_constrained */)); 1138 web_view->LoadInitialURL(url); 1139 web_view->SetPreferredSize( 1140 gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight)); 1141 1142 layout->StartRow(1, 0); 1143 layout->AddView(web_view); 1144 1145 return view; 1146} 1147 1148views::View* ProfileChooserView::CreateAccountRemovalView() { 1149 views::View* view = new views::View(); 1150 views::GridLayout* layout = CreateSingleColumnLayout( 1151 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew); 1152 layout->SetInsets(views::kButtonVEdgeMarginNew, 1153 views::kButtonHEdgeMarginNew, 1154 views::kButtonVEdgeMarginNew, 1155 views::kButtonHEdgeMarginNew); 1156 1157 // Adds title. 1158 layout->StartRow(1, 0); 1159 layout->AddView(new TitleCard(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE, this, 1160 &account_removal_cancel_button_)); 1161 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing); 1162 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1163 1164 const std::string& primary_account = SigninManagerFactory::GetForProfile( 1165 browser_->profile())->GetAuthenticatedUsername(); 1166 bool is_primary_account = primary_account == account_id_to_remove_; 1167 1168 // Adds main text. 1169 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1170 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1171 const gfx::FontList& small_font_list = 1172 rb->GetFontList(ui::ResourceBundle::SmallFont); 1173 1174 if (is_primary_account) { 1175 std::vector<size_t> offsets; 1176 const base::string16 settings_text = 1177 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK); 1178 const base::string16 primary_account_removal_text = 1179 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT, 1180 base::UTF8ToUTF16(account_id_to_remove_), settings_text, &offsets); 1181 views::StyledLabel* primary_account_removal_label = 1182 new views::StyledLabel(primary_account_removal_text, this); 1183 primary_account_removal_label->AddStyleRange( 1184 gfx::Range(offsets[1], offsets[1] + settings_text.size()), 1185 views::StyledLabel::RangeStyleInfo::CreateForLink()); 1186 primary_account_removal_label->SetBaseFontList(small_font_list); 1187 layout->AddView(primary_account_removal_label); 1188 } else { 1189 views::Label* content_label = new views::Label( 1190 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT)); 1191 content_label->SetMultiLine(true); 1192 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1193 content_label->SetFontList(small_font_list); 1194 layout->AddView(content_label); 1195 } 1196 1197 // Adds button. 1198 if (!is_primary_account) { 1199 remove_account_and_relaunch_button_ = new views::BlueButton( 1200 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON)); 1201 remove_account_and_relaunch_button_->SetHorizontalAlignment( 1202 gfx::ALIGN_CENTER); 1203 layout->StartRowWithPadding( 1204 1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1205 layout->AddView(remove_account_and_relaunch_button_); 1206 } else { 1207 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 1208 } 1209 1210 return view; 1211} 1212 1213views::View* ProfileChooserView::CreateNewProfileManagementPreviewView() { 1214 return CreateTutorialView( 1215 TUTORIAL_MODE_ENABLE_PREVIEW, 1216 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_TITLE), 1217 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_CONTENT_TEXT), 1218 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE), 1219 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_TRY_BUTTON), 1220 &tutorial_learn_more_link_, 1221 &tutorial_enable_new_profile_management_button_); 1222} 1223 1224views::View* ProfileChooserView::CreateEndPreviewView() { 1225 views::View* view = new views::View(); 1226 views::GridLayout* layout = CreateSingleColumnLayout( 1227 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew); 1228 layout->SetInsets(views::kButtonVEdgeMarginNew, 1229 views::kButtonHEdgeMarginNew, 1230 views::kButtonVEdgeMarginNew, 1231 views::kButtonHEdgeMarginNew); 1232 1233 // Adds title. 1234 layout->StartRow(1, 0); 1235 layout->AddView(new TitleCard(IDS_PROFILES_END_PREVIEW, this, 1236 &end_preview_cancel_button_)); 1237 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing); 1238 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1239 1240 // Adds main text. 1241 views::Label* content_label = new views::Label( 1242 l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW_TEXT)); 1243 content_label->SetMultiLine(true); 1244 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1245 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1246 const gfx::FontList& small_font_list = 1247 rb->GetFontList(ui::ResourceBundle::SmallFont); 1248 content_label->SetFontList(small_font_list); 1249 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1250 layout->AddView(content_label); 1251 1252 // Adds button. 1253 end_preview_and_relaunch_button_ = new views::BlueButton( 1254 this, l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW_AND_RELAUNCH)); 1255 end_preview_and_relaunch_button_->SetHorizontalAlignment( 1256 gfx::ALIGN_CENTER); 1257 layout->StartRowWithPadding( 1258 1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1259 layout->AddView(end_preview_and_relaunch_button_); 1260 1261 return view; 1262} 1263 1264