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

Unified 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: 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 side-by-side diff with in-line comments
Download patch
Index: ash/system/user/tray_user.cc
diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc
index 6b1ab2e349a59cb20e4264a4a9b7465347b77c09..dd297c1e30f5d1f75e187e9399655eb2e421b277 100644
--- a/ash/system/user/tray_user.cc
+++ b/ash/system/user/tray_user.cc
@@ -13,19 +13,27 @@
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_item_view.h"
#include "ash/system/tray/tray_views.h"
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "grit/ash_strings.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/native_theme/native_theme.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/text/text_elider.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/insets.h"
+#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/border.h"
@@ -33,15 +41,27 @@
#include "ui/views/controls/button/text_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
+#include "ui/views/controls/link.h"
+#include "ui/views/controls/link_listener.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
+#include "ui/views/view_text_utils.h"
#include "ui/views/widget/widget.h"
namespace {
-const int kUserInfoVerticalPadding = 10;
-const int kUserIconSize = 27;
+const int kUserDetailsVerticalPadding = 5;
+const int kUserCardVerticalPadding = 10;
const int kProfileRoundedCornerRadius = 2;
+const int kUserIconSize = 27;
+
+string16 kDisplayName() {
+ return ASCIIToUTF16("DISPLAY_NAME");
+}
+
+string16 kDomain() {
+ return ASCIIToUTF16("DOMAIN");
+}
} // namespace
@@ -106,6 +126,261 @@ class RoundedImageView : public views::View {
DISALLOW_COPY_AND_ASSIGN(RoundedImageView);
};
+// A chunk of text with associated color.
+class TextChunk {
+ public:
+ TextChunk(const string16& text, const SkColor& color, bool is_url)
+ : text_(text), color_(color), is_url_(is_url) {}
+
+ const string16& Text() const { return text_; }
+ const SkColor& Color() const { return color_; }
+ bool IsUrl() const { return is_url_; }
+
+ private:
+ string16 text_;
+ SkColor color_;
+ bool is_url_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextChunk);
+};
+
+// The user details shown in public account mode. This is essentially a label
+// but with custom painting code as the text is styled with multiple colors and
+// contains a link.
+class PublicAccountUserDetails : public views::View,
+ public views::LinkListener {
+ public:
+ PublicAccountUserDetails() : learn_more_(NULL) {
+ set_border(views::Border::CreateEmptyBorder(
+ kUserDetailsVerticalPadding, 0, kUserDetailsVerticalPadding, 0));
+ const string16 text =
+ l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL);
+ const size_t display_name_start = text.find(kDisplayName());
+ DCHECK(display_name_start != string16::npos);
+ const size_t domain_start = text.find(kDomain());
+ DCHECK(domain_start != string16::npos);
+ const size_t display_name_end = display_name_start +
+ kDisplayName().size();
+ const size_t domain_end = domain_start + kDomain().size();
+ bool display_name_first = display_name_start < domain_start;
+
+ SkColor default_color = GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_LabelEnabledColor);
+ ash::SystemTrayDelegate* tray = ash::Shell::GetInstance()->tray_delegate();
+ TextChunk* display_name = new TextChunk(tray->GetUserDisplayName(),
+ default_color, false);
+ TextChunk *domain = new TextChunk(UTF8ToUTF16(tray->GetEnterpriseDomain()),
+ kPublicAccountUserCardTextColor, true);
+ const size_t chunk_1_end = std::min(display_name_start, domain_start);
+ chunks_.push_back(new TextChunk(text.substr(0, chunk_1_end),
+ kPublicAccountUserCardTextColor, false));
+ chunks_.push_back(display_name_first ? display_name : domain);
+ const size_t chunk_2_start = std::min(display_name_end, domain_end);
+ const size_t chunk_2_end = std::max(display_name_start, domain_start);
+ chunks_.push_back(new TextChunk(text.substr(chunk_2_start,
+ chunk_2_end - chunk_2_start),
+ kPublicAccountUserCardTextColor, false));
+ chunks_.push_back(display_name_first ? domain : display_name);
+ const size_t chunk_3_start = std::max(display_name_end, domain_end);
+ chunks_.push_back(new TextChunk(text.substr(chunk_3_start),
+ kPublicAccountUserCardTextColor, false));
stevenjb 2012/11/13 20:54:22 This seems like something that ought to be general
bartfab (slow) 2012/11/16 19:59:15 Done.
+ chunks_.push_back(new TextChunk(ASCIIToUTF16(" "),
+ kPublicAccountUserCardTextColor, false));
stevenjb 2012/11/13 20:54:22 This bit seems strange to me. Is this the spacing
bartfab (slow) 2012/11/16 19:59:15 Done.
+
+ learn_more_ = new views::Link(
+ l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LEARN_MORE));
+ learn_more_->set_listener(this);
+ AddChildView(learn_more_);
+ }
+
+ // Overridden from views::LinkListener.
+ virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE {
+ DCHECK_EQ(source, learn_more_);
+ ash::Shell::GetInstance()->tray_delegate()->ShowPublicAccountInfo();
+ }
+
+ // Overridden from views::View.
+ void Layout() OVERRIDE {
+ learn_more_->SetBoundsRect(PaintTextAndCalculateLinkRect(
+ NULL, GetContentsBounds()));
+ }
+
+ virtual gfx::Size GetPreferredSize() OVERRIDE {
+ if (!visible())
+ return gfx::Size();
+ const gfx::Insets insets = GetInsets();
+ const gfx::Rect link_rect = PaintTextAndCalculateLinkRect(
+ NULL, gfx::Rect(INT_MAX, INT_MAX));
+ return gfx::Size(link_rect.right() + insets.width(),
+ link_rect.bottom() + insets.height());
+ }
+
+ virtual int GetHeightForWidth(int w) OVERRIDE {
+ if (!visible())
+ return 0;
+ const gfx::Insets insets = GetInsets();
+ const gfx::Rect link_rect = PaintTextAndCalculateLinkRect(
+ NULL, gfx::Rect(w - insets.width(), INT_MAX));
+ return link_rect.bottom() + GetInsets().height();
+ }
+
+ private:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
+ views::View::OnPaint(canvas);
+ PaintTextAndCalculateLinkRect(canvas, GetContentsBounds());
+ }
+
+ gfx::Rect PaintTextAndCalculateLinkRect(gfx::Canvas* canvas,
+ const gfx::Rect& content_area) {
+ gfx::Size position;
+ const bool text_direction_is_rtl = base::i18n::IsRTL();
+ const gfx::Font& font = label_.font();
+ label_.SetBoundsRect(content_area);
+ for (ScopedVector<TextChunk>::const_iterator it = chunks_.begin();
+ it != chunks_.end(); ++it) {
+ label_.SetEnabledColor((*it)->Color());
+ string16 text;
+ if ((*it)->IsUrl()) {
+ text = ui::ElideText((*it)->Text(), font, content_area.width(),
+ ui::ELIDE_IN_MIDDLE);
+ base::i18n::WrapStringWithLTRFormatting(&text);
+ } else {
+ text = (*it)->Text();
+ }
+ view_text_utils::DrawTextAndPositionUrl(
+ canvas, &label_, text, NULL, NULL, &position, text_direction_is_rtl,
+ content_area, font);
+ }
stevenjb 2012/11/13 20:54:22 So, I don't want to overcomplicate this CL too muc
bartfab (slow) 2012/11/16 19:59:15 I went for the bonus points: I replaced the views_
+ gfx::Rect link_rect;
+ view_text_utils::DrawTextAndPositionUrl(
+ canvas, &label_, string16(), learn_more_, &link_rect, &position,
+ text_direction_is_rtl, content_area, font);
+ // The link is separated from the text by a single space. If the link was
+ // wrapped onto a new line, remove the preceding space as it is not needed
+ // in this case.
+ const int space_width =
+ gfx::Canvas::GetStringWidth(ASCIIToUTF16(" "), font);
+ if (link_rect.x() == content_area.x() + space_width)
+ link_rect.Offset(-space_width, 0);
+ return link_rect;
+ }
+
+ ScopedVector<TextChunk> chunks_;
+ views::Label label_;
+ views::Link* learn_more_;
+
+ DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails);
+};
+
+// The user card, consisting of an avatar picture (except in retail mode) and
+// user details.
+class UserCard : public views::View {
+ public:
+ explicit UserCard(ash::user::LoginStatus login)
+ : avatar_(NULL), details_(NULL) {
+ set_border(views::Border::CreateEmptyBorder(kUserCardVerticalPadding, 0,
+ kUserCardVerticalPadding, 0));
+ if (login == ash::user::LOGGED_IN_KIOSK) {
+ views::Label* details = new views::Label;
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ details->SetText(
+ bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
+ details->set_border(views::Border::CreateEmptyBorder(0, 4, 0, 1));
+ details->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ AddChildView(details);
+ details_ = details;
+ return;
+ }
+
+ avatar_ = new RoundedImageView(kProfileRoundedCornerRadius);
+ avatar_->SetImage(
+ ash::Shell::GetInstance()->tray_delegate()->GetUserImage(),
+ gfx::Size(kUserIconSize, kUserIconSize));
+ AddChildView(avatar_);
+
+ if (login == ash::user::LOGGED_IN_PUBLIC) {
+ details_ = new PublicAccountUserDetails();
+ AddChildView(details_);
+ return;
+ }
+
+ ash::SystemTrayDelegate* tray = ash::Shell::GetInstance()->tray_delegate();
+ views::View* details = new views::View;
+ details->SetLayoutManager(new views::BoxLayout(
+ views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0));
+ views::Label* username = new views::Label(tray->GetUserDisplayName());
+ username->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ details->AddChildView(username);
+
+ views::Label* email = new views::Label(UTF8ToUTF16(tray->GetUserEmail()));
+ email->SetFont(username->font().DeriveFont(-1));
+ email->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ email->SetEnabled(false);
+ details->AddChildView(email);
+ AddChildView(details);
+ details_ = details;
+ }
+
+ // Overridden from views::View.
+ virtual gfx::Size GetPreferredSize() OVERRIDE {
+ gfx::Size size;
+ if (!visible())
+ return size;
+ if (avatar_)
+ size = avatar_->GetPreferredSize();
+ if (details_) {
+ gfx::Size details_size = details_->GetPreferredSize();
+ size.set_height(std::max(size.height(), details_size.height()));
+ size.Enlarge(details_size.width(), 0);
+ }
+ if (avatar_ && details_)
+ size.Enlarge(kTrayPopupPaddingBetweenItems, 0);
+ gfx::Insets insets = GetInsets();
+ size.Enlarge(insets.width(), insets.height());
+ return size;
+ }
+
+ virtual int GetHeightForWidth(int w) OVERRIDE {
+ if (!visible())
+ return 0;
+ gfx::Insets insets = GetInsets();
+ int width = w - insets.width();
+ int height = 0;
+ if (avatar_) {
+ gfx::Size avatar_size = avatar_->GetPreferredSize();
+ width -= avatar_size.width();
+ height = avatar_size.height();
+ }
+ if (avatar_ && details_)
+ width -= kTrayPopupPaddingBetweenItems;
+ if (details_)
+ height = std::max(height, details_->GetHeightForWidth(width));
+ return height + insets.height();
+ }
+
+ virtual void Layout() OVERRIDE {
+ gfx::Rect contents_area(GetContentsBounds());
+ gfx::Point top_left = contents_area.origin();
+ if (avatar_) {
+ const int avatar_width = avatar_->GetPreferredSize().width();
+ gfx::Rect avatar_area = contents_area;
+ avatar_area.set_width(avatar_width);
+ avatar_->SetBoundsRect(avatar_area);
+ contents_area.Inset(avatar_width, 0, 0, 0);
+ }
+ if (avatar_ && details_)
+ contents_area.Inset(kTrayPopupPaddingBetweenItems, 0, 0, 0);
+ if (details_)
+ details_->SetBoundsRect(contents_area);
+ }
+
+ private:
+ RoundedImageView* avatar_;
+ views::View* details_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserCard);
+};
+
// A custom tray popup text button that can be queried for its preferred width
// with a given upper limit, allowing the button's width to be reduced when
// space is tight while guaranteeing that its content is wrapped and displayed
@@ -181,7 +456,7 @@ class UserView : public views::View,
set_background(views::Background::CreateSolidBackground(
login == ash::user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor :
kBackgroundColor));
- AddUserInfo(login);
+ AddUserCard(login);
AddLogoutButton(login);
}
@@ -257,52 +532,16 @@ class UserView : public views::View,
}
private:
- void AddUserInfo(ash::user::LoginStatus login) {
+ void AddUserCard(ash::user::LoginStatus login) {
if (login == ash::user::LOGGED_IN_GUEST)
return;
set_border(views::Border::CreateEmptyBorder(
0, kTrayPopupPaddingHorizontal, 0, kTrayPopupPaddingHorizontal));
- user_card_ = new views::View;
- user_card_->SetLayoutManager(new views::BoxLayout(
- views::BoxLayout::kHorizontal, 0,
- kUserInfoVerticalPadding, kTrayPopupPaddingBetweenItems));
+ user_card_ = new UserCard(login);
AddChildView(user_card_);
-
- if (login == ash::user::LOGGED_IN_KIOSK) {
- views::Label* label = new views::Label;
- ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
- label->SetText(
- bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
- label->set_border(views::Border::CreateEmptyBorder(
- 0, 4, 0, 1));
- label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- user_card_->AddChildView(label);
- return;
- }
-
- RoundedImageView* image = new RoundedImageView(kProfileRoundedCornerRadius);
- image->SetImage(ash::Shell::GetInstance()->tray_delegate()->GetUserImage(),
- gfx::Size(kUserIconSize, kUserIconSize));
- user_card_->AddChildView(image);
-
- views::View* user = new views::View;
- user->SetLayoutManager(new views::BoxLayout(
- views::BoxLayout::kVertical, 0, 5, 0));
- ash::SystemTrayDelegate* tray =
- ash::Shell::GetInstance()->tray_delegate();
- views::Label* username = new views::Label(tray->GetUserDisplayName());
- username->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- user->AddChildView(username);
-
- views::Label* email = new views::Label(UTF8ToUTF16(tray->GetUserEmail()));
- email->SetFont(username->font().DeriveFont(-1));
- email->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- email->SetEnabled(false);
- user->AddChildView(email);
-
- user_card_->AddChildView(user);
+ return;
}
void AddLogoutButton(ash::user::LoginStatus login) {

Powered by Google App Engine
This is Rietveld 408576698