tray_ime.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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/system_notifier.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/message_center/message_center.h"
31#include "ui/message_center/notification.h"
32#include "ui/message_center/notification_delegate.h"
33#include "ui/views/controls/label.h"
34#include "ui/views/layout/box_layout.h"
35#include "ui/views/widget/widget.h"
36
37using message_center::Notification;
38
39namespace {
40
41const char kIMENotificationId[] = "chrome://settings/ime";
42
43}  // namespace
44
45namespace ash {
46namespace internal {
47namespace tray {
48
49class IMEDefaultView : public TrayItemMore {
50 public:
51  explicit IMEDefaultView(SystemTrayItem* owner)
52      : TrayItemMore(owner, true) {
53    ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
54
55    SetImage(bundle.GetImageNamed(
56        IDR_AURA_UBER_TRAY_IME).ToImageSkia());
57
58    IMEInfo info;
59    Shell::GetInstance()->system_tray_delegate()->GetCurrentIME(&info);
60    UpdateLabel(info);
61  }
62
63  virtual ~IMEDefaultView() {}
64
65  void UpdateLabel(const IMEInfo& info) {
66    SetLabel(info.name);
67    SetAccessibleName(info.name);
68  }
69
70 private:
71  DISALLOW_COPY_AND_ASSIGN(IMEDefaultView);
72};
73
74class IMEDetailedView : public TrayDetailsView,
75                        public ViewClickListener {
76 public:
77  IMEDetailedView(SystemTrayItem* owner, user::LoginStatus login)
78      : TrayDetailsView(owner),
79        login_(login) {
80    SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
81    IMEInfoList list;
82    delegate->GetAvailableIMEList(&list);
83    IMEPropertyInfoList property_list;
84    delegate->GetCurrentIMEProperties(&property_list);
85    Update(list, property_list);
86  }
87
88  virtual ~IMEDetailedView() {}
89
90  void Update(const IMEInfoList& list,
91              const IMEPropertyInfoList& property_list) {
92    Reset();
93
94    AppendIMEList(list);
95    if (!property_list.empty())
96      AppendIMEProperties(property_list);
97    if (login_ != user::LOGGED_IN_NONE && login_ != user::LOGGED_IN_LOCKED)
98      AppendSettings();
99    AppendHeaderEntry();
100
101    Layout();
102    SchedulePaint();
103  }
104
105 private:
106  void AppendHeaderEntry() {
107    CreateSpecialRow(IDS_ASH_STATUS_TRAY_IME, this);
108  }
109
110  void AppendIMEList(const IMEInfoList& list) {
111    ime_map_.clear();
112    CreateScrollableList();
113    for (size_t i = 0; i < list.size(); i++) {
114      HoverHighlightView* container = new HoverHighlightView(this);
115      container->AddLabel(list[i].name,
116          list[i].selected ? gfx::Font::BOLD : gfx::Font::NORMAL);
117      scroll_content()->AddChildView(container);
118      ime_map_[container] = list[i].id;
119    }
120  }
121
122  void AppendIMEProperties(const IMEPropertyInfoList& property_list) {
123    property_map_.clear();
124    for (size_t i = 0; i < property_list.size(); i++) {
125      HoverHighlightView* container = new HoverHighlightView(this);
126      container->AddLabel(
127          property_list[i].name,
128          property_list[i].selected ? gfx::Font::BOLD : gfx::Font::NORMAL);
129      if (i == 0)
130        container->set_border(views::Border::CreateSolidSidedBorder(1, 0, 0, 0,
131        kBorderLightColor));
132      scroll_content()->AddChildView(container);
133      property_map_[container] = property_list[i].key;
134    }
135  }
136
137  void AppendSettings() {
138    HoverHighlightView* container = new HoverHighlightView(this);
139    container->AddLabel(ui::ResourceBundle::GetSharedInstance().
140        GetLocalizedString(IDS_ASH_STATUS_TRAY_IME_SETTINGS),
141        gfx::Font::NORMAL);
142    AddChildView(container);
143    settings_ = container;
144  }
145
146  // Overridden from ViewClickListener.
147  virtual void OnViewClicked(views::View* sender) OVERRIDE {
148    SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
149    if (sender == footer()->content()) {
150      TransitionToDefaultView();
151    } else if (sender == settings_) {
152      delegate->ShowIMESettings();
153    } else {
154      std::map<views::View*, std::string>::const_iterator ime_find;
155      ime_find = ime_map_.find(sender);
156      if (ime_find != ime_map_.end()) {
157        std::string ime_id = ime_find->second;
158        delegate->SwitchIME(ime_id);
159        GetWidget()->Close();
160      } else {
161        std::map<views::View*, std::string>::const_iterator prop_find;
162        prop_find = property_map_.find(sender);
163        if (prop_find != property_map_.end()) {
164          const std::string key = prop_find->second;
165          delegate->ActivateIMEProperty(key);
166          GetWidget()->Close();
167        }
168      }
169    }
170  }
171
172  user::LoginStatus login_;
173
174  std::map<views::View*, std::string> ime_map_;
175  std::map<views::View*, std::string> property_map_;
176  views::View* settings_;
177
178  DISALLOW_COPY_AND_ASSIGN(IMEDetailedView);
179};
180
181}  // namespace tray
182
183TrayIME::TrayIME(SystemTray* system_tray)
184    : SystemTrayItem(system_tray),
185      tray_label_(NULL),
186      default_(NULL),
187      detailed_(NULL),
188      message_shown_(false) {
189  Shell::GetInstance()->system_tray_notifier()->AddIMEObserver(this);
190}
191
192TrayIME::~TrayIME() {
193  Shell::GetInstance()->system_tray_notifier()->RemoveIMEObserver(this);
194  message_center::MessageCenter::Get()->RemoveNotification(
195      kIMENotificationId, false /* by_user */);
196}
197
198void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) {
199  if (tray_label_) {
200    if (current.third_party) {
201      tray_label_->label()->SetText(current.short_name + UTF8ToUTF16("*"));
202    } else {
203      tray_label_->label()->SetText(current.short_name);
204    }
205    tray_label_->SetVisible(count > 1);
206    SetTrayLabelItemBorder(tray_label_, system_tray()->shelf_alignment());
207    tray_label_->Layout();
208  }
209}
210
211void TrayIME::UpdateOrCreateNotification() {
212  message_center::MessageCenter* message_center =
213      message_center::MessageCenter::Get();
214
215  if (!message_center->HasNotification(kIMENotificationId) && message_shown_)
216    return;
217
218  SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
219  IMEInfo current;
220  delegate->GetCurrentIME(&current);
221
222  ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
223  scoped_ptr<Notification> notification(new Notification(
224      message_center::NOTIFICATION_TYPE_SIMPLE,
225      kIMENotificationId,
226      // TODO(zork): Use IDS_ASH_STATUS_TRAY_THIRD_PARTY_IME_TURNED_ON_BUBBLE
227      // for third party IMEs
228      l10n_util::GetStringFUTF16(
229          IDS_ASH_STATUS_TRAY_IME_TURNED_ON_BUBBLE,
230          current.medium_name),
231      base::string16(),  // message
232      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_IME),
233      base::string16(),  // display_source
234      message_center::NotifierId(
235          message_center::NotifierId::SYSTEM_COMPONENT,
236          system_notifier::kNotifierInputMethod),
237      message_center::RichNotificationData(),
238      new message_center::HandleNotificationClickedDelegate(
239          base::Bind(&TrayIME::PopupDetailedView,
240                     base::Unretained(this), 0, true))));
241  message_center->AddNotification(notification.Pass());
242  message_shown_ = true;
243}
244
245views::View* TrayIME::CreateTrayView(user::LoginStatus status) {
246  CHECK(tray_label_ == NULL);
247  tray_label_ = new TrayItemView(this);
248  tray_label_->CreateLabel();
249  SetupLabelForTray(tray_label_->label());
250  // Hide IME tray when it is created, it will be updated when it is notified
251  // for IME refresh event.
252  tray_label_->SetVisible(false);
253  return tray_label_;
254}
255
256views::View* TrayIME::CreateDefaultView(user::LoginStatus status) {
257  SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
258  IMEInfoList list;
259  IMEPropertyInfoList property_list;
260  delegate->GetAvailableIMEList(&list);
261  delegate->GetCurrentIMEProperties(&property_list);
262  if (list.size() <= 1 && property_list.size() <= 1)
263    return NULL;
264  CHECK(default_ == NULL);
265  default_ = new tray::IMEDefaultView(this);
266  return default_;
267}
268
269views::View* TrayIME::CreateDetailedView(user::LoginStatus status) {
270  CHECK(detailed_ == NULL);
271  detailed_ = new tray::IMEDetailedView(this, status);
272  return detailed_;
273}
274
275void TrayIME::DestroyTrayView() {
276  tray_label_ = NULL;
277}
278
279void TrayIME::DestroyDefaultView() {
280  default_ = NULL;
281}
282
283void TrayIME::DestroyDetailedView() {
284  detailed_ = NULL;
285}
286
287void TrayIME::UpdateAfterLoginStatusChange(user::LoginStatus status) {
288}
289
290void TrayIME::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
291  SetTrayLabelItemBorder(tray_label_, alignment);
292  tray_label_->Layout();
293}
294
295void TrayIME::OnIMERefresh(bool show_message) {
296  SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
297  IMEInfoList list;
298  IMEInfo current;
299  IMEPropertyInfoList property_list;
300  delegate->GetCurrentIME(&current);
301  delegate->GetAvailableIMEList(&list);
302  delegate->GetCurrentIMEProperties(&property_list);
303
304  UpdateTrayLabel(current, list.size());
305
306  if (default_)
307    default_->UpdateLabel(current);
308  if (detailed_)
309    detailed_->Update(list, property_list);
310
311  if (list.size() > 1 && show_message)
312    UpdateOrCreateNotification();
313}
314
315}  // namespace internal
316}  // namespace ash
317