• 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/session/session_state_delegate.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.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/accessibility/ax_enums.h"
28 #include "ui/accessibility/ax_view_state.h"
29 #include "ui/base/resource/resource_bundle.h"
30 #include "ui/gfx/font.h"
31 #include "ui/gfx/image/image.h"
32 #include "ui/views/controls/label.h"
33 #include "ui/views/layout/box_layout.h"
34 #include "ui/views/widget/widget.h"
35 
36 namespace ash {
37 namespace tray {
38 
39 // A |HoverHighlightView| that uses bold or normal font depending on whetehr
40 // it is selected.  This view exposes itself as a checkbox to the accessibility
41 // framework.
42 class SelectableHoverHighlightView : public HoverHighlightView {
43  public:
SelectableHoverHighlightView(ViewClickListener * listener,const base::string16 & label,bool selected)44   SelectableHoverHighlightView(ViewClickListener* listener,
45                                const base::string16& label,
46                                bool selected)
47       : HoverHighlightView(listener), selected_(selected) {
48     AddLabel(
49         label, gfx::ALIGN_LEFT, selected ? gfx::Font::BOLD : gfx::Font::NORMAL);
50   }
51 
~SelectableHoverHighlightView()52   virtual ~SelectableHoverHighlightView() {}
53 
54  protected:
55   // Overridden from views::View.
GetAccessibleState(ui::AXViewState * state)56   virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE {
57     HoverHighlightView::GetAccessibleState(state);
58     state->role = ui::AX_ROLE_CHECK_BOX;
59     if (selected_)
60       state->AddStateFlag(ui::AX_STATE_CHECKED);
61   }
62 
63  private:
64   bool selected_;
65 
66   DISALLOW_COPY_AND_ASSIGN(SelectableHoverHighlightView);
67 };
68 
69 class IMEDefaultView : public TrayItemMore {
70  public:
IMEDefaultView(SystemTrayItem * owner)71   explicit IMEDefaultView(SystemTrayItem* owner)
72       : TrayItemMore(owner, true) {
73     ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
74 
75     SetImage(bundle.GetImageNamed(
76         IDR_AURA_UBER_TRAY_IME).ToImageSkia());
77 
78     IMEInfo info;
79     Shell::GetInstance()->system_tray_delegate()->GetCurrentIME(&info);
80     UpdateLabel(info);
81   }
82 
~IMEDefaultView()83   virtual ~IMEDefaultView() {}
84 
UpdateLabel(const IMEInfo & info)85   void UpdateLabel(const IMEInfo& info) {
86     SetLabel(info.name);
87     SetAccessibleName(info.name);
88   }
89 
90  private:
91   DISALLOW_COPY_AND_ASSIGN(IMEDefaultView);
92 };
93 
94 class IMEDetailedView : public TrayDetailsView,
95                         public ViewClickListener {
96  public:
IMEDetailedView(SystemTrayItem * owner,user::LoginStatus login)97   IMEDetailedView(SystemTrayItem* owner, user::LoginStatus login)
98       : TrayDetailsView(owner),
99         login_(login) {
100     SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
101     IMEInfoList list;
102     delegate->GetAvailableIMEList(&list);
103     IMEPropertyInfoList property_list;
104     delegate->GetCurrentIMEProperties(&property_list);
105     Update(list, property_list);
106   }
107 
~IMEDetailedView()108   virtual ~IMEDetailedView() {}
109 
Update(const IMEInfoList & list,const IMEPropertyInfoList & property_list)110   void Update(const IMEInfoList& list,
111               const IMEPropertyInfoList& property_list) {
112     Reset();
113 
114     AppendIMEList(list);
115     if (!property_list.empty())
116       AppendIMEProperties(property_list);
117     bool userAddingRunning = ash::Shell::GetInstance()
118                                  ->session_state_delegate()
119                                  ->IsInSecondaryLoginScreen();
120 
121     if (login_ != user::LOGGED_IN_NONE && login_ != user::LOGGED_IN_LOCKED &&
122         !userAddingRunning)
123       AppendSettings();
124     AppendHeaderEntry();
125 
126     Layout();
127     SchedulePaint();
128   }
129 
130  private:
AppendHeaderEntry()131   void AppendHeaderEntry() {
132     CreateSpecialRow(IDS_ASH_STATUS_TRAY_IME, this);
133   }
134 
AppendIMEList(const IMEInfoList & list)135   void AppendIMEList(const IMEInfoList& list) {
136     ime_map_.clear();
137     CreateScrollableList();
138     for (size_t i = 0; i < list.size(); i++) {
139       HoverHighlightView* container = new SelectableHoverHighlightView(
140           this, list[i].name, list[i].selected);
141       scroll_content()->AddChildView(container);
142       ime_map_[container] = list[i].id;
143     }
144   }
145 
AppendIMEProperties(const IMEPropertyInfoList & property_list)146   void AppendIMEProperties(const IMEPropertyInfoList& property_list) {
147     property_map_.clear();
148     for (size_t i = 0; i < property_list.size(); i++) {
149       HoverHighlightView* container = new SelectableHoverHighlightView(
150           this, property_list[i].name, property_list[i].selected);
151       if (i == 0)
152         container->SetBorder(views::Border::CreateSolidSidedBorder(
153             1, 0, 0, 0, kBorderLightColor));
154       scroll_content()->AddChildView(container);
155       property_map_[container] = property_list[i].key;
156     }
157   }
158 
AppendSettings()159   void AppendSettings() {
160     HoverHighlightView* container = new HoverHighlightView(this);
161     container->AddLabel(
162         ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
163             IDS_ASH_STATUS_TRAY_IME_SETTINGS),
164         gfx::ALIGN_LEFT,
165         gfx::Font::NORMAL);
166     AddChildView(container);
167     settings_ = container;
168   }
169 
170   // Overridden from ViewClickListener.
OnViewClicked(views::View * sender)171   virtual void OnViewClicked(views::View* sender) OVERRIDE {
172     SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
173     if (sender == footer()->content()) {
174       TransitionToDefaultView();
175     } else if (sender == settings_) {
176       Shell::GetInstance()->metrics()->RecordUserMetricsAction(
177           ash::UMA_STATUS_AREA_IME_SHOW_DETAILED);
178       delegate->ShowIMESettings();
179     } else {
180       std::map<views::View*, std::string>::const_iterator ime_find;
181       ime_find = ime_map_.find(sender);
182       if (ime_find != ime_map_.end()) {
183         Shell::GetInstance()->metrics()->RecordUserMetricsAction(
184             ash::UMA_STATUS_AREA_IME_SWITCH_MODE);
185         std::string ime_id = ime_find->second;
186         delegate->SwitchIME(ime_id);
187         GetWidget()->Close();
188       } else {
189         std::map<views::View*, std::string>::const_iterator prop_find;
190         prop_find = property_map_.find(sender);
191         if (prop_find != property_map_.end()) {
192           const std::string key = prop_find->second;
193           delegate->ActivateIMEProperty(key);
194           GetWidget()->Close();
195         }
196       }
197     }
198   }
199 
200   user::LoginStatus login_;
201 
202   std::map<views::View*, std::string> ime_map_;
203   std::map<views::View*, std::string> property_map_;
204   views::View* settings_;
205 
206   DISALLOW_COPY_AND_ASSIGN(IMEDetailedView);
207 };
208 
209 }  // namespace tray
210 
TrayIME(SystemTray * system_tray)211 TrayIME::TrayIME(SystemTray* system_tray)
212     : SystemTrayItem(system_tray),
213       tray_label_(NULL),
214       default_(NULL),
215       detailed_(NULL) {
216   Shell::GetInstance()->system_tray_notifier()->AddIMEObserver(this);
217 }
218 
~TrayIME()219 TrayIME::~TrayIME() {
220   Shell::GetInstance()->system_tray_notifier()->RemoveIMEObserver(this);
221 }
222 
UpdateTrayLabel(const IMEInfo & current,size_t count)223 void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) {
224   if (tray_label_) {
225     bool visible = count > 1;
226     tray_label_->SetVisible(visible);
227     // Do not change label before hiding because this change is noticeable.
228     if (!visible)
229       return;
230     if (current.third_party) {
231       tray_label_->label()->SetText(
232           current.short_name + base::UTF8ToUTF16("*"));
233     } else {
234       tray_label_->label()->SetText(current.short_name);
235     }
236     SetTrayLabelItemBorder(tray_label_, system_tray()->shelf_alignment());
237     tray_label_->Layout();
238   }
239 }
240 
CreateTrayView(user::LoginStatus status)241 views::View* TrayIME::CreateTrayView(user::LoginStatus status) {
242   CHECK(tray_label_ == NULL);
243   tray_label_ = new TrayItemView(this);
244   tray_label_->CreateLabel();
245   SetupLabelForTray(tray_label_->label());
246   // Hide IME tray when it is created, it will be updated when it is notified
247   // for IME refresh event.
248   tray_label_->SetVisible(false);
249   return tray_label_;
250 }
251 
CreateDefaultView(user::LoginStatus status)252 views::View* TrayIME::CreateDefaultView(user::LoginStatus status) {
253   SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
254   IMEInfoList list;
255   IMEPropertyInfoList property_list;
256   delegate->GetAvailableIMEList(&list);
257   delegate->GetCurrentIMEProperties(&property_list);
258   if (list.size() <= 1 && property_list.size() <= 1)
259     return NULL;
260   CHECK(default_ == NULL);
261   default_ = new tray::IMEDefaultView(this);
262   return default_;
263 }
264 
CreateDetailedView(user::LoginStatus status)265 views::View* TrayIME::CreateDetailedView(user::LoginStatus status) {
266   CHECK(detailed_ == NULL);
267   detailed_ = new tray::IMEDetailedView(this, status);
268   return detailed_;
269 }
270 
DestroyTrayView()271 void TrayIME::DestroyTrayView() {
272   tray_label_ = NULL;
273 }
274 
DestroyDefaultView()275 void TrayIME::DestroyDefaultView() {
276   default_ = NULL;
277 }
278 
DestroyDetailedView()279 void TrayIME::DestroyDetailedView() {
280   detailed_ = NULL;
281 }
282 
UpdateAfterLoginStatusChange(user::LoginStatus status)283 void TrayIME::UpdateAfterLoginStatusChange(user::LoginStatus status) {
284 }
285 
UpdateAfterShelfAlignmentChange(ShelfAlignment alignment)286 void TrayIME::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
287   SetTrayLabelItemBorder(tray_label_, alignment);
288   tray_label_->Layout();
289 }
290 
OnIMERefresh()291 void TrayIME::OnIMERefresh() {
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 
308 }  // namespace ash
309