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