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