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/tray/hover_highlight_view.h"
     14 #include "ash/system/tray/system_tray.h"
     15 #include "ash/system/tray/system_tray_delegate.h"
     16 #include "ash/system/tray/system_tray_notifier.h"
     17 #include "ash/system/tray/tray_constants.h"
     18 #include "ash/system/tray/tray_details_view.h"
     19 #include "ash/system/tray/tray_item_more.h"
     20 #include "ash/system/tray/tray_item_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/accessibility/ax_enums.h"
     27 #include "ui/accessibility/ax_view_state.h"
     28 #include "ui/base/l10n/l10n_util.h"
     29 #include "ui/base/resource/resource_bundle.h"
     30 #include "ui/gfx/font.h"
     31 #include "ui/gfx/image/image.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 namespace ash {
     37 namespace tray {
     38 
     39 // A |HoverHighlightView| that uses bold or normal font depending on whetehr
     40 // it is selected.  This view exposes itself as a checkbox to the accessibility
     41 // framework.
     42 class SelectableHoverHighlightView : public HoverHighlightView {
     43  public:
     44   SelectableHoverHighlightView(ViewClickListener* listener,
     45                                const base::string16& label,
     46                                bool selected)
     47       : HoverHighlightView(listener), selected_(selected) {
     48     AddLabel(
     49         label, gfx::ALIGN_LEFT, selected ? gfx::Font::BOLD : gfx::Font::NORMAL);
     50   }
     51 
     52   virtual ~SelectableHoverHighlightView() {}
     53 
     54  protected:
     55   // Overridden from views::View.
     56   virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE {
     57     HoverHighlightView::GetAccessibleState(state);
     58     state->role = ui::AX_ROLE_CHECK_BOX;
     59     if (selected_)
     60       state->AddStateFlag(ui::AX_STATE_CHECKED);
     61   }
     62 
     63  private:
     64   bool selected_;
     65 
     66   DISALLOW_COPY_AND_ASSIGN(SelectableHoverHighlightView);
     67 };
     68 
     69 class IMEDefaultView : public TrayItemMore {
     70  public:
     71   explicit IMEDefaultView(SystemTrayItem* owner)
     72       : TrayItemMore(owner, true) {
     73     ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
     74 
     75     SetImage(bundle.GetImageNamed(
     76         IDR_AURA_UBER_TRAY_IME).ToImageSkia());
     77 
     78     IMEInfo info;
     79     Shell::GetInstance()->system_tray_delegate()->GetCurrentIME(&info);
     80     UpdateLabel(info);
     81   }
     82 
     83   virtual ~IMEDefaultView() {}
     84 
     85   void UpdateLabel(const IMEInfo& info) {
     86     SetLabel(info.name);
     87     SetAccessibleName(info.name);
     88   }
     89 
     90  private:
     91   DISALLOW_COPY_AND_ASSIGN(IMEDefaultView);
     92 };
     93 
     94 class IMEDetailedView : public TrayDetailsView,
     95                         public ViewClickListener {
     96  public:
     97   IMEDetailedView(SystemTrayItem* owner, user::LoginStatus login)
     98       : TrayDetailsView(owner),
     99         login_(login) {
    100     SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
    101     IMEInfoList list;
    102     delegate->GetAvailableIMEList(&list);
    103     IMEPropertyInfoList property_list;
    104     delegate->GetCurrentIMEProperties(&property_list);
    105     Update(list, property_list);
    106   }
    107 
    108   virtual ~IMEDetailedView() {}
    109 
    110   void Update(const IMEInfoList& list,
    111               const IMEPropertyInfoList& property_list) {
    112     Reset();
    113 
    114     AppendIMEList(list);
    115     if (!property_list.empty())
    116       AppendIMEProperties(property_list);
    117     if (login_ != user::LOGGED_IN_NONE && login_ != user::LOGGED_IN_LOCKED)
    118       AppendSettings();
    119     AppendHeaderEntry();
    120 
    121     Layout();
    122     SchedulePaint();
    123   }
    124 
    125  private:
    126   void AppendHeaderEntry() {
    127     CreateSpecialRow(IDS_ASH_STATUS_TRAY_IME, this);
    128   }
    129 
    130   void AppendIMEList(const IMEInfoList& list) {
    131     ime_map_.clear();
    132     CreateScrollableList();
    133     for (size_t i = 0; i < list.size(); i++) {
    134       HoverHighlightView* container = new SelectableHoverHighlightView(
    135           this, list[i].name, list[i].selected);
    136       scroll_content()->AddChildView(container);
    137       ime_map_[container] = list[i].id;
    138     }
    139   }
    140 
    141   void AppendIMEProperties(const IMEPropertyInfoList& property_list) {
    142     property_map_.clear();
    143     for (size_t i = 0; i < property_list.size(); i++) {
    144       HoverHighlightView* container = new SelectableHoverHighlightView(
    145           this, property_list[i].name, property_list[i].selected);
    146       if (i == 0)
    147         container->SetBorder(views::Border::CreateSolidSidedBorder(
    148             1, 0, 0, 0, kBorderLightColor));
    149       scroll_content()->AddChildView(container);
    150       property_map_[container] = property_list[i].key;
    151     }
    152   }
    153 
    154   void AppendSettings() {
    155     HoverHighlightView* container = new HoverHighlightView(this);
    156     container->AddLabel(
    157         ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
    158             IDS_ASH_STATUS_TRAY_IME_SETTINGS),
    159         gfx::ALIGN_LEFT,
    160         gfx::Font::NORMAL);
    161     AddChildView(container);
    162     settings_ = container;
    163   }
    164 
    165   // Overridden from ViewClickListener.
    166   virtual void OnViewClicked(views::View* sender) OVERRIDE {
    167     SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
    168     if (sender == footer()->content()) {
    169       TransitionToDefaultView();
    170     } else if (sender == settings_) {
    171       Shell::GetInstance()->metrics()->RecordUserMetricsAction(
    172           ash::UMA_STATUS_AREA_IME_SHOW_DETAILED);
    173       delegate->ShowIMESettings();
    174     } else {
    175       std::map<views::View*, std::string>::const_iterator ime_find;
    176       ime_find = ime_map_.find(sender);
    177       if (ime_find != ime_map_.end()) {
    178         Shell::GetInstance()->metrics()->RecordUserMetricsAction(
    179             ash::UMA_STATUS_AREA_IME_SWITCH_MODE);
    180         std::string ime_id = ime_find->second;
    181         delegate->SwitchIME(ime_id);
    182         GetWidget()->Close();
    183       } else {
    184         std::map<views::View*, std::string>::const_iterator prop_find;
    185         prop_find = property_map_.find(sender);
    186         if (prop_find != property_map_.end()) {
    187           const std::string key = prop_find->second;
    188           delegate->ActivateIMEProperty(key);
    189           GetWidget()->Close();
    190         }
    191       }
    192     }
    193   }
    194 
    195   user::LoginStatus login_;
    196 
    197   std::map<views::View*, std::string> ime_map_;
    198   std::map<views::View*, std::string> property_map_;
    199   views::View* settings_;
    200 
    201   DISALLOW_COPY_AND_ASSIGN(IMEDetailedView);
    202 };
    203 
    204 }  // namespace tray
    205 
    206 TrayIME::TrayIME(SystemTray* system_tray)
    207     : SystemTrayItem(system_tray),
    208       tray_label_(NULL),
    209       default_(NULL),
    210       detailed_(NULL) {
    211   Shell::GetInstance()->system_tray_notifier()->AddIMEObserver(this);
    212 }
    213 
    214 TrayIME::~TrayIME() {
    215   Shell::GetInstance()->system_tray_notifier()->RemoveIMEObserver(this);
    216 }
    217 
    218 void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) {
    219   if (tray_label_) {
    220     bool visible = count > 1;
    221     tray_label_->SetVisible(visible);
    222     // Do not change label before hiding because this change is noticeable.
    223     if (!visible)
    224       return;
    225     if (current.third_party) {
    226       tray_label_->label()->SetText(
    227           current.short_name + base::UTF8ToUTF16("*"));
    228     } else {
    229       tray_label_->label()->SetText(current.short_name);
    230     }
    231     SetTrayLabelItemBorder(tray_label_, system_tray()->shelf_alignment());
    232     tray_label_->Layout();
    233   }
    234 }
    235 
    236 views::View* TrayIME::CreateTrayView(user::LoginStatus status) {
    237   CHECK(tray_label_ == NULL);
    238   tray_label_ = new TrayItemView(this);
    239   tray_label_->CreateLabel();
    240   SetupLabelForTray(tray_label_->label());
    241   // Hide IME tray when it is created, it will be updated when it is notified
    242   // for IME refresh event.
    243   tray_label_->SetVisible(false);
    244   return tray_label_;
    245 }
    246 
    247 views::View* TrayIME::CreateDefaultView(user::LoginStatus status) {
    248   SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
    249   IMEInfoList list;
    250   IMEPropertyInfoList property_list;
    251   delegate->GetAvailableIMEList(&list);
    252   delegate->GetCurrentIMEProperties(&property_list);
    253   if (list.size() <= 1 && property_list.size() <= 1)
    254     return NULL;
    255   CHECK(default_ == NULL);
    256   default_ = new tray::IMEDefaultView(this);
    257   return default_;
    258 }
    259 
    260 views::View* TrayIME::CreateDetailedView(user::LoginStatus status) {
    261   CHECK(detailed_ == NULL);
    262   detailed_ = new tray::IMEDetailedView(this, status);
    263   return detailed_;
    264 }
    265 
    266 void TrayIME::DestroyTrayView() {
    267   tray_label_ = NULL;
    268 }
    269 
    270 void TrayIME::DestroyDefaultView() {
    271   default_ = NULL;
    272 }
    273 
    274 void TrayIME::DestroyDetailedView() {
    275   detailed_ = NULL;
    276 }
    277 
    278 void TrayIME::UpdateAfterLoginStatusChange(user::LoginStatus status) {
    279 }
    280 
    281 void TrayIME::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
    282   SetTrayLabelItemBorder(tray_label_, alignment);
    283   tray_label_->Layout();
    284 }
    285 
    286 void TrayIME::OnIMERefresh() {
    287   SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
    288   IMEInfoList list;
    289   IMEInfo current;
    290   IMEPropertyInfoList property_list;
    291   delegate->GetCurrentIME(&current);
    292   delegate->GetAvailableIMEList(&list);
    293   delegate->GetCurrentIMEProperties(&property_list);
    294 
    295   UpdateTrayLabel(current, list.size());
    296 
    297   if (default_)
    298     default_->UpdateLabel(current);
    299   if (detailed_)
    300     detailed_->Update(list, property_list);
    301 }
    302 
    303 }  // namespace ash
    304