tray_caps_lock.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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
3// found in the LICENSE file.
4
5#include "ash/system/chromeos/tray_caps_lock.h"
6
7#include "ash/metrics/user_metrics_recorder.h"
8#include "ash/shell.h"
9#include "ash/system/tray/actionable_view.h"
10#include "ash/system/tray/fixed_sized_image_view.h"
11#include "ash/system/tray/system_tray_notifier.h"
12#include "ash/system/tray/tray_constants.h"
13#include "base/sys_info.h"
14#include "chromeos/ime/ime_keyboard.h"
15#include "chromeos/ime/input_method_manager.h"
16#include "grit/ash_resources.h"
17#include "grit/ash_strings.h"
18#include "ui/accessibility/ax_view_state.h"
19#include "ui/base/resource/resource_bundle.h"
20#include "ui/gfx/image/image.h"
21#include "ui/views/controls/image_view.h"
22#include "ui/views/controls/label.h"
23#include "ui/views/layout/box_layout.h"
24#include "ui/views/widget/widget.h"
25
26namespace ash {
27namespace {
28
29bool CapsLockIsEnabled() {
30  chromeos::input_method::InputMethodManager* ime =
31      chromeos::input_method::InputMethodManager::Get();
32  return (ime && ime->GetImeKeyboard())
33             ? ime->GetImeKeyboard()->CapsLockIsEnabled()
34             : false;
35}
36
37}
38
39class CapsLockDefaultView : public ActionableView {
40 public:
41  CapsLockDefaultView()
42      : text_label_(new views::Label),
43        shortcut_label_(new views::Label) {
44    SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
45                                          kTrayPopupPaddingHorizontal,
46                                          0,
47                                          kTrayPopupPaddingBetweenItems));
48
49    ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
50    FixedSizedImageView* image =
51        new FixedSizedImageView(0, kTrayPopupItemHeight);
52    image->SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_CAPS_LOCK_DARK).
53        ToImageSkia());
54    AddChildView(image);
55
56    text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
57    AddChildView(text_label_);
58
59    shortcut_label_->SetEnabled(false);
60    AddChildView(shortcut_label_);
61  }
62
63  virtual ~CapsLockDefaultView() {}
64
65  // Updates the label text and the shortcut text.
66  void Update(bool caps_lock_enabled) {
67    ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
68    const int text_string_id = caps_lock_enabled ?
69        IDS_ASH_STATUS_TRAY_CAPS_LOCK_ENABLED :
70        IDS_ASH_STATUS_TRAY_CAPS_LOCK_DISABLED;
71    text_label_->SetText(bundle.GetLocalizedString(text_string_id));
72
73    int shortcut_string_id = 0;
74    bool search_mapped_to_caps_lock = Shell::GetInstance()->
75        system_tray_delegate()->IsSearchKeyMappedToCapsLock();
76    if (caps_lock_enabled) {
77      shortcut_string_id = search_mapped_to_caps_lock ?
78          IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_SEARCH_OR_SHIFT :
79          IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_ALT_SEARCH_OR_SHIFT;
80    } else {
81      shortcut_string_id = search_mapped_to_caps_lock ?
82          IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_SEARCH :
83          IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_ALT_SEARCH;
84    }
85    shortcut_label_->SetText(bundle.GetLocalizedString(shortcut_string_id));
86
87    Layout();
88  }
89
90 private:
91  // Overridden from views::View:
92  virtual void Layout() OVERRIDE {
93    views::View::Layout();
94
95    // Align the shortcut text with the right end
96    const int old_x = shortcut_label_->x();
97    const int new_x =
98        width() - shortcut_label_->width() - kTrayPopupPaddingHorizontal;
99    shortcut_label_->SetX(new_x);
100    const gfx::Size text_size = text_label_->size();
101    text_label_->SetSize(gfx::Size(text_size.width() + new_x - old_x,
102                                   text_size.height()));
103  }
104
105  virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE {
106    state->role = ui::AX_ROLE_BUTTON;
107    state->name = text_label_->text();
108  }
109
110  // Overridden from ActionableView:
111  virtual bool PerformAction(const ui::Event& event) OVERRIDE {
112    chromeos::input_method::ImeKeyboard* keyboard =
113        chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
114    Shell::GetInstance()->metrics()->RecordUserMetricsAction(
115        keyboard->CapsLockIsEnabled() ?
116        ash::UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK :
117        ash::UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK);
118    keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled());
119    return true;
120  }
121
122  views::Label* text_label_;
123  views::Label* shortcut_label_;
124
125  DISALLOW_COPY_AND_ASSIGN(CapsLockDefaultView);
126};
127
128TrayCapsLock::TrayCapsLock(SystemTray* system_tray)
129    : TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_CAPS_LOCK),
130      default_(NULL),
131      detailed_(NULL),
132      caps_lock_enabled_(CapsLockIsEnabled()),
133      message_shown_(false) {
134  // Since keyboard handling differs between ChromeOS and Linux we need to
135  // use different observers depending on the two platforms.
136  if (base::SysInfo::IsRunningOnChromeOS()) {
137    chromeos::input_method::ImeKeyboard* keyboard =
138        chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
139    keyboard->AddObserver(this);
140  } else {
141    Shell::GetInstance()->PrependPreTargetHandler(this);
142  }
143}
144
145TrayCapsLock::~TrayCapsLock() {
146  // Since keyboard handling differs between ChromeOS and Linux we need to
147  // use different observers depending on the two platforms.
148  if (base::SysInfo::IsRunningOnChromeOS()) {
149    chromeos::input_method::ImeKeyboard* keyboard =
150        chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
151    keyboard->RemoveObserver(this);
152  } else {
153    Shell::GetInstance()->RemovePreTargetHandler(this);
154  }
155}
156
157void TrayCapsLock::OnCapsLockChanged(bool enabled) {
158  caps_lock_enabled_ = enabled;
159
160  if (tray_view())
161    tray_view()->SetVisible(caps_lock_enabled_);
162
163  if (default_) {
164    default_->Update(caps_lock_enabled_);
165  } else {
166    if (caps_lock_enabled_) {
167      if (!message_shown_) {
168        Shell::GetInstance()->metrics()->RecordUserMetricsAction(
169            ash::UMA_STATUS_AREA_CAPS_LOCK_POPUP);
170        PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false);
171        message_shown_ = true;
172      }
173    } else if (detailed_) {
174      detailed_->GetWidget()->Close();
175    }
176  }
177}
178
179void TrayCapsLock::OnKeyEvent(ui::KeyEvent* key) {
180  if (key->type() == ui::ET_KEY_PRESSED && key->key_code() == ui::VKEY_CAPITAL)
181    OnCapsLockChanged(!caps_lock_enabled_);
182}
183
184bool TrayCapsLock::GetInitialVisibility() {
185  return CapsLockIsEnabled();
186}
187
188views::View* TrayCapsLock::CreateDefaultView(user::LoginStatus status) {
189  if (!caps_lock_enabled_)
190    return NULL;
191  DCHECK(default_ == NULL);
192  default_ = new CapsLockDefaultView;
193  default_->Update(caps_lock_enabled_);
194  return default_;
195}
196
197views::View* TrayCapsLock::CreateDetailedView(user::LoginStatus status) {
198  DCHECK(detailed_ == NULL);
199  detailed_ = new views::View;
200
201  detailed_->SetLayoutManager(new
202      views::BoxLayout(views::BoxLayout::kHorizontal,
203      kTrayPopupPaddingHorizontal, 10, kTrayPopupPaddingBetweenItems));
204
205  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
206  views::ImageView* image = new views::ImageView;
207  image->SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_CAPS_LOCK_DARK).
208      ToImageSkia());
209
210  detailed_->AddChildView(image);
211
212  const int string_id = Shell::GetInstance()->system_tray_delegate()->
213                            IsSearchKeyMappedToCapsLock() ?
214      IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_SEARCH :
215      IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_ALT_SEARCH;
216  views::Label* label = new views::Label(bundle.GetLocalizedString(string_id));
217  label->SetMultiLine(true);
218  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
219  detailed_->AddChildView(label);
220  Shell::GetInstance()->metrics()->RecordUserMetricsAction(
221      ash::UMA_STATUS_AREA_CAPS_LOCK_DETAILED);
222
223  return detailed_;
224}
225
226void TrayCapsLock::DestroyDefaultView() {
227  default_ = NULL;
228}
229
230void TrayCapsLock::DestroyDetailedView() {
231  detailed_ = NULL;
232}
233
234}  // namespace ash
235