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 |