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