| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ui/views/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_info_util.h" | |
| 12 #include "chrome/browser/profiles/profile_manager.h" | |
| 13 #include "chrome/browser/profiles/profile_window.h" | |
| 14 #include "chrome/browser/profiles/profiles_state.h" | |
| 15 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" | |
| 16 #include "chrome/browser/signin/signin_manager_factory.h" | |
| 17 #include "chrome/browser/signin/signin_promo.h" | |
| 18 #include "chrome/browser/ui/browser.h" | |
| 19 #include "chrome/browser/ui/browser_dialogs.h" | |
| 20 #include "chrome/browser/ui/singleton_tabs.h" | |
| 21 #include "chrome/browser/ui/views/user_manager_view.h" | |
| 22 #include "chrome/common/pref_names.h" | |
| 23 #include "chrome/common/profile_management_switches.h" | |
| 24 #include "chrome/common/url_constants.h" | |
| 25 #include "components/signin/core/browser/mutable_profile_oauth2_token_service.h" | |
| 26 #include "components/signin/core/browser/profile_oauth2_token_service.h" | |
| 27 #include "components/signin/core/browser/signin_manager.h" | |
| 28 #include "grit/chromium_strings.h" | |
| 29 #include "grit/generated_resources.h" | |
| 30 #include "grit/theme_resources.h" | |
| 31 #include "third_party/skia/include/core/SkColor.h" | |
| 32 #include "ui/base/l10n/l10n_util.h" | |
| 33 #include "ui/base/resource/resource_bundle.h" | |
| 34 #include "ui/gfx/canvas.h" | |
| 35 #include "ui/gfx/image/image.h" | |
| 36 #include "ui/gfx/image/image_skia.h" | |
| 37 #include "ui/gfx/text_elider.h" | |
| 38 #include "ui/native_theme/native_theme.h" | |
| 39 #include "ui/views/controls/button/blue_button.h" | |
| 40 #include "ui/views/controls/button/image_button.h" | |
| 41 #include "ui/views/controls/button/label_button.h" | |
| 42 #include "ui/views/controls/button/menu_button.h" | |
| 43 #include "ui/views/controls/label.h" | |
| 44 #include "ui/views/controls/link.h" | |
| 45 #include "ui/views/controls/separator.h" | |
| 46 #include "ui/views/controls/textfield/textfield.h" | |
| 47 #include "ui/views/controls/webview/webview.h" | |
| 48 #include "ui/views/layout/grid_layout.h" | |
| 49 #include "ui/views/layout/layout_constants.h" | |
| 50 #include "ui/views/widget/widget.h" | |
| 51 | |
| 52 namespace { | |
| 53 | |
| 54 // Helpers -------------------------------------------------------------------- | |
| 55 | |
| 56 const int kFixedMenuWidth = 250; | |
| 57 const int kButtonHeight = 29; | |
| 58 const int kProfileAvatarTutorialShowMax = 5; | |
| 59 const int kFixedGaiaViewHeight = 400; | |
| 60 const int kFixedGaiaViewWidth = 360; | |
| 61 const int kFixedAccountRemovalViewWidth = 280; | |
| 62 | |
| 63 // Creates a GridLayout with a single column. This ensures that all the child | |
| 64 // views added get auto-expanded to fill the full width of the bubble. | |
| 65 views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) { | |
| 66 views::GridLayout* layout = new views::GridLayout(view); | |
| 67 view->SetLayoutManager(layout); | |
| 68 | |
| 69 views::ColumnSet* columns = layout->AddColumnSet(0); | |
| 70 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, | |
| 71 views::GridLayout::FIXED, width, width); | |
| 72 return layout; | |
| 73 } | |
| 74 | |
| 75 // Creates a GridLayout with two columns. | |
| 76 views::GridLayout* CreateDoubleColumnLayout(views::View* view) { | |
| 77 views::GridLayout* layout = new views::GridLayout(view); | |
| 78 view->SetLayoutManager(layout); | |
| 79 | |
| 80 views::ColumnSet* columns = layout->AddColumnSet(0); | |
| 81 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, | |
| 82 views::GridLayout::USE_PREF, 0, 0); | |
| 83 columns->AddPaddingColumn(0, views::kUnrelatedControlLargeHorizontalSpacing); | |
| 84 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, | |
| 85 views::GridLayout::USE_PREF, 0, 0); | |
| 86 return layout; | |
| 87 } | |
| 88 | |
| 89 views::Link* CreateLink(const base::string16& link_text, | |
| 90 views::LinkListener* listener) { | |
| 91 views::Link* link_button = new views::Link(link_text); | |
| 92 link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
| 93 link_button->SetUnderline(false); | |
| 94 link_button->set_listener(listener); | |
| 95 return link_button; | |
| 96 } | |
| 97 | |
| 98 | |
| 99 // BackgroundColorHoverButton ------------------------------------------------- | |
| 100 | |
| 101 // A custom button that allows for setting a background color when hovered over. | |
| 102 class BackgroundColorHoverButton : public views::LabelButton { | |
| 103 public: | |
| 104 BackgroundColorHoverButton(views::ButtonListener* listener, | |
| 105 const base::string16& text, | |
| 106 const gfx::ImageSkia& normal_icon, | |
| 107 const gfx::ImageSkia& hover_icon); | |
| 108 virtual ~BackgroundColorHoverButton(); | |
| 109 | |
| 110 private: | |
| 111 // views::LabelButton: | |
| 112 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; | |
| 113 | |
| 114 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton); | |
| 115 }; | |
| 116 | |
| 117 BackgroundColorHoverButton::BackgroundColorHoverButton( | |
| 118 views::ButtonListener* listener, | |
| 119 const base::string16& text, | |
| 120 const gfx::ImageSkia& normal_icon, | |
| 121 const gfx::ImageSkia& hover_icon) | |
| 122 : views::LabelButton(listener, text) { | |
| 123 SetBorder(views::Border::CreateEmptyBorder(0, views::kButtonHEdgeMarginNew, | |
| 124 0, views::kButtonHEdgeMarginNew)); | |
| 125 set_min_size(gfx::Size(0, kButtonHeight)); | |
| 126 SetImage(STATE_NORMAL, normal_icon); | |
| 127 SetImage(STATE_HOVERED, hover_icon); | |
| 128 SetImage(STATE_PRESSED, hover_icon); | |
| 129 } | |
| 130 | |
| 131 BackgroundColorHoverButton::~BackgroundColorHoverButton() {} | |
| 132 | |
| 133 void BackgroundColorHoverButton::OnPaint(gfx::Canvas* canvas) { | |
| 134 if ((state() == STATE_PRESSED) || (state() == STATE_HOVERED) || HasFocus()) { | |
| 135 canvas->DrawColor(GetNativeTheme()->GetSystemColor( | |
| 136 ui::NativeTheme::kColorId_MenuSeparatorColor)); | |
| 137 } | |
| 138 LabelButton::OnPaint(canvas); | |
| 139 } | |
| 140 | |
| 141 } // namespace | |
| 142 | |
| 143 | |
| 144 // EditableProfilePhoto ------------------------------------------------- | |
| 145 | |
| 146 // A custom Image control that shows a "change" button when moused over. | |
| 147 class EditableProfilePhoto : public views::ImageView { | |
| 148 public: | |
| 149 EditableProfilePhoto(views::ButtonListener* listener, | |
| 150 const gfx::Image& icon, | |
| 151 bool is_editing_allowed) | |
| 152 : views::ImageView(), | |
| 153 change_photo_button_(NULL) { | |
| 154 const int kLargeImageSide = 64; | |
| 155 gfx::Image image = profiles::GetSizedAvatarIconWithBorder( | |
| 156 icon, true, | |
| 157 kLargeImageSide + profiles::kAvatarIconPadding, | |
| 158 kLargeImageSide + profiles::kAvatarIconPadding); | |
| 159 SetImage(image.ToImageSkia()); | |
| 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 profiles::kAvatarIconPadding, | |
| 182 kLargeImageSide - kOverlayHeight, | |
| 183 kLargeImageSide - profiles::kAvatarIconPadding, | |
| 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. | |
| 214 class 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 SetBorder(views::Border::NullBorder()); | |
| 227 | |
| 228 if (!is_editing_allowed) | |
| 229 return; | |
| 230 | |
| 231 SetImage(STATE_HOVERED, | |
| 232 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER)); | |
| 233 SetImage(STATE_PRESSED, | |
| 234 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED)); | |
| 235 | |
| 236 // Textfield that overlaps the button. | |
| 237 profile_name_textfield_ = new views::Textfield(); | |
| 238 profile_name_textfield_->set_controller(controller); | |
| 239 profile_name_textfield_->SetFontList(medium_font_list); | |
| 240 profile_name_textfield_->SetVisible(false); | |
| 241 AddChildView(profile_name_textfield_); | |
| 242 } | |
| 243 | |
| 244 views::Textfield* profile_name_textfield() { | |
| 245 return profile_name_textfield_; | |
| 246 } | |
| 247 | |
| 248 // Hide the editable textfield to show the profile name button instead. | |
| 249 void ShowReadOnlyView() { | |
| 250 if (profile_name_textfield_) | |
| 251 profile_name_textfield_->SetVisible(false); | |
| 252 } | |
| 253 | |
| 254 private: | |
| 255 // views::ButtonListener: | |
| 256 virtual void ButtonPressed(views::Button* sender, | |
| 257 const ui::Event& event) OVERRIDE { | |
| 258 if (profile_name_textfield_) { | |
| 259 profile_name_textfield_->SetVisible(true); | |
| 260 profile_name_textfield_->SetText(GetText()); | |
| 261 profile_name_textfield_->SelectAll(false); | |
| 262 profile_name_textfield_->RequestFocus(); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 // views::LabelButton: | |
| 267 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE { | |
| 268 // Override CustomButton's implementation, which presses the button when | |
| 269 // you press space and clicks it when you release space, as the space can be | |
| 270 // part of the new profile name typed in the textfield. | |
| 271 return false; | |
| 272 } | |
| 273 | |
| 274 virtual void Layout() OVERRIDE { | |
| 275 if (profile_name_textfield_) | |
| 276 profile_name_textfield_->SetBounds(0, 0, width(), height()); | |
| 277 // This layout trick keeps the text left-aligned and the icon right-aligned. | |
| 278 SetHorizontalAlignment(gfx::ALIGN_RIGHT); | |
| 279 views::LabelButton::Layout(); | |
| 280 label()->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
| 281 } | |
| 282 | |
| 283 // Button that is shown when hovering over the image view. Can be NULL if | |
| 284 // the profile name isn't allowed to be edited (e.g. for guest profiles). | |
| 285 views::Textfield* profile_name_textfield_; | |
| 286 | |
| 287 DISALLOW_COPY_AND_ASSIGN(EditableProfileName); | |
| 288 }; | |
| 289 | |
| 290 // A title card with one back button right aligned and one label center aligned. | |
| 291 class TitleCard : public views::View { | |
| 292 public: | |
| 293 TitleCard(int message_id, views::ButtonListener* listener, | |
| 294 views::ImageButton** back_button) { | |
| 295 back_button_ = new views::ImageButton(listener); | |
| 296 back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, | |
| 297 views::ImageButton::ALIGN_MIDDLE); | |
| 298 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); | |
| 299 back_button_->SetImage(views::ImageButton::STATE_NORMAL, | |
| 300 rb->GetImageSkiaNamed(IDR_BACK)); | |
| 301 back_button_->SetImage(views::ImageButton::STATE_HOVERED, | |
| 302 rb->GetImageSkiaNamed(IDR_BACK_H)); | |
| 303 back_button_->SetImage(views::ImageButton::STATE_PRESSED, | |
| 304 rb->GetImageSkiaNamed(IDR_BACK_P)); | |
| 305 back_button_->SetImage(views::ImageButton::STATE_DISABLED, | |
| 306 rb->GetImageSkiaNamed(IDR_BACK_D)); | |
| 307 *back_button = back_button_; | |
| 308 | |
| 309 title_label_ = new views::Label(l10n_util::GetStringUTF16(message_id)); | |
| 310 title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); | |
| 311 const gfx::FontList& medium_font_list = | |
| 312 rb->GetFontList(ui::ResourceBundle::MediumFont); | |
| 313 title_label_->SetFontList(medium_font_list); | |
| 314 | |
| 315 AddChildView(back_button_); | |
| 316 AddChildView(title_label_); | |
| 317 } | |
| 318 | |
| 319 private: | |
| 320 virtual void Layout() OVERRIDE{ | |
| 321 back_button_->SetBounds( | |
| 322 0, 0, back_button_->GetPreferredSize().width(), height()); | |
| 323 title_label_->SetBoundsRect(GetContentsBounds()); | |
| 324 } | |
| 325 | |
| 326 virtual gfx::Size GetPreferredSize() OVERRIDE{ | |
| 327 int height = profiles::kAvatarIconPadding * 2 + | |
| 328 std::max(title_label_->GetPreferredSize().height(), | |
| 329 back_button_->GetPreferredSize().height()); | |
| 330 return gfx::Size(width(), height); | |
| 331 } | |
| 332 | |
| 333 views::ImageButton* back_button_; | |
| 334 views::Label* title_label_; | |
| 335 | |
| 336 DISALLOW_COPY_AND_ASSIGN(TitleCard); | |
| 337 }; | |
| 338 | |
| 339 // ProfileChooserView --------------------------------------------------------- | |
| 340 | |
| 341 // static | |
| 342 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL; | |
| 343 bool ProfileChooserView::close_on_deactivate_for_testing_ = true; | |
| 344 | |
| 345 // static | |
| 346 void ProfileChooserView::ShowBubble( | |
| 347 BubbleViewMode view_mode, | |
| 348 views::View* anchor_view, | |
| 349 views::BubbleBorder::Arrow arrow, | |
| 350 views::BubbleBorder::BubbleAlignment border_alignment, | |
| 351 const gfx::Rect& anchor_rect, | |
| 352 Browser* browser) { | |
| 353 profile_bubble_ = new ProfileChooserView( | |
| 354 anchor_view, arrow, anchor_rect, browser); | |
| 355 views::BubbleDelegateView::CreateBubble(profile_bubble_); | |
| 356 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_); | |
| 357 profile_bubble_->SetAlignment(border_alignment); | |
| 358 profile_bubble_->GetWidget()->Show(); | |
| 359 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE); | |
| 360 | |
| 361 if (view_mode != BUBBLE_VIEW_MODE_PROFILE_CHOOSER) | |
| 362 profile_bubble_->ShowView(view_mode, profile_bubble_->avatar_menu_.get()); | |
| 363 } | |
| 364 | |
| 365 // static | |
| 366 bool ProfileChooserView::IsShowing() { | |
| 367 return profile_bubble_ != NULL; | |
| 368 } | |
| 369 | |
| 370 // static | |
| 371 void ProfileChooserView::Hide() { | |
| 372 if (IsShowing()) | |
| 373 profile_bubble_->GetWidget()->Close(); | |
| 374 } | |
| 375 | |
| 376 ProfileChooserView::ProfileChooserView(views::View* anchor_view, | |
| 377 views::BubbleBorder::Arrow arrow, | |
| 378 const gfx::Rect& anchor_rect, | |
| 379 Browser* browser) | |
| 380 : BubbleDelegateView(anchor_view, arrow), | |
| 381 browser_(browser), | |
| 382 view_mode_(BUBBLE_VIEW_MODE_PROFILE_CHOOSER), | |
| 383 tutorial_showing_(false) { | |
| 384 // Reset the default margins inherited from the BubbleDelegateView. | |
| 385 set_margins(gfx::Insets()); | |
| 386 | |
| 387 ResetView(); | |
| 388 | |
| 389 set_background(views::Background::CreateSolidBackground( | |
| 390 GetNativeTheme()->GetSystemColor( | |
| 391 ui::NativeTheme::kColorId_DialogBackground))); | |
| 392 | |
| 393 avatar_menu_.reset(new AvatarMenu( | |
| 394 &g_browser_process->profile_manager()->GetProfileInfoCache(), | |
| 395 this, | |
| 396 browser_)); | |
| 397 avatar_menu_->RebuildMenu(); | |
| 398 | |
| 399 ProfileOAuth2TokenService* oauth2_token_service = | |
| 400 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile()); | |
| 401 if (oauth2_token_service) | |
| 402 oauth2_token_service->AddObserver(this); | |
| 403 } | |
| 404 | |
| 405 ProfileChooserView::~ProfileChooserView() { | |
| 406 ProfileOAuth2TokenService* oauth2_token_service = | |
| 407 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile()); | |
| 408 if (oauth2_token_service) | |
| 409 oauth2_token_service->RemoveObserver(this); | |
| 410 } | |
| 411 | |
| 412 void ProfileChooserView::ResetView() { | |
| 413 manage_accounts_link_ = NULL; | |
| 414 signin_current_profile_link_ = NULL; | |
| 415 users_button_ = NULL; | |
| 416 lock_button_ = NULL; | |
| 417 add_account_button_ = NULL; | |
| 418 current_profile_photo_ = NULL; | |
| 419 current_profile_name_ = NULL; | |
| 420 tutorial_ok_button_ = NULL; | |
| 421 tutorial_learn_more_link_ = NULL; | |
| 422 account_removal_cancel_button_ = NULL; | |
| 423 gaia_signin_cancel_button_ = NULL; | |
| 424 open_other_profile_indexes_map_.clear(); | |
| 425 current_profile_accounts_map_.clear(); | |
| 426 tutorial_showing_ = false; | |
| 427 } | |
| 428 | |
| 429 void ProfileChooserView::Init() { | |
| 430 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); | |
| 431 } | |
| 432 | |
| 433 void ProfileChooserView::OnAvatarMenuChanged( | |
| 434 AvatarMenu* avatar_menu) { | |
| 435 // Refresh the view with the new menu. We can't just update the local copy | |
| 436 // as this may have been triggered by a sign out action, in which case | |
| 437 // the view is being destroyed. | |
| 438 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu); | |
| 439 } | |
| 440 | |
| 441 void ProfileChooserView::OnRefreshTokenAvailable( | |
| 442 const std::string& account_id) { | |
| 443 // Refresh the account management view when a new account is added to the | |
| 444 // profile. | |
| 445 if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT || | |
| 446 view_mode_ == BUBBLE_VIEW_MODE_GAIA_SIGNIN || | |
| 447 view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT) { | |
| 448 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); | |
| 449 } | |
| 450 } | |
| 451 | |
| 452 void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) { | |
| 453 // Refresh the account management view when an account is removed from the | |
| 454 // profile. | |
| 455 if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) | |
| 456 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); | |
| 457 } | |
| 458 | |
| 459 void ProfileChooserView::ShowView(BubbleViewMode view_to_display, | |
| 460 AvatarMenu* avatar_menu) { | |
| 461 // The account management view should only be displayed if the active profile | |
| 462 // is signed in. | |
| 463 if (view_to_display == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) { | |
| 464 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt( | |
| 465 avatar_menu->GetActiveProfileIndex()); | |
| 466 DCHECK(active_item.signed_in); | |
| 467 } | |
| 468 | |
| 469 // Records if the tutorial card is currently shown before resetting the view. | |
| 470 bool tutorial_shown = tutorial_showing_; | |
| 471 ResetView(); | |
| 472 RemoveAllChildViews(true); | |
| 473 view_mode_ = view_to_display; | |
| 474 | |
| 475 if (view_mode_ == BUBBLE_VIEW_MODE_GAIA_SIGNIN || | |
| 476 view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT || | |
| 477 view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL) { | |
| 478 bool is_removal_view = view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL; | |
| 479 views::GridLayout* layout = CreateSingleColumnLayout(this, | |
| 480 is_removal_view ? kFixedAccountRemovalViewWidth : kFixedGaiaViewWidth); | |
| 481 layout->StartRow(1, 0); | |
| 482 layout->AddView(is_removal_view ? CreateAccountRemovalView(): | |
| 483 CreateGaiaSigninView(view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT)); | |
| 484 Layout(); | |
| 485 if (GetBubbleFrameView()) | |
| 486 SizeToContents(); | |
| 487 return; | |
| 488 } | |
| 489 | |
| 490 views::GridLayout* layout = CreateSingleColumnLayout(this, kFixedMenuWidth); | |
| 491 // Separate items into active and alternatives. | |
| 492 Indexes other_profiles; | |
| 493 views::View* tutorial_view = NULL; | |
| 494 views::View* current_profile_view = NULL; | |
| 495 views::View* current_profile_accounts = NULL; | |
| 496 views::View* option_buttons_view = NULL; | |
| 497 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) { | |
| 498 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i); | |
| 499 if (item.active) { | |
| 500 option_buttons_view = CreateOptionsView(item.signed_in); | |
| 501 if (view_to_display == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { | |
| 502 tutorial_view = CreateTutorialView(item, tutorial_shown); | |
| 503 current_profile_view = CreateCurrentProfileView(item, false); | |
| 504 } else { | |
| 505 current_profile_view = CreateCurrentProfileEditableView(item); | |
| 506 current_profile_accounts = CreateCurrentProfileAccountsView(item); | |
| 507 } | |
| 508 } else { | |
| 509 other_profiles.push_back(i); | |
| 510 } | |
| 511 } | |
| 512 | |
| 513 if (tutorial_view) { | |
| 514 layout->StartRow(1, 0); | |
| 515 layout->AddView(tutorial_view); | |
| 516 } | |
| 517 | |
| 518 if (!current_profile_view) { | |
| 519 // Guest windows don't have an active profile. | |
| 520 current_profile_view = CreateGuestProfileView(); | |
| 521 option_buttons_view = CreateOptionsView(false); | |
| 522 } | |
| 523 | |
| 524 layout->StartRow(1, 0); | |
| 525 layout->AddView(current_profile_view); | |
| 526 | |
| 527 if (view_to_display == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { | |
| 528 layout->StartRow(1, 0); | |
| 529 if (switches::IsFastUserSwitching()) | |
| 530 layout->AddView(CreateOtherProfilesView(other_profiles)); | |
| 531 } else { | |
| 532 DCHECK(current_profile_accounts); | |
| 533 layout->StartRow(0, 0); | |
| 534 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); | |
| 535 layout->StartRow(1, 0); | |
| 536 layout->AddView(current_profile_accounts); | |
| 537 } | |
| 538 | |
| 539 layout->StartRow(0, 0); | |
| 540 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); | |
| 541 | |
| 542 // Action buttons. | |
| 543 layout->StartRow(0, 0); | |
| 544 layout->AddView(option_buttons_view); | |
| 545 | |
| 546 Layout(); | |
| 547 if (GetBubbleFrameView()) | |
| 548 SizeToContents(); | |
| 549 } | |
| 550 | |
| 551 void ProfileChooserView::WindowClosing() { | |
| 552 DCHECK_EQ(profile_bubble_, this); | |
| 553 profile_bubble_ = NULL; | |
| 554 } | |
| 555 | |
| 556 void ProfileChooserView::ButtonPressed(views::Button* sender, | |
| 557 const ui::Event& event) { | |
| 558 // Disable button after clicking so that it doesn't get clicked twice and | |
| 559 // start a second action... which can crash Chrome. But don't disable if it | |
| 560 // has no parent (like in tests) because that will also crash. | |
| 561 if (sender->parent()) | |
| 562 sender->SetEnabled(false); | |
| 563 | |
| 564 if (sender == users_button_) { | |
| 565 chrome::ShowUserManager(base::FilePath()); | |
| 566 } else if (sender == lock_button_) { | |
| 567 profiles::LockProfile(browser_->profile()); | |
| 568 } else if (sender == add_account_button_) { | |
| 569 ShowView(BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get()); | |
| 570 } else if (sender == tutorial_ok_button_) { | |
| 571 // If the user manually dismissed the tutorial, never show it again by | |
| 572 // setting the number of times shown to the maximum plus 1, so that later we | |
| 573 // could distinguish between the dismiss case and the case when the tutorial | |
| 574 // is indeed shown for the maximum number of times. | |
| 575 browser_->profile()->GetPrefs()->SetInteger( | |
| 576 prefs::kProfileAvatarTutorialShown, kProfileAvatarTutorialShowMax + 1); | |
| 577 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); | |
| 578 } else if (sender == remove_account_and_relaunch_button_) { | |
| 579 RemoveAccount(); | |
| 580 } else if (sender == account_removal_cancel_button_) { | |
| 581 account_id_to_remove_.clear(); | |
| 582 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); | |
| 583 } else if (sender == gaia_signin_cancel_button_) { | |
| 584 std::string primary_account = | |
| 585 SigninManagerFactory::GetForProfile(browser_->profile())-> | |
| 586 GetAuthenticatedUsername(); | |
| 587 ShowView(primary_account.empty() ? BUBBLE_VIEW_MODE_PROFILE_CHOOSER : | |
| 588 BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, | |
| 589 avatar_menu_.get()); | |
| 590 } else if (current_profile_photo_ && | |
| 591 sender == current_profile_photo_->change_photo_button()) { | |
| 592 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex()); | |
| 593 } else { | |
| 594 // One of the "other profiles" buttons was pressed. | |
| 595 ButtonIndexes::const_iterator match = | |
| 596 open_other_profile_indexes_map_.find(sender); | |
| 597 DCHECK(match != open_other_profile_indexes_map_.end()); | |
| 598 avatar_menu_->SwitchToProfile( | |
| 599 match->second, | |
| 600 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW, | |
| 601 ProfileMetrics::SWITCH_PROFILE_ICON); | |
| 602 } | |
| 603 } | |
| 604 | |
| 605 void ProfileChooserView::OnMenuButtonClicked(views::View* source, | |
| 606 const gfx::Point& point) { | |
| 607 AccountButtonIndexes::const_iterator match = | |
| 608 current_profile_accounts_map_.find(source); | |
| 609 DCHECK(match != current_profile_accounts_map_.end()); | |
| 610 account_id_to_remove_ = match->second; | |
| 611 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL, avatar_menu_.get()); | |
| 612 } | |
| 613 | |
| 614 void ProfileChooserView::RemoveAccount() { | |
| 615 DCHECK(!account_id_to_remove_.empty()); | |
| 616 MutableProfileOAuth2TokenService* oauth2_token_service = | |
| 617 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile( | |
| 618 browser_->profile()); | |
| 619 if (oauth2_token_service) | |
| 620 oauth2_token_service->RevokeCredentials(account_id_to_remove_); | |
| 621 account_id_to_remove_.clear(); | |
| 622 | |
| 623 chrome::AttemptRestart(); | |
| 624 } | |
| 625 | |
| 626 void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) { | |
| 627 if (sender == manage_accounts_link_) { | |
| 628 // ShowView() will DCHECK if this view is displayed for non signed-in users. | |
| 629 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); | |
| 630 } else if (sender == tutorial_learn_more_link_) { | |
| 631 // TODO(guohui): update |learn_more_url| once it is decided. | |
| 632 const GURL lear_more_url("https://support.google.com/chrome/?hl=en#to"); | |
| 633 chrome::NavigateParams params( | |
| 634 browser_->profile(), | |
| 635 lear_more_url, | |
| 636 content::PAGE_TRANSITION_LINK); | |
| 637 params.disposition = NEW_FOREGROUND_TAB; | |
| 638 chrome::Navigate(¶ms); | |
| 639 } else { | |
| 640 DCHECK(sender == signin_current_profile_link_); | |
| 641 ShowView(BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get()); | |
| 642 } | |
| 643 } | |
| 644 | |
| 645 bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender, | |
| 646 const ui::KeyEvent& key_event) { | |
| 647 views::Textfield* name_textfield = | |
| 648 current_profile_name_->profile_name_textfield(); | |
| 649 DCHECK(sender == name_textfield); | |
| 650 | |
| 651 if (key_event.key_code() == ui::VKEY_RETURN || | |
| 652 key_event.key_code() == ui::VKEY_TAB) { | |
| 653 // Pressing Tab/Enter commits the new profile name, unless it's empty. | |
| 654 base::string16 new_profile_name = name_textfield->text(); | |
| 655 if (new_profile_name.empty()) | |
| 656 return true; | |
| 657 | |
| 658 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt( | |
| 659 avatar_menu_->GetActiveProfileIndex()); | |
| 660 Profile* profile = g_browser_process->profile_manager()->GetProfile( | |
| 661 active_item.profile_path); | |
| 662 DCHECK(profile); | |
| 663 | |
| 664 if (profile->IsManaged()) | |
| 665 return true; | |
| 666 | |
| 667 profiles::UpdateProfileName(profile, new_profile_name); | |
| 668 current_profile_name_->ShowReadOnlyView(); | |
| 669 return true; | |
| 670 } | |
| 671 return false; | |
| 672 } | |
| 673 | |
| 674 views::View* ProfileChooserView::CreateTutorialView( | |
| 675 const AvatarMenu::Item& current_avatar_item, bool tutorial_shown) { | |
| 676 if (!current_avatar_item.signed_in) | |
| 677 return NULL; | |
| 678 | |
| 679 Profile* profile = browser_->profile(); | |
| 680 const int show_count = profile->GetPrefs()->GetInteger( | |
| 681 prefs::kProfileAvatarTutorialShown); | |
| 682 // Do not show the tutorial if user has dismissed it. | |
| 683 if (show_count > kProfileAvatarTutorialShowMax) | |
| 684 return NULL; | |
| 685 | |
| 686 if (!tutorial_shown) { | |
| 687 if (show_count == kProfileAvatarTutorialShowMax) | |
| 688 return NULL; | |
| 689 profile->GetPrefs()->SetInteger( | |
| 690 prefs::kProfileAvatarTutorialShown, show_count + 1); | |
| 691 } | |
| 692 tutorial_showing_ = true; | |
| 693 | |
| 694 views::View* view = new views::View(); | |
| 695 view->set_background(views::Background::CreateSolidBackground( | |
| 696 profiles::kAvatarTutorialBackgroundColor)); | |
| 697 views::GridLayout* layout = CreateSingleColumnLayout(view, | |
| 698 kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew); | |
| 699 layout->SetInsets(views::kButtonVEdgeMarginNew, | |
| 700 views::kButtonHEdgeMarginNew, | |
| 701 views::kButtonVEdgeMarginNew, | |
| 702 views::kButtonHEdgeMarginNew); | |
| 703 | |
| 704 // Adds title. | |
| 705 views::Label* title_label = new views::Label( | |
| 706 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_TUTORIAL_TITLE)); | |
| 707 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
| 708 title_label->SetAutoColorReadabilityEnabled(false); | |
| 709 title_label->SetEnabledColor(SK_ColorWHITE); | |
| 710 title_label ->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( | |
| 711 ui::ResourceBundle::MediumFont)); | |
| 712 layout->StartRow(1, 0); | |
| 713 layout->AddView(title_label); | |
| 714 | |
| 715 // Adds body content. | |
| 716 views::Label* content_label = new views::Label( | |
| 717 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_TUTORIAL_CONTENT_TEXT)); | |
| 718 content_label->SetMultiLine(true); | |
| 719 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
| 720 content_label->SetAutoColorReadabilityEnabled(false); | |
| 721 content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor); | |
| 722 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing); | |
| 723 layout->AddView(content_label); | |
| 724 | |
| 725 // Adds links and buttons. | |
| 726 views::View* button_row = new views::View(); | |
| 727 views::GridLayout* button_layout = new views::GridLayout(button_row); | |
| 728 views::ColumnSet* button_columns = button_layout->AddColumnSet(0); | |
| 729 button_columns->AddColumn(views::GridLayout::LEADING, | |
| 730 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); | |
| 731 button_columns->AddPaddingColumn( | |
| 732 1, views::kUnrelatedControlHorizontalSpacing); | |
| 733 button_columns->AddColumn(views::GridLayout::TRAILING, | |
| 734 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); | |
| 735 button_row->SetLayoutManager(button_layout); | |
| 736 | |
| 737 tutorial_learn_more_link_ = CreateLink( | |
| 738 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE), | |
| 739 this); | |
| 740 tutorial_learn_more_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
| 741 tutorial_learn_more_link_->SetAutoColorReadabilityEnabled(false); | |
| 742 tutorial_learn_more_link_->SetEnabledColor(SK_ColorWHITE); | |
| 743 button_layout->StartRow(1, 0); | |
| 744 button_layout->AddView(tutorial_learn_more_link_); | |
| 745 | |
| 746 tutorial_ok_button_ = new views::LabelButton( | |
| 747 this, l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_TUTORIAL_OK_BUTTON)); | |
| 748 tutorial_ok_button_->SetHorizontalAlignment(gfx::ALIGN_CENTER); | |
| 749 tutorial_ok_button_->SetStyle(views::Button::STYLE_BUTTON); | |
| 750 button_layout->AddView(tutorial_ok_button_); | |
| 751 | |
| 752 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); | |
| 753 layout->AddView(button_row); | |
| 754 | |
| 755 // Adds a padded caret image at the bottom. | |
| 756 views::View* padded_caret_view = new views::View(); | |
| 757 views::GridLayout* padded_caret_layout = | |
| 758 new views::GridLayout(padded_caret_view); | |
| 759 views::ColumnSet* padded_columns = padded_caret_layout->AddColumnSet(0); | |
| 760 padded_columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); | |
| 761 padded_columns->AddColumn(views::GridLayout::LEADING, | |
| 762 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); | |
| 763 padded_caret_view->SetLayoutManager(padded_caret_layout); | |
| 764 | |
| 765 views::ImageView* caret_image_view = new views::ImageView(); | |
| 766 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); | |
| 767 caret_image_view->SetImage( | |
| 768 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_CARET)); | |
| 769 | |
| 770 padded_caret_layout->StartRow(1, 0); | |
| 771 padded_caret_layout->AddView(caret_image_view); | |
| 772 | |
| 773 views::View* view_with_caret = new views::View(); | |
| 774 views::GridLayout* layout_with_caret = | |
| 775 CreateSingleColumnLayout(view_with_caret, kFixedMenuWidth); | |
| 776 layout_with_caret->StartRow(1, 0); | |
| 777 layout_with_caret->AddView(view); | |
| 778 layout_with_caret->StartRow(1, 0); | |
| 779 layout_with_caret->AddView(padded_caret_view); | |
| 780 return view_with_caret; | |
| 781 } | |
| 782 | |
| 783 views::View* ProfileChooserView::CreateCurrentProfileView( | |
| 784 const AvatarMenu::Item& avatar_item, | |
| 785 bool is_guest) { | |
| 786 views::View* view = new views::View(); | |
| 787 views::GridLayout* layout = CreateDoubleColumnLayout(view); | |
| 788 layout->SetInsets(views::kButtonVEdgeMarginNew, | |
| 789 views::kButtonHEdgeMarginNew, | |
| 790 views::kButtonVEdgeMarginNew, | |
| 791 views::kButtonHEdgeMarginNew); | |
| 792 | |
| 793 current_profile_photo_ = | |
| 794 new EditableProfilePhoto(this, avatar_item.icon, !is_guest); | |
| 795 view->SetBoundsRect(current_profile_photo_->bounds()); | |
| 796 current_profile_name_ = new EditableProfileName( | |
| 797 this, profiles::GetAvatarNameForProfile(browser_->profile()), !is_guest); | |
| 798 layout->StartRow(1, 0); | |
| 799 layout->AddView(current_profile_photo_, 1, 3); | |
| 800 layout->AddView(current_profile_name_); | |
| 801 | |
| 802 if (is_guest) { | |
| 803 layout->StartRow(1, 0); | |
| 804 layout->SkipColumns(1); | |
| 805 layout->StartRow(1, 0); | |
| 806 layout->SkipColumns(1); | |
| 807 } else if (avatar_item.signed_in) { | |
| 808 manage_accounts_link_ = CreateLink( | |
| 809 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON), | |
| 810 this); | |
| 811 layout->StartRow(1, 0); | |
| 812 layout->SkipColumns(1); | |
| 813 layout->AddView(manage_accounts_link_); | |
| 814 layout->StartRow(1, 0); | |
| 815 layout->SkipColumns(1); | |
| 816 } else { | |
| 817 signin_current_profile_link_ = CreateLink( | |
| 818 l10n_util::GetStringFUTF16( | |
| 819 IDS_SYNC_START_SYNC_BUTTON_LABEL, | |
| 820 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)), | |
| 821 this); | |
| 822 layout->StartRow(1, 0); | |
| 823 layout->SkipColumns(1); | |
| 824 layout->AddView(signin_current_profile_link_); | |
| 825 layout->StartRow(1, 0); | |
| 826 layout->SkipColumns(1); | |
| 827 } | |
| 828 | |
| 829 return view; | |
| 830 } | |
| 831 | |
| 832 views::View* ProfileChooserView::CreateCurrentProfileEditableView( | |
| 833 const AvatarMenu::Item& avatar_item) { | |
| 834 DCHECK(avatar_item.signed_in); | |
| 835 views::View* view = new views::View(); | |
| 836 views::GridLayout* layout = CreateDoubleColumnLayout(view); | |
| 837 layout->SetInsets(views::kButtonVEdgeMarginNew, | |
| 838 views::kButtonHEdgeMarginNew, | |
| 839 views::kButtonVEdgeMarginNew, | |
| 840 views::kButtonHEdgeMarginNew); | |
| 841 | |
| 842 current_profile_photo_ = | |
| 843 new EditableProfilePhoto(this, avatar_item.icon, true); | |
| 844 view->SetBoundsRect(current_profile_photo_->bounds()); | |
| 845 current_profile_name_ = new EditableProfileName( | |
| 846 this, profiles::GetAvatarNameForProfile(browser_->profile()), true); | |
| 847 | |
| 848 layout->StartRow(1, 0); | |
| 849 layout->AddView(current_profile_photo_, 1, 3); | |
| 850 layout->AddView(current_profile_name_); | |
| 851 | |
| 852 layout->StartRow(1, 0); | |
| 853 layout->SkipColumns(1); | |
| 854 | |
| 855 layout->StartRow(1, 0); | |
| 856 layout->SkipColumns(1); | |
| 857 return view; | |
| 858 } | |
| 859 | |
| 860 views::View* ProfileChooserView::CreateGuestProfileView() { | |
| 861 gfx::Image guest_icon = | |
| 862 ui::ResourceBundle::GetSharedInstance().GetImageNamed(IDR_LOGIN_GUEST); | |
| 863 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon); | |
| 864 guest_avatar_item.active = true; | |
| 865 guest_avatar_item.name = l10n_util::GetStringUTF16( | |
| 866 IDS_PROFILES_GUEST_PROFILE_NAME); | |
| 867 guest_avatar_item.signed_in = false; | |
| 868 | |
| 869 return CreateCurrentProfileView(guest_avatar_item, true); | |
| 870 } | |
| 871 | |
| 872 views::View* ProfileChooserView::CreateOtherProfilesView( | |
| 873 const Indexes& avatars_to_show) { | |
| 874 views::View* view = new views::View(); | |
| 875 views::GridLayout* layout = CreateSingleColumnLayout( | |
| 876 view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew); | |
| 877 layout->SetInsets(0, views::kButtonHEdgeMarginNew, | |
| 878 views::kButtonVEdgeMarginNew, views::kButtonHEdgeMarginNew); | |
| 879 int num_avatars_to_show = avatars_to_show.size(); | |
| 880 for (int i = 0; i < num_avatars_to_show; ++i) { | |
| 881 const size_t index = avatars_to_show[i]; | |
| 882 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index); | |
| 883 const int kSmallImageSide = 32; | |
| 884 | |
| 885 gfx::Image image = profiles::GetSizedAvatarIconWithBorder( | |
| 886 item.icon, true, | |
| 887 kSmallImageSide + profiles::kAvatarIconPadding, | |
| 888 kSmallImageSide + profiles::kAvatarIconPadding); | |
| 889 | |
| 890 views::LabelButton* button = new views::LabelButton(this, item.name); | |
| 891 open_other_profile_indexes_map_[button] = index; | |
| 892 button->SetImage(views::Button::STATE_NORMAL, *image.ToImageSkia()); | |
| 893 button->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( | |
| 894 ui::ResourceBundle::MediumFont)); | |
| 895 button->SetBorder(views::Border::NullBorder()); | |
| 896 | |
| 897 layout->StartRow(1, 0); | |
| 898 layout->AddView(button); | |
| 899 | |
| 900 // The last avatar in the list does not need any bottom padding. | |
| 901 if (i < num_avatars_to_show - 1) | |
| 902 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); | |
| 903 } | |
| 904 | |
| 905 return view; | |
| 906 } | |
| 907 | |
| 908 views::View* ProfileChooserView::CreateOptionsView(bool enable_lock) { | |
| 909 views::View* view = new views::View(); | |
| 910 views::GridLayout* layout; | |
| 911 | |
| 912 // Only signed-in users have the ability to lock. | |
| 913 if (enable_lock) { | |
| 914 layout = new views::GridLayout(view); | |
| 915 views::ColumnSet* columns = layout->AddColumnSet(0); | |
| 916 int width_of_lock_button = | |
| 917 2 * views::kUnrelatedControlLargeHorizontalSpacing + 12; | |
| 918 int width_of_users_button = kFixedMenuWidth - width_of_lock_button; | |
| 919 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, | |
| 920 views::GridLayout::FIXED, width_of_users_button, | |
| 921 width_of_users_button); | |
| 922 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, | |
| 923 views::GridLayout::FIXED, width_of_lock_button, | |
| 924 width_of_lock_button); | |
| 925 view->SetLayoutManager(layout); | |
| 926 } else { | |
| 927 layout = CreateSingleColumnLayout(view, kFixedMenuWidth); | |
| 928 } | |
| 929 | |
| 930 // The horizontal padding will be set by each button individually, so that | |
| 931 // in the hovered state the button spans the entire parent view. | |
| 932 layout->SetInsets(views::kRelatedControlVerticalSpacing, 0, | |
| 933 views::kRelatedControlVerticalSpacing, 0); | |
| 934 | |
| 935 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); | |
| 936 users_button_ = new BackgroundColorHoverButton( | |
| 937 this, | |
| 938 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU_BUTTON, | |
| 939 profiles::GetAvatarNameForProfile(browser_->profile())), | |
| 940 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR), | |
| 941 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR)); | |
| 942 | |
| 943 layout->StartRow(1, 0); | |
| 944 layout->AddView(users_button_); | |
| 945 | |
| 946 if (enable_lock) { | |
| 947 lock_button_ = new BackgroundColorHoverButton( | |
| 948 this, | |
| 949 base::string16(), | |
| 950 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK), | |
| 951 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK)); | |
| 952 layout->AddView(lock_button_); | |
| 953 } | |
| 954 return view; | |
| 955 } | |
| 956 | |
| 957 views::View* ProfileChooserView::CreateCurrentProfileAccountsView( | |
| 958 const AvatarMenu::Item& avatar_item) { | |
| 959 DCHECK(avatar_item.signed_in); | |
| 960 views::View* view = new views::View(); | |
| 961 int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew; | |
| 962 views::GridLayout* layout = CreateSingleColumnLayout(view, column_width); | |
| 963 layout->SetInsets(views::kButtonVEdgeMarginNew, | |
| 964 views::kButtonHEdgeMarginNew, | |
| 965 views::kButtonVEdgeMarginNew, | |
| 966 views::kButtonHEdgeMarginNew); | |
| 967 | |
| 968 Profile* profile = browser_->profile(); | |
| 969 std::string primary_account = | |
| 970 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername(); | |
| 971 DCHECK(!primary_account.empty()); | |
| 972 std::vector<std::string>accounts = | |
| 973 profiles::GetSecondaryAccountsForProfile(profile, primary_account); | |
| 974 | |
| 975 // The primary account should always be listed first. | |
| 976 // TODO(rogerta): we still need to further differentiate the primary account | |
| 977 // from the others in the UI, so more work is likely required here: | |
| 978 // crbug.com/311124. | |
| 979 CreateAccountButton(layout, primary_account, true, column_width); | |
| 980 for (size_t i = 0; i < accounts.size(); ++i) | |
| 981 CreateAccountButton(layout, accounts[i], false, column_width); | |
| 982 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); | |
| 983 | |
| 984 add_account_button_ = new views::BlueButton( | |
| 985 this, | |
| 986 l10n_util::GetStringFUTF16(IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, | |
| 987 avatar_item.name)); | |
| 988 layout->StartRow(1, 0); | |
| 989 layout->AddView(add_account_button_); | |
| 990 return view; | |
| 991 } | |
| 992 | |
| 993 void ProfileChooserView::CreateAccountButton(views::GridLayout* layout, | |
| 994 const std::string& account, | |
| 995 bool is_primary_account, | |
| 996 int width) { | |
| 997 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); | |
| 998 const gfx::ImageSkia* menu_marker = | |
| 999 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia(); | |
| 1000 // Use a MenuButtonListener and not a regular ButtonListener to be | |
| 1001 // able to distinguish between the unnamed "other profile" buttons and the | |
| 1002 // unnamed "multiple accounts" buttons. | |
| 1003 views::MenuButton* email_button = new views::MenuButton( | |
| 1004 NULL, | |
| 1005 gfx::ElideEmail(base::UTF8ToUTF16(account), | |
| 1006 rb->GetFontList(ui::ResourceBundle::BaseFont), | |
| 1007 width - menu_marker->width()), | |
| 1008 this, | |
| 1009 true /* show_menu_marker */); | |
| 1010 email_button->SetBorder(views::Border::CreateEmptyBorder(0, 0, 0, 0)); | |
| 1011 email_button->set_menu_marker(menu_marker); | |
| 1012 if (!is_primary_account) | |
| 1013 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); | |
| 1014 layout->StartRow(1, 0); | |
| 1015 layout->AddView(email_button); | |
| 1016 | |
| 1017 // Save the original email address, as the button text could be elided. | |
| 1018 current_profile_accounts_map_[email_button] = account; | |
| 1019 } | |
| 1020 | |
| 1021 views::View* ProfileChooserView::CreateGaiaSigninView( | |
| 1022 bool add_secondary_account) { | |
| 1023 views::View* view = new views::View(); | |
| 1024 views::GridLayout* layout = | |
| 1025 CreateSingleColumnLayout(view, kFixedGaiaViewWidth); | |
| 1026 | |
| 1027 // Adds title. | |
| 1028 views::View* padded_title = new views::View(); | |
| 1029 int available_width = kFixedGaiaViewWidth - 2 * views::kButtonHEdgeMarginNew; | |
| 1030 views::GridLayout* padded_layout = CreateSingleColumnLayout( | |
| 1031 padded_title, available_width); | |
| 1032 padded_layout->SetInsets(views::kButtonVEdgeMarginNew, | |
| 1033 views::kButtonHEdgeMarginNew, | |
| 1034 views::kButtonVEdgeMarginNew, | |
| 1035 views::kButtonHEdgeMarginNew); | |
| 1036 padded_layout->StartRow(1, 0); | |
| 1037 padded_layout->AddView(new TitleCard( | |
| 1038 add_secondary_account ? IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE : | |
| 1039 IDS_PROFILES_GAIA_SIGNIN_TITLE, | |
| 1040 this, &gaia_signin_cancel_button_)); | |
| 1041 | |
| 1042 layout->StartRow(1, 0); | |
| 1043 layout->AddView(padded_title); | |
| 1044 layout->StartRow(1, 0); | |
| 1045 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); | |
| 1046 | |
| 1047 // Adds Gaia signin webview | |
| 1048 Profile* profile = browser_->profile(); | |
| 1049 views::WebView* web_view = new views::WebView(profile); | |
| 1050 signin::Source source = add_secondary_account ? | |
| 1051 signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT : | |
| 1052 signin::SOURCE_AVATAR_BUBBLE_SIGN_IN; | |
| 1053 GURL url(signin::GetPromoURL( | |
| 1054 source, false /* auto_close */, true /* is_constrained */)); | |
| 1055 web_view->LoadInitialURL(url); | |
| 1056 web_view->SetPreferredSize( | |
| 1057 gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight)); | |
| 1058 | |
| 1059 layout->StartRow(1, 0); | |
| 1060 layout->AddView(web_view); | |
| 1061 | |
| 1062 return view; | |
| 1063 } | |
| 1064 | |
| 1065 views::View* ProfileChooserView::CreateAccountRemovalView() { | |
| 1066 views::View* view = new views::View(); | |
| 1067 views::GridLayout* layout = CreateSingleColumnLayout( | |
| 1068 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew); | |
| 1069 layout->SetInsets(views::kButtonVEdgeMarginNew, | |
| 1070 views::kButtonHEdgeMarginNew, | |
| 1071 views::kButtonVEdgeMarginNew, | |
| 1072 views::kButtonHEdgeMarginNew); | |
| 1073 | |
| 1074 // Adds title. | |
| 1075 layout->StartRow(1, 0); | |
| 1076 layout->AddView(new TitleCard(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE, this, | |
| 1077 &account_removal_cancel_button_)); | |
| 1078 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing); | |
| 1079 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); | |
| 1080 | |
| 1081 const std::string& primary_account = SigninManagerFactory::GetForProfile( | |
| 1082 browser_->profile())->GetAuthenticatedUsername(); | |
| 1083 bool is_primary_account = primary_account == account_id_to_remove_; | |
| 1084 | |
| 1085 // Adds main text. | |
| 1086 views::Label* content_label = new views::Label(is_primary_account ? | |
| 1087 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT, | |
| 1088 base::UTF8ToUTF16(account_id_to_remove_)) : | |
| 1089 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT)); | |
| 1090 | |
| 1091 content_label->SetMultiLine(true); | |
| 1092 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
| 1093 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); | |
| 1094 const gfx::FontList& small_font_list = | |
| 1095 rb->GetFontList(ui::ResourceBundle::SmallFont); | |
| 1096 content_label->SetFontList(small_font_list); | |
| 1097 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); | |
| 1098 layout->AddView(content_label); | |
| 1099 | |
| 1100 // Adds button. | |
| 1101 if (!is_primary_account) { | |
| 1102 remove_account_and_relaunch_button_ = new views::BlueButton( | |
| 1103 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON)); | |
| 1104 remove_account_and_relaunch_button_->SetHorizontalAlignment( | |
| 1105 gfx::ALIGN_CENTER); | |
| 1106 layout->StartRowWithPadding( | |
| 1107 1, 0, 0, views::kUnrelatedControlVerticalSpacing); | |
| 1108 layout->AddView(remove_account_and_relaunch_button_); | |
| 1109 } else { | |
| 1110 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); | |
| 1111 } | |
| 1112 | |
| 1113 return view; | |
| 1114 } | |
| OLD | NEW |