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

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

Issue 11377133: Customize user details in ash system bubble for public account mode (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Re-uploading to try and unstuck the CQ. Created 8 years 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
« no previous file with comments | « ash/system/user/tray_user.h ('k') | chrome/browser/chromeos/system/ash_system_tray_delegate.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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>
8 #include <climits>
9 #include <vector>
10
7 #include "ash/shell.h" 11 #include "ash/shell.h"
12 #include "ash/system/tray/system_tray.h"
8 #include "ash/system/tray/system_tray_delegate.h" 13 #include "ash/system/tray/system_tray_delegate.h"
9 #include "ash/system/tray/tray_constants.h" 14 #include "ash/system/tray/tray_constants.h"
10 #include "ash/system/tray/tray_item_view.h" 15 #include "ash/system/tray/tray_item_view.h"
11 #include "ash/system/tray/tray_views.h" 16 #include "ash/system/tray/tray_views.h"
17 #include "base/i18n/rtl.h"
18 #include "base/logging.h"
19 #include "base/memory/scoped_vector.h"
20 #include "base/string16.h"
21 #include "base/string_util.h"
12 #include "base/utf_string_conversions.h" 22 #include "base/utf_string_conversions.h"
23 #include "grit/ash_resources.h"
13 #include "grit/ash_strings.h" 24 #include "grit/ash_strings.h"
14 #include "skia/ext/image_operations.h" 25 #include "skia/ext/image_operations.h"
15 #include "third_party/skia/include/core/SkCanvas.h" 26 #include "third_party/skia/include/core/SkCanvas.h"
16 #include "third_party/skia/include/core/SkPaint.h" 27 #include "third_party/skia/include/core/SkPaint.h"
17 #include "third_party/skia/include/core/SkPath.h" 28 #include "third_party/skia/include/core/SkPath.h"
29 #include "ui/base/l10n/l10n_util.h"
30 #include "ui/base/range/range.h"
18 #include "ui/base/resource/resource_bundle.h" 31 #include "ui/base/resource/resource_bundle.h"
32 #include "ui/base/text/text_elider.h"
19 #include "ui/gfx/canvas.h" 33 #include "ui/gfx/canvas.h"
34 #include "ui/gfx/font.h"
20 #include "ui/gfx/image/image.h" 35 #include "ui/gfx/image/image.h"
21 #include "ui/gfx/image/image_skia_operations.h" 36 #include "ui/gfx/image/image_skia_operations.h"
37 #include "ui/gfx/insets.h"
38 #include "ui/gfx/rect.h"
39 #include "ui/gfx/render_text.h"
22 #include "ui/gfx/size.h" 40 #include "ui/gfx/size.h"
23 #include "ui/gfx/skia_util.h" 41 #include "ui/gfx/skia_util.h"
42 #include "ui/views/border.h"
43 #include "ui/views/bubble/tray_bubble_view.h"
44 #include "ui/views/controls/button/border_images.h"
24 #include "ui/views/controls/button/button.h" 45 #include "ui/views/controls/button/button.h"
25 #include "ui/views/controls/button/text_button.h" 46 #include "ui/views/controls/button/custom_button.h"
26 #include "ui/views/controls/image_view.h" 47 #include "ui/views/controls/image_view.h"
27 #include "ui/views/controls/label.h" 48 #include "ui/views/controls/label.h"
49 #include "ui/views/controls/link.h"
50 #include "ui/views/controls/link_listener.h"
28 #include "ui/views/layout/box_layout.h" 51 #include "ui/views/layout/box_layout.h"
29 #include "ui/views/view.h" 52 #include "ui/views/view.h"
30 #include "ui/views/widget/widget.h" 53 #include "ui/views/widget/widget.h"
31 54
32 namespace { 55 namespace {
33 56
34 const int kUserInfoVerticalPadding = 10; 57 const int kUserDetailsVerticalPadding = 5;
58 const int kUserCardVerticalPadding = 10;
59 const int kProfileRoundedCornerRadius = 2;
35 const int kUserIconSize = 27; 60 const int kUserIconSize = 27;
36 const int kProfileRoundedCornerRadius = 2; 61
62 // The invisible word joiner character, used as a marker to indicate the start
63 // and end of the user's display name in the public account user card's text.
64 const char16 kDisplayNameMark[] = { 0x2060, 0 };
65
66 const int kPublicAccountLogoutButtonBorderImagesNormal[] = {
67 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
68 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
69 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
70 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
71 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
72 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
73 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
74 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
75 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
76 };
77
78 const int kPublicAccountLogoutButtonBorderImagesHovered[] = {
79 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
80 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
81 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
82 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
83 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_HOVER_BACKGROUND,
84 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
85 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
86 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
87 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
88 };
37 89
38 } // namespace 90 } // namespace
39 91
40 namespace ash { 92 namespace ash {
41 namespace internal { 93 namespace internal {
42 94
43 namespace tray { 95 namespace tray {
44 96
45 // A custom image view with rounded edges. 97 // A custom image view with rounded edges.
46 class RoundedImageView : public views::View { 98 class RoundedImageView : public views::View {
47 public: 99 public:
48 // Constructs a new rounded image view with rounded corners of radius 100 // Constructs a new rounded image view with rounded corners of radius
49 // |corner_radius|. 101 // |corner_radius|.
50 explicit RoundedImageView(int corner_radius) : corner_radius_(corner_radius) { 102 explicit RoundedImageView(int corner_radius);
51 } 103 virtual ~RoundedImageView();
52 104
53 virtual ~RoundedImageView() { 105 // Set the image that should be displayed. The image contents is copied to the
54 } 106 // receiver's image.
55 107 void SetImage(const gfx::ImageSkia& img, const gfx::Size& size);
56 // Set the image that should be displayed from a pointer. The pointer
57 // contents is copied in the receiver's image.
58 void SetImage(const gfx::ImageSkia& img, const gfx::Size& size) {
59 image_ = img;
60 image_size_ = size;
61
62 // Try to get the best image quality for the avatar.
63 resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_,
64 skia::ImageOperations::RESIZE_BEST, size);
65 if (GetWidget() && visible()) {
66 PreferredSizeChanged();
67 SchedulePaint();
68 }
69 }
70
71 // Overridden from views::View.
72 virtual gfx::Size GetPreferredSize() OVERRIDE {
73 return gfx::Size(image_size_.width() + GetInsets().width(),
74 image_size_.height() + GetInsets().height());
75 }
76
77 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
78 View::OnPaint(canvas);
79 gfx::Rect image_bounds(size());
80 image_bounds.ClampToCenteredSize(GetPreferredSize());
81 image_bounds.Inset(GetInsets());
82 const SkScalar kRadius = SkIntToScalar(corner_radius_);
83 SkPath path;
84 path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius, kRadius);
85 SkPaint paint;
86 paint.setAntiAlias(true);
87 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
88 canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(),
89 path, paint);
90 }
91 108
92 private: 109 private:
110 // Overridden from views::View.
111 virtual gfx::Size GetPreferredSize() OVERRIDE;
112 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
113
93 gfx::ImageSkia image_; 114 gfx::ImageSkia image_;
94 gfx::ImageSkia resized_; 115 gfx::ImageSkia resized_;
95 gfx::Size image_size_; 116 gfx::Size image_size_;
96 int corner_radius_; 117 int corner_radius_;
97 118
98 DISALLOW_COPY_AND_ASSIGN(RoundedImageView); 119 DISALLOW_COPY_AND_ASSIGN(RoundedImageView);
99 }; 120 };
100 121
122 // The user details shown in public account mode. This is essentially a label
123 // but with custom painting code as the text is styled with multiple colors and
124 // contains a link.
125 class PublicAccountUserDetails : public views::View,
126 public views::LinkListener {
127 public:
128 PublicAccountUserDetails(SystemTrayItem* owner, int used_width);
129 virtual ~PublicAccountUserDetails();
130
131 private:
132 // Overridden from views::View.
133 virtual void Layout() OVERRIDE;
134 virtual gfx::Size GetPreferredSize() OVERRIDE;
135 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
136
137 // Overridden from views::LinkListener.
138 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
139
140 // Calculate a preferred size that ensures the label text and the following
141 // link do not wrap over more than three lines in total for aesthetic reasons
142 // if possible.
143 void CalculatePreferredSize(SystemTrayItem* owner, int used_width);
144
145 string16 text_;
146 views::Link* learn_more_;
147 gfx::Size preferred_size_;
148 ScopedVector<gfx::RenderText> lines_;
149
150 DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails);
151 };
152
101 class UserView : public views::View, 153 class UserView : public views::View,
102 public views::ButtonListener { 154 public views::ButtonListener {
103 public: 155 public:
104 explicit UserView(ash::user::LoginStatus login) 156 explicit UserView(SystemTrayItem* owner, ash::user::LoginStatus login);
105 : login_(login), 157 virtual ~UserView();
106 user_info_(NULL),
107 username_(NULL),
108 email_(NULL),
109 signout_(NULL) {
110 CHECK(login_ != ash::user::LOGGED_IN_NONE);
111
112 bool public_account = login_ == ash::user::LOGGED_IN_PUBLIC;
113 bool guest = login_ == ash::user::LOGGED_IN_GUEST;
114 bool locked = login_ == ash::user::LOGGED_IN_LOCKED;
115
116 set_background(views::Background::CreateSolidBackground(
117 public_account ? kPublicAccountBackgroundColor : kBackgroundColor));
118
119 if (!guest)
120 AddUserInfo();
121
122 // A user should not be able to modify logged in state when screen is
123 // locked.
124 if (!locked)
125 AddButtonContainer();
126 }
127
128 virtual ~UserView() {}
129
130 // Create container for buttons.
131 void AddButtonContainer() {
132 const string16 title = ash::user::GetLocalizedSignOutStringForStatus(login_,
133 true);
134 TrayPopupLabelButton* button = new TrayPopupLabelButton(this, title);
135 button->SetAccessibleName(title);
136 AddChildView(button);
137 signout_ = button;
138 }
139 158
140 private: 159 private:
141 void AddUserInfo() { 160 // Overridden from views::View.
142 user_info_ = new views::View; 161 virtual gfx::Size GetPreferredSize() OVERRIDE;
143 user_info_->SetLayoutManager(new views::BoxLayout( 162 virtual void Layout() OVERRIDE;
144 views::BoxLayout::kHorizontal, kTrayPopupPaddingHorizontal,
145 kUserInfoVerticalPadding, kTrayPopupPaddingBetweenItems));
146 AddChildView(user_info_);
147
148 if (login_ == ash::user::LOGGED_IN_KIOSK) {
149 views::Label* label = new views::Label;
150 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
151 label->SetText(
152 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
153 label->set_border(views::Border::CreateEmptyBorder(
154 0, 4, 0, 1));
155 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
156 user_info_->AddChildView(label);
157 return;
158 }
159
160 RoundedImageView* image = new RoundedImageView(kProfileRoundedCornerRadius);
161 image->SetImage(ash::Shell::GetInstance()->tray_delegate()->GetUserImage(),
162 gfx::Size(kUserIconSize, kUserIconSize));
163 user_info_->AddChildView(image);
164
165 views::View* user = new views::View;
166 user->SetLayoutManager(new views::BoxLayout(
167 views::BoxLayout::kVertical, 0, 5, 0));
168 ash::SystemTrayDelegate* tray =
169 ash::Shell::GetInstance()->tray_delegate();
170 username_ = new views::Label(tray->GetUserDisplayName());
171 username_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
172 user->AddChildView(username_);
173
174 email_ = new views::Label(UTF8ToUTF16(tray->GetUserEmail()));
175 email_->SetFont(username_->font().DeriveFont(-1));
176 email_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
177 email_->SetEnabled(false);
178 user->AddChildView(email_);
179
180 user_info_->AddChildView(user);
181 }
182 163
183 // Overridden from views::ButtonListener. 164 // Overridden from views::ButtonListener.
184 virtual void ButtonPressed(views::Button* sender, 165 virtual void ButtonPressed(views::Button* sender,
185 const ui::Event& event) OVERRIDE { 166 const ui::Event& event) OVERRIDE;
186 CHECK(sender == signout_); 167
187 ash::SystemTrayDelegate* tray = ash::Shell::GetInstance()->tray_delegate(); 168 void AddLogoutButton(ash::user::LoginStatus login);
188 tray->SignOut(); 169 void AddUserCard(SystemTrayItem* owner, ash::user::LoginStatus login);
189 } 170
190 171 views::View* user_card_;
191 // Overridden from views::View. 172 views::View* logout_button_;
192 virtual gfx::Size GetPreferredSize() OVERRIDE {
193 gfx::Size size;
194 if (user_info_)
195 size = user_info_->GetPreferredSize();
196 if (signout_) {
197 gfx::Size signout_size = signout_->GetPreferredSize();
198 // Make sure the user default view item at least as tall as the other
199 // tray popup items.
200 if (size.height() == 0)
201 size.set_height(kTrayPopupItemHeight);
202 size.set_height(std::max(size.height(), signout_size.height()));
203 size.set_width(size.width() + signout_size.width() +
204 kTrayPopupPaddingHorizontal * 2 + kTrayPopupPaddingBetweenItems);
205 }
206 return size;
207 }
208
209 virtual void Layout() OVERRIDE {
210 views::View::Layout();
211 if (bounds().IsEmpty())
212 return;
213
214 if (signout_ && user_info_) {
215 gfx::Rect signout_bounds(bounds());
216 signout_bounds.ClampToCenteredSize(signout_->GetPreferredSize());
217 signout_bounds.set_x(width() - signout_bounds.width() -
218 kTrayPopupPaddingHorizontal);
219 signout_->SetBoundsRect(signout_bounds);
220
221 gfx::Rect usercard_bounds(user_info_->GetPreferredSize());
222 usercard_bounds.set_width(signout_bounds.x());
223 user_info_->SetBoundsRect(usercard_bounds);
224 } else if (signout_) {
225 signout_->SetBoundsRect(gfx::Rect(size()));
226 } else if (user_info_) {
227 user_info_->SetBoundsRect(gfx::Rect(size()));
228 }
229 }
230
231 user::LoginStatus login_;
232
233 views::View* user_info_;
234 views::Label* username_;
235 views::Label* email_;
236
237 views::Button* signout_;
238 173
239 DISALLOW_COPY_AND_ASSIGN(UserView); 174 DISALLOW_COPY_AND_ASSIGN(UserView);
240 }; 175 };
241 176
177 RoundedImageView::RoundedImageView(int corner_radius)
178 : corner_radius_(corner_radius) {}
179
180 RoundedImageView::~RoundedImageView() {}
181
182 void RoundedImageView::SetImage(const gfx::ImageSkia& img,
183 const gfx::Size& size) {
184 image_ = img;
185 image_size_ = size;
186
187 // Try to get the best image quality for the avatar.
188 resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_,
189 skia::ImageOperations::RESIZE_BEST, size);
190 if (GetWidget() && visible()) {
191 PreferredSizeChanged();
192 SchedulePaint();
193 }
194 }
195
196 gfx::Size RoundedImageView::GetPreferredSize() {
197 return gfx::Size(image_size_.width() + GetInsets().width(),
198 image_size_.height() + GetInsets().height());
199 }
200
201 void RoundedImageView::OnPaint(gfx::Canvas* canvas) {
202 View::OnPaint(canvas);
203 gfx::Rect image_bounds(size());
204 image_bounds.ClampToCenteredSize(GetPreferredSize());
205 image_bounds.Inset(GetInsets());
206 const SkScalar kRadius = SkIntToScalar(corner_radius_);
207 SkPath path;
208 path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius, kRadius);
209 SkPaint paint;
210 paint.setAntiAlias(true);
211 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
212 canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(),
213 path, paint);
214 }
215
216 PublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner,
217 int used_width)
218 : learn_more_(NULL) {
219 const int inner_padding =
220 kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems;
221 const bool rtl = base::i18n::IsRTL();
222 set_border(views::Border::CreateEmptyBorder(
223 kUserDetailsVerticalPadding, rtl ? 0 : inner_padding,
224 kUserDetailsVerticalPadding, rtl ? inner_padding : 0));
225
226 ash::SystemTrayDelegate* delegate =
227 ash::Shell::GetInstance()->tray_delegate();
228 // Retrieve the user's display name and wrap it with markers.
229 string16 display_name = delegate->GetUserDisplayName();
230 RemoveChars(display_name, kDisplayNameMark, &display_name);
231 display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0];
232 // Retrieve the domain managing the device and wrap it with markers.
233 string16 domain = UTF8ToUTF16(delegate->GetEnterpriseDomain());
234 RemoveChars(domain, kDisplayNameMark, &domain);
235 base::i18n::WrapStringWithLTRFormatting(&domain);
236 // Retrieve the label text, inserting the display name and domain.
237 text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL,
238 display_name, domain);
239
240 learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE));
241 learn_more_->SetUnderline(false);
242 learn_more_->set_listener(this);
243 AddChildView(learn_more_);
244
245 CalculatePreferredSize(owner, used_width);
246 }
247
248 PublicAccountUserDetails::~PublicAccountUserDetails() {}
249
250 void PublicAccountUserDetails::Layout() {
251 lines_.clear();
252 const gfx::Rect contents_area = GetContentsBounds();
253 if (contents_area.IsEmpty())
254 return;
255
256 // Word-wrap the label text.
257 const gfx::Font font;
258 std::vector<string16> lines;
259 ui::ElideRectangleText(text_, font, contents_area.width(),
260 contents_area.height(), ui::ELIDE_LONG_WORDS, &lines);
261 // Loop through the lines, creating a renderer for each.
262 gfx::Point position = contents_area.origin();
263 ui::Range display_name(ui::Range::InvalidRange());
264 for (std::vector<string16>::const_iterator it = lines.begin();
265 it != lines.end(); ++it) {
266 gfx::RenderText* line = gfx::RenderText::CreateInstance();
267 line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI);
268 line->SetText(*it);
269 const gfx::Size size(contents_area.width(), line->GetStringSize().height());
270 line->SetDisplayRect(gfx::Rect(position, size));
271 position.set_y(position.y() + size.height());
272
273 // Set the default text color for the line.
274 gfx::StyleRange default_style(line->default_style());
275 default_style.foreground = kPublicAccountUserCardTextColor;
276 line->set_default_style(default_style);
277 line->ApplyDefaultStyle();
278
279 // If a range of the line contains the user's display name, apply a custom
280 // text color to it.
281 if (display_name.is_empty())
282 display_name.set_start(it->find(kDisplayNameMark));
283 if (!display_name.is_empty()) {
284 display_name.set_end(
285 it->find(kDisplayNameMark, display_name.start() + 1));
286 gfx::StyleRange display_name_style(line->default_style());
287 display_name_style.foreground = kPublicAccountUserCardNameColor;
288 ui::Range line_range(0, it->size());
289 display_name_style.range = display_name.Intersect(line_range);
290 line->ApplyStyleRange(display_name_style);
291 // Update the range for the next line.
292 if (display_name.end() >= line_range.end())
293 display_name.set_start(0);
294 else
295 display_name = ui::Range::InvalidRange();
296 }
297
298 lines_.push_back(line);
299 }
300
301 // Position the link after the label text, separated by a space. If it does
302 // not fit onto the last line of the text, wrap the link onto its own line.
303 const gfx::Size last_line_size = lines_.back()->GetStringSize();
304 const int space_width = font.GetStringWidth(ASCIIToUTF16(" "));
305 const gfx::Size link_size = learn_more_->GetPreferredSize();
306 if (contents_area.width() - last_line_size.width() >=
307 space_width + link_size.width()) {
308 position.set_x(position.x() + last_line_size.width() + space_width);
309 position.set_y(position.y() - last_line_size.height());
310 }
311 position.set_y(position.y() - learn_more_->GetInsets().top());
312 gfx::Rect learn_more_bounds(position, link_size);
313 learn_more_bounds.Intersect(contents_area);
314 if (base::i18n::IsRTL()) {
315 const gfx::Insets insets = GetInsets();
316 learn_more_bounds.Offset(insets.right() - insets.left(), 0);
317 }
318 learn_more_->SetBoundsRect(learn_more_bounds);
319 }
320
321 gfx::Size PublicAccountUserDetails::GetPreferredSize() {
322 return preferred_size_;
323 }
324
325 void PublicAccountUserDetails::OnPaint(gfx::Canvas* canvas) {
326 for (ScopedVector<gfx::RenderText>::const_iterator it = lines_.begin();
327 it != lines_.end(); ++it) {
328 (*it)->Draw(canvas);
329 }
330 views::View::OnPaint(canvas);
331 }
332
333 void PublicAccountUserDetails::LinkClicked(views::Link* source,
334 int event_flags) {
335 DCHECK_EQ(source, learn_more_);
336 ash::Shell::GetInstance()->tray_delegate()->ShowPublicAccountInfo();
337 }
338
339 void PublicAccountUserDetails::CalculatePreferredSize(SystemTrayItem* owner,
340 int used_width) {
341 const gfx::Font font;
342 const gfx::Size link_size = learn_more_->GetPreferredSize();
343 const int space_width = font.GetStringWidth(ASCIIToUTF16(" "));
344 const gfx::Insets insets = GetInsets();
345 views::TrayBubbleView* bubble_view =
346 owner->system_tray()->GetSystemBubble()->bubble_view();
347 int min_width = std::max(
348 link_size.width(),
349 bubble_view->GetPreferredSize().width() - (used_width + insets.width()));
350 int max_width = std::min(
351 font.GetStringWidth(text_) + space_width + link_size.width(),
352 bubble_view->GetMaximumSize().width() - (used_width + insets.width()));
353 // Do a binary search for the minimum width that ensures no more than three
354 // lines are needed. The lower bound is the minimum of the current bubble
355 // width and the width of the link (as no wrapping is permitted inside the
356 // link). The upper bound is the maximum of the largest allowed bubble width
357 // and the sum of the label text and link widths when put on a single line.
358 std::vector<string16> lines;
359 while (min_width < max_width) {
360 lines.clear();
361 const int width = (min_width + max_width) / 2;
362 const bool too_narrow = ui::ElideRectangleText(
363 text_, font, width, INT_MAX, ui::TRUNCATE_LONG_WORDS, &lines) != 0;
364 int line_count = lines.size();
365 if (!too_narrow && line_count == 3 &&
366 width - font.GetStringWidth(lines.back()) <=
367 space_width + link_size.width()) {
368 ++line_count;
369 }
370 if (too_narrow || line_count > 3)
371 min_width = width + 1;
372 else
373 max_width = width;
374 }
375
376 // Calculate the corresponding height and set the preferred size.
377 lines.clear();
378 ui::ElideRectangleText(
379 text_, font, min_width, INT_MAX, ui::TRUNCATE_LONG_WORDS, &lines);
380 int line_count = lines.size();
381 if (min_width - font.GetStringWidth(lines.back()) <=
382 space_width + link_size.width()) {
383 ++line_count;
384 }
385 const int line_height = font.GetHeight();
386 const int link_extra_height = std::max(
387 link_size.height() - learn_more_->GetInsets().top() - line_height, 0);
388 preferred_size_ = gfx::Size(
389 min_width + insets.width(),
390 line_count * line_height + link_extra_height + insets.height());
391
392 bubble_view->SetWidth(preferred_size_.width() + used_width);
393 }
394
395 UserView::UserView(SystemTrayItem* owner, ash::user::LoginStatus login)
396 : user_card_(NULL),
397 logout_button_(NULL) {
398 CHECK_NE(ash::user::LOGGED_IN_NONE, login);
399 set_background(views::Background::CreateSolidBackground(
400 login == ash::user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor :
401 kBackgroundColor));
402 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
403 kTrayPopupPaddingBetweenItems));
404 // The logout button must be added before the user card so that the user card
405 // can correctly calculate the remaining available width.
406 AddLogoutButton(login);
407 AddUserCard(owner, login);
408 }
409
410 UserView::~UserView() {}
411
412 gfx::Size UserView::GetPreferredSize() {
413 gfx::Size size = views::View::GetPreferredSize();
414 if (!user_card_) {
415 // Make sure the default user view item is at least as tall as the other
416 // items.
417 size.set_height(std::max(size.height(),
418 kTrayPopupItemHeight + GetInsets().height()));
419 }
420 return size;
421 }
422
423 void UserView::Layout() {
424 gfx::Rect contents_area(GetContentsBounds());
425 if (user_card_ && logout_button_) {
426 // Give the logout button the space it requests.
427 gfx::Rect logout_area = contents_area;
428 logout_area.ClampToCenteredSize(logout_button_->GetPreferredSize());
429 logout_area.set_x(contents_area.right() - logout_area.width());
430 logout_button_->SetBoundsRect(logout_area);
431
432 // Give the remaining space to the user card.
433 gfx::Rect user_card_area = contents_area;
434 user_card_area.set_width(contents_area.width() -
435 (logout_area.width() + kTrayPopupPaddingBetweenItems));
436 user_card_->SetBoundsRect(user_card_area);
437 } else if (user_card_) {
438 user_card_->SetBoundsRect(contents_area);
439 } else if (logout_button_) {
440 logout_button_->SetBoundsRect(contents_area);
441 }
442 }
443
444 void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
445 DCHECK_EQ(logout_button_, sender);
446 ash::Shell::GetInstance()->tray_delegate()->SignOut();
447 }
448
449 void UserView::AddLogoutButton(ash::user::LoginStatus login) {
450 // A user should not be able to modify logged-in state when screen is
451 // locked.
452 if (login == ash::user::LOGGED_IN_LOCKED)
453 return;
454
455 const string16 title = ash::user::GetLocalizedSignOutStringForStatus(login,
456 true);
457 TrayPopupLabelButton* logout_button = new TrayPopupLabelButton(this, title);
458 logout_button->SetAccessibleName(title);
459 logout_button_ = logout_button;
460 // In public account mode, the logout button border has a custom color.
461 if (login == ash::user::LOGGED_IN_PUBLIC) {
462 TrayPopupLabelButtonBorder* border =
463 static_cast<TrayPopupLabelButtonBorder*>(logout_button_->border());
464 border->SetImages(views::CustomButton::STATE_NORMAL, views::BorderImages(
465 kPublicAccountLogoutButtonBorderImagesNormal));
466 border->SetImages(views::CustomButton::STATE_HOVERED, views::BorderImages(
467 kPublicAccountLogoutButtonBorderImagesHovered));
468 border->SetImages(views::CustomButton::STATE_PRESSED, views::BorderImages(
469 kPublicAccountLogoutButtonBorderImagesHovered));
470 }
471 AddChildView(logout_button_);
472 }
473
474 void UserView::AddUserCard(SystemTrayItem* owner,
475 ash::user::LoginStatus login) {
476 if (login == ash::user::LOGGED_IN_GUEST)
477 return;
478
479 set_border(views::Border::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal,
480 0, kTrayPopupPaddingHorizontal));
481
482 user_card_ = new views::View();
483 user_card_->SetLayoutManager(new views::BoxLayout(
484 views::BoxLayout::kHorizontal, 0, kUserCardVerticalPadding,
485 kTrayPopupPaddingBetweenItems));
486 AddChildViewAt(user_card_, 0);
487
488 if (login == ash::user::LOGGED_IN_KIOSK) {
489 views::Label* details = new views::Label;
490 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
491 details->SetText(
492 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
493 details->set_border(views::Border::CreateEmptyBorder(0, 4, 0, 1));
494 details->SetHorizontalAlignment(gfx::ALIGN_LEFT);
495 user_card_->AddChildView(details);
496 return;
497 }
498
499 RoundedImageView* avatar = new RoundedImageView(kProfileRoundedCornerRadius);
500 avatar->SetImage(ash::Shell::GetInstance()->tray_delegate()->GetUserImage(),
501 gfx::Size(kUserIconSize, kUserIconSize));
502 user_card_->AddChildView(avatar);
503
504 if (login == ash::user::LOGGED_IN_PUBLIC) {
505 user_card_->AddChildView(new PublicAccountUserDetails(
506 owner, GetPreferredSize().width() + kTrayPopupPaddingBetweenItems));
507 return;
508 }
509
510 ash::SystemTrayDelegate* delegate =
511 ash::Shell::GetInstance()->tray_delegate();
512 views::View* details = new views::View;
513 details->SetLayoutManager(new views::BoxLayout(
514 views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0));
515 views::Label* username = new views::Label(delegate->GetUserDisplayName());
516 username->SetHorizontalAlignment(gfx::ALIGN_LEFT);
517 details->AddChildView(username);
518
519 views::Label* email = new views::Label(UTF8ToUTF16(delegate->GetUserEmail()));
520 email->SetFont(username->font().DeriveFont(-1));
521 email->SetHorizontalAlignment(gfx::ALIGN_LEFT);
522 email->SetEnabled(false);
523 details->AddChildView(email);
524 user_card_->AddChildView(details);
525 }
526
242 } // namespace tray 527 } // namespace tray
243 528
244 TrayUser::TrayUser(SystemTray* system_tray) 529 TrayUser::TrayUser(SystemTray* system_tray)
245 : SystemTrayItem(system_tray), 530 : SystemTrayItem(system_tray),
246 user_(NULL), 531 user_(NULL),
247 avatar_(NULL), 532 avatar_(NULL),
248 label_(NULL) { 533 label_(NULL) {
249 } 534 }
250 535
251 TrayUser::~TrayUser() { 536 TrayUser::~TrayUser() {
(...skipping 13 matching lines...) Expand all
265 UpdateAfterLoginStatusChange(status); 550 UpdateAfterLoginStatusChange(status);
266 return avatar_ ? static_cast<views::View*>(avatar_) 551 return avatar_ ? static_cast<views::View*>(avatar_)
267 : static_cast<views::View*>(label_); 552 : static_cast<views::View*>(label_);
268 } 553 }
269 554
270 views::View* TrayUser::CreateDefaultView(user::LoginStatus status) { 555 views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
271 if (status == user::LOGGED_IN_NONE) 556 if (status == user::LOGGED_IN_NONE)
272 return NULL; 557 return NULL;
273 558
274 CHECK(user_ == NULL); 559 CHECK(user_ == NULL);
275 user_ = new tray::UserView(status); 560 user_ = new tray::UserView(this, status);
276 return user_; 561 return user_;
277 } 562 }
278 563
279 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) { 564 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) {
280 return NULL; 565 return NULL;
281 } 566 }
282 567
283 void TrayUser::DestroyTrayView() { 568 void TrayUser::DestroyTrayView() {
284 avatar_ = NULL; 569 avatar_ = NULL;
285 label_ = NULL; 570 label_ = NULL;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 // Check for null to avoid crbug.com/150944. 628 // Check for null to avoid crbug.com/150944.
344 if (avatar_) { 629 if (avatar_) {
345 avatar_->SetImage( 630 avatar_->SetImage(
346 ash::Shell::GetInstance()->tray_delegate()->GetUserImage(), 631 ash::Shell::GetInstance()->tray_delegate()->GetUserImage(),
347 gfx::Size(kUserIconSize, kUserIconSize)); 632 gfx::Size(kUserIconSize, kUserIconSize));
348 } 633 }
349 } 634 }
350 635
351 } // namespace internal 636 } // namespace internal
352 } // namespace ash 637 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/user/tray_user.h ('k') | chrome/browser/chromeos/system/ash_system_tray_delegate.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698