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