language_switch_menu.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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/login/language_switch_menu.h"
6
7#include "app/resource_bundle.h"
8#include "base/i18n/rtl.h"
9#include "base/utf_string_conversions.h"
10#include "chrome/browser/browser_process.h"
11#include "chrome/browser/chromeos/cros/cros_library.h"
12#include "chrome/browser/chromeos/cros/keyboard_library.h"
13#include "chrome/browser/chromeos/input_method/input_method_util.h"
14#include "chrome/browser/chromeos/language_preferences.h"
15#include "chrome/browser/chromeos/login/screen_observer.h"
16#include "chrome/browser/prefs/pref_service.h"
17#include "chrome/common/pref_names.h"
18#include "grit/generated_resources.h"
19#include "views/controls/button/menu_button.h"
20#include "views/widget/widget_gtk.h"
21
22namespace {
23
24const int kLanguageMainMenuSize = 5;
25// TODO(glotov): need to specify the list as a part of the image customization.
26const char kLanguagesTopped[] = "es,it,de,fr,en-US";
27const int kMoreLanguagesSubMenu = 200;
28
29}  // namespace
30
31namespace chromeos {
32
33LanguageSwitchMenu::LanguageSwitchMenu()
34    : ALLOW_THIS_IN_INITIALIZER_LIST(menu_model_(this)),
35      ALLOW_THIS_IN_INITIALIZER_LIST(menu_model_submenu_(this)),
36      menu_alignment_(views::Menu2::ALIGN_TOPRIGHT) {
37}
38
39void LanguageSwitchMenu::InitLanguageMenu() {
40  // Update LanguageList to contain entries in current locale.
41  language_list_.reset(new LanguageList);
42  language_list_->CopySpecifiedLanguagesUp(kLanguagesTopped);
43
44  // Clear older menu items.
45  menu_model_.Clear();
46  menu_model_submenu_.Clear();
47
48  // Fill menu items with updated items.
49  for (int line = 0; line != kLanguageMainMenuSize; line++) {
50    menu_model_.AddItem(line, language_list_->GetLanguageNameAt(line));
51  }
52  menu_model_.AddSeparator();
53  menu_model_.AddSubMenuWithStringId(kMoreLanguagesSubMenu,
54                                     IDS_LANGUAGES_MORE,
55                                     &menu_model_submenu_);
56  for (int line = kLanguageMainMenuSize;
57       line != language_list_->get_languages_count(); line++) {
58    menu_model_submenu_.AddItem(
59        line, language_list_->GetLanguageNameAt(line));
60  }
61
62  // Initialize menu here so it appears fast when called.
63  menu_.reset(new views::Menu2(&menu_model_));
64}
65
66string16 LanguageSwitchMenu::GetCurrentLocaleName() const {
67  DCHECK(g_browser_process);
68  const std::string locale = g_browser_process->GetApplicationLocale();
69  int index = language_list_->GetIndexFromLocale(locale);
70  CHECK_NE(-1, index) << "Unknown locale: " << locale;
71  return language_list_->GetLanguageNameAt(index);
72};
73
74void LanguageSwitchMenu::SetFirstLevelMenuWidth(int width) {
75  DCHECK(menu_ != NULL);
76  menu_->SetMinimumWidth(width);
77}
78
79// static
80void LanguageSwitchMenu::SwitchLanguage(const std::string& locale) {
81  DCHECK(g_browser_process);
82  if (g_browser_process->GetApplicationLocale() == locale) {
83    return;
84  }
85  // Save new locale.
86  PrefService* prefs = g_browser_process->local_state();
87  // TODO(markusheintz): If the preference is managed and can not be changed by
88  // the user, changing the language should be disabled in the UI.
89  // TODO(markusheintz): Change the if condition to prefs->IsUserModifiable()
90  // once Mattias landed his pending patch.
91  if (!prefs->IsManagedPreference(prefs::kApplicationLocale)) {
92    prefs->SetString(prefs::kApplicationLocale, locale);
93    prefs->SavePersistentPrefs();
94
95    // Switch the locale.
96    const std::string loaded_locale =
97        ResourceBundle::ReloadSharedInstance(locale);
98    CHECK(!loaded_locale.empty()) << "Locale could not be found for " << locale;
99
100    // Enable the keyboard layouts that are necessary for the new locale.
101    input_method::EnableInputMethods(
102        locale, input_method::kKeyboardLayoutsOnly,
103        CrosLibrary::Get()->GetKeyboardLibrary()->
104            GetHardwareKeyboardLayoutName());
105
106    // The following line does not seem to affect locale anyhow. Maybe in
107    // future..
108    g_browser_process->SetApplicationLocale(locale);
109  }
110}
111
112////////////////////////////////////////////////////////////////////////////////
113// views::ViewMenuDelegate implementation.
114
115void LanguageSwitchMenu::RunMenu(views::View* source, const gfx::Point& pt) {
116  DCHECK(menu_ != NULL);
117  views::MenuButton* button = static_cast<views::MenuButton*>(source);
118  // We align the on left edge of the button for non RTL case.
119  gfx::Point new_pt(pt);
120  if (menu_alignment_ == views::Menu2::ALIGN_TOPLEFT) {
121    int reverse_offset = button->width() + button->menu_offset().x() * 2;
122    if (base::i18n::IsRTL()) {
123      new_pt.set_x(pt.x() + reverse_offset);
124    } else {
125      new_pt.set_x(pt.x() - reverse_offset);
126    }
127  }
128  menu_->RunMenuAt(new_pt, menu_alignment_);
129}
130
131////////////////////////////////////////////////////////////////////////////////
132// menus::SimpleMenuModel::Delegate implementation.
133
134bool LanguageSwitchMenu::IsCommandIdChecked(int command_id) const {
135  return false;
136}
137
138bool LanguageSwitchMenu::IsCommandIdEnabled(int command_id) const {
139  return true;
140}
141
142bool LanguageSwitchMenu::GetAcceleratorForCommandId(
143    int command_id, menus::Accelerator* accelerator) {
144  return false;
145}
146
147void LanguageSwitchMenu::ExecuteCommand(int command_id) {
148  const std::string locale = language_list_->GetLocaleFromIndex(command_id);
149  SwitchLanguage(locale);
150  InitLanguageMenu();
151
152  // Update all view hierarchies that the locale has changed.
153  views::Widget::NotifyLocaleChanged();
154}
155
156}  // namespace chromeos
157