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