1 // Copyright (c) 2011 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 "chrome/browser/chromeos/status/input_method_menu_button.h"
6
7 #include <string>
8
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/chromeos/cros/cros_library.h"
11 #include "chrome/browser/chromeos/input_method/input_method_util.h"
12 #include "chrome/browser/chromeos/status/status_area_host.h"
13 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_list.h"
17 #include "chrome/browser/ui/browser_window.h"
18 #include "views/window/window.h"
19
20 namespace {
21
22 // Returns PrefService object associated with |host|. Returns NULL if we are NOT
23 // within a browser.
GetPrefService(chromeos::StatusAreaHost * host)24 PrefService* GetPrefService(chromeos::StatusAreaHost* host) {
25 if (host->GetProfile()) {
26 return host->GetProfile()->GetPrefs();
27 }
28 return NULL;
29 }
30
31 // A class which implements interfaces of chromeos::InputMethodMenu. This class
32 // is just for avoiding multiple inheritance.
33 class MenuImpl : public chromeos::InputMethodMenu {
34 public:
MenuImpl(chromeos::InputMethodMenuButton * button,PrefService * pref_service,chromeos::StatusAreaHost::ScreenMode screen_mode)35 MenuImpl(chromeos::InputMethodMenuButton* button,
36 PrefService* pref_service,
37 chromeos::StatusAreaHost::ScreenMode screen_mode)
38 : InputMethodMenu(pref_service, screen_mode, false), button_(button) {}
39
40 private:
41 // InputMethodMenu implementation.
UpdateUI(const std::string & input_method_id,const std::wstring & name,const std::wstring & tooltip,size_t num_active_input_methods)42 virtual void UpdateUI(const std::string& input_method_id,
43 const std::wstring& name,
44 const std::wstring& tooltip,
45 size_t num_active_input_methods) {
46 button_->UpdateUI(input_method_id, name, tooltip, num_active_input_methods);
47 }
ShouldSupportConfigUI()48 virtual bool ShouldSupportConfigUI() {
49 return button_->ShouldSupportConfigUI();
50 }
OpenConfigUI()51 virtual void OpenConfigUI() {
52 button_->OpenConfigUI();
53 }
54 // The UI (views button) to which this class delegates all requests.
55 chromeos::InputMethodMenuButton* button_;
56
57 DISALLOW_COPY_AND_ASSIGN(MenuImpl);
58 };
59
60 } // namespace
61
62 namespace chromeos {
63
64 ////////////////////////////////////////////////////////////////////////////////
65 // InputMethodMenuButton
66
InputMethodMenuButton(StatusAreaHost * host)67 InputMethodMenuButton::InputMethodMenuButton(StatusAreaHost* host)
68 : StatusAreaButton(host, this),
69 menu_(new MenuImpl(this, GetPrefService(host), host->GetScreenMode())) {
70 UpdateUIFromCurrentInputMethod();
71 }
72
73 ////////////////////////////////////////////////////////////////////////////////
74 // views::View implementation:
75
GetPreferredSize()76 gfx::Size InputMethodMenuButton::GetPreferredSize() {
77 // If not enabled, then hide this button.
78 if (!IsEnabled()) {
79 return gfx::Size(0, 0);
80 }
81 return StatusAreaButton::GetPreferredSize();
82 }
83
OnLocaleChanged()84 void InputMethodMenuButton::OnLocaleChanged() {
85 input_method::OnLocaleChanged();
86 UpdateUIFromCurrentInputMethod();
87 Layout();
88 SchedulePaint();
89 }
90
91 ////////////////////////////////////////////////////////////////////////////////
92 // views::ViewMenuDelegate implementation:
93
RunMenu(views::View * unused_source,const gfx::Point & pt)94 void InputMethodMenuButton::RunMenu(views::View* unused_source,
95 const gfx::Point& pt) {
96 menu_->RunMenu(unused_source, pt);
97 }
98
WindowIsActive()99 bool InputMethodMenuButton::WindowIsActive() {
100 Browser* active_browser = BrowserList::GetLastActive();
101 if (!active_browser) {
102 // Can't get an active browser. Just return true, which is safer.
103 return true;
104 }
105 BrowserWindow* active_window = active_browser->window();
106 const views::Window* current_window = GetWindow();
107 if (!active_window || !current_window) {
108 // Can't get an active or current window. Just return true as well.
109 return true;
110 }
111 return active_window->GetNativeHandle() == current_window->GetNativeWindow();
112 }
113
UpdateUI(const std::string & input_method_id,const std::wstring & name,const std::wstring & tooltip,size_t num_active_input_methods)114 void InputMethodMenuButton::UpdateUI(const std::string& input_method_id,
115 const std::wstring& name,
116 const std::wstring& tooltip,
117 size_t num_active_input_methods) {
118 // Hide the button only if there is only one input method, and the input
119 // method is a XKB keyboard layout. We don't hide the button for other
120 // types of input methods as these might have intra input method modes,
121 // like Hiragana and Katakana modes in Japanese input methods.
122 if (num_active_input_methods == 1 &&
123 input_method::IsKeyboardLayout(input_method_id) &&
124 host_->GetScreenMode() == StatusAreaHost::kBrowserMode) {
125 // As the disabled color is set to invisible, disabling makes the
126 // button disappear.
127 SetEnabled(false);
128 SetTooltipText(L""); // remove tooltip
129 } else {
130 SetEnabled(true);
131 SetTooltipText(tooltip);
132 }
133 SetText(name);
134
135 if (WindowIsActive()) {
136 // We don't call these functions if the |current_window| is not active since
137 // the calls are relatively expensive (crosbug.com/9206). Please note that
138 // PrepareMenu() is necessary for fixing crosbug.com/7522 when the window
139 // is active.
140 menu_->PrepareMenu();
141 SchedulePaint();
142 }
143
144 // TODO(yusukes): For a window which isn't on top, probably it's better to
145 // update the texts when the window gets activated because SetTooltipText()
146 // and SetText() are also expensive.
147 }
148
OpenConfigUI()149 void InputMethodMenuButton::OpenConfigUI() {
150 host_->OpenButtonOptions(this); // ask browser to open the WebUI page.
151 }
152
ShouldSupportConfigUI()153 bool InputMethodMenuButton::ShouldSupportConfigUI() {
154 return host_->ShouldOpenButtonOptions(this);
155 }
156
UpdateUIFromCurrentInputMethod()157 void InputMethodMenuButton::UpdateUIFromCurrentInputMethod() {
158 chromeos::InputMethodLibrary* input_method_library =
159 chromeos::CrosLibrary::Get()->GetInputMethodLibrary();
160 const InputMethodDescriptor& input_method =
161 input_method_library->current_input_method();
162 const std::wstring name = InputMethodMenu::GetTextForIndicator(input_method);
163 const std::wstring tooltip = InputMethodMenu::GetTextForMenu(input_method);
164 const size_t num_active_input_methods =
165 input_method_library->GetNumActiveInputMethods();
166 UpdateUI(input_method.id, name, tooltip, num_active_input_methods);
167 }
168
169 } // namespace chromeos
170