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

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