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