tray_ime.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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_notification_view.h"
21#include "base/logging.h"
22#include "base/timer.h"
23#include "base/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 internal {
36
37namespace tray {
38
39class IMEDefaultView : public TrayItemMore {
40 public:
41  explicit IMEDefaultView(SystemTrayItem* owner)
42      : TrayItemMore(owner, true) {
43    ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
44
45    SetImage(bundle.GetImageNamed(
46        IDR_AURA_UBER_TRAY_IME).ToImageSkia());
47
48    IMEInfo info;
49    Shell::GetInstance()->system_tray_delegate()->GetCurrentIME(&info);
50    UpdateLabel(info);
51  }
52
53  virtual ~IMEDefaultView() {}
54
55  void UpdateLabel(const IMEInfo& info) {
56    SetLabel(info.name);
57    SetAccessibleName(info.name);
58  }
59
60 private:
61  DISALLOW_COPY_AND_ASSIGN(IMEDefaultView);
62};
63
64class IMEDetailedView : public TrayDetailsView,
65                        public ViewClickListener {
66 public:
67  IMEDetailedView(SystemTrayItem* owner, user::LoginStatus login)
68      : TrayDetailsView(owner),
69        login_(login) {
70    SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
71    IMEInfoList list;
72    delegate->GetAvailableIMEList(&list);
73    IMEPropertyInfoList property_list;
74    delegate->GetCurrentIMEProperties(&property_list);
75    Update(list, property_list);
76  }
77
78  virtual ~IMEDetailedView() {}
79
80  void Update(const IMEInfoList& list,
81              const IMEPropertyInfoList& property_list) {
82    Reset();
83
84    AppendIMEList(list);
85    if (!property_list.empty())
86      AppendIMEProperties(property_list);
87    if (login_ != user::LOGGED_IN_NONE && login_ != user::LOGGED_IN_LOCKED)
88      AppendSettings();
89    AppendHeaderEntry();
90
91    Layout();
92    SchedulePaint();
93  }
94
95 private:
96  void AppendHeaderEntry() {
97    CreateSpecialRow(IDS_ASH_STATUS_TRAY_IME, this);
98  }
99
100  void AppendIMEList(const IMEInfoList& list) {
101    ime_map_.clear();
102    CreateScrollableList();
103    for (size_t i = 0; i < list.size(); i++) {
104      HoverHighlightView* container = new HoverHighlightView(this);
105      container->AddLabel(list[i].name,
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          property_list[i].selected ? gfx::Font::BOLD : gfx::Font::NORMAL);
119      if (i == 0)
120        container->set_border(views::Border::CreateSolidSidedBorder(1, 0, 0, 0,
121        kBorderLightColor));
122      scroll_content()->AddChildView(container);
123      property_map_[container] = property_list[i].key;
124    }
125  }
126
127  void AppendSettings() {
128    HoverHighlightView* container = new HoverHighlightView(this);
129    container->AddLabel(ui::ResourceBundle::GetSharedInstance().
130        GetLocalizedString(IDS_ASH_STATUS_TRAY_IME_SETTINGS),
131        gfx::Font::NORMAL);
132    AddChildView(container);
133    settings_ = container;
134  }
135
136  // Overridden from ViewClickListener.
137  virtual void OnViewClicked(views::View* sender) OVERRIDE {
138    SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
139    if (sender == footer()->content()) {
140      owner()->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
141    } else if (sender == settings_) {
142      delegate->ShowIMESettings();
143    } else {
144      std::map<views::View*, std::string>::const_iterator ime_find;
145      ime_find = ime_map_.find(sender);
146      if (ime_find != ime_map_.end()) {
147        std::string ime_id = ime_find->second;
148        delegate->SwitchIME(ime_id);
149        GetWidget()->Close();
150      } else {
151        std::map<views::View*, std::string>::const_iterator prop_find;
152        prop_find = property_map_.find(sender);
153        if (prop_find != property_map_.end()) {
154          const std::string key = prop_find->second;
155          delegate->ActivateIMEProperty(key);
156          GetWidget()->Close();
157        }
158      }
159    }
160  }
161
162  user::LoginStatus login_;
163
164  std::map<views::View*, std::string> ime_map_;
165  std::map<views::View*, std::string> property_map_;
166  views::View* settings_;
167
168  DISALLOW_COPY_AND_ASSIGN(IMEDetailedView);
169};
170
171class IMENotificationView : public TrayNotificationView {
172 public:
173  explicit IMENotificationView(TrayIME* owner)
174      : TrayNotificationView(owner, IDR_AURA_UBER_TRAY_IME) {
175    InitView(GetLabel());
176  }
177
178  void UpdateLabel() {
179    RestartAutoCloseTimer();
180    UpdateView(GetLabel());
181  }
182
183  void StartAutoCloseTimer(int seconds) {
184    autoclose_.Stop();
185    autoclose_delay_ = seconds;
186    if (autoclose_delay_) {
187      autoclose_.Start(FROM_HERE,
188                       base::TimeDelta::FromSeconds(autoclose_delay_),
189                       this, &IMENotificationView::Close);
190    }
191  }
192
193  void StopAutoCloseTimer() {
194    autoclose_.Stop();
195  }
196
197  void RestartAutoCloseTimer() {
198    if (autoclose_delay_)
199      StartAutoCloseTimer(autoclose_delay_);
200  }
201
202  // Overridden from TrayNotificationView.
203  virtual void OnClickAction() OVERRIDE {
204    owner()->PopupDetailedView(0, true);
205  }
206
207 private:
208  void Close() {
209    owner()->HideNotificationView();
210  }
211
212  views::Label* GetLabel() {
213    SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
214    IMEInfo current;
215    delegate->GetCurrentIME(&current);
216
217    // TODO(zork): Use IDS_ASH_STATUS_TRAY_THIRD_PARTY_IME_TURNED_ON_BUBBLE for
218    // third party IMEs
219    views::Label* label = new views::Label(
220        l10n_util::GetStringFUTF16(
221            IDS_ASH_STATUS_TRAY_IME_TURNED_ON_BUBBLE,
222            current.medium_name));
223    label->SetMultiLine(true);
224    label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
225    return label;
226  }
227
228
229  int autoclose_delay_;
230  base::OneShotTimer<IMENotificationView> autoclose_;
231
232  DISALLOW_COPY_AND_ASSIGN(IMENotificationView);
233};
234
235
236}  // namespace tray
237
238TrayIME::TrayIME(SystemTray* system_tray)
239    : SystemTrayItem(system_tray),
240      tray_label_(NULL),
241      default_(NULL),
242      detailed_(NULL),
243      notification_(NULL),
244      message_shown_(false) {
245  Shell::GetInstance()->system_tray_notifier()->AddIMEObserver(this);
246}
247
248TrayIME::~TrayIME() {
249  Shell::GetInstance()->system_tray_notifier()->RemoveIMEObserver(this);
250}
251
252void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) {
253  if (tray_label_) {
254    if (current.third_party) {
255      tray_label_->label()->SetText(current.short_name + UTF8ToUTF16("*"));
256    } else {
257      tray_label_->label()->SetText(current.short_name);
258    }
259    tray_label_->SetVisible(count > 1);
260    SetTrayLabelItemBorder(tray_label_, system_tray()->shelf_alignment());
261    tray_label_->Layout();
262  }
263}
264
265views::View* TrayIME::CreateTrayView(user::LoginStatus status) {
266  CHECK(tray_label_ == NULL);
267  tray_label_ = new TrayItemView(this);
268  tray_label_->CreateLabel();
269  SetupLabelForTray(tray_label_->label());
270  return tray_label_;
271}
272
273views::View* TrayIME::CreateDefaultView(user::LoginStatus status) {
274  SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
275  IMEInfoList list;
276  IMEPropertyInfoList property_list;
277  delegate->GetAvailableIMEList(&list);
278  delegate->GetCurrentIMEProperties(&property_list);
279  if (list.size() <= 1 && property_list.size() <= 1)
280    return NULL;
281  CHECK(default_ == NULL);
282  default_ = new tray::IMEDefaultView(this);
283  return default_;
284}
285
286views::View* TrayIME::CreateDetailedView(user::LoginStatus status) {
287  CHECK(detailed_ == NULL);
288  detailed_ = new tray::IMEDetailedView(this, status);
289  return detailed_;
290}
291
292views::View* TrayIME::CreateNotificationView(user::LoginStatus status) {
293  DCHECK(notification_ == NULL);
294  notification_ = new tray::IMENotificationView(this);
295  notification_->StartAutoCloseTimer(kTrayPopupAutoCloseDelayForTextInSeconds);
296  return notification_;
297}
298
299void TrayIME::DestroyTrayView() {
300  tray_label_ = NULL;
301}
302
303void TrayIME::DestroyDefaultView() {
304  default_ = NULL;
305}
306
307void TrayIME::DestroyDetailedView() {
308  detailed_ = NULL;
309}
310
311void TrayIME::DestroyNotificationView() {
312  notification_ = NULL;
313}
314
315void TrayIME::UpdateAfterLoginStatusChange(user::LoginStatus status) {
316}
317
318void TrayIME::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
319  SetTrayLabelItemBorder(tray_label_, alignment);
320}
321
322void TrayIME::OnIMERefresh(bool show_message) {
323  SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
324  IMEInfoList list;
325  IMEInfo current;
326  IMEPropertyInfoList property_list;
327  delegate->GetCurrentIME(&current);
328  delegate->GetAvailableIMEList(&list);
329  delegate->GetCurrentIMEProperties(&property_list);
330
331  UpdateTrayLabel(current, list.size());
332
333  if (default_)
334    default_->UpdateLabel(current);
335  if (detailed_)
336    detailed_->Update(list, property_list);
337
338  if (list.size() > 1 && show_message) {
339    // If the notification is still visible, hide it and clear the flag so it is
340    // refreshed.
341    if (notification_) {
342      notification_->UpdateLabel();
343    } else if (!Shell::GetPrimaryRootWindowController()->shelf()->IsVisible() ||
344               !message_shown_) {
345      ShowNotificationView();
346      message_shown_ = true;
347    }
348  }
349}
350
351}  // namespace internal
352}  // namespace ash
353