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/session/session_state_delegate.h"
     12 #include "ash/shelf/shelf_widget.h"
     13 #include "ash/shell.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/accessibility/ax_enums.h"
     28 #include "ui/accessibility/ax_view_state.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     bool userAddingRunning = ash::Shell::GetInstance()
    118                                  ->session_state_delegate()
    119                                  ->IsInSecondaryLoginScreen();
    120 
    121     if (login_ != user::LOGGED_IN_NONE && login_ != user::LOGGED_IN_LOCKED &&
    122         !userAddingRunning)
    123       AppendSettings();
    124     AppendHeaderEntry();
    125 
    126     Layout();
    127     SchedulePaint();
    128   }
    129 
    130  private:
    131   void AppendHeaderEntry() {
    132     CreateSpecialRow(IDS_ASH_STATUS_TRAY_IME, this);
    133   }
    134 
    135   void AppendIMEList(const IMEInfoList& list) {
    136     ime_map_.clear();
    137     CreateScrollableList();
    138     for (size_t i = 0; i < list.size(); i++) {
    139       HoverHighlightView* container = new SelectableHoverHighlightView(
    140           this, list[i].name, list[i].selected);
    141       scroll_content()->AddChildView(container);
    142       ime_map_[container] = list[i].id;
    143     }
    144   }
    145 
    146   void AppendIMEProperties(const IMEPropertyInfoList& property_list) {
    147     property_map_.clear();
    148     for (size_t i = 0; i < property_list.size(); i++) {
    149       HoverHighlightView* container = new SelectableHoverHighlightView(
    150           this, property_list[i].name, property_list[i].selected);
    151       if (i == 0)
    152         container->SetBorder(views::Border::CreateSolidSidedBorder(
    153             1, 0, 0, 0, kBorderLightColor));
    154       scroll_content()->AddChildView(container);
    155       property_map_[container] = property_list[i].key;
    156     }
    157   }
    158 
    159   void AppendSettings() {
    160     HoverHighlightView* container = new HoverHighlightView(this);
    161     container->AddLabel(
    162         ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
    163             IDS_ASH_STATUS_TRAY_IME_SETTINGS),
    164         gfx::ALIGN_LEFT,
    165         gfx::Font::NORMAL);
    166     AddChildView(container);
    167     settings_ = container;
    168   }
    169 
    170   // Overridden from ViewClickListener.
    171   virtual void OnViewClicked(views::View* sender) OVERRIDE {
    172     SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
    173     if (sender == footer()->content()) {
    174       TransitionToDefaultView();
    175     } else if (sender == settings_) {
    176       Shell::GetInstance()->metrics()->RecordUserMetricsAction(
    177           ash::UMA_STATUS_AREA_IME_SHOW_DETAILED);
    178       delegate->ShowIMESettings();
    179     } else {
    180       std::map<views::View*, std::string>::const_iterator ime_find;
    181       ime_find = ime_map_.find(sender);
    182       if (ime_find != ime_map_.end()) {
    183         Shell::GetInstance()->metrics()->RecordUserMetricsAction(
    184             ash::UMA_STATUS_AREA_IME_SWITCH_MODE);
    185         std::string ime_id = ime_find->second;
    186         delegate->SwitchIME(ime_id);
    187         GetWidget()->Close();
    188       } else {
    189         std::map<views::View*, std::string>::const_iterator prop_find;
    190         prop_find = property_map_.find(sender);
    191         if (prop_find != property_map_.end()) {
    192           const std::string key = prop_find->second;
    193           delegate->ActivateIMEProperty(key);
    194           GetWidget()->Close();
    195         }
    196       }
    197     }
    198   }
    199 
    200   user::LoginStatus login_;
    201 
    202   std::map<views::View*, std::string> ime_map_;
    203   std::map<views::View*, std::string> property_map_;
    204   views::View* settings_;
    205 
    206   DISALLOW_COPY_AND_ASSIGN(IMEDetailedView);
    207 };
    208 
    209 }  // namespace tray
    210 
    211 TrayIME::TrayIME(SystemTray* system_tray)
    212     : SystemTrayItem(system_tray),
    213       tray_label_(NULL),
    214       default_(NULL),
    215       detailed_(NULL) {
    216   Shell::GetInstance()->system_tray_notifier()->AddIMEObserver(this);
    217 }
    218 
    219 TrayIME::~TrayIME() {
    220   Shell::GetInstance()->system_tray_notifier()->RemoveIMEObserver(this);
    221 }
    222 
    223 void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) {
    224   if (tray_label_) {
    225     bool visible = count > 1;
    226     tray_label_->SetVisible(visible);
    227     // Do not change label before hiding because this change is noticeable.
    228     if (!visible)
    229       return;
    230     if (current.third_party) {
    231       tray_label_->label()->SetText(
    232           current.short_name + base::UTF8ToUTF16("*"));
    233     } else {
    234       tray_label_->label()->SetText(current.short_name);
    235     }
    236     SetTrayLabelItemBorder(tray_label_, system_tray()->shelf_alignment());
    237     tray_label_->Layout();
    238   }
    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   tray_label_->Layout();
    289 }
    290 
    291 void TrayIME::OnIMERefresh() {
    292   SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
    293   IMEInfoList list;
    294   IMEInfo current;
    295   IMEPropertyInfoList property_list;
    296   delegate->GetCurrentIME(&current);
    297   delegate->GetAvailableIMEList(&list);
    298   delegate->GetCurrentIMEProperties(&property_list);
    299 
    300   UpdateTrayLabel(current, list.size());
    301 
    302   if (default_)
    303     default_->UpdateLabel(current);
    304   if (detailed_)
    305     detailed_->Update(list, property_list);
    306 }
    307 
    308 }  // namespace ash
    309