tray_caps_lock.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 "chromeos/ime/input_method_manager.h"
14#include "chromeos/ime/xkeyboard.h"
15#include "grit/ash_resources.h"
16#include "grit/ash_strings.h"
17#include "ui/accessibility/ax_view_state.h"
18#include "ui/base/resource/resource_bundle.h"
19#include "ui/gfx/image/image.h"
20#include "ui/views/controls/image_view.h"
21#include "ui/views/controls/label.h"
22#include "ui/views/layout/box_layout.h"
23#include "ui/views/widget/widget.h"
24
25namespace ash {
26namespace internal {
27
28namespace {
29
30bool CapsLockIsEnabled() {
31  chromeos::input_method::InputMethodManager* ime =
32      chromeos::input_method::InputMethodManager::Get();
33  return (ime && ime->GetXKeyboard()) ? ime->GetXKeyboard()->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::XKeyboard* xkeyboard =
113        chromeos::input_method::InputMethodManager::Get()->GetXKeyboard();
114    Shell::GetInstance()->metrics()->RecordUserMetricsAction(
115        xkeyboard->CapsLockIsEnabled() ?
116        ash::UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK :
117        ash::UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK);
118    xkeyboard->SetCapsLockEnabled(!xkeyboard->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  // Make sure the event is processed by this before the IME.
135  Shell::GetInstance()->PrependPreTargetHandler(this);
136}
137
138TrayCapsLock::~TrayCapsLock() {
139  Shell::GetInstance()->RemovePreTargetHandler(this);
140}
141
142void TrayCapsLock::OnCapsLockChanged(bool enabled) {
143  if (tray_view())
144    tray_view()->SetVisible(enabled);
145
146  caps_lock_enabled_ = enabled;
147
148  if (default_) {
149    default_->Update(enabled);
150  } else {
151    if (enabled) {
152      if (!message_shown_) {
153        Shell::GetInstance()->metrics()->RecordUserMetricsAction(
154            ash::UMA_STATUS_AREA_CAPS_LOCK_POPUP);
155        PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false);
156        message_shown_ = true;
157      }
158    } else if (detailed_) {
159      detailed_->GetWidget()->Close();
160    }
161  }
162}
163
164void TrayCapsLock::OnKeyEvent(ui::KeyEvent* key) {
165  if (key->type() == ui::ET_KEY_PRESSED && key->key_code() == ui::VKEY_CAPITAL)
166    OnCapsLockChanged(!caps_lock_enabled_);
167}
168
169bool TrayCapsLock::GetInitialVisibility() {
170  return CapsLockIsEnabled();
171}
172
173views::View* TrayCapsLock::CreateDefaultView(user::LoginStatus status) {
174  if (!caps_lock_enabled_)
175    return NULL;
176  DCHECK(default_ == NULL);
177  default_ = new CapsLockDefaultView;
178  default_->Update(caps_lock_enabled_);
179  return default_;
180}
181
182views::View* TrayCapsLock::CreateDetailedView(user::LoginStatus status) {
183  DCHECK(detailed_ == NULL);
184  detailed_ = new views::View;
185
186  detailed_->SetLayoutManager(new
187      views::BoxLayout(views::BoxLayout::kHorizontal,
188      kTrayPopupPaddingHorizontal, 10, kTrayPopupPaddingBetweenItems));
189
190  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
191  views::ImageView* image = new views::ImageView;
192  image->SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_CAPS_LOCK_DARK).
193      ToImageSkia());
194
195  detailed_->AddChildView(image);
196
197  const int string_id = Shell::GetInstance()->system_tray_delegate()->
198                            IsSearchKeyMappedToCapsLock() ?
199      IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_SEARCH :
200      IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_ALT_SEARCH;
201  views::Label* label = new views::Label(bundle.GetLocalizedString(string_id));
202  label->SetMultiLine(true);
203  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
204  detailed_->AddChildView(label);
205  Shell::GetInstance()->metrics()->RecordUserMetricsAction(
206      ash::UMA_STATUS_AREA_CAPS_LOCK_DETAILED);
207
208  return detailed_;
209}
210
211void TrayCapsLock::DestroyDefaultView() {
212  default_ = NULL;
213}
214
215void TrayCapsLock::DestroyDetailedView() {
216  detailed_ = NULL;
217}
218
219}  // namespace internal
220}  // namespace ash
221