cros_language_options_handler.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 "chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.h"
6
7#include <map>
8#include <set>
9#include <vector>
10
11#include "base/bind.h"
12#include "base/bind_helpers.h"
13#include "base/i18n/rtl.h"
14#include "base/stringprintf.h"
15#include "base/utf_string_conversions.h"
16#include "base/values.h"
17#include "chrome/app/chrome_command_ids.h"
18#include "chrome/browser/browser_process.h"
19#include "chrome/browser/chromeos/input_method/input_method_configuration.h"
20#include "chrome/browser/chromeos/input_method/input_method_manager.h"
21#include "chrome/browser/chromeos/input_method/input_method_util.h"
22#include "chrome/browser/lifetime/application_lifetime.h"
23#include "chrome/browser/profiles/profile.h"
24#include "chrome/browser/ui/browser.h"
25#include "chrome/browser/ui/browser_finder.h"
26#include "content/public/browser/navigation_controller.h"
27#include "content/public/browser/user_metrics.h"
28#include "content/public/browser/web_contents.h"
29#include "grit/chromium_strings.h"
30#include "grit/generated_resources.h"
31#include "ui/base/l10n/l10n_util.h"
32
33using content::UserMetricsAction;
34
35namespace chromeos {
36namespace options {
37
38CrosLanguageOptionsHandler::CrosLanguageOptionsHandler() {
39}
40
41CrosLanguageOptionsHandler::~CrosLanguageOptionsHandler() {
42}
43
44void CrosLanguageOptionsHandler::GetLocalizedValues(
45    DictionaryValue* localized_strings) {
46  ::options::LanguageOptionsHandlerCommon::GetLocalizedValues(
47      localized_strings);
48
49  RegisterTitle(localized_strings, "languagePage",
50                IDS_OPTIONS_SETTINGS_LANGUAGES_AND_INPUT_DIALOG_TITLE);
51  localized_strings->SetString("ok_button", l10n_util::GetStringUTF16(IDS_OK));
52  localized_strings->SetString("configure",
53      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE));
54  localized_strings->SetString("input_method",
55      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD));
56  localized_strings->SetString("please_add_another_input_method",
57      l10n_util::GetStringUTF16(
58          IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_INPUT_METHOD));
59  localized_strings->SetString("input_method_instructions",
60      l10n_util::GetStringUTF16(
61          IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_INSTRUCTIONS));
62  localized_strings->SetString("switch_input_methods_hint",
63      l10n_util::GetStringUTF16(
64          IDS_OPTIONS_SETTINGS_LANGUAGES_SWITCH_INPUT_METHODS_HINT));
65  localized_strings->SetString("select_previous_input_method_hint",
66      l10n_util::GetStringUTF16(
67          IDS_OPTIONS_SETTINGS_LANGUAGES_SELECT_PREVIOUS_INPUT_METHOD_HINT));
68  localized_strings->SetString("restart_button",
69      l10n_util::GetStringUTF16(
70          IDS_OPTIONS_SETTINGS_LANGUAGES_SIGN_OUT_BUTTON));
71  localized_strings->SetString("extension_ime_label",
72      l10n_util::GetStringUTF16(
73          IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_EXTENSION_IME));
74  localized_strings->SetString("extension_ime_description",
75      l10n_util::GetStringUTF16(
76          IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_EXTENSION_DESCRIPTION));
77
78  input_method::InputMethodManager* manager =
79      input_method::GetInputMethodManager();
80  // GetSupportedInputMethods() never return NULL.
81  scoped_ptr<input_method::InputMethodDescriptors> descriptors(
82      manager->GetSupportedInputMethods());
83  localized_strings->Set("languageList", GetLanguageList(*descriptors));
84  localized_strings->Set("inputMethodList", GetInputMethodList(*descriptors));
85  localized_strings->Set("extensionImeList", GetExtensionImeList());
86}
87
88void CrosLanguageOptionsHandler::RegisterMessages() {
89  ::options::LanguageOptionsHandlerCommon::RegisterMessages();
90
91  web_ui()->RegisterMessageCallback("inputMethodDisable",
92      base::Bind(&CrosLanguageOptionsHandler::InputMethodDisableCallback,
93                 base::Unretained(this)));
94  web_ui()->RegisterMessageCallback("inputMethodEnable",
95      base::Bind(&CrosLanguageOptionsHandler::InputMethodEnableCallback,
96                 base::Unretained(this)));
97  web_ui()->RegisterMessageCallback("inputMethodOptionsOpen",
98      base::Bind(&CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback,
99                 base::Unretained(this)));
100  web_ui()->RegisterMessageCallback("uiLanguageRestart",
101      base::Bind(&CrosLanguageOptionsHandler::RestartCallback,
102                 base::Unretained(this)));
103}
104
105ListValue* CrosLanguageOptionsHandler::GetInputMethodList(
106    const input_method::InputMethodDescriptors& descriptors) {
107  input_method::InputMethodManager* manager =
108      input_method::GetInputMethodManager();
109
110  ListValue* input_method_list = new ListValue();
111
112  for (size_t i = 0; i < descriptors.size(); ++i) {
113    const input_method::InputMethodDescriptor& descriptor =
114        descriptors[i];
115    const std::string language_code = descriptor.language_code();
116    const std::string display_name =
117        manager->GetInputMethodUtil()->GetInputMethodDisplayNameFromId(
118            descriptor.id());
119    DictionaryValue* dictionary = new DictionaryValue();
120    dictionary->SetString("id", descriptor.id());
121    dictionary->SetString("displayName", display_name);
122
123    // One input method can be associated with multiple languages, hence
124    // we use a dictionary here.
125    DictionaryValue* language_codes = new DictionaryValue();
126    language_codes->SetBoolean(language_code, true);
127    // Check extra languages to see if there are languages associated with
128    // this input method. If these are present, add these.
129    const std::vector<std::string> extra_language_codes =
130        manager->GetInputMethodUtil()->GetExtraLanguageCodesFromId(
131            descriptor.id());
132    for (size_t j = 0; j < extra_language_codes.size(); ++j)
133      language_codes->SetBoolean(extra_language_codes[j], true);
134    dictionary->Set("languageCodeSet", language_codes);
135
136    input_method_list->Append(dictionary);
137  }
138
139  return input_method_list;
140}
141
142ListValue* CrosLanguageOptionsHandler::GetLanguageList(
143    const input_method::InputMethodDescriptors& descriptors) {
144  std::set<std::string> language_codes;
145  // Collect the language codes from the supported input methods.
146  for (size_t i = 0; i < descriptors.size(); ++i) {
147    const input_method::InputMethodDescriptor& descriptor = descriptors[i];
148    const std::string language_code = descriptor.language_code();
149    language_codes.insert(language_code);
150  }
151  // Collect the language codes from extra languages.
152  const std::vector<std::string> extra_language_codes =
153      input_method::GetInputMethodManager()->GetInputMethodUtil()
154          ->GetExtraLanguageCodeList();
155  for (size_t i = 0; i < extra_language_codes.size(); ++i)
156    language_codes.insert(extra_language_codes[i]);
157
158  // Map of display name -> {language code, native_display_name}.
159  // In theory, we should be able to create a map that is sorted by
160  // display names using ICU comparator, but doing it is hard, thus we'll
161  // use an auxiliary vector to achieve the same result.
162  typedef std::pair<std::string, string16> LanguagePair;
163  typedef std::map<string16, LanguagePair> LanguageMap;
164  LanguageMap language_map;
165  // The auxiliary vector mentioned above.
166  std::vector<string16> display_names;
167
168  // Build the list of display names, and build the language map.
169  for (std::set<std::string>::const_iterator iter = language_codes.begin();
170       iter != language_codes.end(); ++iter) {
171    input_method::InputMethodUtil* input_method_util =
172        input_method::GetInputMethodManager()->GetInputMethodUtil();
173    const string16 display_name =
174        input_method_util->GetLanguageDisplayNameFromCode(*iter);
175    const string16 native_display_name =
176        input_method::InputMethodUtil::GetLanguageNativeDisplayNameFromCode(
177            *iter);
178    display_names.push_back(display_name);
179    language_map[display_name] =
180        std::make_pair(*iter, native_display_name);
181  }
182  DCHECK_EQ(display_names.size(), language_map.size());
183
184  // Sort display names using locale specific sorter.
185  l10n_util::SortStrings16(g_browser_process->GetApplicationLocale(),
186                           &display_names);
187
188  // Build the language list from the language map.
189  ListValue* language_list = new ListValue();
190  for (size_t i = 0; i < display_names.size(); ++i) {
191    // Sets the directionality of the display language name.
192    string16 display_name(display_names[i]);
193    bool markup_removal =
194        base::i18n::UnadjustStringForLocaleDirection(&display_name);
195    DCHECK(markup_removal);
196    bool has_rtl_chars = base::i18n::StringContainsStrongRTLChars(display_name);
197    std::string directionality = has_rtl_chars ? "rtl" : "ltr";
198
199    const LanguagePair& pair = language_map[display_names[i]];
200    DictionaryValue* dictionary = new DictionaryValue();
201    dictionary->SetString("code", pair.first);
202    dictionary->SetString("displayName", display_names[i]);
203    dictionary->SetString("textDirection", directionality);
204    dictionary->SetString("nativeDisplayName", pair.second);
205    language_list->Append(dictionary);
206  }
207
208  return language_list;
209}
210
211base::ListValue* CrosLanguageOptionsHandler::GetExtensionImeList() {
212  input_method::InputMethodManager* manager =
213      input_method::GetInputMethodManager();
214
215  input_method::InputMethodDescriptors descriptors;
216  manager->GetInputMethodExtensions(&descriptors);
217
218  ListValue* extension_ime_ids_list = new ListValue();
219
220  for (size_t i = 0; i < descriptors.size(); ++i) {
221    const input_method::InputMethodDescriptor& descriptor = descriptors[i];
222    DictionaryValue* dictionary = new DictionaryValue();
223    dictionary->SetString("id", descriptor.id());
224    dictionary->SetString("displayName", descriptor.name());
225    extension_ime_ids_list->Append(dictionary);
226  }
227
228  return extension_ime_ids_list;
229}
230
231string16 CrosLanguageOptionsHandler::GetProductName() {
232  return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
233}
234
235void CrosLanguageOptionsHandler::SetApplicationLocale(
236    const std::string& language_code) {
237  Profile::FromWebUI(web_ui())->ChangeAppLocale(
238      language_code, Profile::APP_LOCALE_CHANGED_VIA_SETTINGS);
239}
240
241void CrosLanguageOptionsHandler::RestartCallback(const ListValue* args) {
242  content::RecordAction(UserMetricsAction("LanguageOptions_SignOut"));
243  chrome::AttemptUserExit();
244}
245
246void CrosLanguageOptionsHandler::InputMethodDisableCallback(
247    const ListValue* args) {
248  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
249  const std::string action = base::StringPrintf(
250      "LanguageOptions_DisableInputMethod_%s", input_method_id.c_str());
251  content::RecordComputedAction(action);
252}
253
254void CrosLanguageOptionsHandler::InputMethodEnableCallback(
255    const ListValue* args) {
256  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
257  const std::string action = base::StringPrintf(
258      "LanguageOptions_EnableInputMethod_%s", input_method_id.c_str());
259  content::RecordComputedAction(action);
260}
261
262void CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback(
263    const ListValue* args) {
264  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
265  const std::string action = base::StringPrintf(
266      "InputMethodOptions_Open_%s", input_method_id.c_str());
267  content::RecordComputedAction(action);
268}
269
270}  // namespace options
271}  // namespace chromeos
272