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 "ash/system/chromeos/session/logout_button_tray.h"
6
7#include "ash/shelf/shelf_types.h"
8#include "ash/shell.h"
9#include "ash/system/chromeos/session/logout_confirmation_controller.h"
10#include "ash/system/status_area_widget.h"
11#include "ash/system/tray/system_tray_delegate.h"
12#include "ash/system/tray/system_tray_notifier.h"
13#include "ash/system/tray/tray_constants.h"
14#include "ash/system/tray/tray_utils.h"
15#include "base/logging.h"
16#include "base/memory/scoped_ptr.h"
17#include "grit/ash_resources.h"
18#include "third_party/skia/include/core/SkColor.h"
19#include "ui/events/event.h"
20#include "ui/gfx/geometry/insets.h"
21#include "ui/gfx/geometry/size.h"
22#include "ui/views/bubble/tray_bubble_view.h"
23#include "ui/views/controls/button/label_button.h"
24#include "ui/views/controls/button/label_button_border.h"
25#include "ui/views/painter.h"
26
27namespace ash {
28namespace {
29
30const int kLogoutButtonHorizontalExtraPadding = 7;
31
32const int kLogoutButtonNormalImages[] = {
33  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_LEFT,
34  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP,
35  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_RIGHT,
36  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_LEFT,
37  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_CENTER,
38  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_RIGHT,
39  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_LEFT,
40  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM,
41  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_RIGHT
42};
43
44const int kLogoutButtonPushedImages[] = {
45  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_LEFT,
46  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP,
47  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_RIGHT,
48  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_LEFT,
49  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_CENTER,
50  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_RIGHT,
51  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_LEFT,
52  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM,
53  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_RIGHT
54};
55
56class LogoutButton : public views::LabelButton {
57 public:
58  LogoutButton(views::ButtonListener* listener);
59  virtual ~LogoutButton();
60
61 private:
62  DISALLOW_COPY_AND_ASSIGN(LogoutButton);
63};
64
65}  // namespace
66
67LogoutButton::LogoutButton(views::ButtonListener* listener)
68    : views::LabelButton(listener, base::string16()) {
69  SetupLabelForTray(label());
70  SetFontList(label()->font_list());
71  for (size_t state = 0; state < views::Button::STATE_COUNT; ++state)
72    SetTextColor(static_cast<views::Button::ButtonState>(state), SK_ColorWHITE);
73
74  scoped_ptr<views::LabelButtonBorder> border(
75      new views::LabelButtonBorder(views::Button::STYLE_TEXTBUTTON));
76  border->SetPainter(false, views::Button::STATE_NORMAL,
77      views::Painter::CreateImageGridPainter(kLogoutButtonNormalImages));
78  border->SetPainter(false, views::Button::STATE_HOVERED,
79      views::Painter::CreateImageGridPainter(kLogoutButtonNormalImages));
80  border->SetPainter(false, views::Button::STATE_PRESSED,
81      views::Painter::CreateImageGridPainter(kLogoutButtonPushedImages));
82  gfx::Insets insets = border->GetInsets();
83  insets += gfx::Insets(0, kLogoutButtonHorizontalExtraPadding,
84                        0, kLogoutButtonHorizontalExtraPadding);
85  border->set_insets(insets);
86  SetBorder(border.PassAs<views::Border>());
87  set_animate_on_state_change(false);
88
89  SetMinSize(gfx::Size(0, kShelfItemHeight));
90}
91
92LogoutButton::~LogoutButton() {
93}
94
95LogoutButtonTray::LogoutButtonTray(StatusAreaWidget* status_area_widget)
96    : TrayBackgroundView(status_area_widget),
97      button_(NULL),
98      login_status_(user::LOGGED_IN_NONE),
99      show_logout_button_in_tray_(false) {
100  button_ = new LogoutButton(this);
101  tray_container()->AddChildView(button_);
102  tray_container()->SetBorder(views::Border::NullBorder());
103  Shell::GetInstance()->system_tray_notifier()->AddLogoutButtonObserver(this);
104}
105
106LogoutButtonTray::~LogoutButtonTray() {
107  Shell::GetInstance()->system_tray_notifier()->
108      RemoveLogoutButtonObserver(this);
109}
110
111void LogoutButtonTray::SetShelfAlignment(ShelfAlignment alignment) {
112  TrayBackgroundView::SetShelfAlignment(alignment);
113  tray_container()->SetBorder(views::Border::NullBorder());
114}
115
116base::string16 LogoutButtonTray::GetAccessibleNameForTray() {
117  return button_->GetText();
118}
119
120void LogoutButtonTray::HideBubbleWithView(
121    const views::TrayBubbleView* bubble_view) {
122}
123
124bool LogoutButtonTray::ClickedOutsideBubble() {
125  return false;
126}
127
128void LogoutButtonTray::OnShowLogoutButtonInTrayChanged(bool show) {
129  show_logout_button_in_tray_ = show;
130  UpdateVisibility();
131}
132
133void LogoutButtonTray::OnLogoutDialogDurationChanged(base::TimeDelta duration) {
134  dialog_duration_ = duration;
135}
136
137void LogoutButtonTray::ButtonPressed(views::Button* sender,
138                                     const ui::Event& event) {
139  DCHECK_EQ(sender, button_);
140  if (dialog_duration_ <= base::TimeDelta()) {
141    // Sign out immediately if |dialog_duration_| is non-positive.
142    Shell::GetInstance()->system_tray_delegate()->SignOut();
143  } else if (Shell::GetInstance()->logout_confirmation_controller()) {
144    Shell::GetInstance()->logout_confirmation_controller()->ConfirmLogout(
145        base::TimeTicks::Now() + dialog_duration_);
146  }
147}
148
149void LogoutButtonTray::UpdateAfterLoginStatusChange(
150    user::LoginStatus login_status) {
151  login_status_ = login_status;
152  const base::string16 title =
153      GetLocalizedSignOutStringForStatus(login_status, false);
154  button_->SetText(title);
155  button_->SetAccessibleName(title);
156  UpdateVisibility();
157}
158
159void LogoutButtonTray::UpdateVisibility() {
160  SetVisible(show_logout_button_in_tray_ &&
161             login_status_ != user::LOGGED_IN_NONE &&
162             login_status_ != user::LOGGED_IN_LOCKED);
163}
164
165}  // namespace ash
166