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