tray_ime.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/ime/tray_ime.h" 6 7#include <vector> 8 9#include "ash/root_window_controller.h" 10#include "ash/shelf/shelf_widget.h" 11#include "ash/shell.h" 12#include "ash/system/tray/hover_highlight_view.h" 13#include "ash/system/tray/system_tray.h" 14#include "ash/system/tray/system_tray_delegate.h" 15#include "ash/system/tray/system_tray_notifier.h" 16#include "ash/system/tray/tray_constants.h" 17#include "ash/system/tray/tray_details_view.h" 18#include "ash/system/tray/tray_item_more.h" 19#include "ash/system/tray/tray_item_view.h" 20#include "ash/system/tray/tray_notification_view.h" 21#include "ash/system/tray/tray_utils.h" 22#include "base/logging.h" 23#include "base/strings/utf_string_conversions.h" 24#include "grit/ash_resources.h" 25#include "grit/ash_strings.h" 26#include "ui/base/l10n/l10n_util.h" 27#include "ui/base/resource/resource_bundle.h" 28#include "ui/gfx/font.h" 29#include "ui/gfx/image/image.h" 30#include "ui/views/controls/label.h" 31#include "ui/views/layout/box_layout.h" 32#include "ui/views/widget/widget.h" 33 34namespace ash { 35namespace internal { 36 37namespace tray { 38 39class IMEDefaultView : public TrayItemMore { 40 public: 41 explicit IMEDefaultView(SystemTrayItem* owner) 42 : TrayItemMore(owner, true) { 43 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 44 45 SetImage(bundle.GetImageNamed( 46 IDR_AURA_UBER_TRAY_IME).ToImageSkia()); 47 48 IMEInfo info; 49 Shell::GetInstance()->system_tray_delegate()->GetCurrentIME(&info); 50 UpdateLabel(info); 51 } 52 53 virtual ~IMEDefaultView() {} 54 55 void UpdateLabel(const IMEInfo& info) { 56 SetLabel(info.name); 57 SetAccessibleName(info.name); 58 } 59 60 private: 61 DISALLOW_COPY_AND_ASSIGN(IMEDefaultView); 62}; 63 64class IMEDetailedView : public TrayDetailsView, 65 public ViewClickListener { 66 public: 67 IMEDetailedView(SystemTrayItem* owner, user::LoginStatus login) 68 : TrayDetailsView(owner), 69 login_(login) { 70 SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate(); 71 IMEInfoList list; 72 delegate->GetAvailableIMEList(&list); 73 IMEPropertyInfoList property_list; 74 delegate->GetCurrentIMEProperties(&property_list); 75 Update(list, property_list); 76 } 77 78 virtual ~IMEDetailedView() {} 79 80 void Update(const IMEInfoList& list, 81 const IMEPropertyInfoList& property_list) { 82 Reset(); 83 84 AppendIMEList(list); 85 if (!property_list.empty()) 86 AppendIMEProperties(property_list); 87 if (login_ != user::LOGGED_IN_NONE && login_ != user::LOGGED_IN_LOCKED) 88 AppendSettings(); 89 AppendHeaderEntry(); 90 91 Layout(); 92 SchedulePaint(); 93 } 94 95 private: 96 void AppendHeaderEntry() { 97 CreateSpecialRow(IDS_ASH_STATUS_TRAY_IME, this); 98 } 99 100 void AppendIMEList(const IMEInfoList& list) { 101 ime_map_.clear(); 102 CreateScrollableList(); 103 for (size_t i = 0; i < list.size(); i++) { 104 HoverHighlightView* container = new HoverHighlightView(this); 105 container->AddLabel(list[i].name, 106 list[i].selected ? gfx::Font::BOLD : gfx::Font::NORMAL); 107 scroll_content()->AddChildView(container); 108 ime_map_[container] = list[i].id; 109 } 110 } 111 112 void AppendIMEProperties(const IMEPropertyInfoList& property_list) { 113 property_map_.clear(); 114 for (size_t i = 0; i < property_list.size(); i++) { 115 HoverHighlightView* container = new HoverHighlightView(this); 116 container->AddLabel( 117 property_list[i].name, 118 property_list[i].selected ? gfx::Font::BOLD : gfx::Font::NORMAL); 119 if (i == 0) 120 container->set_border(views::Border::CreateSolidSidedBorder(1, 0, 0, 0, 121 kBorderLightColor)); 122 scroll_content()->AddChildView(container); 123 property_map_[container] = property_list[i].key; 124 } 125 } 126 127 void AppendSettings() { 128 HoverHighlightView* container = new HoverHighlightView(this); 129 container->AddLabel(ui::ResourceBundle::GetSharedInstance(). 130 GetLocalizedString(IDS_ASH_STATUS_TRAY_IME_SETTINGS), 131 gfx::Font::NORMAL); 132 AddChildView(container); 133 settings_ = container; 134 } 135 136 // Overridden from ViewClickListener. 137 virtual void OnViewClicked(views::View* sender) OVERRIDE { 138 SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate(); 139 if (sender == footer()->content()) { 140 owner()->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 141 } else if (sender == settings_) { 142 delegate->ShowIMESettings(); 143 } else { 144 std::map<views::View*, std::string>::const_iterator ime_find; 145 ime_find = ime_map_.find(sender); 146 if (ime_find != ime_map_.end()) { 147 std::string ime_id = ime_find->second; 148 delegate->SwitchIME(ime_id); 149 GetWidget()->Close(); 150 } else { 151 std::map<views::View*, std::string>::const_iterator prop_find; 152 prop_find = property_map_.find(sender); 153 if (prop_find != property_map_.end()) { 154 const std::string key = prop_find->second; 155 delegate->ActivateIMEProperty(key); 156 GetWidget()->Close(); 157 } 158 } 159 } 160 } 161 162 user::LoginStatus login_; 163 164 std::map<views::View*, std::string> ime_map_; 165 std::map<views::View*, std::string> property_map_; 166 views::View* settings_; 167 168 DISALLOW_COPY_AND_ASSIGN(IMEDetailedView); 169}; 170 171class IMENotificationView : public TrayNotificationView { 172 public: 173 explicit IMENotificationView(TrayIME* owner) 174 : TrayNotificationView(owner, IDR_AURA_UBER_TRAY_IME) { 175 InitView(GetLabel()); 176 } 177 178 void UpdateLabel() { 179 RestartAutoCloseTimer(); 180 UpdateView(GetLabel()); 181 } 182 183 // Overridden from TrayNotificationView. 184 virtual void OnClickAction() OVERRIDE { 185 owner()->PopupDetailedView(0, true); 186 } 187 188 private: 189 views::Label* GetLabel() { 190 SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate(); 191 IMEInfo current; 192 delegate->GetCurrentIME(¤t); 193 194 // TODO(zork): Use IDS_ASH_STATUS_TRAY_THIRD_PARTY_IME_TURNED_ON_BUBBLE for 195 // third party IMEs 196 views::Label* label = new views::Label( 197 l10n_util::GetStringFUTF16( 198 IDS_ASH_STATUS_TRAY_IME_TURNED_ON_BUBBLE, 199 current.medium_name)); 200 label->SetMultiLine(true); 201 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 202 return label; 203 } 204 205 DISALLOW_COPY_AND_ASSIGN(IMENotificationView); 206}; 207 208 209} // namespace tray 210 211TrayIME::TrayIME(SystemTray* system_tray) 212 : SystemTrayItem(system_tray), 213 tray_label_(NULL), 214 default_(NULL), 215 detailed_(NULL), 216 notification_(NULL), 217 message_shown_(false) { 218 Shell::GetInstance()->system_tray_notifier()->AddIMEObserver(this); 219} 220 221TrayIME::~TrayIME() { 222 Shell::GetInstance()->system_tray_notifier()->RemoveIMEObserver(this); 223} 224 225void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) { 226 if (tray_label_) { 227 if (current.third_party) { 228 tray_label_->label()->SetText(current.short_name + UTF8ToUTF16("*")); 229 } else { 230 tray_label_->label()->SetText(current.short_name); 231 } 232 tray_label_->SetVisible(count > 1); 233 SetTrayLabelItemBorder(tray_label_, system_tray()->shelf_alignment()); 234 tray_label_->Layout(); 235 } 236} 237 238views::View* TrayIME::CreateTrayView(user::LoginStatus status) { 239 CHECK(tray_label_ == NULL); 240 tray_label_ = new TrayItemView(this); 241 tray_label_->CreateLabel(); 242 SetupLabelForTray(tray_label_->label()); 243 // Hide IME tray when it is created, it will be updated when it is notified 244 // for IME refresh event. 245 tray_label_->SetVisible(false); 246 return tray_label_; 247} 248 249views::View* TrayIME::CreateDefaultView(user::LoginStatus status) { 250 SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate(); 251 IMEInfoList list; 252 IMEPropertyInfoList property_list; 253 delegate->GetAvailableIMEList(&list); 254 delegate->GetCurrentIMEProperties(&property_list); 255 if (list.size() <= 1 && property_list.size() <= 1) 256 return NULL; 257 CHECK(default_ == NULL); 258 default_ = new tray::IMEDefaultView(this); 259 return default_; 260} 261 262views::View* TrayIME::CreateDetailedView(user::LoginStatus status) { 263 CHECK(detailed_ == NULL); 264 detailed_ = new tray::IMEDetailedView(this, status); 265 return detailed_; 266} 267 268views::View* TrayIME::CreateNotificationView(user::LoginStatus status) { 269 DCHECK(notification_ == NULL); 270 notification_ = new tray::IMENotificationView(this); 271 notification_->StartAutoCloseTimer(kTrayPopupAutoCloseDelayForTextInSeconds); 272 return notification_; 273} 274 275void TrayIME::DestroyTrayView() { 276 tray_label_ = NULL; 277} 278 279void TrayIME::DestroyDefaultView() { 280 default_ = NULL; 281} 282 283void TrayIME::DestroyDetailedView() { 284 detailed_ = NULL; 285} 286 287void TrayIME::DestroyNotificationView() { 288 notification_ = NULL; 289} 290 291void TrayIME::UpdateAfterLoginStatusChange(user::LoginStatus status) { 292} 293 294void TrayIME::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 295 SetTrayLabelItemBorder(tray_label_, alignment); 296} 297 298void TrayIME::OnIMERefresh(bool show_message) { 299 SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate(); 300 IMEInfoList list; 301 IMEInfo current; 302 IMEPropertyInfoList property_list; 303 delegate->GetCurrentIME(¤t); 304 delegate->GetAvailableIMEList(&list); 305 delegate->GetCurrentIMEProperties(&property_list); 306 307 UpdateTrayLabel(current, list.size()); 308 309 if (default_) 310 default_->UpdateLabel(current); 311 if (detailed_) 312 detailed_->Update(list, property_list); 313 314 if (list.size() > 1 && show_message) { 315 // If the notification is still visible, hide it and clear the flag so it is 316 // refreshed. 317 if (notification_) { 318 notification_->UpdateLabel(); 319 } else if (!Shell::GetPrimaryRootWindowController()->shelf()->IsVisible() || 320 !message_shown_) { 321 ShowNotificationView(); 322 message_shown_ = true; 323 } 324 } 325} 326 327} // namespace internal 328} // namespace ash 329