Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / profiles / new_avatar_button.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/views/profiles/new_avatar_button.h"
6
7 #include "base/win/windows_version.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/profiles/profile_manager.h"
10 #include "chrome/browser/profiles/profiles_state.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
13 #include "grit/theme_resources.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/views/border.h"
17 #include "ui/views/controls/button/label_button_border.h"
18 #include "ui/views/painter.h"
19
20 namespace {
21
22 scoped_ptr<views::Border> CreateBorder(const int normal_image_set[],
23                                        const int hot_image_set[],
24                                        const int pushed_image_set[]) {
25   scoped_ptr<views::LabelButtonBorder> border(
26       new views::LabelButtonBorder(views::Button::STYLE_TEXTBUTTON));
27   border->SetPainter(false, views::Button::STATE_NORMAL,
28       views::Painter::CreateImageGridPainter(normal_image_set));
29   border->SetPainter(false, views::Button::STATE_HOVERED,
30       views::Painter::CreateImageGridPainter(hot_image_set));
31   border->SetPainter(false, views::Button::STATE_PRESSED,
32       views::Painter::CreateImageGridPainter(pushed_image_set));
33
34   const int kLeftRightInset = 8;
35   const int kTopInset = 2;
36   const int kBottomInset = 4;
37   border->set_insets(gfx::Insets(kTopInset, kLeftRightInset,
38                                  kBottomInset, kLeftRightInset));
39
40   return border.Pass();
41 }
42
43 }  // namespace
44
45 NewAvatarButton::NewAvatarButton(views::ButtonListener* listener,
46                                  AvatarButtonStyle button_style,
47                                  Browser* browser)
48     : LabelButton(listener, base::string16()),
49       browser_(browser),
50       has_auth_error_(false),
51       suppress_mouse_released_action_(false) {
52   set_animate_on_state_change(false);
53   SetTextColor(views::Button::STATE_NORMAL, SK_ColorWHITE);
54   SetTextColor(views::Button::STATE_HOVERED, SK_ColorWHITE);
55   SetTextColor(views::Button::STATE_PRESSED, SK_ColorWHITE);
56   SetTextSubpixelRenderingEnabled(false);
57   SetHorizontalAlignment(gfx::ALIGN_CENTER);
58
59   // The largest text height that fits in the button. If the font list height
60   // is larger than this, it will be shrunk to match it.
61   // TODO(noms): Calculate this constant algorithmically.
62   const int kDisplayFontHeight = 15;
63   SetFontList(GetFontList().DeriveWithHeightUpperBound(kDisplayFontHeight));
64
65   ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
66   if (button_style == THEMED_BUTTON) {
67     const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_NORMAL);
68     const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_HOVER);
69     const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_PRESSED);
70
71     SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
72     generic_avatar_ =
73         *rb->GetImageNamed(IDR_AVATAR_THEMED_BUTTON_AVATAR).ToImageSkia();
74 #if defined(OS_WIN)
75   } else if (base::win::GetVersion() >= base::win::VERSION_WIN8 ||
76              browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) {
77     const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_NORMAL);
78     const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_HOVER);
79     const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_PRESSED);
80
81     SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
82     generic_avatar_ =
83         *rb->GetImageNamed(IDR_AVATAR_METRO_BUTTON_AVATAR).ToImageSkia();
84 #endif
85   } else {
86     const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_NORMAL);
87     const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_HOVER);
88     const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_PRESSED);
89
90     SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
91     generic_avatar_ =
92         *rb->GetImageNamed(IDR_AVATAR_GLASS_BUTTON_AVATAR).ToImageSkia();
93   }
94
95   g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this);
96
97   // Subscribe to authentication error changes so that the avatar button can
98   // update itself.  Note that guest mode profiles won't have a token service.
99   SigninErrorController* error =
100       profiles::GetSigninErrorController(browser_->profile());
101   if (error) {
102     error->AddObserver(this);
103     // This calls UpdateAvatarButtonAndRelayoutParent().
104     OnErrorChanged();
105   } else {
106     UpdateAvatarButtonAndRelayoutParent();
107   }
108   SchedulePaint();
109 }
110
111 NewAvatarButton::~NewAvatarButton() {
112   g_browser_process->profile_manager()->
113       GetProfileInfoCache().RemoveObserver(this);
114   SigninErrorController* error =
115       profiles::GetSigninErrorController(browser_->profile());
116   if (error)
117     error->RemoveObserver(this);
118 }
119
120 bool NewAvatarButton::OnMousePressed(const ui::MouseEvent& event) {
121   // Prevent the bubble from being re-shown if it's already showing.
122   suppress_mouse_released_action_ = ProfileChooserView::IsShowing();
123   return LabelButton::OnMousePressed(event);
124 }
125
126 void NewAvatarButton::OnMouseReleased(const ui::MouseEvent& event) {
127   if (suppress_mouse_released_action_)
128     suppress_mouse_released_action_ = false;
129   else
130     LabelButton::OnMouseReleased(event);
131 }
132
133 void NewAvatarButton::OnProfileAdded(const base::FilePath& profile_path) {
134   UpdateAvatarButtonAndRelayoutParent();
135 }
136
137 void NewAvatarButton::OnProfileWasRemoved(
138       const base::FilePath& profile_path,
139       const base::string16& profile_name) {
140   // If deleting the active profile, don't bother updating the avatar
141   // button, as the browser window is being closed anyway.
142   if (browser_->profile()->GetPath() != profile_path)
143     UpdateAvatarButtonAndRelayoutParent();
144 }
145
146 void NewAvatarButton::OnProfileNameChanged(
147       const base::FilePath& profile_path,
148       const base::string16& old_profile_name) {
149   if (browser_->profile()->GetPath() == profile_path)
150     UpdateAvatarButtonAndRelayoutParent();
151 }
152
153 void NewAvatarButton::OnProfileAvatarChanged(
154       const base::FilePath& profile_path) {
155   if (browser_->profile()->GetPath() == profile_path)
156     UpdateAvatarButtonAndRelayoutParent();
157 }
158
159 void NewAvatarButton::OnProfileSupervisedUserIdChanged(
160       const base::FilePath& profile_path) {
161   if (browser_->profile()->GetPath() == profile_path)
162     UpdateAvatarButtonAndRelayoutParent();
163 }
164
165 void NewAvatarButton::OnErrorChanged() {
166   // If there is an error, show an warning icon.
167   const SigninErrorController* error =
168       profiles::GetSigninErrorController(browser_->profile());
169   has_auth_error_ = error && error->HasError();
170
171   UpdateAvatarButtonAndRelayoutParent();
172 }
173
174 void NewAvatarButton::UpdateAvatarButtonAndRelayoutParent() {
175   const ProfileInfoCache& cache =
176       g_browser_process->profile_manager()->GetProfileInfoCache();
177
178   // If we have a single local profile, then use the generic avatar
179   // button instead of the profile name. Never use the generic button if
180   // the active profile is Guest.
181   bool use_generic_button = (!browser_->profile()->IsGuestSession() &&
182                              cache.GetNumberOfProfiles() == 1 &&
183                              cache.GetUserNameOfProfileAtIndex(0).empty());
184
185   SetText(use_generic_button ? base::string16() :
186       profiles::GetAvatarButtonTextForProfile(browser_->profile()));
187
188   // If the button has no text, clear the text shadows to make sure the
189   // image is centered correctly.
190   SetTextShadows(use_generic_button ? gfx::ShadowValues() : gfx::ShadowValues(
191       10, gfx::ShadowValue(gfx::Point(), 1.0f, SK_ColorDKGRAY)));
192
193   // We want the button to resize if the new text is shorter.
194   SetMinSize(gfx::Size());
195
196   if (use_generic_button) {
197     SetImage(views::Button::STATE_NORMAL, generic_avatar_);
198   } else if (has_auth_error_) {
199     SetImage(views::Button::STATE_NORMAL,
200              *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
201                   IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR).ToImageSkia());
202   } else {
203     SetImage(views::Button::STATE_NORMAL, gfx::ImageSkia());
204   }
205
206   // If we are not using the generic button, then reset the spacing between
207   // the text and the possible authentication error icon.
208   const int kDefaultImageTextSpacing = 5;
209   SetImageLabelSpacing(use_generic_button ? 0 : kDefaultImageTextSpacing);
210
211   InvalidateLayout();
212
213   // Because the width of the button might have changed, the parent browser
214   // frame needs to recalculate the button bounds and redraw it.
215   if (parent())
216     parent()->Layout();
217 }