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

Side by Side Diff: ash/system/user/tray_user.cc

Issue 14756019: Adding new user menu section to the SystemTrayMenu & refactoring of user access (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/system/user/tray_user.h" 5 #include "ash/system/user/tray_user.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <climits> 8 #include <climits>
9 #include <vector> 9 #include <vector>
10 10
11 #include "ash/session_state_delegate.h"
11 #include "ash/shell.h" 12 #include "ash/shell.h"
12 #include "ash/shell_delegate.h" 13 #include "ash/shell_delegate.h"
13 #include "ash/system/tray/system_tray.h" 14 #include "ash/system/tray/system_tray.h"
14 #include "ash/system/tray/system_tray_delegate.h" 15 #include "ash/system/tray/system_tray_delegate.h"
15 #include "ash/system/tray/system_tray_notifier.h" 16 #include "ash/system/tray/system_tray_notifier.h"
16 #include "ash/system/tray/tray_constants.h" 17 #include "ash/system/tray/tray_constants.h"
17 #include "ash/system/tray/tray_item_view.h" 18 #include "ash/system/tray/tray_item_view.h"
18 #include "ash/system/tray/tray_popup_label_button.h" 19 #include "ash/system/tray/tray_popup_label_button.h"
19 #include "ash/system/tray/tray_popup_label_button_border.h" 20 #include "ash/system/tray/tray_popup_label_button_border.h"
20 #include "ash/system/tray/tray_utils.h" 21 #include "ash/system/tray/tray_utils.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 #include "ui/views/layout/box_layout.h" 55 #include "ui/views/layout/box_layout.h"
55 #include "ui/views/layout/fill_layout.h" 56 #include "ui/views/layout/fill_layout.h"
56 #include "ui/views/painter.h" 57 #include "ui/views/painter.h"
57 #include "ui/views/view.h" 58 #include "ui/views/view.h"
58 #include "ui/views/widget/widget.h" 59 #include "ui/views/widget/widget.h"
59 60
60 namespace { 61 namespace {
61 62
62 const int kUserDetailsVerticalPadding = 5; 63 const int kUserDetailsVerticalPadding = 5;
63 const int kUserCardVerticalPadding = 10; 64 const int kUserCardVerticalPadding = 10;
65 const int kInactiveUserCardVerticalPadding = 4;
64 const int kProfileRoundedCornerRadius = 2; 66 const int kProfileRoundedCornerRadius = 2;
65 const int kUserIconSize = 27; 67 const int kUserIconSize = 27;
66 const int kUserLabelToIconPadding = 5; 68 const int kUserLabelToIconPadding = 5;
67 69
70 // The maximum number of simultaneous user profiles.
71 const int kMaxSimultaneousUserProfiles = 3;
James Cook 2013/05/17 14:03:25 Can this constant be shared with the other copy?
Mr4D (OOO till 08-26) 2013/05/17 16:26:40 Done.
72
73 // When a hover border is used, it is starting this many pixels before the icon
74 // position.
75 const int kTrayUserTileHoverBorderInset = 10;
76 // The border color of the user button.
77 const SkColor kBorderColor = 0xffdcdcdc;
78
68 // The invisible word joiner character, used as a marker to indicate the start 79 // The invisible word joiner character, used as a marker to indicate the start
69 // and end of the user's display name in the public account user card's text. 80 // and end of the user's display name in the public account user card's text.
70 const char16 kDisplayNameMark[] = { 0x2060, 0 }; 81 const char16 kDisplayNameMark[] = { 0x2060, 0 };
71 82
72 const int kPublicAccountLogoutButtonBorderImagesNormal[] = { 83 const int kPublicAccountLogoutButtonBorderImagesNormal[] = {
73 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 84 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
74 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 85 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
75 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 86 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
76 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, 87 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
77 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, 88 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
(...skipping 19 matching lines...) Expand all
97 108
98 namespace ash { 109 namespace ash {
99 namespace internal { 110 namespace internal {
100 111
101 namespace tray { 112 namespace tray {
102 113
103 // A custom image view with rounded edges. 114 // A custom image view with rounded edges.
104 class RoundedImageView : public views::View { 115 class RoundedImageView : public views::View {
105 public: 116 public:
106 // Constructs a new rounded image view with rounded corners of radius 117 // Constructs a new rounded image view with rounded corners of radius
107 // |corner_radius|. 118 // |corner_radius|. If |active_user| is set, the icon will be drawn in
108 explicit RoundedImageView(int corner_radius); 119 // full colors - otherwise it will fade into the background.
120 RoundedImageView(int corner_radius, bool active_user);
James Cook 2013/05/17 14:03:25 Given that this is just a view painting, it seems
Mr4D (OOO till 08-26) 2013/05/17 16:26:40 Well ... this is a bool - and since our designers
109 virtual ~RoundedImageView(); 121 virtual ~RoundedImageView();
110 122
111 // Set the image that should be displayed. The image contents is copied to the 123 // Set the image that should be displayed. The image contents is copied to the
112 // receiver's image. 124 // receiver's image.
113 void SetImage(const gfx::ImageSkia& img, const gfx::Size& size); 125 void SetImage(const gfx::ImageSkia& img, const gfx::Size& size);
114 126
115 private: 127 private:
116 // Overridden from views::View. 128 // Overridden from views::View.
117 virtual gfx::Size GetPreferredSize() OVERRIDE; 129 virtual gfx::Size GetPreferredSize() OVERRIDE;
118 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 130 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
119 131
120 gfx::ImageSkia image_; 132 gfx::ImageSkia image_;
121 gfx::ImageSkia resized_; 133 gfx::ImageSkia resized_;
122 gfx::Size image_size_; 134 gfx::Size image_size_;
123 int corner_radius_; 135 int corner_radius_;
124 136
137 // True if the given user is the active user and the icon should get
138 // painted as active.
139 bool active_user_;
140
125 DISALLOW_COPY_AND_ASSIGN(RoundedImageView); 141 DISALLOW_COPY_AND_ASSIGN(RoundedImageView);
126 }; 142 };
127 143
128 class ClickableAvatar : public views::CustomButton {
129 public:
130 explicit ClickableAvatar(views::ButtonListener* listener);
131 virtual ~ClickableAvatar();
132
133 private:
134 DISALLOW_COPY_AND_ASSIGN(ClickableAvatar);
135 };
136
137 // The user details shown in public account mode. This is essentially a label 144 // The user details shown in public account mode. This is essentially a label
138 // but with custom painting code as the text is styled with multiple colors and 145 // but with custom painting code as the text is styled with multiple colors and
139 // contains a link. 146 // contains a link.
140 class PublicAccountUserDetails : public views::View, 147 class PublicAccountUserDetails : public views::View,
141 public views::LinkListener { 148 public views::LinkListener {
142 public: 149 public:
143 PublicAccountUserDetails(SystemTrayItem* owner, int used_width); 150 PublicAccountUserDetails(SystemTrayItem* owner, int used_width);
144 virtual ~PublicAccountUserDetails(); 151 virtual ~PublicAccountUserDetails();
145 152
146 private: 153 private:
(...skipping 11 matching lines...) Expand all
158 void CalculatePreferredSize(SystemTrayItem* owner, int used_width); 165 void CalculatePreferredSize(SystemTrayItem* owner, int used_width);
159 166
160 base::string16 text_; 167 base::string16 text_;
161 views::Link* learn_more_; 168 views::Link* learn_more_;
162 gfx::Size preferred_size_; 169 gfx::Size preferred_size_;
163 ScopedVector<gfx::RenderText> lines_; 170 ScopedVector<gfx::RenderText> lines_;
164 171
165 DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails); 172 DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails);
166 }; 173 };
167 174
175 // The button which holds the user card in case of multi profile.
176 class UserCard : public views::CustomButton {
177 public:
178 explicit UserCard(views::ButtonListener* listener, bool active_user);
James Cook 2013/05/17 14:03:25 no explicit
Mr4D (OOO till 08-26) 2013/05/17 16:26:40 Done.
179 virtual ~UserCard();
180
181 // Overridden from views::View
182 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
183 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
184
185 private:
186 void ShowActive(bool active);
187
188 // True if this is the active user.
189 bool is_active_user_;
190 DISALLOW_COPY_AND_ASSIGN(UserCard);
191 };
192
168 class UserView : public views::View, 193 class UserView : public views::View,
169 public views::ButtonListener { 194 public views::ButtonListener {
170 public: 195 public:
171 explicit UserView(SystemTrayItem* owner, ash::user::LoginStatus login); 196 explicit UserView(SystemTrayItem* owner,
James Cook 2013/05/17 14:03:25 no explicit
Mr4D (OOO till 08-26) 2013/05/17 16:26:40 Done.
197 ash::user::LoginStatus login,
198 MultiProfileIndex index);
172 virtual ~UserView(); 199 virtual ~UserView();
173 200
174 private: 201 private:
175 // Overridden from views::View. 202 // Overridden from views::View.
176 virtual gfx::Size GetPreferredSize() OVERRIDE; 203 virtual gfx::Size GetPreferredSize() OVERRIDE;
177 virtual int GetHeightForWidth(int width) OVERRIDE; 204 virtual int GetHeightForWidth(int width) OVERRIDE;
178 virtual void Layout() OVERRIDE; 205 virtual void Layout() OVERRIDE;
179 206
180 // Overridden from views::ButtonListener. 207 // Overridden from views::ButtonListener.
181 virtual void ButtonPressed(views::Button* sender, 208 virtual void ButtonPressed(views::Button* sender,
182 const ui::Event& event) OVERRIDE; 209 const ui::Event& event) OVERRIDE;
183 210
184 void AddLogoutButton(ash::user::LoginStatus login); 211 void AddLogoutButton(ash::user::LoginStatus login);
185 void AddUserCard(SystemTrayItem* owner, ash::user::LoginStatus login); 212 void AddUserCard(SystemTrayItem* owner, ash::user::LoginStatus login);
186 213
214 MultiProfileIndex multiprofile_index_;
187 views::View* user_card_; 215 views::View* user_card_;
188 views::View* logout_button_; 216 views::View* logout_button_;
189 ClickableAvatar* profile_picture_;
190 217
191 DISALLOW_COPY_AND_ASSIGN(UserView); 218 DISALLOW_COPY_AND_ASSIGN(UserView);
192 }; 219 };
193 220
194 RoundedImageView::RoundedImageView(int corner_radius) 221 RoundedImageView::RoundedImageView(int corner_radius, bool active_user)
195 : corner_radius_(corner_radius) {} 222 : corner_radius_(corner_radius),
223 active_user_(active_user) {}
196 224
197 RoundedImageView::~RoundedImageView() {} 225 RoundedImageView::~RoundedImageView() {}
198 226
199 void RoundedImageView::SetImage(const gfx::ImageSkia& img, 227 void RoundedImageView::SetImage(const gfx::ImageSkia& img,
200 const gfx::Size& size) { 228 const gfx::Size& size) {
201 image_ = img; 229 image_ = img;
202 image_size_ = size; 230 image_size_ = size;
203 231
204 // Try to get the best image quality for the avatar. 232 // Try to get the best image quality for the avatar.
205 resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_, 233 resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_,
(...skipping 12 matching lines...) Expand all
218 void RoundedImageView::OnPaint(gfx::Canvas* canvas) { 246 void RoundedImageView::OnPaint(gfx::Canvas* canvas) {
219 View::OnPaint(canvas); 247 View::OnPaint(canvas);
220 gfx::Rect image_bounds(size()); 248 gfx::Rect image_bounds(size());
221 image_bounds.ClampToCenteredSize(GetPreferredSize()); 249 image_bounds.ClampToCenteredSize(GetPreferredSize());
222 image_bounds.Inset(GetInsets()); 250 image_bounds.Inset(GetInsets());
223 const SkScalar kRadius = SkIntToScalar(corner_radius_); 251 const SkScalar kRadius = SkIntToScalar(corner_radius_);
224 SkPath path; 252 SkPath path;
225 path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius, kRadius); 253 path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius, kRadius);
226 SkPaint paint; 254 SkPaint paint;
227 paint.setAntiAlias(true); 255 paint.setAntiAlias(true);
228 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); 256 paint.setXfermodeMode(active_user_ ? SkXfermode::kSrcOver_Mode :
257 SkXfermode::kLuminosity_Mode);
James Cook 2013/05/17 14:03:25 Aha, that's how you do it!
Mr4D (OOO till 08-26) 2013/05/17 16:26:40 Yepp.
229 canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(), 258 canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(),
230 path, paint); 259 path, paint);
231 } 260 }
232 261
233 ClickableAvatar::ClickableAvatar(views::ButtonListener* listener)
234 : views::CustomButton(listener) {
235 SetLayoutManager(new views::FillLayout());
236 RoundedImageView* user_picture =
237 new RoundedImageView(kProfileRoundedCornerRadius);
238 user_picture->SetImage(
239 ash::Shell::GetInstance()->system_tray_delegate()->GetUserImage(),
240 gfx::Size(kUserIconSize, kUserIconSize));
241 AddChildView(user_picture);
242 }
243
244 ClickableAvatar::~ClickableAvatar() {}
245
246 PublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner, 262 PublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner,
247 int used_width) 263 int used_width)
248 : learn_more_(NULL) { 264 : learn_more_(NULL) {
249 const int inner_padding = 265 const int inner_padding =
250 kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems; 266 kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems;
251 const bool rtl = base::i18n::IsRTL(); 267 const bool rtl = base::i18n::IsRTL();
252 set_border(views::Border::CreateEmptyBorder( 268 set_border(views::Border::CreateEmptyBorder(
253 kUserDetailsVerticalPadding, rtl ? 0 : inner_padding, 269 kUserDetailsVerticalPadding, rtl ? 0 : inner_padding,
254 kUserDetailsVerticalPadding, rtl ? inner_padding : 0)); 270 kUserDetailsVerticalPadding, rtl ? inner_padding : 0));
255 271
256 ash::SystemTrayDelegate* delegate =
257 ash::Shell::GetInstance()->system_tray_delegate();
258 // Retrieve the user's display name and wrap it with markers. 272 // Retrieve the user's display name and wrap it with markers.
259 base::string16 display_name = delegate->GetUserDisplayName(); 273 // Note that since this is a public account it always has to be the primary
274 // user.
275 base::string16 display_name =
276 ash::Shell::GetInstance()->session_state_delegate()->GetUserDisplayName(
277 0);
260 RemoveChars(display_name, kDisplayNameMark, &display_name); 278 RemoveChars(display_name, kDisplayNameMark, &display_name);
261 display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0]; 279 display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0];
262 // Retrieve the domain managing the device and wrap it with markers. 280 // Retrieve the domain managing the device and wrap it with markers.
263 base::string16 domain = UTF8ToUTF16(delegate->GetEnterpriseDomain()); 281 base::string16 domain = UTF8ToUTF16(
282 ash::Shell::GetInstance()->system_tray_delegate()->GetEnterpriseDomain());
264 RemoveChars(domain, kDisplayNameMark, &domain); 283 RemoveChars(domain, kDisplayNameMark, &domain);
265 base::i18n::WrapStringWithLTRFormatting(&domain); 284 base::i18n::WrapStringWithLTRFormatting(&domain);
266 // Retrieve the label text, inserting the display name and domain. 285 // Retrieve the label text, inserting the display name and domain.
267 text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL, 286 text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL,
268 display_name, domain); 287 display_name, domain);
269 288
270 learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE)); 289 learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE));
271 learn_more_->SetUnderline(false); 290 learn_more_->SetUnderline(false);
272 learn_more_->set_listener(this); 291 learn_more_->set_listener(this);
273 AddChildView(learn_more_); 292 AddChildView(learn_more_);
274 293
275 CalculatePreferredSize(owner, used_width); 294 CalculatePreferredSize(owner, used_width);
276 } 295 }
277 296
278 PublicAccountUserDetails::~PublicAccountUserDetails() {} 297 PublicAccountUserDetails::~PublicAccountUserDetails() {}
279 298
280 void PublicAccountUserDetails::Layout() { 299 void PublicAccountUserDetails::Layout() {
281 lines_.clear(); 300 lines_.clear();
282 const gfx::Rect contents_area = GetContentsBounds(); 301 const gfx::Rect contents_area = GetContentsBounds();
283 if (contents_area.IsEmpty()) 302 if (contents_area.IsEmpty())
284 return; 303 return;
285 304
286 // Word-wrap the label text. 305 // Word-wrap the label text.
287 const gfx::Font font; 306 const gfx::Font font;
288 std::vector<base::string16> lines; 307 std::vector<base::string16> lines;
289 ui::ElideRectangleText(text_, font, contents_area.width(), 308 ui::ElideRectangleText(text_, font, contents_area.width(),
290 contents_area.height(), ui::ELIDE_LONG_WORDS, &lines); 309 contents_area.height(), ui::ELIDE_LONG_WORDS, &lines);
291 // Loop through the lines, creating a renderer for each. 310 // Loop through the lines, creating a renderer for each.
292 gfx::Point position = contents_area.origin(); 311 gfx::Point position = contents_area.origin();
293 ui::Range display_name(ui::Range::InvalidRange()); 312 ui::Range display_name(ui::Range::InvalidRange());
294 for (std::vector<base::string16>::const_iterator it = lines.begin(); 313 for (std::vector<base::string16>::const_iterator it = lines.begin();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 const int line_height = font.GetHeight(); 429 const int line_height = font.GetHeight();
411 const int link_extra_height = std::max( 430 const int link_extra_height = std::max(
412 link_size.height() - learn_more_->GetInsets().top() - line_height, 0); 431 link_size.height() - learn_more_->GetInsets().top() - line_height, 0);
413 preferred_size_ = gfx::Size( 432 preferred_size_ = gfx::Size(
414 min_width + insets.width(), 433 min_width + insets.width(),
415 line_count * line_height + link_extra_height + insets.height()); 434 line_count * line_height + link_extra_height + insets.height());
416 435
417 bubble_view->SetWidth(preferred_size_.width() + used_width); 436 bubble_view->SetWidth(preferred_size_.width() + used_width);
418 } 437 }
419 438
420 UserView::UserView(SystemTrayItem* owner, ash::user::LoginStatus login) 439 UserCard::UserCard(views::ButtonListener* listener, bool active_user)
421 : user_card_(NULL), 440 : CustomButton(listener),
422 logout_button_(NULL), 441 is_active_user_(active_user) {
423 profile_picture_(NULL) { 442 if (is_active_user_) {
443 set_background(
444 views::Background::CreateSolidBackground(kBackgroundColor));
445 ShowActive(false);
446 }
447 }
448
449 UserCard::~UserCard() {}
450
451 void UserCard::OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
452 if (is_active_user_) {
453 background()->SetNativeControlColor(kHoverBackgroundColor);
454 ShowActive(true);
455 SchedulePaint();
456 }
457 }
458
459 void UserCard::OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
460 if (is_active_user_) {
461 background()->SetNativeControlColor(kBackgroundColor);
462 ShowActive(false);
463 SchedulePaint();
464 }
465 }
466
467 void UserCard::ShowActive(bool active) {
468 int width = active ? 1 : 0;
469 set_border(views::Border::CreateSolidSidedBorder(width, width, width, 1,
470 kBorderColor));
471 }
472
473 UserView::UserView(SystemTrayItem* owner,
474 ash::user::LoginStatus login,
475 MultiProfileIndex index)
476 : multiprofile_index_(index),
477 user_card_(NULL),
478 logout_button_(NULL) {
424 CHECK_NE(ash::user::LOGGED_IN_NONE, login); 479 CHECK_NE(ash::user::LOGGED_IN_NONE, login);
425 set_background(views::Background::CreateSolidBackground( 480 if (!index) {
426 login == ash::user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor : 481 // Only the logged in user will have a background. All other users will have
427 kBackgroundColor)); 482 // have none to allow the TrayPopupContainer to highlight the menu line.
483 set_background(views::Background::CreateSolidBackground(
484 login == ash::user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor :
485 kBackgroundColor));
486 }
428 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 487 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
429 kTrayPopupPaddingBetweenItems)); 488 kTrayPopupPaddingBetweenItems));
430 // The logout button must be added before the user card so that the user card 489 // The logout button must be added before the user card so that the user card
431 // can correctly calculate the remaining available width. 490 // can correctly calculate the remaining available width.
432 AddLogoutButton(login); 491 // Note that only the current multiprofile user gets a button.
492 AddLogoutButton(!multiprofile_index_ ? login : ash::user::LOGGED_IN_LOCKED);
433 AddUserCard(owner, login); 493 AddUserCard(owner, login);
434 } 494 }
435 495
436 UserView::~UserView() {} 496 UserView::~UserView() {}
437 497
438 gfx::Size UserView::GetPreferredSize() { 498 gfx::Size UserView::GetPreferredSize() {
439 gfx::Size size = views::View::GetPreferredSize(); 499 gfx::Size size = views::View::GetPreferredSize();
440 if (!user_card_) { 500 if (!user_card_) {
441 // Make sure the default user view item is at least as tall as the other 501 // The default user view item should be at least as tall as the other items.
442 // items.
443 size.set_height(std::max(size.height(), 502 size.set_height(std::max(size.height(),
444 kTrayPopupItemHeight + GetInsets().height())); 503 kTrayPopupItemHeight + GetInsets().height()));
445 } 504 }
446 return size; 505 return size;
447 } 506 }
448 507
449 int UserView::GetHeightForWidth(int width) { 508 int UserView::GetHeightForWidth(int width) {
450 return GetPreferredSize().height(); 509 return GetPreferredSize().height();
451 } 510 }
452 511
453 void UserView::Layout() { 512 void UserView::Layout() {
454 gfx::Rect contents_area(GetContentsBounds()); 513 gfx::Rect contents_area(GetContentsBounds());
455 if (user_card_ && logout_button_) { 514 if (user_card_ && logout_button_) {
456 // Give the logout button the space it requests. 515 // Give the logout button the space it requests.
457 gfx::Rect logout_area = contents_area; 516 gfx::Rect logout_area = contents_area;
458 logout_area.ClampToCenteredSize(logout_button_->GetPreferredSize()); 517 logout_area.ClampToCenteredSize(logout_button_->GetPreferredSize());
459 logout_area.set_x(contents_area.right() - logout_area.width()); 518 logout_area.set_x(contents_area.right() - logout_area.width());
460 logout_button_->SetBoundsRect(logout_area);
461 519
462 // Give the remaining space to the user card. 520 // Give the remaining space to the user card.
463 gfx::Rect user_card_area = contents_area; 521 gfx::Rect user_card_area = contents_area;
464 int remaining_width = contents_area.width() - 522 int remaining_width = contents_area.width() - logout_area.width();
465 (logout_area.width() + kTrayPopupPaddingBetweenItems); 523 if (ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled()) {
466 user_card_area.set_width(std::max(0, remaining_width)); 524 // In multiprofile case |user_card_| and |logout_button_| have to have the
525 // same height.
526 int y = std::min(user_card_area.y(), logout_area.y());
527 int height = std::max(user_card_area.height(), logout_area.height());
528 logout_area.set_y(y);
529 logout_area.set_height(height);
530 user_card_area.set_y(y);
531 user_card_area.set_height(height);
532 // In multiprofile mode we have also to increase the size of the card by
533 // the size of the border to make it overlap with the logout button.
534 user_card_area.set_width(std::max(0, remaining_width + 1));
535 // To make the logout button symmetrical with the user card we also make
536 // the button longer by the same size the hover area in front of the icon
537 // got inset.
538 logout_area.set_width(logout_area.width() +
539 kTrayUserTileHoverBorderInset);
540 } else {
541 // In all other modes we have to make sure that there is enough spacing
542 // between the two.
543 remaining_width -= kTrayPopupPaddingBetweenItems;
544 }
467 user_card_->SetBoundsRect(user_card_area); 545 user_card_->SetBoundsRect(user_card_area);
546 logout_button_->SetBoundsRect(logout_area);
468 } else if (user_card_) { 547 } else if (user_card_) {
469 user_card_->SetBoundsRect(contents_area); 548 user_card_->SetBoundsRect(contents_area);
470 } else if (logout_button_) { 549 } else if (logout_button_) {
471 logout_button_->SetBoundsRect(contents_area); 550 logout_button_->SetBoundsRect(contents_area);
472 } 551 }
473 } 552 }
474 553
475 void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) { 554 void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
476 if (sender == logout_button_) { 555 if (sender == logout_button_) {
477 ash::Shell::GetInstance()->system_tray_delegate()->SignOut(); 556 ash::Shell::GetInstance()->system_tray_delegate()->SignOut();
478 } else if (sender == profile_picture_) { 557 } else if (sender == user_card_ &&
479 if (ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled()) 558 ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled()) {
480 ash::Shell::GetInstance()->system_tray_delegate()->ShowUserLogin(); 559 if (!multiprofile_index_) {
481 else 560 // TODO(skuhne): Need to add the images & adding logic here.
482 ash::Shell::GetInstance()->system_tray_delegate()->ChangeProfilePicture(); 561 // TODO(skuhne): Make sure that we do not offer an add when this mode is
562 // active.
563 // TODO(skuhne): Use IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT as
564 // string.
565 if (ash::Shell::GetInstance()->session_state_delegate()->
James Cook 2013/05/17 14:03:25 optional nit: Sometimes for functions like this wi
Mr4D (OOO till 08-26) 2013/05/17 16:26:40 Done. Note: Also that this is moving into a new pl
566 NumberOfLoggedInUsers() >= kMaxSimultaneousUserProfiles) {
567 // TODO(skuhne): Use IDS_ASH_STATUS_TRAY_CAPTION_CANNOT_ADD_USER and
568 // IDS_ASH_STATUS_TRAY_MESSAGE_CANNOT_ADD_USER when showing the error
569 // message that no more users can be added.
570 } else {
571 ash::Shell::GetInstance()->system_tray_delegate()->ShowUserLogin();
572 }
573 } else {
574 ash::SessionStateDelegate* delegate =
575 ash::Shell::GetInstance()->session_state_delegate();
576 delegate->SwitchActiveUser(delegate->GetUserEmail(multiprofile_index_));
577 }
483 } else { 578 } else {
484 NOTREACHED(); 579 NOTREACHED();
485 } 580 }
486 } 581 }
487 582
488 void UserView::AddLogoutButton(ash::user::LoginStatus login) { 583 void UserView::AddLogoutButton(ash::user::LoginStatus login) {
489 // A user should not be able to modify logged-in state when screen is 584 // A user should not be able to modify logged-in state when screen is
490 // locked. 585 // locked.
491 if (login == ash::user::LOGGED_IN_LOCKED) 586 if (login == ash::user::LOGGED_IN_LOCKED)
492 return; 587 return;
(...skipping 18 matching lines...) Expand all
511 kPublicAccountLogoutButtonBorderImagesHovered)); 606 kPublicAccountLogoutButtonBorderImagesHovered));
512 } 607 }
513 AddChildView(logout_button_); 608 AddChildView(logout_button_);
514 } 609 }
515 610
516 void UserView::AddUserCard(SystemTrayItem* owner, 611 void UserView::AddUserCard(SystemTrayItem* owner,
517 ash::user::LoginStatus login) { 612 ash::user::LoginStatus login) {
518 if (login == ash::user::LOGGED_IN_GUEST) 613 if (login == ash::user::LOGGED_IN_GUEST)
519 return; 614 return;
520 615
521 set_border(views::Border::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 616 // Add padding around the panel.
522 0, kTrayPopupPaddingHorizontal)); 617 set_border(views::Border::CreateEmptyBorder(
618 kUserCardVerticalPadding, kTrayPopupPaddingHorizontal,
619 kUserCardVerticalPadding, kTrayPopupPaddingHorizontal));
523 620
524 user_card_ = new views::View(); 621 if (ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled() &&
622 login != ash::user::LOGGED_IN_RETAIL_MODE)
623 user_card_ = new UserCard(this, multiprofile_index_ == 0);
624 else
625 user_card_ = new views::View();
626
525 user_card_->SetLayoutManager(new views::BoxLayout( 627 user_card_->SetLayoutManager(new views::BoxLayout(
526 views::BoxLayout::kHorizontal, 0, kUserCardVerticalPadding, 628 views::BoxLayout::kHorizontal, 0, 0 , kTrayPopupPaddingBetweenItems));
527 kTrayPopupPaddingBetweenItems));
528 AddChildViewAt(user_card_, 0); 629 AddChildViewAt(user_card_, 0);
529 630
530 if (login == ash::user::LOGGED_IN_RETAIL_MODE) { 631 if (login == ash::user::LOGGED_IN_RETAIL_MODE) {
531 views::Label* details = new views::Label; 632 views::Label* details = new views::Label;
532 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 633 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
533 details->SetText( 634 details->SetText(
534 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL)); 635 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
535 details->set_border(views::Border::CreateEmptyBorder(0, 4, 0, 1)); 636 details->set_border(views::Border::CreateEmptyBorder(0, 4, 0, 1));
536 details->SetHorizontalAlignment(gfx::ALIGN_LEFT); 637 details->SetHorizontalAlignment(gfx::ALIGN_LEFT);
537 user_card_->AddChildView(details); 638 user_card_->AddChildView(details);
538 return; 639 return;
539 } 640 }
540 profile_picture_ = new ClickableAvatar(this); 641
541 user_card_->AddChildView(profile_picture_); 642 // The entire user card should trigger hover (the inner items get disabled).
643 user_card_->SetEnabled(true);
644
645 RoundedImageView* icon = new RoundedImageView(kProfileRoundedCornerRadius,
646 multiprofile_index_ == 0);
647 icon->SetEnabled(false);
648 icon->SetImage(
649 ash::Shell::GetInstance()->session_state_delegate()->GetUserImage(
650 multiprofile_index_),
651 gfx::Size(kUserIconSize, kUserIconSize));
652 user_card_->AddChildView(icon);
542 653
543 if (login == ash::user::LOGGED_IN_PUBLIC) { 654 if (login == ash::user::LOGGED_IN_PUBLIC) {
544 user_card_->AddChildView(new PublicAccountUserDetails( 655 user_card_->AddChildView(new PublicAccountUserDetails(
545 owner, GetPreferredSize().width() + kTrayPopupPaddingBetweenItems)); 656 owner, GetPreferredSize().width() + kTrayPopupPaddingBetweenItems));
546 return; 657 return;
547 } 658 }
548 659
549 ash::SystemTrayDelegate* delegate = 660 // To allow the border to start before the icon, reduce the size before and
550 ash::Shell::GetInstance()->system_tray_delegate(); 661 // add an inset to the icon to get the spacing.
662 if (multiprofile_index_ == 0 &&
663 ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled()) {
664 icon->set_border(views::Border::CreateEmptyBorder(
665 0, kTrayUserTileHoverBorderInset, 0, 0));
666 set_border(views::Border::CreateEmptyBorder(
667 kUserCardVerticalPadding,
668 kTrayPopupPaddingHorizontal - kTrayUserTileHoverBorderInset,
669 kUserCardVerticalPadding,
670 kTrayPopupPaddingHorizontal));
671 }
672 ash::SessionStateDelegate* delegate =
673 ash::Shell::GetInstance()->session_state_delegate();
551 views::View* details = new views::View; 674 views::View* details = new views::View;
675 details->SetEnabled(false);
552 details->SetLayoutManager(new views::BoxLayout( 676 details->SetLayoutManager(new views::BoxLayout(
553 views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0)); 677 views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0));
554 views::Label* username = new views::Label(delegate->GetUserDisplayName()); 678 views::Label* username = NULL;
555 username->SetHorizontalAlignment(gfx::ALIGN_LEFT); 679 if (!multiprofile_index_) {
556 details->AddChildView(username); 680 username =
557 681 new views::Label(delegate->GetUserDisplayName(multiprofile_index_));
682 username->SetEnabled(false);
683 username->SetHorizontalAlignment(gfx::ALIGN_LEFT);
684 details->AddChildView(username);
685 }
558 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 686 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
559 687
560 views::Label* additional = new views::Label(); 688 views::Label* additional = new views::Label();
561 689 additional->SetEnabled(false);
562 additional->SetText(login == ash::user::LOGGED_IN_LOCALLY_MANAGED ? 690 additional->SetText(login == ash::user::LOGGED_IN_LOCALLY_MANAGED ?
563 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL) : 691 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL) :
564 UTF8ToUTF16(delegate->GetUserEmail())); 692 UTF8ToUTF16(delegate->GetUserEmail(multiprofile_index_)));
565 693
566 additional->SetFont(bundle.GetFont(ui::ResourceBundle::SmallFont));
567 additional->SetHorizontalAlignment(gfx::ALIGN_LEFT); 694 additional->SetHorizontalAlignment(gfx::ALIGN_LEFT);
568 additional->SetEnabled(false);
569 details->AddChildView(additional); 695 details->AddChildView(additional);
696 // Adjust text properties dependent on if it is an active or inactive user.
697 if (multiprofile_index_) {
698 // Fade the text of non active users to 50%.
699 SkColor text_color = additional->enabled_color();
700 text_color = SkColorSetA(text_color, SkColorGetA(text_color) / 2);
701 additional->SetDisabledColor(text_color);
702 if (username)
703 username->SetDisabledColor(text_color);
704 }
705
706 // Use a small font for email address if username is given.
707 if (username)
708 additional->SetFont(bundle.GetFont(ui::ResourceBundle::SmallFont));
709
570 user_card_->AddChildView(details); 710 user_card_->AddChildView(details);
571 } 711 }
572 712
573 } // namespace tray 713 } // namespace tray
574 714
575 TrayUser::TrayUser(SystemTray* system_tray) 715 TrayUser::TrayUser(SystemTray* system_tray, MultiProfileIndex index)
576 : SystemTrayItem(system_tray), 716 : SystemTrayItem(system_tray),
717 multiprofile_index_(index),
577 user_(NULL), 718 user_(NULL),
578 layout_view_(NULL), 719 layout_view_(NULL),
579 avatar_(NULL), 720 avatar_(NULL),
580 label_(NULL) { 721 label_(NULL) {
581 Shell::GetInstance()->system_tray_notifier()->AddUserObserver(this); 722 Shell::GetInstance()->system_tray_notifier()->AddUserObserver(this);
582 } 723 }
583 724
584 TrayUser::~TrayUser() { 725 TrayUser::~TrayUser() {
585 Shell::GetInstance()->system_tray_notifier()->RemoveUserObserver(this); 726 Shell::GetInstance()->system_tray_notifier()->RemoveUserObserver(this);
586 } 727 }
587 728
588 views::View* TrayUser::CreateTrayView(user::LoginStatus status) { 729 views::View* TrayUser::CreateTrayView(user::LoginStatus status) {
589 CHECK(layout_view_ == NULL); 730 CHECK(layout_view_ == NULL);
731 // Only the current user gets an icon. All other users will only be
732 // represented in the tray menu.
733 if (multiprofile_index_)
734 return NULL;
735
590 layout_view_ = new views::View(); 736 layout_view_ = new views::View();
591 layout_view_->SetLayoutManager( 737 layout_view_->SetLayoutManager(
592 new views::BoxLayout(views::BoxLayout::kHorizontal, 738 new views::BoxLayout(views::BoxLayout::kHorizontal,
593 0, 0, kUserLabelToIconPadding)); 739 0, 0, kUserLabelToIconPadding));
594 UpdateAfterLoginStatusChange(status); 740 UpdateAfterLoginStatusChange(status);
595 return layout_view_; 741 return layout_view_;
596 } 742 }
597 743
598 views::View* TrayUser::CreateDefaultView(user::LoginStatus status) { 744 views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
599 if (status == user::LOGGED_IN_NONE) 745 if (status == user::LOGGED_IN_NONE)
600 return NULL; 746 return NULL;
601 747
602 CHECK(user_ == NULL); 748 CHECK(user_ == NULL);
603 user_ = new tray::UserView(this, status); 749
750 int logged_in_users = ash::Shell::GetInstance()->session_state_delegate()->
751 NumberOfLoggedInUsers();
752
753 // If there are multiple users logged in, the users will be separated from the
754 // rest of the menu by a separator.
755 if (multiprofile_index_ == kMaxSimultaneousUserProfiles &&
756 logged_in_users > 1)
757 return new views::View();
758
759 // Do not show more UserView's then there are logged in users.
760 if (multiprofile_index_ >= logged_in_users)
761 return NULL;;
762
763 user_ = new tray::UserView(this, status, multiprofile_index_);
604 return user_; 764 return user_;
605 } 765 }
606 766
607 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) { 767 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) {
608 return NULL; 768 return NULL;
609 } 769 }
610 770
611 void TrayUser::DestroyTrayView() { 771 void TrayUser::DestroyTrayView() {
612 layout_view_ = NULL; 772 layout_view_ = NULL;
613 avatar_ = NULL; 773 avatar_ = NULL;
614 label_ = NULL; 774 label_ = NULL;
615 } 775 }
616 776
617 void TrayUser::DestroyDefaultView() { 777 void TrayUser::DestroyDefaultView() {
618 user_ = NULL; 778 user_ = NULL;
619 } 779 }
620 780
621 void TrayUser::DestroyDetailedView() { 781 void TrayUser::DestroyDetailedView() {
622 } 782 }
623 783
624 void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status) { 784 void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status) {
625 CHECK(layout_view_); 785 // Only the active user is represented in the tray.
786 if (!layout_view_)
787 return;
626 bool need_label = false; 788 bool need_label = false;
627 bool need_avatar = false; 789 bool need_avatar = false;
628 switch (status) { 790 switch (status) {
629 case user::LOGGED_IN_LOCKED: 791 case user::LOGGED_IN_LOCKED:
630 case user::LOGGED_IN_USER: 792 case user::LOGGED_IN_USER:
631 case user::LOGGED_IN_OWNER: 793 case user::LOGGED_IN_OWNER:
632 case user::LOGGED_IN_PUBLIC: 794 case user::LOGGED_IN_PUBLIC:
633 need_avatar = true; 795 need_avatar = true;
634 break; 796 break;
635 case user::LOGGED_IN_LOCALLY_MANAGED: 797 case user::LOGGED_IN_LOCALLY_MANAGED:
(...skipping 13 matching lines...) Expand all
649 (need_label != (label_ != NULL))) { 811 (need_label != (label_ != NULL))) {
650 layout_view_->RemoveAllChildViews(true); 812 layout_view_->RemoveAllChildViews(true);
651 if (need_label) { 813 if (need_label) {
652 label_ = new views::Label; 814 label_ = new views::Label;
653 SetupLabelForTray(label_); 815 SetupLabelForTray(label_);
654 layout_view_->AddChildView(label_); 816 layout_view_->AddChildView(label_);
655 } else { 817 } else {
656 label_ = NULL; 818 label_ = NULL;
657 } 819 }
658 if (need_avatar) { 820 if (need_avatar) {
659 avatar_ = new tray::RoundedImageView(kProfileRoundedCornerRadius); 821 avatar_ = new tray::RoundedImageView(kProfileRoundedCornerRadius, true);
660 layout_view_->AddChildView(avatar_); 822 layout_view_->AddChildView(avatar_);
661 } else { 823 } else {
662 avatar_ = NULL; 824 avatar_ = NULL;
663 } 825 }
664 } 826 }
665 827
666 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 828 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
667 if (status == user::LOGGED_IN_LOCALLY_MANAGED) { 829 if (status == user::LOGGED_IN_LOCALLY_MANAGED) {
668 label_->SetText( 830 label_->SetText(
669 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL)); 831 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL));
670 } else if (status == user::LOGGED_IN_GUEST) { 832 } else if (status == user::LOGGED_IN_GUEST) {
671 label_->SetText(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL)); 833 label_->SetText(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL));
672 } 834 }
673 835
674 if (avatar_) { 836 if (avatar_) {
675 avatar_->SetImage( 837 avatar_->SetImage(
676 ash::Shell::GetInstance()->system_tray_delegate()->GetUserImage(), 838 ash::Shell::GetInstance()->session_state_delegate()->GetUserImage(
839 multiprofile_index_),
677 gfx::Size(kUserIconSize, kUserIconSize)); 840 gfx::Size(kUserIconSize, kUserIconSize));
678 } 841 }
679 } 842 }
680 843
681 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 844 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
682 CHECK(layout_view_); 845 // Inactive users won't have a layout.
846 if (!layout_view_)
847 return;
683 if (alignment == SHELF_ALIGNMENT_BOTTOM || 848 if (alignment == SHELF_ALIGNMENT_BOTTOM ||
684 alignment == SHELF_ALIGNMENT_TOP) { 849 alignment == SHELF_ALIGNMENT_TOP) {
685 if (avatar_) { 850 if (avatar_) {
686 avatar_->set_border(views::Border::CreateEmptyBorder( 851 avatar_->set_border(views::Border::CreateEmptyBorder(
687 0, kTrayImageItemHorizontalPaddingBottomAlignment + 2, 852 0, kTrayImageItemHorizontalPaddingBottomAlignment + 2,
688 0, kTrayImageItemHorizontalPaddingBottomAlignment)); 853 0, kTrayImageItemHorizontalPaddingBottomAlignment));
689 854
690 } 855 }
691 if (label_) { 856 if (label_) {
692 label_->set_border(views::Border::CreateEmptyBorder( 857 label_->set_border(views::Border::CreateEmptyBorder(
(...skipping 16 matching lines...) Expand all
709 layout_view_->SetLayoutManager( 874 layout_view_->SetLayoutManager(
710 new views::BoxLayout(views::BoxLayout::kVertical, 875 new views::BoxLayout(views::BoxLayout::kVertical,
711 0, 0, kUserLabelToIconPadding)); 876 0, 0, kUserLabelToIconPadding));
712 } 877 }
713 } 878 }
714 879
715 void TrayUser::OnUserUpdate() { 880 void TrayUser::OnUserUpdate() {
716 // Check for null to avoid crbug.com/150944. 881 // Check for null to avoid crbug.com/150944.
717 if (avatar_) { 882 if (avatar_) {
718 avatar_->SetImage( 883 avatar_->SetImage(
719 ash::Shell::GetInstance()->system_tray_delegate()->GetUserImage(), 884 ash::Shell::GetInstance()->session_state_delegate()->GetUserImage(
885 multiprofile_index_),
720 gfx::Size(kUserIconSize, kUserIconSize)); 886 gfx::Size(kUserIconSize, kUserIconSize));
721 } 887 }
722 } 888 }
723 889
724 } // namespace internal 890 } // namespace internal
725 } // namespace ash 891 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698