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 27 namespace ash { 28 namespace { 29 30 bool 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 40 class 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 131 TrayCapsLock::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 143 TrayCapsLock::~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 150 void 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 172 bool TrayCapsLock::GetInitialVisibility() { 173 return CapsLockIsEnabled(); 174 } 175 176 views::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 185 views::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 214 void TrayCapsLock::DestroyDefaultView() { 215 default_ = NULL; 216 } 217 218 void TrayCapsLock::DestroyDetailedView() { 219 detailed_ = NULL; 220 } 221 222 } // namespace ash 223