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