tray_caps_lock.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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    if (keyboard) {
115      Shell::GetInstance()->metrics()->RecordUserMetricsAction(
116          keyboard->CapsLockIsEnabled() ?
117          ash::UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK :
118          ash::UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK);
119      keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled());
120    }
121    return true;
122  }
123
124  views::Label* text_label_;
125  views::Label* shortcut_label_;
126
127  DISALLOW_COPY_AND_ASSIGN(CapsLockDefaultView);
128};
129
130TrayCapsLock::TrayCapsLock(SystemTray* system_tray)
131    : TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_CAPS_LOCK),
132      default_(NULL),
133      detailed_(NULL),
134      caps_lock_enabled_(CapsLockIsEnabled()),
135      message_shown_(false) {
136  chromeos::input_method::InputMethodManager* ime =
137      chromeos::input_method::InputMethodManager::Get();
138  if (ime && ime->GetImeKeyboard())
139    ime->GetImeKeyboard()->AddObserver(this);
140}
141
142TrayCapsLock::~TrayCapsLock() {
143  chromeos::input_method::InputMethodManager* ime =
144      chromeos::input_method::InputMethodManager::Get();
145  if (ime && ime->GetImeKeyboard())
146    ime->GetImeKeyboard()->RemoveObserver(this);
147}
148
149void TrayCapsLock::OnCapsLockChanged(bool enabled) {
150  caps_lock_enabled_ = enabled;
151
152  if (tray_view())
153    tray_view()->SetVisible(caps_lock_enabled_);
154
155  if (default_) {
156    default_->Update(caps_lock_enabled_);
157  } else {
158    if (caps_lock_enabled_) {
159      if (!message_shown_) {
160        Shell::GetInstance()->metrics()->RecordUserMetricsAction(
161            ash::UMA_STATUS_AREA_CAPS_LOCK_POPUP);
162        PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false);
163        message_shown_ = true;
164      }
165    } else if (detailed_) {
166      detailed_->GetWidget()->Close();
167    }
168  }
169}
170
171bool TrayCapsLock::GetInitialVisibility() {
172  return CapsLockIsEnabled();
173}
174
175views::View* TrayCapsLock::CreateDefaultView(user::LoginStatus status) {
176  if (!caps_lock_enabled_)
177    return NULL;
178  DCHECK(default_ == NULL);
179  default_ = new CapsLockDefaultView;
180  default_->Update(caps_lock_enabled_);
181  return default_;
182}
183
184views::View* TrayCapsLock::CreateDetailedView(user::LoginStatus status) {
185  DCHECK(detailed_ == NULL);
186  detailed_ = new views::View;
187
188  detailed_->SetLayoutManager(new
189      views::BoxLayout(views::BoxLayout::kHorizontal,
190      kTrayPopupPaddingHorizontal, 10, kTrayPopupPaddingBetweenItems));
191
192  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
193  views::ImageView* image = new views::ImageView;
194  image->SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_CAPS_LOCK_DARK).
195      ToImageSkia());
196
197  detailed_->AddChildView(image);
198
199  const int string_id = Shell::GetInstance()->system_tray_delegate()->
200                            IsSearchKeyMappedToCapsLock() ?
201      IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_SEARCH :
202      IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_ALT_SEARCH;
203  views::Label* label = new views::Label(bundle.GetLocalizedString(string_id));
204  label->SetMultiLine(true);
205  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
206  detailed_->AddChildView(label);
207  Shell::GetInstance()->metrics()->RecordUserMetricsAction(
208      ash::UMA_STATUS_AREA_CAPS_LOCK_DETAILED);
209
210  return detailed_;
211}
212
213void TrayCapsLock::DestroyDefaultView() {
214  default_ = NULL;
215}
216
217void TrayCapsLock::DestroyDetailedView() {
218  detailed_ = NULL;
219}
220
221}  // namespace ash
222